@burdenoff/microfe-auth 2026.1107.1 → 2026.1107.2
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.
- package/dist/auth/components/AuthLayout.js +4 -3
- package/dist/auth/components/AuthLayout.js.map +1 -1
- package/dist/auth/pages/LoginPage.js +4 -0
- package/dist/auth/pages/LoginPage.js.map +1 -1
- package/dist/auth/pages/MfaVerifyPage.js +1 -0
- package/dist/auth/pages/MfaVerifyPage.js.map +1 -1
- package/dist/auth/pages/PasswordResetPage.js +2 -0
- package/dist/auth/pages/PasswordResetPage.js.map +1 -1
- package/dist/auth/pages/ReactivatePage.js +3 -1
- package/dist/auth/pages/ReactivatePage.js.map +1 -1
- package/dist/auth/pages/RegisterPage.js +3 -1
- package/dist/auth/pages/RegisterPage.js.map +1 -1
- package/dist/auth/pages/SsoLoginPage.js +2 -1
- package/dist/auth/pages/SsoLoginPage.js.map +1 -1
- package/dist/microfe-auth.css +1 -1
- package/package.json +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"RegisterPage.js","names":["_Fragment","RegisterPage","tr","useTr","useAuth","navigate","useNavigate","searchParams","useSearchParams","rawReturnTo","returnTo","useMemo","sanitizeReturnPath","loginPath","authPathWithReturnTo","useAuthOperations","useOAuthOperations","showPassword","setShowPassword","useState","formData","setFormData","validationErrors","setValidationErrors","signupSuccess","setSignupSuccess","error","setError","oauthError","setOauthError","captchaToken","setCaptchaToken","captchaResetKey","setCaptchaResetKey","captchaEnabled","captchaSiteKey","useSignupCaptcha","isResendingVerification","setIsResendingVerification","resendError","setResendError","isAccountDeactivated","errorCode","isAccountRemoved","isAccountSuspended","passwordChecks","password","passwordStrength","metCount","c","handleSubmit","errors","validateEmail","userFieldsValidation","validateUserFields","passwordValidation","validatePassword","userFields","signUp","err","message","k","handleGoogleSignup","handleMicrosoftSignup","isGoogleConfigured","isProviderConfigured","isMicrosoftConfigured","oauthProviders","GoogleIcon","GitHubIcon","MicrosoftIcon","verificationEmailPrefix","verificationEmailSuffix","AuthLayout","Button","resendVerification","productName","PagePurpose","AlertIcon","UserIcon","EmailIcon","LockIcon","jsx","EyeOffIcon","EyeIcon","check","CheckIcon","XIcon","resolveLegalUrl","CaptchaV2","isLoading","Fragment","SpinnerIcon","provider"],"sources":["../../../src/auth/pages/RegisterPage.tsx"],"sourcesContent":["import { useEffect, useMemo, useState } from \"react\";\nimport { useNavigate, useSearchParams } from \"react-router\";\nimport { useTr } from \"../../shared/hooks/useTr\";\nimport {\n validateEmail,\n validatePassword,\n validateUserFields,\n} from \"../utils/validation\";\nimport { resolveLegalUrl } from \"../utils/legalUrls\";\nimport {\n authPathWithReturnTo,\n rememberReturnTo,\n sanitizeReturnPath,\n} from \"../utils/pendingReturnTo\";\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 tr = useTr();\n const { productName } = useAuth();\n const navigate = useNavigate();\n const [searchParams] = useSearchParams();\n const rawReturnTo = searchParams.get(\"returnTo\");\n // Where to go after the visitor verifies their email and signs in. Kept\n // across the verification email round trip (see pendingReturnTo.ts).\n const returnTo = useMemo(\n () => sanitizeReturnPath(rawReturnTo),\n [rawReturnTo],\n );\n useEffect(() => {\n rememberReturnTo(rawReturnTo);\n }, [rawReturnTo]);\n const loginPath = authPathWithReturnTo(\"/auth/login\", returnTo);\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 const userFieldsValidation = validateUserFields(formData);\n if (!userFieldsValidation.valid) {\n errors.push(\n ...userFieldsValidation.errors.map((e) =>\n tr(`auth.register.${e.field}_${e.code}`, e.message),\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 // Submit the canonicalised values the validators approved, not the\n // raw formData — so leading/trailing whitespace and typographic\n // apostrophes/hyphens don't reach the backend / DB. The cast is\n // sound because the `errors.length > 0` early return above would\n // have caught any failed validation.\n const userFields = (\n userFieldsValidation as {\n valid: true;\n values: { firstName: string; lastName: string; username: string };\n }\n ).values;\n await signUp({\n ...formData,\n firstName: userFields.firstName,\n lastName: userFields.lastName,\n username: userFields.username,\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(loginPath)}\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={\n showPassword\n ? tr(\"auth.register.hidePassword\", \"Hide password\")\n : tr(\"auth.register.showPassword\", \"Show password\")\n }\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 {/* These link to the PUBLIC marketing site, not an app route: the\n reader is signed out, and the app's /legal/:slug route sits behind\n the shell's auth guard. Opened in a new tab so a half-completed\n signup form is not discarded to read the terms. */}\n <a\n href={resolveLegalUrl(\"/terms\")}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\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={resolveLegalUrl(\"/privacy\")}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\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(loginPath)}\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":["_Fragment","RegisterPage","tr","useTr","useAuth","navigate","useNavigate","searchParams","useSearchParams","rawReturnTo","returnTo","useMemo","sanitizeReturnPath","loginPath","authPathWithReturnTo","useAuthOperations","useOAuthOperations","showPassword","setShowPassword","useState","formData","setFormData","validationErrors","setValidationErrors","signupSuccess","setSignupSuccess","error","setError","oauthError","setOauthError","captchaToken","setCaptchaToken","captchaResetKey","setCaptchaResetKey","captchaEnabled","captchaSiteKey","useSignupCaptcha","isResendingVerification","setIsResendingVerification","resendError","setResendError","isAccountDeactivated","errorCode","isAccountRemoved","isAccountSuspended","passwordChecks","password","passwordStrength","metCount","c","handleSubmit","errors","validateEmail","userFieldsValidation","validateUserFields","passwordValidation","validatePassword","userFields","signUp","err","message","k","handleGoogleSignup","handleMicrosoftSignup","isGoogleConfigured","isProviderConfigured","isMicrosoftConfigured","oauthProviders","GoogleIcon","GitHubIcon","MicrosoftIcon","verificationEmailPrefix","verificationEmailSuffix","AuthLayout","Button","resendVerification","productName","PagePurpose","AlertIcon","UserIcon","EmailIcon","LockIcon","jsx","EyeOffIcon","EyeIcon","check","CheckIcon","XIcon","resolveLegalUrl","CaptchaV2","isLoading","Fragment","SpinnerIcon","provider"],"sources":["../../../src/auth/pages/RegisterPage.tsx"],"sourcesContent":["import { useEffect, useMemo, useState } from \"react\";\nimport { useNavigate, useSearchParams } from \"react-router\";\nimport { useTr } from \"../../shared/hooks/useTr\";\nimport {\n validateEmail,\n validatePassword,\n validateUserFields,\n} from \"../utils/validation\";\nimport { resolveLegalUrl } from \"../utils/legalUrls\";\nimport {\n authPathWithReturnTo,\n rememberReturnTo,\n sanitizeReturnPath,\n} from \"../utils/pendingReturnTo\";\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 tr = useTr();\n const { productName } = useAuth();\n const navigate = useNavigate();\n const [searchParams] = useSearchParams();\n const rawReturnTo = searchParams.get(\"returnTo\");\n // Where to go after the visitor verifies their email and signs in. Kept\n // across the verification email round trip (see pendingReturnTo.ts).\n const returnTo = useMemo(\n () => sanitizeReturnPath(rawReturnTo),\n [rawReturnTo],\n );\n useEffect(() => {\n rememberReturnTo(rawReturnTo);\n }, [rawReturnTo]);\n const loginPath = authPathWithReturnTo(\"/auth/login\", returnTo);\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 const userFieldsValidation = validateUserFields(formData);\n if (!userFieldsValidation.valid) {\n errors.push(\n ...userFieldsValidation.errors.map((e) =>\n tr(`auth.register.${e.field}_${e.code}`, e.message),\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 // Submit the canonicalised values the validators approved, not the\n // raw formData — so leading/trailing whitespace and typographic\n // apostrophes/hyphens don't reach the backend / DB. The cast is\n // sound because the `errors.length > 0` early return above would\n // have caught any failed validation.\n const userFields = (\n userFieldsValidation as {\n valid: true;\n values: { firstName: string; lastName: string; username: string };\n }\n ).values;\n await signUp({\n ...formData,\n firstName: userFields.firstName,\n lastName: userFields.lastName,\n username: userFields.username,\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 <h2 className=\"text-lg font-semibold text-[var(--color-text-primary)] mb-2\">\n {tr(\n \"auth.register.accountCreated\",\n \"Account created successfully!\",\n )}\n </h2>\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(loginPath)}\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\n role=\"alert\"\n className=\"flex items-start gap-3 p-4 rounded-xl bg-status-error-bg-subtle border border-status-error-border\"\n >\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={\n showPassword\n ? tr(\"auth.register.hidePassword\", \"Hide password\")\n : tr(\"auth.register.showPassword\", \"Show password\")\n }\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 {/* These link to the PUBLIC marketing site, not an app route: the\n reader is signed out, and the app's /legal/:slug route sits behind\n the shell's auth guard. Opened in a new tab so a half-completed\n signup form is not discarded to read the terms. */}\n <a\n href={resolveLegalUrl(\"/terms\")}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\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={resolveLegalUrl(\"/privacy\")}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\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\n role=\"alert\"\n className=\"flex items-start gap-3 p-4 rounded-xl border bg-status-error-bg-subtle border-status-error-border\"\n >\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(loginPath)}\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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"}
|
|
@@ -42,6 +42,7 @@ function h() {
|
|
|
42
42
|
className: "space-y-5",
|
|
43
43
|
children: [
|
|
44
44
|
E && /* @__PURE__ */ f("div", {
|
|
45
|
+
role: "alert",
|
|
45
46
|
className: `flex items-start gap-3 p-4 rounded-xl border ${M ? "bg-status-warning-bg-subtle border-status-warning-border" : "bg-status-error-bg-subtle border-status-error-border"}`,
|
|
46
47
|
children: [/* @__PURE__ */ d(r, { className: `size-5 flex-shrink-0 mt-0.5 ${M ? "text-status-warning-text" : "text-status-error-text"}` }), /* @__PURE__ */ f("div", {
|
|
47
48
|
className: "flex-1",
|
|
@@ -230,7 +231,7 @@ function h() {
|
|
|
230
231
|
}),
|
|
231
232
|
/* @__PURE__ */ f("div", {
|
|
232
233
|
className: "mt-6 p-4 rounded-xl bg-bg-canvas/50 border border-border-subtle",
|
|
233
|
-
children: [/* @__PURE__ */ d("
|
|
234
|
+
children: [/* @__PURE__ */ d("h2", {
|
|
234
235
|
className: "text-sm font-medium text-[var(--color-text-primary)] mb-2",
|
|
235
236
|
children: h("auth.ssoLogin.noSso", "Don't see your company's SSO?")
|
|
236
237
|
}), /* @__PURE__ */ d("p", {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SsoLoginPage.js","names":["_Fragment","SsoLoginPage","tr","useTr","navigate","useNavigate","searchParams","useSearchParams","tenantFromUrl","methodFromUrl","useSsoOperations","email","setEmail","useState","error","setError","ssoMethod","setSsoMethod","isInitiating","setIsInitiating","isSsoNotConfigured","setIsSsoNotConfigured","handleSubmit","domain","tenantId","initiateExternalOidcLogin","initiateSsoLogin","err","errorMessage","isSubmitting","isGeneratingRequest","isGeneratingOidcUrl","AuthLayout","PagePurpose","AlertIcon","EmailIcon","Button","Fragment","SpinnerIcon"],"sources":["../../../src/auth/pages/SsoLoginPage.tsx"],"sourcesContent":["import { useState, useEffect } from \"react\";\nimport { useTr } from \"../../shared/hooks/useTr\";\nimport { useNavigate, useSearchParams } from \"react-router\";\nimport { useSsoOperations } from \"../hooks/useSsoOperations\";\nimport { AuthLayout } from \"../components/AuthLayout\";\nimport { Button } from \"@burdenoff/fe-libs/button\";\nimport { PagePurpose } from \"@burdenoff/fe-libs/ui\";\nimport { EmailIcon, SpinnerIcon, AlertIcon } from \"../components/AuthIcons\";\n\ntype SsoMethod = \"saml\" | \"oidc\";\n\n/**\n * SSO Login Page\n * Allows users to enter their email/company domain to initiate SSO login\n * Supports both SAML 2.0 and OIDC authentication methods\n */\nexport function SsoLoginPage() {\n const tr = useTr();\n\n const navigate = useNavigate();\n const [searchParams] = useSearchParams();\n const tenantFromUrl = searchParams.get(\"tenant\");\n const methodFromUrl = searchParams.get(\"method\") as SsoMethod | null;\n const {\n initiateSsoLogin,\n initiateExternalOidcLogin,\n isGeneratingRequest,\n isGeneratingOidcUrl,\n } = useSsoOperations(tenantFromUrl ?? undefined);\n\n const [email, setEmail] = useState(\"\");\n const [error, setError] = useState<string | null>(null);\n const [ssoMethod, setSsoMethod] = useState<SsoMethod>(\"oidc\");\n const [isInitiating, setIsInitiating] = useState(false);\n const [isSsoNotConfigured, setIsSsoNotConfigured] = useState(false);\n\n // Set method from URL if provided\n useEffect(() => {\n if (methodFromUrl === \"saml\" || methodFromUrl === \"oidc\") {\n setSsoMethod(methodFromUrl);\n }\n }, [methodFromUrl]);\n\n const handleSubmit = async (e: React.FormEvent) => {\n e.preventDefault();\n setError(null);\n setIsSsoNotConfigured(false);\n setIsInitiating(true);\n\n try {\n // Extract domain from email\n const domain = email.split(\"@\")[1];\n if (!domain) {\n setError(\n tr(\n \"auth.ssoLogin.invalidEmailDomain\",\n \"Please enter a valid email address with your company domain\",\n ),\n );\n setIsInitiating(false);\n return;\n }\n\n // In a real app, you would look up the tenant by domain\n // For now, we'll use the tenant from URL or the domain itself\n const tenantId = tenantFromUrl || domain;\n\n // Store email for post-login\n sessionStorage.setItem(\"sso_email\", email);\n\n if (ssoMethod === \"oidc\") {\n // External OIDC flow (Azure AD, Google, etc.)\n await initiateExternalOidcLogin(tenantId, \"/dashboard\");\n } else {\n await initiateSsoLogin(tenantId, \"/dashboard\");\n }\n } catch (err) {\n console.error(\"SSO login failed:\", err);\n const errorMessage =\n err instanceof Error\n ? err.message\n : \"Failed to initiate SSO login. Please check your configuration.\";\n\n // Check if error is about SSO not being configured\n if (\n errorMessage.toLowerCase().includes(\"sso\") &&\n (errorMessage.toLowerCase().includes(\"not configured\") ||\n errorMessage.toLowerCase().includes(\"not set up\"))\n ) {\n setIsSsoNotConfigured(true);\n setError(\n tr(\n \"auth.ssoLogin.ssoNotConfigured\",\n \"SSO is not configured for your organization. Please use regular email/password login or contact your administrator to set up SSO.\",\n ),\n );\n } else {\n setError(errorMessage);\n }\n\n setIsInitiating(false);\n }\n };\n\n const isSubmitting =\n isGeneratingRequest || isGeneratingOidcUrl || isInitiating;\n\n return (\n <AuthLayout\n title={tr(\"auth.ssoLogin.title\", \"Enterprise SSO\")}\n subtitle={tr(\n \"auth.ssoLogin.subtitle\",\n \"Sign in with your company's identity provider\",\n )}\n >\n <PagePurpose className=\"mb-5\">\n {tr(\n \"auth.ssoLogin.purpose\",\n \"Sign in through your company's identity provider (Okta, Azure AD, Google, and more). Enter your work email and we'll route you to your organization's OIDC or SAML login.\",\n )}\n </PagePurpose>\n <form onSubmit={handleSubmit} className=\"space-y-5\">\n {/* Error Alert */}\n {error && (\n <div\n className={`flex items-start gap-3 p-4 rounded-xl border ${\n isSsoNotConfigured\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 isSsoNotConfigured\n ? \"text-status-warning-text\"\n : \"text-status-error-text\"\n }`}\n />\n <div className=\"flex-1\">\n <p\n className={`text-sm ${\n isSsoNotConfigured\n ? \"text-status-warning-text\"\n : \"text-status-error-text\"\n }`}\n >\n {error}\n </p>\n {isSsoNotConfigured && (\n <button\n type=\"button\"\n onClick={() => navigate(\"/auth/login\", { state: { email } })}\n className=\"mt-3 inline-flex items-center gap-2 px-4 py-2 rounded-lg bg-status-warning-bg-subtle hover:bg-status-warning-bg-subtle text-status-warning-text text-sm font-semibold transition-all\"\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=\"M11 16l-4-4m0 0l4-4m-4 4h14m-5 4v1a3 3 0 01-3 3H6a3 3 0 01-3-3V7a3 3 0 013-3h7a3 3 0 013 3v1\"\n />\n </svg>\n {tr(\n \"auth.ssoLogin.useEmailLogin\",\n \"Use Email/Password Login Instead\",\n )}\n </button>\n )}\n </div>\n </div>\n )}\n\n {/* SSO Method Toggle */}\n <div className=\"space-y-2\">\n <label className=\"block text-sm font-medium text-[var(--color-text-primary)]\">\n {tr(\"auth.ssoLogin.authMethod\", \"Authentication Method\")}\n </label>\n <div className=\"grid grid-cols-2 gap-3\">\n <button\n type=\"button\"\n onClick={() => setSsoMethod(\"oidc\")}\n className={`p-4 rounded-xl border-2 transition-all ${\n ssoMethod === \"oidc\"\n ? \"border-action-primary-bg bg-status-info-bg-subtle\"\n : \"border-border-subtle hover:border-border-default\"\n }`}\n >\n <div className=\"flex items-center gap-3\">\n <div\n className={`size-10 rounded-lg flex items-center justify-center ${\n ssoMethod === \"oidc\"\n ? \"bg-status-info-bg-subtle0\"\n : \"bg-bg-sunken\"\n }`}\n >\n <svg\n className={`size-5 ${ssoMethod === \"oidc\" ? \"text-white\" : \"text-text-secondary\"}`}\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=\"M21 12a9 9 0 01-9 9m9-9a9 9 0 00-9-9m9 9H3m9 9a9 9 0 01-9-9m9 9c1.657 0 3-4.03 3-9s-1.343-9-3-9m0 18c-1.657 0-3-4.03-3-9s1.343-9 3-9m-9 9a9 9 0 019-9\"\n />\n </svg>\n </div>\n <div className=\"text-left\">\n <div\n className={`font-medium ${ssoMethod === \"oidc\" ? \"text-text-linkHover\" : \"text-text-primary\"}`}\n >\n OpenID Connect\n </div>\n <div className=\"text-xs text-text-secondary\">\n {tr(\n \"auth.ssoLogin.modernRecommended\",\n \"Modern & Recommended\",\n )}\n </div>\n </div>\n </div>\n </button>\n\n <button\n type=\"button\"\n onClick={() => setSsoMethod(\"saml\")}\n className={`p-4 rounded-xl border-2 transition-all ${\n ssoMethod === \"saml\"\n ? \"border-accent-purple bg-accent-purple-subtle\"\n : \"border-border-subtle hover:border-border-default\"\n }`}\n >\n <div className=\"flex items-center gap-3\">\n <div\n className={`size-10 rounded-lg flex items-center justify-center ${\n ssoMethod === \"saml\"\n ? \"bg-accent-purple-subtle0\"\n : \"bg-bg-sunken\"\n }`}\n >\n <svg\n className={`size-5 ${ssoMethod === \"saml\" ? \"text-white\" : \"text-text-secondary\"}`}\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=\"M9 12l2 2 4-4m5.618-4.016A11.955 11.955 0 0112 2.944a11.955 11.955 0 01-8.618 3.04A12.02 12.02 0 003 9c0 5.591 3.824 10.29 9 11.622 5.176-1.332 9-6.03 9-11.622 0-1.042-.133-2.052-.382-3.016z\"\n />\n </svg>\n </div>\n <div className=\"text-left\">\n <div\n className={`font-medium ${ssoMethod === \"saml\" ? \"text-accent-purple\" : \"text-text-primary\"}`}\n >\n SAML 2.0\n </div>\n <div className=\"text-xs text-text-secondary\">\n {tr(\"auth.ssoLogin.enterpriseLegacy\", \"Enterprise Legacy\")}\n </div>\n </div>\n </div>\n </button>\n </div>\n </div>\n\n {/* Info Banner */}\n <div\n className={`p-4 rounded-xl border ${\n ssoMethod === \"oidc\"\n ? \"bg-status-info-bg-subtle border-status-info-border\"\n : \"bg-accent-purple-subtle border-accent-purple-subtle\"\n }`}\n >\n <p\n className={`text-sm ${\n ssoMethod === \"oidc\"\n ? \"text-status-info-text\"\n : \"text-accent-purple\"\n }`}\n >\n {ssoMethod === \"oidc\"\n ? tr(\n \"auth.sso.oidcInfoBannerPkce\",\n \"Sign in using OpenID Connect with your identity provider. Supports modern SSO with PKCE security.\",\n )\n : tr(\n \"auth.sso.samlInfoBanner\",\n \"Sign in using SAML 2.0 with your enterprise identity provider (Okta, Azure AD, etc.).\",\n )}\n </p>\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.ssoLogin.workEmail\", \"Work Email Address\")}\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.ssoLogin.workEmail\", \"Work Email Address\")}\n value={email}\n onChange={(e) => setEmail(e.target.value)}\n autoComplete=\"email\"\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.ssoLogin.emailPlaceholder\",\n \"you@company.com\",\n )}\n />\n </div>\n <p className=\"text-xs text-[var(--color-text-tertiary)]\">\n {tr(\n \"auth.ssoLogin.useCompanyEmail\",\n \"Use your company email (e.g., @yourcompany.com)\",\n )}\n </p>\n </div>\n\n {/* Submit Button */}\n <Button\n type=\"submit\"\n disabled={isSubmitting || !email}\n variant=\"default\"\n size=\"lg\"\n className={`w-full font-semibold ${\n ssoMethod === \"saml\"\n ? \"bg-accent-purple text-white hover:bg-accent-purple hover:opacity-90\"\n : \"\"\n }`}\n >\n {isSubmitting ? (\n <>\n <SpinnerIcon className=\"size-5 animate-spin\" />\n <span>{tr(\"auth.sso.redirecting\", \"Redirecting...\")}</span>\n </>\n ) : (\n <>\n <svg\n className=\"size-5\"\n fill=\"none\"\n viewBox=\"0 0 24 24\"\n stroke=\"currentColor\"\n aria-hidden=\"true\"\n >\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth={2}\n d=\"M11 16l-4-4m0 0l4-4m-4 4h14m-5 4v1a3 3 0 01-3 3H6a3 3 0 01-3-3V7a3 3 0 013-3h7a3 3 0 013 3v1\"\n />\n </svg>\n <span>\n {ssoMethod === \"oidc\"\n ? tr(\"auth.sso.continueWithOidc\", \"Continue with OIDC\")\n : tr(\"auth.sso.continueWithSaml\", \"Continue with SAML\")}\n </span>\n </>\n )}\n </Button>\n </form>\n\n {/* Back to Regular Login */}\n <div className=\"mt-6 text-center\">\n <button\n type=\"button\"\n onClick={() => navigate(\"/auth/login\")}\n className=\"text-sm text-[var(--color-text-secondary)] hover:text-[var(--color-text-primary)] transition-colors\"\n >\n <span className=\"font-semibold text-text-link hover:text-text-linkHover\">\n {tr(\"auth.ssoLogin.backToLogin\", \"Back to regular login\")}\n </span>\n </button>\n </div>\n\n {/* Reactivate Account Link */}\n <div className=\"mt-4 text-center\">\n <button\n type=\"button\"\n onClick={() => navigate(\"/auth/reactivate\")}\n className=\"text-sm text-[var(--color-text-secondary)] hover:text-[var(--color-text-primary)] transition-colors\"\n >\n {tr(\n \"auth.ssoLogin.deactivatedAccount\",\n \"Have a deactivated account?\",\n )}{\" \"}\n <span className=\"font-semibold text-status-success-text hover:text-status-success-text\">\n {tr(\"auth.ssoLogin.reactivateIt\", \"Reactivate it\")}\n </span>\n </button>\n </div>\n\n {/* Help Text */}\n <div className=\"mt-6 p-4 rounded-xl bg-bg-canvas/50 border border-border-subtle\">\n <h4 className=\"text-sm font-medium text-[var(--color-text-primary)] mb-2\">\n {tr(\"auth.ssoLogin.noSso\", \"Don't see your company's SSO?\")}\n </h4>\n <p className=\"text-xs text-[var(--color-text-secondary)]\">\n {tr(\n \"auth.ssoLogin.contactIT\",\n \"Contact your IT administrator to set up SSO for your organization. They'll need to configure your identity provider with our service.\",\n )}\n </p>\n </div>\n </AuthLayout>\n );\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"SsoLoginPage.js","names":["_Fragment","SsoLoginPage","tr","useTr","navigate","useNavigate","searchParams","useSearchParams","tenantFromUrl","methodFromUrl","useSsoOperations","email","setEmail","useState","error","setError","ssoMethod","setSsoMethod","isInitiating","setIsInitiating","isSsoNotConfigured","setIsSsoNotConfigured","handleSubmit","domain","tenantId","initiateExternalOidcLogin","initiateSsoLogin","err","errorMessage","isSubmitting","isGeneratingRequest","isGeneratingOidcUrl","AuthLayout","PagePurpose","AlertIcon","EmailIcon","Button","Fragment","SpinnerIcon"],"sources":["../../../src/auth/pages/SsoLoginPage.tsx"],"sourcesContent":["import { useState, useEffect } from \"react\";\nimport { useTr } from \"../../shared/hooks/useTr\";\nimport { useNavigate, useSearchParams } from \"react-router\";\nimport { useSsoOperations } from \"../hooks/useSsoOperations\";\nimport { AuthLayout } from \"../components/AuthLayout\";\nimport { Button } from \"@burdenoff/fe-libs/button\";\nimport { PagePurpose } from \"@burdenoff/fe-libs/ui\";\nimport { EmailIcon, SpinnerIcon, AlertIcon } from \"../components/AuthIcons\";\n\ntype SsoMethod = \"saml\" | \"oidc\";\n\n/**\n * SSO Login Page\n * Allows users to enter their email/company domain to initiate SSO login\n * Supports both SAML 2.0 and OIDC authentication methods\n */\nexport function SsoLoginPage() {\n const tr = useTr();\n\n const navigate = useNavigate();\n const [searchParams] = useSearchParams();\n const tenantFromUrl = searchParams.get(\"tenant\");\n const methodFromUrl = searchParams.get(\"method\") as SsoMethod | null;\n const {\n initiateSsoLogin,\n initiateExternalOidcLogin,\n isGeneratingRequest,\n isGeneratingOidcUrl,\n } = useSsoOperations(tenantFromUrl ?? undefined);\n\n const [email, setEmail] = useState(\"\");\n const [error, setError] = useState<string | null>(null);\n const [ssoMethod, setSsoMethod] = useState<SsoMethod>(\"oidc\");\n const [isInitiating, setIsInitiating] = useState(false);\n const [isSsoNotConfigured, setIsSsoNotConfigured] = useState(false);\n\n // Set method from URL if provided\n useEffect(() => {\n if (methodFromUrl === \"saml\" || methodFromUrl === \"oidc\") {\n setSsoMethod(methodFromUrl);\n }\n }, [methodFromUrl]);\n\n const handleSubmit = async (e: React.FormEvent) => {\n e.preventDefault();\n setError(null);\n setIsSsoNotConfigured(false);\n setIsInitiating(true);\n\n try {\n // Extract domain from email\n const domain = email.split(\"@\")[1];\n if (!domain) {\n setError(\n tr(\n \"auth.ssoLogin.invalidEmailDomain\",\n \"Please enter a valid email address with your company domain\",\n ),\n );\n setIsInitiating(false);\n return;\n }\n\n // In a real app, you would look up the tenant by domain\n // For now, we'll use the tenant from URL or the domain itself\n const tenantId = tenantFromUrl || domain;\n\n // Store email for post-login\n sessionStorage.setItem(\"sso_email\", email);\n\n if (ssoMethod === \"oidc\") {\n // External OIDC flow (Azure AD, Google, etc.)\n await initiateExternalOidcLogin(tenantId, \"/dashboard\");\n } else {\n await initiateSsoLogin(tenantId, \"/dashboard\");\n }\n } catch (err) {\n console.error(\"SSO login failed:\", err);\n const errorMessage =\n err instanceof Error\n ? err.message\n : \"Failed to initiate SSO login. Please check your configuration.\";\n\n // Check if error is about SSO not being configured\n if (\n errorMessage.toLowerCase().includes(\"sso\") &&\n (errorMessage.toLowerCase().includes(\"not configured\") ||\n errorMessage.toLowerCase().includes(\"not set up\"))\n ) {\n setIsSsoNotConfigured(true);\n setError(\n tr(\n \"auth.ssoLogin.ssoNotConfigured\",\n \"SSO is not configured for your organization. Please use regular email/password login or contact your administrator to set up SSO.\",\n ),\n );\n } else {\n setError(errorMessage);\n }\n\n setIsInitiating(false);\n }\n };\n\n const isSubmitting =\n isGeneratingRequest || isGeneratingOidcUrl || isInitiating;\n\n return (\n <AuthLayout\n title={tr(\"auth.ssoLogin.title\", \"Enterprise SSO\")}\n subtitle={tr(\n \"auth.ssoLogin.subtitle\",\n \"Sign in with your company's identity provider\",\n )}\n >\n <PagePurpose className=\"mb-5\">\n {tr(\n \"auth.ssoLogin.purpose\",\n \"Sign in through your company's identity provider (Okta, Azure AD, Google, and more). Enter your work email and we'll route you to your organization's OIDC or SAML login.\",\n )}\n </PagePurpose>\n <form onSubmit={handleSubmit} className=\"space-y-5\">\n {/* Error Alert */}\n {error && (\n <div\n role=\"alert\"\n className={`flex items-start gap-3 p-4 rounded-xl border ${\n isSsoNotConfigured\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 isSsoNotConfigured\n ? \"text-status-warning-text\"\n : \"text-status-error-text\"\n }`}\n />\n <div className=\"flex-1\">\n <p\n className={`text-sm ${\n isSsoNotConfigured\n ? \"text-status-warning-text\"\n : \"text-status-error-text\"\n }`}\n >\n {error}\n </p>\n {isSsoNotConfigured && (\n <button\n type=\"button\"\n onClick={() => navigate(\"/auth/login\", { state: { email } })}\n className=\"mt-3 inline-flex items-center gap-2 px-4 py-2 rounded-lg bg-status-warning-bg-subtle hover:bg-status-warning-bg-subtle text-status-warning-text text-sm font-semibold transition-all\"\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=\"M11 16l-4-4m0 0l4-4m-4 4h14m-5 4v1a3 3 0 01-3 3H6a3 3 0 01-3-3V7a3 3 0 013-3h7a3 3 0 013 3v1\"\n />\n </svg>\n {tr(\n \"auth.ssoLogin.useEmailLogin\",\n \"Use Email/Password Login Instead\",\n )}\n </button>\n )}\n </div>\n </div>\n )}\n\n {/* SSO Method Toggle */}\n <div className=\"space-y-2\">\n <label className=\"block text-sm font-medium text-[var(--color-text-primary)]\">\n {tr(\"auth.ssoLogin.authMethod\", \"Authentication Method\")}\n </label>\n <div className=\"grid grid-cols-2 gap-3\">\n <button\n type=\"button\"\n onClick={() => setSsoMethod(\"oidc\")}\n className={`p-4 rounded-xl border-2 transition-all ${\n ssoMethod === \"oidc\"\n ? \"border-action-primary-bg bg-status-info-bg-subtle\"\n : \"border-border-subtle hover:border-border-default\"\n }`}\n >\n <div className=\"flex items-center gap-3\">\n <div\n className={`size-10 rounded-lg flex items-center justify-center ${\n ssoMethod === \"oidc\"\n ? \"bg-status-info-bg-subtle0\"\n : \"bg-bg-sunken\"\n }`}\n >\n <svg\n className={`size-5 ${ssoMethod === \"oidc\" ? \"text-white\" : \"text-text-secondary\"}`}\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=\"M21 12a9 9 0 01-9 9m9-9a9 9 0 00-9-9m9 9H3m9 9a9 9 0 01-9-9m9 9c1.657 0 3-4.03 3-9s-1.343-9-3-9m0 18c-1.657 0-3-4.03-3-9s1.343-9 3-9m-9 9a9 9 0 019-9\"\n />\n </svg>\n </div>\n <div className=\"text-left\">\n <div\n className={`font-medium ${ssoMethod === \"oidc\" ? \"text-text-linkHover\" : \"text-text-primary\"}`}\n >\n OpenID Connect\n </div>\n <div className=\"text-xs text-text-secondary\">\n {tr(\n \"auth.ssoLogin.modernRecommended\",\n \"Modern & Recommended\",\n )}\n </div>\n </div>\n </div>\n </button>\n\n <button\n type=\"button\"\n onClick={() => setSsoMethod(\"saml\")}\n className={`p-4 rounded-xl border-2 transition-all ${\n ssoMethod === \"saml\"\n ? \"border-accent-purple bg-accent-purple-subtle\"\n : \"border-border-subtle hover:border-border-default\"\n }`}\n >\n <div className=\"flex items-center gap-3\">\n <div\n className={`size-10 rounded-lg flex items-center justify-center ${\n ssoMethod === \"saml\"\n ? \"bg-accent-purple-subtle0\"\n : \"bg-bg-sunken\"\n }`}\n >\n <svg\n className={`size-5 ${ssoMethod === \"saml\" ? \"text-white\" : \"text-text-secondary\"}`}\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=\"M9 12l2 2 4-4m5.618-4.016A11.955 11.955 0 0112 2.944a11.955 11.955 0 01-8.618 3.04A12.02 12.02 0 003 9c0 5.591 3.824 10.29 9 11.622 5.176-1.332 9-6.03 9-11.622 0-1.042-.133-2.052-.382-3.016z\"\n />\n </svg>\n </div>\n <div className=\"text-left\">\n <div\n className={`font-medium ${ssoMethod === \"saml\" ? \"text-accent-purple\" : \"text-text-primary\"}`}\n >\n SAML 2.0\n </div>\n <div className=\"text-xs text-text-secondary\">\n {tr(\"auth.ssoLogin.enterpriseLegacy\", \"Enterprise Legacy\")}\n </div>\n </div>\n </div>\n </button>\n </div>\n </div>\n\n {/* Info Banner */}\n <div\n className={`p-4 rounded-xl border ${\n ssoMethod === \"oidc\"\n ? \"bg-status-info-bg-subtle border-status-info-border\"\n : \"bg-accent-purple-subtle border-accent-purple-subtle\"\n }`}\n >\n <p\n className={`text-sm ${\n ssoMethod === \"oidc\"\n ? \"text-status-info-text\"\n : \"text-accent-purple\"\n }`}\n >\n {ssoMethod === \"oidc\"\n ? tr(\n \"auth.sso.oidcInfoBannerPkce\",\n \"Sign in using OpenID Connect with your identity provider. Supports modern SSO with PKCE security.\",\n )\n : tr(\n \"auth.sso.samlInfoBanner\",\n \"Sign in using SAML 2.0 with your enterprise identity provider (Okta, Azure AD, etc.).\",\n )}\n </p>\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.ssoLogin.workEmail\", \"Work Email Address\")}\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.ssoLogin.workEmail\", \"Work Email Address\")}\n value={email}\n onChange={(e) => setEmail(e.target.value)}\n autoComplete=\"email\"\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.ssoLogin.emailPlaceholder\",\n \"you@company.com\",\n )}\n />\n </div>\n <p className=\"text-xs text-[var(--color-text-tertiary)]\">\n {tr(\n \"auth.ssoLogin.useCompanyEmail\",\n \"Use your company email (e.g., @yourcompany.com)\",\n )}\n </p>\n </div>\n\n {/* Submit Button */}\n <Button\n type=\"submit\"\n disabled={isSubmitting || !email}\n variant=\"default\"\n size=\"lg\"\n className={`w-full font-semibold ${\n ssoMethod === \"saml\"\n ? \"bg-accent-purple text-white hover:bg-accent-purple hover:opacity-90\"\n : \"\"\n }`}\n >\n {isSubmitting ? (\n <>\n <SpinnerIcon className=\"size-5 animate-spin\" />\n <span>{tr(\"auth.sso.redirecting\", \"Redirecting...\")}</span>\n </>\n ) : (\n <>\n <svg\n className=\"size-5\"\n fill=\"none\"\n viewBox=\"0 0 24 24\"\n stroke=\"currentColor\"\n aria-hidden=\"true\"\n >\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth={2}\n d=\"M11 16l-4-4m0 0l4-4m-4 4h14m-5 4v1a3 3 0 01-3 3H6a3 3 0 01-3-3V7a3 3 0 013-3h7a3 3 0 013 3v1\"\n />\n </svg>\n <span>\n {ssoMethod === \"oidc\"\n ? tr(\"auth.sso.continueWithOidc\", \"Continue with OIDC\")\n : tr(\"auth.sso.continueWithSaml\", \"Continue with SAML\")}\n </span>\n </>\n )}\n </Button>\n </form>\n\n {/* Back to Regular Login */}\n <div className=\"mt-6 text-center\">\n <button\n type=\"button\"\n onClick={() => navigate(\"/auth/login\")}\n className=\"text-sm text-[var(--color-text-secondary)] hover:text-[var(--color-text-primary)] transition-colors\"\n >\n <span className=\"font-semibold text-text-link hover:text-text-linkHover\">\n {tr(\"auth.ssoLogin.backToLogin\", \"Back to regular login\")}\n </span>\n </button>\n </div>\n\n {/* Reactivate Account Link */}\n <div className=\"mt-4 text-center\">\n <button\n type=\"button\"\n onClick={() => navigate(\"/auth/reactivate\")}\n className=\"text-sm text-[var(--color-text-secondary)] hover:text-[var(--color-text-primary)] transition-colors\"\n >\n {tr(\n \"auth.ssoLogin.deactivatedAccount\",\n \"Have a deactivated account?\",\n )}{\" \"}\n <span className=\"font-semibold text-status-success-text hover:text-status-success-text\">\n {tr(\"auth.ssoLogin.reactivateIt\", \"Reactivate it\")}\n </span>\n </button>\n </div>\n\n {/* Help Text */}\n <div className=\"mt-6 p-4 rounded-xl bg-bg-canvas/50 border border-border-subtle\">\n <h2 className=\"text-sm font-medium text-[var(--color-text-primary)] mb-2\">\n {tr(\"auth.ssoLogin.noSso\", \"Don't see your company's SSO?\")}\n </h2>\n <p className=\"text-xs text-[var(--color-text-secondary)]\">\n {tr(\n \"auth.ssoLogin.contactIT\",\n \"Contact your IT administrator to set up SSO for your organization. They'll need to configure your identity provider with our service.\",\n )}\n </p>\n </div>\n </AuthLayout>\n );\n}\n"],"mappings":"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"}
|
package/dist/microfe-auth.css
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
/*! tailwindcss v4.3.4 | MIT License | https://tailwindcss.com */
|
|
2
|
-
@layer properties{@supports (((-webkit-hyphens:none)) and (not (margin-trim:block))) 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-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:var(--color-action-primary-bg,#2563eb);--color-primary-foreground:var(--color-action-primary-text,#fff)}}@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,-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", "Noto Sans", Arial, 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:where(:not(iframe)){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}.collapse{visibility:collapse}.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-10{height:calc(var(--spacing) * 10)}.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,.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:2147483647px}.rounded-lg{border-radius:var(--radius-lg)}.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)}}.bg-primary,.bg-primary\/5{background-color:var(--color-primary)}@supports (color:color-mix(in lab, red, red)){.bg-primary\/5{background-color:color-mix(in oklab, var(--color-primary) 5%, transparent)}}.bg-primary\/10{background-color:var(--color-primary)}@supports (color:color-mix(in lab, red, red)){.bg-primary\/10{background-color:color-mix(in oklab, var(--color-primary) 10%, transparent)}}.bg-primary\/15{background-color:var(--color-primary)}@supports (color:color-mix(in lab, red, red)){.bg-primary\/15{background-color:color-mix(in oklab, var(--color-primary) 15%, transparent)}}.object-contain{-o-object-fit:contain;object-fit:contain}.object-cover{-o-object-fit:cover;object-fit:cover}.p-1{padding:var(--spacing)}.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)}.px-8{padding-inline:calc(var(--spacing) * 8)}.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-primary{color:var(--color-primary)}.text-primary-foreground{color:var(--color-primary-foreground)}.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)}.scheme-normal{color-scheme:normal}.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){:is(:where(.group):hover .group-hover\:bg-\[var\(--color-action-primary-bg-subtle\)\]){background-color:var(--color-action-primary-bg-subtle)}:is(:where(.group):hover .group-hover\:bg-\[var\(--color-action-secondary-bg-subtle\)\]){background-color:var(--color-action-secondary-bg-subtle)}:is(:where(.group):hover .group-hover\:text-\[var\(--color-text-primary\)\]){color:var(--color-text-primary)}:is(:where(.group):hover .group-hover\:text-indigo-500){color:var(--color-indigo-500)}:is(:where(.group):hover .group-hover\:opacity-100){opacity:1}}.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\:bg-primary\/90:hover{background-color:var(--color-primary)}@supports (color:color-mix(in lab, red, red)){.hover\:bg-primary\/90:hover{background-color:color-mix(in oklab, var(--color-primary) 90%, transparent)}}.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:var(--color-primary)}@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}}@media (prefers-color-scheme:dark){.dark\:scheme-dark{--lightningcss-light: ;--lightningcss-dark:initial;color-scheme:dark}}}.dark{--color-background:#020817;--color-foreground:#f8fafc;--color-card:#020817;--color-card-foreground:#020817;--color-popover:#020817;--color-popover-foreground:#020817;--color-primary:var(--color-action-primary-bg,#3b82f6);--color-primary-foreground:var(--color-action-primary-text,#0f172a);--color-ring:var(--color-action-primary-bg,#3b82f6);--color-secondary:#1e293b;--color-secondary-foreground:#f8fafc;--color-muted:#1e293b;--color-muted-foreground:#94a3b8;--color-accent:#1e293b;--color-accent-foreground:#f8fafc;--color-destructive:#7f1d1d;--color-destructive-foreground:#f8fafc;--color-border:#1e293b;--color-input:#1e293b}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:block))) 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-outline-style:solid;--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-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:var(--color-action-primary-bg,#2563eb);--color-primary-foreground:var(--color-action-primary-text,#fff)}}@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,-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", "Noto Sans", Arial, 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:where(:not(iframe)){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}.collapse{visibility:collapse}.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-10{height:calc(var(--spacing) * 10)}.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,.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:2147483647px}.rounded-lg{border-radius:var(--radius-lg)}.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)}}.bg-primary,.bg-primary\/5{background-color:var(--color-primary)}@supports (color:color-mix(in lab, red, red)){.bg-primary\/5{background-color:color-mix(in oklab, var(--color-primary) 5%, transparent)}}.bg-primary\/10{background-color:var(--color-primary)}@supports (color:color-mix(in lab, red, red)){.bg-primary\/10{background-color:color-mix(in oklab, var(--color-primary) 10%, transparent)}}.bg-primary\/15{background-color:var(--color-primary)}@supports (color:color-mix(in lab, red, red)){.bg-primary\/15{background-color:color-mix(in oklab, var(--color-primary) 15%, transparent)}}.object-contain{-o-object-fit:contain;object-fit:contain}.object-cover{-o-object-fit:cover;object-fit:cover}.p-1{padding:var(--spacing)}.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)}.px-8{padding-inline:calc(var(--spacing) * 8)}.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-primary{color:var(--color-primary)}.text-primary-foreground{color:var(--color-primary-foreground)}.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)}.scheme-normal{color-scheme:normal}.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)}.outline{outline-style:var(--tw-outline-style);outline-width:1px}.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){:is(:where(.group):hover .group-hover\:bg-\[var\(--color-action-primary-bg-subtle\)\]){background-color:var(--color-action-primary-bg-subtle)}:is(:where(.group):hover .group-hover\:bg-\[var\(--color-action-secondary-bg-subtle\)\]){background-color:var(--color-action-secondary-bg-subtle)}:is(:where(.group):hover .group-hover\:text-\[var\(--color-text-primary\)\]){color:var(--color-text-primary)}:is(:where(.group):hover .group-hover\:text-indigo-500){color:var(--color-indigo-500)}:is(:where(.group):hover .group-hover\:opacity-100){opacity:1}}.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\:bg-primary\/90:hover{background-color:var(--color-primary)}@supports (color:color-mix(in lab, red, red)){.hover\:bg-primary\/90:hover{background-color:color-mix(in oklab, var(--color-primary) 90%, transparent)}}.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:var(--color-primary)}@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}}@media (prefers-color-scheme:dark){.dark\:scheme-dark{--lightningcss-light: ;--lightningcss-dark:initial;color-scheme:dark}}}.dark{--color-background:#020817;--color-foreground:#f8fafc;--color-card:#020817;--color-card-foreground:#020817;--color-popover:#020817;--color-popover-foreground:#020817;--color-primary:var(--color-action-primary-bg,#3b82f6);--color-primary-foreground:var(--color-action-primary-text,#0f172a);--color-ring:var(--color-action-primary-bg,#3b82f6);--color-secondary:#1e293b;--color-secondary-foreground:#f8fafc;--color-muted:#1e293b;--color-muted-foreground:#94a3b8;--color-accent:#1e293b;--color-accent-foreground:#f8fafc;--color-destructive:#7f1d1d;--color-destructive-foreground:#f8fafc;--color-border:#1e293b;--color-input:#1e293b}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-outline-style{syntax:"*";inherits:false;initial-value:solid}@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*/
|