diff --git a/frontends/react-native-ios/.gitignore b/frontends/auth/react-native/.gitignore
similarity index 100%
rename from frontends/react-native-ios/.gitignore
rename to frontends/auth/react-native/.gitignore
diff --git a/frontends/react-native-ios/App.tsx b/frontends/auth/react-native/App.tsx
similarity index 100%
rename from frontends/react-native-ios/App.tsx
rename to frontends/auth/react-native/App.tsx
diff --git a/frontends/react-native-ios/app.json b/frontends/auth/react-native/app.json
similarity index 100%
rename from frontends/react-native-ios/app.json
rename to frontends/auth/react-native/app.json
diff --git a/frontends/react-native-ios/app/(app)/(tabs)/_layout.tsx b/frontends/auth/react-native/app/(app)/(tabs)/_layout.tsx
similarity index 100%
rename from frontends/react-native-ios/app/(app)/(tabs)/_layout.tsx
rename to frontends/auth/react-native/app/(app)/(tabs)/_layout.tsx
diff --git a/frontends/react-native-ios/app/(app)/(tabs)/home.tsx b/frontends/auth/react-native/app/(app)/(tabs)/home.tsx
similarity index 100%
rename from frontends/react-native-ios/app/(app)/(tabs)/home.tsx
rename to frontends/auth/react-native/app/(app)/(tabs)/home.tsx
diff --git a/frontends/react-native-ios/app/(app)/(tabs)/settings.tsx b/frontends/auth/react-native/app/(app)/(tabs)/settings.tsx
similarity index 100%
rename from frontends/react-native-ios/app/(app)/(tabs)/settings.tsx
rename to frontends/auth/react-native/app/(app)/(tabs)/settings.tsx
diff --git a/frontends/react-native-ios/app/(app)/_layout.tsx b/frontends/auth/react-native/app/(app)/_layout.tsx
similarity index 100%
rename from frontends/react-native-ios/app/(app)/_layout.tsx
rename to frontends/auth/react-native/app/(app)/_layout.tsx
diff --git a/frontends/react-native-ios/app/(app)/profile.tsx b/frontends/auth/react-native/app/(app)/profile.tsx
similarity index 100%
rename from frontends/react-native-ios/app/(app)/profile.tsx
rename to frontends/auth/react-native/app/(app)/profile.tsx
diff --git a/frontends/react-native-ios/app/(auth)/_layout.tsx b/frontends/auth/react-native/app/(auth)/_layout.tsx
similarity index 100%
rename from frontends/react-native-ios/app/(auth)/_layout.tsx
rename to frontends/auth/react-native/app/(auth)/_layout.tsx
diff --git a/frontends/react-native-ios/app/(auth)/login.tsx b/frontends/auth/react-native/app/(auth)/login.tsx
similarity index 100%
rename from frontends/react-native-ios/app/(auth)/login.tsx
rename to frontends/auth/react-native/app/(auth)/login.tsx
diff --git a/frontends/react-native-ios/app/(auth)/register.tsx b/frontends/auth/react-native/app/(auth)/register.tsx
similarity index 100%
rename from frontends/react-native-ios/app/(auth)/register.tsx
rename to frontends/auth/react-native/app/(auth)/register.tsx
diff --git a/frontends/react-native-ios/app/_layout.tsx b/frontends/auth/react-native/app/_layout.tsx
similarity index 100%
rename from frontends/react-native-ios/app/_layout.tsx
rename to frontends/auth/react-native/app/_layout.tsx
diff --git a/frontends/react-native-ios/app/index.tsx b/frontends/auth/react-native/app/index.tsx
similarity index 100%
rename from frontends/react-native-ios/app/index.tsx
rename to frontends/auth/react-native/app/index.tsx
diff --git a/frontends/react-native-ios/assets/adaptive-icon.png b/frontends/auth/react-native/assets/adaptive-icon.png
similarity index 100%
rename from frontends/react-native-ios/assets/adaptive-icon.png
rename to frontends/auth/react-native/assets/adaptive-icon.png
diff --git a/frontends/react-native-ios/assets/favicon.png b/frontends/auth/react-native/assets/favicon.png
similarity index 100%
rename from frontends/react-native-ios/assets/favicon.png
rename to frontends/auth/react-native/assets/favicon.png
diff --git a/frontends/react-native-ios/assets/icon.png b/frontends/auth/react-native/assets/icon.png
similarity index 100%
rename from frontends/react-native-ios/assets/icon.png
rename to frontends/auth/react-native/assets/icon.png
diff --git a/frontends/react-native-ios/assets/splash-icon.png b/frontends/auth/react-native/assets/splash-icon.png
similarity index 100%
rename from frontends/react-native-ios/assets/splash-icon.png
rename to frontends/auth/react-native/assets/splash-icon.png
diff --git a/frontends/react-native-ios/babel.config.js b/frontends/auth/react-native/babel.config.js
similarity index 100%
rename from frontends/react-native-ios/babel.config.js
rename to frontends/auth/react-native/babel.config.js
diff --git a/frontends/react-native-ios/biome.json b/frontends/auth/react-native/biome.json
similarity index 100%
rename from frontends/react-native-ios/biome.json
rename to frontends/auth/react-native/biome.json
diff --git a/frontends/react-native-ios/eas.json b/frontends/auth/react-native/eas.json
similarity index 100%
rename from frontends/react-native-ios/eas.json
rename to frontends/auth/react-native/eas.json
diff --git a/frontends/react-native-ios/index.ts b/frontends/auth/react-native/index.ts
similarity index 100%
rename from frontends/react-native-ios/index.ts
rename to frontends/auth/react-native/index.ts
diff --git a/frontends/react-native-ios/justfile b/frontends/auth/react-native/justfile
similarity index 100%
rename from frontends/react-native-ios/justfile
rename to frontends/auth/react-native/justfile
diff --git a/frontends/react-native-ios/package.json b/frontends/auth/react-native/package.json
similarity index 100%
rename from frontends/react-native-ios/package.json
rename to frontends/auth/react-native/package.json
diff --git a/frontends/react-native-ios/pnpm-lock.yaml b/frontends/auth/react-native/pnpm-lock.yaml
similarity index 100%
rename from frontends/react-native-ios/pnpm-lock.yaml
rename to frontends/auth/react-native/pnpm-lock.yaml
diff --git a/frontends/react-native-ios/src/api/hooks/index.ts b/frontends/auth/react-native/src/api/hooks/index.ts
similarity index 100%
rename from frontends/react-native-ios/src/api/hooks/index.ts
rename to frontends/auth/react-native/src/api/hooks/index.ts
diff --git a/frontends/react-native-ios/src/api/hooks/useAuth.ts b/frontends/auth/react-native/src/api/hooks/useAuth.ts
similarity index 100%
rename from frontends/react-native-ios/src/api/hooks/useAuth.ts
rename to frontends/auth/react-native/src/api/hooks/useAuth.ts
diff --git a/frontends/react-native-ios/src/api/hooks/useUsers.ts b/frontends/auth/react-native/src/api/hooks/useUsers.ts
similarity index 100%
rename from frontends/react-native-ios/src/api/hooks/useUsers.ts
rename to frontends/auth/react-native/src/api/hooks/useUsers.ts
diff --git a/frontends/react-native-ios/src/api/types/auth.types.ts b/frontends/auth/react-native/src/api/types/auth.types.ts
similarity index 100%
rename from frontends/react-native-ios/src/api/types/auth.types.ts
rename to frontends/auth/react-native/src/api/types/auth.types.ts
diff --git a/frontends/react-native-ios/src/api/types/index.ts b/frontends/auth/react-native/src/api/types/index.ts
similarity index 100%
rename from frontends/react-native-ios/src/api/types/index.ts
rename to frontends/auth/react-native/src/api/types/index.ts
diff --git a/frontends/react-native-ios/src/api/types/user.types.ts b/frontends/auth/react-native/src/api/types/user.types.ts
similarity index 100%
rename from frontends/react-native-ios/src/api/types/user.types.ts
rename to frontends/auth/react-native/src/api/types/user.types.ts
diff --git a/frontends/react-native-ios/src/core/api/api.config.ts b/frontends/auth/react-native/src/core/api/api.config.ts
similarity index 100%
rename from frontends/react-native-ios/src/core/api/api.config.ts
rename to frontends/auth/react-native/src/core/api/api.config.ts
diff --git a/frontends/react-native-ios/src/core/api/errors.ts b/frontends/auth/react-native/src/core/api/errors.ts
similarity index 100%
rename from frontends/react-native-ios/src/core/api/errors.ts
rename to frontends/auth/react-native/src/core/api/errors.ts
diff --git a/frontends/react-native-ios/src/core/api/index.ts b/frontends/auth/react-native/src/core/api/index.ts
similarity index 100%
rename from frontends/react-native-ios/src/core/api/index.ts
rename to frontends/auth/react-native/src/core/api/index.ts
diff --git a/frontends/react-native-ios/src/core/api/query.config.ts b/frontends/auth/react-native/src/core/api/query.config.ts
similarity index 100%
rename from frontends/react-native-ios/src/core/api/query.config.ts
rename to frontends/auth/react-native/src/core/api/query.config.ts
diff --git a/frontends/react-native-ios/src/core/config.ts b/frontends/auth/react-native/src/core/config.ts
similarity index 100%
rename from frontends/react-native-ios/src/core/config.ts
rename to frontends/auth/react-native/src/core/config.ts
diff --git a/frontends/react-native-ios/src/core/lib/auth.store.ts b/frontends/auth/react-native/src/core/lib/auth.store.ts
similarity index 100%
rename from frontends/react-native-ios/src/core/lib/auth.store.ts
rename to frontends/auth/react-native/src/core/lib/auth.store.ts
diff --git a/frontends/react-native-ios/src/core/lib/index.ts b/frontends/auth/react-native/src/core/lib/index.ts
similarity index 100%
rename from frontends/react-native-ios/src/core/lib/index.ts
rename to frontends/auth/react-native/src/core/lib/index.ts
diff --git a/frontends/react-native-ios/src/core/lib/ui.store.ts b/frontends/auth/react-native/src/core/lib/ui.store.ts
similarity index 100%
rename from frontends/react-native-ios/src/core/lib/ui.store.ts
rename to frontends/auth/react-native/src/core/lib/ui.store.ts
diff --git a/frontends/react-native-ios/src/core/storage/app.storage.ts b/frontends/auth/react-native/src/core/storage/app.storage.ts
similarity index 100%
rename from frontends/react-native-ios/src/core/storage/app.storage.ts
rename to frontends/auth/react-native/src/core/storage/app.storage.ts
diff --git a/frontends/react-native-ios/src/core/storage/index.ts b/frontends/auth/react-native/src/core/storage/index.ts
similarity index 100%
rename from frontends/react-native-ios/src/core/storage/index.ts
rename to frontends/auth/react-native/src/core/storage/index.ts
diff --git a/frontends/react-native-ios/src/core/storage/secure.storage.ts b/frontends/auth/react-native/src/core/storage/secure.storage.ts
similarity index 100%
rename from frontends/react-native-ios/src/core/storage/secure.storage.ts
rename to frontends/auth/react-native/src/core/storage/secure.storage.ts
diff --git a/frontends/react-native-ios/src/shared/components/index.ts b/frontends/auth/react-native/src/shared/components/index.ts
similarity index 100%
rename from frontends/react-native-ios/src/shared/components/index.ts
rename to frontends/auth/react-native/src/shared/components/index.ts
diff --git a/frontends/react-native-ios/src/shared/components/ui/Button.tsx b/frontends/auth/react-native/src/shared/components/ui/Button.tsx
similarity index 100%
rename from frontends/react-native-ios/src/shared/components/ui/Button.tsx
rename to frontends/auth/react-native/src/shared/components/ui/Button.tsx
diff --git a/frontends/react-native-ios/src/shared/components/ui/Card.tsx b/frontends/auth/react-native/src/shared/components/ui/Card.tsx
similarity index 100%
rename from frontends/react-native-ios/src/shared/components/ui/Card.tsx
rename to frontends/auth/react-native/src/shared/components/ui/Card.tsx
diff --git a/frontends/react-native-ios/src/shared/components/ui/DottedBackground.tsx b/frontends/auth/react-native/src/shared/components/ui/DottedBackground.tsx
similarity index 100%
rename from frontends/react-native-ios/src/shared/components/ui/DottedBackground.tsx
rename to frontends/auth/react-native/src/shared/components/ui/DottedBackground.tsx
diff --git a/frontends/react-native-ios/src/shared/components/ui/Input.tsx b/frontends/auth/react-native/src/shared/components/ui/Input.tsx
similarity index 100%
rename from frontends/react-native-ios/src/shared/components/ui/Input.tsx
rename to frontends/auth/react-native/src/shared/components/ui/Input.tsx
diff --git a/frontends/react-native-ios/src/shared/components/ui/PasswordInput.tsx b/frontends/auth/react-native/src/shared/components/ui/PasswordInput.tsx
similarity index 100%
rename from frontends/react-native-ios/src/shared/components/ui/PasswordInput.tsx
rename to frontends/auth/react-native/src/shared/components/ui/PasswordInput.tsx
diff --git a/frontends/react-native-ios/src/shared/components/ui/index.ts b/frontends/auth/react-native/src/shared/components/ui/index.ts
similarity index 100%
rename from frontends/react-native-ios/src/shared/components/ui/index.ts
rename to frontends/auth/react-native/src/shared/components/ui/index.ts
diff --git a/frontends/react-native-ios/src/shared/hooks/index.ts b/frontends/auth/react-native/src/shared/hooks/index.ts
similarity index 100%
rename from frontends/react-native-ios/src/shared/hooks/index.ts
rename to frontends/auth/react-native/src/shared/hooks/index.ts
diff --git a/frontends/react-native-ios/src/shared/hooks/useAppState.ts b/frontends/auth/react-native/src/shared/hooks/useAppState.ts
similarity index 100%
rename from frontends/react-native-ios/src/shared/hooks/useAppState.ts
rename to frontends/auth/react-native/src/shared/hooks/useAppState.ts
diff --git a/frontends/react-native-ios/src/shared/hooks/useBiometricAuth.ts b/frontends/auth/react-native/src/shared/hooks/useBiometricAuth.ts
similarity index 100%
rename from frontends/react-native-ios/src/shared/hooks/useBiometricAuth.ts
rename to frontends/auth/react-native/src/shared/hooks/useBiometricAuth.ts
diff --git a/frontends/react-native-ios/src/shared/hooks/useBiometrics.ts b/frontends/auth/react-native/src/shared/hooks/useBiometrics.ts
similarity index 100%
rename from frontends/react-native-ios/src/shared/hooks/useBiometrics.ts
rename to frontends/auth/react-native/src/shared/hooks/useBiometrics.ts
diff --git a/frontends/react-native-ios/src/shared/hooks/useOnlineManager.ts b/frontends/auth/react-native/src/shared/hooks/useOnlineManager.ts
similarity index 100%
rename from frontends/react-native-ios/src/shared/hooks/useOnlineManager.ts
rename to frontends/auth/react-native/src/shared/hooks/useOnlineManager.ts
diff --git a/frontends/react-native-ios/src/shared/hooks/useSession.ts b/frontends/auth/react-native/src/shared/hooks/useSession.ts
similarity index 100%
rename from frontends/react-native-ios/src/shared/hooks/useSession.ts
rename to frontends/auth/react-native/src/shared/hooks/useSession.ts
diff --git a/frontends/react-native-ios/src/shared/index.ts b/frontends/auth/react-native/src/shared/index.ts
similarity index 100%
rename from frontends/react-native-ios/src/shared/index.ts
rename to frontends/auth/react-native/src/shared/index.ts
diff --git a/frontends/react-native-ios/src/shared/utils/haptics.ts b/frontends/auth/react-native/src/shared/utils/haptics.ts
similarity index 100%
rename from frontends/react-native-ios/src/shared/utils/haptics.ts
rename to frontends/auth/react-native/src/shared/utils/haptics.ts
diff --git a/frontends/react-native-ios/src/shared/utils/index.ts b/frontends/auth/react-native/src/shared/utils/index.ts
similarity index 100%
rename from frontends/react-native-ios/src/shared/utils/index.ts
rename to frontends/auth/react-native/src/shared/utils/index.ts
diff --git a/frontends/react-native-ios/src/theme/tamagui.config.ts b/frontends/auth/react-native/src/theme/tamagui.config.ts
similarity index 100%
rename from frontends/react-native-ios/src/theme/tamagui.config.ts
rename to frontends/auth/react-native/src/theme/tamagui.config.ts
diff --git a/frontends/react-native-ios/src/theme/themes.ts b/frontends/auth/react-native/src/theme/themes.ts
similarity index 100%
rename from frontends/react-native-ios/src/theme/themes.ts
rename to frontends/auth/react-native/src/theme/themes.ts
diff --git a/frontends/react-native-ios/src/theme/tokens.ts b/frontends/auth/react-native/src/theme/tokens.ts
similarity index 100%
rename from frontends/react-native-ios/src/theme/tokens.ts
rename to frontends/auth/react-native/src/theme/tokens.ts
diff --git a/frontends/react-native-ios/tamagui.config.ts b/frontends/auth/react-native/tamagui.config.ts
similarity index 100%
rename from frontends/react-native-ios/tamagui.config.ts
rename to frontends/auth/react-native/tamagui.config.ts
diff --git a/frontends/react-native-ios/tsconfig.json b/frontends/auth/react-native/tsconfig.json
similarity index 100%
rename from frontends/react-native-ios/tsconfig.json
rename to frontends/auth/react-native/tsconfig.json
diff --git a/frontends/react-scss/.dockerignore b/frontends/auth/react-scss/.dockerignore
similarity index 100%
rename from frontends/react-scss/.dockerignore
rename to frontends/auth/react-scss/.dockerignore
diff --git a/frontends/react-scss/.gitignore b/frontends/auth/react-scss/.gitignore
similarity index 100%
rename from frontends/react-scss/.gitignore
rename to frontends/auth/react-scss/.gitignore
diff --git a/frontends/react-scss/.stylelintignore b/frontends/auth/react-scss/.stylelintignore
similarity index 100%
rename from frontends/react-scss/.stylelintignore
rename to frontends/auth/react-scss/.stylelintignore
diff --git a/frontends/react-scss/biome.json b/frontends/auth/react-scss/biome.json
similarity index 100%
rename from frontends/react-scss/biome.json
rename to frontends/auth/react-scss/biome.json
diff --git a/frontends/react-scss/index.html b/frontends/auth/react-scss/index.html
similarity index 100%
rename from frontends/react-scss/index.html
rename to frontends/auth/react-scss/index.html
diff --git a/frontends/react-scss/package.json b/frontends/auth/react-scss/package.json
similarity index 100%
rename from frontends/react-scss/package.json
rename to frontends/auth/react-scss/package.json
diff --git a/frontends/react-scss/pnpm-lock.yaml b/frontends/auth/react-scss/pnpm-lock.yaml
similarity index 100%
rename from frontends/react-scss/pnpm-lock.yaml
rename to frontends/auth/react-scss/pnpm-lock.yaml
diff --git a/frontends/react-scss/public/assets/android-chrome-192x192.png b/frontends/auth/react-scss/public/assets/android-chrome-192x192.png
similarity index 100%
rename from frontends/react-scss/public/assets/android-chrome-192x192.png
rename to frontends/auth/react-scss/public/assets/android-chrome-192x192.png
diff --git a/frontends/react-scss/public/assets/android-chrome-512x512.png b/frontends/auth/react-scss/public/assets/android-chrome-512x512.png
similarity index 100%
rename from frontends/react-scss/public/assets/android-chrome-512x512.png
rename to frontends/auth/react-scss/public/assets/android-chrome-512x512.png
diff --git a/frontends/react-scss/public/assets/apple-touch-icon.png b/frontends/auth/react-scss/public/assets/apple-touch-icon.png
similarity index 100%
rename from frontends/react-scss/public/assets/apple-touch-icon.png
rename to frontends/auth/react-scss/public/assets/apple-touch-icon.png
diff --git a/frontends/react-scss/public/assets/favicon-16x16.png b/frontends/auth/react-scss/public/assets/favicon-16x16.png
similarity index 100%
rename from frontends/react-scss/public/assets/favicon-16x16.png
rename to frontends/auth/react-scss/public/assets/favicon-16x16.png
diff --git a/frontends/react-scss/public/assets/favicon-32x32.png b/frontends/auth/react-scss/public/assets/favicon-32x32.png
similarity index 100%
rename from frontends/react-scss/public/assets/favicon-32x32.png
rename to frontends/auth/react-scss/public/assets/favicon-32x32.png
diff --git a/frontends/react-scss/public/assets/favicon.ico b/frontends/auth/react-scss/public/assets/favicon.ico
similarity index 100%
rename from frontends/react-scss/public/assets/favicon.ico
rename to frontends/auth/react-scss/public/assets/favicon.ico
diff --git a/frontends/react-scss/public/assets/site.webmanifest b/frontends/auth/react-scss/public/assets/site.webmanifest
similarity index 100%
rename from frontends/react-scss/public/assets/site.webmanifest
rename to frontends/auth/react-scss/public/assets/site.webmanifest
diff --git a/frontends/react-scss/src/App.tsx b/frontends/auth/react-scss/src/App.tsx
similarity index 100%
rename from frontends/react-scss/src/App.tsx
rename to frontends/auth/react-scss/src/App.tsx
diff --git a/frontends/react-scss/src/api/hooks/index.ts b/frontends/auth/react-scss/src/api/hooks/index.ts
similarity index 100%
rename from frontends/react-scss/src/api/hooks/index.ts
rename to frontends/auth/react-scss/src/api/hooks/index.ts
diff --git a/frontends/react-scss/src/api/hooks/useAdmin.ts b/frontends/auth/react-scss/src/api/hooks/useAdmin.ts
similarity index 100%
rename from frontends/react-scss/src/api/hooks/useAdmin.ts
rename to frontends/auth/react-scss/src/api/hooks/useAdmin.ts
diff --git a/frontends/react-scss/src/api/hooks/useAuth.ts b/frontends/auth/react-scss/src/api/hooks/useAuth.ts
similarity index 100%
rename from frontends/react-scss/src/api/hooks/useAuth.ts
rename to frontends/auth/react-scss/src/api/hooks/useAuth.ts
diff --git a/frontends/react-scss/src/api/hooks/useUsers.ts b/frontends/auth/react-scss/src/api/hooks/useUsers.ts
similarity index 100%
rename from frontends/react-scss/src/api/hooks/useUsers.ts
rename to frontends/auth/react-scss/src/api/hooks/useUsers.ts
diff --git a/frontends/react-scss/src/api/index.ts b/frontends/auth/react-scss/src/api/index.ts
similarity index 100%
rename from frontends/react-scss/src/api/index.ts
rename to frontends/auth/react-scss/src/api/index.ts
diff --git a/frontends/react-scss/src/api/types/auth.types.ts b/frontends/auth/react-scss/src/api/types/auth.types.ts
similarity index 100%
rename from frontends/react-scss/src/api/types/auth.types.ts
rename to frontends/auth/react-scss/src/api/types/auth.types.ts
diff --git a/frontends/react-scss/src/api/types/index.ts b/frontends/auth/react-scss/src/api/types/index.ts
similarity index 100%
rename from frontends/react-scss/src/api/types/index.ts
rename to frontends/auth/react-scss/src/api/types/index.ts
diff --git a/frontends/react-scss/src/api/types/user.types.ts b/frontends/auth/react-scss/src/api/types/user.types.ts
similarity index 100%
rename from frontends/react-scss/src/api/types/user.types.ts
rename to frontends/auth/react-scss/src/api/types/user.types.ts
diff --git a/frontends/react-scss/src/components/index.tsx b/frontends/auth/react-scss/src/components/index.tsx
similarity index 100%
rename from frontends/react-scss/src/components/index.tsx
rename to frontends/auth/react-scss/src/components/index.tsx
diff --git a/frontends/react-scss/src/config.ts b/frontends/auth/react-scss/src/config.ts
similarity index 100%
rename from frontends/react-scss/src/config.ts
rename to frontends/auth/react-scss/src/config.ts
diff --git a/frontends/react-scss/src/core/api/api.config.ts b/frontends/auth/react-scss/src/core/api/api.config.ts
similarity index 100%
rename from frontends/react-scss/src/core/api/api.config.ts
rename to frontends/auth/react-scss/src/core/api/api.config.ts
diff --git a/frontends/react-scss/src/core/api/errors.ts b/frontends/auth/react-scss/src/core/api/errors.ts
similarity index 100%
rename from frontends/react-scss/src/core/api/errors.ts
rename to frontends/auth/react-scss/src/core/api/errors.ts
diff --git a/frontends/react-scss/src/core/api/index.ts b/frontends/auth/react-scss/src/core/api/index.ts
similarity index 100%
rename from frontends/react-scss/src/core/api/index.ts
rename to frontends/auth/react-scss/src/core/api/index.ts
diff --git a/frontends/react-scss/src/core/api/query.config.ts b/frontends/auth/react-scss/src/core/api/query.config.ts
similarity index 100%
rename from frontends/react-scss/src/core/api/query.config.ts
rename to frontends/auth/react-scss/src/core/api/query.config.ts
diff --git a/frontends/react-scss/src/core/app/protected-route.tsx b/frontends/auth/react-scss/src/core/app/protected-route.tsx
similarity index 100%
rename from frontends/react-scss/src/core/app/protected-route.tsx
rename to frontends/auth/react-scss/src/core/app/protected-route.tsx
diff --git a/frontends/react-scss/src/core/app/routers.tsx b/frontends/auth/react-scss/src/core/app/routers.tsx
similarity index 100%
rename from frontends/react-scss/src/core/app/routers.tsx
rename to frontends/auth/react-scss/src/core/app/routers.tsx
diff --git a/frontends/auth/react-scss/src/core/app/shell.module.scss b/frontends/auth/react-scss/src/core/app/shell.module.scss
new file mode 100644
index 0000000..3466896
--- /dev/null
+++ b/frontends/auth/react-scss/src/core/app/shell.module.scss
@@ -0,0 +1,4 @@
+// ===================
+// © AngelaMos | 2026
+// shell.module.scss
+// ===================
diff --git a/frontends/react-scss/src/core/app/shell.tsx b/frontends/auth/react-scss/src/core/app/shell.tsx
similarity index 100%
rename from frontends/react-scss/src/core/app/shell.tsx
rename to frontends/auth/react-scss/src/core/app/shell.tsx
diff --git a/frontends/auth/react-scss/src/core/app/toast.module.scss b/frontends/auth/react-scss/src/core/app/toast.module.scss
new file mode 100644
index 0000000..62a8ee3
--- /dev/null
+++ b/frontends/auth/react-scss/src/core/app/toast.module.scss
@@ -0,0 +1,4 @@
+// ===================
+// © AngelaMos | 2026
+// toast.module.scss
+// ===================
diff --git a/frontends/react-scss/src/core/lib/auth.form.store.ts b/frontends/auth/react-scss/src/core/lib/auth.form.store.ts
similarity index 100%
rename from frontends/react-scss/src/core/lib/auth.form.store.ts
rename to frontends/auth/react-scss/src/core/lib/auth.form.store.ts
diff --git a/frontends/react-scss/src/core/lib/auth.store.ts b/frontends/auth/react-scss/src/core/lib/auth.store.ts
similarity index 100%
rename from frontends/react-scss/src/core/lib/auth.store.ts
rename to frontends/auth/react-scss/src/core/lib/auth.store.ts
diff --git a/frontends/react-scss/src/core/lib/index.ts b/frontends/auth/react-scss/src/core/lib/index.ts
similarity index 100%
rename from frontends/react-scss/src/core/lib/index.ts
rename to frontends/auth/react-scss/src/core/lib/index.ts
diff --git a/frontends/react-scss/src/core/lib/shell.ui.store.ts b/frontends/auth/react-scss/src/core/lib/shell.ui.store.ts
similarity index 100%
rename from frontends/react-scss/src/core/lib/shell.ui.store.ts
rename to frontends/auth/react-scss/src/core/lib/shell.ui.store.ts
diff --git a/frontends/react-scss/src/main.tsx b/frontends/auth/react-scss/src/main.tsx
similarity index 100%
rename from frontends/react-scss/src/main.tsx
rename to frontends/auth/react-scss/src/main.tsx
diff --git a/frontends/auth/react-scss/src/pages/admin/admin.module.scss b/frontends/auth/react-scss/src/pages/admin/admin.module.scss
new file mode 100644
index 0000000..c59b723
--- /dev/null
+++ b/frontends/auth/react-scss/src/pages/admin/admin.module.scss
@@ -0,0 +1,4 @@
+// ===================
+// © AngelaMos | 2026
+// admin.module.scss
+// ===================
diff --git a/frontends/react-scss/src/pages/admin/index.tsx b/frontends/auth/react-scss/src/pages/admin/index.tsx
similarity index 100%
rename from frontends/react-scss/src/pages/admin/index.tsx
rename to frontends/auth/react-scss/src/pages/admin/index.tsx
diff --git a/frontends/auth/react-scss/src/pages/dashboard/dashboard.module.scss b/frontends/auth/react-scss/src/pages/dashboard/dashboard.module.scss
new file mode 100644
index 0000000..cbf1f90
--- /dev/null
+++ b/frontends/auth/react-scss/src/pages/dashboard/dashboard.module.scss
@@ -0,0 +1,4 @@
+// ===================
+// © AngelaMos | 2026
+// dashboard.module.scss
+// ===================
diff --git a/frontends/react-scss/src/pages/dashboard/index.tsx b/frontends/auth/react-scss/src/pages/dashboard/index.tsx
similarity index 100%
rename from frontends/react-scss/src/pages/dashboard/index.tsx
rename to frontends/auth/react-scss/src/pages/dashboard/index.tsx
diff --git a/frontends/react-scss/src/pages/landing/index.tsx b/frontends/auth/react-scss/src/pages/landing/index.tsx
similarity index 100%
rename from frontends/react-scss/src/pages/landing/index.tsx
rename to frontends/auth/react-scss/src/pages/landing/index.tsx
diff --git a/frontends/auth/react-scss/src/pages/landing/landing.module.scss b/frontends/auth/react-scss/src/pages/landing/landing.module.scss
new file mode 100644
index 0000000..164f39a
--- /dev/null
+++ b/frontends/auth/react-scss/src/pages/landing/landing.module.scss
@@ -0,0 +1,4 @@
+// ===================
+// © AngelaMos | 2026
+// landing.module.scss
+// ===================
diff --git a/frontends/react-scss/src/pages/login/index.tsx b/frontends/auth/react-scss/src/pages/login/index.tsx
similarity index 100%
rename from frontends/react-scss/src/pages/login/index.tsx
rename to frontends/auth/react-scss/src/pages/login/index.tsx
diff --git a/frontends/auth/react-scss/src/pages/login/login.module.scss b/frontends/auth/react-scss/src/pages/login/login.module.scss
new file mode 100644
index 0000000..ea09982
--- /dev/null
+++ b/frontends/auth/react-scss/src/pages/login/login.module.scss
@@ -0,0 +1,4 @@
+// ===================
+// © AngelaMos | 2026
+// login.module.scss
+// ===================
diff --git a/frontends/react-scss/src/pages/register/index.tsx b/frontends/auth/react-scss/src/pages/register/index.tsx
similarity index 100%
rename from frontends/react-scss/src/pages/register/index.tsx
rename to frontends/auth/react-scss/src/pages/register/index.tsx
diff --git a/frontends/auth/react-scss/src/pages/register/register.module.scss b/frontends/auth/react-scss/src/pages/register/register.module.scss
new file mode 100644
index 0000000..acdeec0
--- /dev/null
+++ b/frontends/auth/react-scss/src/pages/register/register.module.scss
@@ -0,0 +1,4 @@
+// ===================
+// © AngelaMos | 2026
+// register.module.scss
+// ===================
diff --git a/frontends/react-scss/src/pages/settings/index.tsx b/frontends/auth/react-scss/src/pages/settings/index.tsx
similarity index 100%
rename from frontends/react-scss/src/pages/settings/index.tsx
rename to frontends/auth/react-scss/src/pages/settings/index.tsx
diff --git a/frontends/auth/react-scss/src/pages/settings/settings.module.scss b/frontends/auth/react-scss/src/pages/settings/settings.module.scss
new file mode 100644
index 0000000..e95e0f8
--- /dev/null
+++ b/frontends/auth/react-scss/src/pages/settings/settings.module.scss
@@ -0,0 +1,4 @@
+// ===================
+// © AngelaMos | 2026
+// settings.module.scss
+// ===================
diff --git a/frontends/react-scss/src/styles.scss b/frontends/auth/react-scss/src/styles.scss
similarity index 64%
rename from frontends/react-scss/src/styles.scss
rename to frontends/auth/react-scss/src/styles.scss
index 4ac95fe..240ec55 100644
--- a/frontends/react-scss/src/styles.scss
+++ b/frontends/auth/react-scss/src/styles.scss
@@ -1,5 +1,5 @@
// ===================
-// © AngelaMos | 2025
+// © AngelaMos | 2026
// styles.scss
// ===================
@@ -8,22 +8,16 @@
@forward 'styles/mixins';
@use 'styles/reset';
-@use 'styles/tokens' as *;
-@use 'styles/fonts' as *;
#root {
min-height: 100vh;
min-height: 100dvh;
display: flex;
flex-direction: column;
- background: $bg-default;
}
.app {
flex: 1;
display: flex;
flex-direction: column;
- background: $bg-default;
- color: $text-default;
- font-family: $font-sans;
}
diff --git a/frontends/react-scss/src/styles/_fonts.scss b/frontends/auth/react-scss/src/styles/_fonts.scss
similarity index 100%
rename from frontends/react-scss/src/styles/_fonts.scss
rename to frontends/auth/react-scss/src/styles/_fonts.scss
diff --git a/frontends/react-scss/src/styles/_index.scss b/frontends/auth/react-scss/src/styles/_index.scss
similarity index 100%
rename from frontends/react-scss/src/styles/_index.scss
rename to frontends/auth/react-scss/src/styles/_index.scss
diff --git a/frontends/react-scss/src/styles/_mixins.scss b/frontends/auth/react-scss/src/styles/_mixins.scss
similarity index 100%
rename from frontends/react-scss/src/styles/_mixins.scss
rename to frontends/auth/react-scss/src/styles/_mixins.scss
diff --git a/frontends/auth/react-scss/src/styles/_reset.scss b/frontends/auth/react-scss/src/styles/_reset.scss
new file mode 100644
index 0000000..a9cbdc1
--- /dev/null
+++ b/frontends/auth/react-scss/src/styles/_reset.scss
@@ -0,0 +1,105 @@
+// ===================
+// © AngelaMos | 2026
+// _reset.scss
+// ===================
+
+*,
+*::before,
+*::after {
+ box-sizing: border-box;
+}
+
+* {
+ margin: 0;
+ padding: 0;
+ -webkit-tap-highlight-color: transparent;
+}
+
+html {
+ font-size: 16px;
+ -moz-text-size-adjust: none;
+ -webkit-text-size-adjust: none;
+ text-size-adjust: none;
+ overflow-x: hidden;
+}
+
+@media (prefers-reduced-motion: no-preference) {
+ html {
+ interpolate-size: allow-keywords;
+ scroll-behavior: smooth;
+ }
+}
+
+body {
+ min-height: 100vh;
+ min-height: 100dvh;
+ line-height: 1.5;
+ text-rendering: optimizeLegibility;
+ -webkit-font-smoothing: antialiased;
+ -moz-osx-font-smoothing: grayscale;
+ overflow-x: hidden;
+ background-color: #fff;
+ color: #000;
+}
+
+h1,
+h2,
+h3,
+h4,
+h5,
+h6 {
+ line-height: 1.2;
+ text-wrap: balance;
+ overflow-wrap: break-word;
+}
+
+p {
+ text-wrap: pretty;
+ overflow-wrap: break-word;
+}
+
+img,
+picture,
+video,
+canvas,
+svg {
+ display: block;
+ max-width: 100%;
+ height: auto;
+}
+
+input,
+button,
+textarea,
+select {
+ font: inherit;
+ color: inherit;
+}
+
+button {
+ background: none;
+ border: none;
+ cursor: pointer;
+ text-align: inherit;
+ font-family: inherit;
+}
+
+[hidden] {
+ display: none !important;
+}
+
+[disabled] {
+ cursor: not-allowed;
+ opacity: 0.5;
+}
+
+@media (prefers-reduced-motion: reduce) {
+ *,
+ *::before,
+ *::after {
+ animation-duration: 0.01ms !important;
+ animation-iteration-count: 1 !important;
+ transition-duration: 0.01ms !important;
+ scroll-behavior: auto !important;
+ }
+}
diff --git a/frontends/react-scss/src/styles/_tokens.scss b/frontends/auth/react-scss/src/styles/_tokens.scss
similarity index 100%
rename from frontends/react-scss/src/styles/_tokens.scss
rename to frontends/auth/react-scss/src/styles/_tokens.scss
diff --git a/frontends/react-scss/stylelint.config.js b/frontends/auth/react-scss/stylelint.config.js
similarity index 100%
rename from frontends/react-scss/stylelint.config.js
rename to frontends/auth/react-scss/stylelint.config.js
diff --git a/frontends/react-scss/tsconfig.app.json b/frontends/auth/react-scss/tsconfig.app.json
similarity index 100%
rename from frontends/react-scss/tsconfig.app.json
rename to frontends/auth/react-scss/tsconfig.app.json
diff --git a/frontends/react-scss/tsconfig.json b/frontends/auth/react-scss/tsconfig.json
similarity index 100%
rename from frontends/react-scss/tsconfig.json
rename to frontends/auth/react-scss/tsconfig.json
diff --git a/frontends/react-scss/tsconfig.node.json b/frontends/auth/react-scss/tsconfig.node.json
similarity index 100%
rename from frontends/react-scss/tsconfig.node.json
rename to frontends/auth/react-scss/tsconfig.node.json
diff --git a/frontends/react-scss/vite.config.ts b/frontends/auth/react-scss/vite.config.ts
similarity index 100%
rename from frontends/react-scss/vite.config.ts
rename to frontends/auth/react-scss/vite.config.ts
diff --git a/frontends/open/.env.example b/frontends/open/.env.example
new file mode 100644
index 0000000..04ee50a
--- /dev/null
+++ b/frontends/open/.env.example
@@ -0,0 +1,29 @@
+# =============================================================================
+# AngelaMos | 2026
+# .env.example
+# =============================================================================
+# Copy to .env for production, .env.development for dev
+# =============================================================================
+
+# =============================================================================
+# HOST PORTS
+# =============================================================================
+NGINX_HOST_PORT=22784
+FRONTEND_HOST_PORT=33067
+
+# =============================================================================
+# Application
+# =============================================================================
+APP_NAME=no-auth-template
+ENVIRONMENT=production
+
+# =============================================================================
+# Frontend (Vite)
+# =============================================================================
+VITE_API_URL=/api
+VITE_APP_TITLE=No Auth Template
+
+# =============================================================================
+# Cloudflare Tunnel (for cloudflared.compose.yml)
+# =============================================================================
+CLOUDFLARE_TUNNEL_TOKEN=YOUR_TUNNEL_TOKEN_HERE
diff --git a/frontends/open/cloudflared.compose.yml b/frontends/open/cloudflared.compose.yml
new file mode 100644
index 0000000..e91fde7
--- /dev/null
+++ b/frontends/open/cloudflared.compose.yml
@@ -0,0 +1,27 @@
+# =============================================================================
+# AngelaMos | 2026
+# cloudflared.compose.yml
+# =============================================================================
+# Cloudflare Tunnel for production remote access
+# Usage: docker compose -f compose.yml -f cloudflared.compose.yml up -d
+# =============================================================================
+
+services:
+ cloudflared:
+ image: cloudflare/cloudflared:latest
+ container_name: ${APP_NAME:-no-auth-template}-tunnel
+ command: tunnel run --token ${CLOUDFLARE_TUNNEL_TOKEN}
+ networks:
+ - app
+ depends_on:
+ nginx:
+ condition: service_started
+ deploy:
+ resources:
+ limits:
+ cpus: '0.5'
+ memory: 128M
+ reservations:
+ cpus: '0.1'
+ memory: 32M
+ restart: unless-stopped
diff --git a/frontends/open/compose.yml b/frontends/open/compose.yml
new file mode 100644
index 0000000..c1bbec2
--- /dev/null
+++ b/frontends/open/compose.yml
@@ -0,0 +1,36 @@
+# =============================================================================
+# AngelaMos | 2026
+# compose.yml
+# =============================================================================
+# Production compose - Nginx serving built React app
+# For Cloudflare tunnel: docker compose -f compose.yml -f cloudflared.compose.yml up
+# =============================================================================
+
+name: ${APP_NAME:-no-auth-template}
+
+services:
+ nginx:
+ build:
+ context: .
+ dockerfile: infra/docker/vite.prod
+ args:
+ - VITE_API_URL=${VITE_API_URL:-/api}
+ - VITE_APP_TITLE=${VITE_APP_TITLE:-My App}
+ container_name: ${APP_NAME:-no-auth-template}-nginx
+ ports:
+ - "${NGINX_HOST_PORT:-22784}:80"
+ networks:
+ - app
+ deploy:
+ resources:
+ limits:
+ cpus: '1.0'
+ memory: 256M
+ reservations:
+ cpus: '0.25'
+ memory: 64M
+ restart: unless-stopped
+
+networks:
+ app:
+ driver: bridge
diff --git a/frontends/open/dev.compose.yml b/frontends/open/dev.compose.yml
new file mode 100644
index 0000000..6443c02
--- /dev/null
+++ b/frontends/open/dev.compose.yml
@@ -0,0 +1,49 @@
+# =============================================================================
+# AngelaMos | 2026
+# dev.compose.yml
+# =============================================================================
+# Development compose - Nginx + Vite dev server with HMR
+# Uses .env.development
+# =============================================================================
+
+name: ${APP_NAME:-no-auth-template}-dev
+
+services:
+ nginx:
+ image: nginx:1.27-alpine
+ container_name: ${APP_NAME:-no-auth-template}-nginx-dev
+ ports:
+ - "${NGINX_HOST_PORT:-58495}:80"
+ volumes:
+ - ./infra/nginx/nginx.conf:/etc/nginx/nginx.conf:ro
+ - ./infra/nginx/dev.nginx:/etc/nginx/conf.d/default.conf:ro
+ depends_on:
+ frontend:
+ condition: service_started
+ networks:
+ - app
+ restart: unless-stopped
+
+ frontend:
+ build:
+ context: ./react-scss
+ dockerfile: ../infra/docker/vite.dev
+ container_name: ${APP_NAME:-no-auth-template}-frontend-dev
+ ports:
+ - "${FRONTEND_HOST_PORT:-15723}:5173"
+ volumes:
+ - ./react-scss:/app
+ - frontend_modules:/app/node_modules
+ environment:
+ - VITE_API_URL=${VITE_API_URL:-/api}
+ - VITE_APP_TITLE=${VITE_APP_TITLE:-My App}
+ networks:
+ - app
+ restart: unless-stopped
+
+networks:
+ app:
+ driver: bridge
+
+volumes:
+ frontend_modules:
diff --git a/frontends/open/infra/docker/vite.dev b/frontends/open/infra/docker/vite.dev
new file mode 100644
index 0000000..2fafe7f
--- /dev/null
+++ b/frontends/open/infra/docker/vite.dev
@@ -0,0 +1,25 @@
+# =============================================================================
+# AngelaMos | 2026
+# vite.dev
+# =============================================================================
+# Development Dockerfile for Vite/React frontend
+# Features: pnpm, HMR support, polling for Docker file watching
+# =============================================================================
+# syntax=docker/dockerfile:1
+
+FROM node:22-slim
+
+RUN corepack enable && corepack prepare pnpm@latest --activate
+
+WORKDIR /app
+
+COPY package.json pnpm-lock.yaml* ./
+
+RUN --mount=type=cache,target=/root/.local/share/pnpm/store \
+ pnpm install --frozen-lockfile
+
+COPY . .
+
+EXPOSE 5173
+
+CMD ["pnpm", "dev", "--host", "0.0.0.0"]
diff --git a/frontends/open/infra/docker/vite.prod b/frontends/open/infra/docker/vite.prod
new file mode 100644
index 0000000..48bbf36
--- /dev/null
+++ b/frontends/open/infra/docker/vite.prod
@@ -0,0 +1,59 @@
+# =============================================================================
+# AngelaMos | 2026
+# vite.prod
+# =============================================================================
+# Production Dockerfile: builds Vite app, serves via Nginx
+# =============================================================================
+# syntax=docker/dockerfile:1
+
+# ============================================================================
+# BUILD STAGE
+# ============================================================================
+FROM node:22-slim AS builder
+
+RUN corepack enable && corepack prepare pnpm@latest --activate
+
+WORKDIR /app
+
+COPY react-scss/package.json react-scss/pnpm-lock.yaml* ./
+
+RUN --mount=type=cache,target=/root/.local/share/pnpm/store \
+ pnpm install --frozen-lockfile
+
+COPY react-scss/ .
+
+ARG VITE_API_URL=/api
+ARG VITE_APP_TITLE="My App"
+
+ENV VITE_API_URL=${VITE_API_URL} \
+ VITE_APP_TITLE=${VITE_APP_TITLE}
+
+RUN pnpm build
+
+# ============================================================================
+# PRODUCTION STAGE
+# ============================================================================
+FROM nginx:1.27-alpine AS production
+
+RUN rm -rf /usr/share/nginx/html/* && \
+ rm /etc/nginx/conf.d/default.conf
+
+COPY --from=builder /app/dist /usr/share/nginx/html
+
+COPY --chown=nginx:nginx infra/nginx/nginx.prod.conf /etc/nginx/nginx.conf
+COPY --chown=nginx:nginx infra/nginx/prod.nginx /etc/nginx/conf.d/default.conf
+
+RUN chown -R nginx:nginx /usr/share/nginx/html && \
+ chown -R nginx:nginx /var/cache/nginx && \
+ chown -R nginx:nginx /var/log/nginx && \
+ touch /var/run/nginx.pid && \
+ chown -R nginx:nginx /var/run/nginx.pid
+
+USER nginx
+
+EXPOSE 80
+
+HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
+ CMD wget --no-verbose --tries=1 --spider http://localhost:80/health || exit 1
+
+CMD ["nginx", "-g", "daemon off;"]
diff --git a/frontends/open/infra/nginx/dev.nginx b/frontends/open/infra/nginx/dev.nginx
new file mode 100644
index 0000000..7ea1f6e
--- /dev/null
+++ b/frontends/open/infra/nginx/dev.nginx
@@ -0,0 +1,35 @@
+# =============================================================================
+# AngelaMos | 2026
+# dev.nginx
+# =============================================================================
+# Development server block: proxies to Vite dev server with HMR
+
+server {
+ listen 80;
+ listen [::]:80;
+ server_name _;
+
+ access_log /var/log/nginx/access.log main_timed;
+ error_log /var/log/nginx/error.log debug;
+
+ add_header Cache-Control "no-store, no-cache, must-revalidate" always;
+
+ location /health {
+ access_log off;
+ return 200 "healthy\n";
+ add_header Content-Type text/plain;
+ }
+
+ location / {
+ proxy_pass http://frontend_dev;
+ proxy_http_version 1.1;
+ proxy_set_header Upgrade $http_upgrade;
+ proxy_set_header Connection $connection_upgrade;
+ proxy_set_header Host $host;
+ proxy_set_header X-Real-IP $remote_addr;
+ proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
+
+ proxy_read_timeout 60s;
+ proxy_buffering off;
+ }
+}
diff --git a/frontends/open/infra/nginx/nginx.conf b/frontends/open/infra/nginx/nginx.conf
new file mode 100644
index 0000000..eddade5
--- /dev/null
+++ b/frontends/open/infra/nginx/nginx.conf
@@ -0,0 +1,76 @@
+# AngelaMos | 2026
+# nginx.conf
+# Development nginx configuration
+
+user nginx;
+worker_processes auto;
+worker_rlimit_nofile 65535;
+
+error_log /var/log/nginx/error.log warn;
+pid /var/run/nginx.pid;
+
+events {
+ worker_connections 4096;
+ multi_accept on;
+ use epoll;
+}
+
+http {
+ include /etc/nginx/mime.types;
+ default_type application/octet-stream;
+
+ map $http_upgrade $connection_upgrade {
+ default upgrade;
+ '' close;
+ }
+
+ upstream frontend_dev {
+ server frontend:5173;
+ keepalive 8;
+ }
+
+ limit_req_zone $binary_remote_addr zone=api_limit:10m rate=10r/s;
+ limit_conn_zone $binary_remote_addr zone=conn_limit:10m;
+ limit_req_status 429;
+
+ log_format main_timed '$remote_addr - $remote_user [$time_local] '
+ '"$request" $status $body_bytes_sent '
+ '"$http_referer" "$http_user_agent" '
+ 'rt=$request_time uct="$upstream_connect_time" '
+ 'uht="$upstream_header_time" urt="$upstream_response_time"';
+
+ sendfile on;
+ tcp_nopush on;
+ tcp_nodelay on;
+ keepalive_timeout 65;
+ types_hash_max_size 2048;
+ server_tokens off;
+
+ client_body_buffer_size 128k;
+ client_header_buffer_size 16k;
+ client_max_body_size 10m;
+ large_client_header_buffers 4 16k;
+
+ client_body_timeout 12s;
+ client_header_timeout 12s;
+ send_timeout 10s;
+
+ gzip on;
+ gzip_vary on;
+ gzip_proxied any;
+ gzip_comp_level 6;
+ gzip_min_length 256;
+ gzip_types
+ text/plain
+ text/css
+ text/xml
+ text/javascript
+ application/json
+ application/javascript
+ application/xml+rss
+ application/atom+xml
+ image/svg+xml;
+ gzip_disable "msie6";
+
+ include /etc/nginx/conf.d/*.conf;
+}
diff --git a/frontends/open/infra/nginx/nginx.prod.conf b/frontends/open/infra/nginx/nginx.prod.conf
new file mode 100644
index 0000000..f73ad69
--- /dev/null
+++ b/frontends/open/infra/nginx/nginx.prod.conf
@@ -0,0 +1,65 @@
+# AngelaMos | 2026
+# nginx.prod.conf
+# Production nginx configuration
+
+worker_processes auto;
+worker_rlimit_nofile 65535;
+
+error_log /var/log/nginx/error.log warn;
+pid /var/run/nginx.pid;
+
+events {
+ worker_connections 4096;
+ multi_accept on;
+ use epoll;
+}
+
+http {
+ include /etc/nginx/mime.types;
+ default_type application/octet-stream;
+
+ limit_req_zone $binary_remote_addr zone=api_limit:10m rate=10r/s;
+ limit_conn_zone $binary_remote_addr zone=conn_limit:10m;
+ limit_req_status 429;
+
+ log_format main_timed '$remote_addr - $remote_user [$time_local] '
+ '"$request" $status $body_bytes_sent '
+ '"$http_referer" "$http_user_agent" '
+ 'rt=$request_time uct="$upstream_connect_time" '
+ 'uht="$upstream_header_time" urt="$upstream_response_time"';
+
+ sendfile on;
+ tcp_nopush on;
+ tcp_nodelay on;
+ keepalive_timeout 65;
+ types_hash_max_size 2048;
+ server_tokens off;
+
+ client_body_buffer_size 128k;
+ client_header_buffer_size 16k;
+ client_max_body_size 10m;
+ large_client_header_buffers 4 16k;
+
+ client_body_timeout 12s;
+ client_header_timeout 12s;
+ send_timeout 10s;
+
+ gzip on;
+ gzip_vary on;
+ gzip_proxied any;
+ gzip_comp_level 6;
+ gzip_min_length 256;
+ gzip_types
+ text/plain
+ text/css
+ text/xml
+ text/javascript
+ application/json
+ application/javascript
+ application/xml+rss
+ application/atom+xml
+ image/svg+xml;
+ gzip_disable "msie6";
+
+ include /etc/nginx/conf.d/*.conf;
+}
diff --git a/frontends/open/infra/nginx/prod.nginx b/frontends/open/infra/nginx/prod.nginx
new file mode 100644
index 0000000..f6a747e
--- /dev/null
+++ b/frontends/open/infra/nginx/prod.nginx
@@ -0,0 +1,54 @@
+# =============================================================================
+# AngelaMos | 2026
+# prod.nginx
+# =============================================================================
+# Production server block: serves built static files
+# Note: SSL handled by Cloudflare, not here
+
+server {
+ listen 80;
+ listen [::]:80;
+ server_name _;
+
+ root /usr/share/nginx/html;
+ index index.html;
+
+ access_log /var/log/nginx/access.log main_timed buffer=32k flush=5s;
+ error_log /var/log/nginx/error.log warn;
+
+ add_header X-Frame-Options "SAMEORIGIN" always;
+ add_header X-Content-Type-Options "nosniff" always;
+ add_header X-XSS-Protection "1; mode=block" always;
+ add_header Referrer-Policy "strict-origin-when-cross-origin" always;
+ add_header Permissions-Policy "geolocation=(), microphone=(), camera=()" always;
+
+ location /health {
+ access_log off;
+ return 200 "healthy\n";
+ add_header Content-Type text/plain;
+ }
+
+ location /assets/ {
+ expires 1y;
+ add_header Cache-Control "public, immutable";
+ access_log off;
+ try_files $uri =404;
+ }
+
+ location ~* \.(jpg|jpeg|png|gif|ico|svg|webp|avif|woff|woff2|ttf|eot|otf)$ {
+ expires 1y;
+ add_header Cache-Control "public, immutable";
+ access_log off;
+ }
+
+ location / {
+ add_header Cache-Control "no-cache, must-revalidate";
+ try_files $uri $uri/ /index.html;
+ }
+
+ location ~ /\. {
+ deny all;
+ access_log off;
+ log_not_found off;
+ }
+}
diff --git a/frontends/open/justfile b/frontends/open/justfile
new file mode 100644
index 0000000..bb48190
--- /dev/null
+++ b/frontends/open/justfile
@@ -0,0 +1,159 @@
+# =============================================================================
+# AngelaMos | 2026
+# justfile
+# =============================================================================
+
+set dotenv-filename := ".env.development"
+set dotenv-load
+set export
+set shell := ["bash", "-uc"]
+set windows-shell := ["powershell.exe", "-NoLogo", "-Command"]
+
+project := file_name(justfile_directory())
+version := `git describe --tags --always 2>/dev/null || echo "dev"`
+
+# =============================================================================
+# Default
+# =============================================================================
+
+default:
+ @just --list --unsorted
+
+# =============================================================================
+# Frontend Linting
+# =============================================================================
+
+[group('lint')]
+biome *ARGS:
+ cd react-scss && pnpm biome check . {{ARGS}}
+
+[group('lint')]
+biome-fix:
+ cd react-scss && pnpm biome check --write .
+
+[group('lint')]
+stylelint *ARGS:
+ cd react-scss && pnpm stylelint '**/*.scss' {{ARGS}}
+
+[group('lint')]
+stylelint-fix:
+ cd react-scss && pnpm stylelint '**/*.scss' --fix
+
+[group('lint')]
+tsc *ARGS:
+ cd react-scss && pnpm tsc --noEmit {{ARGS}}
+
+# =============================================================================
+# Docker Compose (Production)
+# =============================================================================
+
+[group('prod')]
+up *ARGS:
+ docker compose --env-file .env up {{ARGS}}
+
+[group('prod')]
+start *ARGS:
+ docker compose --env-file .env up -d {{ARGS}}
+
+[group('prod')]
+down *ARGS:
+ docker compose --env-file .env down {{ARGS}}
+
+[group('prod')]
+stop:
+ docker compose --env-file .env stop
+
+[group('prod')]
+build *ARGS:
+ docker compose --env-file .env build {{ARGS}}
+
+[group('prod')]
+rebuild:
+ docker compose --env-file .env build --no-cache
+
+[group('prod')]
+logs *SERVICE:
+ docker compose --env-file .env logs -f {{SERVICE}}
+
+[group('prod')]
+ps:
+ docker compose --env-file .env ps
+
+# =============================================================================
+# Docker Compose (Production + Cloudflare Tunnel)
+# =============================================================================
+
+[group('tunnel')]
+tunnel-up *ARGS:
+ docker compose --env-file .env -f compose.yml -f cloudflared.compose.yml up {{ARGS}}
+
+[group('tunnel')]
+tunnel-start *ARGS:
+ docker compose --env-file .env -f compose.yml -f cloudflared.compose.yml up -d {{ARGS}}
+
+[group('tunnel')]
+tunnel-down *ARGS:
+ docker compose --env-file .env -f compose.yml -f cloudflared.compose.yml down {{ARGS}}
+
+[group('tunnel')]
+tunnel-logs:
+ docker compose --env-file .env -f compose.yml -f cloudflared.compose.yml logs -f cloudflared
+
+# =============================================================================
+# Docker Compose (Development)
+# =============================================================================
+
+[group('dev')]
+dev-up *ARGS:
+ docker compose -f dev.compose.yml up {{ARGS}}
+
+[group('dev')]
+dev-start *ARGS:
+ docker compose -f dev.compose.yml up -d {{ARGS}}
+
+[group('dev')]
+dev-down *ARGS:
+ docker compose -f dev.compose.yml down {{ARGS}}
+
+[group('dev')]
+dev-stop:
+ docker compose -f dev.compose.yml stop
+
+[group('dev')]
+dev-build *ARGS:
+ docker compose -f dev.compose.yml build {{ARGS}}
+
+[group('dev')]
+dev-rebuild:
+ docker compose -f dev.compose.yml build --no-cache
+
+[group('dev')]
+dev-logs *SERVICE:
+ docker compose -f dev.compose.yml logs -f {{SERVICE}}
+
+[group('dev')]
+dev-ps:
+ docker compose -f dev.compose.yml ps
+
+# =============================================================================
+# Utilities
+# =============================================================================
+
+[group('util')]
+init:
+ bash scripts/init.sh
+
+[group('util')]
+ports:
+ bash scripts/randomize-ports.sh
+
+[group('util')]
+info:
+ @echo "Project: {{project}}"
+ @echo "Version: {{version}}"
+ @echo "OS: {{os()}} ({{arch()}})"
+
+[group('util')]
+clean:
+ -rm -rf react-scss/.biome_cache
+ @echo "Cache directories cleaned"
diff --git a/frontends/open/react-scss/.dockerignore b/frontends/open/react-scss/.dockerignore
new file mode 100644
index 0000000..a0256ec
--- /dev/null
+++ b/frontends/open/react-scss/.dockerignore
@@ -0,0 +1,15 @@
+node_modules
+build
+dist
+.git
+.gitignore
+*.md
+.env*
+.vscode
+.idea
+*.log
+npm-debug.log*
+pnpm-debug.log*
+.DS_Store
+coverage
+.nyc_output
diff --git a/frontends/open/react-scss/.gitignore b/frontends/open/react-scss/.gitignore
new file mode 100644
index 0000000..61cb0c2
--- /dev/null
+++ b/frontends/open/react-scss/.gitignore
@@ -0,0 +1,25 @@
+# Logs
+logs
+*.log
+npm-debug.log*
+yarn-debug.log*
+yarn-error.log*
+pnpm-debug.log*
+lerna-debug.log*
+
+node_modules
+dist
+dist-ssr
+*.local
+.vite
+
+# Editor directories and files
+.vscode/*
+!.vscode/extensions.json
+.idea
+.DS_Store
+*.suo
+*.ntvs*
+*.njsproj
+*.sln
+*.sw?
diff --git a/frontends/open/react-scss/.stylelintignore b/frontends/open/react-scss/.stylelintignore
new file mode 100755
index 0000000..37da03e
--- /dev/null
+++ b/frontends/open/react-scss/.stylelintignore
@@ -0,0 +1,22 @@
+# ©AngelaMos | 2025
+# .stylelintignore
+
+# Dependencies
+node_modules/
+
+# Production builds
+dist/
+build/
+out/
+
+# JS/TS files
+**/*.js
+**/*.jsx
+**/*.ts
+**/*.tsx
+
+# Generated files
+*.min.css
+
+# Error system styles - ignore from linting
+src/core/app/_toastStyles.scss
diff --git a/frontends/open/react-scss/biome.json b/frontends/open/react-scss/biome.json
new file mode 100644
index 0000000..7f29029
--- /dev/null
+++ b/frontends/open/react-scss/biome.json
@@ -0,0 +1,94 @@
+{
+ "$schema": "https://biomejs.dev/schemas/2.3.8/schema.json",
+ "vcs": {
+ "enabled": true,
+ "clientKind": "git",
+ "useIgnoreFile": true
+ },
+ "files": {
+ "includes": ["**/*.ts", "**/*.tsx", "**/*.js", "**/*.jsx", "**/*.json"]
+ },
+ "formatter": {
+ "enabled": true,
+ "indentStyle": "space",
+ "indentWidth": 2,
+ "lineWidth": 82,
+ "lineEnding": "lf"
+ },
+ "javascript": {
+ "formatter": {
+ "quoteStyle": "single",
+ "jsxQuoteStyle": "double",
+ "semicolons": "asNeeded",
+ "trailingCommas": "es5",
+ "arrowParentheses": "always"
+ }
+ },
+ "linter": {
+ "enabled": true,
+ "rules": {
+ "recommended": true,
+ "complexity": {
+ "noExcessiveCognitiveComplexity": {
+ "level": "error",
+ "options": { "maxAllowedComplexity": 25 }
+ },
+ "noForEach": "off",
+ "useLiteralKeys": "off"
+ },
+ "correctness": {
+ "noUnusedVariables": "error",
+ "noUnusedImports": "error",
+ "useExhaustiveDependencies": "warn",
+ "useHookAtTopLevel": "error",
+ "noUndeclaredVariables": "error"
+ },
+ "style": {
+ "useImportType": "error",
+ "useConst": "error",
+ "useTemplate": "error",
+ "useSelfClosingElements": "error",
+ "useFragmentSyntax": "error",
+ "noNonNullAssertion": "error",
+ "useConsistentArrayType": {
+ "level": "error",
+ "options": { "syntax": "shorthand" }
+ },
+ "useNamingConvention": "off"
+ },
+ "suspicious": {
+ "noExplicitAny": "error",
+ "noDebugger": "error",
+ "noConsole": "warn",
+ "noArrayIndexKey": "warn",
+ "noAssignInExpressions": "error",
+ "noDoubleEquals": "error",
+ "noRedeclare": "error",
+ "noVar": "error"
+ },
+ "security": {
+ "noDangerouslySetInnerHtml": "error"
+ },
+ "a11y": {
+ "useAltText": "error",
+ "useAnchorContent": "error",
+ "useKeyWithClickEvents": "error",
+ "noStaticElementInteractions": "error",
+ "useButtonType": "error",
+ "useValidAnchor": "error"
+ }
+ }
+ },
+ "overrides": [
+ {
+ "includes": ["src/main.tsx"],
+ "linter": {
+ "rules": {
+ "style": {
+ "noNonNullAssertion": "off"
+ }
+ }
+ }
+ }
+ ]
+}
diff --git a/frontends/open/react-scss/index.html b/frontends/open/react-scss/index.html
new file mode 100644
index 0000000..6ba30cc
--- /dev/null
+++ b/frontends/open/react-scss/index.html
@@ -0,0 +1,48 @@
+
+
+
+
+
+
+
+
+
+
+ No Auth Template
+
+
+
+
+
+
+
+
diff --git a/frontends/open/react-scss/package.json b/frontends/open/react-scss/package.json
new file mode 100644
index 0000000..88da80f
--- /dev/null
+++ b/frontends/open/react-scss/package.json
@@ -0,0 +1,50 @@
+{
+ "name": "no-auth-template",
+ "private": true,
+ "version": "1.0.0",
+ "type": "module",
+ "scripts": {
+ "dev": "vite",
+ "build": "tsc -b && vite build",
+ "preview": "vite preview",
+ "lint": "biome check .",
+ "lint:fix": "biome check --write .",
+ "format": "biome format --write .",
+ "typecheck": "tsc -b",
+ "lint:scss": "stylelint '**/*.scss'",
+ "lint:scss:fix": "stylelint '**/*.scss' --fix"
+ },
+ "dependencies": {
+ "@tanstack/react-query": "^5.90.12",
+ "axios": "^1.13.0",
+ "react": "^19.2.1",
+ "react-dom": "^19.2.0",
+ "react-error-boundary": "^6.0.0",
+ "react-icon": "^1.0.0",
+ "react-icons": "^5.5.0",
+ "react-router-dom": "^7.1.1",
+ "sonner": "^2.0.7",
+ "zod": "^4.1.13",
+ "zustand": "^5.0.9"
+ },
+ "devDependencies": {
+ "@biomejs/biome": "^2.3.8",
+ "@tanstack/react-query-devtools": "^5.91.1",
+ "@types/node": "^24.10.2",
+ "@types/react": "^19.2.7",
+ "@types/react-dom": "^19.2.3",
+ "@vitejs/plugin-react": "^5.1.1",
+ "sass": "^1.95.0",
+ "stylelint": "^16.26.1",
+ "stylelint-config-prettier-scss": "^1.0.0",
+ "stylelint-config-standard-scss": "^16.0.0",
+ "typescript": "~5.9.3",
+ "vite": "npm:rolldown-vite@7.2.5",
+ "vite-tsconfig-paths": "^5.1.0"
+ },
+ "pnpm": {
+ "overrides": {
+ "vite": "npm:rolldown-vite@7.2.5"
+ }
+ }
+}
diff --git a/frontends/open/react-scss/pnpm-lock.yaml b/frontends/open/react-scss/pnpm-lock.yaml
new file mode 100644
index 0000000..d04a716
--- /dev/null
+++ b/frontends/open/react-scss/pnpm-lock.yaml
@@ -0,0 +1,2603 @@
+lockfileVersion: '9.0'
+
+settings:
+ autoInstallPeers: true
+ excludeLinksFromLockfile: false
+
+overrides:
+ vite: npm:rolldown-vite@7.2.5
+
+importers:
+
+ .:
+ dependencies:
+ '@tanstack/react-query':
+ specifier: ^5.90.12
+ version: 5.90.12(react@19.2.1)
+ axios:
+ specifier: ^1.13.0
+ version: 1.13.2
+ react:
+ specifier: ^19.2.1
+ version: 19.2.1
+ react-dom:
+ specifier: ^19.2.0
+ version: 19.2.1(react@19.2.1)
+ react-error-boundary:
+ specifier: ^6.0.0
+ version: 6.0.0(react@19.2.1)
+ react-icon:
+ specifier: ^1.0.0
+ version: 1.0.0(babel-runtime@5.8.38)(react@19.2.1)
+ react-icons:
+ specifier: ^5.5.0
+ version: 5.5.0(react@19.2.1)
+ react-router-dom:
+ specifier: ^7.1.1
+ version: 7.10.1(react-dom@19.2.1(react@19.2.1))(react@19.2.1)
+ sonner:
+ specifier: ^2.0.7
+ version: 2.0.7(react-dom@19.2.1(react@19.2.1))(react@19.2.1)
+ zod:
+ specifier: ^4.1.13
+ version: 4.1.13
+ zustand:
+ specifier: ^5.0.9
+ version: 5.0.9(@types/react@19.2.7)(react@19.2.1)
+ devDependencies:
+ '@biomejs/biome':
+ specifier: ^2.3.8
+ version: 2.3.8
+ '@tanstack/react-query-devtools':
+ specifier: ^5.91.1
+ version: 5.91.1(@tanstack/react-query@5.90.12(react@19.2.1))(react@19.2.1)
+ '@types/node':
+ specifier: ^24.10.2
+ version: 24.10.2
+ '@types/react':
+ specifier: ^19.2.7
+ version: 19.2.7
+ '@types/react-dom':
+ specifier: ^19.2.3
+ version: 19.2.3(@types/react@19.2.7)
+ '@vitejs/plugin-react':
+ specifier: ^5.1.1
+ version: 5.1.2(rolldown-vite@7.2.5(@types/node@24.10.2)(sass@1.95.0))
+ sass:
+ specifier: ^1.95.0
+ version: 1.95.0
+ stylelint:
+ specifier: ^16.26.1
+ version: 16.26.1(typescript@5.9.3)
+ stylelint-config-prettier-scss:
+ specifier: ^1.0.0
+ version: 1.0.0(stylelint@16.26.1(typescript@5.9.3))
+ stylelint-config-standard-scss:
+ specifier: ^16.0.0
+ version: 16.0.0(postcss@8.5.6)(stylelint@16.26.1(typescript@5.9.3))
+ typescript:
+ specifier: ~5.9.3
+ version: 5.9.3
+ vite:
+ specifier: npm:rolldown-vite@7.2.5
+ version: rolldown-vite@7.2.5(@types/node@24.10.2)(sass@1.95.0)
+ vite-tsconfig-paths:
+ specifier: ^5.1.0
+ version: 5.1.4(rolldown-vite@7.2.5(@types/node@24.10.2)(sass@1.95.0))(typescript@5.9.3)
+
+packages:
+
+ '@babel/code-frame@7.27.1':
+ resolution: {integrity: sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg==}
+ engines: {node: '>=6.9.0'}
+
+ '@babel/compat-data@7.28.5':
+ resolution: {integrity: sha512-6uFXyCayocRbqhZOB+6XcuZbkMNimwfVGFji8CTZnCzOHVGvDqzvitu1re2AU5LROliz7eQPhB8CpAMvnx9EjA==}
+ engines: {node: '>=6.9.0'}
+
+ '@babel/core@7.28.5':
+ resolution: {integrity: sha512-e7jT4DxYvIDLk1ZHmU/m/mB19rex9sv0c2ftBtjSBv+kVM/902eh0fINUzD7UwLLNR+jU585GxUJ8/EBfAM5fw==}
+ engines: {node: '>=6.9.0'}
+
+ '@babel/generator@7.28.5':
+ resolution: {integrity: sha512-3EwLFhZ38J4VyIP6WNtt2kUdW9dokXA9Cr4IVIFHuCpZ3H8/YFOl5JjZHisrn1fATPBmKKqXzDFvh9fUwHz6CQ==}
+ engines: {node: '>=6.9.0'}
+
+ '@babel/helper-compilation-targets@7.27.2':
+ resolution: {integrity: sha512-2+1thGUUWWjLTYTHZWK1n8Yga0ijBz1XAhUXcKy81rd5g6yh7hGqMp45v7cadSbEHc9G3OTv45SyneRN3ps4DQ==}
+ engines: {node: '>=6.9.0'}
+
+ '@babel/helper-globals@7.28.0':
+ resolution: {integrity: sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw==}
+ engines: {node: '>=6.9.0'}
+
+ '@babel/helper-module-imports@7.27.1':
+ resolution: {integrity: sha512-0gSFWUPNXNopqtIPQvlD5WgXYI5GY2kP2cCvoT8kczjbfcfuIljTbcWrulD1CIPIX2gt1wghbDy08yE1p+/r3w==}
+ engines: {node: '>=6.9.0'}
+
+ '@babel/helper-module-transforms@7.28.3':
+ resolution: {integrity: sha512-gytXUbs8k2sXS9PnQptz5o0QnpLL51SwASIORY6XaBKF88nsOT0Zw9szLqlSGQDP/4TljBAD5y98p2U1fqkdsw==}
+ engines: {node: '>=6.9.0'}
+ peerDependencies:
+ '@babel/core': ^7.0.0
+
+ '@babel/helper-plugin-utils@7.27.1':
+ resolution: {integrity: sha512-1gn1Up5YXka3YYAHGKpbideQ5Yjf1tDa9qYcgysz+cNCXukyLl6DjPXhD3VRwSb8c0J9tA4b2+rHEZtc6R0tlw==}
+ engines: {node: '>=6.9.0'}
+
+ '@babel/helper-string-parser@7.27.1':
+ resolution: {integrity: sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==}
+ engines: {node: '>=6.9.0'}
+
+ '@babel/helper-validator-identifier@7.28.5':
+ resolution: {integrity: sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==}
+ engines: {node: '>=6.9.0'}
+
+ '@babel/helper-validator-option@7.27.1':
+ resolution: {integrity: sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==}
+ engines: {node: '>=6.9.0'}
+
+ '@babel/helpers@7.28.4':
+ resolution: {integrity: sha512-HFN59MmQXGHVyYadKLVumYsA9dBFun/ldYxipEjzA4196jpLZd8UjEEBLkbEkvfYreDqJhZxYAWFPtrfhNpj4w==}
+ engines: {node: '>=6.9.0'}
+
+ '@babel/parser@7.28.5':
+ resolution: {integrity: sha512-KKBU1VGYR7ORr3At5HAtUQ+TV3SzRCXmA/8OdDZiLDBIZxVyzXuztPjfLd3BV1PRAQGCMWWSHYhL0F8d5uHBDQ==}
+ engines: {node: '>=6.0.0'}
+ hasBin: true
+
+ '@babel/plugin-transform-react-jsx-self@7.27.1':
+ resolution: {integrity: sha512-6UzkCs+ejGdZ5mFFC/OCUrv028ab2fp1znZmCZjAOBKiBK2jXD1O+BPSfX8X2qjJ75fZBMSnQn3Rq2mrBJK2mw==}
+ engines: {node: '>=6.9.0'}
+ peerDependencies:
+ '@babel/core': ^7.0.0-0
+
+ '@babel/plugin-transform-react-jsx-source@7.27.1':
+ resolution: {integrity: sha512-zbwoTsBruTeKB9hSq73ha66iFeJHuaFkUbwvqElnygoNbj/jHRsSeokowZFN3CZ64IvEqcmmkVe89OPXc7ldAw==}
+ engines: {node: '>=6.9.0'}
+ peerDependencies:
+ '@babel/core': ^7.0.0-0
+
+ '@babel/runtime@7.28.4':
+ resolution: {integrity: sha512-Q/N6JNWvIvPnLDvjlE1OUBLPQHH6l3CltCEsHIujp45zQUSSh8K+gHnaEX45yAT1nyngnINhvWtzN+Nb9D8RAQ==}
+ engines: {node: '>=6.9.0'}
+
+ '@babel/template@7.27.2':
+ resolution: {integrity: sha512-LPDZ85aEJyYSd18/DkjNh4/y1ntkE5KwUHWTiqgRxruuZL2F1yuHligVHLvcHY2vMHXttKFpJn6LwfI7cw7ODw==}
+ engines: {node: '>=6.9.0'}
+
+ '@babel/traverse@7.28.5':
+ resolution: {integrity: sha512-TCCj4t55U90khlYkVV/0TfkJkAkUg3jZFA3Neb7unZT8CPok7iiRfaX0F+WnqWqt7OxhOn0uBKXCw4lbL8W0aQ==}
+ engines: {node: '>=6.9.0'}
+
+ '@babel/types@7.28.5':
+ resolution: {integrity: sha512-qQ5m48eI/MFLQ5PxQj4PFaprjyCTLI37ElWMmNs0K8Lk3dVeOdNpB3ks8jc7yM5CDmVC73eMVk/trk3fgmrUpA==}
+ engines: {node: '>=6.9.0'}
+
+ '@biomejs/biome@2.3.8':
+ resolution: {integrity: sha512-Qjsgoe6FEBxWAUzwFGFrB+1+M8y/y5kwmg5CHac+GSVOdmOIqsAiXM5QMVGZJ1eCUCLlPZtq4aFAQ0eawEUuUA==}
+ engines: {node: '>=14.21.3'}
+ hasBin: true
+
+ '@biomejs/cli-darwin-arm64@2.3.8':
+ resolution: {integrity: sha512-HM4Zg9CGQ3txTPflxD19n8MFPrmUAjaC7PQdLkugeeC0cQ+PiVrd7i09gaBS/11QKsTDBJhVg85CEIK9f50Qww==}
+ engines: {node: '>=14.21.3'}
+ cpu: [arm64]
+ os: [darwin]
+
+ '@biomejs/cli-darwin-x64@2.3.8':
+ resolution: {integrity: sha512-lUDQ03D7y/qEao7RgdjWVGCu+BLYadhKTm40HkpJIi6kn8LSv5PAwRlew/DmwP4YZ9ke9XXoTIQDO1vAnbRZlA==}
+ engines: {node: '>=14.21.3'}
+ cpu: [x64]
+ os: [darwin]
+
+ '@biomejs/cli-linux-arm64-musl@2.3.8':
+ resolution: {integrity: sha512-PShR4mM0sjksUMyxbyPNMxoKFPVF48fU8Qe8Sfx6w6F42verbwRLbz+QiKNiDPRJwUoMG1nPM50OBL3aOnTevA==}
+ engines: {node: '>=14.21.3'}
+ cpu: [arm64]
+ os: [linux]
+
+ '@biomejs/cli-linux-arm64@2.3.8':
+ resolution: {integrity: sha512-Uo1OJnIkJgSgF+USx970fsM/drtPcQ39I+JO+Fjsaa9ZdCN1oysQmy6oAGbyESlouz+rzEckLTF6DS7cWse95g==}
+ engines: {node: '>=14.21.3'}
+ cpu: [arm64]
+ os: [linux]
+
+ '@biomejs/cli-linux-x64-musl@2.3.8':
+ resolution: {integrity: sha512-YGLkqU91r1276uwSjiUD/xaVikdxgV1QpsicT0bIA1TaieM6E5ibMZeSyjQ/izBn4tKQthUSsVZacmoJfa3pDA==}
+ engines: {node: '>=14.21.3'}
+ cpu: [x64]
+ os: [linux]
+
+ '@biomejs/cli-linux-x64@2.3.8':
+ resolution: {integrity: sha512-QDPMD5bQz6qOVb3kiBui0zKZXASLo0NIQ9JVJio5RveBEFgDgsvJFUvZIbMbUZT3T00M/1wdzwWXk4GIh0KaAw==}
+ engines: {node: '>=14.21.3'}
+ cpu: [x64]
+ os: [linux]
+
+ '@biomejs/cli-win32-arm64@2.3.8':
+ resolution: {integrity: sha512-H4IoCHvL1fXKDrTALeTKMiE7GGWFAraDwBYFquE/L/5r1927Te0mYIGseXi4F+lrrwhSWbSGt5qPFswNoBaCxg==}
+ engines: {node: '>=14.21.3'}
+ cpu: [arm64]
+ os: [win32]
+
+ '@biomejs/cli-win32-x64@2.3.8':
+ resolution: {integrity: sha512-RguzimPoZWtBapfKhKjcWXBVI91tiSprqdBYu7tWhgN8pKRZhw24rFeNZTNf6UiBfjCYCi9eFQs/JzJZIhuK4w==}
+ engines: {node: '>=14.21.3'}
+ cpu: [x64]
+ os: [win32]
+
+ '@cacheable/memory@2.0.6':
+ resolution: {integrity: sha512-7e8SScMocHxcAb8YhtkbMhGG+EKLRIficb1F5sjvhSYsWTZGxvg4KIDp8kgxnV2PUJ3ddPe6J9QESjKvBWRDkg==}
+
+ '@cacheable/utils@2.3.2':
+ resolution: {integrity: sha512-8kGE2P+HjfY8FglaOiW+y8qxcaQAfAhVML+i66XJR3YX5FtyDqn6Txctr3K2FrbxLKixRRYYBWMbuGciOhYNDg==}
+
+ '@csstools/css-parser-algorithms@3.0.5':
+ resolution: {integrity: sha512-DaDeUkXZKjdGhgYaHNJTV9pV7Y9B3b644jCLs9Upc3VeNGg6LWARAT6O+Q+/COo+2gg/bM5rhpMAtf70WqfBdQ==}
+ engines: {node: '>=18'}
+ peerDependencies:
+ '@csstools/css-tokenizer': ^3.0.4
+
+ '@csstools/css-syntax-patches-for-csstree@1.0.20':
+ resolution: {integrity: sha512-8BHsjXfSciZxjmHQOuVdW2b8WLUPts9a+mfL13/PzEviufUEW2xnvQuOlKs9dRBHgRqJ53SF/DUoK9+MZk72oQ==}
+ engines: {node: '>=18'}
+
+ '@csstools/css-tokenizer@3.0.4':
+ resolution: {integrity: sha512-Vd/9EVDiu6PPJt9yAh6roZP6El1xHrdvIVGjyBsHR0RYwNHgL7FJPyIIW4fANJNG6FtyZfvlRPpFI4ZM/lubvw==}
+ engines: {node: '>=18'}
+
+ '@csstools/media-query-list-parser@4.0.3':
+ resolution: {integrity: sha512-HAYH7d3TLRHDOUQK4mZKf9k9Ph/m8Akstg66ywKR4SFAigjs3yBiUeZtFxywiTm5moZMAp/5W/ZuFnNXXYLuuQ==}
+ engines: {node: '>=18'}
+ peerDependencies:
+ '@csstools/css-parser-algorithms': ^3.0.5
+ '@csstools/css-tokenizer': ^3.0.4
+
+ '@csstools/selector-specificity@5.0.0':
+ resolution: {integrity: sha512-PCqQV3c4CoVm3kdPhyeZ07VmBRdH2EpMFA/pd9OASpOEC3aXNGoqPDAZ80D0cLpMBxnmk0+yNhGsEx31hq7Gtw==}
+ engines: {node: '>=18'}
+ peerDependencies:
+ postcss-selector-parser: ^7.0.0
+
+ '@dual-bundle/import-meta-resolve@4.2.1':
+ resolution: {integrity: sha512-id+7YRUgoUX6CgV0DtuhirQWodeeA7Lf4i2x71JS/vtA5pRb/hIGWlw+G6MeXvsM+MXrz0VAydTGElX1rAfgPg==}
+
+ '@emnapi/core@1.7.1':
+ resolution: {integrity: sha512-o1uhUASyo921r2XtHYOHy7gdkGLge8ghBEQHMWmyJFoXlpU58kIrhhN3w26lpQb6dspetweapMn2CSNwQ8I4wg==}
+
+ '@emnapi/runtime@1.7.1':
+ resolution: {integrity: sha512-PVtJr5CmLwYAU9PZDMITZoR5iAOShYREoR45EyyLrbntV50mdePTgUn4AmOw90Ifcj+x2kRjdzr1HP3RrNiHGA==}
+
+ '@emnapi/wasi-threads@1.1.0':
+ resolution: {integrity: sha512-WI0DdZ8xFSbgMjR1sFsKABJ/C5OnRrjT06JXbZKexJGrDuPTzZdDYfFlsgcCXCyf+suG5QU2e/y1Wo2V/OapLQ==}
+
+ '@jridgewell/gen-mapping@0.3.13':
+ resolution: {integrity: sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==}
+
+ '@jridgewell/remapping@2.3.5':
+ resolution: {integrity: sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==}
+
+ '@jridgewell/resolve-uri@3.1.2':
+ resolution: {integrity: sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==}
+ engines: {node: '>=6.0.0'}
+
+ '@jridgewell/sourcemap-codec@1.5.5':
+ resolution: {integrity: sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==}
+
+ '@jridgewell/trace-mapping@0.3.31':
+ resolution: {integrity: sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==}
+
+ '@keyv/bigmap@1.3.0':
+ resolution: {integrity: sha512-KT01GjzV6AQD5+IYrcpoYLkCu1Jod3nau1Z7EsEuViO3TZGRacSbO9MfHmbJ1WaOXFtWLxPVj169cn2WNKPkIg==}
+ engines: {node: '>= 18'}
+ peerDependencies:
+ keyv: ^5.5.4
+
+ '@keyv/serialize@1.1.1':
+ resolution: {integrity: sha512-dXn3FZhPv0US+7dtJsIi2R+c7qWYiReoEh5zUntWCf4oSpMNib8FDhSoed6m3QyZdx5hK7iLFkYk3rNxwt8vTA==}
+
+ '@napi-rs/wasm-runtime@1.1.0':
+ resolution: {integrity: sha512-Fq6DJW+Bb5jaWE69/qOE0D1TUN9+6uWhCeZpdnSBk14pjLcCWR7Q8n49PTSPHazM37JqrsdpEthXy2xn6jWWiA==}
+
+ '@nodelib/fs.scandir@2.1.5':
+ resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==}
+ engines: {node: '>= 8'}
+
+ '@nodelib/fs.stat@2.0.5':
+ resolution: {integrity: sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==}
+ engines: {node: '>= 8'}
+
+ '@nodelib/fs.walk@1.2.8':
+ resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==}
+ engines: {node: '>= 8'}
+
+ '@oxc-project/runtime@0.97.0':
+ resolution: {integrity: sha512-yH0zw7z+jEws4dZ4IUKoix5Lh3yhqIJWF9Dc8PWvhpo7U7O+lJrv7ZZL4BeRO0la8LBQFwcCewtLBnVV7hPe/w==}
+ engines: {node: ^20.19.0 || >=22.12.0}
+
+ '@oxc-project/types@0.97.0':
+ resolution: {integrity: sha512-lxmZK4xFrdvU0yZiDwgVQTCvh2gHWBJCBk5ALsrtsBWhs0uDIi+FTOnXRQeQfs304imdvTdaakT/lqwQ8hkOXQ==}
+
+ '@parcel/watcher-android-arm64@2.5.1':
+ resolution: {integrity: sha512-KF8+j9nNbUN8vzOFDpRMsaKBHZ/mcjEjMToVMJOhTozkDonQFFrRcfdLWn6yWKCmJKmdVxSgHiYvTCef4/qcBA==}
+ engines: {node: '>= 10.0.0'}
+ cpu: [arm64]
+ os: [android]
+
+ '@parcel/watcher-darwin-arm64@2.5.1':
+ resolution: {integrity: sha512-eAzPv5osDmZyBhou8PoF4i6RQXAfeKL9tjb3QzYuccXFMQU0ruIc/POh30ePnaOyD1UXdlKguHBmsTs53tVoPw==}
+ engines: {node: '>= 10.0.0'}
+ cpu: [arm64]
+ os: [darwin]
+
+ '@parcel/watcher-darwin-x64@2.5.1':
+ resolution: {integrity: sha512-1ZXDthrnNmwv10A0/3AJNZ9JGlzrF82i3gNQcWOzd7nJ8aj+ILyW1MTxVk35Db0u91oD5Nlk9MBiujMlwmeXZg==}
+ engines: {node: '>= 10.0.0'}
+ cpu: [x64]
+ os: [darwin]
+
+ '@parcel/watcher-freebsd-x64@2.5.1':
+ resolution: {integrity: sha512-SI4eljM7Flp9yPuKi8W0ird8TI/JK6CSxju3NojVI6BjHsTyK7zxA9urjVjEKJ5MBYC+bLmMcbAWlZ+rFkLpJQ==}
+ engines: {node: '>= 10.0.0'}
+ cpu: [x64]
+ os: [freebsd]
+
+ '@parcel/watcher-linux-arm-glibc@2.5.1':
+ resolution: {integrity: sha512-RCdZlEyTs8geyBkkcnPWvtXLY44BCeZKmGYRtSgtwwnHR4dxfHRG3gR99XdMEdQ7KeiDdasJwwvNSF5jKtDwdA==}
+ engines: {node: '>= 10.0.0'}
+ cpu: [arm]
+ os: [linux]
+
+ '@parcel/watcher-linux-arm-musl@2.5.1':
+ resolution: {integrity: sha512-6E+m/Mm1t1yhB8X412stiKFG3XykmgdIOqhjWj+VL8oHkKABfu/gjFj8DvLrYVHSBNC+/u5PeNrujiSQ1zwd1Q==}
+ engines: {node: '>= 10.0.0'}
+ cpu: [arm]
+ os: [linux]
+
+ '@parcel/watcher-linux-arm64-glibc@2.5.1':
+ resolution: {integrity: sha512-LrGp+f02yU3BN9A+DGuY3v3bmnFUggAITBGriZHUREfNEzZh/GO06FF5u2kx8x+GBEUYfyTGamol4j3m9ANe8w==}
+ engines: {node: '>= 10.0.0'}
+ cpu: [arm64]
+ os: [linux]
+
+ '@parcel/watcher-linux-arm64-musl@2.5.1':
+ resolution: {integrity: sha512-cFOjABi92pMYRXS7AcQv9/M1YuKRw8SZniCDw0ssQb/noPkRzA+HBDkwmyOJYp5wXcsTrhxO0zq1U11cK9jsFg==}
+ engines: {node: '>= 10.0.0'}
+ cpu: [arm64]
+ os: [linux]
+
+ '@parcel/watcher-linux-x64-glibc@2.5.1':
+ resolution: {integrity: sha512-GcESn8NZySmfwlTsIur+49yDqSny2IhPeZfXunQi48DMugKeZ7uy1FX83pO0X22sHntJ4Ub+9k34XQCX+oHt2A==}
+ engines: {node: '>= 10.0.0'}
+ cpu: [x64]
+ os: [linux]
+
+ '@parcel/watcher-linux-x64-musl@2.5.1':
+ resolution: {integrity: sha512-n0E2EQbatQ3bXhcH2D1XIAANAcTZkQICBPVaxMeaCVBtOpBZpWJuf7LwyWPSBDITb7In8mqQgJ7gH8CILCURXg==}
+ engines: {node: '>= 10.0.0'}
+ cpu: [x64]
+ os: [linux]
+
+ '@parcel/watcher-win32-arm64@2.5.1':
+ resolution: {integrity: sha512-RFzklRvmc3PkjKjry3hLF9wD7ppR4AKcWNzH7kXR7GUe0Igb3Nz8fyPwtZCSquGrhU5HhUNDr/mKBqj7tqA2Vw==}
+ engines: {node: '>= 10.0.0'}
+ cpu: [arm64]
+ os: [win32]
+
+ '@parcel/watcher-win32-ia32@2.5.1':
+ resolution: {integrity: sha512-c2KkcVN+NJmuA7CGlaGD1qJh1cLfDnQsHjE89E60vUEMlqduHGCdCLJCID5geFVM0dOtA3ZiIO8BoEQmzQVfpQ==}
+ engines: {node: '>= 10.0.0'}
+ cpu: [ia32]
+ os: [win32]
+
+ '@parcel/watcher-win32-x64@2.5.1':
+ resolution: {integrity: sha512-9lHBdJITeNR++EvSQVUcaZoWupyHfXe1jZvGZ06O/5MflPcuPLtEphScIBL+AiCWBO46tDSHzWyD0uDmmZqsgA==}
+ engines: {node: '>= 10.0.0'}
+ cpu: [x64]
+ os: [win32]
+
+ '@parcel/watcher@2.5.1':
+ resolution: {integrity: sha512-dfUnCxiN9H4ap84DvD2ubjw+3vUNpstxa0TneY/Paat8a3R4uQZDLSvWjmznAY/DoahqTHl9V46HF/Zs3F29pg==}
+ engines: {node: '>= 10.0.0'}
+
+ '@rolldown/binding-android-arm64@1.0.0-beta.50':
+ resolution: {integrity: sha512-XlEkrOIHLyGT3avOgzfTFSjG+f+dZMw+/qd+Y3HLN86wlndrB/gSimrJCk4gOhr1XtRtEKfszpadI3Md4Z4/Ag==}
+ engines: {node: ^20.19.0 || >=22.12.0}
+ cpu: [arm64]
+ os: [android]
+
+ '@rolldown/binding-darwin-arm64@1.0.0-beta.50':
+ resolution: {integrity: sha512-+JRqKJhoFlt5r9q+DecAGPLZ5PxeLva+wCMtAuoFMWPoZzgcYrr599KQ+Ix0jwll4B4HGP43avu9My8KtSOR+w==}
+ engines: {node: ^20.19.0 || >=22.12.0}
+ cpu: [arm64]
+ os: [darwin]
+
+ '@rolldown/binding-darwin-x64@1.0.0-beta.50':
+ resolution: {integrity: sha512-fFXDjXnuX7/gQZQm/1FoivVtRcyAzdjSik7Eo+9iwPQ9EgtA5/nB2+jmbzaKtMGG3q+BnZbdKHCtOacmNrkIDA==}
+ engines: {node: ^20.19.0 || >=22.12.0}
+ cpu: [x64]
+ os: [darwin]
+
+ '@rolldown/binding-freebsd-x64@1.0.0-beta.50':
+ resolution: {integrity: sha512-F1b6vARy49tjmT/hbloplzgJS7GIvwWZqt+tAHEstCh0JIh9sa8FAMVqEmYxDviqKBaAI8iVvUREm/Kh/PD26Q==}
+ engines: {node: ^20.19.0 || >=22.12.0}
+ cpu: [x64]
+ os: [freebsd]
+
+ '@rolldown/binding-linux-arm-gnueabihf@1.0.0-beta.50':
+ resolution: {integrity: sha512-U6cR76N8T8M6lHj7EZrQ3xunLPxSvYYxA8vJsBKZiFZkT8YV4kjgCO3KwMJL0NOjQCPGKyiXO07U+KmJzdPGRw==}
+ engines: {node: ^20.19.0 || >=22.12.0}
+ cpu: [arm]
+ os: [linux]
+
+ '@rolldown/binding-linux-arm64-gnu@1.0.0-beta.50':
+ resolution: {integrity: sha512-ONgyjofCrrE3bnh5GZb8EINSFyR/hmwTzZ7oVuyUB170lboza1VMCnb8jgE6MsyyRgHYmN8Lb59i3NKGrxrYjw==}
+ engines: {node: ^20.19.0 || >=22.12.0}
+ cpu: [arm64]
+ os: [linux]
+
+ '@rolldown/binding-linux-arm64-musl@1.0.0-beta.50':
+ resolution: {integrity: sha512-L0zRdH2oDPkmB+wvuTl+dJbXCsx62SkqcEqdM+79LOcB+PxbAxxjzHU14BuZIQdXcAVDzfpMfaHWzZuwhhBTcw==}
+ engines: {node: ^20.19.0 || >=22.12.0}
+ cpu: [arm64]
+ os: [linux]
+
+ '@rolldown/binding-linux-x64-gnu@1.0.0-beta.50':
+ resolution: {integrity: sha512-gyoI8o/TGpQd3OzkJnh1M2kxy1Bisg8qJ5Gci0sXm9yLFzEXIFdtc4EAzepxGvrT2ri99ar5rdsmNG0zP0SbIg==}
+ engines: {node: ^20.19.0 || >=22.12.0}
+ cpu: [x64]
+ os: [linux]
+
+ '@rolldown/binding-linux-x64-musl@1.0.0-beta.50':
+ resolution: {integrity: sha512-zti8A7M+xFDpKlghpcCAzyOi+e5nfUl3QhU023ce5NCgUxRG5zGP2GR9LTydQ1rnIPwZUVBWd4o7NjZDaQxaXA==}
+ engines: {node: ^20.19.0 || >=22.12.0}
+ cpu: [x64]
+ os: [linux]
+
+ '@rolldown/binding-openharmony-arm64@1.0.0-beta.50':
+ resolution: {integrity: sha512-eZUssog7qljrrRU9Mi0eqYEPm3Ch0UwB+qlWPMKSUXHNqhm3TvDZarJQdTevGEfu3EHAXJvBIe0YFYr0TPVaMA==}
+ engines: {node: ^20.19.0 || >=22.12.0}
+ cpu: [arm64]
+ os: [openharmony]
+
+ '@rolldown/binding-wasm32-wasi@1.0.0-beta.50':
+ resolution: {integrity: sha512-nmCN0nIdeUnmgeDXiQ+2HU6FT162o+rxnF7WMkBm4M5Ds8qTU7Dzv2Wrf22bo4ftnlrb2hKK6FSwAJSAe2FWLg==}
+ engines: {node: '>=14.0.0'}
+ cpu: [wasm32]
+
+ '@rolldown/binding-win32-arm64-msvc@1.0.0-beta.50':
+ resolution: {integrity: sha512-7kcNLi7Ua59JTTLvbe1dYb028QEPaJPJQHqkmSZ5q3tJueUeb6yjRtx8mw4uIqgWZcnQHAR3PrLN4XRJxvgIkA==}
+ engines: {node: ^20.19.0 || >=22.12.0}
+ cpu: [arm64]
+ os: [win32]
+
+ '@rolldown/binding-win32-ia32-msvc@1.0.0-beta.50':
+ resolution: {integrity: sha512-lL70VTNvSCdSZkDPPVMwWn/M2yQiYvSoXw9hTLgdIWdUfC3g72UaruezusR6ceRuwHCY1Ayu2LtKqXkBO5LIwg==}
+ engines: {node: ^20.19.0 || >=22.12.0}
+ cpu: [ia32]
+ os: [win32]
+
+ '@rolldown/binding-win32-x64-msvc@1.0.0-beta.50':
+ resolution: {integrity: sha512-4qU4x5DXWB4JPjyTne/wBNPqkbQU8J45bl21geERBKtEittleonioACBL1R0PsBu0Aq21SwMK5a9zdBkWSlQtQ==}
+ engines: {node: ^20.19.0 || >=22.12.0}
+ cpu: [x64]
+ os: [win32]
+
+ '@rolldown/pluginutils@1.0.0-beta.50':
+ resolution: {integrity: sha512-5e76wQiQVeL1ICOZVUg4LSOVYg9jyhGCin+icYozhsUzM+fHE7kddi1bdiE0jwVqTfkjba3jUFbEkoC9WkdvyA==}
+
+ '@rolldown/pluginutils@1.0.0-beta.53':
+ resolution: {integrity: sha512-vENRlFU4YbrwVqNDZ7fLvy+JR1CRkyr01jhSiDpE1u6py3OMzQfztQU2jxykW3ALNxO4kSlqIDeYyD0Y9RcQeQ==}
+
+ '@tanstack/query-core@5.90.12':
+ resolution: {integrity: sha512-T1/8t5DhV/SisWjDnaiU2drl6ySvsHj1bHBCWNXd+/T+Hh1cf6JodyEYMd5sgwm+b/mETT4EV3H+zCVczCU5hg==}
+
+ '@tanstack/query-devtools@5.91.1':
+ resolution: {integrity: sha512-l8bxjk6BMsCaVQH6NzQEE/bEgFy1hAs5qbgXl0xhzezlaQbPk6Mgz9BqEg2vTLPOHD8N4k+w/gdgCbEzecGyNg==}
+
+ '@tanstack/react-query-devtools@5.91.1':
+ resolution: {integrity: sha512-tRnJYwEbH0kAOuToy8Ew7bJw1lX3AjkkgSlf/vzb+NpnqmHPdWM+lA2DSdGQSLi1SU0PDRrrCI1vnZnci96CsQ==}
+ peerDependencies:
+ '@tanstack/react-query': ^5.90.10
+ react: ^18 || ^19
+
+ '@tanstack/react-query@5.90.12':
+ resolution: {integrity: sha512-graRZspg7EoEaw0a8faiUASCyJrqjKPdqJ9EwuDRUF9mEYJ1YPczI9H+/agJ0mOJkPCJDk0lsz5QTrLZ/jQ2rg==}
+ peerDependencies:
+ react: ^18 || ^19
+
+ '@tybys/wasm-util@0.10.1':
+ resolution: {integrity: sha512-9tTaPJLSiejZKx+Bmog4uSubteqTvFrVrURwkmHixBo0G4seD0zUxp98E1DzUBJxLQ3NPwXrGKDiVjwx/DpPsg==}
+
+ '@types/babel__core@7.20.5':
+ resolution: {integrity: sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==}
+
+ '@types/babel__generator@7.27.0':
+ resolution: {integrity: sha512-ufFd2Xi92OAVPYsy+P4n7/U7e68fex0+Ee8gSG9KX7eo084CWiQ4sdxktvdl0bOPupXtVJPY19zk6EwWqUQ8lg==}
+
+ '@types/babel__template@7.4.4':
+ resolution: {integrity: sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==}
+
+ '@types/babel__traverse@7.28.0':
+ resolution: {integrity: sha512-8PvcXf70gTDZBgt9ptxJ8elBeBjcLOAcOtoO/mPJjtji1+CdGbHgm77om1GrsPxsiE+uXIpNSK64UYaIwQXd4Q==}
+
+ '@types/node@24.10.2':
+ resolution: {integrity: sha512-WOhQTZ4G8xZ1tjJTvKOpyEVSGgOTvJAfDK3FNFgELyaTpzhdgHVHeqW8V+UJvzF5BT+/B54T/1S2K6gd9c7bbA==}
+
+ '@types/react-dom@19.2.3':
+ resolution: {integrity: sha512-jp2L/eY6fn+KgVVQAOqYItbF0VY/YApe5Mz2F0aykSO8gx31bYCZyvSeYxCHKvzHG5eZjc+zyaS5BrBWya2+kQ==}
+ peerDependencies:
+ '@types/react': ^19.2.0
+
+ '@types/react@19.2.7':
+ resolution: {integrity: sha512-MWtvHrGZLFttgeEj28VXHxpmwYbor/ATPYbBfSFZEIRK0ecCFLl2Qo55z52Hss+UV9CRN7trSeq1zbgx7YDWWg==}
+
+ '@vitejs/plugin-react@5.1.2':
+ resolution: {integrity: sha512-EcA07pHJouywpzsoTUqNh5NwGayl2PPVEJKUSinGGSxFGYn+shYbqMGBg6FXDqgXum9Ou/ecb+411ssw8HImJQ==}
+ engines: {node: ^20.19.0 || >=22.12.0}
+ peerDependencies:
+ vite: ^4.2.0 || ^5.0.0 || ^6.0.0 || ^7.0.0
+
+ ajv@8.17.1:
+ resolution: {integrity: sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==}
+
+ ansi-regex@5.0.1:
+ resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==}
+ engines: {node: '>=8'}
+
+ ansi-styles@4.3.0:
+ resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==}
+ engines: {node: '>=8'}
+
+ argparse@2.0.1:
+ resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==}
+
+ array-union@2.1.0:
+ resolution: {integrity: sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==}
+ engines: {node: '>=8'}
+
+ astral-regex@2.0.0:
+ resolution: {integrity: sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==}
+ engines: {node: '>=8'}
+
+ asynckit@0.4.0:
+ resolution: {integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==}
+
+ axios@1.13.2:
+ resolution: {integrity: sha512-VPk9ebNqPcy5lRGuSlKx752IlDatOjT9paPlm8A7yOuW2Fbvp4X3JznJtT4f0GzGLLiWE9W8onz51SqLYwzGaA==}
+
+ babel-runtime@5.8.38:
+ resolution: {integrity: sha512-KpgoA8VE/pMmNCrnEeeXqFG24TIH11Z3ZaimIhJWsin8EbfZy3WzFKUTIan10ZIDgRVvi9EkLbruJElJC9dRlg==}
+
+ balanced-match@2.0.0:
+ resolution: {integrity: sha512-1ugUSr8BHXRnK23KfuYS+gVMC3LB8QGH9W1iGtDPsNWoQbgtXSExkBu2aDR4epiGWZOjZsj6lDl/N/AqqTC3UA==}
+
+ baseline-browser-mapping@2.9.5:
+ resolution: {integrity: sha512-D5vIoztZOq1XM54LUdttJVc96ggEsIfju2JBvht06pSzpckp3C7HReun67Bghzrtdsq9XdMGbSSB3v3GhMNmAA==}
+ hasBin: true
+
+ braces@3.0.3:
+ resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==}
+ engines: {node: '>=8'}
+
+ browserslist@4.28.1:
+ resolution: {integrity: sha512-ZC5Bd0LgJXgwGqUknZY/vkUQ04r8NXnJZ3yYi4vDmSiZmC/pdSN0NbNRPxZpbtO4uAfDUAFffO8IZoM3Gj8IkA==}
+ engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7}
+ hasBin: true
+
+ cacheable@2.3.0:
+ resolution: {integrity: sha512-HHiAvOBmlcR2f3SQ7kdlYD8+AUJG+wlFZ/Ze8tl1Vzvz0MdOh8IYA/EFU4ve8t1/sZ0j4MGi7ST5MoTwHessQA==}
+
+ call-bind-apply-helpers@1.0.2:
+ resolution: {integrity: sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==}
+ engines: {node: '>= 0.4'}
+
+ callsites@3.1.0:
+ resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==}
+ engines: {node: '>=6'}
+
+ caniuse-lite@1.0.30001759:
+ resolution: {integrity: sha512-Pzfx9fOKoKvevQf8oCXoyNRQ5QyxJj+3O0Rqx2V5oxT61KGx8+n6hV/IUyJeifUci2clnmmKVpvtiqRzgiWjSw==}
+
+ chokidar@4.0.3:
+ resolution: {integrity: sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==}
+ engines: {node: '>= 14.16.0'}
+
+ color-convert@2.0.1:
+ resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==}
+ engines: {node: '>=7.0.0'}
+
+ color-name@1.1.4:
+ resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==}
+
+ colord@2.9.3:
+ resolution: {integrity: sha512-jeC1axXpnb0/2nn/Y1LPuLdgXBLH7aDcHu4KEKfqw3CUhX7ZpfBSlPKyqXE6btIgEzfWtrX3/tyBCaCvXvMkOw==}
+
+ combined-stream@1.0.8:
+ resolution: {integrity: sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==}
+ engines: {node: '>= 0.8'}
+
+ convert-source-map@2.0.0:
+ resolution: {integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==}
+
+ cookie@1.1.1:
+ resolution: {integrity: sha512-ei8Aos7ja0weRpFzJnEA9UHJ/7XQmqglbRwnf2ATjcB9Wq874VKH9kfjjirM6UhU2/E5fFYadylyhFldcqSidQ==}
+ engines: {node: '>=18'}
+
+ core-js@1.2.7:
+ resolution: {integrity: sha512-ZiPp9pZlgxpWRu0M+YWbm6+aQ84XEfH1JRXvfOc/fILWI0VKhLC2LX13X1NYq4fULzLMq7Hfh43CSo2/aIaUPA==}
+ deprecated: core-js@<3.23.3 is no longer maintained and not recommended for usage due to the number of issues. Because of the V8 engine whims, feature detection in old core-js versions could cause a slowdown up to 100x even if nothing is polyfilled. Some versions have web compatibility issues. Please, upgrade your dependencies to the actual version of core-js.
+
+ cosmiconfig@9.0.0:
+ resolution: {integrity: sha512-itvL5h8RETACmOTFc4UfIyB2RfEHi71Ax6E/PivVxq9NseKbOWpeyHEOIbmAw1rs8Ak0VursQNww7lf7YtUwzg==}
+ engines: {node: '>=14'}
+ peerDependencies:
+ typescript: '>=4.9.5'
+ peerDependenciesMeta:
+ typescript:
+ optional: true
+
+ css-functions-list@3.2.3:
+ resolution: {integrity: sha512-IQOkD3hbR5KrN93MtcYuad6YPuTSUhntLHDuLEbFWE+ff2/XSZNdZG+LcbbIW5AXKg/WFIfYItIzVoHngHXZzA==}
+ engines: {node: '>=12 || >=16'}
+
+ css-tree@3.1.0:
+ resolution: {integrity: sha512-0eW44TGN5SQXU1mWSkKwFstI/22X2bG1nYzZTYMAWjylYURhse752YgbE4Cx46AC+bAvI+/dYTPRk1LqSUnu6w==}
+ engines: {node: ^10 || ^12.20.0 || ^14.13.0 || >=15.0.0}
+
+ cssesc@3.0.0:
+ resolution: {integrity: sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==}
+ engines: {node: '>=4'}
+ hasBin: true
+
+ csstype@3.2.3:
+ resolution: {integrity: sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==}
+
+ debug@4.4.3:
+ resolution: {integrity: sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==}
+ engines: {node: '>=6.0'}
+ peerDependencies:
+ supports-color: '*'
+ peerDependenciesMeta:
+ supports-color:
+ optional: true
+
+ delayed-stream@1.0.0:
+ resolution: {integrity: sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==}
+ engines: {node: '>=0.4.0'}
+
+ detect-libc@1.0.3:
+ resolution: {integrity: sha512-pGjwhsmsp4kL2RTz08wcOlGN83otlqHeD/Z5T8GXZB+/YcpQ/dgo+lbU8ZsGxV0HIvqqxo9l7mqYwyYMD9bKDg==}
+ engines: {node: '>=0.10'}
+ hasBin: true
+
+ detect-libc@2.1.2:
+ resolution: {integrity: sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==}
+ engines: {node: '>=8'}
+
+ dir-glob@3.0.1:
+ resolution: {integrity: sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==}
+ engines: {node: '>=8'}
+
+ dunder-proto@1.0.1:
+ resolution: {integrity: sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==}
+ engines: {node: '>= 0.4'}
+
+ electron-to-chromium@1.5.267:
+ resolution: {integrity: sha512-0Drusm6MVRXSOJpGbaSVgcQsuB4hEkMpHXaVstcPmhu5LIedxs1xNK/nIxmQIU/RPC0+1/o0AVZfBTkTNJOdUw==}
+
+ emoji-regex@8.0.0:
+ resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==}
+
+ env-paths@2.2.1:
+ resolution: {integrity: sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==}
+ engines: {node: '>=6'}
+
+ error-ex@1.3.4:
+ resolution: {integrity: sha512-sqQamAnR14VgCr1A618A3sGrygcpK+HEbenA/HiEAkkUwcZIIB/tgWqHFxWgOyDh4nB4JCRimh79dR5Ywc9MDQ==}
+
+ es-define-property@1.0.1:
+ resolution: {integrity: sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==}
+ engines: {node: '>= 0.4'}
+
+ es-errors@1.3.0:
+ resolution: {integrity: sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==}
+ engines: {node: '>= 0.4'}
+
+ es-object-atoms@1.1.1:
+ resolution: {integrity: sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==}
+ engines: {node: '>= 0.4'}
+
+ es-set-tostringtag@2.1.0:
+ resolution: {integrity: sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==}
+ engines: {node: '>= 0.4'}
+
+ escalade@3.2.0:
+ resolution: {integrity: sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==}
+ engines: {node: '>=6'}
+
+ fast-deep-equal@3.1.3:
+ resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==}
+
+ fast-glob@3.3.3:
+ resolution: {integrity: sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==}
+ engines: {node: '>=8.6.0'}
+
+ fast-uri@3.1.0:
+ resolution: {integrity: sha512-iPeeDKJSWf4IEOasVVrknXpaBV0IApz/gp7S2bb7Z4Lljbl2MGJRqInZiUrQwV16cpzw/D3S5j5Julj/gT52AA==}
+
+ fastest-levenshtein@1.0.16:
+ resolution: {integrity: sha512-eRnCtTTtGZFpQCwhJiUOuxPQWRXVKYDn0b2PeHfXL6/Zi53SLAzAHfVhVWK2AryC/WH05kGfxhFIPvTF0SXQzg==}
+ engines: {node: '>= 4.9.1'}
+
+ fastq@1.19.1:
+ resolution: {integrity: sha512-GwLTyxkCXjXbxqIhTsMI2Nui8huMPtnxg7krajPJAjnEG/iiOS7i+zCtWGZR9G0NBKbXKh6X9m9UIsYX/N6vvQ==}
+
+ fdir@6.5.0:
+ resolution: {integrity: sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==}
+ engines: {node: '>=12.0.0'}
+ peerDependencies:
+ picomatch: ^3 || ^4
+ peerDependenciesMeta:
+ picomatch:
+ optional: true
+
+ file-entry-cache@11.1.1:
+ resolution: {integrity: sha512-TPVFSDE7q91Dlk1xpFLvFllf8r0HyOMOlnWy7Z2HBku5H3KhIeOGInexrIeg2D64DosVB/JXkrrk6N/7Wriq4A==}
+
+ fill-range@7.1.1:
+ resolution: {integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==}
+ engines: {node: '>=8'}
+
+ flat-cache@6.1.19:
+ resolution: {integrity: sha512-l/K33newPTZMTGAnnzaiqSl6NnH7Namh8jBNjrgjprWxGmZUuxx/sJNIRaijOh3n7q7ESbhNZC+pvVZMFdeU4A==}
+
+ flatted@3.3.3:
+ resolution: {integrity: sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg==}
+
+ follow-redirects@1.15.11:
+ resolution: {integrity: sha512-deG2P0JfjrTxl50XGCDyfI97ZGVCxIpfKYmfyrQ54n5FO/0gfIES8C/Psl6kWVDolizcaaxZJnTS0QSMxvnsBQ==}
+ engines: {node: '>=4.0'}
+ peerDependencies:
+ debug: '*'
+ peerDependenciesMeta:
+ debug:
+ optional: true
+
+ form-data@4.0.5:
+ resolution: {integrity: sha512-8RipRLol37bNs2bhoV67fiTEvdTrbMUYcFTiy3+wuuOnUog2QBHCZWXDRijWQfAkhBj2Uf5UnVaiWwA5vdd82w==}
+ engines: {node: '>= 6'}
+
+ fsevents@2.3.3:
+ resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==}
+ engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0}
+ os: [darwin]
+
+ function-bind@1.1.2:
+ resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==}
+
+ gensync@1.0.0-beta.2:
+ resolution: {integrity: sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==}
+ engines: {node: '>=6.9.0'}
+
+ get-intrinsic@1.3.0:
+ resolution: {integrity: sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==}
+ engines: {node: '>= 0.4'}
+
+ get-proto@1.0.1:
+ resolution: {integrity: sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==}
+ engines: {node: '>= 0.4'}
+
+ glob-parent@5.1.2:
+ resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==}
+ engines: {node: '>= 6'}
+
+ global-modules@2.0.0:
+ resolution: {integrity: sha512-NGbfmJBp9x8IxyJSd1P+otYK8vonoJactOogrVfFRIAEY1ukil8RSKDz2Yo7wh1oihl51l/r6W4epkeKJHqL8A==}
+ engines: {node: '>=6'}
+
+ global-prefix@3.0.0:
+ resolution: {integrity: sha512-awConJSVCHVGND6x3tmMaKcQvwXLhjdkmomy2W+Goaui8YPgYgXJZewhg3fWC+DlfqqQuWg8AwqjGTD2nAPVWg==}
+ engines: {node: '>=6'}
+
+ globby@11.1.0:
+ resolution: {integrity: sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==}
+ engines: {node: '>=10'}
+
+ globjoin@0.1.4:
+ resolution: {integrity: sha512-xYfnw62CKG8nLkZBfWbhWwDw02CHty86jfPcc2cr3ZfeuK9ysoVPPEUxf21bAD/rWAgk52SuBrLJlefNy8mvFg==}
+
+ globrex@0.1.2:
+ resolution: {integrity: sha512-uHJgbwAMwNFf5mLst7IWLNg14x1CkeqglJb/K3doi4dw6q2IvAAmM/Y81kevy83wP+Sst+nutFTYOGg3d1lsxg==}
+
+ gopd@1.2.0:
+ resolution: {integrity: sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==}
+ engines: {node: '>= 0.4'}
+
+ has-flag@4.0.0:
+ resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==}
+ engines: {node: '>=8'}
+
+ has-symbols@1.1.0:
+ resolution: {integrity: sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==}
+ engines: {node: '>= 0.4'}
+
+ has-tostringtag@1.0.2:
+ resolution: {integrity: sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==}
+ engines: {node: '>= 0.4'}
+
+ hashery@1.3.0:
+ resolution: {integrity: sha512-fWltioiy5zsSAs9ouEnvhsVJeAXRybGCNNv0lvzpzNOSDbULXRy7ivFWwCCv4I5Am6kSo75hmbsCduOoc2/K4w==}
+ engines: {node: '>=20'}
+
+ hasown@2.0.2:
+ resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==}
+ engines: {node: '>= 0.4'}
+
+ hookified@1.14.0:
+ resolution: {integrity: sha512-pi1ynXIMFx/uIIwpWJ/5CEtOHLGtnUB0WhGeeYT+fKcQ+WCQbm3/rrkAXnpfph++PgepNqPdTC2WTj8A6k6zoQ==}
+
+ html-tags@3.3.1:
+ resolution: {integrity: sha512-ztqyC3kLto0e9WbNp0aeP+M3kTt+nbaIveGmUxAtZa+8iFgKLUOD4YKM5j+f3QD89bra7UeumolZHKuOXnTmeQ==}
+ engines: {node: '>=8'}
+
+ ignore@5.3.2:
+ resolution: {integrity: sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==}
+ engines: {node: '>= 4'}
+
+ ignore@7.0.5:
+ resolution: {integrity: sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg==}
+ engines: {node: '>= 4'}
+
+ immutable@5.1.4:
+ resolution: {integrity: sha512-p6u1bG3YSnINT5RQmx/yRZBpenIl30kVxkTLDyHLIMk0gict704Q9n+thfDI7lTRm9vXdDYutVzXhzcThxTnXA==}
+
+ import-fresh@3.3.1:
+ resolution: {integrity: sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==}
+ engines: {node: '>=6'}
+
+ imurmurhash@0.1.4:
+ resolution: {integrity: sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==}
+ engines: {node: '>=0.8.19'}
+
+ ini@1.3.8:
+ resolution: {integrity: sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==}
+
+ is-arrayish@0.2.1:
+ resolution: {integrity: sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==}
+
+ is-extglob@2.1.1:
+ resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==}
+ engines: {node: '>=0.10.0'}
+
+ is-fullwidth-code-point@3.0.0:
+ resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==}
+ engines: {node: '>=8'}
+
+ is-glob@4.0.3:
+ resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==}
+ engines: {node: '>=0.10.0'}
+
+ is-number@7.0.0:
+ resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==}
+ engines: {node: '>=0.12.0'}
+
+ is-plain-object@5.0.0:
+ resolution: {integrity: sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q==}
+ engines: {node: '>=0.10.0'}
+
+ isexe@2.0.0:
+ resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==}
+
+ js-tokens@4.0.0:
+ resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==}
+
+ js-yaml@4.1.1:
+ resolution: {integrity: sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==}
+ hasBin: true
+
+ jsesc@3.1.0:
+ resolution: {integrity: sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==}
+ engines: {node: '>=6'}
+ hasBin: true
+
+ json-parse-even-better-errors@2.3.1:
+ resolution: {integrity: sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==}
+
+ json-schema-traverse@1.0.0:
+ resolution: {integrity: sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==}
+
+ json5@2.2.3:
+ resolution: {integrity: sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==}
+ engines: {node: '>=6'}
+ hasBin: true
+
+ keyv@5.5.5:
+ resolution: {integrity: sha512-FA5LmZVF1VziNc0bIdCSA1IoSVnDCqE8HJIZZv2/W8YmoAM50+tnUgJR/gQZwEeIMleuIOnRnHA/UaZRNeV4iQ==}
+
+ kind-of@6.0.3:
+ resolution: {integrity: sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==}
+ engines: {node: '>=0.10.0'}
+
+ known-css-properties@0.37.0:
+ resolution: {integrity: sha512-JCDrsP4Z1Sb9JwG0aJ8Eo2r7k4Ou5MwmThS/6lcIe1ICyb7UBJKGRIUUdqc2ASdE/42lgz6zFUnzAIhtXnBVrQ==}
+
+ lightningcss-android-arm64@1.30.2:
+ resolution: {integrity: sha512-BH9sEdOCahSgmkVhBLeU7Hc9DWeZ1Eb6wNS6Da8igvUwAe0sqROHddIlvU06q3WyXVEOYDZ6ykBZQnjTbmo4+A==}
+ engines: {node: '>= 12.0.0'}
+ cpu: [arm64]
+ os: [android]
+
+ lightningcss-darwin-arm64@1.30.2:
+ resolution: {integrity: sha512-ylTcDJBN3Hp21TdhRT5zBOIi73P6/W0qwvlFEk22fkdXchtNTOU4Qc37SkzV+EKYxLouZ6M4LG9NfZ1qkhhBWA==}
+ engines: {node: '>= 12.0.0'}
+ cpu: [arm64]
+ os: [darwin]
+
+ lightningcss-darwin-x64@1.30.2:
+ resolution: {integrity: sha512-oBZgKchomuDYxr7ilwLcyms6BCyLn0z8J0+ZZmfpjwg9fRVZIR5/GMXd7r9RH94iDhld3UmSjBM6nXWM2TfZTQ==}
+ engines: {node: '>= 12.0.0'}
+ cpu: [x64]
+ os: [darwin]
+
+ lightningcss-freebsd-x64@1.30.2:
+ resolution: {integrity: sha512-c2bH6xTrf4BDpK8MoGG4Bd6zAMZDAXS569UxCAGcA7IKbHNMlhGQ89eRmvpIUGfKWNVdbhSbkQaWhEoMGmGslA==}
+ engines: {node: '>= 12.0.0'}
+ cpu: [x64]
+ os: [freebsd]
+
+ lightningcss-linux-arm-gnueabihf@1.30.2:
+ resolution: {integrity: sha512-eVdpxh4wYcm0PofJIZVuYuLiqBIakQ9uFZmipf6LF/HRj5Bgm0eb3qL/mr1smyXIS1twwOxNWndd8z0E374hiA==}
+ engines: {node: '>= 12.0.0'}
+ cpu: [arm]
+ os: [linux]
+
+ lightningcss-linux-arm64-gnu@1.30.2:
+ resolution: {integrity: sha512-UK65WJAbwIJbiBFXpxrbTNArtfuznvxAJw4Q2ZGlU8kPeDIWEX1dg3rn2veBVUylA2Ezg89ktszWbaQnxD/e3A==}
+ engines: {node: '>= 12.0.0'}
+ cpu: [arm64]
+ os: [linux]
+
+ lightningcss-linux-arm64-musl@1.30.2:
+ resolution: {integrity: sha512-5Vh9dGeblpTxWHpOx8iauV02popZDsCYMPIgiuw97OJ5uaDsL86cnqSFs5LZkG3ghHoX5isLgWzMs+eD1YzrnA==}
+ engines: {node: '>= 12.0.0'}
+ cpu: [arm64]
+ os: [linux]
+
+ lightningcss-linux-x64-gnu@1.30.2:
+ resolution: {integrity: sha512-Cfd46gdmj1vQ+lR6VRTTadNHu6ALuw2pKR9lYq4FnhvgBc4zWY1EtZcAc6EffShbb1MFrIPfLDXD6Xprbnni4w==}
+ engines: {node: '>= 12.0.0'}
+ cpu: [x64]
+ os: [linux]
+
+ lightningcss-linux-x64-musl@1.30.2:
+ resolution: {integrity: sha512-XJaLUUFXb6/QG2lGIW6aIk6jKdtjtcffUT0NKvIqhSBY3hh9Ch+1LCeH80dR9q9LBjG3ewbDjnumefsLsP6aiA==}
+ engines: {node: '>= 12.0.0'}
+ cpu: [x64]
+ os: [linux]
+
+ lightningcss-win32-arm64-msvc@1.30.2:
+ resolution: {integrity: sha512-FZn+vaj7zLv//D/192WFFVA0RgHawIcHqLX9xuWiQt7P0PtdFEVaxgF9rjM/IRYHQXNnk61/H/gb2Ei+kUQ4xQ==}
+ engines: {node: '>= 12.0.0'}
+ cpu: [arm64]
+ os: [win32]
+
+ lightningcss-win32-x64-msvc@1.30.2:
+ resolution: {integrity: sha512-5g1yc73p+iAkid5phb4oVFMB45417DkRevRbt/El/gKXJk4jid+vPFF/AXbxn05Aky8PapwzZrdJShv5C0avjw==}
+ engines: {node: '>= 12.0.0'}
+ cpu: [x64]
+ os: [win32]
+
+ lightningcss@1.30.2:
+ resolution: {integrity: sha512-utfs7Pr5uJyyvDETitgsaqSyjCb2qNRAtuqUeWIAKztsOYdcACf2KtARYXg2pSvhkt+9NfoaNY7fxjl6nuMjIQ==}
+ engines: {node: '>= 12.0.0'}
+
+ lines-and-columns@1.2.4:
+ resolution: {integrity: sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==}
+
+ lodash.truncate@4.4.2:
+ resolution: {integrity: sha512-jttmRe7bRse52OsWIMDLaXxWqRAmtIUccAQ3garviCqJjafXOfNMO0yMfNpdD6zbGaTU0P5Nz7e7gAT6cKmJRw==}
+
+ lru-cache@5.1.1:
+ resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==}
+
+ math-intrinsics@1.1.0:
+ resolution: {integrity: sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==}
+ engines: {node: '>= 0.4'}
+
+ mathml-tag-names@2.1.3:
+ resolution: {integrity: sha512-APMBEanjybaPzUrfqU0IMU5I0AswKMH7k8OTLs0vvV4KZpExkTkY87nR/zpbuTPj+gARop7aGUbl11pnDfW6xg==}
+
+ mdn-data@2.12.2:
+ resolution: {integrity: sha512-IEn+pegP1aManZuckezWCO+XZQDplx1366JoVhTpMpBB1sPey/SbveZQUosKiKiGYjg1wH4pMlNgXbCiYgihQA==}
+
+ mdn-data@2.25.0:
+ resolution: {integrity: sha512-T2LPsjgUE/tgMmRXREVmwsux89DwWfNjiynOeXuLd2mX6jphGQ2YE3Ukz7LQ2VOFKiVZU/Ee1GqzHiipZCjymw==}
+
+ meow@13.2.0:
+ resolution: {integrity: sha512-pxQJQzB6djGPXh08dacEloMFopsOqGVRKFPYvPOt9XDZ1HasbgDZA74CJGreSU4G3Ak7EFJGoiH2auq+yXISgA==}
+ engines: {node: '>=18'}
+
+ merge2@1.4.1:
+ resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==}
+ engines: {node: '>= 8'}
+
+ micromatch@4.0.8:
+ resolution: {integrity: sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==}
+ engines: {node: '>=8.6'}
+
+ mime-db@1.52.0:
+ resolution: {integrity: sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==}
+ engines: {node: '>= 0.6'}
+
+ mime-types@2.1.35:
+ resolution: {integrity: sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==}
+ engines: {node: '>= 0.6'}
+
+ ms@2.1.3:
+ resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==}
+
+ nanoid@3.3.11:
+ resolution: {integrity: sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==}
+ engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1}
+ hasBin: true
+
+ node-addon-api@7.1.1:
+ resolution: {integrity: sha512-5m3bsyrjFWE1xf7nz7YXdN4udnVtXK6/Yfgn5qnahL6bCkf2yKt4k3nuTKAtT4r3IG8JNR2ncsIMdZuAzJjHQQ==}
+
+ node-releases@2.0.27:
+ resolution: {integrity: sha512-nmh3lCkYZ3grZvqcCH+fjmQ7X+H0OeZgP40OierEaAptX4XofMh5kwNbWh7lBduUzCcV/8kZ+NDLCwm2iorIlA==}
+
+ normalize-path@3.0.0:
+ resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==}
+ engines: {node: '>=0.10.0'}
+
+ parent-module@1.0.1:
+ resolution: {integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==}
+ engines: {node: '>=6'}
+
+ parse-json@5.2.0:
+ resolution: {integrity: sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==}
+ engines: {node: '>=8'}
+
+ path-type@4.0.0:
+ resolution: {integrity: sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==}
+ engines: {node: '>=8'}
+
+ picocolors@1.1.1:
+ resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==}
+
+ picomatch@2.3.1:
+ resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==}
+ engines: {node: '>=8.6'}
+
+ picomatch@4.0.3:
+ resolution: {integrity: sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==}
+ engines: {node: '>=12'}
+
+ postcss-media-query-parser@0.2.3:
+ resolution: {integrity: sha512-3sOlxmbKcSHMjlUXQZKQ06jOswE7oVkXPxmZdoB1r5l0q6gTFTQSHxNxOrCccElbW7dxNytifNEo8qidX2Vsig==}
+
+ postcss-resolve-nested-selector@0.1.6:
+ resolution: {integrity: sha512-0sglIs9Wmkzbr8lQwEyIzlDOOC9bGmfVKcJTaxv3vMmd3uo4o4DerC3En0bnmgceeql9BfC8hRkp7cg0fjdVqw==}
+
+ postcss-safe-parser@7.0.1:
+ resolution: {integrity: sha512-0AioNCJZ2DPYz5ABT6bddIqlhgwhpHZ/l65YAYo0BCIn0xiDpsnTHz0gnoTGk0OXZW0JRs+cDwL8u/teRdz+8A==}
+ engines: {node: '>=18.0'}
+ peerDependencies:
+ postcss: ^8.4.31
+
+ postcss-scss@4.0.9:
+ resolution: {integrity: sha512-AjKOeiwAitL/MXxQW2DliT28EKukvvbEWx3LBmJIRN8KfBGZbRTxNYW0kSqi1COiTZ57nZ9NW06S6ux//N1c9A==}
+ engines: {node: '>=12.0'}
+ peerDependencies:
+ postcss: ^8.4.29
+
+ postcss-selector-parser@7.1.1:
+ resolution: {integrity: sha512-orRsuYpJVw8LdAwqqLykBj9ecS5/cRHlI5+nvTo8LcCKmzDmqVORXtOIYEEQuL9D4BxtA1lm5isAqzQZCoQ6Eg==}
+ engines: {node: '>=4'}
+
+ postcss-value-parser@4.2.0:
+ resolution: {integrity: sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==}
+
+ postcss@8.5.6:
+ resolution: {integrity: sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==}
+ engines: {node: ^10 || ^12 || >=14}
+
+ proxy-from-env@1.1.0:
+ resolution: {integrity: sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==}
+
+ qified@0.5.3:
+ resolution: {integrity: sha512-kXuQdQTB6oN3KhI6V4acnBSZx8D2I4xzZvn9+wFLLFCoBNQY/sFnCW6c43OL7pOQ2HvGV4lnWIXNmgfp7cTWhQ==}
+ engines: {node: '>=20'}
+
+ queue-microtask@1.2.3:
+ resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==}
+
+ react-dom@19.2.1:
+ resolution: {integrity: sha512-ibrK8llX2a4eOskq1mXKu/TGZj9qzomO+sNfO98M6d9zIPOEhlBkMkBUBLd1vgS0gQsLDBzA+8jJBVXDnfHmJg==}
+ peerDependencies:
+ react: ^19.2.1
+
+ react-error-boundary@6.0.0:
+ resolution: {integrity: sha512-gdlJjD7NWr0IfkPlaREN2d9uUZUlksrfOx7SX62VRerwXbMY6ftGCIZua1VG1aXFNOimhISsTq+Owp725b9SiA==}
+ peerDependencies:
+ react: '>=16.13.1'
+
+ react-icon@1.0.0:
+ resolution: {integrity: sha512-VzSlpBHnLanVw79mOxyq98hWDi6DlxK9qPiZ1bAK6bLurMBCaxO/jjyYUrRx9+JGLc/NbnwOmyE/W5Qglbb2QA==}
+ peerDependencies:
+ babel-runtime: ^5.3.3
+ react: '>=0.12.0'
+
+ react-icons@5.5.0:
+ resolution: {integrity: sha512-MEFcXdkP3dLo8uumGI5xN3lDFNsRtrjbOEKDLD7yv76v4wpnEq2Lt2qeHaQOr34I/wPN3s3+N08WkQ+CW37Xiw==}
+ peerDependencies:
+ react: '*'
+
+ react-refresh@0.18.0:
+ resolution: {integrity: sha512-QgT5//D3jfjJb6Gsjxv0Slpj23ip+HtOpnNgnb2S5zU3CB26G/IDPGoy4RJB42wzFE46DRsstbW6tKHoKbhAxw==}
+ engines: {node: '>=0.10.0'}
+
+ react-router-dom@7.10.1:
+ resolution: {integrity: sha512-JNBANI6ChGVjA5bwsUIwJk7LHKmqB4JYnYfzFwyp2t12Izva11elds2jx7Yfoup2zssedntwU0oZ5DEmk5Sdaw==}
+ engines: {node: '>=20.0.0'}
+ peerDependencies:
+ react: '>=18'
+ react-dom: '>=18'
+
+ react-router@7.10.1:
+ resolution: {integrity: sha512-gHL89dRa3kwlUYtRQ+m8NmxGI6CgqN+k4XyGjwcFoQwwCWF6xXpOCUlDovkXClS0d0XJN/5q7kc5W3kiFEd0Yw==}
+ engines: {node: '>=20.0.0'}
+ peerDependencies:
+ react: '>=18'
+ react-dom: '>=18'
+ peerDependenciesMeta:
+ react-dom:
+ optional: true
+
+ react@19.2.1:
+ resolution: {integrity: sha512-DGrYcCWK7tvYMnWh79yrPHt+vdx9tY+1gPZa7nJQtO/p8bLTDaHp4dzwEhQB7pZ4Xe3ok4XKuEPrVuc+wlpkmw==}
+ engines: {node: '>=0.10.0'}
+
+ readdirp@4.1.2:
+ resolution: {integrity: sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==}
+ engines: {node: '>= 14.18.0'}
+
+ require-from-string@2.0.2:
+ resolution: {integrity: sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==}
+ engines: {node: '>=0.10.0'}
+
+ resolve-from@4.0.0:
+ resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==}
+ engines: {node: '>=4'}
+
+ resolve-from@5.0.0:
+ resolution: {integrity: sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==}
+ engines: {node: '>=8'}
+
+ reusify@1.1.0:
+ resolution: {integrity: sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==}
+ engines: {iojs: '>=1.0.0', node: '>=0.10.0'}
+
+ rolldown-vite@7.2.5:
+ resolution: {integrity: sha512-u09tdk/huMiN8xwoiBbig197jKdCamQTtOruSalOzbqGje3jdHiV0njQlAW0YvzoahkirFePNQ4RYlfnRQpXZA==}
+ engines: {node: ^20.19.0 || >=22.12.0}
+ hasBin: true
+ peerDependencies:
+ '@types/node': ^20.19.0 || >=22.12.0
+ esbuild: ^0.25.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
+ 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
+
+ rolldown@1.0.0-beta.50:
+ resolution: {integrity: sha512-JFULvCNl/anKn99eKjOSEubi0lLmNqQDAjyEMME2T4CwezUDL0i6t1O9xZsu2OMehPnV2caNefWpGF+8TnzB6A==}
+ engines: {node: ^20.19.0 || >=22.12.0}
+ hasBin: true
+
+ run-parallel@1.2.0:
+ resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==}
+
+ sass@1.95.0:
+ resolution: {integrity: sha512-9QMjhLq+UkOg/4bb8Lt8A+hJZvY3t+9xeZMKSBtBEgxrXA3ed5Ts4NDreUkYgJP1BTmrscQE/xYhf7iShow6lw==}
+ engines: {node: '>=14.0.0'}
+ hasBin: true
+
+ scheduler@0.27.0:
+ resolution: {integrity: sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q==}
+
+ semver@6.3.1:
+ resolution: {integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==}
+ hasBin: true
+
+ set-cookie-parser@2.7.2:
+ resolution: {integrity: sha512-oeM1lpU/UvhTxw+g3cIfxXHyJRc/uidd3yK1P242gzHds0udQBYzs3y8j4gCCW+ZJ7ad0yctld8RYO+bdurlvw==}
+
+ signal-exit@4.1.0:
+ resolution: {integrity: sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==}
+ engines: {node: '>=14'}
+
+ slash@3.0.0:
+ resolution: {integrity: sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==}
+ engines: {node: '>=8'}
+
+ slice-ansi@4.0.0:
+ resolution: {integrity: sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ==}
+ engines: {node: '>=10'}
+
+ sonner@2.0.7:
+ resolution: {integrity: sha512-W6ZN4p58k8aDKA4XPcx2hpIQXBRAgyiWVkYhT7CvK6D3iAu7xjvVyhQHg2/iaKJZ1XVJ4r7XuwGL+WGEK37i9w==}
+ peerDependencies:
+ react: ^18.0.0 || ^19.0.0 || ^19.0.0-rc
+ react-dom: ^18.0.0 || ^19.0.0 || ^19.0.0-rc
+
+ source-map-js@1.2.1:
+ resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==}
+ engines: {node: '>=0.10.0'}
+
+ string-width@4.2.3:
+ resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==}
+ engines: {node: '>=8'}
+
+ strip-ansi@6.0.1:
+ resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==}
+ engines: {node: '>=8'}
+
+ stylelint-config-prettier-scss@1.0.0:
+ resolution: {integrity: sha512-Gr2qLiyvJGKeDk0E/+awNTrZB/UtNVPLqCDOr07na/sLekZwm26Br6yYIeBYz3ulsEcQgs5j+2IIMXCC+wsaQA==}
+ engines: {node: 14.* || 16.* || >= 18}
+ hasBin: true
+ peerDependencies:
+ stylelint: '>=15.0.0'
+
+ stylelint-config-recommended-scss@16.0.2:
+ resolution: {integrity: sha512-aUTHhPPWCvFyWaxtckJlCPaXTDFsp4pKO8evXNCsW9OwsaUWyMd6jvcUhSmfGWPrTddvzNqK4rS/UuSLcbVGdQ==}
+ engines: {node: '>=20'}
+ peerDependencies:
+ postcss: ^8.3.3
+ stylelint: ^16.24.0
+ peerDependenciesMeta:
+ postcss:
+ optional: true
+
+ stylelint-config-recommended@17.0.0:
+ resolution: {integrity: sha512-WaMSdEiPfZTSFVoYmJbxorJfA610O0tlYuU2aEwY33UQhSPgFbClrVJYWvy3jGJx+XW37O+LyNLiZOEXhKhJmA==}
+ engines: {node: '>=18.12.0'}
+ peerDependencies:
+ stylelint: ^16.23.0
+
+ stylelint-config-standard-scss@16.0.0:
+ resolution: {integrity: sha512-/FHECLUu+med/e6OaPFpprG86ShC4SYT7Tzb2PTVdDjJsehhFBOioSlWqYFqJxmGPIwO3AMBxNo+kY3dxrbczA==}
+ engines: {node: '>=20'}
+ peerDependencies:
+ postcss: ^8.3.3
+ stylelint: ^16.23.1
+ peerDependenciesMeta:
+ postcss:
+ optional: true
+
+ stylelint-config-standard@39.0.1:
+ resolution: {integrity: sha512-b7Fja59EYHRNOTa3aXiuWnhUWXFU2Nfg6h61bLfAb5GS5fX3LMUD0U5t4S8N/4tpHQg3Acs2UVPR9jy2l1g/3A==}
+ engines: {node: '>=18.12.0'}
+ peerDependencies:
+ stylelint: ^16.23.0
+
+ stylelint-scss@6.13.0:
+ resolution: {integrity: sha512-kZPwFUJkfup2gP1enlrS2h9U5+T5wFoqzJ1n/56AlpwSj28kmFe7ww/QFydvPsg5gLjWchAwWWBLtterynZrOw==}
+ engines: {node: '>=18.12.0'}
+ peerDependencies:
+ stylelint: ^16.8.2
+
+ stylelint@16.26.1:
+ resolution: {integrity: sha512-v20V59/crfc8sVTAtge0mdafI3AdnzQ2KsWe6v523L4OA1bJO02S7MO2oyXDCS6iWb9ckIPnqAFVItqSBQr7jw==}
+ engines: {node: '>=18.12.0'}
+ hasBin: true
+
+ supports-color@7.2.0:
+ resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==}
+ engines: {node: '>=8'}
+
+ supports-hyperlinks@3.2.0:
+ resolution: {integrity: sha512-zFObLMyZeEwzAoKCyu1B91U79K2t7ApXuQfo8OuxwXLDgcKxuwM+YvcbIhm6QWqz7mHUH1TVytR1PwVVjEuMig==}
+ engines: {node: '>=14.18'}
+
+ svg-tags@1.0.0:
+ resolution: {integrity: sha512-ovssysQTa+luh7A5Weu3Rta6FJlFBBbInjOh722LIt6klpU2/HtdUbszju/G4devcvk8PGt7FCLv5wftu3THUA==}
+
+ table@6.9.0:
+ resolution: {integrity: sha512-9kY+CygyYM6j02t5YFHbNz2FN5QmYGv9zAjVp4lCDjlCw7amdckXlEt/bjMhUIfj4ThGRE4gCUH5+yGnNuPo5A==}
+ engines: {node: '>=10.0.0'}
+
+ tinyglobby@0.2.15:
+ resolution: {integrity: sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==}
+ engines: {node: '>=12.0.0'}
+
+ to-regex-range@5.0.1:
+ resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==}
+ engines: {node: '>=8.0'}
+
+ tsconfck@3.1.6:
+ resolution: {integrity: sha512-ks6Vjr/jEw0P1gmOVwutM3B7fWxoWBL2KRDb1JfqGVawBmO5UsvmWOQFGHBPl5yxYz4eERr19E6L7NMv+Fej4w==}
+ engines: {node: ^18 || >=20}
+ hasBin: true
+ peerDependencies:
+ typescript: ^5.0.0
+ peerDependenciesMeta:
+ typescript:
+ optional: true
+
+ tslib@2.8.1:
+ resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==}
+
+ typescript@5.9.3:
+ resolution: {integrity: sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==}
+ engines: {node: '>=14.17'}
+ hasBin: true
+
+ undici-types@7.16.0:
+ resolution: {integrity: sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw==}
+
+ update-browserslist-db@1.2.2:
+ resolution: {integrity: sha512-E85pfNzMQ9jpKkA7+TJAi4TJN+tBCuWh5rUcS/sv6cFi+1q9LYDwDI5dpUL0u/73EElyQ8d3TEaeW4sPedBqYA==}
+ hasBin: true
+ peerDependencies:
+ browserslist: '>= 4.21.0'
+
+ util-deprecate@1.0.2:
+ resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==}
+
+ vite-tsconfig-paths@5.1.4:
+ resolution: {integrity: sha512-cYj0LRuLV2c2sMqhqhGpaO3LretdtMn/BVX4cPLanIZuwwrkVl+lK84E/miEXkCHWXuq65rhNN4rXsBcOB3S4w==}
+ peerDependencies:
+ vite: '*'
+ peerDependenciesMeta:
+ vite:
+ optional: true
+
+ which@1.3.1:
+ resolution: {integrity: sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==}
+ hasBin: true
+
+ write-file-atomic@5.0.1:
+ resolution: {integrity: sha512-+QU2zd6OTD8XWIJCbffaiQeH9U73qIqafo1x6V1snCWYGJf6cVE0cDR4D8xRzcEnfI21IFrUPzPGtcPf8AC+Rw==}
+ engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0}
+
+ yallist@3.1.1:
+ resolution: {integrity: sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==}
+
+ zod@4.1.13:
+ resolution: {integrity: sha512-AvvthqfqrAhNH9dnfmrfKzX5upOdjUVJYFqNSlkmGf64gRaTzlPwz99IHYnVs28qYAybvAlBV+H7pn0saFY4Ig==}
+
+ zustand@5.0.9:
+ resolution: {integrity: sha512-ALBtUj0AfjJt3uNRQoL1tL2tMvj6Gp/6e39dnfT6uzpelGru8v1tPOGBzayOWbPJvujM8JojDk3E1LxeFisBNg==}
+ engines: {node: '>=12.20.0'}
+ peerDependencies:
+ '@types/react': '>=18.0.0'
+ immer: '>=9.0.6'
+ react: '>=18.0.0'
+ use-sync-external-store: '>=1.2.0'
+ peerDependenciesMeta:
+ '@types/react':
+ optional: true
+ immer:
+ optional: true
+ react:
+ optional: true
+ use-sync-external-store:
+ optional: true
+
+snapshots:
+
+ '@babel/code-frame@7.27.1':
+ dependencies:
+ '@babel/helper-validator-identifier': 7.28.5
+ js-tokens: 4.0.0
+ picocolors: 1.1.1
+
+ '@babel/compat-data@7.28.5': {}
+
+ '@babel/core@7.28.5':
+ dependencies:
+ '@babel/code-frame': 7.27.1
+ '@babel/generator': 7.28.5
+ '@babel/helper-compilation-targets': 7.27.2
+ '@babel/helper-module-transforms': 7.28.3(@babel/core@7.28.5)
+ '@babel/helpers': 7.28.4
+ '@babel/parser': 7.28.5
+ '@babel/template': 7.27.2
+ '@babel/traverse': 7.28.5
+ '@babel/types': 7.28.5
+ '@jridgewell/remapping': 2.3.5
+ convert-source-map: 2.0.0
+ debug: 4.4.3
+ gensync: 1.0.0-beta.2
+ json5: 2.2.3
+ semver: 6.3.1
+ transitivePeerDependencies:
+ - supports-color
+
+ '@babel/generator@7.28.5':
+ dependencies:
+ '@babel/parser': 7.28.5
+ '@babel/types': 7.28.5
+ '@jridgewell/gen-mapping': 0.3.13
+ '@jridgewell/trace-mapping': 0.3.31
+ jsesc: 3.1.0
+
+ '@babel/helper-compilation-targets@7.27.2':
+ dependencies:
+ '@babel/compat-data': 7.28.5
+ '@babel/helper-validator-option': 7.27.1
+ browserslist: 4.28.1
+ lru-cache: 5.1.1
+ semver: 6.3.1
+
+ '@babel/helper-globals@7.28.0': {}
+
+ '@babel/helper-module-imports@7.27.1':
+ dependencies:
+ '@babel/traverse': 7.28.5
+ '@babel/types': 7.28.5
+ transitivePeerDependencies:
+ - supports-color
+
+ '@babel/helper-module-transforms@7.28.3(@babel/core@7.28.5)':
+ dependencies:
+ '@babel/core': 7.28.5
+ '@babel/helper-module-imports': 7.27.1
+ '@babel/helper-validator-identifier': 7.28.5
+ '@babel/traverse': 7.28.5
+ transitivePeerDependencies:
+ - supports-color
+
+ '@babel/helper-plugin-utils@7.27.1': {}
+
+ '@babel/helper-string-parser@7.27.1': {}
+
+ '@babel/helper-validator-identifier@7.28.5': {}
+
+ '@babel/helper-validator-option@7.27.1': {}
+
+ '@babel/helpers@7.28.4':
+ dependencies:
+ '@babel/template': 7.27.2
+ '@babel/types': 7.28.5
+
+ '@babel/parser@7.28.5':
+ dependencies:
+ '@babel/types': 7.28.5
+
+ '@babel/plugin-transform-react-jsx-self@7.27.1(@babel/core@7.28.5)':
+ dependencies:
+ '@babel/core': 7.28.5
+ '@babel/helper-plugin-utils': 7.27.1
+
+ '@babel/plugin-transform-react-jsx-source@7.27.1(@babel/core@7.28.5)':
+ dependencies:
+ '@babel/core': 7.28.5
+ '@babel/helper-plugin-utils': 7.27.1
+
+ '@babel/runtime@7.28.4': {}
+
+ '@babel/template@7.27.2':
+ dependencies:
+ '@babel/code-frame': 7.27.1
+ '@babel/parser': 7.28.5
+ '@babel/types': 7.28.5
+
+ '@babel/traverse@7.28.5':
+ dependencies:
+ '@babel/code-frame': 7.27.1
+ '@babel/generator': 7.28.5
+ '@babel/helper-globals': 7.28.0
+ '@babel/parser': 7.28.5
+ '@babel/template': 7.27.2
+ '@babel/types': 7.28.5
+ debug: 4.4.3
+ transitivePeerDependencies:
+ - supports-color
+
+ '@babel/types@7.28.5':
+ dependencies:
+ '@babel/helper-string-parser': 7.27.1
+ '@babel/helper-validator-identifier': 7.28.5
+
+ '@biomejs/biome@2.3.8':
+ optionalDependencies:
+ '@biomejs/cli-darwin-arm64': 2.3.8
+ '@biomejs/cli-darwin-x64': 2.3.8
+ '@biomejs/cli-linux-arm64': 2.3.8
+ '@biomejs/cli-linux-arm64-musl': 2.3.8
+ '@biomejs/cli-linux-x64': 2.3.8
+ '@biomejs/cli-linux-x64-musl': 2.3.8
+ '@biomejs/cli-win32-arm64': 2.3.8
+ '@biomejs/cli-win32-x64': 2.3.8
+
+ '@biomejs/cli-darwin-arm64@2.3.8':
+ optional: true
+
+ '@biomejs/cli-darwin-x64@2.3.8':
+ optional: true
+
+ '@biomejs/cli-linux-arm64-musl@2.3.8':
+ optional: true
+
+ '@biomejs/cli-linux-arm64@2.3.8':
+ optional: true
+
+ '@biomejs/cli-linux-x64-musl@2.3.8':
+ optional: true
+
+ '@biomejs/cli-linux-x64@2.3.8':
+ optional: true
+
+ '@biomejs/cli-win32-arm64@2.3.8':
+ optional: true
+
+ '@biomejs/cli-win32-x64@2.3.8':
+ optional: true
+
+ '@cacheable/memory@2.0.6':
+ dependencies:
+ '@cacheable/utils': 2.3.2
+ '@keyv/bigmap': 1.3.0(keyv@5.5.5)
+ hookified: 1.14.0
+ keyv: 5.5.5
+
+ '@cacheable/utils@2.3.2':
+ dependencies:
+ hashery: 1.3.0
+ keyv: 5.5.5
+
+ '@csstools/css-parser-algorithms@3.0.5(@csstools/css-tokenizer@3.0.4)':
+ dependencies:
+ '@csstools/css-tokenizer': 3.0.4
+
+ '@csstools/css-syntax-patches-for-csstree@1.0.20': {}
+
+ '@csstools/css-tokenizer@3.0.4': {}
+
+ '@csstools/media-query-list-parser@4.0.3(@csstools/css-parser-algorithms@3.0.5(@csstools/css-tokenizer@3.0.4))(@csstools/css-tokenizer@3.0.4)':
+ dependencies:
+ '@csstools/css-parser-algorithms': 3.0.5(@csstools/css-tokenizer@3.0.4)
+ '@csstools/css-tokenizer': 3.0.4
+
+ '@csstools/selector-specificity@5.0.0(postcss-selector-parser@7.1.1)':
+ dependencies:
+ postcss-selector-parser: 7.1.1
+
+ '@dual-bundle/import-meta-resolve@4.2.1': {}
+
+ '@emnapi/core@1.7.1':
+ dependencies:
+ '@emnapi/wasi-threads': 1.1.0
+ tslib: 2.8.1
+ optional: true
+
+ '@emnapi/runtime@1.7.1':
+ dependencies:
+ tslib: 2.8.1
+ optional: true
+
+ '@emnapi/wasi-threads@1.1.0':
+ dependencies:
+ tslib: 2.8.1
+ optional: true
+
+ '@jridgewell/gen-mapping@0.3.13':
+ dependencies:
+ '@jridgewell/sourcemap-codec': 1.5.5
+ '@jridgewell/trace-mapping': 0.3.31
+
+ '@jridgewell/remapping@2.3.5':
+ dependencies:
+ '@jridgewell/gen-mapping': 0.3.13
+ '@jridgewell/trace-mapping': 0.3.31
+
+ '@jridgewell/resolve-uri@3.1.2': {}
+
+ '@jridgewell/sourcemap-codec@1.5.5': {}
+
+ '@jridgewell/trace-mapping@0.3.31':
+ dependencies:
+ '@jridgewell/resolve-uri': 3.1.2
+ '@jridgewell/sourcemap-codec': 1.5.5
+
+ '@keyv/bigmap@1.3.0(keyv@5.5.5)':
+ dependencies:
+ hashery: 1.3.0
+ hookified: 1.14.0
+ keyv: 5.5.5
+
+ '@keyv/serialize@1.1.1': {}
+
+ '@napi-rs/wasm-runtime@1.1.0':
+ dependencies:
+ '@emnapi/core': 1.7.1
+ '@emnapi/runtime': 1.7.1
+ '@tybys/wasm-util': 0.10.1
+ optional: true
+
+ '@nodelib/fs.scandir@2.1.5':
+ dependencies:
+ '@nodelib/fs.stat': 2.0.5
+ run-parallel: 1.2.0
+
+ '@nodelib/fs.stat@2.0.5': {}
+
+ '@nodelib/fs.walk@1.2.8':
+ dependencies:
+ '@nodelib/fs.scandir': 2.1.5
+ fastq: 1.19.1
+
+ '@oxc-project/runtime@0.97.0': {}
+
+ '@oxc-project/types@0.97.0': {}
+
+ '@parcel/watcher-android-arm64@2.5.1':
+ optional: true
+
+ '@parcel/watcher-darwin-arm64@2.5.1':
+ optional: true
+
+ '@parcel/watcher-darwin-x64@2.5.1':
+ optional: true
+
+ '@parcel/watcher-freebsd-x64@2.5.1':
+ optional: true
+
+ '@parcel/watcher-linux-arm-glibc@2.5.1':
+ optional: true
+
+ '@parcel/watcher-linux-arm-musl@2.5.1':
+ optional: true
+
+ '@parcel/watcher-linux-arm64-glibc@2.5.1':
+ optional: true
+
+ '@parcel/watcher-linux-arm64-musl@2.5.1':
+ optional: true
+
+ '@parcel/watcher-linux-x64-glibc@2.5.1':
+ optional: true
+
+ '@parcel/watcher-linux-x64-musl@2.5.1':
+ optional: true
+
+ '@parcel/watcher-win32-arm64@2.5.1':
+ optional: true
+
+ '@parcel/watcher-win32-ia32@2.5.1':
+ optional: true
+
+ '@parcel/watcher-win32-x64@2.5.1':
+ optional: true
+
+ '@parcel/watcher@2.5.1':
+ dependencies:
+ detect-libc: 1.0.3
+ is-glob: 4.0.3
+ micromatch: 4.0.8
+ node-addon-api: 7.1.1
+ optionalDependencies:
+ '@parcel/watcher-android-arm64': 2.5.1
+ '@parcel/watcher-darwin-arm64': 2.5.1
+ '@parcel/watcher-darwin-x64': 2.5.1
+ '@parcel/watcher-freebsd-x64': 2.5.1
+ '@parcel/watcher-linux-arm-glibc': 2.5.1
+ '@parcel/watcher-linux-arm-musl': 2.5.1
+ '@parcel/watcher-linux-arm64-glibc': 2.5.1
+ '@parcel/watcher-linux-arm64-musl': 2.5.1
+ '@parcel/watcher-linux-x64-glibc': 2.5.1
+ '@parcel/watcher-linux-x64-musl': 2.5.1
+ '@parcel/watcher-win32-arm64': 2.5.1
+ '@parcel/watcher-win32-ia32': 2.5.1
+ '@parcel/watcher-win32-x64': 2.5.1
+ optional: true
+
+ '@rolldown/binding-android-arm64@1.0.0-beta.50':
+ optional: true
+
+ '@rolldown/binding-darwin-arm64@1.0.0-beta.50':
+ optional: true
+
+ '@rolldown/binding-darwin-x64@1.0.0-beta.50':
+ optional: true
+
+ '@rolldown/binding-freebsd-x64@1.0.0-beta.50':
+ optional: true
+
+ '@rolldown/binding-linux-arm-gnueabihf@1.0.0-beta.50':
+ optional: true
+
+ '@rolldown/binding-linux-arm64-gnu@1.0.0-beta.50':
+ optional: true
+
+ '@rolldown/binding-linux-arm64-musl@1.0.0-beta.50':
+ optional: true
+
+ '@rolldown/binding-linux-x64-gnu@1.0.0-beta.50':
+ optional: true
+
+ '@rolldown/binding-linux-x64-musl@1.0.0-beta.50':
+ optional: true
+
+ '@rolldown/binding-openharmony-arm64@1.0.0-beta.50':
+ optional: true
+
+ '@rolldown/binding-wasm32-wasi@1.0.0-beta.50':
+ dependencies:
+ '@napi-rs/wasm-runtime': 1.1.0
+ optional: true
+
+ '@rolldown/binding-win32-arm64-msvc@1.0.0-beta.50':
+ optional: true
+
+ '@rolldown/binding-win32-ia32-msvc@1.0.0-beta.50':
+ optional: true
+
+ '@rolldown/binding-win32-x64-msvc@1.0.0-beta.50':
+ optional: true
+
+ '@rolldown/pluginutils@1.0.0-beta.50': {}
+
+ '@rolldown/pluginutils@1.0.0-beta.53': {}
+
+ '@tanstack/query-core@5.90.12': {}
+
+ '@tanstack/query-devtools@5.91.1': {}
+
+ '@tanstack/react-query-devtools@5.91.1(@tanstack/react-query@5.90.12(react@19.2.1))(react@19.2.1)':
+ dependencies:
+ '@tanstack/query-devtools': 5.91.1
+ '@tanstack/react-query': 5.90.12(react@19.2.1)
+ react: 19.2.1
+
+ '@tanstack/react-query@5.90.12(react@19.2.1)':
+ dependencies:
+ '@tanstack/query-core': 5.90.12
+ react: 19.2.1
+
+ '@tybys/wasm-util@0.10.1':
+ dependencies:
+ tslib: 2.8.1
+ optional: true
+
+ '@types/babel__core@7.20.5':
+ dependencies:
+ '@babel/parser': 7.28.5
+ '@babel/types': 7.28.5
+ '@types/babel__generator': 7.27.0
+ '@types/babel__template': 7.4.4
+ '@types/babel__traverse': 7.28.0
+
+ '@types/babel__generator@7.27.0':
+ dependencies:
+ '@babel/types': 7.28.5
+
+ '@types/babel__template@7.4.4':
+ dependencies:
+ '@babel/parser': 7.28.5
+ '@babel/types': 7.28.5
+
+ '@types/babel__traverse@7.28.0':
+ dependencies:
+ '@babel/types': 7.28.5
+
+ '@types/node@24.10.2':
+ dependencies:
+ undici-types: 7.16.0
+
+ '@types/react-dom@19.2.3(@types/react@19.2.7)':
+ dependencies:
+ '@types/react': 19.2.7
+
+ '@types/react@19.2.7':
+ dependencies:
+ csstype: 3.2.3
+
+ '@vitejs/plugin-react@5.1.2(rolldown-vite@7.2.5(@types/node@24.10.2)(sass@1.95.0))':
+ dependencies:
+ '@babel/core': 7.28.5
+ '@babel/plugin-transform-react-jsx-self': 7.27.1(@babel/core@7.28.5)
+ '@babel/plugin-transform-react-jsx-source': 7.27.1(@babel/core@7.28.5)
+ '@rolldown/pluginutils': 1.0.0-beta.53
+ '@types/babel__core': 7.20.5
+ react-refresh: 0.18.0
+ vite: rolldown-vite@7.2.5(@types/node@24.10.2)(sass@1.95.0)
+ transitivePeerDependencies:
+ - supports-color
+
+ ajv@8.17.1:
+ dependencies:
+ fast-deep-equal: 3.1.3
+ fast-uri: 3.1.0
+ json-schema-traverse: 1.0.0
+ require-from-string: 2.0.2
+
+ ansi-regex@5.0.1: {}
+
+ ansi-styles@4.3.0:
+ dependencies:
+ color-convert: 2.0.1
+
+ argparse@2.0.1: {}
+
+ array-union@2.1.0: {}
+
+ astral-regex@2.0.0: {}
+
+ asynckit@0.4.0: {}
+
+ axios@1.13.2:
+ dependencies:
+ follow-redirects: 1.15.11
+ form-data: 4.0.5
+ proxy-from-env: 1.1.0
+ transitivePeerDependencies:
+ - debug
+
+ babel-runtime@5.8.38:
+ dependencies:
+ core-js: 1.2.7
+
+ balanced-match@2.0.0: {}
+
+ baseline-browser-mapping@2.9.5: {}
+
+ braces@3.0.3:
+ dependencies:
+ fill-range: 7.1.1
+
+ browserslist@4.28.1:
+ dependencies:
+ baseline-browser-mapping: 2.9.5
+ caniuse-lite: 1.0.30001759
+ electron-to-chromium: 1.5.267
+ node-releases: 2.0.27
+ update-browserslist-db: 1.2.2(browserslist@4.28.1)
+
+ cacheable@2.3.0:
+ dependencies:
+ '@cacheable/memory': 2.0.6
+ '@cacheable/utils': 2.3.2
+ hookified: 1.14.0
+ keyv: 5.5.5
+ qified: 0.5.3
+
+ call-bind-apply-helpers@1.0.2:
+ dependencies:
+ es-errors: 1.3.0
+ function-bind: 1.1.2
+
+ callsites@3.1.0: {}
+
+ caniuse-lite@1.0.30001759: {}
+
+ chokidar@4.0.3:
+ dependencies:
+ readdirp: 4.1.2
+
+ color-convert@2.0.1:
+ dependencies:
+ color-name: 1.1.4
+
+ color-name@1.1.4: {}
+
+ colord@2.9.3: {}
+
+ combined-stream@1.0.8:
+ dependencies:
+ delayed-stream: 1.0.0
+
+ convert-source-map@2.0.0: {}
+
+ cookie@1.1.1: {}
+
+ core-js@1.2.7: {}
+
+ cosmiconfig@9.0.0(typescript@5.9.3):
+ dependencies:
+ env-paths: 2.2.1
+ import-fresh: 3.3.1
+ js-yaml: 4.1.1
+ parse-json: 5.2.0
+ optionalDependencies:
+ typescript: 5.9.3
+
+ css-functions-list@3.2.3: {}
+
+ css-tree@3.1.0:
+ dependencies:
+ mdn-data: 2.12.2
+ source-map-js: 1.2.1
+
+ cssesc@3.0.0: {}
+
+ csstype@3.2.3: {}
+
+ debug@4.4.3:
+ dependencies:
+ ms: 2.1.3
+
+ delayed-stream@1.0.0: {}
+
+ detect-libc@1.0.3:
+ optional: true
+
+ detect-libc@2.1.2: {}
+
+ dir-glob@3.0.1:
+ dependencies:
+ path-type: 4.0.0
+
+ dunder-proto@1.0.1:
+ dependencies:
+ call-bind-apply-helpers: 1.0.2
+ es-errors: 1.3.0
+ gopd: 1.2.0
+
+ electron-to-chromium@1.5.267: {}
+
+ emoji-regex@8.0.0: {}
+
+ env-paths@2.2.1: {}
+
+ error-ex@1.3.4:
+ dependencies:
+ is-arrayish: 0.2.1
+
+ es-define-property@1.0.1: {}
+
+ es-errors@1.3.0: {}
+
+ es-object-atoms@1.1.1:
+ dependencies:
+ es-errors: 1.3.0
+
+ es-set-tostringtag@2.1.0:
+ dependencies:
+ es-errors: 1.3.0
+ get-intrinsic: 1.3.0
+ has-tostringtag: 1.0.2
+ hasown: 2.0.2
+
+ escalade@3.2.0: {}
+
+ fast-deep-equal@3.1.3: {}
+
+ fast-glob@3.3.3:
+ dependencies:
+ '@nodelib/fs.stat': 2.0.5
+ '@nodelib/fs.walk': 1.2.8
+ glob-parent: 5.1.2
+ merge2: 1.4.1
+ micromatch: 4.0.8
+
+ fast-uri@3.1.0: {}
+
+ fastest-levenshtein@1.0.16: {}
+
+ fastq@1.19.1:
+ dependencies:
+ reusify: 1.1.0
+
+ fdir@6.5.0(picomatch@4.0.3):
+ optionalDependencies:
+ picomatch: 4.0.3
+
+ file-entry-cache@11.1.1:
+ dependencies:
+ flat-cache: 6.1.19
+
+ fill-range@7.1.1:
+ dependencies:
+ to-regex-range: 5.0.1
+
+ flat-cache@6.1.19:
+ dependencies:
+ cacheable: 2.3.0
+ flatted: 3.3.3
+ hookified: 1.14.0
+
+ flatted@3.3.3: {}
+
+ follow-redirects@1.15.11: {}
+
+ form-data@4.0.5:
+ dependencies:
+ asynckit: 0.4.0
+ combined-stream: 1.0.8
+ es-set-tostringtag: 2.1.0
+ hasown: 2.0.2
+ mime-types: 2.1.35
+
+ fsevents@2.3.3:
+ optional: true
+
+ function-bind@1.1.2: {}
+
+ gensync@1.0.0-beta.2: {}
+
+ get-intrinsic@1.3.0:
+ dependencies:
+ call-bind-apply-helpers: 1.0.2
+ es-define-property: 1.0.1
+ es-errors: 1.3.0
+ es-object-atoms: 1.1.1
+ function-bind: 1.1.2
+ get-proto: 1.0.1
+ gopd: 1.2.0
+ has-symbols: 1.1.0
+ hasown: 2.0.2
+ math-intrinsics: 1.1.0
+
+ get-proto@1.0.1:
+ dependencies:
+ dunder-proto: 1.0.1
+ es-object-atoms: 1.1.1
+
+ glob-parent@5.1.2:
+ dependencies:
+ is-glob: 4.0.3
+
+ global-modules@2.0.0:
+ dependencies:
+ global-prefix: 3.0.0
+
+ global-prefix@3.0.0:
+ dependencies:
+ ini: 1.3.8
+ kind-of: 6.0.3
+ which: 1.3.1
+
+ globby@11.1.0:
+ dependencies:
+ array-union: 2.1.0
+ dir-glob: 3.0.1
+ fast-glob: 3.3.3
+ ignore: 5.3.2
+ merge2: 1.4.1
+ slash: 3.0.0
+
+ globjoin@0.1.4: {}
+
+ globrex@0.1.2: {}
+
+ gopd@1.2.0: {}
+
+ has-flag@4.0.0: {}
+
+ has-symbols@1.1.0: {}
+
+ has-tostringtag@1.0.2:
+ dependencies:
+ has-symbols: 1.1.0
+
+ hashery@1.3.0:
+ dependencies:
+ hookified: 1.14.0
+
+ hasown@2.0.2:
+ dependencies:
+ function-bind: 1.1.2
+
+ hookified@1.14.0: {}
+
+ html-tags@3.3.1: {}
+
+ ignore@5.3.2: {}
+
+ ignore@7.0.5: {}
+
+ immutable@5.1.4: {}
+
+ import-fresh@3.3.1:
+ dependencies:
+ parent-module: 1.0.1
+ resolve-from: 4.0.0
+
+ imurmurhash@0.1.4: {}
+
+ ini@1.3.8: {}
+
+ is-arrayish@0.2.1: {}
+
+ is-extglob@2.1.1: {}
+
+ is-fullwidth-code-point@3.0.0: {}
+
+ is-glob@4.0.3:
+ dependencies:
+ is-extglob: 2.1.1
+
+ is-number@7.0.0: {}
+
+ is-plain-object@5.0.0: {}
+
+ isexe@2.0.0: {}
+
+ js-tokens@4.0.0: {}
+
+ js-yaml@4.1.1:
+ dependencies:
+ argparse: 2.0.1
+
+ jsesc@3.1.0: {}
+
+ json-parse-even-better-errors@2.3.1: {}
+
+ json-schema-traverse@1.0.0: {}
+
+ json5@2.2.3: {}
+
+ keyv@5.5.5:
+ dependencies:
+ '@keyv/serialize': 1.1.1
+
+ kind-of@6.0.3: {}
+
+ known-css-properties@0.37.0: {}
+
+ lightningcss-android-arm64@1.30.2:
+ optional: true
+
+ lightningcss-darwin-arm64@1.30.2:
+ optional: true
+
+ lightningcss-darwin-x64@1.30.2:
+ optional: true
+
+ lightningcss-freebsd-x64@1.30.2:
+ optional: true
+
+ lightningcss-linux-arm-gnueabihf@1.30.2:
+ optional: true
+
+ lightningcss-linux-arm64-gnu@1.30.2:
+ optional: true
+
+ lightningcss-linux-arm64-musl@1.30.2:
+ optional: true
+
+ lightningcss-linux-x64-gnu@1.30.2:
+ optional: true
+
+ lightningcss-linux-x64-musl@1.30.2:
+ optional: true
+
+ lightningcss-win32-arm64-msvc@1.30.2:
+ optional: true
+
+ lightningcss-win32-x64-msvc@1.30.2:
+ optional: true
+
+ lightningcss@1.30.2:
+ dependencies:
+ detect-libc: 2.1.2
+ optionalDependencies:
+ lightningcss-android-arm64: 1.30.2
+ lightningcss-darwin-arm64: 1.30.2
+ lightningcss-darwin-x64: 1.30.2
+ lightningcss-freebsd-x64: 1.30.2
+ lightningcss-linux-arm-gnueabihf: 1.30.2
+ lightningcss-linux-arm64-gnu: 1.30.2
+ lightningcss-linux-arm64-musl: 1.30.2
+ lightningcss-linux-x64-gnu: 1.30.2
+ lightningcss-linux-x64-musl: 1.30.2
+ lightningcss-win32-arm64-msvc: 1.30.2
+ lightningcss-win32-x64-msvc: 1.30.2
+
+ lines-and-columns@1.2.4: {}
+
+ lodash.truncate@4.4.2: {}
+
+ lru-cache@5.1.1:
+ dependencies:
+ yallist: 3.1.1
+
+ math-intrinsics@1.1.0: {}
+
+ mathml-tag-names@2.1.3: {}
+
+ mdn-data@2.12.2: {}
+
+ mdn-data@2.25.0: {}
+
+ meow@13.2.0: {}
+
+ merge2@1.4.1: {}
+
+ micromatch@4.0.8:
+ dependencies:
+ braces: 3.0.3
+ picomatch: 2.3.1
+
+ mime-db@1.52.0: {}
+
+ mime-types@2.1.35:
+ dependencies:
+ mime-db: 1.52.0
+
+ ms@2.1.3: {}
+
+ nanoid@3.3.11: {}
+
+ node-addon-api@7.1.1:
+ optional: true
+
+ node-releases@2.0.27: {}
+
+ normalize-path@3.0.0: {}
+
+ parent-module@1.0.1:
+ dependencies:
+ callsites: 3.1.0
+
+ parse-json@5.2.0:
+ dependencies:
+ '@babel/code-frame': 7.27.1
+ error-ex: 1.3.4
+ json-parse-even-better-errors: 2.3.1
+ lines-and-columns: 1.2.4
+
+ path-type@4.0.0: {}
+
+ picocolors@1.1.1: {}
+
+ picomatch@2.3.1: {}
+
+ picomatch@4.0.3: {}
+
+ postcss-media-query-parser@0.2.3: {}
+
+ postcss-resolve-nested-selector@0.1.6: {}
+
+ postcss-safe-parser@7.0.1(postcss@8.5.6):
+ dependencies:
+ postcss: 8.5.6
+
+ postcss-scss@4.0.9(postcss@8.5.6):
+ dependencies:
+ postcss: 8.5.6
+
+ postcss-selector-parser@7.1.1:
+ dependencies:
+ cssesc: 3.0.0
+ util-deprecate: 1.0.2
+
+ postcss-value-parser@4.2.0: {}
+
+ postcss@8.5.6:
+ dependencies:
+ nanoid: 3.3.11
+ picocolors: 1.1.1
+ source-map-js: 1.2.1
+
+ proxy-from-env@1.1.0: {}
+
+ qified@0.5.3:
+ dependencies:
+ hookified: 1.14.0
+
+ queue-microtask@1.2.3: {}
+
+ react-dom@19.2.1(react@19.2.1):
+ dependencies:
+ react: 19.2.1
+ scheduler: 0.27.0
+
+ react-error-boundary@6.0.0(react@19.2.1):
+ dependencies:
+ '@babel/runtime': 7.28.4
+ react: 19.2.1
+
+ react-icon@1.0.0(babel-runtime@5.8.38)(react@19.2.1):
+ dependencies:
+ babel-runtime: 5.8.38
+ react: 19.2.1
+
+ react-icons@5.5.0(react@19.2.1):
+ dependencies:
+ react: 19.2.1
+
+ react-refresh@0.18.0: {}
+
+ react-router-dom@7.10.1(react-dom@19.2.1(react@19.2.1))(react@19.2.1):
+ dependencies:
+ react: 19.2.1
+ react-dom: 19.2.1(react@19.2.1)
+ react-router: 7.10.1(react-dom@19.2.1(react@19.2.1))(react@19.2.1)
+
+ react-router@7.10.1(react-dom@19.2.1(react@19.2.1))(react@19.2.1):
+ dependencies:
+ cookie: 1.1.1
+ react: 19.2.1
+ set-cookie-parser: 2.7.2
+ optionalDependencies:
+ react-dom: 19.2.1(react@19.2.1)
+
+ react@19.2.1: {}
+
+ readdirp@4.1.2: {}
+
+ require-from-string@2.0.2: {}
+
+ resolve-from@4.0.0: {}
+
+ resolve-from@5.0.0: {}
+
+ reusify@1.1.0: {}
+
+ rolldown-vite@7.2.5(@types/node@24.10.2)(sass@1.95.0):
+ dependencies:
+ '@oxc-project/runtime': 0.97.0
+ fdir: 6.5.0(picomatch@4.0.3)
+ lightningcss: 1.30.2
+ picomatch: 4.0.3
+ postcss: 8.5.6
+ rolldown: 1.0.0-beta.50
+ tinyglobby: 0.2.15
+ optionalDependencies:
+ '@types/node': 24.10.2
+ fsevents: 2.3.3
+ sass: 1.95.0
+
+ rolldown@1.0.0-beta.50:
+ dependencies:
+ '@oxc-project/types': 0.97.0
+ '@rolldown/pluginutils': 1.0.0-beta.50
+ optionalDependencies:
+ '@rolldown/binding-android-arm64': 1.0.0-beta.50
+ '@rolldown/binding-darwin-arm64': 1.0.0-beta.50
+ '@rolldown/binding-darwin-x64': 1.0.0-beta.50
+ '@rolldown/binding-freebsd-x64': 1.0.0-beta.50
+ '@rolldown/binding-linux-arm-gnueabihf': 1.0.0-beta.50
+ '@rolldown/binding-linux-arm64-gnu': 1.0.0-beta.50
+ '@rolldown/binding-linux-arm64-musl': 1.0.0-beta.50
+ '@rolldown/binding-linux-x64-gnu': 1.0.0-beta.50
+ '@rolldown/binding-linux-x64-musl': 1.0.0-beta.50
+ '@rolldown/binding-openharmony-arm64': 1.0.0-beta.50
+ '@rolldown/binding-wasm32-wasi': 1.0.0-beta.50
+ '@rolldown/binding-win32-arm64-msvc': 1.0.0-beta.50
+ '@rolldown/binding-win32-ia32-msvc': 1.0.0-beta.50
+ '@rolldown/binding-win32-x64-msvc': 1.0.0-beta.50
+
+ run-parallel@1.2.0:
+ dependencies:
+ queue-microtask: 1.2.3
+
+ sass@1.95.0:
+ dependencies:
+ chokidar: 4.0.3
+ immutable: 5.1.4
+ source-map-js: 1.2.1
+ optionalDependencies:
+ '@parcel/watcher': 2.5.1
+
+ scheduler@0.27.0: {}
+
+ semver@6.3.1: {}
+
+ set-cookie-parser@2.7.2: {}
+
+ signal-exit@4.1.0: {}
+
+ slash@3.0.0: {}
+
+ slice-ansi@4.0.0:
+ dependencies:
+ ansi-styles: 4.3.0
+ astral-regex: 2.0.0
+ is-fullwidth-code-point: 3.0.0
+
+ sonner@2.0.7(react-dom@19.2.1(react@19.2.1))(react@19.2.1):
+ dependencies:
+ react: 19.2.1
+ react-dom: 19.2.1(react@19.2.1)
+
+ source-map-js@1.2.1: {}
+
+ string-width@4.2.3:
+ dependencies:
+ emoji-regex: 8.0.0
+ is-fullwidth-code-point: 3.0.0
+ strip-ansi: 6.0.1
+
+ strip-ansi@6.0.1:
+ dependencies:
+ ansi-regex: 5.0.1
+
+ stylelint-config-prettier-scss@1.0.0(stylelint@16.26.1(typescript@5.9.3)):
+ dependencies:
+ stylelint: 16.26.1(typescript@5.9.3)
+
+ stylelint-config-recommended-scss@16.0.2(postcss@8.5.6)(stylelint@16.26.1(typescript@5.9.3)):
+ dependencies:
+ postcss-scss: 4.0.9(postcss@8.5.6)
+ stylelint: 16.26.1(typescript@5.9.3)
+ stylelint-config-recommended: 17.0.0(stylelint@16.26.1(typescript@5.9.3))
+ stylelint-scss: 6.13.0(stylelint@16.26.1(typescript@5.9.3))
+ optionalDependencies:
+ postcss: 8.5.6
+
+ stylelint-config-recommended@17.0.0(stylelint@16.26.1(typescript@5.9.3)):
+ dependencies:
+ stylelint: 16.26.1(typescript@5.9.3)
+
+ stylelint-config-standard-scss@16.0.0(postcss@8.5.6)(stylelint@16.26.1(typescript@5.9.3)):
+ dependencies:
+ stylelint: 16.26.1(typescript@5.9.3)
+ stylelint-config-recommended-scss: 16.0.2(postcss@8.5.6)(stylelint@16.26.1(typescript@5.9.3))
+ stylelint-config-standard: 39.0.1(stylelint@16.26.1(typescript@5.9.3))
+ optionalDependencies:
+ postcss: 8.5.6
+
+ stylelint-config-standard@39.0.1(stylelint@16.26.1(typescript@5.9.3)):
+ dependencies:
+ stylelint: 16.26.1(typescript@5.9.3)
+ stylelint-config-recommended: 17.0.0(stylelint@16.26.1(typescript@5.9.3))
+
+ stylelint-scss@6.13.0(stylelint@16.26.1(typescript@5.9.3)):
+ dependencies:
+ css-tree: 3.1.0
+ is-plain-object: 5.0.0
+ known-css-properties: 0.37.0
+ mdn-data: 2.25.0
+ postcss-media-query-parser: 0.2.3
+ postcss-resolve-nested-selector: 0.1.6
+ postcss-selector-parser: 7.1.1
+ postcss-value-parser: 4.2.0
+ stylelint: 16.26.1(typescript@5.9.3)
+
+ stylelint@16.26.1(typescript@5.9.3):
+ dependencies:
+ '@csstools/css-parser-algorithms': 3.0.5(@csstools/css-tokenizer@3.0.4)
+ '@csstools/css-syntax-patches-for-csstree': 1.0.20
+ '@csstools/css-tokenizer': 3.0.4
+ '@csstools/media-query-list-parser': 4.0.3(@csstools/css-parser-algorithms@3.0.5(@csstools/css-tokenizer@3.0.4))(@csstools/css-tokenizer@3.0.4)
+ '@csstools/selector-specificity': 5.0.0(postcss-selector-parser@7.1.1)
+ '@dual-bundle/import-meta-resolve': 4.2.1
+ balanced-match: 2.0.0
+ colord: 2.9.3
+ cosmiconfig: 9.0.0(typescript@5.9.3)
+ css-functions-list: 3.2.3
+ css-tree: 3.1.0
+ debug: 4.4.3
+ fast-glob: 3.3.3
+ fastest-levenshtein: 1.0.16
+ file-entry-cache: 11.1.1
+ global-modules: 2.0.0
+ globby: 11.1.0
+ globjoin: 0.1.4
+ html-tags: 3.3.1
+ ignore: 7.0.5
+ imurmurhash: 0.1.4
+ is-plain-object: 5.0.0
+ known-css-properties: 0.37.0
+ mathml-tag-names: 2.1.3
+ meow: 13.2.0
+ micromatch: 4.0.8
+ normalize-path: 3.0.0
+ picocolors: 1.1.1
+ postcss: 8.5.6
+ postcss-resolve-nested-selector: 0.1.6
+ postcss-safe-parser: 7.0.1(postcss@8.5.6)
+ postcss-selector-parser: 7.1.1
+ postcss-value-parser: 4.2.0
+ resolve-from: 5.0.0
+ string-width: 4.2.3
+ supports-hyperlinks: 3.2.0
+ svg-tags: 1.0.0
+ table: 6.9.0
+ write-file-atomic: 5.0.1
+ transitivePeerDependencies:
+ - supports-color
+ - typescript
+
+ supports-color@7.2.0:
+ dependencies:
+ has-flag: 4.0.0
+
+ supports-hyperlinks@3.2.0:
+ dependencies:
+ has-flag: 4.0.0
+ supports-color: 7.2.0
+
+ svg-tags@1.0.0: {}
+
+ table@6.9.0:
+ dependencies:
+ ajv: 8.17.1
+ lodash.truncate: 4.4.2
+ slice-ansi: 4.0.0
+ string-width: 4.2.3
+ strip-ansi: 6.0.1
+
+ tinyglobby@0.2.15:
+ dependencies:
+ fdir: 6.5.0(picomatch@4.0.3)
+ picomatch: 4.0.3
+
+ to-regex-range@5.0.1:
+ dependencies:
+ is-number: 7.0.0
+
+ tsconfck@3.1.6(typescript@5.9.3):
+ optionalDependencies:
+ typescript: 5.9.3
+
+ tslib@2.8.1:
+ optional: true
+
+ typescript@5.9.3: {}
+
+ undici-types@7.16.0: {}
+
+ update-browserslist-db@1.2.2(browserslist@4.28.1):
+ dependencies:
+ browserslist: 4.28.1
+ escalade: 3.2.0
+ picocolors: 1.1.1
+
+ util-deprecate@1.0.2: {}
+
+ vite-tsconfig-paths@5.1.4(rolldown-vite@7.2.5(@types/node@24.10.2)(sass@1.95.0))(typescript@5.9.3):
+ dependencies:
+ debug: 4.4.3
+ globrex: 0.1.2
+ tsconfck: 3.1.6(typescript@5.9.3)
+ optionalDependencies:
+ vite: rolldown-vite@7.2.5(@types/node@24.10.2)(sass@1.95.0)
+ transitivePeerDependencies:
+ - supports-color
+ - typescript
+
+ which@1.3.1:
+ dependencies:
+ isexe: 2.0.0
+
+ write-file-atomic@5.0.1:
+ dependencies:
+ imurmurhash: 0.1.4
+ signal-exit: 4.1.0
+
+ yallist@3.1.1: {}
+
+ zod@4.1.13: {}
+
+ zustand@5.0.9(@types/react@19.2.7)(react@19.2.1):
+ optionalDependencies:
+ '@types/react': 19.2.7
+ react: 19.2.1
diff --git a/frontends/open/react-scss/public/assets/android-chrome-192x192.png b/frontends/open/react-scss/public/assets/android-chrome-192x192.png
new file mode 100644
index 0000000..6a31898
Binary files /dev/null and b/frontends/open/react-scss/public/assets/android-chrome-192x192.png differ
diff --git a/frontends/open/react-scss/public/assets/android-chrome-512x512.png b/frontends/open/react-scss/public/assets/android-chrome-512x512.png
new file mode 100644
index 0000000..e79bc03
Binary files /dev/null and b/frontends/open/react-scss/public/assets/android-chrome-512x512.png differ
diff --git a/frontends/open/react-scss/public/assets/apple-touch-icon.png b/frontends/open/react-scss/public/assets/apple-touch-icon.png
new file mode 100644
index 0000000..be0c040
Binary files /dev/null and b/frontends/open/react-scss/public/assets/apple-touch-icon.png differ
diff --git a/frontends/open/react-scss/public/assets/favicon-16x16.png b/frontends/open/react-scss/public/assets/favicon-16x16.png
new file mode 100644
index 0000000..32c2cf9
Binary files /dev/null and b/frontends/open/react-scss/public/assets/favicon-16x16.png differ
diff --git a/frontends/open/react-scss/public/assets/favicon-32x32.png b/frontends/open/react-scss/public/assets/favicon-32x32.png
new file mode 100644
index 0000000..87c75f4
Binary files /dev/null and b/frontends/open/react-scss/public/assets/favicon-32x32.png differ
diff --git a/frontends/open/react-scss/public/assets/favicon.ico b/frontends/open/react-scss/public/assets/favicon.ico
new file mode 100644
index 0000000..6c43eea
Binary files /dev/null and b/frontends/open/react-scss/public/assets/favicon.ico differ
diff --git a/frontends/open/react-scss/public/assets/site.webmanifest b/frontends/open/react-scss/public/assets/site.webmanifest
new file mode 100644
index 0000000..45dc8a2
--- /dev/null
+++ b/frontends/open/react-scss/public/assets/site.webmanifest
@@ -0,0 +1 @@
+{"name":"","short_name":"","icons":[{"src":"/android-chrome-192x192.png","sizes":"192x192","type":"image/png"},{"src":"/android-chrome-512x512.png","sizes":"512x512","type":"image/png"}],"theme_color":"#ffffff","background_color":"#ffffff","display":"standalone"}
\ No newline at end of file
diff --git a/frontends/open/react-scss/src/App.tsx b/frontends/open/react-scss/src/App.tsx
new file mode 100644
index 0000000..a7d82d6
--- /dev/null
+++ b/frontends/open/react-scss/src/App.tsx
@@ -0,0 +1,36 @@
+// ===========================
+// ©AngelaMos | 2026
+// App.tsx
+// ===========================
+
+import { QueryClientProvider } from '@tanstack/react-query'
+import { ReactQueryDevtools } from '@tanstack/react-query-devtools'
+import { RouterProvider } from 'react-router-dom'
+import { Toaster } from 'sonner'
+
+import { queryClient } from '@/core/api'
+import { router } from '@/core/app/routers'
+import '@/core/app/toast.module.scss'
+
+export default function App(): React.ReactElement {
+ return (
+
+
+
+
+
+
+
+ )
+}
diff --git a/frontends/open/react-scss/src/api/hooks/index.ts b/frontends/open/react-scss/src/api/hooks/index.ts
new file mode 100644
index 0000000..6221af9
--- /dev/null
+++ b/frontends/open/react-scss/src/api/hooks/index.ts
@@ -0,0 +1,4 @@
+// ===================
+// © AngelaMos | 2026
+// index.ts
+// ===================
diff --git a/frontends/open/react-scss/src/api/index.ts b/frontends/open/react-scss/src/api/index.ts
new file mode 100644
index 0000000..0840a7c
--- /dev/null
+++ b/frontends/open/react-scss/src/api/index.ts
@@ -0,0 +1,7 @@
+// ===================
+// © AngelaMos | 2025
+// index.ts
+// ===================
+
+export * from './hooks'
+export * from './types'
diff --git a/frontends/open/react-scss/src/api/types/index.ts b/frontends/open/react-scss/src/api/types/index.ts
new file mode 100644
index 0000000..6221af9
--- /dev/null
+++ b/frontends/open/react-scss/src/api/types/index.ts
@@ -0,0 +1,4 @@
+// ===================
+// © AngelaMos | 2026
+// index.ts
+// ===================
diff --git a/frontends/open/react-scss/src/components/index.tsx b/frontends/open/react-scss/src/components/index.tsx
new file mode 100644
index 0000000..6b0a732
--- /dev/null
+++ b/frontends/open/react-scss/src/components/index.tsx
@@ -0,0 +1,4 @@
+/**
+ * ©AngelaMos | 2025
+ * index.tsx
+ */
diff --git a/frontends/open/react-scss/src/config.ts b/frontends/open/react-scss/src/config.ts
new file mode 100644
index 0000000..87c9647
--- /dev/null
+++ b/frontends/open/react-scss/src/config.ts
@@ -0,0 +1,68 @@
+// ===================
+// © AngelaMos | 2026
+// config.ts
+// ===================
+const API_VERSION = 'v1'
+
+export const API_ENDPOINTS = {
+ USERS: {
+ BASE: `/${API_VERSION}/users`,
+ BY_ID: (id: string) => `/${API_VERSION}/users/${id}`,
+ },
+} as const
+
+export const QUERY_KEYS = {
+ USERS: {
+ ALL: ['users'] as const,
+ BY_ID: (id: string) => [...QUERY_KEYS.USERS.ALL, 'detail', id] as const,
+ },
+} as const
+
+export const ROUTES = {
+ HOME: '/',
+ DASHBOARD: '/dashboard',
+ SETTINGS: '/settings',
+} as const
+
+export const STORAGE_KEYS = {
+ UI: 'ui-storage',
+} as const
+
+export const QUERY_CONFIG = {
+ STALE_TIME: {
+ USER: 1000 * 60 * 5,
+ STATIC: Infinity,
+ FREQUENT: 1000 * 30,
+ },
+ GC_TIME: {
+ DEFAULT: 1000 * 60 * 30,
+ LONG: 1000 * 60 * 60,
+ },
+ RETRY: {
+ DEFAULT: 3,
+ NONE: 0,
+ },
+} as const
+
+export const HTTP_STATUS = {
+ OK: 200,
+ CREATED: 201,
+ NO_CONTENT: 204,
+ BAD_REQUEST: 400,
+ UNAUTHORIZED: 401,
+ FORBIDDEN: 403,
+ NOT_FOUND: 404,
+ CONFLICT: 409,
+ TOO_MANY_REQUESTS: 429,
+ INTERNAL_SERVER: 500,
+} as const
+
+export const PAGINATION = {
+ DEFAULT_PAGE: 1,
+ DEFAULT_SIZE: 20,
+ MAX_SIZE: 100,
+} as const
+
+export type ApiEndpoint = typeof API_ENDPOINTS
+export type QueryKey = typeof QUERY_KEYS
+export type Route = typeof ROUTES
diff --git a/frontends/open/react-scss/src/core/api/api.config.ts b/frontends/open/react-scss/src/core/api/api.config.ts
new file mode 100644
index 0000000..f48a4d0
--- /dev/null
+++ b/frontends/open/react-scss/src/core/api/api.config.ts
@@ -0,0 +1,17 @@
+// ===================
+// © AngelaMos | 2026
+// api.config.ts
+// ===================
+
+import axios, { type AxiosInstance } from 'axios'
+
+const getBaseURL = (): string => {
+ return import.meta.env.VITE_API_URL ?? '/api'
+}
+
+export const apiClient: AxiosInstance = axios.create({
+ baseURL: getBaseURL(),
+ timeout: 15000,
+ headers: { 'Content-Type': 'application/json' },
+ withCredentials: true,
+})
diff --git a/frontends/open/react-scss/src/core/api/errors.ts b/frontends/open/react-scss/src/core/api/errors.ts
new file mode 100644
index 0000000..fde5ec6
--- /dev/null
+++ b/frontends/open/react-scss/src/core/api/errors.ts
@@ -0,0 +1,114 @@
+/**
+ * ©AngelaMos | 2025
+ * errors.ts
+ */
+
+import type { AxiosError } from 'axios'
+
+export const ApiErrorCode = {
+ NETWORK_ERROR: 'NETWORK_ERROR',
+ VALIDATION_ERROR: 'VALIDATION_ERROR',
+ AUTHENTICATION_ERROR: 'AUTHENTICATION_ERROR',
+ AUTHORIZATION_ERROR: 'AUTHORIZATION_ERROR',
+ NOT_FOUND: 'NOT_FOUND',
+ CONFLICT: 'CONFLICT',
+ RATE_LIMITED: 'RATE_LIMITED',
+ SERVER_ERROR: 'SERVER_ERROR',
+ UNKNOWN_ERROR: 'UNKNOWN_ERROR',
+} as const
+
+export type ApiErrorCode = (typeof ApiErrorCode)[keyof typeof ApiErrorCode]
+
+export class ApiError extends Error {
+ readonly code: ApiErrorCode
+ readonly statusCode: number
+ readonly details?: Record
+
+ constructor(
+ message: string,
+ code: ApiErrorCode,
+ statusCode: number,
+ details?: Record
+ ) {
+ super(message)
+ this.name = 'ApiError'
+ this.code = code
+ this.statusCode = statusCode
+ this.details = details
+ }
+
+ getUserMessage(): string {
+ const messages: Record = {
+ [ApiErrorCode.NETWORK_ERROR]:
+ 'Unable to connect. Please check your internet connection.',
+ [ApiErrorCode.VALIDATION_ERROR]: 'Please check your input and try again.',
+ [ApiErrorCode.AUTHENTICATION_ERROR]:
+ 'Your session has expired. Please log in again.',
+ [ApiErrorCode.AUTHORIZATION_ERROR]:
+ 'You do not have permission to perform this action.',
+ [ApiErrorCode.NOT_FOUND]: 'The requested resource was not found.',
+ [ApiErrorCode.CONFLICT]:
+ 'This operation conflicts with an existing resource.',
+ [ApiErrorCode.RATE_LIMITED]:
+ 'Too many requests. Please wait a moment and try again.',
+ [ApiErrorCode.SERVER_ERROR]:
+ 'Something went wrong on our end. Please try again later.',
+ [ApiErrorCode.UNKNOWN_ERROR]:
+ 'An unexpected error occurred. Please try again.',
+ }
+ return messages[this.code]
+ }
+}
+
+interface ApiErrorResponse {
+ detail?: string | { msg: string; type: string }[]
+ message?: string
+}
+
+export function transformAxiosError(error: AxiosError): ApiError {
+ if (!error.response) {
+ return new ApiError('Network error', ApiErrorCode.NETWORK_ERROR, 0)
+ }
+
+ const { status } = error.response
+ const data = error.response.data as ApiErrorResponse | undefined
+ let message = 'An error occurred'
+ let details: Record | undefined
+
+ if (data?.detail) {
+ if (typeof data.detail === 'string') {
+ message = data.detail
+ } else if (Array.isArray(data.detail)) {
+ details = { validation: [] }
+ data.detail.forEach((err) => {
+ details?.validation.push(err.msg)
+ })
+ message = 'Validation error'
+ }
+ } else if (data?.message) {
+ message = data.message
+ }
+
+ const codeMap: Record = {
+ 400: ApiErrorCode.VALIDATION_ERROR,
+ 401: ApiErrorCode.AUTHENTICATION_ERROR,
+ 403: ApiErrorCode.AUTHORIZATION_ERROR,
+ 404: ApiErrorCode.NOT_FOUND,
+ 409: ApiErrorCode.CONFLICT,
+ 429: ApiErrorCode.RATE_LIMITED,
+ 500: ApiErrorCode.SERVER_ERROR,
+ 502: ApiErrorCode.SERVER_ERROR,
+ 503: ApiErrorCode.SERVER_ERROR,
+ 504: ApiErrorCode.SERVER_ERROR,
+ }
+
+ const code = codeMap[status] || ApiErrorCode.UNKNOWN_ERROR
+
+ return new ApiError(message, code, status, details)
+}
+
+declare module '@tanstack/react-query' {
+ interface Register {
+ defaultError: ApiError
+ }
+}
diff --git a/frontends/open/react-scss/src/core/api/index.ts b/frontends/open/react-scss/src/core/api/index.ts
new file mode 100644
index 0000000..1818cd7
--- /dev/null
+++ b/frontends/open/react-scss/src/core/api/index.ts
@@ -0,0 +1,8 @@
+// ===================
+// © AngelaMos | 2025
+// index.ts
+// ===================
+
+export * from './api.config'
+export * from './errors'
+export * from './query.config'
diff --git a/frontends/open/react-scss/src/core/api/query.config.ts b/frontends/open/react-scss/src/core/api/query.config.ts
new file mode 100644
index 0000000..8244b22
--- /dev/null
+++ b/frontends/open/react-scss/src/core/api/query.config.ts
@@ -0,0 +1,105 @@
+// ===================
+// © AngelaMos | 2025
+// query.config.ts
+// ===================
+
+import { MutationCache, QueryCache, QueryClient } from '@tanstack/react-query'
+import { toast } from 'sonner'
+import { QUERY_CONFIG } from '@/config'
+import { ApiError, ApiErrorCode } from './errors'
+
+const NO_RETRY_ERROR_CODES: readonly ApiErrorCode[] = [
+ ApiErrorCode.AUTHENTICATION_ERROR,
+ ApiErrorCode.AUTHORIZATION_ERROR,
+ ApiErrorCode.NOT_FOUND,
+ ApiErrorCode.VALIDATION_ERROR,
+] as const
+
+const shouldRetryQuery = (failureCount: number, error: Error): boolean => {
+ if (error instanceof ApiError) {
+ if (NO_RETRY_ERROR_CODES.includes(error.code)) {
+ return false
+ }
+ }
+ return failureCount < QUERY_CONFIG.RETRY.DEFAULT
+}
+
+const calculateRetryDelay = (attemptIndex: number): number => {
+ const baseDelay = 1000
+ const maxDelay = 30000
+ return Math.min(baseDelay * 2 ** attemptIndex, maxDelay)
+}
+
+const handleQueryCacheError = (
+ error: Error,
+ query: { state: { data: unknown } }
+): void => {
+ if (query.state.data !== undefined) {
+ const message =
+ error instanceof ApiError
+ ? error.getUserMessage()
+ : 'Background update failed'
+ toast.error(message)
+ }
+}
+
+const handleMutationCacheError = (
+ error: Error,
+ _variables: unknown,
+ _context: unknown,
+ mutation: { options: { onError?: unknown } }
+): void => {
+ if (mutation.options.onError === undefined) {
+ const message =
+ error instanceof ApiError ? error.getUserMessage() : 'Operation failed'
+ toast.error(message)
+ }
+}
+
+export const QUERY_STRATEGIES = {
+ standard: {
+ staleTime: QUERY_CONFIG.STALE_TIME.USER,
+ gcTime: QUERY_CONFIG.GC_TIME.DEFAULT,
+ },
+ frequent: {
+ staleTime: QUERY_CONFIG.STALE_TIME.FREQUENT,
+ gcTime: QUERY_CONFIG.GC_TIME.DEFAULT,
+ refetchInterval: QUERY_CONFIG.STALE_TIME.FREQUENT,
+ },
+ static: {
+ staleTime: QUERY_CONFIG.STALE_TIME.STATIC,
+ gcTime: QUERY_CONFIG.GC_TIME.LONG,
+ refetchOnMount: false,
+ refetchOnWindowFocus: false,
+ },
+ auth: {
+ staleTime: QUERY_CONFIG.STALE_TIME.USER,
+ gcTime: QUERY_CONFIG.GC_TIME.DEFAULT,
+ retry: QUERY_CONFIG.RETRY.NONE,
+ },
+} as const
+
+export type QueryStrategy = keyof typeof QUERY_STRATEGIES
+
+export const queryClient = new QueryClient({
+ defaultOptions: {
+ queries: {
+ staleTime: QUERY_CONFIG.STALE_TIME.USER,
+ gcTime: QUERY_CONFIG.GC_TIME.DEFAULT,
+ retry: shouldRetryQuery,
+ retryDelay: calculateRetryDelay,
+ refetchOnWindowFocus: true,
+ refetchOnMount: true,
+ refetchOnReconnect: true,
+ },
+ mutations: {
+ retry: QUERY_CONFIG.RETRY.NONE,
+ },
+ },
+ queryCache: new QueryCache({
+ onError: handleQueryCacheError,
+ }),
+ mutationCache: new MutationCache({
+ onError: handleMutationCacheError,
+ }),
+})
diff --git a/frontends/open/react-scss/src/core/app/routers.tsx b/frontends/open/react-scss/src/core/app/routers.tsx
new file mode 100644
index 0000000..d17138c
--- /dev/null
+++ b/frontends/open/react-scss/src/core/app/routers.tsx
@@ -0,0 +1,34 @@
+// ===================
+// © AngelaMos | 2026
+// routers.tsx
+// ===================
+
+import { createBrowserRouter, type RouteObject } from 'react-router-dom'
+import { ROUTES } from '@/config'
+import { Shell } from './shell'
+
+const routes: RouteObject[] = [
+ {
+ path: ROUTES.HOME,
+ lazy: () => import('@/pages/landing'),
+ },
+ {
+ element: ,
+ children: [
+ {
+ path: ROUTES.DASHBOARD,
+ lazy: () => import('@/pages/dashboard'),
+ },
+ {
+ path: ROUTES.SETTINGS,
+ lazy: () => import('@/pages/settings'),
+ },
+ ],
+ },
+ {
+ path: '*',
+ lazy: () => import('@/pages/landing'),
+ },
+]
+
+export const router = createBrowserRouter(routes)
diff --git a/frontends/open/react-scss/src/core/app/shell.module.scss b/frontends/open/react-scss/src/core/app/shell.module.scss
new file mode 100644
index 0000000..3466896
--- /dev/null
+++ b/frontends/open/react-scss/src/core/app/shell.module.scss
@@ -0,0 +1,4 @@
+// ===================
+// © AngelaMos | 2026
+// shell.module.scss
+// ===================
diff --git a/frontends/open/react-scss/src/core/app/shell.tsx b/frontends/open/react-scss/src/core/app/shell.tsx
new file mode 100644
index 0000000..3296f38
--- /dev/null
+++ b/frontends/open/react-scss/src/core/app/shell.tsx
@@ -0,0 +1,116 @@
+/**
+ * ©AngelaMos | 2026
+ * shell.tsx
+ */
+
+import { Suspense } from 'react'
+import { ErrorBoundary } from 'react-error-boundary'
+import { GiCardAceClubs, GiCardJoker } from 'react-icons/gi'
+import { LuChevronLeft, LuChevronRight, LuMenu } from 'react-icons/lu'
+import { NavLink, Outlet, useLocation } from 'react-router-dom'
+import { ROUTES } from '@/config'
+import { useUIStore } from '@/core/lib'
+import styles from './shell.module.scss'
+
+const NAV_ITEMS = [
+ { path: ROUTES.DASHBOARD, label: 'Dashboard', icon: GiCardJoker },
+ { path: ROUTES.SETTINGS, label: 'Settings', icon: GiCardAceClubs },
+]
+
+function ShellErrorFallback({ error }: { error: Error }): React.ReactElement {
+ return (
+
+
Something went wrong
+
{error.message}
+
+ )
+}
+
+function ShellLoading(): React.ReactElement {
+ return Loading...
+}
+
+function getPageTitle(pathname: string): string {
+ const item = NAV_ITEMS.find((i) => i.path === pathname)
+ return item?.label ?? 'Dashboard'
+}
+
+export function Shell(): React.ReactElement {
+ const location = useLocation()
+ const { sidebarOpen, sidebarCollapsed, toggleSidebar, toggleSidebarCollapsed } =
+ useUIStore()
+
+ const pageTitle = getPageTitle(location.pathname)
+
+ return (
+
+
+
+ {sidebarOpen && (
+
+ )
+}
diff --git a/frontends/open/react-scss/src/core/app/toast.module.scss b/frontends/open/react-scss/src/core/app/toast.module.scss
new file mode 100644
index 0000000..62a8ee3
--- /dev/null
+++ b/frontends/open/react-scss/src/core/app/toast.module.scss
@@ -0,0 +1,4 @@
+// ===================
+// © AngelaMos | 2026
+// toast.module.scss
+// ===================
diff --git a/frontends/open/react-scss/src/core/lib/index.ts b/frontends/open/react-scss/src/core/lib/index.ts
new file mode 100644
index 0000000..cdee46e
--- /dev/null
+++ b/frontends/open/react-scss/src/core/lib/index.ts
@@ -0,0 +1,6 @@
+// ===================
+// © AngelaMos | 2026
+// index.ts
+// ===================
+
+export * from './shell.ui.store'
diff --git a/frontends/open/react-scss/src/core/lib/shell.ui.store.ts b/frontends/open/react-scss/src/core/lib/shell.ui.store.ts
new file mode 100644
index 0000000..d601a53
--- /dev/null
+++ b/frontends/open/react-scss/src/core/lib/shell.ui.store.ts
@@ -0,0 +1,63 @@
+/**
+ * ©AngelaMos | 2025
+ * ui.store.ts
+ */
+
+import { create } from 'zustand'
+import { devtools, persist } from 'zustand/middleware'
+
+type Theme = 'light' | 'dark' | 'system'
+
+interface UIState {
+ theme: Theme
+ sidebarOpen: boolean
+ sidebarCollapsed: boolean
+ setTheme: (theme: Theme) => void
+ toggleSidebar: () => void
+ setSidebarOpen: (open: boolean) => void
+ toggleSidebarCollapsed: () => void
+}
+
+export const useUIStore = create()(
+ devtools(
+ persist(
+ (set) => ({
+ theme: 'dark',
+ sidebarOpen: false,
+ sidebarCollapsed: false,
+
+ setTheme: (theme) => set({ theme }, false, 'ui/setTheme'),
+
+ toggleSidebar: () =>
+ set(
+ (state) => ({ sidebarOpen: !state.sidebarOpen }),
+ false,
+ 'ui/toggleSidebar'
+ ),
+
+ setSidebarOpen: (open) =>
+ set({ sidebarOpen: open }, false, 'ui/setSidebarOpen'),
+
+ toggleSidebarCollapsed: () =>
+ set(
+ (state) => ({ sidebarCollapsed: !state.sidebarCollapsed }),
+ false,
+ 'ui/toggleSidebarCollapsed'
+ ),
+ }),
+ {
+ name: 'ui-storage',
+ partialize: (state) => ({
+ theme: state.theme,
+ sidebarCollapsed: state.sidebarCollapsed,
+ }),
+ }
+ ),
+ { name: 'UIStore' }
+ )
+)
+
+export const useTheme = (): Theme => useUIStore((s) => s.theme)
+export const useSidebarOpen = (): boolean => useUIStore((s) => s.sidebarOpen)
+export const useSidebarCollapsed = (): boolean =>
+ useUIStore((s) => s.sidebarCollapsed)
diff --git a/frontends/open/react-scss/src/main.tsx b/frontends/open/react-scss/src/main.tsx
new file mode 100644
index 0000000..1b1f2c8
--- /dev/null
+++ b/frontends/open/react-scss/src/main.tsx
@@ -0,0 +1,15 @@
+// ===========================
+// ©AngelaMos | 2025
+// main.tsx
+// ===========================
+
+import { StrictMode } from 'react'
+import { createRoot } from 'react-dom/client'
+import App from './App'
+import './styles.scss'
+
+createRoot(document.getElementById('root')!).render(
+
+
+
+)
diff --git a/frontends/open/react-scss/src/pages/dashboard/dashboard.module.scss b/frontends/open/react-scss/src/pages/dashboard/dashboard.module.scss
new file mode 100644
index 0000000..cbf1f90
--- /dev/null
+++ b/frontends/open/react-scss/src/pages/dashboard/dashboard.module.scss
@@ -0,0 +1,4 @@
+// ===================
+// © AngelaMos | 2026
+// dashboard.module.scss
+// ===================
diff --git a/frontends/open/react-scss/src/pages/dashboard/index.tsx b/frontends/open/react-scss/src/pages/dashboard/index.tsx
new file mode 100644
index 0000000..ca90889
--- /dev/null
+++ b/frontends/open/react-scss/src/pages/dashboard/index.tsx
@@ -0,0 +1,62 @@
+/**
+ * ©AngelaMos | 2026
+ * index.tsx
+ */
+
+import styles from './dashboard.module.scss'
+
+const AVAILABLE_STORES = [
+ {
+ name: 'useUIStore()',
+ file: 'core/lib/shell.ui.store.ts',
+ description: 'Theme, sidebar open/collapsed state',
+ },
+]
+
+const SUGGESTED_FEATURES = [
+ 'Stats and metrics',
+ 'Recent activity feed',
+ 'Quick actions',
+ 'Charts and analytics',
+ 'Notifications overview',
+ 'Task/project summary',
+]
+
+export function Component(): React.ReactElement {
+ return (
+
+
+
+
Welcome
+
+ Template page — build your dashboard here
+
+
+
+
+ Available Stores
+
+ {AVAILABLE_STORES.map((store) => (
+
+
{store.name}
+
{store.description}
+
{store.file}
+
+ ))}
+
+
+
+
+ Suggested Features
+
+ {SUGGESTED_FEATURES.map((feature) => (
+ - {feature}
+ ))}
+
+
+
+
+ )
+}
+
+Component.displayName = 'Dashboard'
diff --git a/frontends/open/react-scss/src/pages/landing/index.tsx b/frontends/open/react-scss/src/pages/landing/index.tsx
new file mode 100644
index 0000000..7ec81be
--- /dev/null
+++ b/frontends/open/react-scss/src/pages/landing/index.tsx
@@ -0,0 +1,12 @@
+// ===================
+// © AngelaMos | 2026
+// index.tsx
+// ===================
+
+import styles from './landing.module.scss'
+
+export function Component(): React.ReactElement {
+ return
+}
+
+Component.displayName = 'Landing'
diff --git a/frontends/open/react-scss/src/pages/landing/landing.module.scss b/frontends/open/react-scss/src/pages/landing/landing.module.scss
new file mode 100644
index 0000000..164f39a
--- /dev/null
+++ b/frontends/open/react-scss/src/pages/landing/landing.module.scss
@@ -0,0 +1,4 @@
+// ===================
+// © AngelaMos | 2026
+// landing.module.scss
+// ===================
diff --git a/frontends/open/react-scss/src/pages/settings/index.tsx b/frontends/open/react-scss/src/pages/settings/index.tsx
new file mode 100644
index 0000000..9c8dc9a
--- /dev/null
+++ b/frontends/open/react-scss/src/pages/settings/index.tsx
@@ -0,0 +1,56 @@
+/**
+ * ©AngelaMos | 2026
+ * index.tsx
+ */
+
+import styles from './settings.module.scss'
+
+const AVAILABLE_STORES = [
+ {
+ name: 'useUIStore()',
+ file: 'core/lib/shell.ui.store.ts',
+ description: 'Theme, sidebar open/collapsed state',
+ },
+]
+
+export function Component(): React.ReactElement {
+ return (
+
+
+
+
Settings
+
+ Template page — available stores for building your settings UI
+
+
+
+
+ Available Stores
+
+ {AVAILABLE_STORES.map((store) => (
+
+
{store.name}
+
{store.description}
+
+ {store.file}
+
+
+ ))}
+
+
+
+
+ Suggested Features
+
+ - Profile form
+ - Theme toggle (dark/light)
+ - Notification settings
+ - Application preferences
+
+
+
+
+ )
+}
+
+Component.displayName = 'Settings'
diff --git a/frontends/open/react-scss/src/pages/settings/settings.module.scss b/frontends/open/react-scss/src/pages/settings/settings.module.scss
new file mode 100644
index 0000000..e95e0f8
--- /dev/null
+++ b/frontends/open/react-scss/src/pages/settings/settings.module.scss
@@ -0,0 +1,4 @@
+// ===================
+// © AngelaMos | 2026
+// settings.module.scss
+// ===================
diff --git a/frontends/open/react-scss/src/styles.scss b/frontends/open/react-scss/src/styles.scss
new file mode 100644
index 0000000..240ec55
--- /dev/null
+++ b/frontends/open/react-scss/src/styles.scss
@@ -0,0 +1,23 @@
+// ===================
+// © AngelaMos | 2026
+// styles.scss
+// ===================
+
+@forward 'styles/tokens';
+@forward 'styles/fonts';
+@forward 'styles/mixins';
+
+@use 'styles/reset';
+
+#root {
+ min-height: 100vh;
+ min-height: 100dvh;
+ display: flex;
+ flex-direction: column;
+}
+
+.app {
+ flex: 1;
+ display: flex;
+ flex-direction: column;
+}
diff --git a/frontends/open/react-scss/src/styles/_fonts.scss b/frontends/open/react-scss/src/styles/_fonts.scss
new file mode 100644
index 0000000..4f51788
--- /dev/null
+++ b/frontends/open/react-scss/src/styles/_fonts.scss
@@ -0,0 +1,12 @@
+// ===================
+// © AngelaMos | 2025
+// _fonts.scss
+// ===================
+
+@use 'tokens' as *;
+
+$font-sans: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Inter', Roboto,
+ 'Helvetica Neue', Arial, sans-serif;
+
+$font-mono: ui-monospace, SFMono-Regular, 'SF Mono', Menlo, Consolas,
+ 'Liberation Mono', monospace;
diff --git a/frontends/open/react-scss/src/styles/_index.scss b/frontends/open/react-scss/src/styles/_index.scss
new file mode 100644
index 0000000..ac5a826
--- /dev/null
+++ b/frontends/open/react-scss/src/styles/_index.scss
@@ -0,0 +1,8 @@
+// ===================
+// © AngelaMos | 2025
+// _index.scss
+// ===================
+
+@forward 'tokens';
+@forward 'fonts';
+@forward 'mixins';
diff --git a/frontends/open/react-scss/src/styles/_mixins.scss b/frontends/open/react-scss/src/styles/_mixins.scss
new file mode 100644
index 0000000..6b5b1ba
--- /dev/null
+++ b/frontends/open/react-scss/src/styles/_mixins.scss
@@ -0,0 +1,120 @@
+// ===================
+// © AngelaMos | 2025
+// _mixins.scss
+// ===================
+
+@use 'sass:map';
+@use 'sass:list';
+@use 'tokens' as *;
+
+$breakpoints: (
+ 'xs': $breakpoint-xs,
+ 'sm': $breakpoint-sm,
+ 'md': $breakpoint-md,
+ 'lg': $breakpoint-lg,
+ 'xl': $breakpoint-xl,
+ '2xl': $breakpoint-2xl,
+);
+
+@mixin breakpoint-up($size) {
+ @media (min-width: map.get($breakpoints, $size)) {
+ @content;
+ }
+}
+
+@mixin breakpoint-down($size) {
+ @media (width < map.get($breakpoints, $size)) {
+ @content;
+ }
+}
+
+@mixin flex-center {
+ display: flex;
+ align-items: center;
+ justify-content: center;
+}
+
+@mixin flex-between {
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+}
+
+@mixin flex-column {
+ display: flex;
+ flex-direction: column;
+}
+
+@mixin flex-column-center {
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ justify-content: center;
+}
+
+@mixin sr-only {
+ position: absolute;
+ width: 1px;
+ height: 1px;
+ margin: -1px;
+ padding: 0;
+ overflow: hidden;
+ clip: rect(0 0 0 0);
+ clip-path: inset(50%);
+ white-space: nowrap;
+ border: 0;
+}
+
+@mixin truncate {
+ overflow: hidden;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+}
+
+@mixin line-clamp($lines: 2) {
+ display: -webkit-box;
+ -webkit-line-clamp: #{$lines};
+ -webkit-box-orient: vertical;
+ overflow: hidden;
+}
+
+@mixin transition-fast {
+ transition-property: background-color, border-color, color, opacity;
+ transition-duration: $duration-fast;
+ transition-timing-function: $ease-out;
+}
+
+@mixin transition-normal {
+ transition-property: background-color, border-color, color, opacity;
+ transition-duration: $duration-normal;
+ transition-timing-function: $ease-out;
+}
+
+@mixin absolute-fill {
+ position: absolute;
+ inset: 0;
+}
+
+@mixin absolute-center {
+ position: absolute;
+ top: 50%;
+ left: 50%;
+ transform: translate(-50%, -50%);
+}
+
+@mixin hover {
+ @media (hover: hover) and (pointer: fine) {
+ &:hover {
+ @content;
+ }
+ }
+}
+
+@mixin hide-scrollbar {
+ -ms-overflow-style: none;
+ scrollbar-width: none;
+
+ &::-webkit-scrollbar {
+ display: none;
+ }
+}
diff --git a/frontends/open/react-scss/src/styles/_reset.scss b/frontends/open/react-scss/src/styles/_reset.scss
new file mode 100644
index 0000000..a9cbdc1
--- /dev/null
+++ b/frontends/open/react-scss/src/styles/_reset.scss
@@ -0,0 +1,105 @@
+// ===================
+// © AngelaMos | 2026
+// _reset.scss
+// ===================
+
+*,
+*::before,
+*::after {
+ box-sizing: border-box;
+}
+
+* {
+ margin: 0;
+ padding: 0;
+ -webkit-tap-highlight-color: transparent;
+}
+
+html {
+ font-size: 16px;
+ -moz-text-size-adjust: none;
+ -webkit-text-size-adjust: none;
+ text-size-adjust: none;
+ overflow-x: hidden;
+}
+
+@media (prefers-reduced-motion: no-preference) {
+ html {
+ interpolate-size: allow-keywords;
+ scroll-behavior: smooth;
+ }
+}
+
+body {
+ min-height: 100vh;
+ min-height: 100dvh;
+ line-height: 1.5;
+ text-rendering: optimizeLegibility;
+ -webkit-font-smoothing: antialiased;
+ -moz-osx-font-smoothing: grayscale;
+ overflow-x: hidden;
+ background-color: #fff;
+ color: #000;
+}
+
+h1,
+h2,
+h3,
+h4,
+h5,
+h6 {
+ line-height: 1.2;
+ text-wrap: balance;
+ overflow-wrap: break-word;
+}
+
+p {
+ text-wrap: pretty;
+ overflow-wrap: break-word;
+}
+
+img,
+picture,
+video,
+canvas,
+svg {
+ display: block;
+ max-width: 100%;
+ height: auto;
+}
+
+input,
+button,
+textarea,
+select {
+ font: inherit;
+ color: inherit;
+}
+
+button {
+ background: none;
+ border: none;
+ cursor: pointer;
+ text-align: inherit;
+ font-family: inherit;
+}
+
+[hidden] {
+ display: none !important;
+}
+
+[disabled] {
+ cursor: not-allowed;
+ opacity: 0.5;
+}
+
+@media (prefers-reduced-motion: reduce) {
+ *,
+ *::before,
+ *::after {
+ animation-duration: 0.01ms !important;
+ animation-iteration-count: 1 !important;
+ transition-duration: 0.01ms !important;
+ scroll-behavior: auto !important;
+ }
+}
diff --git a/frontends/open/react-scss/src/styles/_tokens.scss b/frontends/open/react-scss/src/styles/_tokens.scss
new file mode 100644
index 0000000..be1f6dd
--- /dev/null
+++ b/frontends/open/react-scss/src/styles/_tokens.scss
@@ -0,0 +1,168 @@
+// ===================
+// © AngelaMos | 2025
+// _tokens.scss
+// ===================
+
+// ============================================================================
+// SPACING (8px base system)
+// ============================================================================
+$space-0: 0;
+$space-px: 1px;
+$space-0-5: 0.125rem;
+$space-1: 0.25rem;
+$space-1-5: 0.375rem;
+$space-2: 0.5rem;
+$space-2-5: 0.625rem;
+$space-3: 0.75rem;
+$space-3-5: 0.875rem;
+$space-4: 1rem;
+$space-5: 1.25rem;
+$space-6: 1.5rem;
+$space-7: 1.75rem;
+$space-8: 2rem;
+$space-9: 2.25rem;
+$space-10: 2.5rem;
+$space-11: 2.75rem;
+$space-12: 3rem;
+$space-14: 3.5rem;
+$space-16: 4rem;
+$space-20: 5rem;
+$space-24: 6rem;
+$space-28: 7rem;
+$space-32: 8rem;
+
+// ============================================================================
+// TYPOGRAPHY SCALE
+// ============================================================================
+$font-size-3xs: 0.625rem;
+$font-size-2xs: 0.6875rem;
+$font-size-xs: 0.75rem;
+$font-size-sm: 0.875rem;
+$font-size-base: 1rem;
+$font-size-lg: 1.125rem;
+$font-size-xl: 1.25rem;
+$font-size-2xl: 1.5rem;
+$font-size-3xl: 1.875rem;
+$font-size-4xl: 2.25rem;
+$font-size-5xl: 3rem;
+
+// ============================================================================
+// FONT WEIGHTS
+// ============================================================================
+$font-weight-regular: 400;
+$font-weight-medium: 500;
+$font-weight-semibold: 600;
+
+// ============================================================================
+// LINE HEIGHTS
+// ============================================================================
+$line-height-none: 1;
+$line-height-tight: 1.2;
+$line-height-snug: 1.375;
+$line-height-normal: 1.5;
+$line-height-relaxed: 1.625;
+
+// ============================================================================
+// LETTER SPACING
+// ============================================================================
+$tracking-tighter: -0.05em;
+$tracking-tight: -0.025em;
+$tracking-normal: 0;
+$tracking-wide: 0.025em;
+$tracking-wider: 0.05em;
+
+// ============================================================================
+// COLORS
+// ============================================================================
+$white: hsl(0, 0%, 100%);
+$black: hsl(0, 0%, 0%);
+
+// Auth
+$bg-page: hsl(0, 0%, 10.5%);
+$bg-card: hsl(0, 0%, 6.2%);
+
+// Home/landing
+$bg-landing: hsl(0, 0%, 10.8%);
+
+$bg-default: hsl(0, 0%, 7.1%);
+$bg-alternative: hsl(0, 0%, 5.9%);
+$bg-surface-75: hsl(0, 0%, 9%);
+$bg-surface-100: hsl(0, 0%, 12.2%);
+$bg-surface-200: hsl(0, 0%, 14.1%);
+$bg-surface-300: hsl(0, 0%, 16.1%);
+$bg-control: hsl(0, 0%, 10%);
+$bg-selection: hsl(0, 0%, 19.2%);
+$bg-overlay: hsl(0, 0%, 14.1%);
+$bg-overlay-hover: hsl(0, 0%, 18%);
+
+$border-muted: hsl(0, 0%, 11.1%);
+$border-default: hsl(0, 0%, 18%);
+$border-strong: hsl(0, 0%, 22.4%);
+$border-stronger: hsl(0, 0%, 27.1%);
+$border-control: hsl(0, 0%, 22.4%);
+
+$text-default: hsl(0, 0%, 98%);
+$text-light: hsl(0, 0%, 70.6%);
+$text-lighter: hsl(0, 0%, 53.7%);
+$text-muted: hsl(0, 0%, 30.2%);
+
+$error-default: hsl(0, 72%, 51%);
+$error-light: hsl(0, 72%, 65%);
+
+// ============================================================================
+// BORDER RADIUS
+// ============================================================================
+$radius-none: 0;
+$radius-xs: 2px;
+$radius-sm: 4px;
+$radius-md: 6px;
+$radius-lg: 8px;
+$radius-xl: 12px;
+$radius-full: 9999px;
+
+// ============================================================================
+// Z-INDEX SCALE
+// ============================================================================
+$z-hide: -1;
+$z-base: 0;
+$z-dropdown: 100;
+$z-sticky: 200;
+$z-fixed: 300;
+$z-overlay: 400;
+$z-modal: 500;
+$z-popover: 600;
+$z-tooltip: 700;
+$z-toast: 800;
+$z-max: 9999;
+
+// ============================================================================
+// TRANSITIONS
+// ============================================================================
+$duration-instant: 0ms;
+$duration-fast: 100ms;
+$duration-normal: 150ms;
+$duration-slow: 200ms;
+
+$ease-out: cubic-bezier(0, 0, 0.2, 1);
+$ease-in-out: cubic-bezier(0.4, 0, 0.2, 1);
+
+// ============================================================================
+// BREAKPOINTS
+// ============================================================================
+$breakpoint-xs: 360px;
+$breakpoint-sm: 480px;
+$breakpoint-md: 768px;
+$breakpoint-lg: 1024px;
+$breakpoint-xl: 1280px;
+$breakpoint-2xl: 1536px;
+
+// ============================================================================
+// CONTAINER WIDTHS
+// ============================================================================
+$container-xs: 20rem;
+$container-sm: 24rem;
+$container-md: 28rem;
+$container-lg: 32rem;
+$container-xl: 36rem;
+$container-2xl: 42rem;
+$container-full: 100%;
diff --git a/frontends/open/react-scss/stylelint.config.js b/frontends/open/react-scss/stylelint.config.js
new file mode 100755
index 0000000..56ebd7b
--- /dev/null
+++ b/frontends/open/react-scss/stylelint.config.js
@@ -0,0 +1,107 @@
+// ©AngelaMos | 2025
+// stylelint.config.js
+
+/** @type {import('stylelint').Config} */
+export default {
+ extends: ['stylelint-config-standard-scss', 'stylelint-config-prettier-scss'],
+ rules: {
+ 'block-no-empty': true,
+ 'declaration-no-important': true,
+ 'color-no-invalid-hex': true,
+ 'property-no-unknown': true,
+ 'selector-pseudo-class-no-unknown': [
+ true,
+ {
+ ignorePseudoClasses: ['global'],
+ },
+ ],
+
+ 'selector-class-pattern': [
+ '^[a-z]([a-z0-9-]+)?(__[a-z0-9]([a-z0-9-]+)?)?(--[a-z0-9]([a-z0-9-]+)?)?$|^[a-z][a-zA-Z0-9]*$',
+ {
+ message:
+ 'Selector should be in BEM format (e.g., .block__element--modifier) or CSS Modules camelCase (e.g., .testButton)',
+ },
+ ],
+
+ 'value-keyword-case': [
+ 'lower',
+ {
+ camelCaseSvgKeywords: true,
+ ignoreKeywords: [
+ 'BlinkMacSystemFont',
+ 'SFMono-Regular',
+ 'Menlo',
+ 'Monaco',
+ 'Consolas',
+ 'Roboto',
+ 'Arial',
+ 'Helvetica',
+ 'Times',
+ 'Georgia',
+ 'Verdana',
+ 'Tahoma',
+ 'Trebuchet',
+ 'Impact',
+ 'Comic',
+ ],
+ },
+ ],
+
+ 'property-no-vendor-prefix': [
+ true,
+ {
+ ignoreProperties: ['text-size-adjust', 'appearance', 'backdrop-filter'],
+ },
+ ],
+ 'value-no-vendor-prefix': true,
+ 'selector-no-vendor-prefix': true,
+
+ 'property-no-deprecated': [
+ true,
+ {
+ ignoreProperties: ['clip'],
+ },
+ ],
+
+ 'container-name-pattern': null,
+ 'layer-name-pattern': null,
+
+ 'scss/at-rule-no-unknown': true,
+ 'scss/declaration-nested-properties-no-divided-groups': true,
+ 'scss/dollar-variable-no-missing-interpolation': true,
+ 'scss/dollar-variable-empty-line-before': null,
+
+ 'declaration-empty-line-before': null,
+ 'custom-property-empty-line-before': null,
+
+ 'no-descending-specificity': null,
+
+ 'media-feature-name-no-unknown': [
+ true,
+ {
+ ignoreMediaFeatureNames: ['map'],
+ },
+ ],
+
+ 'color-function-notation': null,
+ 'hue-degree-notation': null,
+ },
+ ignoreFiles: [
+ 'node_modules/**',
+ 'dist/**',
+ 'build/**',
+ '**/*.js',
+ '**/*.ts',
+ '**/*.tsx',
+ ],
+ overrides: [
+ {
+ files: ['**/styles/_reset.scss', '**/styles/_fonts.scss'],
+ rules: {
+ 'declaration-no-important': null,
+ 'scss/comment-no-empty': null,
+ },
+ },
+ ],
+}
diff --git a/frontends/open/react-scss/tsconfig.app.json b/frontends/open/react-scss/tsconfig.app.json
new file mode 100644
index 0000000..afe17f6
--- /dev/null
+++ b/frontends/open/react-scss/tsconfig.app.json
@@ -0,0 +1,31 @@
+{
+ "compilerOptions": {
+ "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo",
+ "target": "ES2022",
+ "useDefineForClassFields": true,
+ "lib": ["ES2022", "DOM", "DOM.Iterable"],
+ "module": "ESNext",
+ "types": ["vite/client"],
+ "skipLibCheck": true,
+
+ "moduleResolution": "bundler",
+ "allowImportingTsExtensions": true,
+ "verbatimModuleSyntax": true,
+ "moduleDetection": "force",
+ "noEmit": true,
+ "jsx": "react-jsx",
+
+ "strict": true,
+ "noUnusedLocals": true,
+ "noUnusedParameters": true,
+ "erasableSyntaxOnly": true,
+ "noFallthroughCasesInSwitch": true,
+ "noUncheckedSideEffectImports": true,
+
+ "baseUrl": ".",
+ "paths": {
+ "@/*": ["./src/*"]
+ }
+ },
+ "include": ["src"]
+}
diff --git a/frontends/open/react-scss/tsconfig.json b/frontends/open/react-scss/tsconfig.json
new file mode 100644
index 0000000..1ffef60
--- /dev/null
+++ b/frontends/open/react-scss/tsconfig.json
@@ -0,0 +1,7 @@
+{
+ "files": [],
+ "references": [
+ { "path": "./tsconfig.app.json" },
+ { "path": "./tsconfig.node.json" }
+ ]
+}
diff --git a/frontends/open/react-scss/tsconfig.node.json b/frontends/open/react-scss/tsconfig.node.json
new file mode 100644
index 0000000..a96b3e5
--- /dev/null
+++ b/frontends/open/react-scss/tsconfig.node.json
@@ -0,0 +1,24 @@
+{
+ "compilerOptions": {
+ "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo",
+ "target": "ES2023",
+ "lib": ["ES2023"],
+ "module": "ESNext",
+ "types": ["node"],
+ "skipLibCheck": true,
+
+ "moduleResolution": "bundler",
+ "allowImportingTsExtensions": true,
+ "verbatimModuleSyntax": true,
+ "moduleDetection": "force",
+ "noEmit": true,
+
+ "strict": true,
+ "noUnusedLocals": true,
+ "noUnusedParameters": true,
+ "erasableSyntaxOnly": true,
+ "noFallthroughCasesInSwitch": true,
+ "noUncheckedSideEffectImports": true
+ },
+ "include": ["vite.config.ts"]
+}
diff --git a/frontends/open/react-scss/vite.config.ts b/frontends/open/react-scss/vite.config.ts
new file mode 100644
index 0000000..a8d5d47
--- /dev/null
+++ b/frontends/open/react-scss/vite.config.ts
@@ -0,0 +1,71 @@
+/**
+ * ©AngelaMos | 2025
+ * vite.config.ts
+ */
+
+import path from 'node:path'
+import react from '@vitejs/plugin-react'
+import { defineConfig, loadEnv } from 'vite'
+import tsconfigPaths from 'vite-tsconfig-paths'
+
+export default defineConfig(({ mode }) => {
+ const env = loadEnv(mode, path.resolve(__dirname, '..'), '')
+ const isDev = mode === 'development'
+
+ return {
+ plugins: [react(), tsconfigPaths()],
+
+ resolve: {
+ alias: {
+ '@': path.resolve(__dirname, './src'),
+ },
+ },
+
+ css: {
+ preprocessorOptions: {
+ scss: {},
+ },
+ },
+
+ server: {
+ port: 5173,
+ host: '0.0.0.0',
+ proxy: {
+ '/api': {
+ target: env.VITE_API_TARGET || 'http://localhost:8000',
+ changeOrigin: true,
+ rewrite: (p) => p.replace(/^\/api/, ''),
+ },
+ },
+ },
+
+ build: {
+ target: 'esnext',
+ cssTarget: 'chrome100',
+ sourcemap: isDev ? true : 'hidden',
+ minify: 'oxc',
+ rollupOptions: {
+ output: {
+ manualChunks(id: string): string | undefined {
+ if (id.includes('node_modules')) {
+ if (id.includes('react-dom') || id.includes('react-router')) {
+ return 'vendor-react'
+ }
+ if (id.includes('@tanstack/react-query')) {
+ return 'vendor-query'
+ }
+ if (id.includes('zustand')) {
+ return 'vendor-state'
+ }
+ }
+ return undefined
+ },
+ },
+ },
+ },
+
+ preview: {
+ port: 4173,
+ },
+ }
+})
diff --git a/frontends/open/scripts/init.sh b/frontends/open/scripts/init.sh
new file mode 100755
index 0000000..696e630
--- /dev/null
+++ b/frontends/open/scripts/init.sh
@@ -0,0 +1,87 @@
+#!/usr/bin/env bash
+# =============================================================================
+# AngelaMos | 2026
+# init.sh
+# =============================================================================
+# Run once after copying the template.
+# Prompts for a project name, randomizes ports, updates all the right files.
+
+set -euo pipefail
+
+DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
+
+# ── prompt ────────────────────────────────────────────────────────────────────
+echo ""
+read -rp "Project name (kebab-case): " RAW
+
+SLUG="$(echo "$RAW" | tr '[:upper:]' '[:lower:]' | tr ' ' '-' | tr -cd '[:alnum:]-')"
+[[ -z "$SLUG" ]] && { echo "Error: empty name" >&2; exit 1; }
+
+TITLE="$(echo "$SLUG" | tr '-' ' ' | python3 -c "import sys; print(sys.stdin.read().strip().title())")"
+
+# ── ports ─────────────────────────────────────────────────────────────────────
+mapfile -t ports < <(python3 -c "
+import random
+for p in random.sample(range(10000, 65001), 4): print(p)
+")
+
+PROD_NGINX=${ports[0]}
+PROD_FRONTEND=${ports[1]}
+DEV_NGINX=${ports[2]}
+DEV_FRONTEND=${ports[3]}
+
+echo ""
+echo " slug: $SLUG"
+echo " title: $TITLE"
+echo " prod nginx: $PROD_NGINX"
+echo " prod frontend: $PROD_FRONTEND"
+echo " dev nginx: $DEV_NGINX"
+echo " dev frontend: $DEV_FRONTEND"
+echo ""
+
+# ── .env (prod) ───────────────────────────────────────────────────────────────
+sed -i "s|^APP_NAME=.*|APP_NAME=$SLUG|" "$DIR/.env"
+sed -i "s|^VITE_APP_TITLE=.*|VITE_APP_TITLE=$TITLE|" "$DIR/.env"
+sed -i "s|^NGINX_HOST_PORT=.*|NGINX_HOST_PORT=$PROD_NGINX|" "$DIR/.env"
+sed -i "s|^FRONTEND_HOST_PORT=.*|FRONTEND_HOST_PORT=$PROD_FRONTEND|" "$DIR/.env"
+echo " updated .env"
+
+# ── .env.development ──────────────────────────────────────────────────────────
+sed -i "s|^APP_NAME=.*|APP_NAME=$SLUG-dev|" "$DIR/.env.development"
+sed -i "s|^VITE_APP_TITLE=.*|VITE_APP_TITLE=\"$TITLE (Dev)\"|" "$DIR/.env.development"
+sed -i "s|^NGINX_HOST_PORT=.*|NGINX_HOST_PORT=$DEV_NGINX|" "$DIR/.env.development"
+sed -i "s|^FRONTEND_HOST_PORT=.*|FRONTEND_HOST_PORT=$DEV_FRONTEND|" "$DIR/.env.development"
+echo " updated .env.development"
+
+# ── .env.example ──────────────────────────────────────────────────────────────
+sed -i "s|^APP_NAME=.*|APP_NAME=$SLUG|" "$DIR/.env.example"
+sed -i "s|^VITE_APP_TITLE=.*|VITE_APP_TITLE=$TITLE|" "$DIR/.env.example"
+sed -i "s|^NGINX_HOST_PORT=.*|NGINX_HOST_PORT=$PROD_NGINX|" "$DIR/.env.example"
+sed -i "s|^FRONTEND_HOST_PORT=.*|FRONTEND_HOST_PORT=$PROD_FRONTEND|" "$DIR/.env.example"
+echo " updated .env.example"
+
+# ── compose.yml ───────────────────────────────────────────────────────────────
+sed -i "s|\${APP_NAME:-[a-z0-9-]*}|\${APP_NAME:-$SLUG}|g" "$DIR/compose.yml"
+sed -i "s|\${NGINX_HOST_PORT:-[0-9]\+}|\${NGINX_HOST_PORT:-$PROD_NGINX}|g" "$DIR/compose.yml"
+echo " updated compose.yml"
+
+# ── dev.compose.yml ───────────────────────────────────────────────────────────
+sed -i "s|\${APP_NAME:-[a-z0-9-]*}|\${APP_NAME:-$SLUG}|g" "$DIR/dev.compose.yml"
+sed -i "s|\${NGINX_HOST_PORT:-[0-9]\+}|\${NGINX_HOST_PORT:-$DEV_NGINX}|g" "$DIR/dev.compose.yml"
+sed -i "s|\${FRONTEND_HOST_PORT:-[0-9]\+}|\${FRONTEND_HOST_PORT:-$DEV_FRONTEND}|g" "$DIR/dev.compose.yml"
+echo " updated dev.compose.yml"
+
+# ── cloudflared.compose.yml ───────────────────────────────────────────────────
+sed -i "s|\${APP_NAME:-[a-z0-9-]*}|\${APP_NAME:-$SLUG}|g" "$DIR/cloudflared.compose.yml"
+echo " updated cloudflared.compose.yml"
+
+# ── react-scss/package.json ───────────────────────────────────────────────────
+sed -i "s|\"name\": \".*\"|\"name\": \"$SLUG\"|" "$DIR/react-scss/package.json"
+echo " updated react-scss/package.json"
+
+# ── react-scss/index.html ─────────────────────────────────────────────────────
+sed -i "s|Full Stack Template No Auth|$TITLE|g" "$DIR/react-scss/index.html"
+echo " updated react-scss/index.html"
+
+echo ""
+echo "Done. Go build something."
diff --git a/frontends/open/scripts/randomize-ports.sh b/frontends/open/scripts/randomize-ports.sh
new file mode 100755
index 0000000..95348d0
--- /dev/null
+++ b/frontends/open/scripts/randomize-ports.sh
@@ -0,0 +1,56 @@
+#!/usr/bin/env bash
+# =============================================================================
+# AngelaMos | 2026
+# randomize-ports.sh
+# =============================================================================
+# Picks 4 unique random ports (10000-65000) and updates:
+# .env -> prod nginx + frontend ports
+# .env.development -> dev nginx + frontend ports
+# compose.yml -> prod default fallbacks
+# dev.compose.yml -> dev default fallbacks
+
+set -euo pipefail
+
+DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
+
+mapfile -t ports < <(python3 -c "
+import random
+sample = random.sample(range(10000, 65001), 4)
+for p in sample: print(p)
+")
+
+PROD_NGINX=${ports[0]}
+PROD_FRONTEND=${ports[1]}
+DEV_NGINX=${ports[2]}
+DEV_FRONTEND=${ports[3]}
+
+echo "New ports:"
+echo " prod nginx: $PROD_NGINX"
+echo " prod frontend: $PROD_FRONTEND"
+echo " dev nginx: $DEV_NGINX"
+echo " dev frontend: $DEV_FRONTEND"
+echo ""
+
+update_env() {
+ local file="$1" nginx_port="$2" frontend_port="$3"
+ sed -i "s/^NGINX_HOST_PORT=.*/NGINX_HOST_PORT=$nginx_port/" "$file"
+ sed -i "s/^FRONTEND_HOST_PORT=.*/FRONTEND_HOST_PORT=$frontend_port/" "$file"
+ echo " updated $file"
+}
+
+update_compose_defaults() {
+ local file="$1" nginx_port="$2" frontend_port="${3:-}"
+ sed -i "s/\${NGINX_HOST_PORT:-[0-9]\+}/\${NGINX_HOST_PORT:-$nginx_port}/g" "$file"
+ if [[ -n "$frontend_port" ]]; then
+ sed -i "s/\${FRONTEND_HOST_PORT:-[0-9]\+}/\${FRONTEND_HOST_PORT:-$frontend_port}/g" "$file"
+ fi
+ echo " updated $file"
+}
+
+update_env "$DIR/.env" "$PROD_NGINX" "$PROD_FRONTEND"
+update_env "$DIR/.env.development" "$DEV_NGINX" "$DEV_FRONTEND"
+update_compose_defaults "$DIR/compose.yml" "$PROD_NGINX"
+update_compose_defaults "$DIR/dev.compose.yml" "$DEV_NGINX" "$DEV_FRONTEND"
+
+echo ""
+echo "Done."
diff --git a/frontends/react-scss/src/core/app/shell.module.scss b/frontends/react-scss/src/core/app/shell.module.scss
deleted file mode 100644
index 645ca25..0000000
--- a/frontends/react-scss/src/core/app/shell.module.scss
+++ /dev/null
@@ -1,331 +0,0 @@
-// ===================
-// © AngelaMos | 2025
-// shell.module.scss
-// ===================
-
-@use '@/styles' as *;
-
-$sidebar-width: 240px;
-$sidebar-collapsed-width: 64px;
-$header-height: 56px;
-
-.shell {
- display: flex;
- min-height: 100vh;
- min-height: 100dvh;
-}
-
-.sidebar {
- position: fixed;
- top: 0;
- left: 0;
- bottom: 0;
- width: $sidebar-width;
- background: $bg-surface-100;
- border-right: 1px solid $border-default;
- display: flex;
- flex-direction: column;
- z-index: $z-fixed;
- @include transition-fast;
-
- &.collapsed {
- width: $sidebar-collapsed-width;
- }
-
- @include breakpoint-down('sm') {
- transform: translateX(-100%);
-
- &.open {
- transform: translateX(0);
- }
-
- &.collapsed {
- width: $sidebar-width;
- }
- }
-}
-
-.sidebarHeader {
- height: $header-height;
- padding: 0 $space-3;
- display: flex;
- align-items: center;
- justify-content: space-between;
- border-bottom: 1px solid $border-default;
-
- .sidebar.collapsed & {
- justify-content: center;
- padding: 0;
- }
-}
-
-.logo {
- font-size: $font-size-base;
- font-weight: $font-weight-semibold;
- color: $text-default;
- @include transition-fast;
-
- .sidebar.collapsed & {
- display: none;
- }
-}
-
-.nav {
- flex: 1;
- padding: $space-3;
- display: flex;
- flex-direction: column;
- gap: $space-1;
-}
-
-.navItem {
- display: flex;
- align-items: center;
- gap: $space-3;
- padding: $space-2 $space-3;
- border-radius: $radius-md;
- font-size: $font-size-sm;
- color: $text-light;
- @include transition-fast;
-
- @include hover {
- background: $bg-surface-200;
- color: $text-default;
- }
-
- &.active {
- background: $bg-selection;
- color: $text-default;
- }
-
- .sidebar.collapsed & {
- justify-content: center;
- }
-}
-
-.navIcon {
- width: 17px;
- height: 17px;
- flex-shrink: 0;
-}
-
-.navLabel {
- @include transition-fast;
-
- .sidebar.collapsed & {
- display: none;
- }
-}
-
-.adminItem {
- margin-top: auto;
- border-top: 1px solid $border-default;
- padding-top: $space-3;
-}
-
-.collapseBtn {
- width: 45px;
- height: 45px;
- border-radius: $radius-md;
- color: $text-light;
- @include flex-center;
- @include transition-fast;
-
- svg {
- width: 23.5px;
- height: 23.5px;
- }
-
- @include hover {
- background: $bg-surface-200;
- color: $text-default;
- }
-
- @include breakpoint-down('sm') {
- display: none;
- }
-}
-
-.sidebarFooter {
- padding: $space-3;
- border-top: 1px solid $border-default;
-}
-
-.logoutBtn {
- width: 100%;
- display: flex;
- align-items: center;
- gap: $space-3;
- padding: $space-3;
- border-radius: $radius-md;
- font-size: $font-size-sm;
- color: $text-default;
- @include transition-fast;
-
- @include hover {
- background: $bg-surface-200;
- }
-
- .sidebar.collapsed & {
- justify-content: center;
-
- .logoutText {
- display: none;
- }
- }
-}
-
-.logoutIcon {
- width: 18px;
- height: 18px;
- flex-shrink: 0;
-}
-
-.logoutText {
- font-weight: $font-weight-medium;
- @include transition-fast;
-}
-
-.overlay {
- position: fixed;
- inset: 0;
- background: rgb(0, 0, 0, 50%);
- z-index: calc($z-fixed - 1);
- display: none;
- border: none;
- padding: 0;
- cursor: pointer;
-
- @include breakpoint-down('sm') {
- display: block;
- }
-}
-
-.main {
- flex: 1;
- display: flex;
- flex-direction: column;
- margin-left: $sidebar-width;
- min-width: 0;
- @include transition-fast;
-
- &.collapsed {
- margin-left: $sidebar-collapsed-width;
- }
-
- @include breakpoint-down('sm') {
- margin-left: 0;
-
- &.collapsed {
- margin-left: 0;
- }
- }
-}
-
-.header {
- position: sticky;
- top: 0;
- height: $header-height;
- background: $bg-surface-100;
- border-bottom: 1px solid $border-default;
- z-index: $z-sticky;
- display: flex;
- align-items: center;
- justify-content: space-between;
- padding: 0 $space-4;
-}
-
-.headerLeft {
- display: flex;
- align-items: center;
- gap: $space-3;
-}
-
-.menuBtn {
- display: none;
- width: 36px;
- height: 36px;
- border-radius: $radius-md;
- color: $text-light;
- align-items: center;
- justify-content: center;
- @include transition-fast;
-
- svg {
- width: 20px;
- height: 20px;
- }
-
- @include hover {
- background: $bg-surface-200;
- color: $text-default;
- }
-
- @media (width <= 479px) {
- display: flex;
- }
-}
-
-.pageTitle {
- font-size: $font-size-base;
- font-weight: $font-weight-medium;
- color: $text-default;
- margin-left: 7px;
-}
-
-.headerRight {
- display: flex;
- align-items: center;
- gap: $space-3;
-}
-
-.avatar {
- width: 32px;
- height: 32px;
- border-radius: $radius-full;
- background: $bg-surface-300;
- color: $text-light;
- font-size: $font-size-sm;
- font-weight: $font-weight-medium;
- @include flex-center;
- cursor: pointer;
- @include transition-fast;
-
- @include hover {
- filter: brightness(1.2);
- }
-}
-
-.content {
- flex: 1;
- overflow-y: auto;
-}
-
-.loading {
- @include flex-center;
- height: 100%;
- color: $text-muted;
-}
-
-.error {
- @include flex-column-center;
- height: 100%;
- gap: $space-4;
- padding: $space-6;
- color: $error-default;
-
- h2 {
- font-size: $font-size-xl;
- font-weight: $font-weight-semibold;
- }
-
- pre {
- font-family: $font-mono;
- font-size: $font-size-sm;
- padding: $space-4;
- background: $bg-surface-200;
- border-radius: $radius-lg;
- overflow-x: auto;
- max-width: 100%;
- }
-}
diff --git a/frontends/react-scss/src/core/app/toast.module.scss b/frontends/react-scss/src/core/app/toast.module.scss
deleted file mode 100644
index d50ab7f..0000000
--- a/frontends/react-scss/src/core/app/toast.module.scss
+++ /dev/null
@@ -1,67 +0,0 @@
-// ===================
-// © AngelaMos | 2025
-// toast.module.scss
-// ===================
-
-@use '@/styles' as *;
-
-:global {
- [data-sonner-toaster] {
- --normal-bg: #{$bg-surface-100};
- --normal-border: #{$border-default};
- --normal-text: #{$text-default};
-
- --success-bg: #{$bg-surface-100};
- --success-border: #{$border-default};
- --success-text: #{$text-default};
-
- --error-bg: #{$bg-surface-100};
- --error-border: #{$error-default};
- --error-text: #{$text-default};
-
- --warning-bg: #{$bg-surface-100};
- --warning-border: #{$border-default};
- --warning-text: #{$text-default};
-
- --info-bg: #{$bg-surface-100};
- --info-border: #{$border-default};
- --info-text: #{$text-default};
-
- font-family: $font-sans;
- }
-
- [data-sonner-toast] {
- border-radius: $radius-md;
- padding: $space-3 $space-4;
- font-size: $font-size-sm;
- border: 1px solid $border-default;
- background: $bg-surface-100;
- color: $text-default;
-
- [data-title] {
- font-weight: $font-weight-medium;
- }
-
- [data-description] {
- color: $text-light;
- font-size: $font-size-xs;
- }
-
- [data-close-button] {
- background: none;
- border: none;
- padding: 0;
- cursor: pointer;
- color: $text-muted;
- @include transition-fast;
-
- @include hover {
- color: $text-default;
- }
- }
- }
-
- [data-sonner-toast][data-type='error'] {
- border-color: $error-default;
- }
-}
diff --git a/frontends/react-scss/src/pages/admin/admin.module.scss b/frontends/react-scss/src/pages/admin/admin.module.scss
deleted file mode 100644
index ef51500..0000000
--- a/frontends/react-scss/src/pages/admin/admin.module.scss
+++ /dev/null
@@ -1,468 +0,0 @@
-// ===================
-// © AngelaMos | 2025
-// admin.module.scss
-// ===================
-
-@use '@/styles' as *;
-
-.page {
- padding: $space-6;
- min-height: calc(100vh - 56px);
- background-color: $bg-default;
-}
-
-.header {
- @include flex-between;
- margin-bottom: $space-6;
-}
-
-.title {
- font-size: $font-size-2xl;
- font-weight: $font-weight-semibold;
- color: $text-default;
-}
-
-.createBtn {
- display: flex;
- align-items: center;
- gap: $space-2;
- padding: $space-2 $space-4;
- background-color: $white;
- border: none;
- border-radius: $radius-md;
- font-size: $font-size-sm;
- font-weight: $font-weight-medium;
- color: $black;
- cursor: pointer;
- @include transition-fast;
-
- @include hover {
- filter: brightness(0.9);
- }
-
- &:disabled {
- opacity: 0.5;
- cursor: not-allowed;
- }
-
- svg {
- width: 16px;
- height: 16px;
- }
-}
-
-.table {
- width: 100%;
- background: $bg-surface-100;
- border: 1px solid $border-default;
- border-radius: $radius-lg;
- overflow: hidden;
-}
-
-.tableHeader {
- display: grid;
- grid-template-columns: 2fr 1fr 1fr 1fr 100px;
- gap: $space-4;
- padding: $space-3 $space-4;
- background: $bg-surface-200;
- border-bottom: 1px solid $border-default;
-
- @include breakpoint-down('md') {
- display: none;
- }
-}
-
-.tableHeaderCell {
- font-size: $font-size-xs;
- font-weight: $font-weight-medium;
- color: $text-lighter;
- text-transform: uppercase;
- letter-spacing: $tracking-wide;
-}
-
-.tableBody {
- @include flex-column;
-}
-
-.tableRow {
- display: grid;
- grid-template-columns: 2fr 1fr 1fr 1fr 100px;
- gap: $space-4;
- padding: $space-3 $space-4;
- border-bottom: 1px solid $border-default;
- @include transition-fast;
-
- &:last-child {
- border-bottom: none;
- }
-
- @include hover {
- background: $bg-surface-75;
- }
-
- @include breakpoint-down('md') {
- grid-template-columns: 1fr;
- gap: $space-2;
- }
-}
-
-.tableCell {
- display: flex;
- align-items: center;
- font-size: $font-size-sm;
- color: $text-default;
- min-width: 0;
-
- @include breakpoint-down('md') {
- &::before {
- content: attr(data-label);
- font-size: $font-size-xs;
- color: $text-lighter;
- margin-right: $space-2;
- min-width: 80px;
- }
- }
-}
-
-.email {
- @include truncate;
-}
-
-.badge {
- display: inline-flex;
- align-items: center;
- padding: $space-1 $space-2;
- border-radius: $radius-full;
- font-size: $font-size-xs;
- font-weight: $font-weight-medium;
-
- &.admin {
- background: $bg-selection;
- color: $text-default;
- }
-
- &.user {
- background: $bg-surface-200;
- color: $text-light;
- }
-
- &.active {
- background: hsl(142 76% 36% / 20%);
- color: hsl(142, 76%, 46%);
- }
-
- &.inactive {
- background: hsl(0 72% 51% / 20%);
- color: $error-light;
- }
-}
-
-.actions {
- display: flex;
- gap: $space-2;
- justify-content: flex-end;
-
- @include breakpoint-down('md') {
- justify-content: flex-start;
- }
-}
-
-.actionBtn {
- width: 32px;
- height: 32px;
- @include flex-center;
- border: 1px solid $border-default;
- border-radius: $radius-md;
- background: transparent;
- color: $text-light;
- cursor: pointer;
- @include transition-fast;
-
- @include hover {
- background: $bg-surface-200;
- color: $text-default;
- }
-
- &.delete {
- @include hover {
- border-color: $error-default;
- color: $error-default;
- }
- }
-
- svg {
- width: 16px;
- height: 16px;
- }
-}
-
-.pagination {
- @include flex-between;
- padding: $space-4;
- border-top: 1px solid $border-default;
-}
-
-.paginationInfo {
- font-size: $font-size-sm;
- color: $text-lighter;
-}
-
-.paginationBtns {
- display: flex;
- gap: $space-2;
-}
-
-.paginationBtn {
- padding: $space-2 $space-3;
- border: 1px solid $border-default;
- border-radius: $radius-md;
- background: transparent;
- font-size: $font-size-sm;
- color: $text-light;
- cursor: pointer;
- @include transition-fast;
-
- @include hover {
- background: $bg-surface-200;
- color: $text-default;
- }
-
- &:disabled {
- opacity: 0.5;
- cursor: not-allowed;
- }
-}
-
-.empty {
- @include flex-column-center;
- padding: $space-12;
- color: $text-muted;
- font-size: $font-size-sm;
-}
-
-.loading {
- @include flex-center;
- padding: $space-12;
- color: $text-muted;
-}
-
-.modal {
- position: fixed;
- inset: 0;
- z-index: $z-modal;
- @include flex-center;
-}
-
-.modalOverlay {
- @include absolute-fill;
- background: rgb(0, 0, 0, 70%);
-}
-
-.modalContent {
- position: relative;
- width: 100%;
- max-width: 400px;
- margin: $space-4;
- background: $bg-surface-100;
- border: 1px solid $border-default;
- border-radius: $radius-lg;
- padding: $space-6;
-}
-
-.modalHeader {
- @include flex-between;
- margin-bottom: $space-5;
-}
-
-.modalTitle {
- font-size: $font-size-lg;
- font-weight: $font-weight-semibold;
- color: $text-default;
-}
-
-.modalClose {
- width: 32px;
- height: 32px;
- @include flex-center;
- border: none;
- border-radius: $radius-md;
- background: transparent;
- color: $text-light;
- cursor: pointer;
- @include transition-fast;
-
- @include hover {
- background: $bg-surface-200;
- color: $text-default;
- }
-
- svg {
- width: 20px;
- height: 20px;
- }
-}
-
-.form {
- @include flex-column;
- gap: $space-4;
-}
-
-.field {
- @include flex-column;
- gap: $space-2;
-}
-
-.label {
- font-size: $font-size-sm;
- font-weight: $font-weight-medium;
- color: $text-default;
-}
-
-.input {
- width: 100%;
- height: 44px;
- padding: 0 $space-3;
- background: transparent;
- border: 1px solid $border-default;
- border-radius: $radius-md;
- font-size: $font-size-sm;
- color: $text-default;
- @include transition-fast;
-
- &::placeholder {
- color: $text-muted;
- }
-
- &:focus {
- outline: none;
- border-color: $border-strong;
- }
-}
-
-.select {
- width: 100%;
- height: 44px;
- padding: 0 $space-3;
- background: transparent;
- border: 1px solid $border-default;
- border-radius: $radius-md;
- font-size: $font-size-sm;
- color: $text-default;
- cursor: pointer;
- @include transition-fast;
-
- &:focus {
- outline: none;
- border-color: $border-strong;
- }
-
- option {
- background: $bg-surface-100;
- color: $text-default;
- }
-}
-
-.checkbox {
- display: flex;
- align-items: center;
- gap: $space-2;
- cursor: pointer;
-
- input {
- width: 18px;
- height: 18px;
- accent-color: $white;
- }
-
- span {
- font-size: $font-size-sm;
- color: $text-light;
- }
-}
-
-.formActions {
- display: flex;
- gap: $space-3;
- margin-top: $space-2;
-}
-
-.submitBtn {
- flex: 1;
- height: 44px;
- @include flex-center;
- background: $white;
- border: none;
- border-radius: $radius-md;
- font-size: $font-size-sm;
- font-weight: $font-weight-medium;
- color: $black;
- cursor: pointer;
- @include transition-fast;
-
- @include hover {
- filter: brightness(0.9);
- }
-
- &:disabled {
- opacity: 0.5;
- cursor: not-allowed;
- }
-}
-
-.cancelBtn {
- flex: 1;
- height: 44px;
- @include flex-center;
- background: transparent;
- border: 1px solid $border-default;
- border-radius: $radius-md;
- font-size: $font-size-sm;
- font-weight: $font-weight-medium;
- color: $text-light;
- cursor: pointer;
- @include transition-fast;
-
- @include hover {
- background: $bg-surface-200;
- color: $text-default;
- }
-}
-
-.deleteConfirm {
- @include flex-column;
- gap: $space-4;
-}
-
-.deleteText {
- font-size: $font-size-sm;
- color: $text-light;
- line-height: $line-height-relaxed;
-}
-
-.deleteEmail {
- font-weight: $font-weight-medium;
- color: $text-default;
-}
-
-.deleteBtn {
- flex: 1;
- height: 44px;
- @include flex-center;
- background: $error-default;
- border: none;
- border-radius: $radius-md;
- font-size: $font-size-sm;
- font-weight: $font-weight-medium;
- color: $white;
- cursor: pointer;
- @include transition-fast;
-
- @include hover {
- filter: brightness(0.9);
- }
-
- &:disabled {
- opacity: 0.5;
- cursor: not-allowed;
- }
-}
diff --git a/frontends/react-scss/src/pages/dashboard/dashboard.module.scss b/frontends/react-scss/src/pages/dashboard/dashboard.module.scss
deleted file mode 100644
index ecac295..0000000
--- a/frontends/react-scss/src/pages/dashboard/dashboard.module.scss
+++ /dev/null
@@ -1,152 +0,0 @@
-// ===================
-// © AngelaMos | 2025
-// dashboard.module.scss
-// ===================
-
-@use '@/styles' as *;
-
-.page {
- min-height: calc(100vh - 56px);
- padding: $space-6;
- background-color: $bg-default;
-}
-
-.container {
- max-width: 800px;
- margin: 0 auto;
-}
-
-.header {
- margin-bottom: $space-6;
-}
-
-.title {
- font-size: $font-size-2xl;
- font-weight: $font-weight-semibold;
- color: $text-default;
- margin-bottom: $space-2;
-}
-
-.subtitle {
- font-size: $font-size-sm;
- color: $text-lighter;
-}
-
-.userCard {
- display: flex;
- align-items: center;
- gap: $space-4;
- padding: $space-5;
- background: $bg-surface-100;
- border: 1px solid $border-default;
- border-radius: $radius-lg;
- margin-bottom: $space-8;
-}
-
-.avatar {
- width: 56px;
- height: 56px;
- border-radius: $radius-full;
- background: $bg-surface-300;
- color: $text-default;
- font-size: $font-size-xl;
- font-weight: $font-weight-semibold;
- @include flex-center;
- flex-shrink: 0;
-}
-
-.userInfo {
- @include flex-column;
- gap: $space-1;
- min-width: 0;
-}
-
-.userName {
- font-size: $font-size-base;
- font-weight: $font-weight-medium;
- color: $text-default;
- @include truncate;
-}
-
-.userEmail {
- font-size: $font-size-sm;
- color: $text-light;
- @include truncate;
-}
-
-.userRole {
- display: inline-flex;
- align-self: flex-start;
- padding: $space-0-5 $space-2;
- background: $bg-surface-200;
- border-radius: $radius-full;
- font-size: $font-size-xs;
- color: $text-lighter;
- text-transform: uppercase;
- letter-spacing: $tracking-wide;
-}
-
-.section {
- margin-bottom: $space-8;
-}
-
-.sectionTitle {
- font-size: $font-size-sm;
- font-weight: $font-weight-medium;
- color: $text-light;
- text-transform: uppercase;
- letter-spacing: $tracking-wide;
- margin-bottom: $space-4;
-}
-
-.grid {
- display: grid;
- gap: $space-4;
-
- @include breakpoint-up('md') {
- grid-template-columns: repeat(3, 1fr);
- }
-}
-
-.card {
- padding: $space-4;
- background: $bg-surface-100;
- border: 1px solid $border-default;
- border-radius: $radius-lg;
-}
-
-.hookName {
- display: inline-block;
- font-size: $font-size-sm;
- font-weight: $font-weight-medium;
- color: $text-default;
- background: $bg-surface-200;
- padding: $space-1 $space-2;
- border-radius: $radius-sm;
- margin-bottom: $space-2;
-}
-
-.description {
- font-size: $font-size-sm;
- color: $text-light;
- margin-bottom: $space-2;
- line-height: $line-height-relaxed;
-}
-
-.file {
- font-size: $font-size-xs;
- color: $text-muted;
- font-family: $font-mono;
-}
-
-.list {
- @include flex-column;
- gap: $space-2;
- padding-left: $space-5;
- list-style: disc;
-
- li {
- font-size: $font-size-sm;
- color: $text-light;
- }
-}
diff --git a/frontends/react-scss/src/pages/landing/landing.module.scss b/frontends/react-scss/src/pages/landing/landing.module.scss
deleted file mode 100644
index 3013e87..0000000
--- a/frontends/react-scss/src/pages/landing/landing.module.scss
+++ /dev/null
@@ -1,161 +0,0 @@
-// ===================
-// © AngelaMos | 2025
-// landing.module.scss
-// ===================
-
-@use '@/styles' as *;
-
-.page {
- min-height: 100vh;
- min-height: 100dvh;
- @include flex-column-center;
- background-color: $bg-default;
- background-image: radial-gradient(
- circle,
- $bg-landing 1px,
- transparent 1px
- );
- background-size: 20px 20px;
- padding: $space-8;
-}
-
-.header {
- text-align: center;
- margin-bottom: $space-5;
-}
-
-.title {
- font-size: $font-size-4xl;
- font-weight: $font-weight-semibold;
- color: $text-default;
- letter-spacing: $tracking-tight;
- margin-bottom: $space-2;
-}
-
-.subtitle {
- font-size: $font-size-lg;
- color: $text-light;
- margin-bottom: $space-3;
-}
-
-.github {
- display: inline-flex;
- color: $text-muted;
- font-size: $font-size-2xl;
- @include transition-fast;
-
- @include hover {
- &:hover {
- color: $text-default;
- }
- }
-}
-
-.content {
- max-width: 800px;
- text-align: center;
-}
-
-.description {
- font-size: $font-size-base;
- color: $text-light;
- line-height: $line-height-relaxed;
- margin-bottom: $space-8;
-}
-
-.sections {
- display: grid;
- grid-template-columns: repeat(2, 1fr);
- gap: $space-6;
- margin-bottom: $space-10;
- text-align: left;
-
- @include breakpoint-down(md) {
- grid-template-columns: 1fr;
- }
-}
-
-.section {
- padding: $space-5;
- background-color: $bg-surface-75;
- border: 1px solid $border-muted;
- border-radius: $radius-lg;
-}
-
-.sectionTitle {
- font-size: $font-size-sm;
- font-weight: $font-weight-semibold;
- color: $text-default;
- margin-bottom: $space-3;
- letter-spacing: $tracking-wide;
- text-transform: uppercase;
-}
-
-.features {
- list-style: none;
- padding: 0;
- margin: 0;
- display: flex;
- flex-direction: column;
- gap: $space-2;
-
- li {
- font-size: $font-size-sm;
- color: $text-muted;
-
- &::before {
- content: '→';
- margin-right: $space-2;
- color: $text-lighter;
- }
- }
-}
-
-.actions {
- display: flex;
- gap: $space-3;
- justify-content: center;
- flex-wrap: wrap;
-}
-
-.button {
- display: inline-flex;
- align-items: center;
- justify-content: center;
- padding: $space-3 $space-5;
- font-size: $font-size-sm;
- font-weight: $font-weight-medium;
- color: $bg-default;
- background-color: $text-default;
- border-radius: $radius-md;
- text-decoration: none;
- @include transition-fast;
-
- @include hover {
- &:hover {
- filter: brightness(0.9);
- }
- }
-}
-
-.buttonOutline {
- display: inline-flex;
- align-items: center;
- justify-content: center;
- padding: $space-3 $space-5;
- font-size: $font-size-sm;
- font-weight: $font-weight-medium;
- color: $text-default;
- background-color: transparent;
- border: 1px solid $border-default;
- border-radius: $radius-md;
- text-decoration: none;
- @include transition-fast;
-
- @include hover {
- &:hover {
- border-color: $border-strong;
- background-color: $bg-surface-75;
- }
- }
-}
diff --git a/frontends/react-scss/src/pages/login/login.module.scss b/frontends/react-scss/src/pages/login/login.module.scss
deleted file mode 100644
index 6d01ed2..0000000
--- a/frontends/react-scss/src/pages/login/login.module.scss
+++ /dev/null
@@ -1,171 +0,0 @@
-// ===================
-// © AngelaMos | 2025
-// login.module.scss
-// ===================
-
-@use '@/styles' as *;
-
-.page {
- min-height: 100vh;
- min-height: 100dvh;
- @include flex-center;
- background-color: $bg-default;
- background-image: radial-gradient(
- circle,
- $bg-page 1px,
- transparent 1px
- );
- background-size: 22px 22px;
- padding: $space-4;
-}
-
-.card {
- width: 100%;
- max-width: 400px;
- background-color: $black;
- background-image: radial-gradient(
- circle,
- $bg-card 1px,
- transparent 1px
- );
- background-size: 20px 20px;
- border: 1px solid $border-default;
- border-radius: $radius-lg;
- padding: $space-8;
-}
-
-.header {
- margin-bottom: $space-6;
-}
-
-.title {
- font-size: $font-size-2xl;
- font-weight: $font-weight-semibold;
- color: $white;
- margin-bottom: $space-2;
-}
-
-.subtitle {
- font-size: $font-size-sm;
- color: $text-light;
-}
-
-.form {
- @include flex-column;
- gap: $space-5;
-}
-
-.field {
- @include flex-column;
- gap: $space-2;
-}
-
-.label {
- font-size: $font-size-sm;
- font-weight: $font-weight-medium;
- color: $white;
-}
-
-.input {
- width: 100%;
- height: 48px;
- padding: 0 $space-4;
- background-color: transparent;
- border: 1px solid $border-default;
- border-radius: $radius-md;
- font-size: $font-size-base;
- color: $white;
- @include transition-fast;
-
- &::placeholder {
- color: $text-muted;
- }
-
- &:focus {
- outline: none;
- border-color: $border-strong;
- }
-
- &[aria-invalid='true'] {
- border-color: $error-default;
- }
-}
-
-.inputWrapper {
- position: relative;
- width: 100%;
-}
-
-.eyeButton {
- position: absolute;
- right: $space-3;
- top: 50%;
- transform: translateY(-50%);
- display: flex;
- align-items: center;
- justify-content: center;
- background: transparent;
- border: none;
- color: $text-muted;
- cursor: pointer;
- padding: $space-1;
- @include transition-fast;
-
- &:hover {
- color: $white;
- }
-
- svg {
- width: 20px;
- height: 20px;
- }
-}
-
-.error {
- font-size: $font-size-xs;
- color: $error-default;
-}
-
-.submit {
- width: 100%;
- height: 48px;
- margin-top: $space-2;
- display: flex;
- align-items: center;
- justify-content: center;
- background-color: $white;
- border: none;
- border-radius: $radius-md;
- font-size: $font-size-base;
- font-weight: $font-weight-medium;
- color: $black;
- cursor: pointer;
- @include transition-fast;
-
- @include hover {
- filter: brightness(0.9);
- }
-
- &:disabled {
- opacity: 0.5;
- cursor: not-allowed;
- }
-}
-
-.footer {
- margin-top: $space-6;
- text-align: center;
- font-size: $font-size-sm;
- color: $text-light;
-}
-
-.link {
- color: $text-default;
- text-decoration: underline;
- text-underline-offset: 4px;
- @include transition-fast;
-
- @include hover {
- color: $text-light;
- }
-}
diff --git a/frontends/react-scss/src/pages/register/register.module.scss b/frontends/react-scss/src/pages/register/register.module.scss
deleted file mode 100644
index 55ad571..0000000
--- a/frontends/react-scss/src/pages/register/register.module.scss
+++ /dev/null
@@ -1,171 +0,0 @@
-// ===================
-// © AngelaMos | 2025
-// register.module.scss
-// ===================
-
-@use '@/styles' as *;
-
-.page {
- min-height: 100vh;
- min-height: 100dvh;
- @include flex-center;
- background-color: $bg-default;
- background-image: radial-gradient(
- circle,
- $bg-page 1px,
- transparent 1px
- );
- background-size: 22px 22px;
- padding: $space-4;
-}
-
-.card {
- width: 100%;
- max-width: 400px;
- background-color: $black;
- background-image: radial-gradient(
- circle,
- $bg-card 1px,
- transparent 1px
- );
- background-size: 20px 20px;
- border: 1px solid $border-default;
- border-radius: $radius-lg;
- padding: $space-8;
-}
-
-.header {
- margin-bottom: $space-6;
-}
-
-.title {
- font-size: $font-size-2xl;
- font-weight: $font-weight-semibold;
- color: $white;
- margin-bottom: $space-2;
-}
-
-.subtitle {
- font-size: $font-size-sm;
- color: $text-light;
-}
-
-.form {
- @include flex-column;
- gap: $space-5;
-}
-
-.field {
- @include flex-column;
- gap: $space-2;
-}
-
-.label {
- font-size: $font-size-sm;
- font-weight: $font-weight-medium;
- color: $white;
-}
-
-.input {
- width: 100%;
- height: 48px;
- padding: 0 $space-4;
- background-color: transparent;
- border: 1px solid $border-default;
- border-radius: $radius-md;
- font-size: $font-size-base;
- color: $white;
- @include transition-fast;
-
- &::placeholder {
- color: $text-muted;
- }
-
- &:focus {
- outline: none;
- border-color: $border-strong;
- }
-
- &[aria-invalid='true'] {
- border-color: $error-default;
- }
-}
-
-.inputWrapper {
- position: relative;
- width: 100%;
-}
-
-.eyeButton {
- position: absolute;
- right: $space-3;
- top: 50%;
- transform: translateY(-50%);
- display: flex;
- align-items: center;
- justify-content: center;
- background: transparent;
- border: none;
- color: $text-muted;
- cursor: pointer;
- padding: $space-1;
- @include transition-fast;
-
- &:hover {
- color: $white;
- }
-
- svg {
- width: 20px;
- height: 20px;
- }
-}
-
-.error {
- font-size: $font-size-xs;
- color: $error-default;
-}
-
-.submit {
- width: 100%;
- height: 48px;
- margin-top: $space-2;
- display: flex;
- align-items: center;
- justify-content: center;
- background-color: $white;
- border: none;
- border-radius: $radius-md;
- font-size: $font-size-base;
- font-weight: $font-weight-medium;
- color: $black;
- cursor: pointer;
- @include transition-fast;
-
- @include hover {
- filter: brightness(0.9);
- }
-
- &:disabled {
- opacity: 0.5;
- cursor: not-allowed;
- }
-}
-
-.footer {
- margin-top: $space-6;
- text-align: center;
- font-size: $font-size-sm;
- color: $text-light;
-}
-
-.link {
- color: $text-default;
- text-decoration: underline;
- text-underline-offset: 4px;
- @include transition-fast;
-
- @include hover {
- color: $text-light;
- }
-}
diff --git a/frontends/react-scss/src/pages/settings/settings.module.scss b/frontends/react-scss/src/pages/settings/settings.module.scss
deleted file mode 100644
index 16d8585..0000000
--- a/frontends/react-scss/src/pages/settings/settings.module.scss
+++ /dev/null
@@ -1,109 +0,0 @@
-// ===================
-// © AngelaMos | 2025
-// settings.module.scss
-// ===================
-
-@use '@/styles' as *;
-
-.page {
- min-height: calc(100vh - 56px);
- padding: $space-6;
- background-color: $bg-default;
-}
-
-.container {
- max-width: 800px;
- margin: 0 auto;
-}
-
-.header {
- margin-bottom: $space-8;
-}
-
-.title {
- font-size: $font-size-2xl;
- font-weight: $font-weight-semibold;
- color: $text-default;
- margin-bottom: $space-2;
-}
-
-.subtitle {
- font-size: $font-size-sm;
- color: $text-lighter;
-}
-
-.section {
- margin-bottom: $space-8;
-}
-
-.sectionTitle {
- font-size: $font-size-sm;
- font-weight: $font-weight-medium;
- color: $text-light;
- text-transform: uppercase;
- letter-spacing: $tracking-wide;
- margin-bottom: $space-4;
-}
-
-.grid {
- display: grid;
- gap: $space-4;
-
- @include breakpoint-up('md') {
- grid-template-columns: repeat(2, 1fr);
- }
-}
-
-.card {
- padding: $space-4;
- background: $bg-surface-100;
- border: 1px solid $border-default;
- border-radius: $radius-lg;
-}
-
-.hookName {
- display: inline-block;
- font-size: $font-size-sm;
- font-weight: $font-weight-medium;
- color: $text-default;
- background: $bg-surface-200;
- padding: $space-1 $space-2;
- border-radius: $radius-sm;
- margin-bottom: $space-2;
-}
-
-.description {
- font-size: $font-size-sm;
- color: $text-light;
- margin-bottom: $space-3;
- line-height: $line-height-relaxed;
-}
-
-.meta {
- @include flex-column;
- gap: $space-1;
-}
-
-.file {
- font-size: $font-size-xs;
- color: $text-lighter;
- font-family: $font-mono;
-}
-
-.endpoint {
- font-size: $font-size-xs;
- color: $text-muted;
- font-family: $font-mono;
-}
-
-.list {
- @include flex-column;
- gap: $space-2;
- padding-left: $space-5;
- list-style: disc;
-
- li {
- font-size: $font-size-sm;
- color: $text-light;
- }
-}
diff --git a/frontends/react-scss/src/styles/_reset.scss b/frontends/react-scss/src/styles/_reset.scss
deleted file mode 100644
index b6af56b..0000000
--- a/frontends/react-scss/src/styles/_reset.scss
+++ /dev/null
@@ -1,198 +0,0 @@
-// ===================
-// © AngelaMos | 2025
-// _reset.scss
-// ===================
-
-@use 'tokens' as *;
-@use 'fonts' as *;
-
-*,
-*::before,
-*::after {
- box-sizing: border-box;
-}
-
-* {
- margin: 0;
- padding: 0;
- -webkit-tap-highlight-color: transparent;
-}
-
-html {
- font-size: 16px;
- -moz-text-size-adjust: none;
- -webkit-text-size-adjust: none;
- text-size-adjust: none;
- overflow-x: hidden;
-}
-
-@media (prefers-reduced-motion: no-preference) {
- html {
- interpolate-size: allow-keywords;
- scroll-behavior: smooth;
- }
-}
-
-body {
- min-height: 100vh;
- min-height: 100dvh;
- line-height: $line-height-normal;
- text-rendering: optimizeLegibility;
- -webkit-font-smoothing: antialiased;
- -moz-osx-font-smoothing: grayscale;
- overflow-x: hidden;
- background-color: $bg-default;
- color: $text-default;
- font-family: $font-sans;
-}
-
-h1,
-h2,
-h3,
-h4,
-h5,
-h6 {
- line-height: $line-height-tight;
- text-wrap: balance;
- overflow-wrap: break-word;
- font-weight: $font-weight-semibold;
-}
-
-p {
- text-wrap: pretty;
- overflow-wrap: break-word;
-}
-
-ul,
-ol {
- list-style: none;
-}
-
-a {
- color: inherit;
- text-decoration: none;
-}
-
-img,
-picture,
-video,
-canvas,
-svg {
- display: block;
- max-width: 100%;
- height: auto;
-}
-
-input,
-button,
-textarea,
-select {
- font: inherit;
- color: inherit;
-}
-
-input[type='text'],
-input[type='email'],
-input[type='password'],
-input[type='search'],
-input[type='number'],
-input[type='tel'],
-input[type='url'],
-textarea,
-select {
- font-size: $font-size-sm;
- appearance: none;
-}
-
-button {
- background: none;
- border: none;
- cursor: pointer;
- text-align: inherit;
- font-family: inherit;
-}
-
-fieldset {
- border: none;
-}
-
-table {
- border-collapse: collapse;
- border-spacing: 0;
-}
-
-textarea:not([rows]) {
- min-height: 10em;
-}
-
-:target {
- scroll-margin-block: 5ex;
-}
-
-:focus-visible {
- outline: 2px solid $border-strong;
- outline-offset: 2px;
-}
-
-:focus:not(:focus-visible) {
- outline: none;
-}
-
-[hidden] {
- display: none !important;
-}
-
-[disabled] {
- cursor: not-allowed;
- opacity: 0.5;
-}
-
-dialog {
- padding: 0;
- border: none;
- background: transparent;
-}
-
-summary {
- cursor: pointer;
-}
-
-@media (prefers-reduced-motion: reduce) {
- *,
- *::before,
- *::after {
- animation-duration: 0.01ms !important;
- animation-iteration-count: 1 !important;
- transition-duration: 0.01ms !important;
- scroll-behavior: auto !important;
- }
-}
-
-@supports (padding: max(0px)) {
- body {
- padding-left: max(0px, env(safe-area-inset-left));
- padding-right: max(0px, env(safe-area-inset-right));
- }
-}
-
-::-webkit-scrollbar {
- width: 6px;
- height: 6px;
-}
-
-::-webkit-scrollbar-track {
- background: transparent;
-}
-
-::-webkit-scrollbar-thumb {
- background: $border-default;
- border-radius: 3px;
-}
-
-::-webkit-scrollbar-thumb:hover {
- background: $border-strong;
-}
-
-::selection {
- background-color: $bg-selection;
-}
diff --git a/stacks/fastapi-react/frontend/index.html b/stacks/fastapi-react/frontend/index.html
index 7f253ff..c10c3cc 100644
--- a/stacks/fastapi-react/frontend/index.html
+++ b/stacks/fastapi-react/frontend/index.html
@@ -26,8 +26,11 @@
/>
+
+
+
Full Stack Template
-
NavBar Template
+
FST
-
Users
+
+ Command Center
+
Users
+
+
+ Operations Overview
+ Status: Online
+
Welcome{user?.full_name ? `, ${user.full_name}` : ''}
@@ -48,21 +52,30 @@ export function Component(): React.ReactElement {
-
+
{user?.full_name?.[0]?.toUpperCase() ??
user?.email?.[0]?.toUpperCase() ??
'U'}
-
-
{user?.full_name ?? 'User'}
-
{user?.email}
-
{user?.role}
+
+ Email
+ {user?.email}
+
+
+ Role
+ {user?.role}
+
+
+ Name
+
+ {user?.full_name ?? '\u2014'}
+
- Available Stores
+ Available Stores
{AVAILABLE_STORES.map((store) => (
@@ -75,8 +88,8 @@ export function Component(): React.ReactElement {
- Suggested Features
-
+ Suggested Features
+
{SUGGESTED_FEATURES.map((feature) => (
- {feature}
))}
diff --git a/stacks/fastapi-react/frontend/src/pages/landing/index.tsx b/stacks/fastapi-react/frontend/src/pages/landing/index.tsx
index 48729f0..6286558 100644
--- a/stacks/fastapi-react/frontend/src/pages/landing/index.tsx
+++ b/stacks/fastapi-react/frontend/src/pages/landing/index.tsx
@@ -11,85 +11,105 @@ import styles from './landing.module.scss'
export function Component(): React.ReactElement {
return (
-
- Full Stack Template
- by Carter Perez
-
-
-
-
+
-
-
- Boilerplate for medium-large scale applications. Built with modern
- patterns, strict typing, and security best practices.
+
+
+ Build
+
+ Production
+
+ Systems
+
+
+ Opinionated full-stack template for medium-large scale applications.
+ Modern patterns, strict typing, security best practices.
+
-
-
- Frontend
-
- - React 19 + TypeScript with strict mode
- - TanStack Query for server state caching
- - Zustand stores with persistence
- - Axios interceptors with auto token refresh
- - Zod runtime validation on API responses
- - SCSS modules with design tokens
-
-
+
-
- Backend
-
- - DDD + DI Architecture
- - FastAPI with async/await throughout
- - SQLAlchemy 2.0+ async with connection pooling
- - JWT auth with token rotation and replay detection
- - Argon2id hashing with timing safe verification
- - Pydantic v2 strict validation
-
-
+
+
+ 01 — Frontend
+
+ - React 19 + TypeScript strict mode
+ - TanStack Query server state caching
+ - Zustand stores with persistence
+ - Axios interceptors + auto token refresh
+ - Zod runtime validation
+ - SCSS modules + design tokens
+
+
-
- Infrastructure
-
- - Docker Compose with dev/prod configs
- - Nginx reverse proxy with rate limiting
- - PostgreSQL 18 + Redis 7
- - Health checks and graceful shutdown
-
-
+
+ 02 — Backend
+
+ - DDD + DI Architecture
+ - FastAPI async/await throughout
+ - SQLAlchemy 2.0+ async + pooling
+ - JWT auth with token rotation
+ - Argon2id hashing
+ - Pydantic v2 strict validation
+
+
-
- DevOps
-
- - GitHub Actions CI (Ruff, Pylint, Mypy, Biome)
- - Strict type checking on both ends
- - Alembic async migrations
-
-
-
+
+ 03 — Infrastructure
+
+ - Docker Compose dev/prod configs
+ - Nginx reverse proxy + rate limiting
+ - PostgreSQL 18 + Redis 7
+ - Health checks + graceful shutdown
+
+
-
+
+ 04 — DevOps
+
+ - GitHub Actions CI pipeline
+ - Ruff, Pylint, Mypy, Biome linting
+ - Strict type checking both ends
+ - Alembic async migrations
+
+
+
+
+
+
)
}
diff --git a/stacks/fastapi-react/frontend/src/pages/landing/landing.module.scss b/stacks/fastapi-react/frontend/src/pages/landing/landing.module.scss
index 3013e87..f58a0fb 100644
--- a/stacks/fastapi-react/frontend/src/pages/landing/landing.module.scss
+++ b/stacks/fastapi-react/frontend/src/pages/landing/landing.module.scss
@@ -1,161 +1,223 @@
// ===================
-// © AngelaMos | 2025
+// © AngelaMos | 2026
// landing.module.scss
// ===================
-@use '@/styles' as *;
+@use '../../styles' as *;
.page {
min-height: 100vh;
min-height: 100dvh;
- @include flex-column-center;
- background-color: $bg-default;
- background-image: radial-gradient(
- circle,
- $bg-landing 1px,
- transparent 1px
- );
- background-size: 20px 20px;
- padding: $space-8;
+ background: $bg-default;
+ color: $text-default;
+ @include flex-column;
}
-.header {
- text-align: center;
- margin-bottom: $space-5;
+.topBar {
+ @include flex-between;
+ padding: $space-4 $space-6;
+ border-bottom: 1px solid $border-default;
+ font-family: $font-mono;
+ font-size: $font-size-3xs;
+ text-transform: uppercase;
+ letter-spacing: $tracking-widest;
+ color: $text-lighter;
+
+ @include breakpoint-up('md') {
+ padding: $space-4 $space-8;
+ font-size: $font-size-2xs;
+ }
+}
+
+.topLeft {
+ display: flex;
+ align-items: center;
+ gap: $space-4;
}
-.title {
- font-size: $font-size-4xl;
- font-weight: $font-weight-semibold;
+.mark {
color: $text-default;
- letter-spacing: $tracking-tight;
- margin-bottom: $space-2;
+ font-weight: $font-weight-bold;
}
-.subtitle {
- font-size: $font-size-lg;
- color: $text-light;
- margin-bottom: $space-3;
+.topRight {
+ display: flex;
+ align-items: center;
+ gap: $space-6;
}
-.github {
- display: inline-flex;
- color: $text-muted;
- font-size: $font-size-2xl;
- @include transition-fast;
+.status {
+ color: $accent-default;
+}
- @include hover {
- &:hover {
- color: $text-default;
- }
+.hero {
+ padding: $space-16 $space-6 $space-10;
+
+ @include breakpoint-up('md') {
+ padding: $space-20 $space-8 $space-12;
+ }
+
+ @include breakpoint-up('lg') {
+ padding: $space-28 $space-8 $space-16;
}
}
-.content {
- max-width: 800px;
- text-align: center;
+.heroTitle {
+ font-weight: $font-weight-black;
+ font-size: clamp(#{$font-size-5xl}, 10vw, #{$font-size-9xl});
+ line-height: 0.92;
+ letter-spacing: $tracking-tighter;
}
-.description {
- font-size: $font-size-base;
- color: $text-light;
+.heroSub {
+ margin-top: $space-6;
+ font-family: $font-mono;
+ font-size: $font-size-xs;
+ text-transform: uppercase;
+ letter-spacing: $tracking-wide;
+ color: $text-lighter;
+ max-width: 48ch;
line-height: $line-height-relaxed;
- margin-bottom: $space-8;
+
+ @include breakpoint-up('md') {
+ margin-top: $space-8;
+ }
}
-.sections {
+.pattern {
+ height: 36px;
+ margin: 0 $space-6;
+ background: repeating-linear-gradient(
+ -45deg,
+ transparent,
+ transparent 4px,
+ $border-default 4px,
+ $border-default 5px
+ );
+
+ @include breakpoint-up('md') {
+ margin: 0 $space-8;
+ height: 48px;
+ }
+}
+
+.grid {
display: grid;
- grid-template-columns: repeat(2, 1fr);
- gap: $space-6;
- margin-bottom: $space-10;
- text-align: left;
+ grid-template-columns: 1fr;
+ gap: 1px;
+ background: $border-default;
+ margin: $space-6;
+ border: 1px solid $border-default;
- @include breakpoint-down(md) {
- grid-template-columns: 1fr;
+ @include breakpoint-up('md') {
+ grid-template-columns: 1fr 1fr;
+ margin: $space-8;
}
}
-.section {
- padding: $space-5;
- background-color: $bg-surface-75;
- border: 1px solid $border-muted;
- border-radius: $radius-lg;
+.cell {
+ background: $bg-default;
+ padding: $space-5 $space-6;
}
-.sectionTitle {
- font-size: $font-size-sm;
- font-weight: $font-weight-semibold;
- color: $text-default;
- margin-bottom: $space-3;
- letter-spacing: $tracking-wide;
+.cellLabel {
+ display: block;
+ font-family: $font-mono;
+ font-size: $font-size-2xs;
text-transform: uppercase;
+ letter-spacing: $tracking-widest;
+ color: $accent-default;
+ margin-bottom: $space-4;
}
-.features {
+.list {
list-style: none;
- padding: 0;
- margin: 0;
- display: flex;
- flex-direction: column;
+ @include flex-column;
gap: $space-2;
-
- li {
- font-size: $font-size-sm;
- color: $text-muted;
-
- &::before {
- content: '→';
- margin-right: $space-2;
- color: $text-lighter;
- }
- }
+ font-size: $font-size-sm;
+ color: $text-light;
+ line-height: $line-height-normal;
}
.actions {
display: flex;
gap: $space-3;
- justify-content: center;
- flex-wrap: wrap;
+ padding: $space-6;
+ padding-top: $space-4;
+
+ @include breakpoint-up('md') {
+ padding: $space-8;
+ padding-top: $space-6;
+ }
}
-.button {
+.primaryBtn {
display: inline-flex;
align-items: center;
- justify-content: center;
- padding: $space-3 $space-5;
- font-size: $font-size-sm;
- font-weight: $font-weight-medium;
+ padding: $space-3 $space-6;
+ background: $accent-default;
color: $bg-default;
- background-color: $text-default;
- border-radius: $radius-md;
+ font-family: $font-mono;
+ font-size: $font-size-xs;
+ font-weight: $font-weight-medium;
+ text-transform: uppercase;
+ letter-spacing: $tracking-wider;
text-decoration: none;
+ border: 1px solid $accent-default;
@include transition-fast;
@include hover {
- &:hover {
- filter: brightness(0.9);
- }
+ background: $accent-hover;
+ border-color: $accent-hover;
}
}
-.buttonOutline {
+.secondaryBtn {
display: inline-flex;
align-items: center;
- justify-content: center;
- padding: $space-3 $space-5;
- font-size: $font-size-sm;
- font-weight: $font-weight-medium;
+ padding: $space-3 $space-6;
+ background: transparent;
color: $text-default;
- background-color: transparent;
- border: 1px solid $border-default;
- border-radius: $radius-md;
+ font-family: $font-mono;
+ font-size: $font-size-xs;
+ text-transform: uppercase;
+ letter-spacing: $tracking-wider;
text-decoration: none;
+ border: 1px solid $border-strong;
@include transition-fast;
@include hover {
- &:hover {
- border-color: $border-strong;
- background-color: $bg-surface-75;
- }
+ border-color: $text-default;
+ }
+}
+
+.footer {
+ margin-top: auto;
+ padding: $space-4 $space-6;
+ border-top: 1px solid $border-default;
+ @include flex-between;
+ font-family: $font-mono;
+ font-size: $font-size-3xs;
+ text-transform: uppercase;
+ letter-spacing: $tracking-wider;
+ color: $text-muted;
+
+ @include breakpoint-up('md') {
+ padding: $space-4 $space-8;
+ }
+}
+
+.github {
+ color: $text-lighter;
+ @include transition-fast;
+ display: flex;
+
+ @include hover {
+ color: $text-default;
+ }
+
+ svg {
+ width: 16px;
+ height: 16px;
}
}
diff --git a/stacks/fastapi-react/frontend/src/pages/login/index.tsx b/stacks/fastapi-react/frontend/src/pages/login/index.tsx
index 13caa91..5d2a9a1 100644
--- a/stacks/fastapi-react/frontend/src/pages/login/index.tsx
+++ b/stacks/fastapi-react/frontend/src/pages/login/index.tsx
@@ -47,8 +47,11 @@ export function Component(): React.ReactElement {
+
+ ← Back
+
+
Authentication Required
Login
-
Welcome back