@burdenoff/microfe-auth 2026.802.1 → 2026.825.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -601,7 +601,7 @@ function x() {
601
601
  "aria-label": e.name,
602
602
  className: `flex items-center justify-center gap-2 px-4 py-3 rounded-xl border transition-all duration-200 group ${e.disabled ? "border-[var(--color-border-subtle)] bg-[var(--color-bg-disabled)] cursor-not-allowed opacity-50" : "border-[var(--color-border-default)] bg-[var(--color-bg-surface)] hover:bg-[var(--color-bg-sunken)] hover:border-[var(--color-border-strong)]"}`,
603
603
  children: [/* @__PURE__ */ m(e.icon, { className: `size-5 ${e.disabled ? "opacity-50" : ""}` }), /* @__PURE__ */ m("span", {
604
- className: `sr-only sm:not-sr-only text-sm font-medium transition-colors hidden sm:inline ${e.disabled ? "text-[var(--color-text-disabled)]" : "text-[var(--color-text-secondary)] group-hover:text-[var(--color-text-primary)]"}`,
604
+ className: `sr-only sm:not-sr-only text-sm font-medium transition-colors ${e.disabled ? "text-[var(--color-text-disabled)]" : "text-[var(--color-text-secondary)] group-hover:text-[var(--color-text-primary)]"}`,
605
605
  children: e.name
606
606
  })]
607
607
  }, e.name))
@@ -1 +1 @@
1
- {"version":3,"file":"LoginPage.js","names":[],"sources":["../../../src/auth/pages/LoginPage.tsx"],"sourcesContent":["import { useState, useEffect, useCallback, useRef } from \"react\";\nimport { useNavigate, useSearchParams, useLocation } from \"react-router\";\nimport {\n useI18n,\n useActiveContext,\n} from \"@burdenoff/fe-libs/shared/providers/shell\";\nimport {\n getSSORedirectUrl,\n SSORedirectSpinner,\n} from \"@burdenoff/fe-libs/shared/components\";\nimport { resolveAuthBridgeConfig } from \"@burdenoff/fe-libs/shared/config\";\nimport { resolveGatewayUrls } from \"@burdenoff/fe-libs/shared/config/gatewayUrls\";\nimport {\n beginSsoNavigation,\n buildSsoDepositUrl,\n isSsoNavigationPending,\n markSsoDepositPending,\n mintSsoSessionTokens,\n} from \"@burdenoff/fe-libs/shared/utils\";\nimport { Button } from \"@burdenoff/fe-libs/button\";\nimport { PagePurpose } from \"@burdenoff/fe-libs/ui\";\n\nimport {\n getProfileTokens,\n getProfileUser,\n getProfiles,\n getProfileWorkspaceToken,\n resolveActiveProfileId,\n} from \"@burdenoff/fe-libs/shared/providers/shell/ProfileStorageManager\";\nimport { useAuthOperations } from \"../hooks/useAuthOperations\";\nimport { useMyWorkspaces } from \"../hooks/useMyWorkspaces\";\nimport { useOAuthOperations } from \"../hooks/useOAuthOperations\";\nimport { useAuthStore } from \"../store/authStore\";\nimport { useAuth } from \"../providers/AuthProvider\";\nimport { AuthLayout } from \"../components/AuthLayout\";\nimport {\n EmailIcon,\n LockIcon,\n EyeIcon,\n EyeOffIcon,\n AlertIcon,\n SpinnerIcon,\n GoogleIcon,\n // GitHubIcon,\n MicrosoftIcon,\n} from \"../components/AuthIcons\";\nimport { useCaptchaV3 } from \"../hooks/useCaptchaV3\";\nimport { MFA_REDIRECT } from \"../constants/sessionKeys\";\nimport type { SignInInput } from \"../types\";\n\n/**\n * Detect whether the bundle is running inside a native shell (Capacitor on\n * iOS/Android, or Electron). Cross-origin SSO deposit/relay detours only make\n * sense in a multi-origin web context — in a native shell there is one product\n * origin, tokens already live in localStorage, and `window.location.assign` to\n * an external https URL escapes the embedded webview.\n *\n * Detection is runtime-only and avoids importing any platform-specific module\n * so this stays valid when microfe-auth is consumed by a pure web shell too.\n */\nfunction isNativeShell(): boolean {\n if (typeof window === \"undefined\") return false;\n const w = window as typeof window & {\n Capacitor?: { isNativePlatform?: () => boolean };\n };\n if (typeof w.Capacitor?.isNativePlatform === \"function\") {\n try {\n if (w.Capacitor.isNativePlatform()) return true;\n } catch {\n /* fall through */\n }\n }\n if (\n typeof navigator !== \"undefined\" &&\n /Electron/i.test(navigator.userAgent || \"\")\n ) {\n return true;\n }\n return false;\n}\n\nfunction toSameOriginPath(target: string): string {\n if (typeof window === \"undefined\") return target;\n try {\n const url = new URL(target, window.location.origin);\n return `${url.pathname}${url.search}${url.hash}`;\n } catch {\n return target;\n }\n}\n\nfunction hasValidAccessToken(token: string): boolean {\n try {\n const raw = token.split(\".\")[1].replace(/-/g, \"+\").replace(/_/g, \"/\");\n const padded = raw.padEnd(Math.ceil(raw.length / 4) * 4, \"=\");\n const payload = JSON.parse(atob(padded)) as { exp?: unknown };\n return typeof payload.exp === \"number\" && payload.exp > Date.now() / 1000;\n } catch {\n return false;\n }\n}\n\nfunction decodeSameOriginReturnTo(returnTo: string | null): string | null {\n if (!returnTo) return null;\n try {\n const decoded = decodeURIComponent(returnTo);\n const url = new URL(decoded, window.location.origin);\n if (url.origin !== window.location.origin) return null;\n return stripStaleSsoParams(url, { includeOrigin: false });\n } catch {\n return null;\n }\n}\n\nfunction stripStaleSsoParams(\n url: URL,\n options: { includeOrigin: boolean },\n): string {\n for (const param of [\"sso_failed\", \"sso-failed\", \"sso-attempted\"] as const) {\n url.searchParams.delete(param);\n }\n\n if (options.includeOrigin) {\n return url.toString();\n }\n\n const search = url.searchParams.toString();\n return `${url.pathname}${search ? `?${search}` : \"\"}${url.hash}`;\n}\n\nfunction cleanReturnToValue(returnTo: string): string {\n try {\n const decoded = decodeURIComponent(returnTo);\n const url = new URL(decoded, window.location.origin);\n // Preserve cross-origin absolute returnTo values (e.g., redirects back to\n // another product's app shell) — only strip stale SSO params.\n const isCrossOrigin = url.origin !== window.location.origin;\n return stripStaleSsoParams(url, { includeOrigin: isCrossOrigin });\n } catch {\n return returnTo;\n }\n}\n\n/**\n * Login page with professional design\n * Provides email/password login and social OAuth options\n */\nexport function LoginPage() {\n const navigate = useNavigate();\n const location = useLocation();\n const [searchParams] = useSearchParams();\n const { t } = useI18n();\n const tr = useCallback(\n (key: string, fallback: string): string => {\n const translated = t(key);\n return translated === key ? fallback : translated;\n },\n [t],\n );\n const { signIn, isLoading, error, errorCode, resendVerification } =\n useAuthOperations();\n const { completeAuthFlow } = useMyWorkspaces();\n const { setWorkspace, setOrganization } = useActiveContext();\n const { defaultPostLoginPath } = useAuth();\n const { initiateGoogleOAuth, initiateMicrosoftOAuth, isProviderConfigured } =\n useOAuthOperations();\n const mfaRequired = useAuthStore((state) => state.mfaRequired);\n const { executeRecaptcha: executeCaptchaV3 } = useCaptchaV3();\n const [isCompletingAuth, setIsCompletingAuth] = useState(false);\n const [isSsoRedirecting, setIsSsoRedirecting] = useState(false);\n\n /**\n * Build the URL that should receive the post-login redirect.\n *\n * For cross-eTLD+1 SSO on alpha/prod we detour through the central bridge\n * host (alphaapp/app.burdenoff.com) so the freshly-issued tokens land in\n * the bridge origin's first-party (unpartitioned) localStorage. Without\n * this step, a later direct visit to the bridge host has no local tokens\n * and no shared cookie (cross-eTLD+1 cookies don't propagate), so the user\n * sees the login page again.\n *\n * Skipped when:\n * - Already on the bridge host origin (would be a no-op self-redirect).\n * - The user's intended destination is itself on the bridge host\n * (likely an in-product navigation, no deposit needed).\n * - The freshly-stored profile snapshot can't be read (best-effort only —\n * login still succeeds via the direct redirect).\n */\n const buildPostLoginUrl = useCallback(\n async (intendedPath: string): Promise<string> => {\n if (typeof window === \"undefined\") return intendedPath;\n // Native shells (Electron, Capacitor iOS/Android) run as a single origin —\n // skip the cross-eTLD+1 deposit detour, which would otherwise navigate to\n // an external https URL and escape the embedded webview.\n if (isNativeShell()) return intendedPath;\n try {\n const bridge = resolveAuthBridgeConfig();\n const bridgeUrl = new URL(bridge.url);\n const currentOrigin = window.location.origin;\n if (bridgeUrl.origin === currentOrigin) return intendedPath;\n\n // intendedPath can be a path or an absolute URL; resolve to absolute\n // against current origin so the bridge host knows where to send the\n // user back.\n const absoluteIntended = new URL(intendedPath, currentOrigin).href;\n\n const profileId = resolveActiveProfileId();\n if (!profileId) return intendedPath;\n const tokens = getProfileTokens(profileId);\n const user = getProfileUser(profileId);\n if (!tokens || !user) return intendedPath;\n const workspaceToken = getProfileWorkspaceToken(profileId);\n\n // BOFF-4463: mint a DEDICATED refresh-token lineage for the bridge\n // host. Copying this origin's pair verbatim meant the bridge (and\n // every product it later relayed to) shared ONE rotating refresh\n // token — the first origin to refresh revoked it for all others,\n // surfacing as \"products log me out after minutes/hours\". Falls back\n // to the legacy copy if the mutation is unreachable (rollout gap /\n // transient failure) so SSO keeps working.\n let depositTokens: Record<string, unknown> = {\n ...tokens,\n workspaceToken,\n };\n if (tokens.refreshToken) {\n const { globalBaseUrl } = resolveGatewayUrls();\n const { tokens: minted } = await mintSsoSessionTokens(\n `${globalBaseUrl}/global/graphql`,\n tokens.refreshToken,\n );\n if (minted) {\n depositTokens = { ...minted, workspaceToken };\n }\n }\n\n markSsoDepositPending(profileId);\n return buildSsoDepositUrl(bridgeUrl.origin, absoluteIntended, {\n profileId,\n tokens: JSON.stringify(depositTokens),\n user: JSON.stringify(user),\n profiles: JSON.stringify(getProfiles()),\n });\n } catch {\n return intendedPath;\n }\n },\n [],\n );\n\n // Once a cross-document post-login redirect is initiated, the login page\n // must FREEZE: resetting isCompletingAuth re-runs the auto-redirect effect\n // and any state churn schedules same-document navigations that cancel the\n // provisional deposit hop (BOFF-4463).\n const redirectInitiatedRef = useRef(false);\n\n const redirectAfterLogin = useCallback(\n (path: string) => {\n if (typeof window === \"undefined\") {\n navigate(path);\n return;\n }\n try {\n sessionStorage.setItem(\"bf-post-login-return-to\", path);\n } catch {\n // Ignore storage failures; redirect still proceeds.\n }\n // In native shells use SPA navigation so the embedded webview stays in\n // the app — no full reload, no chance of the OS opening the URL\n // externally. Tokens are already in this origin's localStorage.\n if (isNativeShell()) {\n navigate(toSameOriginPath(path));\n return;\n }\n redirectInitiatedRef.current = true;\n void (async () => {\n const target = await buildPostLoginUrl(path);\n if (target.includes(\"/auth/sso-deposit\")) {\n // Cross-document deposit hop: suppress same-document navigators\n // while it is provisional, and retry once if it still gets\n // cancelled — on a committed navigation this document unloads and\n // the timer never fires.\n beginSsoNavigation();\n window.location.assign(target);\n window.setTimeout(() => {\n beginSsoNavigation();\n window.location.replace(target);\n }, 2500);\n } else {\n window.location.assign(target);\n }\n })();\n },\n [navigate, buildPostLoginUrl],\n );\n const [showPassword, setShowPassword] = useState(false);\n const [isAccountInactive, setIsAccountInactive] = useState(false);\n const [isAccountDeleted, setIsAccountDeleted] = useState(false);\n const [isAccountSuspended, setIsAccountSuspended] = useState(false);\n const [isOAuthOnlyAccount, setIsOAuthOnlyAccount] = useState(false);\n const [isEmailNotVerified, setIsEmailNotVerified] = useState(false);\n const [isResendingVerification, setIsResendingVerification] = useState(false);\n const [resendSuccess, setResendSuccess] = useState(false);\n const [oauthError, setOauthError] = useState<string | null>(null);\n const [infoMessage, setInfoMessage] = useState<string | null>(null);\n const [formData, setFormData] = useState<\n SignInInput & { rememberMe?: boolean }\n >({\n email: \"\",\n password: \"\",\n rememberMe: false,\n });\n const [validationError, setValidationError] = useState<string | null>(null);\n const [isDuplicateAccount, setIsDuplicateAccount] = useState(false);\n\n // Detect add-account mode and returnTo from URL params\n const isAddAccountMode = searchParams.get(\"mode\") === \"add-account\";\n const returnTo = searchParams.get(\"returnTo\");\n const initialReturnToRef = useRef<string | null>(returnTo);\n\n // Tell the user WHY they are back on the login page. `session-expired` is\n // set by the shell's forced logout (expired session whose refresh failed);\n // `logout` covers explicit sign-outs and the SSO-clear fallback (which can\n // rewrite a session-expired redirect's reason on the cross-product bounce).\n // Without this the auto-logout looked like a silent, unexplained kick-out.\n const reasonParam = searchParams.get(\"reason\");\n useEffect(() => {\n if (reasonParam === \"session-expired\") {\n setInfoMessage(\n tr(\n \"auth.login.sessionExpired\",\n \"Your session has expired. Please sign in again.\",\n ),\n );\n } else if (reasonParam === \"logout\") {\n setInfoMessage(tr(\"auth.login.signedOut\", \"You have been signed out.\"));\n }\n }, [reasonParam, tr]);\n\n useEffect(() => {\n if (!initialReturnToRef.current && returnTo) {\n initialReturnToRef.current = returnTo;\n }\n }, [returnTo]);\n\n useEffect(() => {\n if (isAddAccountMode || isCompletingAuth) return;\n // A cross-document SSO navigation (deposit/relay hop) is already in\n // flight — issuing another redirect here would cancel it (BOFF-4463).\n if (redirectInitiatedRef.current || isSsoNavigationPending()) return;\n\n const profileId = resolveActiveProfileId();\n if (profileId) {\n const tokens = getProfileTokens(profileId);\n const user = getProfileUser(profileId);\n if (\n tokens?.accessToken &&\n user &&\n hasValidAccessToken(tokens.accessToken)\n ) {\n useAuthStore.getState().loadFromProfile(profileId);\n redirectAfterLogin(decodeSameOriginReturnTo(returnTo) ?? \"/\");\n return;\n }\n }\n\n const ssoUrl = getSSORedirectUrl();\n if (ssoUrl) {\n setIsSsoRedirecting(true);\n window.location.replace(ssoUrl);\n }\n }, [isAddAccountMode, isCompletingAuth, redirectAfterLogin, returnTo]);\n\n // Load remembered email on mount and clean up any legacy plaintext password storage\n useEffect(() => {\n try {\n // Security cleanup: remove any previously stored plaintext passwords\n localStorage.removeItem(\"remembered_password\");\n\n const rememberedEmail = localStorage.getItem(\"remembered_email\");\n\n if (rememberedEmail) {\n setFormData((prev) => ({\n ...prev,\n email: rememberedEmail,\n rememberMe: true,\n }));\n }\n } catch (error) {\n console.warn(\"[LoginPage] Failed to load remembered email:\", error);\n }\n }, []);\n\n // Check for redirect message and email from location state (e.g., from expired MFA or SSO redirect)\n useEffect(() => {\n const state = location.state as { message?: string; email?: string } | null;\n if (state?.message) {\n setInfoMessage(state.message);\n }\n if (state?.email) {\n setFormData((prev) => ({ ...prev, email: state.email }));\n }\n // Clear state to prevent showing message on refresh\n if (state) {\n window.history.replaceState({}, document.title);\n }\n }, [location.state]);\n\n // Determine error type from GraphQL error code (primary) or message (fallback).\n // The backend sends structured codes in extensions.code which are propagated\n // through useAuthOperations → authStore.errorCode.\n const checkErrorType = (\n err: string | null,\n code?: string | null,\n ):\n | \"DELETED\"\n | \"SUSPENDED\"\n | \"OAUTH_ONLY\"\n | \"INACTIVE\"\n | \"EMAIL_NOT_VERIFIED\"\n | null => {\n // Primary: match on GraphQL error code from extensions\n if (code) {\n switch (code) {\n case \"ACCOUNT_DELETED\":\n return \"DELETED\";\n case \"ACCOUNT_SUSPENDED\":\n return \"SUSPENDED\";\n case \"OAUTH_ONLY_ACCOUNT\":\n return \"OAUTH_ONLY\";\n case \"ACCOUNT_INACTIVE\":\n return \"INACTIVE\";\n case \"EMAIL_NOT_VERIFIED\":\n return \"EMAIL_NOT_VERIFIED\";\n default:\n break;\n }\n }\n\n // Fallback: match on error message for non-GraphQL errors or legacy responses\n if (!err) return null;\n const lowerErr = err.toLowerCase();\n\n if (\n lowerErr.includes(\"deleted\") ||\n lowerErr.includes(\"permanently deleted\")\n ) {\n return \"DELETED\";\n }\n if (lowerErr.includes(\"suspended\")) {\n return \"SUSPENDED\";\n }\n if (\n lowerErr.includes(\"oauth provider\") ||\n lowerErr.includes(\"oauth-only\") ||\n lowerErr.includes(\"oauth only\")\n ) {\n return \"OAUTH_ONLY\";\n }\n if (\n lowerErr.includes(\"inactive\") ||\n lowerErr.includes(\"deactivated\") ||\n lowerErr.includes(\"not active\")\n ) {\n return \"INACTIVE\";\n }\n if (\n lowerErr.includes(\"verify your email\") ||\n lowerErr.includes(\"email not verified\") ||\n lowerErr.includes(\"email_not_verified\")\n ) {\n return \"EMAIL_NOT_VERIFIED\";\n }\n return null;\n };\n\n // Pre-fill email from URL query parameter (e.g., after email verification)\n useEffect(() => {\n const emailFromUrl = searchParams.get(\"email\");\n if (emailFromUrl) {\n setFormData((prev) => ({ ...prev, email: emailFromUrl }));\n }\n\n // Check for expired session redirect\n const isExpired = searchParams.get(\"expired\");\n if (isExpired === \"true\") {\n setInfoMessage(\n tr(\n \"auth.login.sessionExpired\",\n \"Your session has expired. Please sign in again.\",\n ),\n );\n // Clear the query param to prevent showing on refresh\n const newUrl = window.location.pathname;\n window.history.replaceState({}, document.title, newUrl);\n }\n }, [searchParams, tr]);\n\n // Redirect to MFA verification when required\n useEffect(() => {\n if (mfaRequired) {\n navigate(\"/auth/mfa-verify\");\n }\n }, [mfaRequired, navigate]);\n\n const handleSubmit = async (e: React.FormEvent) => {\n e.preventDefault();\n setIsAccountInactive(false);\n setIsAccountDeleted(false);\n setIsAccountSuspended(false);\n setIsOAuthOnlyAccount(false);\n setIsEmailNotVerified(false);\n setIsDuplicateAccount(false);\n setResendSuccess(false);\n setValidationError(null);\n\n // Client-side validation\n const emailTrimmed = (formData.email ?? \"\").trim();\n if (!emailTrimmed) {\n setValidationError(\n tr(\n \"auth.login.enterEmailOrUsername\",\n \"Please enter your email or username\",\n ),\n );\n return;\n }\n\n // Basic email format validation (if it contains @)\n if (emailTrimmed.includes(\"@\")) {\n const emailRegex = /^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$/;\n if (!emailRegex.test(emailTrimmed)) {\n setValidationError(\n tr(\"auth.login.invalidEmail\", \"Please enter a valid email address\"),\n );\n return;\n }\n }\n\n if (!formData.password || formData.password.length < 1) {\n setValidationError(\n tr(\"auth.login.enterPassword\", \"Please enter your password\"),\n );\n return;\n }\n\n // In add-account mode, check if this email is already signed in\n if (isAddAccountMode) {\n const existingProfiles = getProfiles();\n const alreadySignedIn = existingProfiles.some(\n (p) => p.email.toLowerCase() === emailTrimmed.toLowerCase(),\n );\n if (alreadySignedIn) {\n setIsDuplicateAccount(true);\n setValidationError(null);\n return;\n }\n }\n setIsDuplicateAccount(false);\n\n try {\n // Get reCAPTCHA v3 token (no-op when captcha is disabled)\n const recaptchaToken = await executeCaptchaV3(\"login\");\n\n const result = await signIn({\n email: emailTrimmed,\n password: formData.password,\n rememberMe: formData.rememberMe,\n ...(recaptchaToken ? { recaptchaToken } : {}),\n });\n\n // If MFA is required, the useEffect above will handle redirect\n if (result.requiresMFA) {\n // Persist the post-login destination so MfaVerifyPage honors\n // `returnTo` and `defaultPostLoginPath` after the user completes\n // verification — otherwise the MFA path falls back to \"/\" and the\n // host-configured home (e.g. \"/vibecontrols\") is lost.\n const effectiveReturnTo = initialReturnToRef.current || returnTo;\n const postMfaPath = effectiveReturnTo\n ? cleanReturnToValue(effectiveReturnTo)\n : cleanReturnToValue(defaultPostLoginPath ?? \"/dashboard\");\n try {\n sessionStorage.setItem(MFA_REDIRECT, postMfaPath);\n } catch {\n // sessionStorage may be unavailable (private mode, quota) — the\n // MFA page still works, it just defaults to \"/\" on completion.\n }\n return;\n }\n\n // Successful login - complete auth flow (fetch workspaces + issue token)\n if (result.success) {\n try {\n const profileId = result.user?.id;\n if (profileId) {\n const hostname = window.location.hostname;\n const domain = hostname.endsWith(\".local.burdenoff.com\")\n ? \".local.burdenoff.com\"\n : undefined;\n const domainPart = domain ? `; domain=${domain}` : \"\";\n const securePart =\n window.location.protocol === \"https:\" ? \"; secure\" : \"\";\n const ssoValue = JSON.stringify({\n id: profileId,\n origin: window.location.origin,\n });\n document.cookie = `bf-sso=${encodeURIComponent(ssoValue)}${domainPart}; path=/; samesite=lax${securePart}; max-age=86400`;\n document.cookie = `bf-sso-profile=${encodeURIComponent(ssoValue)}${domainPart}; path=/; samesite=lax${securePart}; max-age=86400`;\n }\n } catch {\n // Best effort only. Login can continue without the fast-path cookie.\n }\n\n // Handle Remember Me: Save or clear email only (never store passwords)\n try {\n if (formData.rememberMe) {\n localStorage.setItem(\"remembered_email\", emailTrimmed);\n } else {\n localStorage.removeItem(\"remembered_email\");\n }\n } catch (error) {\n console.warn(\n \"[LoginPage] Failed to save/clear remembered email:\",\n error,\n );\n }\n\n setIsCompletingAuth(true);\n // In add-account mode, redirect back to where the user was\n const effectiveReturnTo = initialReturnToRef.current || returnTo;\n const postLoginPath = effectiveReturnTo\n ? cleanReturnToValue(effectiveReturnTo)\n : cleanReturnToValue(defaultPostLoginPath ?? \"/dashboard\");\n try {\n type AuthFlowResult = Awaited<ReturnType<typeof completeAuthFlow>>;\n // Pass the token directly to avoid race condition with React state updates\n const authFlowResult = await Promise.race<AuthFlowResult>([\n completeAuthFlow(result.token),\n new Promise<AuthFlowResult>((resolve) => {\n window.setTimeout(() => {\n resolve({\n success: false,\n error: \"Auth flow timed out after login\",\n });\n }, 5000);\n }),\n ]);\n\n if (authFlowResult.success) {\n // Sync workspace and organization to ActiveContext\n // This is critical for global search and other workspace-scoped features\n if (authFlowResult.workspace) {\n setWorkspace(authFlowResult.workspace.id);\n if (authFlowResult.workspace.organizationId) {\n setOrganization(authFlowResult.workspace.organizationId);\n }\n }\n\n // Full auth flow completed - redirect to dashboard or returnTo\n redirectAfterLogin(postLoginPath);\n } else if (authFlowResult.error?.includes(\"No workspaces found\")) {\n // No workspaces - redirect to onboarding/workspace creation\n navigate(\"/onboarding/create-workspace\");\n } else {\n // Partial success or error - still sync workspace if available and redirect\n if (authFlowResult.workspace) {\n setWorkspace(authFlowResult.workspace.id);\n if (authFlowResult.workspace.organizationId) {\n setOrganization(authFlowResult.workspace.organizationId);\n }\n }\n console.warn(\"Auth flow warning:\", authFlowResult.error);\n redirectAfterLogin(postLoginPath);\n }\n } catch (authFlowError) {\n // Auth flow failed but login succeeded - still redirect\n console.error(\"Auth flow error (login succeeded):\", authFlowError);\n redirectAfterLogin(postLoginPath);\n } finally {\n // Keep the completing state (spinner) once a redirect is in\n // flight: resetting it re-arms the auto-redirect effect whose\n // competing navigation cancels the deposit hop (BOFF-4463). The\n // page is about to unload anyway.\n if (!redirectInitiatedRef.current) {\n setIsCompletingAuth(false);\n }\n }\n }\n } catch (err) {\n if (import.meta.env.DEV) {\n console.error(\"Sign in failed:\", err);\n }\n // Check error type using error code (from store) and message\n const errorMsg = err instanceof Error ? err.message : String(err);\n if (errorMsg.includes(\"reCAPTCHA\")) {\n setValidationError(errorMsg);\n }\n const storeErrorCode = useAuthStore.getState().errorCode;\n const errorType = checkErrorType(errorMsg, storeErrorCode);\n if (errorType === \"DELETED\") {\n setIsAccountDeleted(true);\n } else if (errorType === \"SUSPENDED\") {\n setIsAccountSuspended(true);\n } else if (errorType === \"OAUTH_ONLY\") {\n setIsOAuthOnlyAccount(true);\n } else if (errorType === \"INACTIVE\") {\n setIsAccountInactive(true);\n } else if (errorType === \"EMAIL_NOT_VERIFIED\") {\n setIsEmailNotVerified(true);\n }\n }\n };\n\n // Also check the error from useAuthOperations\n useEffect(() => {\n if (error) {\n const errorType = checkErrorType(error, errorCode);\n if (errorType === \"DELETED\") {\n setIsAccountDeleted(true);\n } else if (errorType === \"SUSPENDED\") {\n setIsAccountSuspended(true);\n } else if (errorType === \"OAUTH_ONLY\") {\n setIsOAuthOnlyAccount(true);\n } else if (errorType === \"INACTIVE\") {\n setIsAccountInactive(true);\n } else if (errorType === \"EMAIL_NOT_VERIFIED\") {\n setIsEmailNotVerified(true);\n }\n }\n }, [error, errorCode]);\n\n /**\n * Handle Google OAuth login\n */\n const handleGoogleLogin = () => {\n setOauthError(null);\n try {\n initiateGoogleOAuth();\n } catch (err) {\n setOauthError(\n err instanceof Error\n ? err.message\n : tr(\n \"auth.login.googleSignInFailed\",\n \"Failed to initiate Google sign in\",\n ),\n );\n }\n };\n\n /**\n * Handle Microsoft OAuth login\n */\n const handleMicrosoftLogin = () => {\n setOauthError(null);\n try {\n initiateMicrosoftOAuth();\n } catch (err) {\n setOauthError(\n err instanceof Error\n ? err.message\n : tr(\n \"auth.login.microsoftSignInFailed\",\n \"Failed to initiate Microsoft sign in\",\n ),\n );\n }\n };\n\n /**\n * Handle resend verification email\n */\n const handleResendVerification = async () => {\n setIsResendingVerification(true);\n setResendSuccess(false);\n try {\n const emailTrimmed = (formData.email ?? \"\").trim();\n const result = await resendVerification(emailTrimmed);\n if (result.success) {\n setResendSuccess(true);\n } else {\n setValidationError(\n tr(\n \"auth.login.resendFailed\",\n \"Failed to resend verification email. Please try again.\",\n ),\n );\n }\n } catch (err) {\n console.error(\"Failed to resend verification email:\", err);\n setValidationError(\n err instanceof Error\n ? err.message\n : tr(\n \"auth.login.resendFailed\",\n \"Failed to resend verification email. Please try again.\",\n ),\n );\n } finally {\n setIsResendingVerification(false);\n }\n };\n\n // Check if OAuth providers are configured\n const isGoogleConfigured = isProviderConfigured(\"google\");\n const isMicrosoftConfigured = isProviderConfigured(\"microsoft\");\n\n const oauthProviders = [\n {\n name: \"Google\",\n icon: GoogleIcon,\n onClick: handleGoogleLogin,\n disabled: !isGoogleConfigured,\n tooltip: isGoogleConfigured\n ? undefined\n : tr(\n \"auth.login.googleNotConfigured\",\n \"Google sign in is not configured\",\n ),\n },\n // {\n // name: \"GitHub\",\n // icon: GitHubIcon,\n // onClick: () => {},\n // disabled: true,\n // tooltip: tr(\n // \"auth.login.githubNotConfigured\",\n // \"GitHub sign in is not configured\",\n // ),\n // },\n {\n name: \"Microsoft\",\n icon: MicrosoftIcon,\n onClick: handleMicrosoftLogin,\n disabled: !isMicrosoftConfigured,\n tooltip: isMicrosoftConfigured\n ? undefined\n : tr(\n \"auth.login.microsoftNotConfigured\",\n \"Microsoft sign in is not configured\",\n ),\n },\n ];\n\n if (isSsoRedirecting) {\n return <SSORedirectSpinner />;\n }\n\n return (\n <AuthLayout\n title={tr(\"auth.login.welcomeBack\", \"Welcome back\")}\n subtitle={tr(\n \"auth.login.enterCredentials\",\n \"Enter your credentials to continue\",\n )}\n >\n <PagePurpose className=\"mb-5\">\n {tr(\n \"auth.login.purpose\",\n \"Sign in to reach your workspaces, agents, and settings. Use your email and password, a social provider, or a passwordless magic link.\",\n )}\n </PagePurpose>\n <form onSubmit={handleSubmit} className=\"space-y-5\">\n {/* Info Message (e.g., from expired MFA redirect) */}\n {infoMessage && (\n <div className=\"flex items-start gap-3 p-4 rounded-xl border bg-status-info-bg-subtle border-status-info-border\">\n <svg\n className=\"size-5 flex-shrink-0 mt-0.5 text-text-link\"\n fill=\"none\"\n viewBox=\"0 0 24 24\"\n stroke=\"currentColor\"\n >\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth={2}\n d=\"M13 16h-1v-4h-1m1-4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z\"\n />\n </svg>\n <p className=\"text-sm text-status-info-text\">{infoMessage}</p>\n </div>\n )}\n\n {/* Validation Error */}\n {validationError && (\n <div className=\"flex items-start gap-3 p-4 rounded-xl border bg-status-warning-bg-subtle border-status-warning-border\">\n <AlertIcon className=\"size-5 flex-shrink-0 mt-0.5 text-status-warning-text\" />\n <p className=\"text-sm text-status-warning-text\">\n {validationError}\n </p>\n </div>\n )}\n\n {/* Duplicate Account Warning (Add Account mode) */}\n {isDuplicateAccount && (\n <div className=\"flex items-start gap-3 p-4 rounded-xl border bg-status-warning-bg-subtle border-status-warning-border\">\n <AlertIcon className=\"size-5 flex-shrink-0 mt-0.5 text-status-warning-text\" />\n <div className=\"flex-1\">\n <p className=\"text-sm font-medium text-status-warning-text\">\n {tr(\n \"auth.login.duplicateAccount\",\n \"This account is already signed in.\",\n )}\n </p>\n <p className=\"mt-1 text-sm text-status-warning-text/80\">\n {tr(\n \"auth.login.duplicateAccountHint\",\n \"Please use a different account, or go back and switch to this account from the profile menu.\",\n )}\n </p>\n {(initialReturnToRef.current || returnTo) && (\n <button\n type=\"button\"\n onClick={() =>\n navigate(\n decodeURIComponent(\n initialReturnToRef.current || returnTo || \"/dashboard\",\n ),\n )\n }\n className=\"mt-3 inline-flex items-center gap-2 px-4 py-2.5 rounded-xl border border-status-warning-border bg-bg-surface text-status-warning-text text-sm font-medium hover:bg-status-warning-bg-subtle hover:border-status-warning-border transition-all shadow-sm\"\n >\n <svg\n className=\"size-4\"\n fill=\"none\"\n viewBox=\"0 0 24 24\"\n stroke=\"currentColor\"\n >\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth={2}\n d=\"M10 19l-7-7m0 0l7-7m-7 7h18\"\n />\n </svg>\n {tr(\n \"auth.login.goBackSwitchAccount\",\n \"Go back and switch account\",\n )}\n </button>\n )}\n </div>\n </div>\n )}\n\n {/* Error Alert */}\n {error && !validationError && !isDuplicateAccount && (\n <div\n className={`flex items-start gap-3 p-4 rounded-xl border ${\n isAccountInactive || isOAuthOnlyAccount || isEmailNotVerified\n ? \"bg-status-warning-bg-subtle border-status-warning-border\"\n : \"bg-status-error-bg-subtle border-status-error-border\"\n }`}\n >\n <AlertIcon\n className={`size-5 flex-shrink-0 mt-0.5 ${\n isAccountInactive || isOAuthOnlyAccount || isEmailNotVerified\n ? \"text-status-warning-text\"\n : \"text-status-error-text\"\n }`}\n />\n <div className=\"flex-1\">\n <p\n className={`text-sm ${\n isAccountInactive || isOAuthOnlyAccount || isEmailNotVerified\n ? \"text-status-warning-text\"\n : \"text-status-error-text\"\n }`}\n >\n {isAccountDeleted\n ? tr(\n \"auth.login.accountDeleted\",\n \"This account has been permanently deleted and cannot be recovered.\",\n )\n : isAccountSuspended\n ? tr(\n \"auth.login.accountSuspended\",\n \"Your account has been suspended. Please contact support for assistance.\",\n )\n : isAccountInactive\n ? tr(\n \"auth.login.accountDeactivated\",\n \"Your account has been deactivated.\",\n )\n : isOAuthOnlyAccount\n ? tr(\n \"auth.login.oauthOnly\",\n \"This account uses OAuth sign-in. Please use Google or Microsoft to sign in.\",\n )\n : isEmailNotVerified\n ? tr(\n \"auth.login.emailNotVerified\",\n \"Please verify your email before signing in. Check your inbox for the verification link.\",\n )\n : error}\n </p>\n {isAccountInactive && (\n <button\n type=\"button\"\n onClick={() =>\n navigate(\"/auth/reactivate\", {\n state: { email: formData.email },\n })\n }\n className=\"mt-2 text-sm font-semibold text-status-warning-text hover:text-status-warning-text underline underline-offset-2\"\n >\n {tr(\n \"auth.login.clickReactivate\",\n \"Click here to reactivate your account\",\n )}\n </button>\n )}\n {isEmailNotVerified && (\n <div className=\"mt-3\">\n {resendSuccess ? (\n <div className=\"flex items-center gap-2 text-sm text-status-success-text\">\n <svg\n className=\"size-4\"\n fill=\"none\"\n viewBox=\"0 0 24 24\"\n stroke=\"currentColor\"\n >\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth={2}\n d=\"M5 13l4 4L19 7\"\n />\n </svg>\n {tr(\n \"auth.login.verificationSent\",\n \"Verification email sent! Please check your inbox.\",\n )}\n </div>\n ) : (\n <button\n type=\"button\"\n onClick={handleResendVerification}\n disabled={isResendingVerification}\n className=\"inline-flex items-center gap-2 px-4 py-2.5 rounded-xl border border-status-warning-border bg-bg-surface text-status-warning-text text-sm font-medium hover:bg-status-warning-bg-subtle hover:border-status-warning-border transition-all shadow-sm disabled:opacity-50 disabled:cursor-not-allowed\"\n >\n {isResendingVerification ? (\n <>\n <SpinnerIcon className=\"size-4 animate-spin\" />\n {tr(\"auth.login.sending\", \"Sending...\")}\n </>\n ) : (\n <>\n <svg\n className=\"size-4\"\n fill=\"none\"\n viewBox=\"0 0 24 24\"\n stroke=\"currentColor\"\n >\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth={2}\n d=\"M3 8l7.89 5.26a2 2 0 002.22 0L21 8M5 19h14a2 2 0 002-2V7a2 2 0 00-2-2H5a2 2 0 00-2 2v10a2 2 0 002 2z\"\n />\n </svg>\n {tr(\n \"auth.login.resendVerification\",\n \"Resend verification email\",\n )}\n </>\n )}\n </button>\n )}\n </div>\n )}\n {isOAuthOnlyAccount && (\n <div className=\"mt-3 flex flex-col gap-2\">\n {isProviderConfigured(\"google\") && (\n <button\n type=\"button\"\n onClick={handleGoogleLogin}\n className=\"inline-flex items-center justify-center gap-2 px-4 py-2.5 rounded-xl border border-border-default bg-bg-surface text-text-primary text-sm font-medium hover:bg-bg-canvas hover:border-border-default transition-all shadow-sm\"\n >\n <GoogleIcon className=\"size-5\" />\n {tr(\"auth.login.signInWithGoogle\", \"Sign in with Google\")}\n </button>\n )}\n {isProviderConfigured(\"microsoft\") && (\n <button\n type=\"button\"\n onClick={handleMicrosoftLogin}\n className=\"inline-flex items-center justify-center gap-2 px-4 py-2.5 rounded-xl border border-border-default bg-bg-surface text-text-primary text-sm font-medium hover:bg-bg-canvas hover:border-border-default transition-all shadow-sm\"\n >\n <MicrosoftIcon className=\"size-5\" />\n {tr(\n \"auth.login.signInWithMicrosoft\",\n \"Sign in with Microsoft\",\n )}\n </button>\n )}\n </div>\n )}\n </div>\n </div>\n )}\n\n {/* Email Input */}\n <div className=\"space-y-2\">\n <label\n htmlFor=\"email\"\n className=\"block text-sm font-medium text-[var(--color-text-primary)]\"\n >\n {tr(\"auth.login.emailLabel\", \"Email\")}\n </label>\n <div className=\"relative\">\n <div className=\"absolute inset-y-0 left-0 pl-3.5 flex items-center pointer-events-none\">\n <EmailIcon className=\"size-5 text-[var(--color-text-tertiary)]\" />\n </div>\n <input\n id=\"email\"\n type=\"email\"\n autoComplete=\"email\"\n required\n aria-required=\"true\"\n aria-label={tr(\"auth.login.emailLabel\", \"Email\")}\n value={formData.email}\n onChange={(e) =>\n setFormData({ ...formData, email: e.target.value })\n }\n className=\"block w-full pl-[3.5rem] pr-4 py-3 rounded-xl border border-[var(--color-border-default)] bg-[var(--color-bg-surface)] text-[var(--color-text-primary)] placeholder:text-[var(--color-text-tertiary)] focus:outline-none focus:ring-2 focus:ring-action-primary-bg/20 focus:border-action-primary-bg transition-all\"\n placeholder={tr(\"auth.login.emailPlaceholder\", \"you@example.com\")}\n />\n </div>\n </div>\n\n {/* Password Input */}\n <div className=\"space-y-2\">\n <label\n htmlFor=\"password\"\n className=\"block text-sm font-medium text-[var(--color-text-primary)]\"\n >\n {tr(\"auth.login.passwordLabel\", \"Password\")}\n </label>\n <div className=\"relative\">\n <div className=\"absolute inset-y-0 left-0 pl-3.5 flex items-center pointer-events-none\">\n <LockIcon className=\"size-5 text-[var(--color-text-tertiary)]\" />\n </div>\n <input\n id=\"password\"\n type={showPassword ? \"text\" : \"password\"}\n autoComplete=\"current-password\"\n required\n aria-required=\"true\"\n aria-label={tr(\"auth.login.passwordLabel\", \"Password\")}\n value={formData.password}\n onChange={(e) =>\n setFormData({ ...formData, password: e.target.value })\n }\n className=\"block w-full pl-[3.5rem] pr-12 py-3 rounded-xl border border-[var(--color-border-default)] bg-[var(--color-bg-surface)] text-[var(--color-text-primary)] placeholder:text-[var(--color-text-tertiary)] focus:outline-none focus:ring-2 focus:ring-action-primary-bg/20 focus:border-action-primary-bg transition-all\"\n placeholder={tr(\n \"auth.login.passwordPlaceholder\",\n \"Enter your password\",\n )}\n />\n <button\n type=\"button\"\n onClick={() => setShowPassword(!showPassword)}\n aria-label={showPassword ? \"Hide password\" : \"Show password\"}\n className=\"absolute inset-y-0 right-0 pr-3.5 flex items-center text-[var(--color-text-tertiary)] hover:text-[var(--color-text-secondary)] transition-colors\"\n >\n {showPassword ? (\n <EyeOffIcon className=\"size-5\" />\n ) : (\n <EyeIcon className=\"size-5\" />\n )}\n </button>\n </div>\n </div>\n\n {/* Remember & Forgot */}\n <div className=\"flex items-center justify-between\">\n <label className=\"flex items-center gap-2 cursor-pointer group\">\n <div className=\"relative\">\n <input\n type=\"checkbox\"\n aria-label={tr(\"auth.login.rememberMe\", \"Remember me\")}\n checked={formData.rememberMe}\n onChange={(e) => {\n const isChecked = e.target.checked;\n setFormData({ ...formData, rememberMe: isChecked });\n\n // Clear saved email immediately when unchecked\n if (!isChecked) {\n try {\n localStorage.removeItem(\"remembered_email\");\n } catch (error) {\n console.warn(\n \"[LoginPage] Failed to clear remembered email:\",\n error,\n );\n }\n }\n }}\n className=\"sr-only peer\"\n />\n <div className=\"size-5 rounded-md border-2 border-[var(--color-border-default)] bg-[var(--color-bg-surface)] peer-checked:bg-status-info-bg-subtle0 peer-checked:border-action-primary-bg transition-all peer-focus:ring-2 peer-focus:ring-action-primary-bg/20\">\n <svg\n className=\"size-full text-white opacity-0 peer-checked:opacity-100 transition-opacity p-0.5\"\n fill=\"none\"\n viewBox=\"0 0 24 24\"\n stroke=\"currentColor\"\n strokeWidth={3}\n >\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n d=\"M5 13l4 4L19 7\"\n />\n </svg>\n </div>\n </div>\n <span className=\"text-sm text-[var(--color-text-secondary)] group-hover:text-[var(--color-text-primary)] transition-colors\">\n {tr(\"auth.login.rememberMe\", \"Remember me\")}\n </span>\n </label>\n <button\n type=\"button\"\n onClick={() => navigate(\"/auth/reset-password\")}\n className=\"text-sm font-medium text-text-link hover:text-text-linkHover transition-colors\"\n >\n {tr(\"auth.login.forgotPassword\", \"Forgot password?\")}\n </button>\n </div>\n\n {/* Submit Button */}\n <Button\n type=\"submit\"\n disabled={isLoading || isCompletingAuth}\n variant=\"default\"\n size=\"lg\"\n className=\"w-full font-semibold\"\n >\n {isLoading || isCompletingAuth ? (\n <>\n <SpinnerIcon className=\"size-5 animate-spin\" />\n <span>\n {isCompletingAuth\n ? tr(\n \"auth.login.settingUpWorkspace\",\n \"Setting up workspace...\",\n )\n : tr(\"auth.login.signingIn\", \"Signing in...\")}\n </span>\n </>\n ) : (\n tr(\"auth.login.signIn\", \"Sign in\")\n )}\n </Button>\n </form>\n\n {/* Divider */}\n <div className=\"relative my-8\">\n <div className=\"absolute inset-0 flex items-center\">\n <div className=\"w-full border-t border-[var(--color-border-default)]\" />\n </div>\n <div className=\"relative flex justify-center\">\n <span className=\"px-4 bg-[var(--color-bg-canvas)] text-sm text-[var(--color-text-tertiary)]\">\n {tr(\"auth.login.orContinueWith\", \"or continue with\")}\n </span>\n </div>\n </div>\n\n {/* OAuth Error */}\n {oauthError && (\n <div className=\"flex items-start gap-3 p-4 rounded-xl border bg-status-error-bg-subtle border-status-error-border\">\n <AlertIcon className=\"size-5 flex-shrink-0 mt-0.5 text-status-error-text\" />\n <p className=\"text-sm text-status-error-text\">{oauthError}</p>\n </div>\n )}\n\n {/* OAuth Buttons */}\n <div className=\"grid grid-cols-3 gap-3\">\n {oauthProviders.map((provider) => (\n <button\n key={provider.name}\n type=\"button\"\n onClick={provider.onClick}\n disabled={provider.disabled}\n title={provider.tooltip}\n aria-label={provider.name}\n className={`flex items-center justify-center gap-2 px-4 py-3 rounded-xl border transition-all duration-200 group ${\n provider.disabled\n ? \"border-[var(--color-border-subtle)] bg-[var(--color-bg-disabled)] cursor-not-allowed opacity-50\"\n : \"border-[var(--color-border-default)] bg-[var(--color-bg-surface)] hover:bg-[var(--color-bg-sunken)] hover:border-[var(--color-border-strong)]\"\n }`}\n >\n <provider.icon\n className={`size-5 ${provider.disabled ? \"opacity-50\" : \"\"}`}\n />\n <span\n className={`sr-only sm:not-sr-only text-sm font-medium transition-colors hidden sm:inline ${\n provider.disabled\n ? \"text-[var(--color-text-disabled)]\"\n : \"text-[var(--color-text-secondary)] group-hover:text-[var(--color-text-primary)]\"\n }`}\n >\n {provider.name}\n </span>\n </button>\n ))}\n </div>\n\n {/* Enterprise SSO Option — temporarily hidden */}\n {/* <div className=\"mt-6\">\n <button type=\"button\"\n onClick={() => navigate(\"/auth/sso/login\")}\n className=\"w-full flex items-center justify-center gap-3 px-4 py-3 rounded-xl border-2 border-dashed border-[var(--color-border-default)] hover:border-action-primary-bg bg-[var(--color-bg-surface)] hover:bg-status-info-bg-subtle transition-all duration-200 group\"\n >\n <svg\n className=\"size-5 text-[var(--color-text-tertiary)] group-hover:text-text-link\"\n fill=\"none\"\n viewBox=\"0 0 24 24\"\n stroke=\"currentColor\"\n >\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth={1.5}\n d=\"M19 21V5a2 2 0 00-2-2H7a2 2 0 00-2 2v16m14 0h2m-2 0h-5m-9 0H3m2 0h5M9 7h1m-1 4h1m4-4h1m-1 4h1m-5 10v-5a1 1 0 011-1h2a1 1 0 011 1v5m-4 0h4\"\n />\n </svg>\n <span className=\"text-sm font-medium text-[var(--color-text-secondary)] group-hover:text-text-link\">\n {tr(\"auth.login.enterpriseSso\", \"Sign in with Enterprise SSO\")}\n </span>\n </button>\n </div> */}\n\n {/* Magic Link Option */}\n <div className=\"mt-4 text-center\">\n <button\n type=\"button\"\n onClick={() => navigate(\"/auth/magic-link\")}\n className=\"text-sm text-[var(--color-text-secondary)] hover:text-[var(--color-text-primary)] transition-colors\"\n >\n {tr(\"auth.login.preferPasswordless\", \"Prefer passwordless login?\")}{\" \"}\n <span className=\"font-semibold text-text-link hover:text-text-linkHover\">\n {tr(\"auth.login.signInMagicLink\", \"Sign in with Magic Link\")}\n </span>\n </button>\n </div>\n\n {/* Sign Up Link */}\n <p className=\"mt-6 text-center text-sm text-[var(--color-text-secondary)]\">\n {tr(\"auth.login.dontHaveAccount\", \"Don't have an account?\")}{\" \"}\n <button\n type=\"button\"\n onClick={() => navigate(\"/auth/register\")}\n className=\"font-semibold text-text-link hover:text-text-linkHover transition-colors\"\n >\n {tr(\"auth.login.signUp\", \"Sign up\")}\n </button>\n </p>\n </AuthLayout>\n );\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"LoginPage.js","names":[],"sources":["../../../src/auth/pages/LoginPage.tsx"],"sourcesContent":["import { useState, useEffect, useCallback, useRef } from \"react\";\nimport { useNavigate, useSearchParams, useLocation } from \"react-router\";\nimport {\n useI18n,\n useActiveContext,\n} from \"@burdenoff/fe-libs/shared/providers/shell\";\nimport {\n getSSORedirectUrl,\n SSORedirectSpinner,\n} from \"@burdenoff/fe-libs/shared/components\";\nimport { resolveAuthBridgeConfig } from \"@burdenoff/fe-libs/shared/config\";\nimport { resolveGatewayUrls } from \"@burdenoff/fe-libs/shared/config/gatewayUrls\";\nimport {\n beginSsoNavigation,\n buildSsoDepositUrl,\n isSsoNavigationPending,\n markSsoDepositPending,\n mintSsoSessionTokens,\n} from \"@burdenoff/fe-libs/shared/utils\";\nimport { Button } from \"@burdenoff/fe-libs/button\";\nimport { PagePurpose } from \"@burdenoff/fe-libs/ui\";\n\nimport {\n getProfileTokens,\n getProfileUser,\n getProfiles,\n getProfileWorkspaceToken,\n resolveActiveProfileId,\n} from \"@burdenoff/fe-libs/shared/providers/shell/ProfileStorageManager\";\nimport { useAuthOperations } from \"../hooks/useAuthOperations\";\nimport { useMyWorkspaces } from \"../hooks/useMyWorkspaces\";\nimport { useOAuthOperations } from \"../hooks/useOAuthOperations\";\nimport { useAuthStore } from \"../store/authStore\";\nimport { useAuth } from \"../providers/AuthProvider\";\nimport { AuthLayout } from \"../components/AuthLayout\";\nimport {\n EmailIcon,\n LockIcon,\n EyeIcon,\n EyeOffIcon,\n AlertIcon,\n SpinnerIcon,\n GoogleIcon,\n // GitHubIcon,\n MicrosoftIcon,\n} from \"../components/AuthIcons\";\nimport { useCaptchaV3 } from \"../hooks/useCaptchaV3\";\nimport { MFA_REDIRECT } from \"../constants/sessionKeys\";\nimport type { SignInInput } from \"../types\";\n\n/**\n * Detect whether the bundle is running inside a native shell (Capacitor on\n * iOS/Android, or Electron). Cross-origin SSO deposit/relay detours only make\n * sense in a multi-origin web context — in a native shell there is one product\n * origin, tokens already live in localStorage, and `window.location.assign` to\n * an external https URL escapes the embedded webview.\n *\n * Detection is runtime-only and avoids importing any platform-specific module\n * so this stays valid when microfe-auth is consumed by a pure web shell too.\n */\nfunction isNativeShell(): boolean {\n if (typeof window === \"undefined\") return false;\n const w = window as typeof window & {\n Capacitor?: { isNativePlatform?: () => boolean };\n };\n if (typeof w.Capacitor?.isNativePlatform === \"function\") {\n try {\n if (w.Capacitor.isNativePlatform()) return true;\n } catch {\n /* fall through */\n }\n }\n if (\n typeof navigator !== \"undefined\" &&\n /Electron/i.test(navigator.userAgent || \"\")\n ) {\n return true;\n }\n return false;\n}\n\nfunction toSameOriginPath(target: string): string {\n if (typeof window === \"undefined\") return target;\n try {\n const url = new URL(target, window.location.origin);\n return `${url.pathname}${url.search}${url.hash}`;\n } catch {\n return target;\n }\n}\n\nfunction hasValidAccessToken(token: string): boolean {\n try {\n const raw = token.split(\".\")[1].replace(/-/g, \"+\").replace(/_/g, \"/\");\n const padded = raw.padEnd(Math.ceil(raw.length / 4) * 4, \"=\");\n const payload = JSON.parse(atob(padded)) as { exp?: unknown };\n return typeof payload.exp === \"number\" && payload.exp > Date.now() / 1000;\n } catch {\n return false;\n }\n}\n\nfunction decodeSameOriginReturnTo(returnTo: string | null): string | null {\n if (!returnTo) return null;\n try {\n const decoded = decodeURIComponent(returnTo);\n const url = new URL(decoded, window.location.origin);\n if (url.origin !== window.location.origin) return null;\n return stripStaleSsoParams(url, { includeOrigin: false });\n } catch {\n return null;\n }\n}\n\nfunction stripStaleSsoParams(\n url: URL,\n options: { includeOrigin: boolean },\n): string {\n for (const param of [\"sso_failed\", \"sso-failed\", \"sso-attempted\"] as const) {\n url.searchParams.delete(param);\n }\n\n if (options.includeOrigin) {\n return url.toString();\n }\n\n const search = url.searchParams.toString();\n return `${url.pathname}${search ? `?${search}` : \"\"}${url.hash}`;\n}\n\nfunction cleanReturnToValue(returnTo: string): string {\n try {\n const decoded = decodeURIComponent(returnTo);\n const url = new URL(decoded, window.location.origin);\n // Preserve cross-origin absolute returnTo values (e.g., redirects back to\n // another product's app shell) — only strip stale SSO params.\n const isCrossOrigin = url.origin !== window.location.origin;\n return stripStaleSsoParams(url, { includeOrigin: isCrossOrigin });\n } catch {\n return returnTo;\n }\n}\n\n/**\n * Login page with professional design\n * Provides email/password login and social OAuth options\n */\nexport function LoginPage() {\n const navigate = useNavigate();\n const location = useLocation();\n const [searchParams] = useSearchParams();\n const { t } = useI18n();\n const tr = useCallback(\n (key: string, fallback: string): string => {\n const translated = t(key);\n return translated === key ? fallback : translated;\n },\n [t],\n );\n const { signIn, isLoading, error, errorCode, resendVerification } =\n useAuthOperations();\n const { completeAuthFlow } = useMyWorkspaces();\n const { setWorkspace, setOrganization } = useActiveContext();\n const { defaultPostLoginPath } = useAuth();\n const { initiateGoogleOAuth, initiateMicrosoftOAuth, isProviderConfigured } =\n useOAuthOperations();\n const mfaRequired = useAuthStore((state) => state.mfaRequired);\n const { executeRecaptcha: executeCaptchaV3 } = useCaptchaV3();\n const [isCompletingAuth, setIsCompletingAuth] = useState(false);\n const [isSsoRedirecting, setIsSsoRedirecting] = useState(false);\n\n /**\n * Build the URL that should receive the post-login redirect.\n *\n * For cross-eTLD+1 SSO on alpha/prod we detour through the central bridge\n * host (alphaapp/app.burdenoff.com) so the freshly-issued tokens land in\n * the bridge origin's first-party (unpartitioned) localStorage. Without\n * this step, a later direct visit to the bridge host has no local tokens\n * and no shared cookie (cross-eTLD+1 cookies don't propagate), so the user\n * sees the login page again.\n *\n * Skipped when:\n * - Already on the bridge host origin (would be a no-op self-redirect).\n * - The user's intended destination is itself on the bridge host\n * (likely an in-product navigation, no deposit needed).\n * - The freshly-stored profile snapshot can't be read (best-effort only —\n * login still succeeds via the direct redirect).\n */\n const buildPostLoginUrl = useCallback(\n async (intendedPath: string): Promise<string> => {\n if (typeof window === \"undefined\") return intendedPath;\n // Native shells (Electron, Capacitor iOS/Android) run as a single origin —\n // skip the cross-eTLD+1 deposit detour, which would otherwise navigate to\n // an external https URL and escape the embedded webview.\n if (isNativeShell()) return intendedPath;\n try {\n const bridge = resolveAuthBridgeConfig();\n const bridgeUrl = new URL(bridge.url);\n const currentOrigin = window.location.origin;\n if (bridgeUrl.origin === currentOrigin) return intendedPath;\n\n // intendedPath can be a path or an absolute URL; resolve to absolute\n // against current origin so the bridge host knows where to send the\n // user back.\n const absoluteIntended = new URL(intendedPath, currentOrigin).href;\n\n const profileId = resolveActiveProfileId();\n if (!profileId) return intendedPath;\n const tokens = getProfileTokens(profileId);\n const user = getProfileUser(profileId);\n if (!tokens || !user) return intendedPath;\n const workspaceToken = getProfileWorkspaceToken(profileId);\n\n // BOFF-4463: mint a DEDICATED refresh-token lineage for the bridge\n // host. Copying this origin's pair verbatim meant the bridge (and\n // every product it later relayed to) shared ONE rotating refresh\n // token — the first origin to refresh revoked it for all others,\n // surfacing as \"products log me out after minutes/hours\". Falls back\n // to the legacy copy if the mutation is unreachable (rollout gap /\n // transient failure) so SSO keeps working.\n let depositTokens: Record<string, unknown> = {\n ...tokens,\n workspaceToken,\n };\n if (tokens.refreshToken) {\n const { globalBaseUrl } = resolveGatewayUrls();\n const { tokens: minted } = await mintSsoSessionTokens(\n `${globalBaseUrl}/global/graphql`,\n tokens.refreshToken,\n );\n if (minted) {\n depositTokens = { ...minted, workspaceToken };\n }\n }\n\n markSsoDepositPending(profileId);\n return buildSsoDepositUrl(bridgeUrl.origin, absoluteIntended, {\n profileId,\n tokens: JSON.stringify(depositTokens),\n user: JSON.stringify(user),\n profiles: JSON.stringify(getProfiles()),\n });\n } catch {\n return intendedPath;\n }\n },\n [],\n );\n\n // Once a cross-document post-login redirect is initiated, the login page\n // must FREEZE: resetting isCompletingAuth re-runs the auto-redirect effect\n // and any state churn schedules same-document navigations that cancel the\n // provisional deposit hop (BOFF-4463).\n const redirectInitiatedRef = useRef(false);\n\n const redirectAfterLogin = useCallback(\n (path: string) => {\n if (typeof window === \"undefined\") {\n navigate(path);\n return;\n }\n try {\n sessionStorage.setItem(\"bf-post-login-return-to\", path);\n } catch {\n // Ignore storage failures; redirect still proceeds.\n }\n // In native shells use SPA navigation so the embedded webview stays in\n // the app — no full reload, no chance of the OS opening the URL\n // externally. Tokens are already in this origin's localStorage.\n if (isNativeShell()) {\n navigate(toSameOriginPath(path));\n return;\n }\n redirectInitiatedRef.current = true;\n void (async () => {\n const target = await buildPostLoginUrl(path);\n if (target.includes(\"/auth/sso-deposit\")) {\n // Cross-document deposit hop: suppress same-document navigators\n // while it is provisional, and retry once if it still gets\n // cancelled — on a committed navigation this document unloads and\n // the timer never fires.\n beginSsoNavigation();\n window.location.assign(target);\n window.setTimeout(() => {\n beginSsoNavigation();\n window.location.replace(target);\n }, 2500);\n } else {\n window.location.assign(target);\n }\n })();\n },\n [navigate, buildPostLoginUrl],\n );\n const [showPassword, setShowPassword] = useState(false);\n const [isAccountInactive, setIsAccountInactive] = useState(false);\n const [isAccountDeleted, setIsAccountDeleted] = useState(false);\n const [isAccountSuspended, setIsAccountSuspended] = useState(false);\n const [isOAuthOnlyAccount, setIsOAuthOnlyAccount] = useState(false);\n const [isEmailNotVerified, setIsEmailNotVerified] = useState(false);\n const [isResendingVerification, setIsResendingVerification] = useState(false);\n const [resendSuccess, setResendSuccess] = useState(false);\n const [oauthError, setOauthError] = useState<string | null>(null);\n const [infoMessage, setInfoMessage] = useState<string | null>(null);\n const [formData, setFormData] = useState<\n SignInInput & { rememberMe?: boolean }\n >({\n email: \"\",\n password: \"\",\n rememberMe: false,\n });\n const [validationError, setValidationError] = useState<string | null>(null);\n const [isDuplicateAccount, setIsDuplicateAccount] = useState(false);\n\n // Detect add-account mode and returnTo from URL params\n const isAddAccountMode = searchParams.get(\"mode\") === \"add-account\";\n const returnTo = searchParams.get(\"returnTo\");\n const initialReturnToRef = useRef<string | null>(returnTo);\n\n // Tell the user WHY they are back on the login page. `session-expired` is\n // set by the shell's forced logout (expired session whose refresh failed);\n // `logout` covers explicit sign-outs and the SSO-clear fallback (which can\n // rewrite a session-expired redirect's reason on the cross-product bounce).\n // Without this the auto-logout looked like a silent, unexplained kick-out.\n const reasonParam = searchParams.get(\"reason\");\n useEffect(() => {\n if (reasonParam === \"session-expired\") {\n setInfoMessage(\n tr(\n \"auth.login.sessionExpired\",\n \"Your session has expired. Please sign in again.\",\n ),\n );\n } else if (reasonParam === \"logout\") {\n setInfoMessage(tr(\"auth.login.signedOut\", \"You have been signed out.\"));\n }\n }, [reasonParam, tr]);\n\n useEffect(() => {\n if (!initialReturnToRef.current && returnTo) {\n initialReturnToRef.current = returnTo;\n }\n }, [returnTo]);\n\n useEffect(() => {\n if (isAddAccountMode || isCompletingAuth) return;\n // A cross-document SSO navigation (deposit/relay hop) is already in\n // flight — issuing another redirect here would cancel it (BOFF-4463).\n if (redirectInitiatedRef.current || isSsoNavigationPending()) return;\n\n const profileId = resolveActiveProfileId();\n if (profileId) {\n const tokens = getProfileTokens(profileId);\n const user = getProfileUser(profileId);\n if (\n tokens?.accessToken &&\n user &&\n hasValidAccessToken(tokens.accessToken)\n ) {\n useAuthStore.getState().loadFromProfile(profileId);\n redirectAfterLogin(decodeSameOriginReturnTo(returnTo) ?? \"/\");\n return;\n }\n }\n\n const ssoUrl = getSSORedirectUrl();\n if (ssoUrl) {\n setIsSsoRedirecting(true);\n window.location.replace(ssoUrl);\n }\n }, [isAddAccountMode, isCompletingAuth, redirectAfterLogin, returnTo]);\n\n // Load remembered email on mount and clean up any legacy plaintext password storage\n useEffect(() => {\n try {\n // Security cleanup: remove any previously stored plaintext passwords\n localStorage.removeItem(\"remembered_password\");\n\n const rememberedEmail = localStorage.getItem(\"remembered_email\");\n\n if (rememberedEmail) {\n setFormData((prev) => ({\n ...prev,\n email: rememberedEmail,\n rememberMe: true,\n }));\n }\n } catch (error) {\n console.warn(\"[LoginPage] Failed to load remembered email:\", error);\n }\n }, []);\n\n // Check for redirect message and email from location state (e.g., from expired MFA or SSO redirect)\n useEffect(() => {\n const state = location.state as { message?: string; email?: string } | null;\n if (state?.message) {\n setInfoMessage(state.message);\n }\n if (state?.email) {\n setFormData((prev) => ({ ...prev, email: state.email }));\n }\n // Clear state to prevent showing message on refresh\n if (state) {\n window.history.replaceState({}, document.title);\n }\n }, [location.state]);\n\n // Determine error type from GraphQL error code (primary) or message (fallback).\n // The backend sends structured codes in extensions.code which are propagated\n // through useAuthOperations → authStore.errorCode.\n const checkErrorType = (\n err: string | null,\n code?: string | null,\n ):\n | \"DELETED\"\n | \"SUSPENDED\"\n | \"OAUTH_ONLY\"\n | \"INACTIVE\"\n | \"EMAIL_NOT_VERIFIED\"\n | null => {\n // Primary: match on GraphQL error code from extensions\n if (code) {\n switch (code) {\n case \"ACCOUNT_DELETED\":\n return \"DELETED\";\n case \"ACCOUNT_SUSPENDED\":\n return \"SUSPENDED\";\n case \"OAUTH_ONLY_ACCOUNT\":\n return \"OAUTH_ONLY\";\n case \"ACCOUNT_INACTIVE\":\n return \"INACTIVE\";\n case \"EMAIL_NOT_VERIFIED\":\n return \"EMAIL_NOT_VERIFIED\";\n default:\n break;\n }\n }\n\n // Fallback: match on error message for non-GraphQL errors or legacy responses\n if (!err) return null;\n const lowerErr = err.toLowerCase();\n\n if (\n lowerErr.includes(\"deleted\") ||\n lowerErr.includes(\"permanently deleted\")\n ) {\n return \"DELETED\";\n }\n if (lowerErr.includes(\"suspended\")) {\n return \"SUSPENDED\";\n }\n if (\n lowerErr.includes(\"oauth provider\") ||\n lowerErr.includes(\"oauth-only\") ||\n lowerErr.includes(\"oauth only\")\n ) {\n return \"OAUTH_ONLY\";\n }\n if (\n lowerErr.includes(\"inactive\") ||\n lowerErr.includes(\"deactivated\") ||\n lowerErr.includes(\"not active\")\n ) {\n return \"INACTIVE\";\n }\n if (\n lowerErr.includes(\"verify your email\") ||\n lowerErr.includes(\"email not verified\") ||\n lowerErr.includes(\"email_not_verified\")\n ) {\n return \"EMAIL_NOT_VERIFIED\";\n }\n return null;\n };\n\n // Pre-fill email from URL query parameter (e.g., after email verification)\n useEffect(() => {\n const emailFromUrl = searchParams.get(\"email\");\n if (emailFromUrl) {\n setFormData((prev) => ({ ...prev, email: emailFromUrl }));\n }\n\n // Check for expired session redirect\n const isExpired = searchParams.get(\"expired\");\n if (isExpired === \"true\") {\n setInfoMessage(\n tr(\n \"auth.login.sessionExpired\",\n \"Your session has expired. Please sign in again.\",\n ),\n );\n // Clear the query param to prevent showing on refresh\n const newUrl = window.location.pathname;\n window.history.replaceState({}, document.title, newUrl);\n }\n }, [searchParams, tr]);\n\n // Redirect to MFA verification when required\n useEffect(() => {\n if (mfaRequired) {\n navigate(\"/auth/mfa-verify\");\n }\n }, [mfaRequired, navigate]);\n\n const handleSubmit = async (e: React.FormEvent) => {\n e.preventDefault();\n setIsAccountInactive(false);\n setIsAccountDeleted(false);\n setIsAccountSuspended(false);\n setIsOAuthOnlyAccount(false);\n setIsEmailNotVerified(false);\n setIsDuplicateAccount(false);\n setResendSuccess(false);\n setValidationError(null);\n\n // Client-side validation\n const emailTrimmed = (formData.email ?? \"\").trim();\n if (!emailTrimmed) {\n setValidationError(\n tr(\n \"auth.login.enterEmailOrUsername\",\n \"Please enter your email or username\",\n ),\n );\n return;\n }\n\n // Basic email format validation (if it contains @)\n if (emailTrimmed.includes(\"@\")) {\n const emailRegex = /^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$/;\n if (!emailRegex.test(emailTrimmed)) {\n setValidationError(\n tr(\"auth.login.invalidEmail\", \"Please enter a valid email address\"),\n );\n return;\n }\n }\n\n if (!formData.password || formData.password.length < 1) {\n setValidationError(\n tr(\"auth.login.enterPassword\", \"Please enter your password\"),\n );\n return;\n }\n\n // In add-account mode, check if this email is already signed in\n if (isAddAccountMode) {\n const existingProfiles = getProfiles();\n const alreadySignedIn = existingProfiles.some(\n (p) => p.email.toLowerCase() === emailTrimmed.toLowerCase(),\n );\n if (alreadySignedIn) {\n setIsDuplicateAccount(true);\n setValidationError(null);\n return;\n }\n }\n setIsDuplicateAccount(false);\n\n try {\n // Get reCAPTCHA v3 token (no-op when captcha is disabled)\n const recaptchaToken = await executeCaptchaV3(\"login\");\n\n const result = await signIn({\n email: emailTrimmed,\n password: formData.password,\n rememberMe: formData.rememberMe,\n ...(recaptchaToken ? { recaptchaToken } : {}),\n });\n\n // If MFA is required, the useEffect above will handle redirect\n if (result.requiresMFA) {\n // Persist the post-login destination so MfaVerifyPage honors\n // `returnTo` and `defaultPostLoginPath` after the user completes\n // verification — otherwise the MFA path falls back to \"/\" and the\n // host-configured home (e.g. \"/vibecontrols\") is lost.\n const effectiveReturnTo = initialReturnToRef.current || returnTo;\n const postMfaPath = effectiveReturnTo\n ? cleanReturnToValue(effectiveReturnTo)\n : cleanReturnToValue(defaultPostLoginPath ?? \"/dashboard\");\n try {\n sessionStorage.setItem(MFA_REDIRECT, postMfaPath);\n } catch {\n // sessionStorage may be unavailable (private mode, quota) — the\n // MFA page still works, it just defaults to \"/\" on completion.\n }\n return;\n }\n\n // Successful login - complete auth flow (fetch workspaces + issue token)\n if (result.success) {\n try {\n const profileId = result.user?.id;\n if (profileId) {\n const hostname = window.location.hostname;\n const domain = hostname.endsWith(\".local.burdenoff.com\")\n ? \".local.burdenoff.com\"\n : undefined;\n const domainPart = domain ? `; domain=${domain}` : \"\";\n const securePart =\n window.location.protocol === \"https:\" ? \"; secure\" : \"\";\n const ssoValue = JSON.stringify({\n id: profileId,\n origin: window.location.origin,\n });\n document.cookie = `bf-sso=${encodeURIComponent(ssoValue)}${domainPart}; path=/; samesite=lax${securePart}; max-age=86400`;\n document.cookie = `bf-sso-profile=${encodeURIComponent(ssoValue)}${domainPart}; path=/; samesite=lax${securePart}; max-age=86400`;\n }\n } catch {\n // Best effort only. Login can continue without the fast-path cookie.\n }\n\n // Handle Remember Me: Save or clear email only (never store passwords)\n try {\n if (formData.rememberMe) {\n localStorage.setItem(\"remembered_email\", emailTrimmed);\n } else {\n localStorage.removeItem(\"remembered_email\");\n }\n } catch (error) {\n console.warn(\n \"[LoginPage] Failed to save/clear remembered email:\",\n error,\n );\n }\n\n setIsCompletingAuth(true);\n // In add-account mode, redirect back to where the user was\n const effectiveReturnTo = initialReturnToRef.current || returnTo;\n const postLoginPath = effectiveReturnTo\n ? cleanReturnToValue(effectiveReturnTo)\n : cleanReturnToValue(defaultPostLoginPath ?? \"/dashboard\");\n try {\n type AuthFlowResult = Awaited<ReturnType<typeof completeAuthFlow>>;\n // Pass the token directly to avoid race condition with React state updates\n const authFlowResult = await Promise.race<AuthFlowResult>([\n completeAuthFlow(result.token),\n new Promise<AuthFlowResult>((resolve) => {\n window.setTimeout(() => {\n resolve({\n success: false,\n error: \"Auth flow timed out after login\",\n });\n }, 5000);\n }),\n ]);\n\n if (authFlowResult.success) {\n // Sync workspace and organization to ActiveContext\n // This is critical for global search and other workspace-scoped features\n if (authFlowResult.workspace) {\n setWorkspace(authFlowResult.workspace.id);\n if (authFlowResult.workspace.organizationId) {\n setOrganization(authFlowResult.workspace.organizationId);\n }\n }\n\n // Full auth flow completed - redirect to dashboard or returnTo\n redirectAfterLogin(postLoginPath);\n } else if (authFlowResult.error?.includes(\"No workspaces found\")) {\n // No workspaces - redirect to onboarding/workspace creation\n navigate(\"/onboarding/create-workspace\");\n } else {\n // Partial success or error - still sync workspace if available and redirect\n if (authFlowResult.workspace) {\n setWorkspace(authFlowResult.workspace.id);\n if (authFlowResult.workspace.organizationId) {\n setOrganization(authFlowResult.workspace.organizationId);\n }\n }\n console.warn(\"Auth flow warning:\", authFlowResult.error);\n redirectAfterLogin(postLoginPath);\n }\n } catch (authFlowError) {\n // Auth flow failed but login succeeded - still redirect\n console.error(\"Auth flow error (login succeeded):\", authFlowError);\n redirectAfterLogin(postLoginPath);\n } finally {\n // Keep the completing state (spinner) once a redirect is in\n // flight: resetting it re-arms the auto-redirect effect whose\n // competing navigation cancels the deposit hop (BOFF-4463). The\n // page is about to unload anyway.\n if (!redirectInitiatedRef.current) {\n setIsCompletingAuth(false);\n }\n }\n }\n } catch (err) {\n if (import.meta.env.DEV) {\n console.error(\"Sign in failed:\", err);\n }\n // Check error type using error code (from store) and message\n const errorMsg = err instanceof Error ? err.message : String(err);\n if (errorMsg.includes(\"reCAPTCHA\")) {\n setValidationError(errorMsg);\n }\n const storeErrorCode = useAuthStore.getState().errorCode;\n const errorType = checkErrorType(errorMsg, storeErrorCode);\n if (errorType === \"DELETED\") {\n setIsAccountDeleted(true);\n } else if (errorType === \"SUSPENDED\") {\n setIsAccountSuspended(true);\n } else if (errorType === \"OAUTH_ONLY\") {\n setIsOAuthOnlyAccount(true);\n } else if (errorType === \"INACTIVE\") {\n setIsAccountInactive(true);\n } else if (errorType === \"EMAIL_NOT_VERIFIED\") {\n setIsEmailNotVerified(true);\n }\n }\n };\n\n // Also check the error from useAuthOperations\n useEffect(() => {\n if (error) {\n const errorType = checkErrorType(error, errorCode);\n if (errorType === \"DELETED\") {\n setIsAccountDeleted(true);\n } else if (errorType === \"SUSPENDED\") {\n setIsAccountSuspended(true);\n } else if (errorType === \"OAUTH_ONLY\") {\n setIsOAuthOnlyAccount(true);\n } else if (errorType === \"INACTIVE\") {\n setIsAccountInactive(true);\n } else if (errorType === \"EMAIL_NOT_VERIFIED\") {\n setIsEmailNotVerified(true);\n }\n }\n }, [error, errorCode]);\n\n /**\n * Handle Google OAuth login\n */\n const handleGoogleLogin = () => {\n setOauthError(null);\n try {\n initiateGoogleOAuth();\n } catch (err) {\n setOauthError(\n err instanceof Error\n ? err.message\n : tr(\n \"auth.login.googleSignInFailed\",\n \"Failed to initiate Google sign in\",\n ),\n );\n }\n };\n\n /**\n * Handle Microsoft OAuth login\n */\n const handleMicrosoftLogin = () => {\n setOauthError(null);\n try {\n initiateMicrosoftOAuth();\n } catch (err) {\n setOauthError(\n err instanceof Error\n ? err.message\n : tr(\n \"auth.login.microsoftSignInFailed\",\n \"Failed to initiate Microsoft sign in\",\n ),\n );\n }\n };\n\n /**\n * Handle resend verification email\n */\n const handleResendVerification = async () => {\n setIsResendingVerification(true);\n setResendSuccess(false);\n try {\n const emailTrimmed = (formData.email ?? \"\").trim();\n const result = await resendVerification(emailTrimmed);\n if (result.success) {\n setResendSuccess(true);\n } else {\n setValidationError(\n tr(\n \"auth.login.resendFailed\",\n \"Failed to resend verification email. Please try again.\",\n ),\n );\n }\n } catch (err) {\n console.error(\"Failed to resend verification email:\", err);\n setValidationError(\n err instanceof Error\n ? err.message\n : tr(\n \"auth.login.resendFailed\",\n \"Failed to resend verification email. Please try again.\",\n ),\n );\n } finally {\n setIsResendingVerification(false);\n }\n };\n\n // Check if OAuth providers are configured\n const isGoogleConfigured = isProviderConfigured(\"google\");\n const isMicrosoftConfigured = isProviderConfigured(\"microsoft\");\n\n const oauthProviders = [\n {\n name: \"Google\",\n icon: GoogleIcon,\n onClick: handleGoogleLogin,\n disabled: !isGoogleConfigured,\n tooltip: isGoogleConfigured\n ? undefined\n : tr(\n \"auth.login.googleNotConfigured\",\n \"Google sign in is not configured\",\n ),\n },\n // {\n // name: \"GitHub\",\n // icon: GitHubIcon,\n // onClick: () => {},\n // disabled: true,\n // tooltip: tr(\n // \"auth.login.githubNotConfigured\",\n // \"GitHub sign in is not configured\",\n // ),\n // },\n {\n name: \"Microsoft\",\n icon: MicrosoftIcon,\n onClick: handleMicrosoftLogin,\n disabled: !isMicrosoftConfigured,\n tooltip: isMicrosoftConfigured\n ? undefined\n : tr(\n \"auth.login.microsoftNotConfigured\",\n \"Microsoft sign in is not configured\",\n ),\n },\n ];\n\n if (isSsoRedirecting) {\n return <SSORedirectSpinner />;\n }\n\n return (\n <AuthLayout\n title={tr(\"auth.login.welcomeBack\", \"Welcome back\")}\n subtitle={tr(\n \"auth.login.enterCredentials\",\n \"Enter your credentials to continue\",\n )}\n >\n <PagePurpose className=\"mb-5\">\n {tr(\n \"auth.login.purpose\",\n \"Sign in to reach your workspaces, agents, and settings. Use your email and password, a social provider, or a passwordless magic link.\",\n )}\n </PagePurpose>\n <form onSubmit={handleSubmit} className=\"space-y-5\">\n {/* Info Message (e.g., from expired MFA redirect) */}\n {infoMessage && (\n <div className=\"flex items-start gap-3 p-4 rounded-xl border bg-status-info-bg-subtle border-status-info-border\">\n <svg\n className=\"size-5 flex-shrink-0 mt-0.5 text-text-link\"\n fill=\"none\"\n viewBox=\"0 0 24 24\"\n stroke=\"currentColor\"\n >\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth={2}\n d=\"M13 16h-1v-4h-1m1-4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z\"\n />\n </svg>\n <p className=\"text-sm text-status-info-text\">{infoMessage}</p>\n </div>\n )}\n\n {/* Validation Error */}\n {validationError && (\n <div className=\"flex items-start gap-3 p-4 rounded-xl border bg-status-warning-bg-subtle border-status-warning-border\">\n <AlertIcon className=\"size-5 flex-shrink-0 mt-0.5 text-status-warning-text\" />\n <p className=\"text-sm text-status-warning-text\">\n {validationError}\n </p>\n </div>\n )}\n\n {/* Duplicate Account Warning (Add Account mode) */}\n {isDuplicateAccount && (\n <div className=\"flex items-start gap-3 p-4 rounded-xl border bg-status-warning-bg-subtle border-status-warning-border\">\n <AlertIcon className=\"size-5 flex-shrink-0 mt-0.5 text-status-warning-text\" />\n <div className=\"flex-1\">\n <p className=\"text-sm font-medium text-status-warning-text\">\n {tr(\n \"auth.login.duplicateAccount\",\n \"This account is already signed in.\",\n )}\n </p>\n <p className=\"mt-1 text-sm text-status-warning-text/80\">\n {tr(\n \"auth.login.duplicateAccountHint\",\n \"Please use a different account, or go back and switch to this account from the profile menu.\",\n )}\n </p>\n {(initialReturnToRef.current || returnTo) && (\n <button\n type=\"button\"\n onClick={() =>\n navigate(\n decodeURIComponent(\n initialReturnToRef.current || returnTo || \"/dashboard\",\n ),\n )\n }\n className=\"mt-3 inline-flex items-center gap-2 px-4 py-2.5 rounded-xl border border-status-warning-border bg-bg-surface text-status-warning-text text-sm font-medium hover:bg-status-warning-bg-subtle hover:border-status-warning-border transition-all shadow-sm\"\n >\n <svg\n className=\"size-4\"\n fill=\"none\"\n viewBox=\"0 0 24 24\"\n stroke=\"currentColor\"\n >\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth={2}\n d=\"M10 19l-7-7m0 0l7-7m-7 7h18\"\n />\n </svg>\n {tr(\n \"auth.login.goBackSwitchAccount\",\n \"Go back and switch account\",\n )}\n </button>\n )}\n </div>\n </div>\n )}\n\n {/* Error Alert */}\n {error && !validationError && !isDuplicateAccount && (\n <div\n className={`flex items-start gap-3 p-4 rounded-xl border ${\n isAccountInactive || isOAuthOnlyAccount || isEmailNotVerified\n ? \"bg-status-warning-bg-subtle border-status-warning-border\"\n : \"bg-status-error-bg-subtle border-status-error-border\"\n }`}\n >\n <AlertIcon\n className={`size-5 flex-shrink-0 mt-0.5 ${\n isAccountInactive || isOAuthOnlyAccount || isEmailNotVerified\n ? \"text-status-warning-text\"\n : \"text-status-error-text\"\n }`}\n />\n <div className=\"flex-1\">\n <p\n className={`text-sm ${\n isAccountInactive || isOAuthOnlyAccount || isEmailNotVerified\n ? \"text-status-warning-text\"\n : \"text-status-error-text\"\n }`}\n >\n {isAccountDeleted\n ? tr(\n \"auth.login.accountDeleted\",\n \"This account has been permanently deleted and cannot be recovered.\",\n )\n : isAccountSuspended\n ? tr(\n \"auth.login.accountSuspended\",\n \"Your account has been suspended. Please contact support for assistance.\",\n )\n : isAccountInactive\n ? tr(\n \"auth.login.accountDeactivated\",\n \"Your account has been deactivated.\",\n )\n : isOAuthOnlyAccount\n ? tr(\n \"auth.login.oauthOnly\",\n \"This account uses OAuth sign-in. Please use Google or Microsoft to sign in.\",\n )\n : isEmailNotVerified\n ? tr(\n \"auth.login.emailNotVerified\",\n \"Please verify your email before signing in. Check your inbox for the verification link.\",\n )\n : error}\n </p>\n {isAccountInactive && (\n <button\n type=\"button\"\n onClick={() =>\n navigate(\"/auth/reactivate\", {\n state: { email: formData.email },\n })\n }\n className=\"mt-2 text-sm font-semibold text-status-warning-text hover:text-status-warning-text underline underline-offset-2\"\n >\n {tr(\n \"auth.login.clickReactivate\",\n \"Click here to reactivate your account\",\n )}\n </button>\n )}\n {isEmailNotVerified && (\n <div className=\"mt-3\">\n {resendSuccess ? (\n <div className=\"flex items-center gap-2 text-sm text-status-success-text\">\n <svg\n className=\"size-4\"\n fill=\"none\"\n viewBox=\"0 0 24 24\"\n stroke=\"currentColor\"\n >\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth={2}\n d=\"M5 13l4 4L19 7\"\n />\n </svg>\n {tr(\n \"auth.login.verificationSent\",\n \"Verification email sent! Please check your inbox.\",\n )}\n </div>\n ) : (\n <button\n type=\"button\"\n onClick={handleResendVerification}\n disabled={isResendingVerification}\n className=\"inline-flex items-center gap-2 px-4 py-2.5 rounded-xl border border-status-warning-border bg-bg-surface text-status-warning-text text-sm font-medium hover:bg-status-warning-bg-subtle hover:border-status-warning-border transition-all shadow-sm disabled:opacity-50 disabled:cursor-not-allowed\"\n >\n {isResendingVerification ? (\n <>\n <SpinnerIcon className=\"size-4 animate-spin\" />\n {tr(\"auth.login.sending\", \"Sending...\")}\n </>\n ) : (\n <>\n <svg\n className=\"size-4\"\n fill=\"none\"\n viewBox=\"0 0 24 24\"\n stroke=\"currentColor\"\n >\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth={2}\n d=\"M3 8l7.89 5.26a2 2 0 002.22 0L21 8M5 19h14a2 2 0 002-2V7a2 2 0 00-2-2H5a2 2 0 00-2 2v10a2 2 0 002 2z\"\n />\n </svg>\n {tr(\n \"auth.login.resendVerification\",\n \"Resend verification email\",\n )}\n </>\n )}\n </button>\n )}\n </div>\n )}\n {isOAuthOnlyAccount && (\n <div className=\"mt-3 flex flex-col gap-2\">\n {isProviderConfigured(\"google\") && (\n <button\n type=\"button\"\n onClick={handleGoogleLogin}\n className=\"inline-flex items-center justify-center gap-2 px-4 py-2.5 rounded-xl border border-border-default bg-bg-surface text-text-primary text-sm font-medium hover:bg-bg-canvas hover:border-border-default transition-all shadow-sm\"\n >\n <GoogleIcon className=\"size-5\" />\n {tr(\"auth.login.signInWithGoogle\", \"Sign in with Google\")}\n </button>\n )}\n {isProviderConfigured(\"microsoft\") && (\n <button\n type=\"button\"\n onClick={handleMicrosoftLogin}\n className=\"inline-flex items-center justify-center gap-2 px-4 py-2.5 rounded-xl border border-border-default bg-bg-surface text-text-primary text-sm font-medium hover:bg-bg-canvas hover:border-border-default transition-all shadow-sm\"\n >\n <MicrosoftIcon className=\"size-5\" />\n {tr(\n \"auth.login.signInWithMicrosoft\",\n \"Sign in with Microsoft\",\n )}\n </button>\n )}\n </div>\n )}\n </div>\n </div>\n )}\n\n {/* Email Input */}\n <div className=\"space-y-2\">\n <label\n htmlFor=\"email\"\n className=\"block text-sm font-medium text-[var(--color-text-primary)]\"\n >\n {tr(\"auth.login.emailLabel\", \"Email\")}\n </label>\n <div className=\"relative\">\n <div className=\"absolute inset-y-0 left-0 pl-3.5 flex items-center pointer-events-none\">\n <EmailIcon className=\"size-5 text-[var(--color-text-tertiary)]\" />\n </div>\n <input\n id=\"email\"\n type=\"email\"\n autoComplete=\"email\"\n required\n aria-required=\"true\"\n aria-label={tr(\"auth.login.emailLabel\", \"Email\")}\n value={formData.email}\n onChange={(e) =>\n setFormData({ ...formData, email: e.target.value })\n }\n className=\"block w-full pl-[3.5rem] pr-4 py-3 rounded-xl border border-[var(--color-border-default)] bg-[var(--color-bg-surface)] text-[var(--color-text-primary)] placeholder:text-[var(--color-text-tertiary)] focus:outline-none focus:ring-2 focus:ring-action-primary-bg/20 focus:border-action-primary-bg transition-all\"\n placeholder={tr(\"auth.login.emailPlaceholder\", \"you@example.com\")}\n />\n </div>\n </div>\n\n {/* Password Input */}\n <div className=\"space-y-2\">\n <label\n htmlFor=\"password\"\n className=\"block text-sm font-medium text-[var(--color-text-primary)]\"\n >\n {tr(\"auth.login.passwordLabel\", \"Password\")}\n </label>\n <div className=\"relative\">\n <div className=\"absolute inset-y-0 left-0 pl-3.5 flex items-center pointer-events-none\">\n <LockIcon className=\"size-5 text-[var(--color-text-tertiary)]\" />\n </div>\n <input\n id=\"password\"\n type={showPassword ? \"text\" : \"password\"}\n autoComplete=\"current-password\"\n required\n aria-required=\"true\"\n aria-label={tr(\"auth.login.passwordLabel\", \"Password\")}\n value={formData.password}\n onChange={(e) =>\n setFormData({ ...formData, password: e.target.value })\n }\n className=\"block w-full pl-[3.5rem] pr-12 py-3 rounded-xl border border-[var(--color-border-default)] bg-[var(--color-bg-surface)] text-[var(--color-text-primary)] placeholder:text-[var(--color-text-tertiary)] focus:outline-none focus:ring-2 focus:ring-action-primary-bg/20 focus:border-action-primary-bg transition-all\"\n placeholder={tr(\n \"auth.login.passwordPlaceholder\",\n \"Enter your password\",\n )}\n />\n <button\n type=\"button\"\n onClick={() => setShowPassword(!showPassword)}\n aria-label={showPassword ? \"Hide password\" : \"Show password\"}\n className=\"absolute inset-y-0 right-0 pr-3.5 flex items-center text-[var(--color-text-tertiary)] hover:text-[var(--color-text-secondary)] transition-colors\"\n >\n {showPassword ? (\n <EyeOffIcon className=\"size-5\" />\n ) : (\n <EyeIcon className=\"size-5\" />\n )}\n </button>\n </div>\n </div>\n\n {/* Remember & Forgot */}\n <div className=\"flex items-center justify-between\">\n <label className=\"flex items-center gap-2 cursor-pointer group\">\n <div className=\"relative\">\n <input\n type=\"checkbox\"\n aria-label={tr(\"auth.login.rememberMe\", \"Remember me\")}\n checked={formData.rememberMe}\n onChange={(e) => {\n const isChecked = e.target.checked;\n setFormData({ ...formData, rememberMe: isChecked });\n\n // Clear saved email immediately when unchecked\n if (!isChecked) {\n try {\n localStorage.removeItem(\"remembered_email\");\n } catch (error) {\n console.warn(\n \"[LoginPage] Failed to clear remembered email:\",\n error,\n );\n }\n }\n }}\n className=\"sr-only peer\"\n />\n <div className=\"size-5 rounded-md border-2 border-[var(--color-border-default)] bg-[var(--color-bg-surface)] peer-checked:bg-status-info-bg-subtle0 peer-checked:border-action-primary-bg transition-all peer-focus:ring-2 peer-focus:ring-action-primary-bg/20\">\n <svg\n className=\"size-full text-white opacity-0 peer-checked:opacity-100 transition-opacity p-0.5\"\n fill=\"none\"\n viewBox=\"0 0 24 24\"\n stroke=\"currentColor\"\n strokeWidth={3}\n >\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n d=\"M5 13l4 4L19 7\"\n />\n </svg>\n </div>\n </div>\n <span className=\"text-sm text-[var(--color-text-secondary)] group-hover:text-[var(--color-text-primary)] transition-colors\">\n {tr(\"auth.login.rememberMe\", \"Remember me\")}\n </span>\n </label>\n <button\n type=\"button\"\n onClick={() => navigate(\"/auth/reset-password\")}\n className=\"text-sm font-medium text-text-link hover:text-text-linkHover transition-colors\"\n >\n {tr(\"auth.login.forgotPassword\", \"Forgot password?\")}\n </button>\n </div>\n\n {/* Submit Button */}\n <Button\n type=\"submit\"\n disabled={isLoading || isCompletingAuth}\n variant=\"default\"\n size=\"lg\"\n className=\"w-full font-semibold\"\n >\n {isLoading || isCompletingAuth ? (\n <>\n <SpinnerIcon className=\"size-5 animate-spin\" />\n <span>\n {isCompletingAuth\n ? tr(\n \"auth.login.settingUpWorkspace\",\n \"Setting up workspace...\",\n )\n : tr(\"auth.login.signingIn\", \"Signing in...\")}\n </span>\n </>\n ) : (\n tr(\"auth.login.signIn\", \"Sign in\")\n )}\n </Button>\n </form>\n\n {/* Divider */}\n <div className=\"relative my-8\">\n <div className=\"absolute inset-0 flex items-center\">\n <div className=\"w-full border-t border-[var(--color-border-default)]\" />\n </div>\n <div className=\"relative flex justify-center\">\n <span className=\"px-4 bg-[var(--color-bg-canvas)] text-sm text-[var(--color-text-tertiary)]\">\n {tr(\"auth.login.orContinueWith\", \"or continue with\")}\n </span>\n </div>\n </div>\n\n {/* OAuth Error */}\n {oauthError && (\n <div className=\"flex items-start gap-3 p-4 rounded-xl border bg-status-error-bg-subtle border-status-error-border\">\n <AlertIcon className=\"size-5 flex-shrink-0 mt-0.5 text-status-error-text\" />\n <p className=\"text-sm text-status-error-text\">{oauthError}</p>\n </div>\n )}\n\n {/* OAuth Buttons */}\n <div className=\"grid grid-cols-3 gap-3\">\n {oauthProviders.map((provider) => (\n <button\n key={provider.name}\n type=\"button\"\n onClick={provider.onClick}\n disabled={provider.disabled}\n title={provider.tooltip}\n aria-label={provider.name}\n className={`flex items-center justify-center gap-2 px-4 py-3 rounded-xl border transition-all duration-200 group ${\n provider.disabled\n ? \"border-[var(--color-border-subtle)] bg-[var(--color-bg-disabled)] cursor-not-allowed opacity-50\"\n : \"border-[var(--color-border-default)] bg-[var(--color-bg-surface)] hover:bg-[var(--color-bg-sunken)] hover:border-[var(--color-border-strong)]\"\n }`}\n >\n <provider.icon\n className={`size-5 ${provider.disabled ? \"opacity-50\" : \"\"}`}\n />\n <span\n className={`sr-only sm:not-sr-only text-sm font-medium transition-colors ${\n provider.disabled\n ? \"text-[var(--color-text-disabled)]\"\n : \"text-[var(--color-text-secondary)] group-hover:text-[var(--color-text-primary)]\"\n }`}\n >\n {provider.name}\n </span>\n </button>\n ))}\n </div>\n\n {/* Enterprise SSO Option — temporarily hidden */}\n {/* <div className=\"mt-6\">\n <button type=\"button\"\n onClick={() => navigate(\"/auth/sso/login\")}\n className=\"w-full flex items-center justify-center gap-3 px-4 py-3 rounded-xl border-2 border-dashed border-[var(--color-border-default)] hover:border-action-primary-bg bg-[var(--color-bg-surface)] hover:bg-status-info-bg-subtle transition-all duration-200 group\"\n >\n <svg\n className=\"size-5 text-[var(--color-text-tertiary)] group-hover:text-text-link\"\n fill=\"none\"\n viewBox=\"0 0 24 24\"\n stroke=\"currentColor\"\n >\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth={1.5}\n d=\"M19 21V5a2 2 0 00-2-2H7a2 2 0 00-2 2v16m14 0h2m-2 0h-5m-9 0H3m2 0h5M9 7h1m-1 4h1m4-4h1m-1 4h1m-5 10v-5a1 1 0 011-1h2a1 1 0 011 1v5m-4 0h4\"\n />\n </svg>\n <span className=\"text-sm font-medium text-[var(--color-text-secondary)] group-hover:text-text-link\">\n {tr(\"auth.login.enterpriseSso\", \"Sign in with Enterprise SSO\")}\n </span>\n </button>\n </div> */}\n\n {/* Magic Link Option */}\n <div className=\"mt-4 text-center\">\n <button\n type=\"button\"\n onClick={() => navigate(\"/auth/magic-link\")}\n className=\"text-sm text-[var(--color-text-secondary)] hover:text-[var(--color-text-primary)] transition-colors\"\n >\n {tr(\"auth.login.preferPasswordless\", \"Prefer passwordless login?\")}{\" \"}\n <span className=\"font-semibold text-text-link hover:text-text-linkHover\">\n {tr(\"auth.login.signInMagicLink\", \"Sign in with Magic Link\")}\n </span>\n </button>\n </div>\n\n {/* Sign Up Link */}\n <p className=\"mt-6 text-center text-sm text-[var(--color-text-secondary)]\">\n {tr(\"auth.login.dontHaveAccount\", \"Don't have an account?\")}{\" \"}\n <button\n type=\"button\"\n onClick={() => navigate(\"/auth/register\")}\n className=\"font-semibold text-text-link hover:text-text-linkHover transition-colors\"\n >\n {tr(\"auth.login.signUp\", \"Sign up\")}\n </button>\n </p>\n </AuthLayout>\n );\n}\n"],"mappings":"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"}
@@ -431,7 +431,7 @@ function _() {
431
431
  " ",
432
432
  /* @__PURE__ */ m("a", {
433
433
  href: "/legal/terms",
434
- className: "text-text-link hover:underline",
434
+ className: "text-text-link underline underline-offset-2",
435
435
  children: b("auth.register.termsOfService", "Terms of Service")
436
436
  }),
437
437
  " ",
@@ -439,7 +439,7 @@ function _() {
439
439
  " ",
440
440
  /* @__PURE__ */ m("a", {
441
441
  href: "/legal/privacy",
442
- className: "text-text-link hover:underline",
442
+ className: "text-text-link underline underline-offset-2",
443
443
  children: b("auth.register.privacyPolicy", "Privacy Policy")
444
444
  }),
445
445
  "."
@@ -490,7 +490,7 @@ function _() {
490
490
  title: e.tooltip,
491
491
  className: `flex items-center justify-center gap-2 px-4 py-3 rounded-xl border transition-all duration-200 group ${e.disabled ? "border-[var(--color-border-subtle)] bg-[var(--color-bg-disabled)] cursor-not-allowed opacity-50" : "border-[var(--color-border-default)] bg-[var(--color-bg-surface)] hover:bg-[var(--color-bg-sunken)] hover:border-[var(--color-border-strong)]"}`,
492
492
  children: [/* @__PURE__ */ m(e.icon, { className: `size-5 ${e.disabled ? "opacity-50" : ""}` }), /* @__PURE__ */ m("span", {
493
- className: `sr-only sm:not-sr-only text-sm font-medium transition-colors hidden sm:inline ${e.disabled ? "text-[var(--color-text-disabled)]" : "text-[var(--color-text-secondary)] group-hover:text-[var(--color-text-primary)]"}`,
493
+ className: `sr-only sm:not-sr-only text-sm font-medium transition-colors ${e.disabled ? "text-[var(--color-text-disabled)]" : "text-[var(--color-text-secondary)] group-hover:text-[var(--color-text-primary)]"}`,
494
494
  children: e.name
495
495
  })]
496
496
  }, e.name))
@@ -1 +1 @@
1
- {"version":3,"file":"RegisterPage.js","names":[],"sources":["../../../src/auth/pages/RegisterPage.tsx"],"sourcesContent":["import { useState } from \"react\";\nimport { useNavigate } from \"react-router\";\nimport { useI18n } from \"@burdenoff/fe-libs/shared/providers/shell\";\nimport { validateEmail, validatePassword } from \"../utils/validation\";\nimport { useAuthOperations } from \"../hooks/useAuthOperations\";\nimport { useOAuthOperations } from \"../hooks/useOAuthOperations\";\nimport { AuthLayout } from \"../components/AuthLayout\";\nimport { Button } from \"@burdenoff/fe-libs/button\";\nimport { PagePurpose } from \"@burdenoff/fe-libs/ui\";\nimport {\n EmailIcon,\n LockIcon,\n UserIcon,\n EyeIcon,\n EyeOffIcon,\n AlertIcon,\n CheckIcon,\n XIcon,\n SpinnerIcon,\n GoogleIcon,\n GitHubIcon,\n MicrosoftIcon,\n} from \"../components/AuthIcons\";\nimport { useAuth } from \"../providers/AuthProvider\";\nimport { CaptchaV2 } from \"../components/CaptchaV2\";\nimport { useSignupCaptcha } from \"../hooks/useSignupCaptcha\";\nimport type { SignUpInput } from \"../types\";\n\n/**\n * Registration page with professional design\n */\nexport function RegisterPage() {\n const { productName } = useAuth();\n const navigate = useNavigate();\n const { t } = useI18n();\n const tr = (key: string, fallback: string): string => {\n const translated = t(key);\n return translated === key ? fallback : translated;\n };\n const { signUp, resendVerification, isLoading, errorCode } =\n useAuthOperations();\n const { initiateGoogleOAuth, initiateMicrosoftOAuth, isProviderConfigured } =\n useOAuthOperations();\n const [showPassword, setShowPassword] = useState(false);\n const [formData, setFormData] = useState<SignUpInput>({\n email: \"\",\n username: \"\",\n password: \"\",\n firstName: \"\",\n lastName: \"\",\n });\n const [validationErrors, setValidationErrors] = useState<string[]>([]);\n const [signupSuccess, setSignupSuccess] = useState(false);\n const [error, setError] = useState<string | null>(null);\n const [oauthError, setOauthError] = useState<string | null>(null);\n const [captchaToken, setCaptchaToken] = useState<string | null>(null);\n // reCAPTCHA v2 tokens are single-use. Bumping this key remounts the widget so\n // a fresh token is issued after a failed submit (the prior token is consumed\n // server-side; reusing it returns timeout-or-duplicate → CAPTCHA_FAILED loop).\n const [captchaResetKey, setCaptchaResetKey] = useState(0);\n const { enabled: captchaEnabled, siteKey: captchaSiteKey } =\n useSignupCaptcha();\n const [isResendingVerification, setIsResendingVerification] = useState(false);\n const [resendError, setResendError] = useState<string | null>(null);\n\n // Signing up with an email that already belongs to a non-active account:\n // route the user to the right recovery path instead of dead-ending.\n const isAccountDeactivated =\n Boolean(error) && errorCode === \"ACCOUNT_DEACTIVATED\";\n const isAccountRemoved = Boolean(error) && errorCode === \"ACCOUNT_REMOVED\";\n const isAccountSuspended =\n Boolean(error) && errorCode === \"ACCOUNT_SUSPENDED\";\n\n // Password strength indicators\n const passwordChecks = (() => {\n const password = formData.password;\n return [\n {\n label: tr(\"auth.register.pwMin8\", \"At least 12 characters\"),\n met: password.length >= 12,\n },\n {\n label: tr(\"auth.register.pwUppercase\", \"One uppercase letter\"),\n met: /[A-Z]/.test(password),\n },\n {\n label: tr(\"auth.register.pwLowercase\", \"One lowercase letter\"),\n met: /[a-z]/.test(password),\n },\n {\n label: tr(\"auth.register.pwNumber\", \"One number\"),\n met: /\\d/.test(password),\n },\n {\n label: tr(\"auth.register.pwSpecial\", \"One special character\"),\n met: /[!@#$%^&*(),.?\":{}|<>]/.test(password),\n },\n ];\n })();\n\n const passwordStrength = (() => {\n const metCount = passwordChecks.filter((c) => c.met).length;\n if (metCount <= 2)\n return {\n level: tr(\"auth.register.passwordStrengthWeak\", \"weak\"),\n color: \"bg-status-error-bg-subtle0\",\n width: \"w-1/4\",\n };\n if (metCount <= 3)\n return {\n level: tr(\"auth.register.passwordStrengthFair\", \"fair\"),\n color: \"bg-status-warning-text\",\n width: \"w-2/4\",\n };\n if (metCount <= 4)\n return {\n level: tr(\"auth.register.passwordStrengthGood\", \"good\"),\n color: \"bg-status-warning-bg-subtle0\",\n width: \"w-3/4\",\n };\n return {\n level: tr(\"auth.register.passwordStrengthStrong\", \"strong\"),\n color: \"bg-status-success-text\",\n width: \"w-full\",\n };\n })();\n\n const handleSubmit = async (e: React.FormEvent) => {\n e.preventDefault();\n\n const errors: string[] = [];\n if (!validateEmail(formData.email)) {\n errors.push(\n tr(\"auth.register.invalidEmail\", \"Please enter a valid email address\"),\n );\n }\n if (!formData.username || formData.username.length < 3) {\n errors.push(\n tr(\n \"auth.register.usernameMin3\",\n \"Username must be at least 3 characters\",\n ),\n );\n }\n if (!/^[a-zA-Z0-9_-]+$/.test(formData.username)) {\n errors.push(\n tr(\n \"auth.register.usernameChars\",\n \"Username can only contain letters, numbers, underscores, and hyphens\",\n ),\n );\n }\n const passwordValidation = validatePassword(formData.password);\n if (!passwordValidation.valid) {\n errors.push(...passwordValidation.errors);\n }\n\n if (captchaEnabled && !captchaToken) {\n errors.push(\n tr(\n \"auth.register.completeCaptcha\",\n \"Please complete the reCAPTCHA verification\",\n ),\n );\n }\n\n if (errors.length > 0) {\n setValidationErrors(errors);\n return;\n }\n\n setValidationErrors([]);\n setError(null);\n try {\n await signUp({\n ...formData,\n ...(captchaToken ? { recaptchaToken: captchaToken } : {}),\n });\n // Sign up successful - check if email verification is required\n // (Backend returns empty tokens when email verification is needed)\n setSignupSuccess(true);\n } catch (err) {\n const message =\n err instanceof Error\n ? err.message\n : tr(\"auth.register.signUpFailed\", \"Sign up failed\");\n setError(message);\n console.error(\"Sign up failed:\", err);\n // The captcha token (if any) was consumed during this attempt — discard it\n // and remount the widget so the user gets a fresh, solvable challenge on\n // retry instead of being trapped in a CAPTCHA_FAILED loop.\n if (captchaEnabled) {\n setCaptchaToken(null);\n setCaptchaResetKey((k) => k + 1);\n }\n }\n };\n\n /**\n * Handle Google OAuth signup\n */\n const handleGoogleSignup = () => {\n setOauthError(null);\n try {\n initiateGoogleOAuth();\n } catch (err) {\n setOauthError(\n err instanceof Error\n ? err.message\n : tr(\n \"auth.register.googleSignUpFailed\",\n \"Failed to initiate Google sign up\",\n ),\n );\n }\n };\n\n /**\n * Handle Microsoft OAuth signup\n */\n const handleMicrosoftSignup = () => {\n setOauthError(null);\n try {\n initiateMicrosoftOAuth();\n } catch (err) {\n setOauthError(\n err instanceof Error\n ? err.message\n : tr(\n \"auth.register.microsoftSignUpFailed\",\n \"Failed to initiate Microsoft sign up\",\n ),\n );\n }\n };\n\n // Check if OAuth providers are configured\n const isGoogleConfigured = isProviderConfigured(\"google\");\n const isMicrosoftConfigured = isProviderConfigured(\"microsoft\");\n\n const oauthProviders = [\n {\n name: \"Google\",\n icon: GoogleIcon,\n onClick: handleGoogleSignup,\n disabled: !isGoogleConfigured,\n tooltip: isGoogleConfigured\n ? undefined\n : tr(\n \"auth.register.googleNotConfigured\",\n \"Google sign up is not configured\",\n ),\n },\n {\n name: \"GitHub\",\n icon: GitHubIcon,\n onClick: () => {},\n disabled: true,\n tooltip: tr(\n \"auth.register.githubNotConfigured\",\n \"GitHub sign up is not configured\",\n ),\n },\n {\n name: \"Microsoft\",\n icon: MicrosoftIcon,\n onClick: handleMicrosoftSignup,\n disabled: !isMicrosoftConfigured,\n tooltip: isMicrosoftConfigured\n ? undefined\n : tr(\n \"auth.register.microsoftNotConfigured\",\n \"Microsoft sign up is not configured\",\n ),\n },\n ];\n\n const verificationEmailMessage = tr(\n \"auth.register.verificationEmailSentTo\",\n \"We've sent a verification email to {{email}}. Please check your inbox and click the verification link to activate your account.\",\n );\n const [verificationEmailPrefix, verificationEmailSuffix = \"\"] =\n verificationEmailMessage.split(\"{{email}}\");\n\n // Show success state after signup\n if (signupSuccess) {\n return (\n <AuthLayout\n title={tr(\"auth.register.checkEmail\", \"Check your email\")}\n subtitle={tr(\n \"auth.register.verificationLinkSent\",\n \"We've sent you a verification link\",\n )}\n >\n <div className=\"flex flex-col items-center justify-center py-6\">\n {/* Success Icon */}\n <div className=\"size-20 rounded-full bg-status-success-bg-subtle flex items-center justify-center mb-6\">\n <svg\n className=\"size-10 text-status-success-text\"\n fill=\"none\"\n viewBox=\"0 0 24 24\"\n stroke=\"currentColor\"\n >\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth={2}\n d=\"M3 8l7.89 5.26a2 2 0 002.22 0L21 8M5 19h14a2 2 0 002-2V7a2 2 0 00-2-2H5a2 2 0 00-2 2v10a2 2 0 002 2z\"\n />\n </svg>\n </div>\n\n <h3 className=\"text-lg font-semibold text-[var(--color-text-primary)] mb-2\">\n {tr(\n \"auth.register.accountCreated\",\n \"Account created successfully!\",\n )}\n </h3>\n\n <p className=\"text-center text-[var(--color-text-secondary)] mb-8 max-w-sm\">\n {verificationEmailPrefix}\n <span className=\"font-medium text-[var(--color-text-primary)]\">\n {formData.email}\n </span>\n {verificationEmailSuffix}\n </p>\n\n <div className=\"space-y-3 w-full\">\n <Button\n type=\"button\"\n onClick={() => navigate(\"/auth/login\")}\n variant=\"default\"\n size=\"lg\"\n className=\"w-full font-semibold\"\n >\n {tr(\"auth.register.continueToSignIn\", \"Continue to sign in\")}\n </Button>\n\n {resendError && (\n <p className=\"text-center text-sm text-status-error-text\">\n {resendError}\n </p>\n )}\n <p className=\"text-center text-sm text-[var(--color-text-tertiary)]\">\n {tr(\n \"auth.register.didntReceiveEmail\",\n \"Didn't receive the email? Check your spam folder or\",\n )}{\" \"}\n <button\n type=\"button\"\n disabled={isResendingVerification}\n onClick={async () => {\n setResendError(null);\n setIsResendingVerification(true);\n try {\n await resendVerification(formData.email);\n } catch (err) {\n setResendError(\n err instanceof Error\n ? err.message\n : tr(\n \"auth.register.resendFailed\",\n \"Failed to resend verification email\",\n ),\n );\n } finally {\n setIsResendingVerification(false);\n }\n }}\n className=\"text-text-link hover:text-text-linkHover font-medium disabled:opacity-50 disabled:cursor-not-allowed\"\n >\n {isResendingVerification\n ? tr(\"auth.register.resending\", \"resending...\")\n : tr(\"auth.register.tryAgain\", \"try again\")}\n </button>\n </p>\n </div>\n </div>\n </AuthLayout>\n );\n }\n\n return (\n <AuthLayout\n title={tr(\"auth.register.createAccount\", \"Create your account\")}\n subtitle={tr(\n \"auth.register.startJourney\",\n \"Start your journey with {{productName}}\",\n ).replace(\"{{productName}}\", productName || \"Burdenoff Workspaces\")}\n productName={productName}\n >\n <PagePurpose className=\"mb-5\">\n {tr(\n \"auth.register.purpose\",\n \"Create your account to get a personal workspace and start collaborating. You'll verify your email, then you can sign in and invite your team.\",\n )}\n </PagePurpose>\n <form onSubmit={handleSubmit} className=\"space-y-5\">\n {/* Deactivated account → offer self-service reactivation */}\n {isAccountDeactivated && (\n <div className=\"flex items-start gap-3 p-4 rounded-xl bg-status-warning-bg-subtle border border-status-warning-border\">\n <AlertIcon className=\"size-5 text-status-warning-text flex-shrink-0 mt-0.5\" />\n <div className=\"space-y-2\">\n <p className=\"text-sm font-medium text-status-warning-text\">\n {tr(\n \"auth.register.accountDeactivated\",\n \"This email belongs to a deactivated account.\",\n )}\n </p>\n <p className=\"text-xs text-status-warning-text/80\">\n {tr(\n \"auth.register.accountDeactivatedHelp\",\n \"If this is your account, you can reactivate it instead of creating a new one.\",\n )}\n </p>\n <button\n type=\"button\"\n onClick={() =>\n navigate(\"/auth/reactivate\", {\n state: { email: formData.email },\n })\n }\n className=\"text-sm font-semibold text-status-warning-text underline underline-offset-2\"\n >\n {tr(\"auth.register.reactivateCta\", \"Reactivate my account\")}\n </button>\n </div>\n </div>\n )}\n\n {/* Admin-removed / suspended → point to support (no self-service path) */}\n {(isAccountRemoved || isAccountSuspended) && (\n <div className=\"flex items-start gap-3 p-4 rounded-xl bg-status-warning-bg-subtle border border-status-warning-border\">\n <AlertIcon className=\"size-5 text-status-warning-text flex-shrink-0 mt-0.5\" />\n <p className=\"text-sm text-status-warning-text\">{error}</p>\n </div>\n )}\n\n {/* Generic error / validation alert */}\n {((error &&\n !isAccountDeactivated &&\n !isAccountRemoved &&\n !isAccountSuspended) ||\n validationErrors.length > 0) && (\n <div className=\"flex items-start gap-3 p-4 rounded-xl bg-status-error-bg-subtle border border-status-error-border\">\n <AlertIcon className=\"size-5 text-status-error-text flex-shrink-0 mt-0.5\" />\n <div className=\"space-y-1\">\n {error &&\n !isAccountDeactivated &&\n !isAccountRemoved &&\n !isAccountSuspended && (\n <p className=\"text-sm text-status-error-text\">{error}</p>\n )}\n {validationErrors.map((err) => (\n <p key={err} className=\"text-sm text-status-error-text\">\n {err}\n </p>\n ))}\n </div>\n </div>\n )}\n\n {/* Name Fields */}\n <div className=\"grid grid-cols-2 gap-4\">\n <div className=\"space-y-2\">\n <label\n htmlFor=\"firstName\"\n className=\"block text-sm font-medium text-[var(--color-text-primary)]\"\n >\n {tr(\"auth.register.firstName\", \"First Name\")}\n </label>\n <input\n id=\"firstName\"\n type=\"text\"\n required\n aria-required=\"true\"\n aria-label={tr(\"auth.register.firstName\", \"First Name\")}\n value={formData.firstName}\n onChange={(e) =>\n setFormData({ ...formData, firstName: e.target.value })\n }\n className=\"block w-full px-4 py-3 rounded-xl border border-[var(--color-border-default)] bg-[var(--color-bg-surface)] text-[var(--color-text-primary)] placeholder:text-[var(--color-text-tertiary)] focus:outline-none focus:ring-2 focus:ring-action-primary-bg/20 focus:border-action-primary-bg transition-all\"\n placeholder={tr(\n \"auth.register.firstNamePlaceholder\",\n \"Enter first name\",\n )}\n />\n </div>\n <div className=\"space-y-2\">\n <label\n htmlFor=\"lastName\"\n className=\"block text-sm font-medium text-[var(--color-text-primary)]\"\n >\n {tr(\"auth.register.lastName\", \"Last Name\")}\n </label>\n <input\n id=\"lastName\"\n type=\"text\"\n required\n aria-required=\"true\"\n aria-label={tr(\"auth.register.lastName\", \"Last Name\")}\n value={formData.lastName}\n onChange={(e) =>\n setFormData({ ...formData, lastName: e.target.value })\n }\n className=\"block w-full px-4 py-3 rounded-xl border border-[var(--color-border-default)] bg-[var(--color-bg-surface)] text-[var(--color-text-primary)] placeholder:text-[var(--color-text-tertiary)] focus:outline-none focus:ring-2 focus:ring-action-primary-bg/20 focus:border-action-primary-bg transition-all\"\n placeholder={tr(\n \"auth.register.lastNamePlaceholder\",\n \"Enter last name\",\n )}\n />\n </div>\n </div>\n\n {/* Username Input */}\n <div className=\"space-y-2\">\n <label\n htmlFor=\"username\"\n className=\"block text-sm font-medium text-[var(--color-text-primary)]\"\n >\n {tr(\"auth.register.username\", \"Username\")}\n </label>\n <div className=\"relative\">\n <div className=\"absolute inset-y-0 left-0 pl-3.5 flex items-center pointer-events-none\">\n <UserIcon className=\"size-5 text-[var(--color-text-tertiary)]\" />\n </div>\n <input\n id=\"username\"\n type=\"text\"\n required\n aria-required=\"true\"\n aria-label={tr(\"auth.register.username\", \"Username\")}\n autoComplete=\"username\"\n value={formData.username}\n onChange={(e) =>\n setFormData({ ...formData, username: e.target.value })\n }\n className=\"block w-full pl-[3.5rem] pr-4 py-3 rounded-xl border border-[var(--color-border-default)] bg-[var(--color-bg-surface)] text-[var(--color-text-primary)] placeholder:text-[var(--color-text-tertiary)] focus:outline-none focus:ring-2 focus:ring-action-primary-bg/20 focus:border-action-primary-bg transition-all\"\n placeholder={tr(\n \"auth.register.usernamePlaceholder\",\n \"Choose a username\",\n )}\n />\n </div>\n </div>\n\n {/* Email Input */}\n <div className=\"space-y-2\">\n <label\n htmlFor=\"email\"\n className=\"block text-sm font-medium text-[var(--color-text-primary)]\"\n >\n {tr(\"auth.register.email\", \"Email\")}\n </label>\n <div className=\"relative\">\n <div className=\"absolute inset-y-0 left-0 pl-3.5 flex items-center pointer-events-none\">\n <EmailIcon className=\"size-5 text-[var(--color-text-tertiary)]\" />\n </div>\n <input\n id=\"email\"\n type=\"email\"\n required\n aria-required=\"true\"\n aria-label={tr(\"auth.register.email\", \"Email\")}\n autoComplete=\"email\"\n value={formData.email}\n onChange={(e) =>\n setFormData({ ...formData, email: e.target.value })\n }\n className=\"block w-full pl-[3.5rem] pr-4 py-3 rounded-xl border border-[var(--color-border-default)] bg-[var(--color-bg-surface)] text-[var(--color-text-primary)] placeholder:text-[var(--color-text-tertiary)] focus:outline-none focus:ring-2 focus:ring-action-primary-bg/20 focus:border-action-primary-bg transition-all\"\n placeholder={tr(\n \"auth.register.emailPlaceholder\",\n \"you@example.com\",\n )}\n />\n </div>\n </div>\n\n {/* Password Input */}\n <div className=\"space-y-2\">\n <label\n htmlFor=\"password\"\n className=\"block text-sm font-medium text-[var(--color-text-primary)]\"\n >\n {tr(\"auth.register.password\", \"Password\")}\n </label>\n <div className=\"relative\">\n <div className=\"absolute inset-y-0 left-0 pl-3.5 flex items-center pointer-events-none\">\n <LockIcon className=\"size-5 text-[var(--color-text-tertiary)]\" />\n </div>\n <input\n id=\"password\"\n type={showPassword ? \"text\" : \"password\"}\n required\n aria-required=\"true\"\n aria-label={tr(\"auth.register.password\", \"Password\")}\n autoComplete=\"new-password\"\n value={formData.password}\n onChange={(e) =>\n setFormData({ ...formData, password: e.target.value })\n }\n className=\"block w-full pl-[3.5rem] pr-12 py-3 rounded-xl border border-[var(--color-border-default)] bg-[var(--color-bg-surface)] text-[var(--color-text-primary)] placeholder:text-[var(--color-text-tertiary)] focus:outline-none focus:ring-2 focus:ring-action-primary-bg/20 focus:border-action-primary-bg transition-all\"\n placeholder={tr(\n \"auth.register.passwordPlaceholder\",\n \"Create a strong password\",\n )}\n />\n <button\n type=\"button\"\n onClick={() => setShowPassword(!showPassword)}\n aria-label={showPassword ? \"Hide password\" : \"Show password\"}\n className=\"absolute inset-y-0 right-0 pr-3.5 flex items-center text-[var(--color-text-tertiary)] hover:text-[var(--color-text-secondary)] transition-colors\"\n >\n {showPassword ? (\n <EyeOffIcon className=\"size-5\" />\n ) : (\n <EyeIcon className=\"size-5\" />\n )}\n </button>\n </div>\n\n {/* Password Strength Indicator */}\n {formData.password && (\n <div className=\"space-y-3 pt-2\">\n {/* Strength Bar */}\n <div className=\"space-y-1\">\n <div className=\"h-1.5 bg-[var(--color-bg-sunken)] rounded-full overflow-hidden\">\n <div\n className={`h-full ${passwordStrength.color} ${passwordStrength.width} transition-all duration-300`}\n />\n </div>\n <p className=\"text-xs text-[var(--color-text-tertiary)] capitalize\">\n {tr(\"auth.register.passwordStrength\", \"Password strength:\")}{\" \"}\n <span className=\"font-medium\">{passwordStrength.level}</span>\n </p>\n </div>\n\n {/* Requirements Checklist */}\n <div className=\"grid grid-cols-2 gap-2\">\n {passwordChecks.map((check) => (\n <div key={check.label} className=\"flex items-center gap-2\">\n {check.met ? (\n <CheckIcon className=\"size-4 text-status-success-text\" />\n ) : (\n <XIcon className=\"size-4 text-[var(--color-text-tertiary)]\" />\n )}\n <span\n className={`text-xs ${\n check.met\n ? \"text-status-success-text\"\n : \"text-[var(--color-text-tertiary)]\"\n }`}\n >\n {check.label}\n </span>\n </div>\n ))}\n </div>\n </div>\n )}\n </div>\n\n {/* Terms Agreement */}\n <p className=\"text-xs text-[var(--color-text-tertiary)] leading-relaxed\">\n {tr(\n \"auth.register.agreeToTerms\",\n \"By creating an account, you agree to our\",\n )}{\" \"}\n <a href=\"/legal/terms\" className=\"text-text-link hover:underline\">\n {tr(\"auth.register.termsOfService\", \"Terms of Service\")}\n </a>{\" \"}\n {tr(\"auth.register.and\", \"and\")}{\" \"}\n <a href=\"/legal/privacy\" className=\"text-text-link hover:underline\">\n {tr(\"auth.register.privacyPolicy\", \"Privacy Policy\")}\n </a>\n .\n </p>\n\n {/* reCAPTCHA v2 Checkbox — enabled per-product via the platform catalog.\n `key` remounts it after a failed submit so a fresh token is issued. */}\n <CaptchaV2\n key={captchaResetKey}\n enabled={captchaEnabled}\n siteKey={captchaSiteKey}\n onVerify={setCaptchaToken}\n onExpired={() => setCaptchaToken(null)}\n />\n\n {/* Submit Button */}\n <Button\n type=\"submit\"\n disabled={isLoading}\n variant=\"default\"\n size=\"lg\"\n className=\"w-full font-semibold\"\n >\n {isLoading ? (\n <>\n <SpinnerIcon className=\"size-5 animate-spin\" />\n <span>\n {tr(\"auth.register.creatingAccount\", \"Creating account...\")}\n </span>\n </>\n ) : (\n tr(\"auth.register.createAccountBtn\", \"Create account\")\n )}\n </Button>\n </form>\n\n {/* Divider */}\n <div className=\"relative my-8\">\n <div className=\"absolute inset-0 flex items-center\">\n <div className=\"w-full border-t border-[var(--color-border-default)]\" />\n </div>\n <div className=\"relative flex justify-center\">\n <span className=\"px-4 bg-[var(--color-bg-canvas)] text-sm text-[var(--color-text-tertiary)]\">\n {tr(\"auth.register.orSignUpWith\", \"or sign up with\")}\n </span>\n </div>\n </div>\n\n {/* OAuth Error */}\n {oauthError && (\n <div className=\"flex items-start gap-3 p-4 rounded-xl border bg-status-error-bg-subtle border-status-error-border\">\n <AlertIcon className=\"size-5 flex-shrink-0 mt-0.5 text-status-error-text\" />\n <p className=\"text-sm text-status-error-text\">{oauthError}</p>\n </div>\n )}\n\n {/* OAuth Buttons */}\n <div className=\"grid grid-cols-3 gap-3\">\n {oauthProviders.map((provider) => (\n <button\n key={provider.name}\n type=\"button\"\n onClick={provider.onClick}\n disabled={provider.disabled}\n title={provider.tooltip}\n className={`flex items-center justify-center gap-2 px-4 py-3 rounded-xl border transition-all duration-200 group ${\n provider.disabled\n ? \"border-[var(--color-border-subtle)] bg-[var(--color-bg-disabled)] cursor-not-allowed opacity-50\"\n : \"border-[var(--color-border-default)] bg-[var(--color-bg-surface)] hover:bg-[var(--color-bg-sunken)] hover:border-[var(--color-border-strong)]\"\n }`}\n >\n <provider.icon\n className={`size-5 ${provider.disabled ? \"opacity-50\" : \"\"}`}\n />\n <span\n className={`sr-only sm:not-sr-only text-sm font-medium transition-colors hidden sm:inline ${\n provider.disabled\n ? \"text-[var(--color-text-disabled)]\"\n : \"text-[var(--color-text-secondary)] group-hover:text-[var(--color-text-primary)]\"\n }`}\n >\n {provider.name}\n </span>\n </button>\n ))}\n </div>\n\n {/* Sign In Link */}\n <p className=\"mt-8 text-center text-sm text-[var(--color-text-secondary)]\">\n {tr(\"auth.register.alreadyHaveAccount\", \"Already have an account?\")}{\" \"}\n <button\n type=\"button\"\n onClick={() => navigate(\"/auth/login\")}\n className=\"font-semibold text-text-link hover:text-text-linkHover transition-colors\"\n >\n {tr(\"auth.register.signIn\", \"Sign in\")}\n </button>\n </p>\n </AuthLayout>\n );\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"RegisterPage.js","names":[],"sources":["../../../src/auth/pages/RegisterPage.tsx"],"sourcesContent":["import { useState } from \"react\";\nimport { useNavigate } from \"react-router\";\nimport { useI18n } from \"@burdenoff/fe-libs/shared/providers/shell\";\nimport { validateEmail, validatePassword } from \"../utils/validation\";\nimport { useAuthOperations } from \"../hooks/useAuthOperations\";\nimport { useOAuthOperations } from \"../hooks/useOAuthOperations\";\nimport { AuthLayout } from \"../components/AuthLayout\";\nimport { Button } from \"@burdenoff/fe-libs/button\";\nimport { PagePurpose } from \"@burdenoff/fe-libs/ui\";\nimport {\n EmailIcon,\n LockIcon,\n UserIcon,\n EyeIcon,\n EyeOffIcon,\n AlertIcon,\n CheckIcon,\n XIcon,\n SpinnerIcon,\n GoogleIcon,\n GitHubIcon,\n MicrosoftIcon,\n} from \"../components/AuthIcons\";\nimport { useAuth } from \"../providers/AuthProvider\";\nimport { CaptchaV2 } from \"../components/CaptchaV2\";\nimport { useSignupCaptcha } from \"../hooks/useSignupCaptcha\";\nimport type { SignUpInput } from \"../types\";\n\n/**\n * Registration page with professional design\n */\nexport function RegisterPage() {\n const { productName } = useAuth();\n const navigate = useNavigate();\n const { t } = useI18n();\n const tr = (key: string, fallback: string): string => {\n const translated = t(key);\n return translated === key ? fallback : translated;\n };\n const { signUp, resendVerification, isLoading, errorCode } =\n useAuthOperations();\n const { initiateGoogleOAuth, initiateMicrosoftOAuth, isProviderConfigured } =\n useOAuthOperations();\n const [showPassword, setShowPassword] = useState(false);\n const [formData, setFormData] = useState<SignUpInput>({\n email: \"\",\n username: \"\",\n password: \"\",\n firstName: \"\",\n lastName: \"\",\n });\n const [validationErrors, setValidationErrors] = useState<string[]>([]);\n const [signupSuccess, setSignupSuccess] = useState(false);\n const [error, setError] = useState<string | null>(null);\n const [oauthError, setOauthError] = useState<string | null>(null);\n const [captchaToken, setCaptchaToken] = useState<string | null>(null);\n // reCAPTCHA v2 tokens are single-use. Bumping this key remounts the widget so\n // a fresh token is issued after a failed submit (the prior token is consumed\n // server-side; reusing it returns timeout-or-duplicate → CAPTCHA_FAILED loop).\n const [captchaResetKey, setCaptchaResetKey] = useState(0);\n const { enabled: captchaEnabled, siteKey: captchaSiteKey } =\n useSignupCaptcha();\n const [isResendingVerification, setIsResendingVerification] = useState(false);\n const [resendError, setResendError] = useState<string | null>(null);\n\n // Signing up with an email that already belongs to a non-active account:\n // route the user to the right recovery path instead of dead-ending.\n const isAccountDeactivated =\n Boolean(error) && errorCode === \"ACCOUNT_DEACTIVATED\";\n const isAccountRemoved = Boolean(error) && errorCode === \"ACCOUNT_REMOVED\";\n const isAccountSuspended =\n Boolean(error) && errorCode === \"ACCOUNT_SUSPENDED\";\n\n // Password strength indicators\n const passwordChecks = (() => {\n const password = formData.password;\n return [\n {\n label: tr(\"auth.register.pwMin8\", \"At least 12 characters\"),\n met: password.length >= 12,\n },\n {\n label: tr(\"auth.register.pwUppercase\", \"One uppercase letter\"),\n met: /[A-Z]/.test(password),\n },\n {\n label: tr(\"auth.register.pwLowercase\", \"One lowercase letter\"),\n met: /[a-z]/.test(password),\n },\n {\n label: tr(\"auth.register.pwNumber\", \"One number\"),\n met: /\\d/.test(password),\n },\n {\n label: tr(\"auth.register.pwSpecial\", \"One special character\"),\n met: /[!@#$%^&*(),.?\":{}|<>]/.test(password),\n },\n ];\n })();\n\n const passwordStrength = (() => {\n const metCount = passwordChecks.filter((c) => c.met).length;\n if (metCount <= 2)\n return {\n level: tr(\"auth.register.passwordStrengthWeak\", \"weak\"),\n color: \"bg-status-error-bg-subtle0\",\n width: \"w-1/4\",\n };\n if (metCount <= 3)\n return {\n level: tr(\"auth.register.passwordStrengthFair\", \"fair\"),\n color: \"bg-status-warning-text\",\n width: \"w-2/4\",\n };\n if (metCount <= 4)\n return {\n level: tr(\"auth.register.passwordStrengthGood\", \"good\"),\n color: \"bg-status-warning-bg-subtle0\",\n width: \"w-3/4\",\n };\n return {\n level: tr(\"auth.register.passwordStrengthStrong\", \"strong\"),\n color: \"bg-status-success-text\",\n width: \"w-full\",\n };\n })();\n\n const handleSubmit = async (e: React.FormEvent) => {\n e.preventDefault();\n\n const errors: string[] = [];\n if (!validateEmail(formData.email)) {\n errors.push(\n tr(\"auth.register.invalidEmail\", \"Please enter a valid email address\"),\n );\n }\n if (!formData.username || formData.username.length < 3) {\n errors.push(\n tr(\n \"auth.register.usernameMin3\",\n \"Username must be at least 3 characters\",\n ),\n );\n }\n if (!/^[a-zA-Z0-9_-]+$/.test(formData.username)) {\n errors.push(\n tr(\n \"auth.register.usernameChars\",\n \"Username can only contain letters, numbers, underscores, and hyphens\",\n ),\n );\n }\n const passwordValidation = validatePassword(formData.password);\n if (!passwordValidation.valid) {\n errors.push(...passwordValidation.errors);\n }\n\n if (captchaEnabled && !captchaToken) {\n errors.push(\n tr(\n \"auth.register.completeCaptcha\",\n \"Please complete the reCAPTCHA verification\",\n ),\n );\n }\n\n if (errors.length > 0) {\n setValidationErrors(errors);\n return;\n }\n\n setValidationErrors([]);\n setError(null);\n try {\n await signUp({\n ...formData,\n ...(captchaToken ? { recaptchaToken: captchaToken } : {}),\n });\n // Sign up successful - check if email verification is required\n // (Backend returns empty tokens when email verification is needed)\n setSignupSuccess(true);\n } catch (err) {\n const message =\n err instanceof Error\n ? err.message\n : tr(\"auth.register.signUpFailed\", \"Sign up failed\");\n setError(message);\n console.error(\"Sign up failed:\", err);\n // The captcha token (if any) was consumed during this attempt — discard it\n // and remount the widget so the user gets a fresh, solvable challenge on\n // retry instead of being trapped in a CAPTCHA_FAILED loop.\n if (captchaEnabled) {\n setCaptchaToken(null);\n setCaptchaResetKey((k) => k + 1);\n }\n }\n };\n\n /**\n * Handle Google OAuth signup\n */\n const handleGoogleSignup = () => {\n setOauthError(null);\n try {\n initiateGoogleOAuth();\n } catch (err) {\n setOauthError(\n err instanceof Error\n ? err.message\n : tr(\n \"auth.register.googleSignUpFailed\",\n \"Failed to initiate Google sign up\",\n ),\n );\n }\n };\n\n /**\n * Handle Microsoft OAuth signup\n */\n const handleMicrosoftSignup = () => {\n setOauthError(null);\n try {\n initiateMicrosoftOAuth();\n } catch (err) {\n setOauthError(\n err instanceof Error\n ? err.message\n : tr(\n \"auth.register.microsoftSignUpFailed\",\n \"Failed to initiate Microsoft sign up\",\n ),\n );\n }\n };\n\n // Check if OAuth providers are configured\n const isGoogleConfigured = isProviderConfigured(\"google\");\n const isMicrosoftConfigured = isProviderConfigured(\"microsoft\");\n\n const oauthProviders = [\n {\n name: \"Google\",\n icon: GoogleIcon,\n onClick: handleGoogleSignup,\n disabled: !isGoogleConfigured,\n tooltip: isGoogleConfigured\n ? undefined\n : tr(\n \"auth.register.googleNotConfigured\",\n \"Google sign up is not configured\",\n ),\n },\n {\n name: \"GitHub\",\n icon: GitHubIcon,\n onClick: () => {},\n disabled: true,\n tooltip: tr(\n \"auth.register.githubNotConfigured\",\n \"GitHub sign up is not configured\",\n ),\n },\n {\n name: \"Microsoft\",\n icon: MicrosoftIcon,\n onClick: handleMicrosoftSignup,\n disabled: !isMicrosoftConfigured,\n tooltip: isMicrosoftConfigured\n ? undefined\n : tr(\n \"auth.register.microsoftNotConfigured\",\n \"Microsoft sign up is not configured\",\n ),\n },\n ];\n\n const verificationEmailMessage = tr(\n \"auth.register.verificationEmailSentTo\",\n \"We've sent a verification email to {{email}}. Please check your inbox and click the verification link to activate your account.\",\n );\n const [verificationEmailPrefix, verificationEmailSuffix = \"\"] =\n verificationEmailMessage.split(\"{{email}}\");\n\n // Show success state after signup\n if (signupSuccess) {\n return (\n <AuthLayout\n title={tr(\"auth.register.checkEmail\", \"Check your email\")}\n subtitle={tr(\n \"auth.register.verificationLinkSent\",\n \"We've sent you a verification link\",\n )}\n >\n <div className=\"flex flex-col items-center justify-center py-6\">\n {/* Success Icon */}\n <div className=\"size-20 rounded-full bg-status-success-bg-subtle flex items-center justify-center mb-6\">\n <svg\n className=\"size-10 text-status-success-text\"\n fill=\"none\"\n viewBox=\"0 0 24 24\"\n stroke=\"currentColor\"\n >\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth={2}\n d=\"M3 8l7.89 5.26a2 2 0 002.22 0L21 8M5 19h14a2 2 0 002-2V7a2 2 0 00-2-2H5a2 2 0 00-2 2v10a2 2 0 002 2z\"\n />\n </svg>\n </div>\n\n <h3 className=\"text-lg font-semibold text-[var(--color-text-primary)] mb-2\">\n {tr(\n \"auth.register.accountCreated\",\n \"Account created successfully!\",\n )}\n </h3>\n\n <p className=\"text-center text-[var(--color-text-secondary)] mb-8 max-w-sm\">\n {verificationEmailPrefix}\n <span className=\"font-medium text-[var(--color-text-primary)]\">\n {formData.email}\n </span>\n {verificationEmailSuffix}\n </p>\n\n <div className=\"space-y-3 w-full\">\n <Button\n type=\"button\"\n onClick={() => navigate(\"/auth/login\")}\n variant=\"default\"\n size=\"lg\"\n className=\"w-full font-semibold\"\n >\n {tr(\"auth.register.continueToSignIn\", \"Continue to sign in\")}\n </Button>\n\n {resendError && (\n <p className=\"text-center text-sm text-status-error-text\">\n {resendError}\n </p>\n )}\n <p className=\"text-center text-sm text-[var(--color-text-tertiary)]\">\n {tr(\n \"auth.register.didntReceiveEmail\",\n \"Didn't receive the email? Check your spam folder or\",\n )}{\" \"}\n <button\n type=\"button\"\n disabled={isResendingVerification}\n onClick={async () => {\n setResendError(null);\n setIsResendingVerification(true);\n try {\n await resendVerification(formData.email);\n } catch (err) {\n setResendError(\n err instanceof Error\n ? err.message\n : tr(\n \"auth.register.resendFailed\",\n \"Failed to resend verification email\",\n ),\n );\n } finally {\n setIsResendingVerification(false);\n }\n }}\n className=\"text-text-link hover:text-text-linkHover font-medium disabled:opacity-50 disabled:cursor-not-allowed\"\n >\n {isResendingVerification\n ? tr(\"auth.register.resending\", \"resending...\")\n : tr(\"auth.register.tryAgain\", \"try again\")}\n </button>\n </p>\n </div>\n </div>\n </AuthLayout>\n );\n }\n\n return (\n <AuthLayout\n title={tr(\"auth.register.createAccount\", \"Create your account\")}\n subtitle={tr(\n \"auth.register.startJourney\",\n \"Start your journey with {{productName}}\",\n ).replace(\"{{productName}}\", productName || \"Burdenoff Workspaces\")}\n productName={productName}\n >\n <PagePurpose className=\"mb-5\">\n {tr(\n \"auth.register.purpose\",\n \"Create your account to get a personal workspace and start collaborating. You'll verify your email, then you can sign in and invite your team.\",\n )}\n </PagePurpose>\n <form onSubmit={handleSubmit} className=\"space-y-5\">\n {/* Deactivated account → offer self-service reactivation */}\n {isAccountDeactivated && (\n <div className=\"flex items-start gap-3 p-4 rounded-xl bg-status-warning-bg-subtle border border-status-warning-border\">\n <AlertIcon className=\"size-5 text-status-warning-text flex-shrink-0 mt-0.5\" />\n <div className=\"space-y-2\">\n <p className=\"text-sm font-medium text-status-warning-text\">\n {tr(\n \"auth.register.accountDeactivated\",\n \"This email belongs to a deactivated account.\",\n )}\n </p>\n <p className=\"text-xs text-status-warning-text/80\">\n {tr(\n \"auth.register.accountDeactivatedHelp\",\n \"If this is your account, you can reactivate it instead of creating a new one.\",\n )}\n </p>\n <button\n type=\"button\"\n onClick={() =>\n navigate(\"/auth/reactivate\", {\n state: { email: formData.email },\n })\n }\n className=\"text-sm font-semibold text-status-warning-text underline underline-offset-2\"\n >\n {tr(\"auth.register.reactivateCta\", \"Reactivate my account\")}\n </button>\n </div>\n </div>\n )}\n\n {/* Admin-removed / suspended → point to support (no self-service path) */}\n {(isAccountRemoved || isAccountSuspended) && (\n <div className=\"flex items-start gap-3 p-4 rounded-xl bg-status-warning-bg-subtle border border-status-warning-border\">\n <AlertIcon className=\"size-5 text-status-warning-text flex-shrink-0 mt-0.5\" />\n <p className=\"text-sm text-status-warning-text\">{error}</p>\n </div>\n )}\n\n {/* Generic error / validation alert */}\n {((error &&\n !isAccountDeactivated &&\n !isAccountRemoved &&\n !isAccountSuspended) ||\n validationErrors.length > 0) && (\n <div className=\"flex items-start gap-3 p-4 rounded-xl bg-status-error-bg-subtle border border-status-error-border\">\n <AlertIcon className=\"size-5 text-status-error-text flex-shrink-0 mt-0.5\" />\n <div className=\"space-y-1\">\n {error &&\n !isAccountDeactivated &&\n !isAccountRemoved &&\n !isAccountSuspended && (\n <p className=\"text-sm text-status-error-text\">{error}</p>\n )}\n {validationErrors.map((err) => (\n <p key={err} className=\"text-sm text-status-error-text\">\n {err}\n </p>\n ))}\n </div>\n </div>\n )}\n\n {/* Name Fields */}\n <div className=\"grid grid-cols-2 gap-4\">\n <div className=\"space-y-2\">\n <label\n htmlFor=\"firstName\"\n className=\"block text-sm font-medium text-[var(--color-text-primary)]\"\n >\n {tr(\"auth.register.firstName\", \"First Name\")}\n </label>\n <input\n id=\"firstName\"\n type=\"text\"\n required\n aria-required=\"true\"\n aria-label={tr(\"auth.register.firstName\", \"First Name\")}\n value={formData.firstName}\n onChange={(e) =>\n setFormData({ ...formData, firstName: e.target.value })\n }\n className=\"block w-full px-4 py-3 rounded-xl border border-[var(--color-border-default)] bg-[var(--color-bg-surface)] text-[var(--color-text-primary)] placeholder:text-[var(--color-text-tertiary)] focus:outline-none focus:ring-2 focus:ring-action-primary-bg/20 focus:border-action-primary-bg transition-all\"\n placeholder={tr(\n \"auth.register.firstNamePlaceholder\",\n \"Enter first name\",\n )}\n />\n </div>\n <div className=\"space-y-2\">\n <label\n htmlFor=\"lastName\"\n className=\"block text-sm font-medium text-[var(--color-text-primary)]\"\n >\n {tr(\"auth.register.lastName\", \"Last Name\")}\n </label>\n <input\n id=\"lastName\"\n type=\"text\"\n required\n aria-required=\"true\"\n aria-label={tr(\"auth.register.lastName\", \"Last Name\")}\n value={formData.lastName}\n onChange={(e) =>\n setFormData({ ...formData, lastName: e.target.value })\n }\n className=\"block w-full px-4 py-3 rounded-xl border border-[var(--color-border-default)] bg-[var(--color-bg-surface)] text-[var(--color-text-primary)] placeholder:text-[var(--color-text-tertiary)] focus:outline-none focus:ring-2 focus:ring-action-primary-bg/20 focus:border-action-primary-bg transition-all\"\n placeholder={tr(\n \"auth.register.lastNamePlaceholder\",\n \"Enter last name\",\n )}\n />\n </div>\n </div>\n\n {/* Username Input */}\n <div className=\"space-y-2\">\n <label\n htmlFor=\"username\"\n className=\"block text-sm font-medium text-[var(--color-text-primary)]\"\n >\n {tr(\"auth.register.username\", \"Username\")}\n </label>\n <div className=\"relative\">\n <div className=\"absolute inset-y-0 left-0 pl-3.5 flex items-center pointer-events-none\">\n <UserIcon className=\"size-5 text-[var(--color-text-tertiary)]\" />\n </div>\n <input\n id=\"username\"\n type=\"text\"\n required\n aria-required=\"true\"\n aria-label={tr(\"auth.register.username\", \"Username\")}\n autoComplete=\"username\"\n value={formData.username}\n onChange={(e) =>\n setFormData({ ...formData, username: e.target.value })\n }\n className=\"block w-full pl-[3.5rem] pr-4 py-3 rounded-xl border border-[var(--color-border-default)] bg-[var(--color-bg-surface)] text-[var(--color-text-primary)] placeholder:text-[var(--color-text-tertiary)] focus:outline-none focus:ring-2 focus:ring-action-primary-bg/20 focus:border-action-primary-bg transition-all\"\n placeholder={tr(\n \"auth.register.usernamePlaceholder\",\n \"Choose a username\",\n )}\n />\n </div>\n </div>\n\n {/* Email Input */}\n <div className=\"space-y-2\">\n <label\n htmlFor=\"email\"\n className=\"block text-sm font-medium text-[var(--color-text-primary)]\"\n >\n {tr(\"auth.register.email\", \"Email\")}\n </label>\n <div className=\"relative\">\n <div className=\"absolute inset-y-0 left-0 pl-3.5 flex items-center pointer-events-none\">\n <EmailIcon className=\"size-5 text-[var(--color-text-tertiary)]\" />\n </div>\n <input\n id=\"email\"\n type=\"email\"\n required\n aria-required=\"true\"\n aria-label={tr(\"auth.register.email\", \"Email\")}\n autoComplete=\"email\"\n value={formData.email}\n onChange={(e) =>\n setFormData({ ...formData, email: e.target.value })\n }\n className=\"block w-full pl-[3.5rem] pr-4 py-3 rounded-xl border border-[var(--color-border-default)] bg-[var(--color-bg-surface)] text-[var(--color-text-primary)] placeholder:text-[var(--color-text-tertiary)] focus:outline-none focus:ring-2 focus:ring-action-primary-bg/20 focus:border-action-primary-bg transition-all\"\n placeholder={tr(\n \"auth.register.emailPlaceholder\",\n \"you@example.com\",\n )}\n />\n </div>\n </div>\n\n {/* Password Input */}\n <div className=\"space-y-2\">\n <label\n htmlFor=\"password\"\n className=\"block text-sm font-medium text-[var(--color-text-primary)]\"\n >\n {tr(\"auth.register.password\", \"Password\")}\n </label>\n <div className=\"relative\">\n <div className=\"absolute inset-y-0 left-0 pl-3.5 flex items-center pointer-events-none\">\n <LockIcon className=\"size-5 text-[var(--color-text-tertiary)]\" />\n </div>\n <input\n id=\"password\"\n type={showPassword ? \"text\" : \"password\"}\n required\n aria-required=\"true\"\n aria-label={tr(\"auth.register.password\", \"Password\")}\n autoComplete=\"new-password\"\n value={formData.password}\n onChange={(e) =>\n setFormData({ ...formData, password: e.target.value })\n }\n className=\"block w-full pl-[3.5rem] pr-12 py-3 rounded-xl border border-[var(--color-border-default)] bg-[var(--color-bg-surface)] text-[var(--color-text-primary)] placeholder:text-[var(--color-text-tertiary)] focus:outline-none focus:ring-2 focus:ring-action-primary-bg/20 focus:border-action-primary-bg transition-all\"\n placeholder={tr(\n \"auth.register.passwordPlaceholder\",\n \"Create a strong password\",\n )}\n />\n <button\n type=\"button\"\n onClick={() => setShowPassword(!showPassword)}\n aria-label={showPassword ? \"Hide password\" : \"Show password\"}\n className=\"absolute inset-y-0 right-0 pr-3.5 flex items-center text-[var(--color-text-tertiary)] hover:text-[var(--color-text-secondary)] transition-colors\"\n >\n {showPassword ? (\n <EyeOffIcon className=\"size-5\" />\n ) : (\n <EyeIcon className=\"size-5\" />\n )}\n </button>\n </div>\n\n {/* Password Strength Indicator */}\n {formData.password && (\n <div className=\"space-y-3 pt-2\">\n {/* Strength Bar */}\n <div className=\"space-y-1\">\n <div className=\"h-1.5 bg-[var(--color-bg-sunken)] rounded-full overflow-hidden\">\n <div\n className={`h-full ${passwordStrength.color} ${passwordStrength.width} transition-all duration-300`}\n />\n </div>\n <p className=\"text-xs text-[var(--color-text-tertiary)] capitalize\">\n {tr(\"auth.register.passwordStrength\", \"Password strength:\")}{\" \"}\n <span className=\"font-medium\">{passwordStrength.level}</span>\n </p>\n </div>\n\n {/* Requirements Checklist */}\n <div className=\"grid grid-cols-2 gap-2\">\n {passwordChecks.map((check) => (\n <div key={check.label} className=\"flex items-center gap-2\">\n {check.met ? (\n <CheckIcon className=\"size-4 text-status-success-text\" />\n ) : (\n <XIcon className=\"size-4 text-[var(--color-text-tertiary)]\" />\n )}\n <span\n className={`text-xs ${\n check.met\n ? \"text-status-success-text\"\n : \"text-[var(--color-text-tertiary)]\"\n }`}\n >\n {check.label}\n </span>\n </div>\n ))}\n </div>\n </div>\n )}\n </div>\n\n {/* Terms Agreement */}\n <p className=\"text-xs text-[var(--color-text-tertiary)] leading-relaxed\">\n {tr(\n \"auth.register.agreeToTerms\",\n \"By creating an account, you agree to our\",\n )}{\" \"}\n <a\n href=\"/legal/terms\"\n className=\"text-text-link underline underline-offset-2\"\n >\n {tr(\"auth.register.termsOfService\", \"Terms of Service\")}\n </a>{\" \"}\n {tr(\"auth.register.and\", \"and\")}{\" \"}\n <a\n href=\"/legal/privacy\"\n className=\"text-text-link underline underline-offset-2\"\n >\n {tr(\"auth.register.privacyPolicy\", \"Privacy Policy\")}\n </a>\n .\n </p>\n\n {/* reCAPTCHA v2 Checkbox — enabled per-product via the platform catalog.\n `key` remounts it after a failed submit so a fresh token is issued. */}\n <CaptchaV2\n key={captchaResetKey}\n enabled={captchaEnabled}\n siteKey={captchaSiteKey}\n onVerify={setCaptchaToken}\n onExpired={() => setCaptchaToken(null)}\n />\n\n {/* Submit Button */}\n <Button\n type=\"submit\"\n disabled={isLoading}\n variant=\"default\"\n size=\"lg\"\n className=\"w-full font-semibold\"\n >\n {isLoading ? (\n <>\n <SpinnerIcon className=\"size-5 animate-spin\" />\n <span>\n {tr(\"auth.register.creatingAccount\", \"Creating account...\")}\n </span>\n </>\n ) : (\n tr(\"auth.register.createAccountBtn\", \"Create account\")\n )}\n </Button>\n </form>\n\n {/* Divider */}\n <div className=\"relative my-8\">\n <div className=\"absolute inset-0 flex items-center\">\n <div className=\"w-full border-t border-[var(--color-border-default)]\" />\n </div>\n <div className=\"relative flex justify-center\">\n <span className=\"px-4 bg-[var(--color-bg-canvas)] text-sm text-[var(--color-text-tertiary)]\">\n {tr(\"auth.register.orSignUpWith\", \"or sign up with\")}\n </span>\n </div>\n </div>\n\n {/* OAuth Error */}\n {oauthError && (\n <div className=\"flex items-start gap-3 p-4 rounded-xl border bg-status-error-bg-subtle border-status-error-border\">\n <AlertIcon className=\"size-5 flex-shrink-0 mt-0.5 text-status-error-text\" />\n <p className=\"text-sm text-status-error-text\">{oauthError}</p>\n </div>\n )}\n\n {/* OAuth Buttons */}\n <div className=\"grid grid-cols-3 gap-3\">\n {oauthProviders.map((provider) => (\n <button\n key={provider.name}\n type=\"button\"\n onClick={provider.onClick}\n disabled={provider.disabled}\n title={provider.tooltip}\n className={`flex items-center justify-center gap-2 px-4 py-3 rounded-xl border transition-all duration-200 group ${\n provider.disabled\n ? \"border-[var(--color-border-subtle)] bg-[var(--color-bg-disabled)] cursor-not-allowed opacity-50\"\n : \"border-[var(--color-border-default)] bg-[var(--color-bg-surface)] hover:bg-[var(--color-bg-sunken)] hover:border-[var(--color-border-strong)]\"\n }`}\n >\n <provider.icon\n className={`size-5 ${provider.disabled ? \"opacity-50\" : \"\"}`}\n />\n <span\n className={`sr-only sm:not-sr-only text-sm font-medium transition-colors ${\n provider.disabled\n ? \"text-[var(--color-text-disabled)]\"\n : \"text-[var(--color-text-secondary)] group-hover:text-[var(--color-text-primary)]\"\n }`}\n >\n {provider.name}\n </span>\n </button>\n ))}\n </div>\n\n {/* Sign In Link */}\n <p className=\"mt-8 text-center text-sm text-[var(--color-text-secondary)]\">\n {tr(\"auth.register.alreadyHaveAccount\", \"Already have an account?\")}{\" \"}\n <button\n type=\"button\"\n onClick={() => navigate(\"/auth/login\")}\n className=\"font-semibold text-text-link hover:text-text-linkHover transition-colors\"\n >\n {tr(\"auth.register.signIn\", \"Sign in\")}\n </button>\n </p>\n </AuthLayout>\n );\n}\n"],"mappings":"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"}
@@ -1,3 +1,3 @@
1
1
  /*! tailwindcss v4.3.1 | MIT License | https://tailwindcss.com */
2
- @layer properties{@supports (((-webkit-hyphens:none)) and (not (margin-trim:inline))) or ((-moz-orient:inline) and (not (color:rgb(from red r g b)))){*,:before,:after,::backdrop{--tw-space-y-reverse:0;--tw-border-style:solid;--tw-leading:initial;--tw-font-weight:initial;--tw-tracking:initial;--tw-shadow:0 0 #0000;--tw-shadow-color:initial;--tw-shadow-alpha:100%;--tw-inset-shadow:0 0 #0000;--tw-inset-shadow-color:initial;--tw-inset-shadow-alpha:100%;--tw-ring-color:initial;--tw-ring-shadow:0 0 #0000;--tw-inset-ring-color:initial;--tw-inset-ring-shadow:0 0 #0000;--tw-ring-inset:initial;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-offset-shadow:0 0 #0000;--tw-blur:initial;--tw-brightness:initial;--tw-contrast:initial;--tw-grayscale:initial;--tw-hue-rotate:initial;--tw-invert:initial;--tw-opacity:initial;--tw-saturate:initial;--tw-sepia:initial;--tw-drop-shadow:initial;--tw-drop-shadow-color:initial;--tw-drop-shadow-alpha:100%;--tw-drop-shadow-size:initial;--tw-backdrop-blur:initial;--tw-backdrop-brightness:initial;--tw-backdrop-contrast:initial;--tw-backdrop-grayscale:initial;--tw-backdrop-hue-rotate:initial;--tw-backdrop-invert:initial;--tw-backdrop-opacity:initial;--tw-backdrop-saturate:initial;--tw-backdrop-sepia:initial;--tw-duration:initial}}}@layer theme{:root,:host{--font-sans:Inter, ui-sans-serif, system-ui, sans-serif, "Apple Color Emoji", "Segoe UI Emoji";--font-mono:"JetBrains Mono", ui-monospace, monospace;--color-indigo-500:oklch(58.5% .233 277.117);--color-black:#000;--color-white:#fff;--spacing:.25rem;--container-sm:24rem;--container-md:28rem;--container-2xl:42rem;--container-4xl:56rem;--container-5xl:64rem;--container-6xl:72rem;--container-7xl:80rem;--text-xs:.75rem;--text-xs--line-height:calc(1 / .75);--text-sm:.875rem;--text-sm--line-height:calc(1.25 / .875);--text-base:1rem;--text-base--line-height:calc(1.5 / 1);--text-lg:1.125rem;--text-lg--line-height:calc(1.75 / 1.125);--text-xl:1.25rem;--text-xl--line-height:calc(1.75 / 1.25);--text-2xl:1.5rem;--text-2xl--line-height:calc(2 / 1.5);--text-3xl:1.875rem;--text-3xl--line-height:calc(2.25 / 1.875);--text-4xl:2.25rem;--text-4xl--line-height:calc(2.5 / 2.25);--font-weight-medium:500;--font-weight-semibold:600;--font-weight-bold:700;--tracking-widest:.1em;--leading-tight:1.25;--leading-relaxed:1.625;--radius-md:.375rem;--radius-lg:.5rem;--radius-xl:.75rem;--radius-2xl:1rem;--animate-spin:spin 1s linear infinite;--blur-sm:8px;--blur-3xl:64px;--default-transition-duration:.15s;--default-transition-timing-function:cubic-bezier(.4, 0, .2, 1);--default-font-family:var(--font-sans);--default-mono-font-family:var(--font-mono);--radius:.5rem;--color-primary:221.2 83.2% 53.3%}}@layer base{*,:after,:before,::backdrop{box-sizing:border-box;border:0 solid;margin:0;padding:0}::file-selector-button{box-sizing:border-box;border:0 solid;margin:0;padding:0}html,:host{-webkit-text-size-adjust:100%;tab-size:4;line-height:1.5;font-family:var(--default-font-family,ui-sans-serif, system-ui, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji");font-feature-settings:var(--default-font-feature-settings,normal);font-variation-settings:var(--default-font-variation-settings,normal);-webkit-tap-highlight-color:transparent}hr{height:0;color:inherit;border-top-width:1px}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;-webkit-text-decoration:inherit;-webkit-text-decoration:inherit;-webkit-text-decoration:inherit;-webkit-text-decoration:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,samp,pre{font-family:var(--default-mono-font-family,ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace);font-feature-settings:var(--default-mono-font-feature-settings,normal);font-variation-settings:var(--default-mono-font-variation-settings,normal);font-size:1em}small{font-size:80%}sub,sup{vertical-align:baseline;font-size:75%;line-height:0;position:relative}sub{bottom:-.25em}sup{top:-.5em}table{text-indent:0;border-color:inherit;border-collapse:collapse}:-moz-focusring{outline:auto}progress{vertical-align:baseline}summary{display:list-item}ol,ul,menu{list-style:none}img,svg,video,canvas,audio,iframe,embed,object{vertical-align:middle;display:block}img,video{max-width:100%;height:auto}button,input,select,optgroup,textarea{font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;color:inherit;opacity:1;background-color:#0000;border-radius:0}::file-selector-button{font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;color:inherit;opacity:1;background-color:#0000;border-radius:0}:where(select:is([multiple],[size])) optgroup{font-weight:bolder}:where(select:is([multiple],[size])) optgroup option{padding-inline-start:20px}::file-selector-button{margin-inline-end:4px}::placeholder{opacity:1}@supports (not ((-webkit-appearance:-apple-pay-button))) or (contain-intrinsic-size:1px){::placeholder{color:currentColor}@supports (color:color-mix(in lab, red, red)){::placeholder{color:color-mix(in oklab, currentcolor 50%, transparent)}}}textarea{resize:vertical}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-date-and-time-value{min-height:1lh;text-align:inherit}::-webkit-datetime-edit{display:inline-flex}::-webkit-datetime-edit-fields-wrapper{padding:0}::-webkit-datetime-edit{padding-block:0}::-webkit-datetime-edit-year-field{padding-block:0}::-webkit-datetime-edit-month-field{padding-block:0}::-webkit-datetime-edit-day-field{padding-block:0}::-webkit-datetime-edit-hour-field{padding-block:0}::-webkit-datetime-edit-minute-field{padding-block:0}::-webkit-datetime-edit-second-field{padding-block:0}::-webkit-datetime-edit-millisecond-field{padding-block:0}::-webkit-datetime-edit-meridiem-field{padding-block:0}::-webkit-calendar-picker-indicator{line-height:1}:-moz-ui-invalid{box-shadow:none}button,input:where([type=button],[type=reset],[type=submit]){appearance:button}::file-selector-button{appearance:button}::-webkit-inner-spin-button{height:auto}::-webkit-outer-spin-button{height:auto}[hidden]:where(:not([hidden=until-found])){display:none!important}}@layer components;@layer utilities{.pointer-events-none{pointer-events:none}.invisible{visibility:hidden}.visible{visibility:visible}.sr-only{clip-path:inset(50%);white-space:nowrap;border-width:0;width:1px;height:1px;margin:-1px;padding:0;position:absolute;overflow:hidden}.absolute{position:absolute}.fixed{position:fixed}.relative{position:relative}.static{position:static}.inset-0{inset:0}.inset-y-0{inset-block:0}.-top-40{top:calc(var(--spacing) * -40)}.top-0{top:0}.top-1\/2{top:50%}.top-4{top:calc(var(--spacing) * 4)}.top-full{top:100%}.-right-20{right:calc(var(--spacing) * -20)}.right-0{right:0}.right-4{right:calc(var(--spacing) * 4)}.-bottom-40{bottom:calc(var(--spacing) * -40)}.bottom-0{bottom:0}.-left-40{left:calc(var(--spacing) * -40)}.left-0{left:0}.left-1\/4{left:25%}.z-10{z-index:10}.z-50{z-index:50}.container{width:100%}@media (width>=40rem){.container{max-width:40rem}}@media (width>=48rem){.container{max-width:48rem}}@media (width>=64rem){.container{max-width:64rem}}@media (width>=80rem){.container{max-width:80rem}}@media (width>=96rem){.container{max-width:96rem}}.mx-4{margin-inline:calc(var(--spacing) * 4)}.mx-auto{margin-inline:auto}.my-8{margin-block:calc(var(--spacing) * 8)}.mt-0\.5{margin-top:calc(var(--spacing) * .5)}.mt-1{margin-top:var(--spacing)}.mt-2{margin-top:calc(var(--spacing) * 2)}.mt-3{margin-top:calc(var(--spacing) * 3)}.mt-4{margin-top:calc(var(--spacing) * 4)}.mt-6{margin-top:calc(var(--spacing) * 6)}.mt-8{margin-top:calc(var(--spacing) * 8)}.mt-10{margin-top:calc(var(--spacing) * 10)}.mt-12{margin-top:calc(var(--spacing) * 12)}.mb-1{margin-bottom:var(--spacing)}.mb-2{margin-bottom:calc(var(--spacing) * 2)}.mb-3{margin-bottom:calc(var(--spacing) * 3)}.mb-4{margin-bottom:calc(var(--spacing) * 4)}.mb-5{margin-bottom:calc(var(--spacing) * 5)}.mb-6{margin-bottom:calc(var(--spacing) * 6)}.mb-8{margin-bottom:calc(var(--spacing) * 8)}.ml-3{margin-left:calc(var(--spacing) * 3)}.ml-4{margin-left:calc(var(--spacing) * 4)}.ml-auto{margin-left:auto}.block{display:block}.contents{display:contents}.flex{display:flex}.grid{display:grid}.hidden{display:none}.inline{display:inline}.inline-block{display:inline-block}.inline-flex{display:inline-flex}.table{display:table}.size-2{width:calc(var(--spacing) * 2);height:calc(var(--spacing) * 2)}.size-3{width:calc(var(--spacing) * 3);height:calc(var(--spacing) * 3)}.size-4{width:calc(var(--spacing) * 4);height:calc(var(--spacing) * 4)}.size-5{width:calc(var(--spacing) * 5);height:calc(var(--spacing) * 5)}.size-6{width:calc(var(--spacing) * 6);height:calc(var(--spacing) * 6)}.size-8{width:calc(var(--spacing) * 8);height:calc(var(--spacing) * 8)}.size-10{width:calc(var(--spacing) * 10);height:calc(var(--spacing) * 10)}.size-12{width:calc(var(--spacing) * 12);height:calc(var(--spacing) * 12)}.size-14{width:calc(var(--spacing) * 14);height:calc(var(--spacing) * 14)}.size-16{width:calc(var(--spacing) * 16);height:calc(var(--spacing) * 16)}.size-20{width:calc(var(--spacing) * 20);height:calc(var(--spacing) * 20)}.size-48{width:calc(var(--spacing) * 48);height:calc(var(--spacing) * 48)}.size-72{width:calc(var(--spacing) * 72);height:calc(var(--spacing) * 72)}.size-80{width:calc(var(--spacing) * 80);height:calc(var(--spacing) * 80)}.size-96{width:calc(var(--spacing) * 96);height:calc(var(--spacing) * 96)}.size-full{width:100%;height:100%}.h-0\.5{height:calc(var(--spacing) * .5)}.h-1\.5{height:calc(var(--spacing) * 1.5)}.h-12{height:calc(var(--spacing) * 12)}.h-full{height:100%}.min-h-\[400px\]{min-height:400px}.min-h-screen{min-height:100vh}.w-1\/4{width:25%}.w-2\/4{width:50%}.w-3\/4{width:75%}.w-10{width:calc(var(--spacing) * 10)}.w-48{width:calc(var(--spacing) * 48)}.w-64{width:calc(var(--spacing) * 64)}.w-\[80px\]{width:80px}.w-\[100px\]{width:100px}.w-\[130px\]{width:130px}.w-\[180px\]{width:180px}.w-\[280px\]{width:280px}.w-full{width:100%}.max-w-2xl{max-width:var(--container-2xl)}.max-w-4xl{max-width:var(--container-4xl)}.max-w-5xl{max-width:var(--container-5xl)}.max-w-6xl{max-width:var(--container-6xl)}.max-w-7xl{max-width:var(--container-7xl)}.max-w-md{max-width:var(--container-md)}.max-w-sm{max-width:var(--container-sm)}.min-w-0{min-width:0}.min-w-\[200px\]{min-width:200px}.min-w-\[800px\]{min-width:800px}.flex-1{flex:1}.flex-shrink-0{flex-shrink:0}.shrink{flex-shrink:1}.shrink-0{flex-shrink:0}.rotate-180{rotate:180deg}.animate-spin{animation:var(--animate-spin)}.cursor-not-allowed{cursor:not-allowed}.cursor-pointer{cursor:pointer}.list-inside{list-style-position:inside}.list-disc{list-style-type:disc}.grid-cols-1{grid-template-columns:repeat(1,minmax(0,1fr))}.grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.grid-cols-3{grid-template-columns:repeat(3,minmax(0,1fr))}.flex-col{flex-direction:column}.flex-nowrap{flex-wrap:nowrap}.flex-wrap{flex-wrap:wrap}.items-center{align-items:center}.items-end{align-items:flex-end}.items-start{align-items:flex-start}.justify-between{justify-content:space-between}.justify-center{justify-content:center}.justify-end{justify-content:flex-end}.gap-1{gap:var(--spacing)}.gap-1\.5{gap:calc(var(--spacing) * 1.5)}.gap-2{gap:calc(var(--spacing) * 2)}.gap-3{gap:calc(var(--spacing) * 3)}.gap-4{gap:calc(var(--spacing) * 4)}.gap-6{gap:calc(var(--spacing) * 6)}:where(.space-y-1>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(var(--spacing) * var(--tw-space-y-reverse));margin-block-end:calc(var(--spacing) * calc(1 - var(--tw-space-y-reverse)))}:where(.space-y-2>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing) * 2) * var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing) * 2) * calc(1 - var(--tw-space-y-reverse)))}:where(.space-y-3>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing) * 3) * var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing) * 3) * calc(1 - var(--tw-space-y-reverse)))}:where(.space-y-4>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing) * 4) * var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing) * 4) * calc(1 - var(--tw-space-y-reverse)))}:where(.space-y-5>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing) * 5) * var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing) * 5) * calc(1 - var(--tw-space-y-reverse)))}:where(.space-y-6>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing) * 6) * var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing) * 6) * calc(1 - var(--tw-space-y-reverse)))}:where(.space-y-8>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing) * 8) * var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing) * 8) * calc(1 - var(--tw-space-y-reverse)))}.truncate{text-overflow:ellipsis;white-space:nowrap;overflow:hidden}.overflow-hidden{overflow:hidden}.overflow-x-auto{overflow-x:auto}.rounded{border-radius:var(--radius)}.rounded-2xl{border-radius:var(--radius-2xl)}.rounded-full{border-radius:3.40282e38px}.rounded-lg{border-radius:var(--radius-lg)}.rounded-md{border-radius:var(--radius-md)}.rounded-xl{border-radius:var(--radius-xl)}.border{border-style:var(--tw-border-style);border-width:1px}.border-2{border-style:var(--tw-border-style);border-width:2px}.border-4{border-style:var(--tw-border-style);border-width:4px}.border-t{border-top-style:var(--tw-border-style);border-top-width:1px}.border-b{border-bottom-style:var(--tw-border-style);border-bottom-width:1px}.border-b-2{border-bottom-style:var(--tw-border-style);border-bottom-width:2px}.border-dashed{--tw-border-style:dashed;border-style:dashed}.border-\[var\(--color-accent-primary\)\]{border-color:var(--color-accent-primary)}.border-\[var\(--color-border-default\)\]{border-color:var(--color-border-default)}.border-\[var\(--color-border-primary\)\]{border-color:var(--color-border-primary)}.border-\[var\(--color-border-subtle\)\]{border-color:var(--color-border-subtle)}.border-\[var\(--color-status-error-border\)\]{border-color:var(--color-status-error-border)}.border-\[var\(--color-status-success-border\)\]{border-color:var(--color-status-success-border)}.border-\[var\(--color-status-warning-border\)\]{border-color:var(--color-status-warning-border)}.border-primary{border-color:var(--color-primary)}.border-t-transparent{border-top-color:#0000}.bg-\[var\(--color-accent-primary\)\]{background-color:var(--color-accent-primary)}.bg-\[var\(--color-action-primary-bg\)\]{background-color:var(--color-action-primary-bg)}.bg-\[var\(--color-action-secondary-bg-subtle\)\]{background-color:var(--color-action-secondary-bg-subtle)}.bg-\[var\(--color-background-base\)\]{background-color:var(--color-background-base)}.bg-\[var\(--color-bg-accent\)\]{background-color:var(--color-bg-accent)}.bg-\[var\(--color-bg-canvas\)\]{background-color:var(--color-bg-canvas)}.bg-\[var\(--color-bg-disabled\)\]{background-color:var(--color-bg-disabled)}.bg-\[var\(--color-bg-muted\)\]{background-color:var(--color-bg-muted)}.bg-\[var\(--color-bg-sunken\)\]{background-color:var(--color-bg-sunken)}.bg-\[var\(--color-bg-surface\)\]{background-color:var(--color-bg-surface)}.bg-\[var\(--color-status-error-bg\)\]{background-color:var(--color-status-error-bg)}.bg-\[var\(--color-status-error-bg-subtle\)\]{background-color:var(--color-status-error-bg-subtle)}.bg-\[var\(--color-status-error-subtle\)\]{background-color:var(--color-status-error-subtle)}.bg-\[var\(--color-status-info-bg-subtle\)\]{background-color:var(--color-status-info-bg-subtle)}.bg-\[var\(--color-status-success-bg-subtle\)\]{background-color:var(--color-status-success-bg-subtle)}.bg-\[var\(--color-status-success-subtle\)\]{background-color:var(--color-status-success-subtle)}.bg-\[var\(--color-status-warning-bg\)\]{background-color:var(--color-status-warning-bg)}.bg-\[var\(--color-status-warning-bg-subtle\)\]{background-color:var(--color-status-warning-bg-subtle)}.bg-black\/40{background-color:#0006}@supports (color:color-mix(in lab, red, red)){.bg-black\/40{background-color:color-mix(in oklab, var(--color-black) 40%, transparent)}}.bg-black\/50{background-color:#00000080}@supports (color:color-mix(in lab, red, red)){.bg-black\/50{background-color:color-mix(in oklab, var(--color-black) 50%, transparent)}}.object-contain{-o-object-fit:contain;object-fit:contain}.object-cover{-o-object-fit:cover;object-fit:cover}.p-0\.5{padding:calc(var(--spacing) * .5)}.p-2{padding:calc(var(--spacing) * 2)}.p-3{padding:calc(var(--spacing) * 3)}.p-4{padding:calc(var(--spacing) * 4)}.p-5{padding:calc(var(--spacing) * 5)}.p-6{padding:calc(var(--spacing) * 6)}.p-8{padding:calc(var(--spacing) * 8)}.p-12{padding:calc(var(--spacing) * 12)}.px-1{padding-inline:var(--spacing)}.px-2{padding-inline:calc(var(--spacing) * 2)}.px-2\.5{padding-inline:calc(var(--spacing) * 2.5)}.px-3{padding-inline:calc(var(--spacing) * 3)}.px-4{padding-inline:calc(var(--spacing) * 4)}.px-5{padding-inline:calc(var(--spacing) * 5)}.px-6{padding-inline:calc(var(--spacing) * 6)}.py-0\.5{padding-block:calc(var(--spacing) * .5)}.py-1{padding-block:var(--spacing)}.py-1\.5{padding-block:calc(var(--spacing) * 1.5)}.py-2{padding-block:calc(var(--spacing) * 2)}.py-2\.5{padding-block:calc(var(--spacing) * 2.5)}.py-3{padding-block:calc(var(--spacing) * 3)}.py-6{padding-block:calc(var(--spacing) * 6)}.py-8{padding-block:calc(var(--spacing) * 8)}.py-12{padding-block:calc(var(--spacing) * 12)}.py-16{padding-block:calc(var(--spacing) * 16)}.pt-2{padding-top:calc(var(--spacing) * 2)}.pt-4{padding-top:calc(var(--spacing) * 4)}.pt-6{padding-top:calc(var(--spacing) * 6)}.pt-12{padding-top:calc(var(--spacing) * 12)}.pr-3\.5{padding-right:calc(var(--spacing) * 3.5)}.pr-4{padding-right:calc(var(--spacing) * 4)}.pr-12{padding-right:calc(var(--spacing) * 12)}.pb-3{padding-bottom:calc(var(--spacing) * 3)}.pl-3{padding-left:calc(var(--spacing) * 3)}.pl-3\.5{padding-left:calc(var(--spacing) * 3.5)}.pl-\[3\.5rem\]{padding-left:3.5rem}.pl-\[3\.25rem\]{padding-left:3.25rem}.text-center{text-align:center}.text-left{text-align:left}.text-right{text-align:right}.font-mono{font-family:var(--font-mono)}.text-2xl{font-size:var(--text-2xl);line-height:var(--tw-leading,var(--text-2xl--line-height))}.text-3xl{font-size:var(--text-3xl);line-height:var(--tw-leading,var(--text-3xl--line-height))}.text-4xl{font-size:var(--text-4xl);line-height:var(--tw-leading,var(--text-4xl--line-height))}.text-base{font-size:var(--text-base);line-height:var(--tw-leading,var(--text-base--line-height))}.text-lg{font-size:var(--text-lg);line-height:var(--tw-leading,var(--text-lg--line-height))}.text-sm{font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height))}.text-xl{font-size:var(--text-xl);line-height:var(--tw-leading,var(--text-xl--line-height))}.text-xs{font-size:var(--text-xs);line-height:var(--tw-leading,var(--text-xs--line-height))}.leading-none{--tw-leading:1;line-height:1}.leading-relaxed{--tw-leading:var(--leading-relaxed);line-height:var(--leading-relaxed)}.leading-tight{--tw-leading:var(--leading-tight);line-height:var(--leading-tight)}.font-bold{--tw-font-weight:var(--font-weight-bold);font-weight:var(--font-weight-bold)}.font-medium{--tw-font-weight:var(--font-weight-medium);font-weight:var(--font-weight-medium)}.font-semibold{--tw-font-weight:var(--font-weight-semibold);font-weight:var(--font-weight-semibold)}.tracking-widest{--tw-tracking:var(--tracking-widest);letter-spacing:var(--tracking-widest)}.break-all{word-break:break-all}.whitespace-nowrap{white-space:nowrap}.text-\[var\(--color-accent-primary\)\]{color:var(--color-accent-primary)}.text-\[var\(--color-action-primary-bg\)\]{color:var(--color-action-primary-bg)}.text-\[var\(--color-action-primary-text\)\]{color:var(--color-action-primary-text)}.text-\[var\(--color-action-secondary-text\)\]{color:var(--color-action-secondary-text)}.text-\[var\(--color-status-error\)\]{color:var(--color-status-error)}.text-\[var\(--color-status-error-text\)\]{color:var(--color-status-error-text)}.text-\[var\(--color-status-info-text\)\]{color:var(--color-status-info-text)}.text-\[var\(--color-status-success\)\]{color:var(--color-status-success)}.text-\[var\(--color-status-success-text\)\]{color:var(--color-status-success-text)}.text-\[var\(--color-status-warning-text\)\]{color:var(--color-status-warning-text)}.text-\[var\(--color-text-disabled\)\]{color:var(--color-text-disabled)}.text-\[var\(--color-text-inverse\)\]{color:var(--color-text-inverse)}.text-\[var\(--color-text-link\)\]{color:var(--color-text-link)}.text-\[var\(--color-text-primary\)\]{color:var(--color-text-primary)}.text-\[var\(--color-text-secondary\)\]{color:var(--color-text-secondary)}.text-\[var\(--color-text-tertiary\)\]{color:var(--color-text-tertiary)}.text-white{color:var(--color-white)}.capitalize{text-transform:capitalize}.lowercase{text-transform:lowercase}.uppercase{text-transform:uppercase}.underline{text-decoration-line:underline}.underline-offset-2{text-underline-offset:2px}.placeholder-\[var\(--color-text-secondary\)\]::placeholder{color:var(--color-text-secondary)}.opacity-0{opacity:0}.opacity-5{opacity:.05}.opacity-25{opacity:.25}.opacity-50{opacity:.5}.opacity-75{opacity:.75}.shadow-2xl{--tw-shadow:0 25px 50px -12px var(--tw-shadow-color,#00000040);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.shadow-lg{--tw-shadow:0 10px 15px -3px var(--tw-shadow-color,#0000001a), 0 4px 6px -4px var(--tw-shadow-color,#0000001a);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.shadow-sm{--tw-shadow:0 1px 3px 0 var(--tw-shadow-color,#0000001a), 0 1px 2px -1px var(--tw-shadow-color,#0000001a);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.shadow-xl{--tw-shadow:0 20px 25px -5px var(--tw-shadow-color,#0000001a), 0 8px 10px -6px var(--tw-shadow-color,#0000001a);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.blur-3xl{--tw-blur:blur(var(--blur-3xl));filter:var(--tw-blur,) var(--tw-brightness,) var(--tw-contrast,) var(--tw-grayscale,) var(--tw-hue-rotate,) var(--tw-invert,) var(--tw-saturate,) var(--tw-sepia,) var(--tw-drop-shadow,)}.filter{filter:var(--tw-blur,) var(--tw-brightness,) var(--tw-contrast,) var(--tw-grayscale,) var(--tw-hue-rotate,) var(--tw-invert,) var(--tw-saturate,) var(--tw-sepia,) var(--tw-drop-shadow,)}.backdrop-blur-sm{--tw-backdrop-blur:blur(var(--blur-sm));-webkit-backdrop-filter:var(--tw-backdrop-blur,) var(--tw-backdrop-brightness,) var(--tw-backdrop-contrast,) var(--tw-backdrop-grayscale,) var(--tw-backdrop-hue-rotate,) var(--tw-backdrop-invert,) var(--tw-backdrop-opacity,) var(--tw-backdrop-saturate,) var(--tw-backdrop-sepia,);backdrop-filter:var(--tw-backdrop-blur,) var(--tw-backdrop-brightness,) var(--tw-backdrop-contrast,) var(--tw-backdrop-grayscale,) var(--tw-backdrop-hue-rotate,) var(--tw-backdrop-invert,) var(--tw-backdrop-opacity,) var(--tw-backdrop-saturate,) var(--tw-backdrop-sepia,)}.transition{transition-property:color,background-color,border-color,outline-color,text-decoration-color,fill,stroke,--tw-gradient-from,--tw-gradient-via,--tw-gradient-to,opacity,box-shadow,transform,translate,scale,rotate,filter,-webkit-backdrop-filter,backdrop-filter,display,content-visibility,overlay,pointer-events;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.transition-all{transition-property:all;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.transition-colors{transition-property:color,background-color,border-color,outline-color,text-decoration-color,fill,stroke,--tw-gradient-from,--tw-gradient-via,--tw-gradient-to;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.transition-opacity{transition-property:opacity;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.transition-shadow{transition-property:box-shadow;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.transition-transform{transition-property:transform,translate,scale,rotate;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.duration-200{--tw-duration:.2s;transition-duration:.2s}.duration-300{--tw-duration:.3s;transition-duration:.3s}.outline-none{--tw-outline-style:none;outline-style:none}.select-all{-webkit-user-select:all;user-select:all}@media (hover:hover){.group-hover\:bg-\[var\(--color-action-primary-bg-subtle\)\]:is(:where(.group):hover *){background-color:var(--color-action-primary-bg-subtle)}.group-hover\:bg-\[var\(--color-action-secondary-bg-subtle\)\]:is(:where(.group):hover *){background-color:var(--color-action-secondary-bg-subtle)}.group-hover\:text-\[var\(--color-text-primary\)\]:is(:where(.group):hover *){color:var(--color-text-primary)}.group-hover\:text-indigo-500:is(:where(.group):hover *){color:var(--color-indigo-500)}.group-hover\:opacity-100:is(:where(.group):hover *){opacity:1}}.peer-checked\:opacity-100:is(:where(.peer):checked~*){opacity:1}.peer-focus\:ring-2:is(:where(.peer):focus~*){--tw-ring-shadow:var(--tw-ring-inset,) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color,currentcolor);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.placeholder\:text-\[var\(--color-text-tertiary\)\]::placeholder{color:var(--color-text-tertiary)}.last\:border-b-0:last-child{border-bottom-style:var(--tw-border-style);border-bottom-width:0}@media (hover:hover){.hover\:border-\[var\(--color-action-primary-border\)\]:hover{border-color:var(--color-action-primary-border)}.hover\:border-\[var\(--color-action-secondary-border\)\]:hover{border-color:var(--color-action-secondary-border)}.hover\:border-\[var\(--color-border-strong\)\]:hover{border-color:var(--color-border-strong)}.hover\:bg-\[var\(--color-accent-primary-hover\)\]:hover{background-color:var(--color-accent-primary-hover)}.hover\:bg-\[var\(--color-action-primary-bgHover\)\]:hover{background-color:var(--color-action-primary-bgHover)}.hover\:bg-\[var\(--color-bg-muted\)\]:hover{background-color:var(--color-bg-muted)}.hover\:bg-\[var\(--color-bg-subtle\)\]:hover{background-color:var(--color-bg-subtle)}.hover\:bg-\[var\(--color-bg-sunken\)\]:hover{background-color:var(--color-bg-sunken)}.hover\:bg-\[var\(--color-status-error-bg-subtle\)\]:hover{background-color:var(--color-status-error-bg-subtle)}.hover\:text-\[var\(--color-text-primary\)\]:hover{color:var(--color-text-primary)}.hover\:text-\[var\(--color-text-secondary\)\]:hover{color:var(--color-text-secondary)}.hover\:underline:hover{text-decoration-line:underline}.hover\:opacity-90:hover{opacity:.9}.hover\:shadow-lg:hover{--tw-shadow:0 10px 15px -3px var(--tw-shadow-color,#0000001a), 0 4px 6px -4px var(--tw-shadow-color,#0000001a);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.hover\:shadow-md:hover{--tw-shadow:0 4px 6px -1px var(--tw-shadow-color,#0000001a), 0 2px 4px -2px var(--tw-shadow-color,#0000001a);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}}.focus\:border-primary:focus{border-color:var(--color-primary)}.focus\:border-transparent:focus{border-color:#0000}.focus\:ring-2:focus{--tw-ring-shadow:var(--tw-ring-inset,) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color,currentcolor);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.focus\:ring-\[var\(--color-accent-primary\)\]:focus{--tw-ring-color:var(--color-accent-primary)}.focus\:ring-primary\/20:focus{--tw-ring-color:color-mix(in srgb, 221.2 83.2% 53.3% 20%, transparent)}@supports (color:color-mix(in lab, red, red)){.focus\:ring-primary\/20:focus{--tw-ring-color:color-mix(in oklab, var(--color-primary) 20%, transparent)}}.focus\:outline-none:focus{--tw-outline-style:none;outline-style:none}.disabled\:cursor-not-allowed:disabled{cursor:not-allowed}.disabled\:opacity-40:disabled{opacity:.4}.disabled\:opacity-50:disabled{opacity:.5}.disabled\:opacity-60:disabled{opacity:.6}@media (width>=40rem){.sm\:not-sr-only{clip-path:none;white-space:normal;width:auto;height:auto;margin:0;padding:0;position:static;overflow:visible}.sm\:top-6{top:calc(var(--spacing) * 6)}.sm\:right-6{right:calc(var(--spacing) * 6)}.sm\:col-span-2{grid-column:span 2/span 2}.sm\:block{display:block}.sm\:inline{display:inline}.sm\:h-14{height:calc(var(--spacing) * 14)}.sm\:w-12{width:calc(var(--spacing) * 12)}.sm\:w-auto{width:auto}.sm\:grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.sm\:flex-row{flex-direction:row}.sm\:items-center{align-items:center}.sm\:justify-between{justify-content:space-between}.sm\:gap-3{gap:calc(var(--spacing) * 3)}.sm\:p-12{padding:calc(var(--spacing) * 12)}.sm\:text-2xl{font-size:var(--text-2xl);line-height:var(--tw-leading,var(--text-2xl--line-height))}.sm\:text-3xl{font-size:var(--text-3xl);line-height:var(--tw-leading,var(--text-3xl--line-height))}}@media (width>=48rem){.md\:col-span-2{grid-column:span 2/span 2}.md\:grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.md\:grid-cols-3{grid-template-columns:repeat(3,minmax(0,1fr))}.md\:flex-row{flex-direction:row}.md\:items-center{align-items:center}.md\:justify-between{justify-content:space-between}}@media (width>=64rem){.lg\:col-span-1{grid-column:span 1/span 1}.lg\:flex{display:flex}.lg\:hidden{display:none}.lg\:w-1\/2{width:50%}.lg\:grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.lg\:grid-cols-3{grid-template-columns:repeat(3,minmax(0,1fr))}.lg\:grid-cols-4{grid-template-columns:repeat(4,minmax(0,1fr))}.lg\:text-left{text-align:left}}}.dark{--color-background:222.2 84% 4.9%;--color-foreground:210 40% 98%;--color-card:222.2 84% 4.9%;--color-card-foreground:210 40% 98%;--color-popover:222.2 84% 4.9%;--color-popover-foreground:210 40% 98%;--color-primary:217.2 91.2% 59.8%;--color-primary-foreground:222.2 47.4% 11.2%;--color-secondary:217.2 32.6% 17.5%;--color-secondary-foreground:210 40% 98%;--color-muted:217.2 32.6% 17.5%;--color-muted-foreground:215 20.2% 65.1%;--color-accent:217.2 32.6% 17.5%;--color-accent-foreground:210 40% 98%;--color-destructive:0 62.8% 30.6%;--color-destructive-foreground:210 40% 98%;--color-border:217.2 32.6% 17.5%;--color-input:217.2 32.6% 17.5%;--color-ring:224.3 76.3% 48%}body{font-feature-settings:"rlig" 1, "calt" 1}.auth-primary-button{background:var(--color-action-primary-bg);color:var(--color-action-primary-text);box-shadow:0 12px 30px var(--color-action-primary-bg);border-radius:.75rem}@supports (color:color-mix(in lab, red, red)){.auth-primary-button{box-shadow:0 12px 30px color-mix(in srgb, var(--color-action-primary-bg) 24%, transparent)}}.auth-primary-button{transition:opacity .16s,transform .16s,box-shadow .16s,background-color .16s}.auth-primary-button:hover{opacity:.96;box-shadow:0 16px 36px var(--color-action-primary-bg)}@supports (color:color-mix(in lab, red, red)){.auth-primary-button:hover{box-shadow:0 16px 36px color-mix(in srgb, var(--color-action-primary-bg) 30%, transparent)}}.auth-primary-button:focus-visible{outline:2px solid var(--color-action-primary-bg)}@supports (color:color-mix(in lab, red, red)){.auth-primary-button:focus-visible{outline:2px solid color-mix(in srgb, var(--color-action-primary-bg) 45%, transparent)}}.auth-primary-button:focus-visible{outline-offset:2px}.auth-primary-button:disabled{cursor:not-allowed;opacity:.55;box-shadow:none}.auth-brand-badge{background:linear-gradient(135deg, var(--color-action-primary-bg) 0%, var(--color-action-primary-bg) 100%)}@supports (color:color-mix(in lab, red, red)){.auth-brand-badge{background:linear-gradient(135deg, color-mix(in srgb, var(--color-action-primary-bg) 92%, white 8%) 0%, color-mix(in srgb, var(--color-action-primary-bg) 72%, var(--color-bg-surface) 28%) 100%)}}.auth-brand-badge{color:var(--color-action-primary-text);box-shadow:0 12px 30px var(--color-action-primary-bg)}@supports (color:color-mix(in lab, red, red)){.auth-brand-badge{box-shadow:0 12px 30px color-mix(in srgb, var(--color-action-primary-bg) 22%, transparent)}}.auth-brand-panel{background:radial-gradient(circle at top left, var(--color-action-primary-bg) 0%, transparent 35%), radial-gradient(circle at bottom right, var(--color-text-link) 0%, transparent 38%), linear-gradient(135deg, var(--color-bg-surface) 0%, var(--color-bg-canvas) 100%)}@supports (color:color-mix(in lab, red, red)){.auth-brand-panel{background:radial-gradient(circle at top left, color-mix(in srgb, var(--color-action-primary-bg) 20%, transparent) 0%, transparent 35%), radial-gradient(circle at bottom right, color-mix(in srgb, var(--color-text-link) 18%, transparent) 0%, transparent 38%), linear-gradient(135deg, color-mix(in srgb, var(--color-bg-surface) 92%, black 8%) 0%, color-mix(in srgb, var(--color-bg-canvas) 70%, black 30%) 100%)}}.auth-brand-panel,.auth-brand-copy{color:var(--color-text-primary)}@supports (color:color-mix(in lab, red, red)){.auth-brand-copy{color:color-mix(in srgb, var(--color-text-primary) 88%, white 12%)}}.auth-brand-copy-muted{color:var(--color-text-secondary)}@supports (color:color-mix(in lab, red, red)){.auth-brand-copy-muted{color:color-mix(in srgb, var(--color-text-secondary) 75%, white 25%)}}.auth-highlight-chip{background:var(--color-bg-surface)}@supports (color:color-mix(in lab, red, red)){.auth-highlight-chip{background:color-mix(in srgb, var(--color-bg-surface) 84%, transparent)}}.auth-highlight-chip{border:1px solid var(--color-border-subtle)}@supports (color:color-mix(in lab, red, red)){.auth-highlight-chip{border:1px solid color-mix(in srgb, var(--color-border-subtle) 65%, transparent)}}.auth-highlight-chip{-webkit-backdrop-filter:blur(14px);backdrop-filter:blur(14px)}.auth-shell-gradient{background:linear-gradient(180deg, var(--color-bg-canvas) 0%, var(--color-bg-surface) 100%)}@supports (color:color-mix(in lab, red, red)){.auth-shell-gradient{background:linear-gradient(180deg, color-mix(in srgb, var(--color-bg-canvas) 96%, transparent) 0%, color-mix(in srgb, var(--color-bg-surface) 96%, transparent) 100%)}}.auth-hero-card{background:linear-gradient(135deg, var(--color-action-primary-bg) 0%, var(--color-text-link) 100%)}@supports (color:color-mix(in lab, red, red)){.auth-hero-card{background:linear-gradient(135deg, color-mix(in srgb, var(--color-action-primary-bg) 90%, transparent) 0%, color-mix(in srgb, var(--color-text-link) 70%, var(--color-action-primary-bg) 30%) 100%)}}.auth-hero-card{color:var(--color-action-primary-text);box-shadow:0 18px 42px var(--color-action-primary-bg)}@supports (color:color-mix(in lab, red, red)){.auth-hero-card{box-shadow:0 18px 42px color-mix(in srgb, var(--color-action-primary-bg) 26%, transparent)}}@property --tw-space-y-reverse{syntax:"*";inherits:false;initial-value:0}@property --tw-border-style{syntax:"*";inherits:false;initial-value:solid}@property --tw-leading{syntax:"*";inherits:false}@property --tw-font-weight{syntax:"*";inherits:false}@property --tw-tracking{syntax:"*";inherits:false}@property --tw-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-shadow-color{syntax:"*";inherits:false}@property --tw-shadow-alpha{syntax:"<percentage>";inherits:false;initial-value:100%}@property --tw-inset-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-inset-shadow-color{syntax:"*";inherits:false}@property --tw-inset-shadow-alpha{syntax:"<percentage>";inherits:false;initial-value:100%}@property --tw-ring-color{syntax:"*";inherits:false}@property --tw-ring-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-inset-ring-color{syntax:"*";inherits:false}@property --tw-inset-ring-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-ring-inset{syntax:"*";inherits:false}@property --tw-ring-offset-width{syntax:"<length>";inherits:false;initial-value:0}@property --tw-ring-offset-color{syntax:"*";inherits:false;initial-value:#fff}@property --tw-ring-offset-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-blur{syntax:"*";inherits:false}@property --tw-brightness{syntax:"*";inherits:false}@property --tw-contrast{syntax:"*";inherits:false}@property --tw-grayscale{syntax:"*";inherits:false}@property --tw-hue-rotate{syntax:"*";inherits:false}@property --tw-invert{syntax:"*";inherits:false}@property --tw-opacity{syntax:"*";inherits:false}@property --tw-saturate{syntax:"*";inherits:false}@property --tw-sepia{syntax:"*";inherits:false}@property --tw-drop-shadow{syntax:"*";inherits:false}@property --tw-drop-shadow-color{syntax:"*";inherits:false}@property --tw-drop-shadow-alpha{syntax:"<percentage>";inherits:false;initial-value:100%}@property --tw-drop-shadow-size{syntax:"*";inherits:false}@property --tw-backdrop-blur{syntax:"*";inherits:false}@property --tw-backdrop-brightness{syntax:"*";inherits:false}@property --tw-backdrop-contrast{syntax:"*";inherits:false}@property --tw-backdrop-grayscale{syntax:"*";inherits:false}@property --tw-backdrop-hue-rotate{syntax:"*";inherits:false}@property --tw-backdrop-invert{syntax:"*";inherits:false}@property --tw-backdrop-opacity{syntax:"*";inherits:false}@property --tw-backdrop-saturate{syntax:"*";inherits:false}@property --tw-backdrop-sepia{syntax:"*";inherits:false}@property --tw-duration{syntax:"*";inherits:false}@keyframes spin{to{transform:rotate(360deg)}}
2
+ @layer properties{@supports (((-webkit-hyphens:none)) and (not (margin-trim:inline))) or ((-moz-orient:inline) and (not (color:rgb(from red r g b)))){*,:before,:after,::backdrop{--tw-space-y-reverse:0;--tw-border-style:solid;--tw-leading:initial;--tw-font-weight:initial;--tw-tracking:initial;--tw-shadow:0 0 #0000;--tw-shadow-color:initial;--tw-shadow-alpha:100%;--tw-inset-shadow:0 0 #0000;--tw-inset-shadow-color:initial;--tw-inset-shadow-alpha:100%;--tw-ring-color:initial;--tw-ring-shadow:0 0 #0000;--tw-inset-ring-color:initial;--tw-inset-ring-shadow:0 0 #0000;--tw-ring-inset:initial;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-offset-shadow:0 0 #0000;--tw-blur:initial;--tw-brightness:initial;--tw-contrast:initial;--tw-grayscale:initial;--tw-hue-rotate:initial;--tw-invert:initial;--tw-opacity:initial;--tw-saturate:initial;--tw-sepia:initial;--tw-drop-shadow:initial;--tw-drop-shadow-color:initial;--tw-drop-shadow-alpha:100%;--tw-drop-shadow-size:initial;--tw-backdrop-blur:initial;--tw-backdrop-brightness:initial;--tw-backdrop-contrast:initial;--tw-backdrop-grayscale:initial;--tw-backdrop-hue-rotate:initial;--tw-backdrop-invert:initial;--tw-backdrop-opacity:initial;--tw-backdrop-saturate:initial;--tw-backdrop-sepia:initial;--tw-duration:initial}}}@layer theme{:root,:host{--font-sans:Inter, ui-sans-serif, system-ui, sans-serif, "Apple Color Emoji", "Segoe UI Emoji";--font-mono:"JetBrains Mono", ui-monospace, monospace;--color-indigo-500:oklch(58.5% .233 277.117);--color-black:#000;--color-white:#fff;--spacing:.25rem;--container-sm:24rem;--container-md:28rem;--container-2xl:42rem;--container-4xl:56rem;--container-5xl:64rem;--container-6xl:72rem;--container-7xl:80rem;--text-xs:.75rem;--text-xs--line-height:calc(1 / .75);--text-sm:.875rem;--text-sm--line-height:calc(1.25 / .875);--text-base:1rem;--text-base--line-height:calc(1.5 / 1);--text-lg:1.125rem;--text-lg--line-height:calc(1.75 / 1.125);--text-xl:1.25rem;--text-xl--line-height:calc(1.75 / 1.25);--text-2xl:1.5rem;--text-2xl--line-height:calc(2 / 1.5);--text-3xl:1.875rem;--text-3xl--line-height:calc(2.25 / 1.875);--text-4xl:2.25rem;--text-4xl--line-height:calc(2.5 / 2.25);--font-weight-medium:500;--font-weight-semibold:600;--font-weight-bold:700;--tracking-widest:.1em;--leading-tight:1.25;--leading-relaxed:1.625;--radius-md:.375rem;--radius-lg:.5rem;--radius-xl:.75rem;--radius-2xl:1rem;--animate-spin:spin 1s linear infinite;--blur-sm:8px;--blur-3xl:64px;--default-transition-duration:.15s;--default-transition-timing-function:cubic-bezier(.4, 0, .2, 1);--default-font-family:var(--font-sans);--default-mono-font-family:var(--font-mono);--radius:.5rem;--color-primary:221.2 83.2% 53.3%}}@layer base{*,:after,:before,::backdrop{box-sizing:border-box;border:0 solid;margin:0;padding:0}::file-selector-button{box-sizing:border-box;border:0 solid;margin:0;padding:0}html,:host{-webkit-text-size-adjust:100%;tab-size:4;line-height:1.5;font-family:var(--default-font-family,ui-sans-serif, system-ui, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji");font-feature-settings:var(--default-font-feature-settings,normal);font-variation-settings:var(--default-font-variation-settings,normal);-webkit-tap-highlight-color:transparent}hr{height:0;color:inherit;border-top-width:1px}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;-webkit-text-decoration:inherit;-webkit-text-decoration:inherit;-webkit-text-decoration:inherit;-webkit-text-decoration:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,samp,pre{font-family:var(--default-mono-font-family,ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace);font-feature-settings:var(--default-mono-font-feature-settings,normal);font-variation-settings:var(--default-mono-font-variation-settings,normal);font-size:1em}small{font-size:80%}sub,sup{vertical-align:baseline;font-size:75%;line-height:0;position:relative}sub{bottom:-.25em}sup{top:-.5em}table{text-indent:0;border-color:inherit;border-collapse:collapse}:-moz-focusring{outline:auto}progress{vertical-align:baseline}summary{display:list-item}ol,ul,menu{list-style:none}img,svg,video,canvas,audio,iframe,embed,object{vertical-align:middle;display:block}img,video{max-width:100%;height:auto}button,input,select,optgroup,textarea{font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;color:inherit;opacity:1;background-color:#0000;border-radius:0}::file-selector-button{font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;color:inherit;opacity:1;background-color:#0000;border-radius:0}:where(select:is([multiple],[size])) optgroup{font-weight:bolder}:where(select:is([multiple],[size])) optgroup option{padding-inline-start:20px}::file-selector-button{margin-inline-end:4px}::placeholder{opacity:1}@supports (not ((-webkit-appearance:-apple-pay-button))) or (contain-intrinsic-size:1px){::placeholder{color:currentColor}@supports (color:color-mix(in lab, red, red)){::placeholder{color:color-mix(in oklab, currentcolor 50%, transparent)}}}textarea{resize:vertical}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-date-and-time-value{min-height:1lh;text-align:inherit}::-webkit-datetime-edit{display:inline-flex}::-webkit-datetime-edit-fields-wrapper{padding:0}::-webkit-datetime-edit{padding-block:0}::-webkit-datetime-edit-year-field{padding-block:0}::-webkit-datetime-edit-month-field{padding-block:0}::-webkit-datetime-edit-day-field{padding-block:0}::-webkit-datetime-edit-hour-field{padding-block:0}::-webkit-datetime-edit-minute-field{padding-block:0}::-webkit-datetime-edit-second-field{padding-block:0}::-webkit-datetime-edit-millisecond-field{padding-block:0}::-webkit-datetime-edit-meridiem-field{padding-block:0}::-webkit-calendar-picker-indicator{line-height:1}:-moz-ui-invalid{box-shadow:none}button,input:where([type=button],[type=reset],[type=submit]){appearance:button}::file-selector-button{appearance:button}::-webkit-inner-spin-button{height:auto}::-webkit-outer-spin-button{height:auto}[hidden]:where(:not([hidden=until-found])){display:none!important}}@layer components;@layer utilities{.pointer-events-none{pointer-events:none}.invisible{visibility:hidden}.visible{visibility:visible}.sr-only{clip-path:inset(50%);white-space:nowrap;border-width:0;width:1px;height:1px;margin:-1px;padding:0;position:absolute;overflow:hidden}.absolute{position:absolute}.fixed{position:fixed}.relative{position:relative}.static{position:static}.inset-0{inset:0}.inset-y-0{inset-block:0}.-top-40{top:calc(var(--spacing) * -40)}.top-0{top:0}.top-1\/2{top:50%}.top-4{top:calc(var(--spacing) * 4)}.top-full{top:100%}.-right-20{right:calc(var(--spacing) * -20)}.right-0{right:0}.right-4{right:calc(var(--spacing) * 4)}.-bottom-40{bottom:calc(var(--spacing) * -40)}.bottom-0{bottom:0}.-left-40{left:calc(var(--spacing) * -40)}.left-0{left:0}.left-1\/4{left:25%}.z-10{z-index:10}.z-50{z-index:50}.container{width:100%}@media (width>=40rem){.container{max-width:40rem}}@media (width>=48rem){.container{max-width:48rem}}@media (width>=64rem){.container{max-width:64rem}}@media (width>=80rem){.container{max-width:80rem}}@media (width>=96rem){.container{max-width:96rem}}.mx-4{margin-inline:calc(var(--spacing) * 4)}.mx-auto{margin-inline:auto}.my-8{margin-block:calc(var(--spacing) * 8)}.mt-0\.5{margin-top:calc(var(--spacing) * .5)}.mt-1{margin-top:var(--spacing)}.mt-2{margin-top:calc(var(--spacing) * 2)}.mt-3{margin-top:calc(var(--spacing) * 3)}.mt-4{margin-top:calc(var(--spacing) * 4)}.mt-6{margin-top:calc(var(--spacing) * 6)}.mt-8{margin-top:calc(var(--spacing) * 8)}.mt-10{margin-top:calc(var(--spacing) * 10)}.mt-12{margin-top:calc(var(--spacing) * 12)}.mb-1{margin-bottom:var(--spacing)}.mb-2{margin-bottom:calc(var(--spacing) * 2)}.mb-3{margin-bottom:calc(var(--spacing) * 3)}.mb-4{margin-bottom:calc(var(--spacing) * 4)}.mb-5{margin-bottom:calc(var(--spacing) * 5)}.mb-6{margin-bottom:calc(var(--spacing) * 6)}.mb-8{margin-bottom:calc(var(--spacing) * 8)}.ml-3{margin-left:calc(var(--spacing) * 3)}.ml-4{margin-left:calc(var(--spacing) * 4)}.ml-auto{margin-left:auto}.block{display:block}.contents{display:contents}.flex{display:flex}.grid{display:grid}.hidden{display:none}.inline{display:inline}.inline-block{display:inline-block}.inline-flex{display:inline-flex}.table{display:table}.size-2{width:calc(var(--spacing) * 2);height:calc(var(--spacing) * 2)}.size-3{width:calc(var(--spacing) * 3);height:calc(var(--spacing) * 3)}.size-4{width:calc(var(--spacing) * 4);height:calc(var(--spacing) * 4)}.size-5{width:calc(var(--spacing) * 5);height:calc(var(--spacing) * 5)}.size-6{width:calc(var(--spacing) * 6);height:calc(var(--spacing) * 6)}.size-8{width:calc(var(--spacing) * 8);height:calc(var(--spacing) * 8)}.size-10{width:calc(var(--spacing) * 10);height:calc(var(--spacing) * 10)}.size-12{width:calc(var(--spacing) * 12);height:calc(var(--spacing) * 12)}.size-14{width:calc(var(--spacing) * 14);height:calc(var(--spacing) * 14)}.size-16{width:calc(var(--spacing) * 16);height:calc(var(--spacing) * 16)}.size-20{width:calc(var(--spacing) * 20);height:calc(var(--spacing) * 20)}.size-48{width:calc(var(--spacing) * 48);height:calc(var(--spacing) * 48)}.size-72{width:calc(var(--spacing) * 72);height:calc(var(--spacing) * 72)}.size-80{width:calc(var(--spacing) * 80);height:calc(var(--spacing) * 80)}.size-96{width:calc(var(--spacing) * 96);height:calc(var(--spacing) * 96)}.size-full{width:100%;height:100%}.h-0\.5{height:calc(var(--spacing) * .5)}.h-1\.5{height:calc(var(--spacing) * 1.5)}.h-12{height:calc(var(--spacing) * 12)}.h-full{height:100%}.min-h-\[400px\]{min-height:400px}.min-h-screen{min-height:100vh}.w-1\/4{width:25%}.w-2\/4{width:50%}.w-3\/4{width:75%}.w-10{width:calc(var(--spacing) * 10)}.w-48{width:calc(var(--spacing) * 48)}.w-64{width:calc(var(--spacing) * 64)}.w-\[80px\]{width:80px}.w-\[100px\]{width:100px}.w-\[130px\]{width:130px}.w-\[180px\]{width:180px}.w-\[280px\]{width:280px}.w-full{width:100%}.max-w-2xl{max-width:var(--container-2xl)}.max-w-4xl{max-width:var(--container-4xl)}.max-w-5xl{max-width:var(--container-5xl)}.max-w-6xl{max-width:var(--container-6xl)}.max-w-7xl{max-width:var(--container-7xl)}.max-w-md{max-width:var(--container-md)}.max-w-sm{max-width:var(--container-sm)}.min-w-0{min-width:0}.min-w-\[200px\]{min-width:200px}.min-w-\[800px\]{min-width:800px}.flex-1{flex:1}.flex-shrink-0{flex-shrink:0}.shrink{flex-shrink:1}.shrink-0{flex-shrink:0}.rotate-180{rotate:180deg}.animate-spin{animation:var(--animate-spin)}.cursor-not-allowed{cursor:not-allowed}.cursor-pointer{cursor:pointer}.list-inside{list-style-position:inside}.list-disc{list-style-type:disc}.grid-cols-1{grid-template-columns:repeat(1,minmax(0,1fr))}.grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.grid-cols-3{grid-template-columns:repeat(3,minmax(0,1fr))}.flex-col{flex-direction:column}.flex-nowrap{flex-wrap:nowrap}.flex-wrap{flex-wrap:wrap}.items-center{align-items:center}.items-end{align-items:flex-end}.items-start{align-items:flex-start}.justify-between{justify-content:space-between}.justify-center{justify-content:center}.justify-end{justify-content:flex-end}.gap-1{gap:var(--spacing)}.gap-1\.5{gap:calc(var(--spacing) * 1.5)}.gap-2{gap:calc(var(--spacing) * 2)}.gap-3{gap:calc(var(--spacing) * 3)}.gap-4{gap:calc(var(--spacing) * 4)}.gap-6{gap:calc(var(--spacing) * 6)}:where(.space-y-1>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(var(--spacing) * var(--tw-space-y-reverse));margin-block-end:calc(var(--spacing) * calc(1 - var(--tw-space-y-reverse)))}:where(.space-y-2>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing) * 2) * var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing) * 2) * calc(1 - var(--tw-space-y-reverse)))}:where(.space-y-3>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing) * 3) * var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing) * 3) * calc(1 - var(--tw-space-y-reverse)))}:where(.space-y-4>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing) * 4) * var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing) * 4) * calc(1 - var(--tw-space-y-reverse)))}:where(.space-y-5>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing) * 5) * var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing) * 5) * calc(1 - var(--tw-space-y-reverse)))}:where(.space-y-6>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing) * 6) * var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing) * 6) * calc(1 - var(--tw-space-y-reverse)))}:where(.space-y-8>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing) * 8) * var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing) * 8) * calc(1 - var(--tw-space-y-reverse)))}.truncate{text-overflow:ellipsis;white-space:nowrap;overflow:hidden}.overflow-hidden{overflow:hidden}.overflow-x-auto{overflow-x:auto}.rounded{border-radius:var(--radius)}.rounded-2xl{border-radius:var(--radius-2xl)}.rounded-full{border-radius:3.40282e38px}.rounded-lg{border-radius:var(--radius-lg)}.rounded-md{border-radius:var(--radius-md)}.rounded-xl{border-radius:var(--radius-xl)}.border{border-style:var(--tw-border-style);border-width:1px}.border-2{border-style:var(--tw-border-style);border-width:2px}.border-4{border-style:var(--tw-border-style);border-width:4px}.border-t{border-top-style:var(--tw-border-style);border-top-width:1px}.border-b{border-bottom-style:var(--tw-border-style);border-bottom-width:1px}.border-b-2{border-bottom-style:var(--tw-border-style);border-bottom-width:2px}.border-dashed{--tw-border-style:dashed;border-style:dashed}.border-\[var\(--color-accent-primary\)\]{border-color:var(--color-accent-primary)}.border-\[var\(--color-border-default\)\]{border-color:var(--color-border-default)}.border-\[var\(--color-border-primary\)\]{border-color:var(--color-border-primary)}.border-\[var\(--color-border-subtle\)\]{border-color:var(--color-border-subtle)}.border-\[var\(--color-status-error-border\)\]{border-color:var(--color-status-error-border)}.border-\[var\(--color-status-success-border\)\]{border-color:var(--color-status-success-border)}.border-\[var\(--color-status-warning-border\)\]{border-color:var(--color-status-warning-border)}.border-primary{border-color:var(--color-primary)}.border-t-transparent{border-top-color:#0000}.bg-\[var\(--color-accent-primary\)\]{background-color:var(--color-accent-primary)}.bg-\[var\(--color-action-primary-bg\)\]{background-color:var(--color-action-primary-bg)}.bg-\[var\(--color-action-secondary-bg-subtle\)\]{background-color:var(--color-action-secondary-bg-subtle)}.bg-\[var\(--color-background-base\)\]{background-color:var(--color-background-base)}.bg-\[var\(--color-bg-accent\)\]{background-color:var(--color-bg-accent)}.bg-\[var\(--color-bg-canvas\)\]{background-color:var(--color-bg-canvas)}.bg-\[var\(--color-bg-disabled\)\]{background-color:var(--color-bg-disabled)}.bg-\[var\(--color-bg-muted\)\]{background-color:var(--color-bg-muted)}.bg-\[var\(--color-bg-sunken\)\]{background-color:var(--color-bg-sunken)}.bg-\[var\(--color-bg-surface\)\]{background-color:var(--color-bg-surface)}.bg-\[var\(--color-status-error-bg\)\]{background-color:var(--color-status-error-bg)}.bg-\[var\(--color-status-error-bg-subtle\)\]{background-color:var(--color-status-error-bg-subtle)}.bg-\[var\(--color-status-error-subtle\)\]{background-color:var(--color-status-error-subtle)}.bg-\[var\(--color-status-info-bg-subtle\)\]{background-color:var(--color-status-info-bg-subtle)}.bg-\[var\(--color-status-success-bg-subtle\)\]{background-color:var(--color-status-success-bg-subtle)}.bg-\[var\(--color-status-success-subtle\)\]{background-color:var(--color-status-success-subtle)}.bg-\[var\(--color-status-warning-bg\)\]{background-color:var(--color-status-warning-bg)}.bg-\[var\(--color-status-warning-bg-subtle\)\]{background-color:var(--color-status-warning-bg-subtle)}.bg-black\/40{background-color:#0006}@supports (color:color-mix(in lab, red, red)){.bg-black\/40{background-color:color-mix(in oklab, var(--color-black) 40%, transparent)}}.bg-black\/50{background-color:#00000080}@supports (color:color-mix(in lab, red, red)){.bg-black\/50{background-color:color-mix(in oklab, var(--color-black) 50%, transparent)}}.object-contain{-o-object-fit:contain;object-fit:contain}.object-cover{-o-object-fit:cover;object-fit:cover}.p-0\.5{padding:calc(var(--spacing) * .5)}.p-2{padding:calc(var(--spacing) * 2)}.p-3{padding:calc(var(--spacing) * 3)}.p-4{padding:calc(var(--spacing) * 4)}.p-5{padding:calc(var(--spacing) * 5)}.p-6{padding:calc(var(--spacing) * 6)}.p-8{padding:calc(var(--spacing) * 8)}.p-12{padding:calc(var(--spacing) * 12)}.px-1{padding-inline:var(--spacing)}.px-2{padding-inline:calc(var(--spacing) * 2)}.px-2\.5{padding-inline:calc(var(--spacing) * 2.5)}.px-3{padding-inline:calc(var(--spacing) * 3)}.px-4{padding-inline:calc(var(--spacing) * 4)}.px-5{padding-inline:calc(var(--spacing) * 5)}.px-6{padding-inline:calc(var(--spacing) * 6)}.py-0\.5{padding-block:calc(var(--spacing) * .5)}.py-1{padding-block:var(--spacing)}.py-1\.5{padding-block:calc(var(--spacing) * 1.5)}.py-2{padding-block:calc(var(--spacing) * 2)}.py-2\.5{padding-block:calc(var(--spacing) * 2.5)}.py-3{padding-block:calc(var(--spacing) * 3)}.py-6{padding-block:calc(var(--spacing) * 6)}.py-8{padding-block:calc(var(--spacing) * 8)}.py-12{padding-block:calc(var(--spacing) * 12)}.py-16{padding-block:calc(var(--spacing) * 16)}.pt-2{padding-top:calc(var(--spacing) * 2)}.pt-4{padding-top:calc(var(--spacing) * 4)}.pt-6{padding-top:calc(var(--spacing) * 6)}.pt-12{padding-top:calc(var(--spacing) * 12)}.pr-3\.5{padding-right:calc(var(--spacing) * 3.5)}.pr-4{padding-right:calc(var(--spacing) * 4)}.pr-12{padding-right:calc(var(--spacing) * 12)}.pb-3{padding-bottom:calc(var(--spacing) * 3)}.pl-3{padding-left:calc(var(--spacing) * 3)}.pl-3\.5{padding-left:calc(var(--spacing) * 3.5)}.pl-\[3\.5rem\]{padding-left:3.5rem}.pl-\[3\.25rem\]{padding-left:3.25rem}.text-center{text-align:center}.text-left{text-align:left}.text-right{text-align:right}.font-mono{font-family:var(--font-mono)}.text-2xl{font-size:var(--text-2xl);line-height:var(--tw-leading,var(--text-2xl--line-height))}.text-3xl{font-size:var(--text-3xl);line-height:var(--tw-leading,var(--text-3xl--line-height))}.text-4xl{font-size:var(--text-4xl);line-height:var(--tw-leading,var(--text-4xl--line-height))}.text-base{font-size:var(--text-base);line-height:var(--tw-leading,var(--text-base--line-height))}.text-lg{font-size:var(--text-lg);line-height:var(--tw-leading,var(--text-lg--line-height))}.text-sm{font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height))}.text-xl{font-size:var(--text-xl);line-height:var(--tw-leading,var(--text-xl--line-height))}.text-xs{font-size:var(--text-xs);line-height:var(--tw-leading,var(--text-xs--line-height))}.leading-none{--tw-leading:1;line-height:1}.leading-relaxed{--tw-leading:var(--leading-relaxed);line-height:var(--leading-relaxed)}.leading-tight{--tw-leading:var(--leading-tight);line-height:var(--leading-tight)}.font-bold{--tw-font-weight:var(--font-weight-bold);font-weight:var(--font-weight-bold)}.font-medium{--tw-font-weight:var(--font-weight-medium);font-weight:var(--font-weight-medium)}.font-semibold{--tw-font-weight:var(--font-weight-semibold);font-weight:var(--font-weight-semibold)}.tracking-widest{--tw-tracking:var(--tracking-widest);letter-spacing:var(--tracking-widest)}.break-all{word-break:break-all}.whitespace-nowrap{white-space:nowrap}.text-\[var\(--color-accent-primary\)\]{color:var(--color-accent-primary)}.text-\[var\(--color-action-primary-bg\)\]{color:var(--color-action-primary-bg)}.text-\[var\(--color-action-primary-text\)\]{color:var(--color-action-primary-text)}.text-\[var\(--color-action-secondary-text\)\]{color:var(--color-action-secondary-text)}.text-\[var\(--color-status-error\)\]{color:var(--color-status-error)}.text-\[var\(--color-status-error-text\)\]{color:var(--color-status-error-text)}.text-\[var\(--color-status-info-text\)\]{color:var(--color-status-info-text)}.text-\[var\(--color-status-success\)\]{color:var(--color-status-success)}.text-\[var\(--color-status-success-text\)\]{color:var(--color-status-success-text)}.text-\[var\(--color-status-warning-text\)\]{color:var(--color-status-warning-text)}.text-\[var\(--color-text-disabled\)\]{color:var(--color-text-disabled)}.text-\[var\(--color-text-inverse\)\]{color:var(--color-text-inverse)}.text-\[var\(--color-text-link\)\]{color:var(--color-text-link)}.text-\[var\(--color-text-primary\)\]{color:var(--color-text-primary)}.text-\[var\(--color-text-secondary\)\]{color:var(--color-text-secondary)}.text-\[var\(--color-text-tertiary\)\]{color:var(--color-text-tertiary)}.text-white{color:var(--color-white)}.capitalize{text-transform:capitalize}.lowercase{text-transform:lowercase}.uppercase{text-transform:uppercase}.underline{text-decoration-line:underline}.underline-offset-2{text-underline-offset:2px}.placeholder-\[var\(--color-text-secondary\)\]::placeholder{color:var(--color-text-secondary)}.opacity-0{opacity:0}.opacity-5{opacity:.05}.opacity-25{opacity:.25}.opacity-50{opacity:.5}.opacity-75{opacity:.75}.shadow-2xl{--tw-shadow:0 25px 50px -12px var(--tw-shadow-color,#00000040);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.shadow-lg{--tw-shadow:0 10px 15px -3px var(--tw-shadow-color,#0000001a), 0 4px 6px -4px var(--tw-shadow-color,#0000001a);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.shadow-sm{--tw-shadow:0 1px 3px 0 var(--tw-shadow-color,#0000001a), 0 1px 2px -1px var(--tw-shadow-color,#0000001a);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.shadow-xl{--tw-shadow:0 20px 25px -5px var(--tw-shadow-color,#0000001a), 0 8px 10px -6px var(--tw-shadow-color,#0000001a);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.blur-3xl{--tw-blur:blur(var(--blur-3xl));filter:var(--tw-blur,) var(--tw-brightness,) var(--tw-contrast,) var(--tw-grayscale,) var(--tw-hue-rotate,) var(--tw-invert,) var(--tw-saturate,) var(--tw-sepia,) var(--tw-drop-shadow,)}.filter{filter:var(--tw-blur,) var(--tw-brightness,) var(--tw-contrast,) var(--tw-grayscale,) var(--tw-hue-rotate,) var(--tw-invert,) var(--tw-saturate,) var(--tw-sepia,) var(--tw-drop-shadow,)}.backdrop-blur-sm{--tw-backdrop-blur:blur(var(--blur-sm));-webkit-backdrop-filter:var(--tw-backdrop-blur,) var(--tw-backdrop-brightness,) var(--tw-backdrop-contrast,) var(--tw-backdrop-grayscale,) var(--tw-backdrop-hue-rotate,) var(--tw-backdrop-invert,) var(--tw-backdrop-opacity,) var(--tw-backdrop-saturate,) var(--tw-backdrop-sepia,);backdrop-filter:var(--tw-backdrop-blur,) var(--tw-backdrop-brightness,) var(--tw-backdrop-contrast,) var(--tw-backdrop-grayscale,) var(--tw-backdrop-hue-rotate,) var(--tw-backdrop-invert,) var(--tw-backdrop-opacity,) var(--tw-backdrop-saturate,) var(--tw-backdrop-sepia,)}.transition{transition-property:color,background-color,border-color,outline-color,text-decoration-color,fill,stroke,--tw-gradient-from,--tw-gradient-via,--tw-gradient-to,opacity,box-shadow,transform,translate,scale,rotate,filter,-webkit-backdrop-filter,backdrop-filter,display,content-visibility,overlay,pointer-events;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.transition-all{transition-property:all;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.transition-colors{transition-property:color,background-color,border-color,outline-color,text-decoration-color,fill,stroke,--tw-gradient-from,--tw-gradient-via,--tw-gradient-to;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.transition-opacity{transition-property:opacity;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.transition-shadow{transition-property:box-shadow;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.transition-transform{transition-property:transform,translate,scale,rotate;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.duration-200{--tw-duration:.2s;transition-duration:.2s}.duration-300{--tw-duration:.3s;transition-duration:.3s}.outline-none{--tw-outline-style:none;outline-style:none}.select-all{-webkit-user-select:all;user-select:all}@media (hover:hover){.group-hover\:bg-\[var\(--color-action-primary-bg-subtle\)\]:is(:where(.group):hover *){background-color:var(--color-action-primary-bg-subtle)}.group-hover\:bg-\[var\(--color-action-secondary-bg-subtle\)\]:is(:where(.group):hover *){background-color:var(--color-action-secondary-bg-subtle)}.group-hover\:text-\[var\(--color-text-primary\)\]:is(:where(.group):hover *){color:var(--color-text-primary)}.group-hover\:text-indigo-500:is(:where(.group):hover *){color:var(--color-indigo-500)}.group-hover\:opacity-100:is(:where(.group):hover *){opacity:1}}.peer-checked\:opacity-100:is(:where(.peer):checked~*){opacity:1}.peer-focus\:ring-2:is(:where(.peer):focus~*){--tw-ring-shadow:var(--tw-ring-inset,) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color,currentcolor);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.placeholder\:text-\[var\(--color-text-tertiary\)\]::placeholder{color:var(--color-text-tertiary)}.last\:border-b-0:last-child{border-bottom-style:var(--tw-border-style);border-bottom-width:0}@media (hover:hover){.hover\:border-\[var\(--color-action-primary-border\)\]:hover{border-color:var(--color-action-primary-border)}.hover\:border-\[var\(--color-action-secondary-border\)\]:hover{border-color:var(--color-action-secondary-border)}.hover\:border-\[var\(--color-border-strong\)\]:hover{border-color:var(--color-border-strong)}.hover\:bg-\[var\(--color-accent-primary-hover\)\]:hover{background-color:var(--color-accent-primary-hover)}.hover\:bg-\[var\(--color-action-primary-bgHover\)\]:hover{background-color:var(--color-action-primary-bgHover)}.hover\:bg-\[var\(--color-bg-muted\)\]:hover{background-color:var(--color-bg-muted)}.hover\:bg-\[var\(--color-bg-subtle\)\]:hover{background-color:var(--color-bg-subtle)}.hover\:bg-\[var\(--color-bg-sunken\)\]:hover{background-color:var(--color-bg-sunken)}.hover\:bg-\[var\(--color-status-error-bg-subtle\)\]:hover{background-color:var(--color-status-error-bg-subtle)}.hover\:text-\[var\(--color-text-primary\)\]:hover{color:var(--color-text-primary)}.hover\:text-\[var\(--color-text-secondary\)\]:hover{color:var(--color-text-secondary)}.hover\:underline:hover{text-decoration-line:underline}.hover\:opacity-90:hover{opacity:.9}.hover\:shadow-lg:hover{--tw-shadow:0 10px 15px -3px var(--tw-shadow-color,#0000001a), 0 4px 6px -4px var(--tw-shadow-color,#0000001a);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.hover\:shadow-md:hover{--tw-shadow:0 4px 6px -1px var(--tw-shadow-color,#0000001a), 0 2px 4px -2px var(--tw-shadow-color,#0000001a);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}}.focus\:border-primary:focus{border-color:var(--color-primary)}.focus\:border-transparent:focus{border-color:#0000}.focus\:ring-2:focus{--tw-ring-shadow:var(--tw-ring-inset,) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color,currentcolor);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.focus\:ring-\[var\(--color-accent-primary\)\]:focus{--tw-ring-color:var(--color-accent-primary)}.focus\:ring-primary\/20:focus{--tw-ring-color:color-mix(in srgb, 221.2 83.2% 53.3% 20%, transparent)}@supports (color:color-mix(in lab, red, red)){.focus\:ring-primary\/20:focus{--tw-ring-color:color-mix(in oklab, var(--color-primary) 20%, transparent)}}.focus\:outline-none:focus{--tw-outline-style:none;outline-style:none}.disabled\:cursor-not-allowed:disabled{cursor:not-allowed}.disabled\:opacity-40:disabled{opacity:.4}.disabled\:opacity-50:disabled{opacity:.5}.disabled\:opacity-60:disabled{opacity:.6}@media (width>=40rem){.sm\:not-sr-only{clip-path:none;white-space:normal;width:auto;height:auto;margin:0;padding:0;position:static;overflow:visible}.sm\:top-6{top:calc(var(--spacing) * 6)}.sm\:right-6{right:calc(var(--spacing) * 6)}.sm\:col-span-2{grid-column:span 2/span 2}.sm\:block{display:block}.sm\:h-14{height:calc(var(--spacing) * 14)}.sm\:w-12{width:calc(var(--spacing) * 12)}.sm\:w-auto{width:auto}.sm\:grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.sm\:flex-row{flex-direction:row}.sm\:items-center{align-items:center}.sm\:justify-between{justify-content:space-between}.sm\:gap-3{gap:calc(var(--spacing) * 3)}.sm\:p-12{padding:calc(var(--spacing) * 12)}.sm\:text-2xl{font-size:var(--text-2xl);line-height:var(--tw-leading,var(--text-2xl--line-height))}.sm\:text-3xl{font-size:var(--text-3xl);line-height:var(--tw-leading,var(--text-3xl--line-height))}}@media (width>=48rem){.md\:col-span-2{grid-column:span 2/span 2}.md\:grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.md\:grid-cols-3{grid-template-columns:repeat(3,minmax(0,1fr))}.md\:flex-row{flex-direction:row}.md\:items-center{align-items:center}.md\:justify-between{justify-content:space-between}}@media (width>=64rem){.lg\:col-span-1{grid-column:span 1/span 1}.lg\:flex{display:flex}.lg\:hidden{display:none}.lg\:w-1\/2{width:50%}.lg\:grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.lg\:grid-cols-3{grid-template-columns:repeat(3,minmax(0,1fr))}.lg\:grid-cols-4{grid-template-columns:repeat(4,minmax(0,1fr))}.lg\:text-left{text-align:left}}}.dark{--color-background:222.2 84% 4.9%;--color-foreground:210 40% 98%;--color-card:222.2 84% 4.9%;--color-card-foreground:210 40% 98%;--color-popover:222.2 84% 4.9%;--color-popover-foreground:210 40% 98%;--color-primary:217.2 91.2% 59.8%;--color-primary-foreground:222.2 47.4% 11.2%;--color-secondary:217.2 32.6% 17.5%;--color-secondary-foreground:210 40% 98%;--color-muted:217.2 32.6% 17.5%;--color-muted-foreground:215 20.2% 65.1%;--color-accent:217.2 32.6% 17.5%;--color-accent-foreground:210 40% 98%;--color-destructive:0 62.8% 30.6%;--color-destructive-foreground:210 40% 98%;--color-border:217.2 32.6% 17.5%;--color-input:217.2 32.6% 17.5%;--color-ring:224.3 76.3% 48%}body{font-feature-settings:"rlig" 1, "calt" 1}.auth-primary-button{background:var(--color-action-primary-bg);color:var(--color-action-primary-text);box-shadow:0 12px 30px var(--color-action-primary-bg);border-radius:.75rem}@supports (color:color-mix(in lab, red, red)){.auth-primary-button{box-shadow:0 12px 30px color-mix(in srgb, var(--color-action-primary-bg) 24%, transparent)}}.auth-primary-button{transition:opacity .16s,transform .16s,box-shadow .16s,background-color .16s}.auth-primary-button:hover{opacity:.96;box-shadow:0 16px 36px var(--color-action-primary-bg)}@supports (color:color-mix(in lab, red, red)){.auth-primary-button:hover{box-shadow:0 16px 36px color-mix(in srgb, var(--color-action-primary-bg) 30%, transparent)}}.auth-primary-button:focus-visible{outline:2px solid var(--color-action-primary-bg)}@supports (color:color-mix(in lab, red, red)){.auth-primary-button:focus-visible{outline:2px solid color-mix(in srgb, var(--color-action-primary-bg) 45%, transparent)}}.auth-primary-button:focus-visible{outline-offset:2px}.auth-primary-button:disabled{cursor:not-allowed;opacity:.55;box-shadow:none}.auth-brand-badge{background:linear-gradient(135deg, var(--color-action-primary-bg) 0%, var(--color-action-primary-bg) 100%)}@supports (color:color-mix(in lab, red, red)){.auth-brand-badge{background:linear-gradient(135deg, color-mix(in srgb, var(--color-action-primary-bg) 92%, white 8%) 0%, color-mix(in srgb, var(--color-action-primary-bg) 72%, var(--color-bg-surface) 28%) 100%)}}.auth-brand-badge{color:var(--color-action-primary-text);box-shadow:0 12px 30px var(--color-action-primary-bg)}@supports (color:color-mix(in lab, red, red)){.auth-brand-badge{box-shadow:0 12px 30px color-mix(in srgb, var(--color-action-primary-bg) 22%, transparent)}}.auth-brand-panel{background:radial-gradient(circle at top left, var(--color-action-primary-bg) 0%, transparent 35%), radial-gradient(circle at bottom right, var(--color-text-link) 0%, transparent 38%), linear-gradient(135deg, var(--color-bg-surface) 0%, var(--color-bg-canvas) 100%)}@supports (color:color-mix(in lab, red, red)){.auth-brand-panel{background:radial-gradient(circle at top left, color-mix(in srgb, var(--color-action-primary-bg) 20%, transparent) 0%, transparent 35%), radial-gradient(circle at bottom right, color-mix(in srgb, var(--color-text-link) 18%, transparent) 0%, transparent 38%), linear-gradient(135deg, color-mix(in srgb, var(--color-bg-surface) 92%, black 8%) 0%, color-mix(in srgb, var(--color-bg-canvas) 70%, black 30%) 100%)}}.auth-brand-panel,.auth-brand-copy{color:var(--color-text-primary)}@supports (color:color-mix(in lab, red, red)){.auth-brand-copy{color:color-mix(in srgb, var(--color-text-primary) 88%, white 12%)}}.auth-brand-copy-muted{color:var(--color-text-secondary)}@supports (color:color-mix(in lab, red, red)){.auth-brand-copy-muted{color:color-mix(in srgb, var(--color-text-secondary) 75%, white 25%)}}.auth-highlight-chip{background:var(--color-bg-surface)}@supports (color:color-mix(in lab, red, red)){.auth-highlight-chip{background:color-mix(in srgb, var(--color-bg-surface) 84%, transparent)}}.auth-highlight-chip{border:1px solid var(--color-border-subtle)}@supports (color:color-mix(in lab, red, red)){.auth-highlight-chip{border:1px solid color-mix(in srgb, var(--color-border-subtle) 65%, transparent)}}.auth-highlight-chip{-webkit-backdrop-filter:blur(14px);backdrop-filter:blur(14px)}.auth-shell-gradient{background:linear-gradient(180deg, var(--color-bg-canvas) 0%, var(--color-bg-surface) 100%)}@supports (color:color-mix(in lab, red, red)){.auth-shell-gradient{background:linear-gradient(180deg, color-mix(in srgb, var(--color-bg-canvas) 96%, transparent) 0%, color-mix(in srgb, var(--color-bg-surface) 96%, transparent) 100%)}}.auth-hero-card{background:linear-gradient(135deg, var(--color-action-primary-bg) 0%, var(--color-text-link) 100%)}@supports (color:color-mix(in lab, red, red)){.auth-hero-card{background:linear-gradient(135deg, color-mix(in srgb, var(--color-action-primary-bg) 90%, transparent) 0%, color-mix(in srgb, var(--color-text-link) 70%, var(--color-action-primary-bg) 30%) 100%)}}.auth-hero-card{color:var(--color-action-primary-text);box-shadow:0 18px 42px var(--color-action-primary-bg)}@supports (color:color-mix(in lab, red, red)){.auth-hero-card{box-shadow:0 18px 42px color-mix(in srgb, var(--color-action-primary-bg) 26%, transparent)}}@property --tw-space-y-reverse{syntax:"*";inherits:false;initial-value:0}@property --tw-border-style{syntax:"*";inherits:false;initial-value:solid}@property --tw-leading{syntax:"*";inherits:false}@property --tw-font-weight{syntax:"*";inherits:false}@property --tw-tracking{syntax:"*";inherits:false}@property --tw-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-shadow-color{syntax:"*";inherits:false}@property --tw-shadow-alpha{syntax:"<percentage>";inherits:false;initial-value:100%}@property --tw-inset-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-inset-shadow-color{syntax:"*";inherits:false}@property --tw-inset-shadow-alpha{syntax:"<percentage>";inherits:false;initial-value:100%}@property --tw-ring-color{syntax:"*";inherits:false}@property --tw-ring-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-inset-ring-color{syntax:"*";inherits:false}@property --tw-inset-ring-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-ring-inset{syntax:"*";inherits:false}@property --tw-ring-offset-width{syntax:"<length>";inherits:false;initial-value:0}@property --tw-ring-offset-color{syntax:"*";inherits:false;initial-value:#fff}@property --tw-ring-offset-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-blur{syntax:"*";inherits:false}@property --tw-brightness{syntax:"*";inherits:false}@property --tw-contrast{syntax:"*";inherits:false}@property --tw-grayscale{syntax:"*";inherits:false}@property --tw-hue-rotate{syntax:"*";inherits:false}@property --tw-invert{syntax:"*";inherits:false}@property --tw-opacity{syntax:"*";inherits:false}@property --tw-saturate{syntax:"*";inherits:false}@property --tw-sepia{syntax:"*";inherits:false}@property --tw-drop-shadow{syntax:"*";inherits:false}@property --tw-drop-shadow-color{syntax:"*";inherits:false}@property --tw-drop-shadow-alpha{syntax:"<percentage>";inherits:false;initial-value:100%}@property --tw-drop-shadow-size{syntax:"*";inherits:false}@property --tw-backdrop-blur{syntax:"*";inherits:false}@property --tw-backdrop-brightness{syntax:"*";inherits:false}@property --tw-backdrop-contrast{syntax:"*";inherits:false}@property --tw-backdrop-grayscale{syntax:"*";inherits:false}@property --tw-backdrop-hue-rotate{syntax:"*";inherits:false}@property --tw-backdrop-invert{syntax:"*";inherits:false}@property --tw-backdrop-opacity{syntax:"*";inherits:false}@property --tw-backdrop-saturate{syntax:"*";inherits:false}@property --tw-backdrop-sepia{syntax:"*";inherits:false}@property --tw-duration{syntax:"*";inherits:false}@keyframes spin{to{transform:rotate(360deg)}}
3
3
  /*$vite$:1*/
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@burdenoff/microfe-auth",
3
- "version": "2026.802.1",
3
+ "version": "2026.825.1",
4
4
  "description": "Auth microfrontend for Burdenoff products",
5
5
  "type": "module",
6
6
  "imports": {
@@ -94,7 +94,7 @@
94
94
  "react-dom": "^19.0.0"
95
95
  },
96
96
  "publishConfig": {
97
- "access": "restricted"
97
+ "access": "public"
98
98
  },
99
99
  "overrides": {
100
100
  "lodash": ">=4.17.21",