@burdenoff/microfe-auth 2026.527.2 → 2026.527.3

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.
Files changed (44) hide show
  1. package/dist/auth/components/CaptchaV2.js.map +1 -1
  2. package/dist/auth/components/workspace/WorkspaceSelector.js +103 -93
  3. package/dist/auth/components/workspace/WorkspaceSelector.js.map +1 -1
  4. package/dist/auth/hooks/useContextSwitcherData.js +1 -1
  5. package/dist/auth/hooks/useContextSwitcherData.js.map +1 -1
  6. package/dist/auth/hooks/useMyWorkspaces.js +1 -1
  7. package/dist/auth/hooks/useMyWorkspaces.js.map +1 -1
  8. package/dist/auth/hooks/useWorkspaceToken.js +24 -24
  9. package/dist/auth/hooks/useWorkspaceToken.js.map +1 -1
  10. package/dist/auth/pages/AuditLogPage.js +3 -5
  11. package/dist/auth/pages/AuditLogPage.js.map +1 -1
  12. package/dist/auth/pages/EmailVerifyPage.js +21 -21
  13. package/dist/auth/pages/EmailVerifyPage.js.map +1 -1
  14. package/dist/auth/pages/LoginPage.js +3 -0
  15. package/dist/auth/pages/LoginPage.js.map +1 -1
  16. package/dist/auth/pages/MagicLinkPage.js +92 -95
  17. package/dist/auth/pages/MagicLinkPage.js.map +1 -1
  18. package/dist/auth/pages/MfaVerifyPage.js +1 -0
  19. package/dist/auth/pages/MfaVerifyPage.js.map +1 -1
  20. package/dist/auth/pages/OAuthCallbackPage.js +6 -1
  21. package/dist/auth/pages/OAuthCallbackPage.js.map +1 -1
  22. package/dist/auth/pages/PasswordResetPage.js +3 -0
  23. package/dist/auth/pages/PasswordResetPage.js.map +1 -1
  24. package/dist/auth/pages/ReactivatePage.js +2 -0
  25. package/dist/auth/pages/ReactivatePage.js.map +1 -1
  26. package/dist/auth/pages/RegisterPage.js +5 -0
  27. package/dist/auth/pages/RegisterPage.js.map +1 -1
  28. package/dist/auth/pages/SSORelayPage.js +39 -33
  29. package/dist/auth/pages/SSORelayPage.js.map +1 -1
  30. package/dist/auth/pages/SecurityPage.js +7 -6
  31. package/dist/auth/pages/SecurityPage.js.map +1 -1
  32. package/dist/auth/pages/SessionsPage.js +5 -8
  33. package/dist/auth/pages/SessionsPage.js.map +1 -1
  34. package/dist/auth/pages/SsoCallbackPage.js +11 -8
  35. package/dist/auth/pages/SsoCallbackPage.js.map +1 -1
  36. package/dist/auth/pages/SsoConfigPage.js +10 -1
  37. package/dist/auth/pages/SsoConfigPage.js.map +1 -1
  38. package/dist/auth/pages/SsoLoginPage.js +1 -0
  39. package/dist/auth/pages/SsoLoginPage.js.map +1 -1
  40. package/dist/auth/pages/UserProfilePage.js +7 -1
  41. package/dist/auth/pages/UserProfilePage.js.map +1 -1
  42. package/dist/auth/pages/UsersPage.js +10 -3
  43. package/dist/auth/pages/UsersPage.js.map +1 -1
  44. package/package.json +1 -1
@@ -2,41 +2,44 @@ import { useEffect as e } from "react";
2
2
  import { useSearchParams as t } from "react-router-dom";
3
3
  import { jsx as n } from "react/jsx-runtime";
4
4
  //#region src/auth/pages/SSORelayPage.tsx
5
- var r = new Set(/* @__PURE__ */ "burdenoff.com,vibecontrols.com,fluidgrids.com,botlit.ai,bigconsole.com,gethealthybowl.com,headshotmarketing.com,timecampus.com,ggnomad.com,movethewheels.com,crewfoundry.com,planmagnet.com,eventfullymanaged.com,kadaikodi.com,assethandler.com,technospam.com,semanticfed.com,manufacturedops.com,theglobalfuel.com,housingvista.com,proserviceworld.com,mybodyshield.com,artistrybase.com,collabkin.com,brainyrich.com,theculturepost.com,comradecircle.com,cosmicintersection.com,govcitizenhub.com,intelwatchtower.com,ecoimpacthub.com,buildmyiq.com,fluidgrids.ai".split(",")), i = "relayChain", a = "sso_failed";
6
- function o(e) {
5
+ var r = new Set(/* @__PURE__ */ "burdenoff.com,vibecontrols.com,fluidgrids.com,botlit.ai,bigconsole.com,gethealthybowl.com,headshotmarketing.com,timecampus.com,ggnomad.com,movethewheels.com,crewfoundry.com,planmagnet.com,eventfullymanaged.com,kadaikodi.com,assethandler.com,technospam.com,semanticfed.com,manufacturedops.com,theglobalfuel.com,housingvista.com,proserviceworld.com,mybodyshield.com,artistrybase.com,collabkin.com,brainyrich.com,theculturepost.com,comradecircle.com,cosmicintersection.com,govcitizenhub.com,intelwatchtower.com,ecoimpacthub.com,buildmyiq.com,fluidgrids.ai".split(",")), i = "relayChain", a = "sso_failed", o = new Set(["localhost", "127.0.0.1"]), s = {
6
+ "bf-sso": /(?:^|;\s*)bf-sso=([^;]*)/,
7
+ "bf-sso-profile": /(?:^|;\s*)bf-sso-profile=([^;]*)/
8
+ };
9
+ function c(e) {
7
10
  if (e.hostname === "localhost" || e.hostname === "127.0.0.1" || e.hostname.endsWith(".local.burdenoff.com")) return !0;
8
11
  if (e.protocol !== "https:") return !1;
9
12
  for (let t of r) if (e.hostname === t || e.hostname === `app.${t}` || e.hostname === `alphaapp.${t}` || e.hostname === `www.${t}`) return !0;
10
13
  return !1;
11
14
  }
12
- function s() {
15
+ function l() {
13
16
  try {
14
17
  let e = window.location.hostname, t = e.endsWith(".local.burdenoff.com") ? ".local.burdenoff.com" : void 0;
15
- for (let n of ["bf-sso", "bf-sso-profile"]) document.cookie = `${n}=; path=/; max-age=0`, t && (document.cookie = `${n}=; path=/; domain=${t}; max-age=0`), e && !["localhost", "127.0.0.1"].includes(e) && (document.cookie = `${n}=; path=/; domain=${e}; max-age=0`);
18
+ for (let n of ["bf-sso", "bf-sso-profile"]) document.cookie = `${n}=; path=/; max-age=0`, t && (document.cookie = `${n}=; path=/; domain=${t}; max-age=0`), e && !o.has(e) && (document.cookie = `${n}=; path=/; domain=${e}; max-age=0`);
16
19
  } catch {}
17
20
  }
18
- function c() {
21
+ function u() {
19
22
  try {
20
23
  return (new URLSearchParams(window.location.search).get(i) || "").split("|").filter((e) => e.length > 0);
21
24
  } catch {
22
25
  return [];
23
26
  }
24
27
  }
25
- function l(e) {
28
+ function d(e) {
26
29
  try {
27
30
  let t = new URL(e, window.location.origin);
28
- return t.origin !== window.location.origin && !o(t) ? "/auth/login" : (t.searchParams.set(a, "1"), t.href);
31
+ return t.origin !== window.location.origin && !c(t) ? "/auth/login" : (t.searchParams.set(a, "1"), t.href);
29
32
  } catch {
30
33
  return "/auth/login?sso_failed=1";
31
34
  }
32
35
  }
33
- function u() {
34
- return d()?.id ?? null;
36
+ function f() {
37
+ return p()?.id ?? null;
35
38
  }
36
- function d() {
39
+ function p() {
37
40
  try {
38
41
  for (let e of ["bf-sso", "bf-sso-profile"]) {
39
- let t = document.cookie.match(RegExp(`(?:^|;\\s*)${e}=([^;]*)`));
42
+ let t = document.cookie.match(s[e]);
40
43
  if (!t) continue;
41
44
  let n = JSON.parse(decodeURIComponent(t[1]));
42
45
  if (typeof n == "string") return {
@@ -53,13 +56,13 @@ function d() {
53
56
  }
54
57
  return null;
55
58
  }
56
- function f(e) {
59
+ function m(e) {
57
60
  try {
58
- let t = d();
61
+ let t = p();
59
62
  if (!t?.origin) return !1;
60
63
  let n = new URL(t.origin);
61
- if (!o(n) || n.origin === window.location.origin) return !1;
62
- let r = c();
64
+ if (!c(n) || n.origin === window.location.origin) return !1;
65
+ let r = u();
63
66
  if (r.includes(n.origin) || r.length >= 3) return !1;
64
67
  let a = new URL("/auth/sso-relay", n.origin);
65
68
  return a.searchParams.set("returnTo", e), a.searchParams.set(i, Array.from(new Set([...r, window.location.origin])).join("|")), window.location.replace(a.href), !0;
@@ -67,19 +70,22 @@ function f(e) {
67
70
  return !1;
68
71
  }
69
72
  }
70
- function p() {
73
+ function h() {
74
+ return localStorage.getItem("bf-profiles");
75
+ }
76
+ function g() {
71
77
  try {
72
- let e = localStorage.getItem("bf-profiles");
78
+ let e = h();
73
79
  return (e ? JSON.parse(e) : []).map((e) => e.id).filter((e) => typeof e == "string" && e.length > 0);
74
80
  } catch {
75
81
  return [];
76
82
  }
77
83
  }
78
- function m() {
84
+ function _() {
79
85
  let e = [
80
- u(),
86
+ f(),
81
87
  sessionStorage.getItem("bf-active-profile"),
82
- ...p()
88
+ ...g()
83
89
  ].filter((e) => typeof e == "string" && e.length > 0);
84
90
  for (let t of Array.from(new Set(e))) {
85
91
  let e = localStorage.getItem(`bf-p-${t}-tokens`), n = localStorage.getItem(`bf-p-${t}-user`);
@@ -87,48 +93,48 @@ function m() {
87
93
  }
88
94
  return null;
89
95
  }
90
- function h() {
96
+ function v() {
91
97
  let [r] = t();
92
98
  return e(() => {
93
99
  let e = r.get("returnTo");
94
100
  if (!e) return;
95
- let t = m();
101
+ let t = _();
96
102
  if (!t) {
97
- if (f(e)) return;
98
- s(), window.location.replace(l(e));
103
+ if (m(e)) return;
104
+ l(), window.location.replace(d(e));
99
105
  return;
100
106
  }
101
- let n = localStorage.getItem(`bf-p-${t}-tokens`), i = localStorage.getItem(`bf-p-${t}-user`), a = localStorage.getItem("bf-profiles");
107
+ let n = localStorage.getItem(`bf-p-${t}-tokens`), i = localStorage.getItem(`bf-p-${t}-user`), a = h();
102
108
  if (!n || !i) {
103
- if (f(e)) return;
104
- s(), window.location.replace(l(e));
109
+ if (m(e)) return;
110
+ l(), window.location.replace(d(e));
105
111
  return;
106
112
  }
107
- let c = btoa(JSON.stringify({
113
+ let o = btoa(JSON.stringify({
108
114
  profileId: t,
109
115
  tokens: n,
110
116
  user: i,
111
117
  profiles: a
112
- })), u;
118
+ })), s;
113
119
  try {
114
120
  let t = new URL(e);
115
- if (!o(t)) {
121
+ if (!c(t)) {
116
122
  window.location.replace("/");
117
123
  return;
118
124
  }
119
125
  let n = t.pathname + t.search;
120
- u = `${t.origin}/auth/sso-callback?returnTo=${encodeURIComponent(n)}#sso=${c}`;
126
+ s = `${t.origin}/auth/sso-callback?returnTo=${encodeURIComponent(n)}#sso=${o}`;
121
127
  } catch {
122
128
  window.location.replace(e);
123
129
  return;
124
130
  }
125
- window.location.replace(u);
131
+ window.location.replace(s);
126
132
  }, [r]), /* @__PURE__ */ n("div", {
127
133
  className: "flex items-center justify-center min-h-screen bg-bg-canvas",
128
134
  children: /* @__PURE__ */ n("div", { className: "animate-spin rounded-full size-8 border-2 border-action-primary-bg border-t-transparent" })
129
135
  });
130
136
  }
131
137
  //#endregion
132
- export { h as SSORelayPage };
138
+ export { v as SSORelayPage };
133
139
 
134
140
  //# sourceMappingURL=SSORelayPage.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"SSORelayPage.js","names":[],"sources":["../../../src/auth/pages/SSORelayPage.tsx"],"sourcesContent":["/**\n * SSORelayPage — Cross-domain SSO token relay.\n *\n * This page is loaded on the ORIGIN where the user is logged in.\n * It reads tokens from localStorage and redirects to the TARGET domain's\n * /auth/sso-callback with the tokens in a URL fragment (not query param\n * for security — fragments are not sent to servers).\n *\n * Flow:\n * 1. User visits productA.com → not logged in → detects SSO cookie\n * 2. Redirect to productB.com/auth/sso-relay?returnTo=productA.com/dashboard\n * (productB is where the user IS logged in — identified by cookie)\n * 3. This page reads tokens from productB's localStorage\n * 4. Redirects to productA.com/auth/sso-callback#token=<base64-encoded-tokens>\n * 5. SSORelayCallbackPage on productA decodes and stores tokens, redirects to /dashboard\n */\n\nimport { useEffect } from \"react\";\nimport { useSearchParams } from \"react-router-dom\";\n\nconst ALLOWED_RELAY_DOMAINS = new Set([\n \"burdenoff.com\",\n \"vibecontrols.com\",\n \"fluidgrids.com\",\n \"botlit.ai\",\n \"bigconsole.com\",\n \"gethealthybowl.com\",\n \"headshotmarketing.com\",\n \"timecampus.com\",\n \"ggnomad.com\",\n \"movethewheels.com\",\n \"crewfoundry.com\",\n \"planmagnet.com\",\n \"eventfullymanaged.com\",\n \"kadaikodi.com\",\n \"assethandler.com\",\n \"technospam.com\",\n \"semanticfed.com\",\n \"manufacturedops.com\",\n \"theglobalfuel.com\",\n \"housingvista.com\",\n \"proserviceworld.com\",\n \"mybodyshield.com\",\n \"artistrybase.com\",\n \"collabkin.com\",\n \"brainyrich.com\",\n \"theculturepost.com\",\n \"comradecircle.com\",\n \"cosmicintersection.com\",\n \"govcitizenhub.com\",\n \"intelwatchtower.com\",\n \"ecoimpacthub.com\",\n \"buildmyiq.com\",\n \"fluidgrids.ai\",\n]);\n\nconst RELAY_CHAIN_PARAM = \"relayChain\";\nconst RELAY_FAILED_PARAM = \"sso_failed\";\n\nfunction isAllowedRelayTarget(url: URL): boolean {\n if (url.hostname === \"localhost\" || url.hostname === \"127.0.0.1\") {\n return true;\n }\n if (url.hostname.endsWith(\".local.burdenoff.com\")) {\n return true;\n }\n if (url.protocol !== \"https:\") {\n return false;\n }\n for (const domain of ALLOWED_RELAY_DOMAINS) {\n if (\n url.hostname === domain ||\n url.hostname === `app.${domain}` ||\n url.hostname === `alphaapp.${domain}` ||\n url.hostname === `www.${domain}`\n ) {\n return true;\n }\n }\n return false;\n}\n\nfunction clearRelayCookies(): void {\n try {\n const hostname = window.location.hostname;\n const domain = hostname.endsWith(\".local.burdenoff.com\")\n ? \".local.burdenoff.com\"\n : undefined;\n for (const cookieName of [\"bf-sso\", \"bf-sso-profile\"] as const) {\n document.cookie = `${cookieName}=; path=/; max-age=0`;\n if (domain) {\n document.cookie = `${cookieName}=; path=/; domain=${domain}; max-age=0`;\n }\n if (hostname && ![\"localhost\", \"127.0.0.1\"].includes(hostname)) {\n document.cookie = `${cookieName}=; path=/; domain=${hostname}; max-age=0`;\n }\n }\n } catch {\n /* best effort */\n }\n}\n\nfunction getRelayChain(): string[] {\n try {\n return (\n new URLSearchParams(window.location.search).get(RELAY_CHAIN_PARAM) || \"\"\n )\n .split(\"|\")\n .filter((origin) => origin.length > 0);\n } catch {\n return [];\n }\n}\n\nfunction getFailedReturnTo(returnTo: string): string {\n try {\n const targetUrl = new URL(returnTo, window.location.origin);\n if (\n targetUrl.origin !== window.location.origin &&\n !isAllowedRelayTarget(targetUrl)\n ) {\n return \"/auth/login\";\n }\n targetUrl.searchParams.set(RELAY_FAILED_PARAM, \"1\");\n return targetUrl.href;\n } catch {\n return \"/auth/login?sso_failed=1\";\n }\n}\n\nfunction readSsoCookieProfileId(): string | null {\n return readSsoCookieData()?.id ?? null;\n}\n\nfunction readSsoCookieData(): {\n id: string | null;\n origin: string | null;\n} | null {\n try {\n for (const cookieName of [\"bf-sso\", \"bf-sso-profile\"] as const) {\n const match = document.cookie.match(\n new RegExp(`(?:^|;\\\\s*)${cookieName}=([^;]*)`),\n );\n if (!match) continue;\n\n const parsed = JSON.parse(decodeURIComponent(match[1])) as\n | string\n | { id?: unknown; origin?: unknown };\n if (typeof parsed === \"string\") return { id: parsed, origin: null };\n if (typeof parsed.id === \"string\" && parsed.id.length > 0) {\n return {\n id: parsed.id,\n origin: typeof parsed.origin === \"string\" ? parsed.origin : null,\n };\n }\n }\n } catch {\n return null;\n }\n return null;\n}\n\nfunction redirectToCookieRelayOrigin(returnTo: string): boolean {\n try {\n const ssoCookie = readSsoCookieData();\n if (!ssoCookie?.origin) return false;\n\n const relayUrl = new URL(ssoCookie.origin);\n if (!isAllowedRelayTarget(relayUrl)) return false;\n if (relayUrl.origin === window.location.origin) return false;\n\n const relayChain = getRelayChain();\n if (relayChain.includes(relayUrl.origin) || relayChain.length >= 3) {\n return false;\n }\n\n const nextRelayUrl = new URL(\"/auth/sso-relay\", relayUrl.origin);\n nextRelayUrl.searchParams.set(\"returnTo\", returnTo);\n nextRelayUrl.searchParams.set(\n RELAY_CHAIN_PARAM,\n Array.from(new Set([...relayChain, window.location.origin])).join(\"|\"),\n );\n\n window.location.replace(nextRelayUrl.href);\n return true;\n } catch {\n return false;\n }\n}\n\nfunction readProfileIds(): string[] {\n try {\n const profilesRaw = localStorage.getItem(\"bf-profiles\");\n const profiles = profilesRaw\n ? (JSON.parse(profilesRaw) as Array<{ id?: unknown }>)\n : [];\n return profiles\n .map((profile) => profile.id)\n .filter((id): id is string => typeof id === \"string\" && id.length > 0);\n } catch {\n return [];\n }\n}\n\nfunction resolveRelayProfileId(): string | null {\n const candidates = [\n readSsoCookieProfileId(),\n sessionStorage.getItem(\"bf-active-profile\"),\n ...readProfileIds(),\n ].filter((id): id is string => typeof id === \"string\" && id.length > 0);\n\n for (const profileId of Array.from(new Set(candidates))) {\n const tokensRaw = localStorage.getItem(`bf-p-${profileId}-tokens`);\n const userRaw = localStorage.getItem(`bf-p-${profileId}-user`);\n if (tokensRaw && userRaw) {\n sessionStorage.setItem(\"bf-active-profile\", profileId);\n return profileId;\n }\n }\n\n return null;\n}\n\nexport function SSORelayPage() {\n const [searchParams] = useSearchParams();\n\n useEffect(() => {\n const returnTo = searchParams.get(\"returnTo\");\n if (!returnTo) {\n // No return URL — just show a blank page\n return;\n }\n\n // Read tokens from localStorage (this origin has them). Prefer the shared\n // SSO cookie profile because a relay often runs in a new tab with empty\n // sessionStorage and stale historical profiles in localStorage.\n const profileId = resolveRelayProfileId();\n if (!profileId) {\n if (redirectToCookieRelayOrigin(returnTo)) return;\n clearRelayCookies();\n window.location.replace(getFailedReturnTo(returnTo));\n return;\n }\n\n const tokensRaw = localStorage.getItem(`bf-p-${profileId}-tokens`);\n const userRaw = localStorage.getItem(`bf-p-${profileId}-user`);\n const profilesRaw = localStorage.getItem(\"bf-profiles\");\n\n if (!tokensRaw || !userRaw) {\n // No tokens — redirect back without them\n if (redirectToCookieRelayOrigin(returnTo)) return;\n clearRelayCookies();\n window.location.replace(getFailedReturnTo(returnTo));\n return;\n }\n\n // Encode the auth state as a base64 URL fragment\n const payload = {\n profileId,\n tokens: tokensRaw,\n user: userRaw,\n profiles: profilesRaw,\n };\n const encoded = btoa(JSON.stringify(payload));\n\n // Build the callback URL on the target domain\n // Parse returnTo to get the target origin\n let callbackUrl: string;\n try {\n const targetUrl = new URL(returnTo);\n if (!isAllowedRelayTarget(targetUrl)) {\n window.location.replace(\"/\");\n return;\n }\n const returnPath = targetUrl.pathname + targetUrl.search;\n callbackUrl = `${targetUrl.origin}/auth/sso-callback?returnTo=${encodeURIComponent(returnPath)}#sso=${encoded}`;\n } catch {\n // returnTo is a relative path — can't do cross-domain relay\n window.location.replace(returnTo);\n return;\n }\n\n // Redirect to the callback\n window.location.replace(callbackUrl);\n }, [searchParams]);\n\n return (\n <div className=\"flex items-center justify-center min-h-screen bg-bg-canvas\">\n <div className=\"animate-spin rounded-full size-8 border-2 border-action-primary-bg border-t-transparent\" />\n </div>\n );\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"SSORelayPage.js","names":[],"sources":["../../../src/auth/pages/SSORelayPage.tsx"],"sourcesContent":["/**\n * SSORelayPage — Cross-domain SSO token relay.\n *\n * This page is loaded on the ORIGIN where the user is logged in.\n * It reads tokens from localStorage and redirects to the TARGET domain's\n * /auth/sso-callback with the tokens in a URL fragment (not query param\n * for security — fragments are not sent to servers).\n *\n * Flow:\n * 1. User visits productA.com → not logged in → detects SSO cookie\n * 2. Redirect to productB.com/auth/sso-relay?returnTo=productA.com/dashboard\n * (productB is where the user IS logged in — identified by cookie)\n * 3. This page reads tokens from productB's localStorage\n * 4. Redirects to productA.com/auth/sso-callback#token=<base64-encoded-tokens>\n * 5. SSORelayCallbackPage on productA decodes and stores tokens, redirects to /dashboard\n */\n\nimport { useEffect } from \"react\";\nimport { useSearchParams } from \"react-router-dom\";\n\nconst ALLOWED_RELAY_DOMAINS = new Set([\n \"burdenoff.com\",\n \"vibecontrols.com\",\n \"fluidgrids.com\",\n \"botlit.ai\",\n \"bigconsole.com\",\n \"gethealthybowl.com\",\n \"headshotmarketing.com\",\n \"timecampus.com\",\n \"ggnomad.com\",\n \"movethewheels.com\",\n \"crewfoundry.com\",\n \"planmagnet.com\",\n \"eventfullymanaged.com\",\n \"kadaikodi.com\",\n \"assethandler.com\",\n \"technospam.com\",\n \"semanticfed.com\",\n \"manufacturedops.com\",\n \"theglobalfuel.com\",\n \"housingvista.com\",\n \"proserviceworld.com\",\n \"mybodyshield.com\",\n \"artistrybase.com\",\n \"collabkin.com\",\n \"brainyrich.com\",\n \"theculturepost.com\",\n \"comradecircle.com\",\n \"cosmicintersection.com\",\n \"govcitizenhub.com\",\n \"intelwatchtower.com\",\n \"ecoimpacthub.com\",\n \"buildmyiq.com\",\n \"fluidgrids.ai\",\n]);\n\nconst RELAY_CHAIN_PARAM = \"relayChain\";\nconst RELAY_FAILED_PARAM = \"sso_failed\";\nconst LOCAL_HOSTNAMES = new Set([\"localhost\", \"127.0.0.1\"]);\n\nconst SSO_COOKIE_PATTERNS = {\n \"bf-sso\": /(?:^|;\\s*)bf-sso=([^;]*)/,\n \"bf-sso-profile\": /(?:^|;\\s*)bf-sso-profile=([^;]*)/,\n} as const;\n\nfunction isAllowedRelayTarget(url: URL): boolean {\n if (url.hostname === \"localhost\" || url.hostname === \"127.0.0.1\") {\n return true;\n }\n if (url.hostname.endsWith(\".local.burdenoff.com\")) {\n return true;\n }\n if (url.protocol !== \"https:\") {\n return false;\n }\n for (const domain of ALLOWED_RELAY_DOMAINS) {\n if (\n url.hostname === domain ||\n url.hostname === `app.${domain}` ||\n url.hostname === `alphaapp.${domain}` ||\n url.hostname === `www.${domain}`\n ) {\n return true;\n }\n }\n return false;\n}\n\nfunction clearRelayCookies(): void {\n try {\n const hostname = window.location.hostname;\n const domain = hostname.endsWith(\".local.burdenoff.com\")\n ? \".local.burdenoff.com\"\n : undefined;\n for (const cookieName of [\"bf-sso\", \"bf-sso-profile\"] as const) {\n document.cookie = `${cookieName}=; path=/; max-age=0`;\n if (domain) {\n document.cookie = `${cookieName}=; path=/; domain=${domain}; max-age=0`;\n }\n if (hostname && !LOCAL_HOSTNAMES.has(hostname)) {\n document.cookie = `${cookieName}=; path=/; domain=${hostname}; max-age=0`;\n }\n }\n } catch {\n /* best effort */\n }\n}\n\nfunction getRelayChain(): string[] {\n try {\n return (\n new URLSearchParams(window.location.search).get(RELAY_CHAIN_PARAM) || \"\"\n )\n .split(\"|\")\n .filter((origin) => origin.length > 0);\n } catch {\n return [];\n }\n}\n\nfunction getFailedReturnTo(returnTo: string): string {\n try {\n const targetUrl = new URL(returnTo, window.location.origin);\n if (\n targetUrl.origin !== window.location.origin &&\n !isAllowedRelayTarget(targetUrl)\n ) {\n return \"/auth/login\";\n }\n targetUrl.searchParams.set(RELAY_FAILED_PARAM, \"1\");\n return targetUrl.href;\n } catch {\n return \"/auth/login?sso_failed=1\";\n }\n}\n\nfunction readSsoCookieProfileId(): string | null {\n return readSsoCookieData()?.id ?? null;\n}\n\nfunction readSsoCookieData(): {\n id: string | null;\n origin: string | null;\n} | null {\n try {\n for (const cookieName of [\"bf-sso\", \"bf-sso-profile\"] as const) {\n const match = document.cookie.match(SSO_COOKIE_PATTERNS[cookieName]);\n if (!match) continue;\n\n const parsed = JSON.parse(decodeURIComponent(match[1])) as\n | string\n | { id?: unknown; origin?: unknown };\n if (typeof parsed === \"string\") return { id: parsed, origin: null };\n if (typeof parsed.id === \"string\" && parsed.id.length > 0) {\n return {\n id: parsed.id,\n origin: typeof parsed.origin === \"string\" ? parsed.origin : null,\n };\n }\n }\n } catch {\n return null;\n }\n return null;\n}\n\nfunction redirectToCookieRelayOrigin(returnTo: string): boolean {\n try {\n const ssoCookie = readSsoCookieData();\n if (!ssoCookie?.origin) return false;\n\n const relayUrl = new URL(ssoCookie.origin);\n if (!isAllowedRelayTarget(relayUrl)) return false;\n if (relayUrl.origin === window.location.origin) return false;\n\n const relayChain = getRelayChain();\n if (relayChain.includes(relayUrl.origin) || relayChain.length >= 3) {\n return false;\n }\n\n const nextRelayUrl = new URL(\"/auth/sso-relay\", relayUrl.origin);\n nextRelayUrl.searchParams.set(\"returnTo\", returnTo);\n nextRelayUrl.searchParams.set(\n RELAY_CHAIN_PARAM,\n Array.from(new Set([...relayChain, window.location.origin])).join(\"|\"),\n );\n\n window.location.replace(nextRelayUrl.href);\n return true;\n } catch {\n return false;\n }\n}\n\nfunction readProfilesRaw(): string | null {\n return localStorage.getItem(\"bf-profiles\");\n}\n\nfunction readProfileIds(): string[] {\n try {\n const profilesRaw = readProfilesRaw();\n const profiles = profilesRaw\n ? (JSON.parse(profilesRaw) as Array<{ id?: unknown }>)\n : [];\n return profiles\n .map((profile) => profile.id)\n .filter((id): id is string => typeof id === \"string\" && id.length > 0);\n } catch {\n return [];\n }\n}\n\nfunction resolveRelayProfileId(): string | null {\n const candidates = [\n readSsoCookieProfileId(),\n sessionStorage.getItem(\"bf-active-profile\"),\n ...readProfileIds(),\n ].filter((id): id is string => typeof id === \"string\" && id.length > 0);\n\n for (const profileId of Array.from(new Set(candidates))) {\n const tokensRaw = localStorage.getItem(`bf-p-${profileId}-tokens`);\n const userRaw = localStorage.getItem(`bf-p-${profileId}-user`);\n if (tokensRaw && userRaw) {\n sessionStorage.setItem(\"bf-active-profile\", profileId);\n return profileId;\n }\n }\n\n return null;\n}\n\nexport function SSORelayPage() {\n const [searchParams] = useSearchParams();\n\n useEffect(() => {\n const returnTo = searchParams.get(\"returnTo\");\n if (!returnTo) {\n // No return URL — just show a blank page\n return;\n }\n\n // Read tokens from localStorage (this origin has them). Prefer the shared\n // SSO cookie profile because a relay often runs in a new tab with empty\n // sessionStorage and stale historical profiles in localStorage.\n const profileId = resolveRelayProfileId();\n if (!profileId) {\n if (redirectToCookieRelayOrigin(returnTo)) return;\n clearRelayCookies();\n window.location.replace(getFailedReturnTo(returnTo));\n return;\n }\n\n const tokensRaw = localStorage.getItem(`bf-p-${profileId}-tokens`);\n const userRaw = localStorage.getItem(`bf-p-${profileId}-user`);\n const profilesRaw = readProfilesRaw();\n\n if (!tokensRaw || !userRaw) {\n // No tokens — redirect back without them\n if (redirectToCookieRelayOrigin(returnTo)) return;\n clearRelayCookies();\n window.location.replace(getFailedReturnTo(returnTo));\n return;\n }\n\n // Encode the auth state as a base64 URL fragment\n const payload = {\n profileId,\n tokens: tokensRaw,\n user: userRaw,\n profiles: profilesRaw,\n };\n const encoded = btoa(JSON.stringify(payload));\n\n // Build the callback URL on the target domain\n // Parse returnTo to get the target origin\n let callbackUrl: string;\n try {\n const targetUrl = new URL(returnTo);\n if (!isAllowedRelayTarget(targetUrl)) {\n window.location.replace(\"/\");\n return;\n }\n const returnPath = targetUrl.pathname + targetUrl.search;\n callbackUrl = `${targetUrl.origin}/auth/sso-callback?returnTo=${encodeURIComponent(returnPath)}#sso=${encoded}`;\n } catch {\n // returnTo is a relative path — can't do cross-domain relay\n window.location.replace(returnTo);\n return;\n }\n\n // Redirect to the callback\n window.location.replace(callbackUrl);\n }, [searchParams]);\n\n return (\n <div className=\"flex items-center justify-center min-h-screen bg-bg-canvas\">\n <div className=\"animate-spin rounded-full size-8 border-2 border-action-primary-bg border-t-transparent\" />\n </div>\n );\n}\n"],"mappings":"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"}
@@ -458,9 +458,8 @@ function y() {
458
458
  className: "mb-4 p-3 rounded-lg bg-status-error-bg-subtle text-status-error-text text-sm",
459
459
  children: L
460
460
  }),
461
- z && /* @__PURE__ */ d("div", {
462
- role: "status",
463
- className: "mb-4 p-3 rounded-lg bg-status-success-bg-subtle text-status-success-text text-sm",
461
+ z && /* @__PURE__ */ d("output", {
462
+ className: "block mb-4 p-3 rounded-lg bg-status-success-bg-subtle text-status-success-text text-sm",
464
463
  children: z
465
464
  }),
466
465
  /* @__PURE__ */ f("div", {
@@ -475,6 +474,7 @@ function y() {
475
474
  value: N,
476
475
  onChange: (e) => P(e.target.value),
477
476
  "aria-required": "true",
477
+ "aria-label": b("auth.security.enterPasswordConfirm", "Enter your password to confirm"),
478
478
  "aria-describedby": L ? U : void 0,
479
479
  "aria-invalid": !!L,
480
480
  autoComplete: "current-password",
@@ -529,9 +529,8 @@ function y() {
529
529
  className: "mb-4 p-3 rounded-lg bg-status-error-bg-subtle text-status-error-text text-sm",
530
530
  children: L
531
531
  }),
532
- z && /* @__PURE__ */ d("div", {
533
- role: "status",
534
- className: "mb-4 p-3 rounded-lg bg-status-success-bg-subtle text-status-success-text text-sm",
532
+ z && /* @__PURE__ */ d("output", {
533
+ className: "block mb-4 p-3 rounded-lg bg-status-success-bg-subtle text-status-success-text text-sm",
535
534
  children: z
536
535
  }),
537
536
  /* @__PURE__ */ f("div", {
@@ -546,6 +545,7 @@ function y() {
546
545
  value: N,
547
546
  onChange: (e) => P(e.target.value),
548
547
  "aria-required": "true",
548
+ "aria-label": b("auth.security.enterPasswordDelete", "Enter your password"),
549
549
  "aria-describedby": L ? q : void 0,
550
550
  "aria-invalid": !!L,
551
551
  autoComplete: "current-password",
@@ -574,6 +574,7 @@ function y() {
574
574
  value: F,
575
575
  onChange: (e) => I(e.target.value),
576
576
  "aria-required": "true",
577
+ "aria-label": b("auth.security.deleteConfirmAriaLabel", "Type DELETE MY ACCOUNT to confirm"),
577
578
  "aria-describedby": L ? q : void 0,
578
579
  "aria-invalid": F.length > 0 && F !== v,
579
580
  autoComplete: "off",
@@ -1 +1 @@
1
- {"version":3,"file":"SecurityPage.js","names":[],"sources":["../../../src/auth/pages/SecurityPage.tsx"],"sourcesContent":["import { useId, useRef, useEffect, useState } from \"react\";\nimport { useI18n } from \"@burdenoff/fe-libs/shared/providers/shell\";\nimport { useNavigate } from \"react-router-dom\";\nimport { useAuthStore } from \"../store/authStore\";\nimport { ConfirmActionDialog } from \"../components/ConfirmActionDialog\";\nimport { useAuthOperations } from \"../hooks/useAuthOperations\";\nimport { useAccountOperations } from \"../hooks/useAccountOperations\";\nimport { formatDate } from \"../utils/formatters\";\nimport { nativeImpact, nativeNotify } from \"../../utils/nativeBridge\";\n\n// Icons\nconst ShieldIcon = ({ className }: { className?: string }) => (\n <svg\n className={className}\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={1.5}\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);\n\nconst LockIcon = ({ className }: { className?: string }) => (\n <svg\n className={className}\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={1.5}\n d=\"M12 15v2m-6 4h12a2 2 0 002-2v-6a2 2 0 00-2-2H6a2 2 0 00-2 2v6a2 2 0 002 2zm10-10V7a4 4 0 00-8 0v4h8z\"\n />\n </svg>\n);\n\n// Hidden — moved to Developer Portal\n// const KeyIcon = ({ className }: { className?: string }) => (\n// <svg className={className} fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\">\n// <path strokeLinecap=\"round\" strokeLinejoin=\"round\" strokeWidth={1.5}\n// d=\"M15 7a2 2 0 012 2m4 0a6 6 0 01-7.743 5.743L11 17H9v2H7v2H4a1 1 0 01-1-1v-2.586a1 1 0 01.293-.707l5.964-5.964A6 6 0 1121 9z\" />\n// </svg>\n// );\n\n// const DelegationIcon = ({ className }: { className?: string }) => (\n// <svg className={className} fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\">\n// <path strokeLinecap=\"round\" strokeLinejoin=\"round\" strokeWidth={1.5}\n// d=\"M17 20h5v-2a3 3 0 00-5.356-1.857M17 20H7m10 0v-2c0-.656-.126-1.283-.356-1.857M7 20H2v-2a3 3 0 015.356-1.857M7 20v-2c0-.656.126-1.283.356-1.857m0 0a5.002 5.002 0 019.288 0M15 7a3 3 0 11-6 0 3 3 0 016 0zm6 3a2 2 0 11-4 0 2 2 0 014 0zM7 10a2 2 0 11-4 0 2 2 0 014 0z\" />\n// </svg>\n// );\n\nconst UsersIcon = ({ className }: { className?: string }) => (\n <svg\n className={className}\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={1.5}\n d=\"M12 4.354a4 4 0 110 5.292M15 21H3v-1a6 6 0 0112 0v1zm0 0h6v-1a6 6 0 00-9-5.197M13 7a4 4 0 11-8 0 4 4 0 018 0z\"\n />\n </svg>\n);\n\nconst UserProfileIcon = ({ className }: { className?: string }) => (\n <svg\n className={className}\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={1.5}\n d=\"M16 7a4 4 0 11-8 0 4 4 0 018 0zM12 14a7 7 0 00-7 7h14a7 7 0 00-7-7z\"\n />\n </svg>\n);\n\nconst LinkIcon = ({ className }: { className?: string }) => (\n <svg\n className={className}\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={1.5}\n d=\"M13.828 10.172a4 4 0 00-5.656 0l-4 4a4 4 0 105.656 5.656l1.102-1.101m-.758-4.899a4 4 0 005.656 0l4-4a4 4 0 00-5.656-5.656l-1.1 1.1\"\n />\n </svg>\n);\n\nconst ChevronRightIcon = ({ className }: { className?: string }) => (\n <svg\n className={className}\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=\"M9 5l7 7-7 7\"\n />\n </svg>\n);\n\nconst CheckCircleIcon = ({ className }: { className?: string }) => (\n <svg\n className={className}\n fill=\"currentColor\"\n viewBox=\"0 0 20 20\"\n aria-hidden=\"true\"\n >\n <path\n fillRule=\"evenodd\"\n d=\"M10 18a8 8 0 100-16 8 8 0 000 16zm3.707-9.293a1 1 0 00-1.414-1.414L9 10.586 7.707 9.293a1 1 0 00-1.414 1.414l2 2a1 1 0 001.414 0l4-4z\"\n clipRule=\"evenodd\"\n />\n </svg>\n);\n\nconst ExclamationIcon = ({ className }: { className?: string }) => (\n <svg\n className={className}\n fill=\"currentColor\"\n viewBox=\"0 0 20 20\"\n aria-hidden=\"true\"\n >\n <path\n fillRule=\"evenodd\"\n d=\"M8.257 3.099c.765-1.36 2.722-1.36 3.486 0l5.58 9.92c.75 1.334-.213 2.98-1.742 2.98H4.42c-1.53 0-2.493-1.646-1.743-2.98l5.58-9.92zM11 13a1 1 0 11-2 0 1 1 0 012 0zm-1-8a1 1 0 00-1 1v3a1 1 0 002 0V6a1 1 0 00-1-1z\"\n clipRule=\"evenodd\"\n />\n </svg>\n);\n\nconst SpinnerIcon = ({ className }: { className?: string }) => (\n <svg className={className} fill=\"none\" viewBox=\"0 0 24 24\" aria-hidden=\"true\">\n <circle\n className=\"opacity-25\"\n cx=\"12\"\n cy=\"12\"\n r=\"10\"\n stroke=\"currentColor\"\n strokeWidth=\"4\"\n />\n <path\n className=\"opacity-75\"\n fill=\"currentColor\"\n d=\"M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z\"\n />\n </svg>\n);\n\ninterface NavItem {\n name: string;\n description: string;\n path: string;\n icon: React.FC<{ className?: string }>;\n color: string;\n bgColor: string;\n adminOnly?: boolean;\n}\n\nconst DELETE_ACCOUNT_CONFIRMATION = \"DELETE MY ACCOUNT\";\n\n/**\n * Security Dashboard - Main hub for all authentication features\n */\nexport function SecurityPage() {\n const { t } = useI18n();\n const tr = (key: string, fallback: string): string => {\n const translated = t(key);\n return translated === key ? fallback : translated;\n };\n\n const navigate = useNavigate();\n const user = useAuthStore((state) => state.user);\n const { signOut } = useAuthOperations({\n disableCurrentUserQuery: true,\n });\n const { deactivateAccount, deleteAccount, isDeactivating, isDeleting } =\n useAccountOperations();\n const [isLoggingOut, setIsLoggingOut] = useState(false);\n const [showLogoutDialog, setShowLogoutDialog] = useState(false);\n\n const navigationItems: NavItem[] = [\n {\n name: tr(\"auth.security.navProfile\", \"User Profile\"),\n description: tr(\n \"auth.security.navProfileDesc\",\n \"View and edit your profile information\",\n ),\n path: \"/auth/profile\",\n icon: UserProfileIcon,\n color: \"text-accent-teal\",\n bgColor: \"bg-accent-teal-subtle\",\n },\n {\n name: tr(\"auth.security.navMfa\", \"Two-Factor Authentication\"),\n description: tr(\n \"auth.security.navMfaDesc\",\n \"Secure your account with TOTP\",\n ),\n path: \"/auth/mfa\",\n icon: LockIcon,\n color: \"text-accent-purple\",\n bgColor: \"bg-accent-purple-subtle\",\n },\n // Hidden — moved to Developer Portal\n // {\n // name: tr(\"auth.security.navApiKeys\", \"API Keys\"),\n // description: tr(\"auth.security.navApiKeysDesc\", \"Manage programmatic access tokens\"),\n // path: \"/auth/api-keys\",\n // icon: KeyIcon,\n // color: \"text-status-warning-text\",\n // bgColor: \"bg-status-warning-bg-subtle\",\n // },\n // {\n // name: tr(\"auth.security.navDelegations\", \"Delegations\"),\n // description: tr(\"auth.security.navDelegationsDesc\", \"Manage apps acting on your behalf\"),\n // path: \"/auth/delegations\",\n // icon: DelegationIcon,\n // color: \"text-status-warning-text\",\n // bgColor: \"bg-status-warning-bg-subtle\",\n // },\n {\n name: tr(\"auth.security.navUsers\", \"Users\"),\n description: tr(\"auth.security.navUsersDesc\", \"Manage system users\"),\n path: \"/auth/users\",\n icon: UsersIcon,\n color: \"text-accent-indigo\",\n bgColor: \"bg-accent-indigo-subtle\",\n adminOnly: true,\n },\n ];\n\n const quickActions = [\n {\n name: tr(\"auth.security.navSso\", \"SSO Configuration\"),\n description: tr(\"auth.security.navSsoDesc\", \"Enterprise single sign-on\"),\n path: \"/auth/sso\",\n icon: LinkIcon,\n color: \"text-accent-cyan\",\n bgColor: \"bg-accent-cyan-subtle\",\n adminOnly: true,\n },\n ];\n\n // Account management modal states\n const [showDeactivateModal, setShowDeactivateModal] = useState(false);\n const [showDeleteModal, setShowDeleteModal] = useState(false);\n const [accountPassword, setAccountPassword] = useState(\"\");\n const [deleteConfirmPhrase, setDeleteConfirmPhrase] = useState(\"\");\n const [accountError, setAccountError] = useState<string | null>(null);\n const [accountSuccess, setAccountSuccess] = useState<string | null>(null);\n\n // Accessible IDs for modal labels and form fields\n const deactivateTitleId = useId();\n const deactivatePasswordId = useId();\n const deactivateErrorId = useId();\n const deleteTitleId = useId();\n const deletePasswordId = useId();\n const deleteConfirmId = useId();\n const deleteErrorId = useId();\n\n // Focus management: refs to restore focus and manage modal focus\n const deactivateTriggerRef = useRef<HTMLButtonElement>(null);\n const deleteTriggerRef = useRef<HTMLButtonElement>(null);\n const deactivateDialogRef = useRef<HTMLDivElement>(null);\n const deleteDialogRef = useRef<HTMLDivElement>(null);\n\n // Move focus into modal when it opens; restore to trigger on close\n useEffect(() => {\n if (showDeactivateModal) {\n deactivateDialogRef.current?.focus();\n } else {\n deactivateTriggerRef.current?.focus();\n }\n }, [showDeactivateModal]);\n\n useEffect(() => {\n if (showDeleteModal) {\n deleteDialogRef.current?.focus();\n } else {\n deleteTriggerRef.current?.focus();\n }\n }, [showDeleteModal]);\n\n const handleLogout = async () => {\n setIsLoggingOut(true);\n try {\n await signOut();\n navigate(\"/auth/login\");\n setShowLogoutDialog(false);\n } catch (error) {\n console.error(\"Logout failed:\", error);\n setIsLoggingOut(false);\n }\n };\n\n const handleDeactivateAccount = async () => {\n setAccountError(null);\n try {\n const result = await deactivateAccount(accountPassword);\n if (result.success) {\n // Immediately redirect to login page\n navigate(\"/auth/login\", { replace: true });\n } else {\n setAccountError(\n result.message ||\n tr(\n \"auth.security.deactivateFailed\",\n \"Failed to deactivate account\",\n ),\n );\n }\n } catch (error) {\n setAccountError(\n error instanceof Error\n ? error.message\n : tr(\n \"auth.security.deactivateFailed\",\n \"Failed to deactivate account\",\n ),\n );\n }\n };\n\n const handleDeleteAccount = async () => {\n setAccountError(null);\n if (deleteConfirmPhrase !== DELETE_ACCOUNT_CONFIRMATION) {\n setAccountError(\n tr(\n \"auth.security.deleteConfirmMismatch\",\n 'Please type \"DELETE MY ACCOUNT\" to confirm',\n ),\n );\n return;\n }\n void nativeImpact(\"medium\");\n try {\n const result = await deleteAccount(accountPassword, deleteConfirmPhrase);\n if (result.success) {\n void nativeNotify(\"success\");\n // Immediately redirect to login page\n navigate(\"/auth/login\", { replace: true });\n } else {\n void nativeNotify(\"error\");\n setAccountError(\n result.message ||\n tr(\"auth.security.deleteFailed\", \"Failed to delete account\"),\n );\n }\n } catch (error) {\n void nativeNotify(\"error\");\n setAccountError(\n error instanceof Error\n ? error.message\n : tr(\"auth.security.deleteFailed\", \"Failed to delete account\"),\n );\n }\n };\n\n const closeModals = () => {\n setShowDeactivateModal(false);\n setShowDeleteModal(false);\n setAccountPassword(\"\");\n setDeleteConfirmPhrase(\"\");\n setAccountError(null);\n setAccountSuccess(null);\n };\n\n const isAdmin =\n user?.role === \"SUPER_ADMIN\" ||\n user?.role === \"TENANT_ADMIN\" ||\n user?.role === \"ORG_ADMIN\";\n const filteredNavItems = navigationItems.filter(\n (item) => !item.adminOnly || isAdmin,\n );\n const filteredQuickActions = quickActions.filter(\n (item) => !item.adminOnly || isAdmin,\n );\n\n return (\n <div className=\"bg-bg-canvas p-6\">\n <ConfirmActionDialog\n open={showLogoutDialog}\n onOpenChange={setShowLogoutDialog}\n title={tr(\"auth.security.signOutDialogTitle\", \"Sign out now?\")}\n description={tr(\n \"auth.security.signOutDialogDescription\",\n \"You will be signed out of this device and returned to the login screen.\",\n )}\n confirmText={tr(\"auth.security.signOutDialogConfirm\", \"Sign out\")}\n variant=\"warning\"\n isPending={isLoggingOut}\n onConfirm={handleLogout}\n />\n <main className=\"max-w-7xl mx-auto space-y-8\">\n <div className=\"flex items-center gap-3\">\n <div className=\"auth-brand-badge flex size-10 items-center justify-center rounded-xl\">\n <ShieldIcon className=\"size-6 text-white\" />\n </div>\n <div>\n <h1 className=\"text-lg font-bold text-text-primary\">\n {tr(\"auth.security.title\", \"Security Center\")}\n </h1>\n <p className=\"text-xs text-text-secondary \">\n {tr(\"auth.security.subtitle\", \"Account & Authentication\")}\n </p>\n </div>\n </div>\n\n {/* Security Status Banner */}\n <div className=\"auth-hero-card rounded-2xl p-6\">\n <div className=\"flex flex-col md:flex-row md:items-center md:justify-between gap-4\">\n <div className=\"flex items-center gap-4\">\n <div className=\"size-14 rounded-2xl bg-bg-surface/20 backdrop-blur flex items-center justify-center\">\n <ShieldIcon className=\"size-8 text-white\" />\n </div>\n <div>\n <h2 className=\"text-xl font-bold\">\n {tr(\"auth.security.securityStatus\", \"Security Status\")}\n </h2>\n <p className=\"opacity-80\">\n {user?.mfaEnabled\n ? tr(\n \"auth.security.wellProtected\",\n \"Your account is well protected\",\n )\n : tr(\n \"auth.security.enableMfaSuggestion\",\n \"Enable MFA for better security\",\n )}\n </p>\n </div>\n </div>\n <div className=\"flex items-center gap-3\">\n {user?.mfaEnabled ? (\n <span className=\"inline-flex items-center gap-2 px-4 py-2 rounded-xl bg-bg-surface/20 backdrop-blur text-white font-medium\">\n <CheckCircleIcon className=\"size-5 text-status-success-text\" />\n {tr(\"auth.security.mfaEnabled\", \"MFA Enabled\")}\n </span>\n ) : (\n <button\n type=\"button\"\n onClick={() => navigate(\"/auth/mfa\")}\n className=\"inline-flex items-center gap-2 px-4 py-2 rounded-xl bg-bg-surface text-text-link font-semibold hover:bg-status-info-bg-subtle transition-colors shadow-lg\"\n >\n <ExclamationIcon className=\"size-5 text-status-warning-text\" />\n {tr(\"auth.security.enableMfaNow\", \"Enable MFA Now\")}\n </button>\n )}\n </div>\n </div>\n </div>\n\n {/* Account Information Card */}\n <div className=\"mb-8 p-6 rounded-2xl bg-bg-surface border border-border-subtle shadow-sm\">\n <h3 className=\"text-lg font-semibold text-text-primary mb-4\">\n {tr(\"auth.security.accountInfo\", \"Account Information\")}\n </h3>\n <dl className=\"grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-6\">\n <div className=\"sm:col-span-2 lg:col-span-1\">\n <dt className=\"text-sm font-medium text-text-secondary\">\n {tr(\"auth.security.email\", \"Email\")}\n </dt>\n <dd className=\"mt-1 text-text-primary\">\n <span className=\"block truncate\" title={user?.email}>\n {user?.email}\n </span>\n {user?.emailVerified && (\n <span className=\"mt-1 inline-flex items-center gap-1 px-2 py-0.5 rounded-full bg-status-success-bg-subtle text-status-success-text text-xs font-medium\">\n <CheckCircleIcon className=\"size-3\" />\n {tr(\"auth.security.verified\", \"Verified\")}\n </span>\n )}\n </dd>\n </div>\n <div>\n <dt className=\"text-sm font-medium text-text-secondary\">\n {tr(\"auth.security.username\", \"Username\")}\n </dt>\n <dd\n className=\"mt-1 text-text-primary truncate\"\n title={user?.username ?? undefined}\n >\n {user?.username || \"-\"}\n </dd>\n </div>\n <div>\n <dt className=\"text-sm font-medium text-text-secondary\">\n {tr(\"auth.security.role\", \"Role\")}\n </dt>\n <dd className=\"mt-1\">\n <span className=\"inline-flex px-2.5 py-0.5 rounded-full bg-accent-indigo-subtle text-accent-indigo text-xs font-medium\">\n {user?.role || \"USER\"}\n </span>\n </dd>\n </div>\n <div>\n <dt className=\"text-sm font-medium text-text-secondary\">\n {tr(\"auth.security.memberSince\", \"Member Since\")}\n </dt>\n <dd className=\"mt-1 text-text-primary\">\n {user?.createdAt ? formatDate(user.createdAt) : \"-\"}\n </dd>\n </div>\n </dl>\n </div>\n\n {/* Main Navigation Grid */}\n <div className=\"mb-8\">\n <h3 className=\"text-lg font-semibold text-text-primary mb-4\">\n {tr(\"auth.security.securityAuth\", \"Security & Authentication\")}\n </h3>\n <div className=\"grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-4\">\n {filteredNavItems.map((item) => (\n <button\n key={item.path}\n type=\"button\"\n onClick={() => navigate(item.path)}\n aria-label={item.name}\n className=\"group relative p-5 rounded-2xl bg-bg-surface border border-border-subtle hover:border-border-default hover:shadow-lg transition-all duration-200 text-left\"\n >\n <div className=\"flex items-start gap-4\">\n <div\n className={`size-12 rounded-xl ${item.bgColor} flex items-center justify-center flex-shrink-0 transition-transform group-hover:scale-110`}\n >\n <item.icon className={`size-6 ${item.color}`} />\n </div>\n <div className=\"flex-1 min-w-0\">\n <h4 className=\"text-base font-semibold text-text-primary group-hover:text-accent-indigo transition-colors\">\n {item.name}\n </h4>\n <p className=\"mt-1 text-sm text-text-secondary \">\n {item.description}\n </p>\n </div>\n <ChevronRightIcon className=\"size-5 text-text-tertiary group-hover:text-indigo-500 transition-colors flex-shrink-0\" />\n </div>\n </button>\n ))}\n </div>\n </div>\n\n {/* Quick Actions */}\n <div className=\"mb-8\">\n <h3 className=\"text-lg font-semibold text-text-primary mb-4\">\n {tr(\"auth.security.quickActions\", \"Quick Actions\")}\n </h3>\n <div className=\"grid grid-cols-1 sm:grid-cols-2 gap-4\">\n {filteredQuickActions.map((item) => (\n <button\n key={item.path}\n type=\"button\"\n onClick={() => navigate(item.path)}\n aria-label={item.name}\n className=\"group relative p-5 rounded-2xl bg-bg-surface border border-border-subtle hover:border-border-default hover:shadow-lg transition-all duration-200 text-left\"\n >\n <div className=\"flex items-start gap-4\">\n <div\n className={`size-12 rounded-xl ${item.bgColor} flex items-center justify-center flex-shrink-0 transition-transform group-hover:scale-110`}\n >\n <item.icon className={`size-6 ${item.color}`} />\n </div>\n <div className=\"flex-1 min-w-0\">\n <h4 className=\"text-base font-semibold text-text-primary group-hover:text-accent-indigo transition-colors\">\n {item.name}\n </h4>\n <p className=\"mt-1 text-sm text-text-secondary \">\n {item.description}\n </p>\n </div>\n <ChevronRightIcon className=\"size-5 text-text-tertiary group-hover:text-indigo-500 transition-colors flex-shrink-0\" />\n </div>\n </button>\n ))}\n </div>\n </div>\n\n {/* Password & Danger Zone */}\n <div className=\"grid grid-cols-1 lg:grid-cols-2 gap-6\">\n {/* Password Section */}\n <div className=\"p-6 rounded-2xl bg-bg-surface border border-border-subtle \">\n <div className=\"flex items-start justify-between\">\n <div>\n <h3 className=\"text-lg font-semibold text-text-primary\">\n {tr(\"auth.security.password\", \"Password\")}\n </h3>\n <p className=\"mt-1 text-sm text-text-secondary \">\n {tr(\n \"auth.security.updatePassword\",\n \"Update your password to keep your account secure\",\n )}\n </p>\n <p className=\"mt-2 text-xs text-text-tertiary \">\n {tr(\"auth.security.lastChanged\", \"Last changed: Never\")}\n </p>\n </div>\n </div>\n <button\n type=\"button\"\n onClick={() => navigate(\"/auth/reset-password\")}\n className=\"auth-primary-button mt-4 w-full px-5 py-2.5 font-semibold sm:w-auto\"\n >\n {tr(\"auth.security.changePassword\", \"Change Password\")}\n </button>\n </div>\n\n {/* Danger Zone */}\n <div className=\"p-6 rounded-2xl bg-status-error-bg-subtle border border-status-error-border\">\n <h3 className=\"text-lg font-semibold text-status-error-text\">\n {tr(\"auth.security.dangerZone\", \"Danger Zone\")}\n </h3>\n <p className=\"mt-1 text-sm text-status-error-text/80\">\n {tr(\n \"auth.security.dangerWarning\",\n \"These actions affect your account. Proceed with caution.\",\n )}\n </p>\n <div className=\"mt-4 flex flex-wrap gap-3\">\n <button\n ref={deactivateTriggerRef}\n type=\"button\"\n onClick={() => setShowDeactivateModal(true)}\n className=\"px-5 py-2.5 rounded-xl border-2 border-status-warning-border text-status-warning-text font-semibold hover:bg-status-warning-bg-subtle transition-all duration-200\"\n >\n {tr(\"auth.security.deactivateAccount\", \"Deactivate Account\")}\n </button>\n <button\n ref={deleteTriggerRef}\n type=\"button\"\n onClick={() => setShowDeleteModal(true)}\n className=\"px-5 py-2.5 rounded-xl border-2 border-status-error-border text-status-error-text font-semibold hover:bg-status-error-bg-subtle transition-all duration-200\"\n >\n {tr(\"auth.security.deleteAccount\", \"Delete Account\")}\n </button>\n </div>\n </div>\n </div>\n\n {/* Deactivate Account Modal */}\n {showDeactivateModal && (\n <div\n className=\"fixed inset-0 z-50 flex items-center justify-center bg-black/50 backdrop-blur-sm p-4\"\n role=\"presentation\"\n onClick={(e) => {\n if (e.target === e.currentTarget) closeModals();\n }}\n >\n <div\n ref={deactivateDialogRef}\n role=\"dialog\"\n aria-modal=\"true\"\n aria-labelledby={deactivateTitleId}\n tabIndex={-1}\n className=\"w-full max-w-md bg-bg-surface rounded-2xl shadow-2xl p-6 outline-none\"\n >\n <h3\n id={deactivateTitleId}\n className=\"text-xl font-bold text-text-primary mb-2\"\n >\n {tr(\"auth.security.deactivateTitle\", \"Deactivate Account\")}\n </h3>\n <p className=\"text-sm text-text-secondary mb-4\">\n {tr(\n \"auth.security.deactivateDesc\",\n \"Your account will be temporarily disabled. You can reactivate it by signing in again with your credentials.\",\n )}\n </p>\n {accountError && (\n <div\n id={deactivateErrorId}\n role=\"alert\"\n className=\"mb-4 p-3 rounded-lg bg-status-error-bg-subtle text-status-error-text text-sm\"\n >\n {accountError}\n </div>\n )}\n {accountSuccess && (\n <div\n role=\"status\"\n className=\"mb-4 p-3 rounded-lg bg-status-success-bg-subtle text-status-success-text text-sm\"\n >\n {accountSuccess}\n </div>\n )}\n <div className=\"mb-4\">\n <label\n htmlFor={deactivatePasswordId}\n className=\"block text-sm font-medium text-text-primary mb-1\"\n >\n {tr(\n \"auth.security.enterPasswordConfirm\",\n \"Enter your password to confirm\",\n )}\n </label>\n <input\n id={deactivatePasswordId}\n type=\"password\"\n value={accountPassword}\n onChange={(e) => setAccountPassword(e.target.value)}\n aria-required=\"true\"\n aria-describedby={\n accountError ? deactivateErrorId : undefined\n }\n aria-invalid={!!accountError}\n autoComplete=\"current-password\"\n className=\"w-full px-4 py-2 rounded-lg border border-border-default bg-bg-surface text-text-primary focus:ring-2 focus:ring-status-warning-bg focus:border-transparent\"\n placeholder={tr(\n \"auth.security.yourPassword\",\n \"Your password\",\n )}\n />\n </div>\n <div className=\"flex gap-3\">\n <button\n type=\"button\"\n onClick={closeModals}\n className=\"flex-1 px-4 py-2 rounded-lg border border-border-default text-text-primary font-medium hover:bg-bg-sunken transition-colors\"\n >\n {tr(\"auth.security.cancel\", \"Cancel\")}\n </button>\n <button\n type=\"button\"\n onClick={() => void handleDeactivateAccount()}\n disabled={!accountPassword || isDeactivating}\n className=\"flex-1 px-4 py-2 rounded-lg bg-status-warning-bg text-white font-medium hover:bg-status-warning-bg-hover disabled:opacity-50 disabled:cursor-not-allowed transition-colors flex items-center justify-center gap-2\"\n >\n {isDeactivating && (\n <SpinnerIcon className=\"size-4 animate-spin\" />\n )}\n {tr(\"auth.security.deactivateBtn\", \"Deactivate\")}\n </button>\n </div>\n </div>\n </div>\n )}\n\n {/* Delete Account Modal */}\n {showDeleteModal && (\n <div\n className=\"fixed inset-0 z-50 flex items-center justify-center bg-black/50 backdrop-blur-sm p-4\"\n role=\"presentation\"\n onClick={(e) => {\n if (e.target === e.currentTarget) closeModals();\n }}\n >\n <div\n ref={deleteDialogRef}\n role=\"dialog\"\n aria-modal=\"true\"\n aria-labelledby={deleteTitleId}\n tabIndex={-1}\n className=\"w-full max-w-md bg-bg-surface rounded-2xl shadow-2xl p-6 outline-none\"\n >\n <h3\n id={deleteTitleId}\n className=\"text-xl font-bold text-status-error-text mb-2\"\n >\n {tr(\"auth.security.deleteTitle\", \"Delete Account Permanently\")}\n </h3>\n <p className=\"text-sm text-text-secondary mb-4\">\n {tr(\n \"auth.security.deleteDesc\",\n \"This action is irreversible. All your data will be permanently deleted and cannot be recovered.\",\n )}\n </p>\n {accountError && (\n <div\n id={deleteErrorId}\n role=\"alert\"\n className=\"mb-4 p-3 rounded-lg bg-status-error-bg-subtle text-status-error-text text-sm\"\n >\n {accountError}\n </div>\n )}\n {accountSuccess && (\n <div\n role=\"status\"\n className=\"mb-4 p-3 rounded-lg bg-status-success-bg-subtle text-status-success-text text-sm\"\n >\n {accountSuccess}\n </div>\n )}\n <div className=\"mb-4\">\n <label\n htmlFor={deletePasswordId}\n className=\"block text-sm font-medium text-text-primary mb-1\"\n >\n {tr(\n \"auth.security.enterPasswordDelete\",\n \"Enter your password\",\n )}\n </label>\n <input\n id={deletePasswordId}\n type=\"password\"\n value={accountPassword}\n onChange={(e) => setAccountPassword(e.target.value)}\n aria-required=\"true\"\n aria-describedby={accountError ? deleteErrorId : undefined}\n aria-invalid={!!accountError}\n autoComplete=\"current-password\"\n className=\"w-full px-4 py-2 rounded-lg border border-border-default bg-bg-surface text-text-primary focus:ring-2 focus:ring-status-error-bg focus:border-transparent\"\n placeholder={tr(\n \"auth.security.yourPassword\",\n \"Your password\",\n )}\n />\n </div>\n <div className=\"mb-4\">\n <label\n htmlFor={deleteConfirmId}\n className=\"block text-sm font-medium text-text-primary mb-1\"\n >\n {tr(\"auth.security.type\", \"Type\")}{\" \"}\n <code className=\"px-1 py-0.5 rounded bg-bg-sunken text-status-error-text font-mono text-sm\">\n {DELETE_ACCOUNT_CONFIRMATION}\n </code>{\" \"}\n {tr(\"auth.security.toConfirm\", \"to confirm\")}\n </label>\n <input\n id={deleteConfirmId}\n type=\"text\"\n value={deleteConfirmPhrase}\n onChange={(e) => setDeleteConfirmPhrase(e.target.value)}\n aria-required=\"true\"\n aria-describedby={accountError ? deleteErrorId : undefined}\n aria-invalid={\n deleteConfirmPhrase.length > 0 &&\n deleteConfirmPhrase !== DELETE_ACCOUNT_CONFIRMATION\n }\n autoComplete=\"off\"\n className=\"w-full px-4 py-2 rounded-lg border border-border-default bg-bg-surface text-text-primary focus:ring-2 focus:ring-status-error-bg focus:border-transparent font-mono\"\n placeholder={tr(\n \"auth.security.deleteConfirmPlaceholder\",\n \"DELETE MY ACCOUNT\",\n )}\n />\n </div>\n <div className=\"flex gap-3\">\n <button\n type=\"button\"\n onClick={closeModals}\n className=\"flex-1 px-4 py-2 rounded-lg border border-border-default text-text-primary font-medium hover:bg-bg-sunken transition-colors\"\n >\n {tr(\"auth.security.cancel\", \"Cancel\")}\n </button>\n <button\n type=\"button\"\n onClick={() => void handleDeleteAccount()}\n disabled={\n !accountPassword ||\n deleteConfirmPhrase !== DELETE_ACCOUNT_CONFIRMATION ||\n isDeleting\n }\n className=\"flex-1 px-4 py-2 rounded-lg bg-status-error-bg text-white font-medium hover:bg-status-error-bg-hover disabled:opacity-50 disabled:cursor-not-allowed transition-colors flex items-center justify-center gap-2\"\n >\n {isDeleting && (\n <SpinnerIcon className=\"size-4 animate-spin\" />\n )}\n {tr(\"auth.security.deleteForever\", \"Delete Forever\")}\n </button>\n </div>\n </div>\n </div>\n )}\n\n {/* Footer */}\n <footer className=\"mt-12 pt-6 border-t border-border-subtle \">\n <div className=\"flex flex-col sm:flex-row sm:items-center sm:justify-between gap-4 text-sm text-text-secondary \">\n <p>\n {tr(\"auth.security.signedInAs\", \"Signed in as\")}{\" \"}\n <span className=\"font-medium text-text-primary \">\n {user?.email}\n </span>\n </p>\n <div className=\"flex items-center gap-4\">\n <button\n type=\"button\"\n onClick={() => navigate(\"/auth/login\")}\n className=\"hover:text-text-primary transition-colors\"\n >\n {tr(\"auth.security.switchAccount\", \"Switch Account\")}\n </button>\n <span className=\"text-text-muted\" aria-hidden=\"true\">\n |\n </span>\n <button\n type=\"button\"\n onClick={() => setShowLogoutDialog(true)}\n className=\"hover:text-status-error-text transition-colors\"\n >\n {tr(\"auth.security.signOut\", \"Sign Out\")}\n </button>\n </div>\n </div>\n </footer>\n </main>\n </div>\n );\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"SecurityPage.js","names":[],"sources":["../../../src/auth/pages/SecurityPage.tsx"],"sourcesContent":["import { useId, useRef, useEffect, useState } from \"react\";\nimport { useI18n } from \"@burdenoff/fe-libs/shared/providers/shell\";\nimport { useNavigate } from \"react-router-dom\";\nimport { useAuthStore } from \"../store/authStore\";\nimport { ConfirmActionDialog } from \"../components/ConfirmActionDialog\";\nimport { useAuthOperations } from \"../hooks/useAuthOperations\";\nimport { useAccountOperations } from \"../hooks/useAccountOperations\";\nimport { formatDate } from \"../utils/formatters\";\nimport { nativeImpact, nativeNotify } from \"../../utils/nativeBridge\";\n\n// Icons\nconst ShieldIcon = ({ className }: { className?: string }) => (\n <svg\n className={className}\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={1.5}\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);\n\nconst LockIcon = ({ className }: { className?: string }) => (\n <svg\n className={className}\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={1.5}\n d=\"M12 15v2m-6 4h12a2 2 0 002-2v-6a2 2 0 00-2-2H6a2 2 0 00-2 2v6a2 2 0 002 2zm10-10V7a4 4 0 00-8 0v4h8z\"\n />\n </svg>\n);\n\n// Hidden — moved to Developer Portal\n// const KeyIcon = ({ className }: { className?: string }) => (\n// <svg className={className} fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\">\n// <path strokeLinecap=\"round\" strokeLinejoin=\"round\" strokeWidth={1.5}\n// d=\"M15 7a2 2 0 012 2m4 0a6 6 0 01-7.743 5.743L11 17H9v2H7v2H4a1 1 0 01-1-1v-2.586a1 1 0 01.293-.707l5.964-5.964A6 6 0 1121 9z\" />\n// </svg>\n// );\n\n// const DelegationIcon = ({ className }: { className?: string }) => (\n// <svg className={className} fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\">\n// <path strokeLinecap=\"round\" strokeLinejoin=\"round\" strokeWidth={1.5}\n// d=\"M17 20h5v-2a3 3 0 00-5.356-1.857M17 20H7m10 0v-2c0-.656-.126-1.283-.356-1.857M7 20H2v-2a3 3 0 015.356-1.857M7 20v-2c0-.656.126-1.283.356-1.857m0 0a5.002 5.002 0 019.288 0M15 7a3 3 0 11-6 0 3 3 0 016 0zm6 3a2 2 0 11-4 0 2 2 0 014 0zM7 10a2 2 0 11-4 0 2 2 0 014 0z\" />\n// </svg>\n// );\n\nconst UsersIcon = ({ className }: { className?: string }) => (\n <svg\n className={className}\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={1.5}\n d=\"M12 4.354a4 4 0 110 5.292M15 21H3v-1a6 6 0 0112 0v1zm0 0h6v-1a6 6 0 00-9-5.197M13 7a4 4 0 11-8 0 4 4 0 018 0z\"\n />\n </svg>\n);\n\nconst UserProfileIcon = ({ className }: { className?: string }) => (\n <svg\n className={className}\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={1.5}\n d=\"M16 7a4 4 0 11-8 0 4 4 0 018 0zM12 14a7 7 0 00-7 7h14a7 7 0 00-7-7z\"\n />\n </svg>\n);\n\nconst LinkIcon = ({ className }: { className?: string }) => (\n <svg\n className={className}\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={1.5}\n d=\"M13.828 10.172a4 4 0 00-5.656 0l-4 4a4 4 0 105.656 5.656l1.102-1.101m-.758-4.899a4 4 0 005.656 0l4-4a4 4 0 00-5.656-5.656l-1.1 1.1\"\n />\n </svg>\n);\n\nconst ChevronRightIcon = ({ className }: { className?: string }) => (\n <svg\n className={className}\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=\"M9 5l7 7-7 7\"\n />\n </svg>\n);\n\nconst CheckCircleIcon = ({ className }: { className?: string }) => (\n <svg\n className={className}\n fill=\"currentColor\"\n viewBox=\"0 0 20 20\"\n aria-hidden=\"true\"\n >\n <path\n fillRule=\"evenodd\"\n d=\"M10 18a8 8 0 100-16 8 8 0 000 16zm3.707-9.293a1 1 0 00-1.414-1.414L9 10.586 7.707 9.293a1 1 0 00-1.414 1.414l2 2a1 1 0 001.414 0l4-4z\"\n clipRule=\"evenodd\"\n />\n </svg>\n);\n\nconst ExclamationIcon = ({ className }: { className?: string }) => (\n <svg\n className={className}\n fill=\"currentColor\"\n viewBox=\"0 0 20 20\"\n aria-hidden=\"true\"\n >\n <path\n fillRule=\"evenodd\"\n d=\"M8.257 3.099c.765-1.36 2.722-1.36 3.486 0l5.58 9.92c.75 1.334-.213 2.98-1.742 2.98H4.42c-1.53 0-2.493-1.646-1.743-2.98l5.58-9.92zM11 13a1 1 0 11-2 0 1 1 0 012 0zm-1-8a1 1 0 00-1 1v3a1 1 0 002 0V6a1 1 0 00-1-1z\"\n clipRule=\"evenodd\"\n />\n </svg>\n);\n\nconst SpinnerIcon = ({ className }: { className?: string }) => (\n <svg className={className} fill=\"none\" viewBox=\"0 0 24 24\" aria-hidden=\"true\">\n <circle\n className=\"opacity-25\"\n cx=\"12\"\n cy=\"12\"\n r=\"10\"\n stroke=\"currentColor\"\n strokeWidth=\"4\"\n />\n <path\n className=\"opacity-75\"\n fill=\"currentColor\"\n d=\"M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z\"\n />\n </svg>\n);\n\ninterface NavItem {\n name: string;\n description: string;\n path: string;\n icon: React.FC<{ className?: string }>;\n color: string;\n bgColor: string;\n adminOnly?: boolean;\n}\n\nconst DELETE_ACCOUNT_CONFIRMATION = \"DELETE MY ACCOUNT\";\n\n/**\n * Security Dashboard - Main hub for all authentication features\n */\nexport function SecurityPage() {\n const { t } = useI18n();\n const tr = (key: string, fallback: string): string => {\n const translated = t(key);\n return translated === key ? fallback : translated;\n };\n\n const navigate = useNavigate();\n const user = useAuthStore((state) => state.user);\n const { signOut } = useAuthOperations({\n disableCurrentUserQuery: true,\n });\n const { deactivateAccount, deleteAccount, isDeactivating, isDeleting } =\n useAccountOperations();\n const [isLoggingOut, setIsLoggingOut] = useState(false);\n const [showLogoutDialog, setShowLogoutDialog] = useState(false);\n\n const navigationItems: NavItem[] = [\n {\n name: tr(\"auth.security.navProfile\", \"User Profile\"),\n description: tr(\n \"auth.security.navProfileDesc\",\n \"View and edit your profile information\",\n ),\n path: \"/auth/profile\",\n icon: UserProfileIcon,\n color: \"text-accent-teal\",\n bgColor: \"bg-accent-teal-subtle\",\n },\n {\n name: tr(\"auth.security.navMfa\", \"Two-Factor Authentication\"),\n description: tr(\n \"auth.security.navMfaDesc\",\n \"Secure your account with TOTP\",\n ),\n path: \"/auth/mfa\",\n icon: LockIcon,\n color: \"text-accent-purple\",\n bgColor: \"bg-accent-purple-subtle\",\n },\n // Hidden — moved to Developer Portal\n // {\n // name: tr(\"auth.security.navApiKeys\", \"API Keys\"),\n // description: tr(\"auth.security.navApiKeysDesc\", \"Manage programmatic access tokens\"),\n // path: \"/auth/api-keys\",\n // icon: KeyIcon,\n // color: \"text-status-warning-text\",\n // bgColor: \"bg-status-warning-bg-subtle\",\n // },\n // {\n // name: tr(\"auth.security.navDelegations\", \"Delegations\"),\n // description: tr(\"auth.security.navDelegationsDesc\", \"Manage apps acting on your behalf\"),\n // path: \"/auth/delegations\",\n // icon: DelegationIcon,\n // color: \"text-status-warning-text\",\n // bgColor: \"bg-status-warning-bg-subtle\",\n // },\n {\n name: tr(\"auth.security.navUsers\", \"Users\"),\n description: tr(\"auth.security.navUsersDesc\", \"Manage system users\"),\n path: \"/auth/users\",\n icon: UsersIcon,\n color: \"text-accent-indigo\",\n bgColor: \"bg-accent-indigo-subtle\",\n adminOnly: true,\n },\n ];\n\n const quickActions = [\n {\n name: tr(\"auth.security.navSso\", \"SSO Configuration\"),\n description: tr(\"auth.security.navSsoDesc\", \"Enterprise single sign-on\"),\n path: \"/auth/sso\",\n icon: LinkIcon,\n color: \"text-accent-cyan\",\n bgColor: \"bg-accent-cyan-subtle\",\n adminOnly: true,\n },\n ];\n\n // Account management modal states\n const [showDeactivateModal, setShowDeactivateModal] = useState(false);\n const [showDeleteModal, setShowDeleteModal] = useState(false);\n const [accountPassword, setAccountPassword] = useState(\"\");\n const [deleteConfirmPhrase, setDeleteConfirmPhrase] = useState(\"\");\n const [accountError, setAccountError] = useState<string | null>(null);\n const [accountSuccess, setAccountSuccess] = useState<string | null>(null);\n\n // Accessible IDs for modal labels and form fields\n const deactivateTitleId = useId();\n const deactivatePasswordId = useId();\n const deactivateErrorId = useId();\n const deleteTitleId = useId();\n const deletePasswordId = useId();\n const deleteConfirmId = useId();\n const deleteErrorId = useId();\n\n // Focus management: refs to restore focus and manage modal focus\n const deactivateTriggerRef = useRef<HTMLButtonElement>(null);\n const deleteTriggerRef = useRef<HTMLButtonElement>(null);\n const deactivateDialogRef = useRef<HTMLDivElement>(null);\n const deleteDialogRef = useRef<HTMLDivElement>(null);\n\n // Move focus into modal when it opens; restore to trigger on close\n useEffect(() => {\n if (showDeactivateModal) {\n deactivateDialogRef.current?.focus();\n } else {\n deactivateTriggerRef.current?.focus();\n }\n }, [showDeactivateModal]);\n\n useEffect(() => {\n if (showDeleteModal) {\n deleteDialogRef.current?.focus();\n } else {\n deleteTriggerRef.current?.focus();\n }\n }, [showDeleteModal]);\n\n const handleLogout = async () => {\n setIsLoggingOut(true);\n try {\n await signOut();\n navigate(\"/auth/login\");\n setShowLogoutDialog(false);\n } catch (error) {\n console.error(\"Logout failed:\", error);\n setIsLoggingOut(false);\n }\n };\n\n const handleDeactivateAccount = async () => {\n setAccountError(null);\n try {\n const result = await deactivateAccount(accountPassword);\n if (result.success) {\n // Immediately redirect to login page\n navigate(\"/auth/login\", { replace: true });\n } else {\n setAccountError(\n result.message ||\n tr(\n \"auth.security.deactivateFailed\",\n \"Failed to deactivate account\",\n ),\n );\n }\n } catch (error) {\n setAccountError(\n error instanceof Error\n ? error.message\n : tr(\n \"auth.security.deactivateFailed\",\n \"Failed to deactivate account\",\n ),\n );\n }\n };\n\n const handleDeleteAccount = async () => {\n setAccountError(null);\n if (deleteConfirmPhrase !== DELETE_ACCOUNT_CONFIRMATION) {\n setAccountError(\n tr(\n \"auth.security.deleteConfirmMismatch\",\n 'Please type \"DELETE MY ACCOUNT\" to confirm',\n ),\n );\n return;\n }\n void nativeImpact(\"medium\");\n try {\n const result = await deleteAccount(accountPassword, deleteConfirmPhrase);\n if (result.success) {\n void nativeNotify(\"success\");\n // Immediately redirect to login page\n navigate(\"/auth/login\", { replace: true });\n } else {\n void nativeNotify(\"error\");\n setAccountError(\n result.message ||\n tr(\"auth.security.deleteFailed\", \"Failed to delete account\"),\n );\n }\n } catch (error) {\n void nativeNotify(\"error\");\n setAccountError(\n error instanceof Error\n ? error.message\n : tr(\"auth.security.deleteFailed\", \"Failed to delete account\"),\n );\n }\n };\n\n const closeModals = () => {\n setShowDeactivateModal(false);\n setShowDeleteModal(false);\n setAccountPassword(\"\");\n setDeleteConfirmPhrase(\"\");\n setAccountError(null);\n setAccountSuccess(null);\n };\n\n const isAdmin =\n user?.role === \"SUPER_ADMIN\" ||\n user?.role === \"TENANT_ADMIN\" ||\n user?.role === \"ORG_ADMIN\";\n const filteredNavItems = navigationItems.filter(\n (item) => !item.adminOnly || isAdmin,\n );\n const filteredQuickActions = quickActions.filter(\n (item) => !item.adminOnly || isAdmin,\n );\n\n return (\n <div className=\"bg-bg-canvas p-6\">\n <ConfirmActionDialog\n open={showLogoutDialog}\n onOpenChange={setShowLogoutDialog}\n title={tr(\"auth.security.signOutDialogTitle\", \"Sign out now?\")}\n description={tr(\n \"auth.security.signOutDialogDescription\",\n \"You will be signed out of this device and returned to the login screen.\",\n )}\n confirmText={tr(\"auth.security.signOutDialogConfirm\", \"Sign out\")}\n variant=\"warning\"\n isPending={isLoggingOut}\n onConfirm={handleLogout}\n />\n <main className=\"max-w-7xl mx-auto space-y-8\">\n <div className=\"flex items-center gap-3\">\n <div className=\"auth-brand-badge flex size-10 items-center justify-center rounded-xl\">\n <ShieldIcon className=\"size-6 text-white\" />\n </div>\n <div>\n <h1 className=\"text-lg font-bold text-text-primary\">\n {tr(\"auth.security.title\", \"Security Center\")}\n </h1>\n <p className=\"text-xs text-text-secondary \">\n {tr(\"auth.security.subtitle\", \"Account & Authentication\")}\n </p>\n </div>\n </div>\n\n {/* Security Status Banner */}\n <div className=\"auth-hero-card rounded-2xl p-6\">\n <div className=\"flex flex-col md:flex-row md:items-center md:justify-between gap-4\">\n <div className=\"flex items-center gap-4\">\n <div className=\"size-14 rounded-2xl bg-bg-surface/20 backdrop-blur flex items-center justify-center\">\n <ShieldIcon className=\"size-8 text-white\" />\n </div>\n <div>\n <h2 className=\"text-xl font-bold\">\n {tr(\"auth.security.securityStatus\", \"Security Status\")}\n </h2>\n <p className=\"opacity-80\">\n {user?.mfaEnabled\n ? tr(\n \"auth.security.wellProtected\",\n \"Your account is well protected\",\n )\n : tr(\n \"auth.security.enableMfaSuggestion\",\n \"Enable MFA for better security\",\n )}\n </p>\n </div>\n </div>\n <div className=\"flex items-center gap-3\">\n {user?.mfaEnabled ? (\n <span className=\"inline-flex items-center gap-2 px-4 py-2 rounded-xl bg-bg-surface/20 backdrop-blur text-white font-medium\">\n <CheckCircleIcon className=\"size-5 text-status-success-text\" />\n {tr(\"auth.security.mfaEnabled\", \"MFA Enabled\")}\n </span>\n ) : (\n <button\n type=\"button\"\n onClick={() => navigate(\"/auth/mfa\")}\n className=\"inline-flex items-center gap-2 px-4 py-2 rounded-xl bg-bg-surface text-text-link font-semibold hover:bg-status-info-bg-subtle transition-colors shadow-lg\"\n >\n <ExclamationIcon className=\"size-5 text-status-warning-text\" />\n {tr(\"auth.security.enableMfaNow\", \"Enable MFA Now\")}\n </button>\n )}\n </div>\n </div>\n </div>\n\n {/* Account Information Card */}\n <div className=\"mb-8 p-6 rounded-2xl bg-bg-surface border border-border-subtle shadow-sm\">\n <h3 className=\"text-lg font-semibold text-text-primary mb-4\">\n {tr(\"auth.security.accountInfo\", \"Account Information\")}\n </h3>\n <dl className=\"grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-6\">\n <div className=\"sm:col-span-2 lg:col-span-1\">\n <dt className=\"text-sm font-medium text-text-secondary\">\n {tr(\"auth.security.email\", \"Email\")}\n </dt>\n <dd className=\"mt-1 text-text-primary\">\n <span className=\"block truncate\" title={user?.email}>\n {user?.email}\n </span>\n {user?.emailVerified && (\n <span className=\"mt-1 inline-flex items-center gap-1 px-2 py-0.5 rounded-full bg-status-success-bg-subtle text-status-success-text text-xs font-medium\">\n <CheckCircleIcon className=\"size-3\" />\n {tr(\"auth.security.verified\", \"Verified\")}\n </span>\n )}\n </dd>\n </div>\n <div>\n <dt className=\"text-sm font-medium text-text-secondary\">\n {tr(\"auth.security.username\", \"Username\")}\n </dt>\n <dd\n className=\"mt-1 text-text-primary truncate\"\n title={user?.username ?? undefined}\n >\n {user?.username || \"-\"}\n </dd>\n </div>\n <div>\n <dt className=\"text-sm font-medium text-text-secondary\">\n {tr(\"auth.security.role\", \"Role\")}\n </dt>\n <dd className=\"mt-1\">\n <span className=\"inline-flex px-2.5 py-0.5 rounded-full bg-accent-indigo-subtle text-accent-indigo text-xs font-medium\">\n {user?.role || \"USER\"}\n </span>\n </dd>\n </div>\n <div>\n <dt className=\"text-sm font-medium text-text-secondary\">\n {tr(\"auth.security.memberSince\", \"Member Since\")}\n </dt>\n <dd className=\"mt-1 text-text-primary\">\n {user?.createdAt ? formatDate(user.createdAt) : \"-\"}\n </dd>\n </div>\n </dl>\n </div>\n\n {/* Main Navigation Grid */}\n <div className=\"mb-8\">\n <h3 className=\"text-lg font-semibold text-text-primary mb-4\">\n {tr(\"auth.security.securityAuth\", \"Security & Authentication\")}\n </h3>\n <div className=\"grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-4\">\n {filteredNavItems.map((item) => (\n <button\n key={item.path}\n type=\"button\"\n onClick={() => navigate(item.path)}\n aria-label={item.name}\n className=\"group relative p-5 rounded-2xl bg-bg-surface border border-border-subtle hover:border-border-default hover:shadow-lg transition-all duration-200 text-left\"\n >\n <div className=\"flex items-start gap-4\">\n <div\n className={`size-12 rounded-xl ${item.bgColor} flex items-center justify-center flex-shrink-0 transition-transform group-hover:scale-110`}\n >\n <item.icon className={`size-6 ${item.color}`} />\n </div>\n <div className=\"flex-1 min-w-0\">\n <h4 className=\"text-base font-semibold text-text-primary group-hover:text-accent-indigo transition-colors\">\n {item.name}\n </h4>\n <p className=\"mt-1 text-sm text-text-secondary \">\n {item.description}\n </p>\n </div>\n <ChevronRightIcon className=\"size-5 text-text-tertiary group-hover:text-indigo-500 transition-colors flex-shrink-0\" />\n </div>\n </button>\n ))}\n </div>\n </div>\n\n {/* Quick Actions */}\n <div className=\"mb-8\">\n <h3 className=\"text-lg font-semibold text-text-primary mb-4\">\n {tr(\"auth.security.quickActions\", \"Quick Actions\")}\n </h3>\n <div className=\"grid grid-cols-1 sm:grid-cols-2 gap-4\">\n {filteredQuickActions.map((item) => (\n <button\n key={item.path}\n type=\"button\"\n onClick={() => navigate(item.path)}\n aria-label={item.name}\n className=\"group relative p-5 rounded-2xl bg-bg-surface border border-border-subtle hover:border-border-default hover:shadow-lg transition-all duration-200 text-left\"\n >\n <div className=\"flex items-start gap-4\">\n <div\n className={`size-12 rounded-xl ${item.bgColor} flex items-center justify-center flex-shrink-0 transition-transform group-hover:scale-110`}\n >\n <item.icon className={`size-6 ${item.color}`} />\n </div>\n <div className=\"flex-1 min-w-0\">\n <h4 className=\"text-base font-semibold text-text-primary group-hover:text-accent-indigo transition-colors\">\n {item.name}\n </h4>\n <p className=\"mt-1 text-sm text-text-secondary \">\n {item.description}\n </p>\n </div>\n <ChevronRightIcon className=\"size-5 text-text-tertiary group-hover:text-indigo-500 transition-colors flex-shrink-0\" />\n </div>\n </button>\n ))}\n </div>\n </div>\n\n {/* Password & Danger Zone */}\n <div className=\"grid grid-cols-1 lg:grid-cols-2 gap-6\">\n {/* Password Section */}\n <div className=\"p-6 rounded-2xl bg-bg-surface border border-border-subtle \">\n <div className=\"flex items-start justify-between\">\n <div>\n <h3 className=\"text-lg font-semibold text-text-primary\">\n {tr(\"auth.security.password\", \"Password\")}\n </h3>\n <p className=\"mt-1 text-sm text-text-secondary \">\n {tr(\n \"auth.security.updatePassword\",\n \"Update your password to keep your account secure\",\n )}\n </p>\n <p className=\"mt-2 text-xs text-text-tertiary \">\n {tr(\"auth.security.lastChanged\", \"Last changed: Never\")}\n </p>\n </div>\n </div>\n <button\n type=\"button\"\n onClick={() => navigate(\"/auth/reset-password\")}\n className=\"auth-primary-button mt-4 w-full px-5 py-2.5 font-semibold sm:w-auto\"\n >\n {tr(\"auth.security.changePassword\", \"Change Password\")}\n </button>\n </div>\n\n {/* Danger Zone */}\n <div className=\"p-6 rounded-2xl bg-status-error-bg-subtle border border-status-error-border\">\n <h3 className=\"text-lg font-semibold text-status-error-text\">\n {tr(\"auth.security.dangerZone\", \"Danger Zone\")}\n </h3>\n <p className=\"mt-1 text-sm text-status-error-text/80\">\n {tr(\n \"auth.security.dangerWarning\",\n \"These actions affect your account. Proceed with caution.\",\n )}\n </p>\n <div className=\"mt-4 flex flex-wrap gap-3\">\n <button\n ref={deactivateTriggerRef}\n type=\"button\"\n onClick={() => setShowDeactivateModal(true)}\n className=\"px-5 py-2.5 rounded-xl border-2 border-status-warning-border text-status-warning-text font-semibold hover:bg-status-warning-bg-subtle transition-all duration-200\"\n >\n {tr(\"auth.security.deactivateAccount\", \"Deactivate Account\")}\n </button>\n <button\n ref={deleteTriggerRef}\n type=\"button\"\n onClick={() => setShowDeleteModal(true)}\n className=\"px-5 py-2.5 rounded-xl border-2 border-status-error-border text-status-error-text font-semibold hover:bg-status-error-bg-subtle transition-all duration-200\"\n >\n {tr(\"auth.security.deleteAccount\", \"Delete Account\")}\n </button>\n </div>\n </div>\n </div>\n\n {/* Deactivate Account Modal */}\n {showDeactivateModal && (\n <div\n className=\"fixed inset-0 z-50 flex items-center justify-center bg-black/50 backdrop-blur-sm p-4\"\n role=\"presentation\"\n onClick={(e) => {\n if (e.target === e.currentTarget) closeModals();\n }}\n >\n <div\n ref={deactivateDialogRef}\n role=\"dialog\"\n aria-modal=\"true\"\n aria-labelledby={deactivateTitleId}\n tabIndex={-1}\n className=\"w-full max-w-md bg-bg-surface rounded-2xl shadow-2xl p-6 outline-none\"\n >\n <h3\n id={deactivateTitleId}\n className=\"text-xl font-bold text-text-primary mb-2\"\n >\n {tr(\"auth.security.deactivateTitle\", \"Deactivate Account\")}\n </h3>\n <p className=\"text-sm text-text-secondary mb-4\">\n {tr(\n \"auth.security.deactivateDesc\",\n \"Your account will be temporarily disabled. You can reactivate it by signing in again with your credentials.\",\n )}\n </p>\n {accountError && (\n <div\n id={deactivateErrorId}\n role=\"alert\"\n className=\"mb-4 p-3 rounded-lg bg-status-error-bg-subtle text-status-error-text text-sm\"\n >\n {accountError}\n </div>\n )}\n {accountSuccess && (\n <output\n className=\"block mb-4 p-3 rounded-lg bg-status-success-bg-subtle text-status-success-text text-sm\"\n >\n {accountSuccess}\n </output>\n )}\n <div className=\"mb-4\">\n <label\n htmlFor={deactivatePasswordId}\n className=\"block text-sm font-medium text-text-primary mb-1\"\n >\n {tr(\n \"auth.security.enterPasswordConfirm\",\n \"Enter your password to confirm\",\n )}\n </label>\n <input\n id={deactivatePasswordId}\n type=\"password\"\n value={accountPassword}\n onChange={(e) => setAccountPassword(e.target.value)}\n aria-required=\"true\"\n aria-label={tr(\"auth.security.enterPasswordConfirm\", \"Enter your password to confirm\")}\n aria-describedby={\n accountError ? deactivateErrorId : undefined\n }\n aria-invalid={!!accountError}\n autoComplete=\"current-password\"\n className=\"w-full px-4 py-2 rounded-lg border border-border-default bg-bg-surface text-text-primary focus:ring-2 focus:ring-status-warning-bg focus:border-transparent\"\n placeholder={tr(\n \"auth.security.yourPassword\",\n \"Your password\",\n )}\n />\n </div>\n <div className=\"flex gap-3\">\n <button\n type=\"button\"\n onClick={closeModals}\n className=\"flex-1 px-4 py-2 rounded-lg border border-border-default text-text-primary font-medium hover:bg-bg-sunken transition-colors\"\n >\n {tr(\"auth.security.cancel\", \"Cancel\")}\n </button>\n <button\n type=\"button\"\n onClick={() => void handleDeactivateAccount()}\n disabled={!accountPassword || isDeactivating}\n className=\"flex-1 px-4 py-2 rounded-lg bg-status-warning-bg text-white font-medium hover:bg-status-warning-bg-hover disabled:opacity-50 disabled:cursor-not-allowed transition-colors flex items-center justify-center gap-2\"\n >\n {isDeactivating && (\n <SpinnerIcon className=\"size-4 animate-spin\" />\n )}\n {tr(\"auth.security.deactivateBtn\", \"Deactivate\")}\n </button>\n </div>\n </div>\n </div>\n )}\n\n {/* Delete Account Modal */}\n {showDeleteModal && (\n <div\n className=\"fixed inset-0 z-50 flex items-center justify-center bg-black/50 backdrop-blur-sm p-4\"\n role=\"presentation\"\n onClick={(e) => {\n if (e.target === e.currentTarget) closeModals();\n }}\n >\n <div\n ref={deleteDialogRef}\n role=\"dialog\"\n aria-modal=\"true\"\n aria-labelledby={deleteTitleId}\n tabIndex={-1}\n className=\"w-full max-w-md bg-bg-surface rounded-2xl shadow-2xl p-6 outline-none\"\n >\n <h3\n id={deleteTitleId}\n className=\"text-xl font-bold text-status-error-text mb-2\"\n >\n {tr(\"auth.security.deleteTitle\", \"Delete Account Permanently\")}\n </h3>\n <p className=\"text-sm text-text-secondary mb-4\">\n {tr(\n \"auth.security.deleteDesc\",\n \"This action is irreversible. All your data will be permanently deleted and cannot be recovered.\",\n )}\n </p>\n {accountError && (\n <div\n id={deleteErrorId}\n role=\"alert\"\n className=\"mb-4 p-3 rounded-lg bg-status-error-bg-subtle text-status-error-text text-sm\"\n >\n {accountError}\n </div>\n )}\n {accountSuccess && (\n <output\n className=\"block mb-4 p-3 rounded-lg bg-status-success-bg-subtle text-status-success-text text-sm\"\n >\n {accountSuccess}\n </output>\n )}\n <div className=\"mb-4\">\n <label\n htmlFor={deletePasswordId}\n className=\"block text-sm font-medium text-text-primary mb-1\"\n >\n {tr(\n \"auth.security.enterPasswordDelete\",\n \"Enter your password\",\n )}\n </label>\n <input\n id={deletePasswordId}\n type=\"password\"\n value={accountPassword}\n onChange={(e) => setAccountPassword(e.target.value)}\n aria-required=\"true\"\n aria-label={tr(\"auth.security.enterPasswordDelete\", \"Enter your password\")}\n aria-describedby={accountError ? deleteErrorId : undefined}\n aria-invalid={!!accountError}\n autoComplete=\"current-password\"\n className=\"w-full px-4 py-2 rounded-lg border border-border-default bg-bg-surface text-text-primary focus:ring-2 focus:ring-status-error-bg focus:border-transparent\"\n placeholder={tr(\n \"auth.security.yourPassword\",\n \"Your password\",\n )}\n />\n </div>\n <div className=\"mb-4\">\n <label\n htmlFor={deleteConfirmId}\n className=\"block text-sm font-medium text-text-primary mb-1\"\n >\n {tr(\"auth.security.type\", \"Type\")}{\" \"}\n <code className=\"px-1 py-0.5 rounded bg-bg-sunken text-status-error-text font-mono text-sm\">\n {DELETE_ACCOUNT_CONFIRMATION}\n </code>{\" \"}\n {tr(\"auth.security.toConfirm\", \"to confirm\")}\n </label>\n <input\n id={deleteConfirmId}\n type=\"text\"\n value={deleteConfirmPhrase}\n onChange={(e) => setDeleteConfirmPhrase(e.target.value)}\n aria-required=\"true\"\n aria-label={tr(\"auth.security.deleteConfirmAriaLabel\", \"Type DELETE MY ACCOUNT to confirm\")}\n aria-describedby={accountError ? deleteErrorId : undefined}\n aria-invalid={\n deleteConfirmPhrase.length > 0 &&\n deleteConfirmPhrase !== DELETE_ACCOUNT_CONFIRMATION\n }\n autoComplete=\"off\"\n className=\"w-full px-4 py-2 rounded-lg border border-border-default bg-bg-surface text-text-primary focus:ring-2 focus:ring-status-error-bg focus:border-transparent font-mono\"\n placeholder={tr(\n \"auth.security.deleteConfirmPlaceholder\",\n \"DELETE MY ACCOUNT\",\n )}\n />\n </div>\n <div className=\"flex gap-3\">\n <button\n type=\"button\"\n onClick={closeModals}\n className=\"flex-1 px-4 py-2 rounded-lg border border-border-default text-text-primary font-medium hover:bg-bg-sunken transition-colors\"\n >\n {tr(\"auth.security.cancel\", \"Cancel\")}\n </button>\n <button\n type=\"button\"\n onClick={() => void handleDeleteAccount()}\n disabled={\n !accountPassword ||\n deleteConfirmPhrase !== DELETE_ACCOUNT_CONFIRMATION ||\n isDeleting\n }\n className=\"flex-1 px-4 py-2 rounded-lg bg-status-error-bg text-white font-medium hover:bg-status-error-bg-hover disabled:opacity-50 disabled:cursor-not-allowed transition-colors flex items-center justify-center gap-2\"\n >\n {isDeleting && (\n <SpinnerIcon className=\"size-4 animate-spin\" />\n )}\n {tr(\"auth.security.deleteForever\", \"Delete Forever\")}\n </button>\n </div>\n </div>\n </div>\n )}\n\n {/* Footer */}\n <footer className=\"mt-12 pt-6 border-t border-border-subtle \">\n <div className=\"flex flex-col sm:flex-row sm:items-center sm:justify-between gap-4 text-sm text-text-secondary \">\n <p>\n {tr(\"auth.security.signedInAs\", \"Signed in as\")}{\" \"}\n <span className=\"font-medium text-text-primary \">\n {user?.email}\n </span>\n </p>\n <div className=\"flex items-center gap-4\">\n <button\n type=\"button\"\n onClick={() => navigate(\"/auth/login\")}\n className=\"hover:text-text-primary transition-colors\"\n >\n {tr(\"auth.security.switchAccount\", \"Switch Account\")}\n </button>\n <span className=\"text-text-muted\" aria-hidden=\"true\">\n |\n </span>\n <button\n type=\"button\"\n onClick={() => setShowLogoutDialog(true)}\n className=\"hover:text-status-error-text transition-colors\"\n >\n {tr(\"auth.security.signOut\", \"Sign Out\")}\n </button>\n </div>\n </div>\n </footer>\n </main>\n </div>\n );\n}\n"],"mappings":";;;;;;;;;;;AAWA,IAAM,KAAc,EAAE,mBACpB,kBAAC,OAAD;CACa;CACX,MAAK;CACL,SAAQ;CACR,QAAO;CACP,eAAY;WAEZ,kBAAC,QAAD;EACE,eAAc;EACd,gBAAe;EACf,aAAa;EACb,GAAE;EACF,CAAA;CACE,CAAA,EAGF,MAAY,EAAE,mBAClB,kBAAC,OAAD;CACa;CACX,MAAK;CACL,SAAQ;CACR,QAAO;CACP,eAAY;WAEZ,kBAAC,QAAD;EACE,eAAc;EACd,gBAAe;EACf,aAAa;EACb,GAAE;EACF,CAAA;CACE,CAAA,EAkBF,MAAa,EAAE,mBACnB,kBAAC,OAAD;CACa;CACX,MAAK;CACL,SAAQ;CACR,QAAO;CACP,eAAY;WAEZ,kBAAC,QAAD;EACE,eAAc;EACd,gBAAe;EACf,aAAa;EACb,GAAE;EACF,CAAA;CACE,CAAA,EAGF,MAAmB,EAAE,mBACzB,kBAAC,OAAD;CACa;CACX,MAAK;CACL,SAAQ;CACR,QAAO;CACP,eAAY;WAEZ,kBAAC,QAAD;EACE,eAAc;EACd,gBAAe;EACf,aAAa;EACb,GAAE;EACF,CAAA;CACE,CAAA,EAGF,MAAY,EAAE,mBAClB,kBAAC,OAAD;CACa;CACX,MAAK;CACL,SAAQ;CACR,QAAO;CACP,eAAY;WAEZ,kBAAC,QAAD;EACE,eAAc;EACd,gBAAe;EACf,aAAa;EACb,GAAE;EACF,CAAA;CACE,CAAA,EAGF,KAAoB,EAAE,mBAC1B,kBAAC,OAAD;CACa;CACX,MAAK;CACL,SAAQ;CACR,QAAO;CACP,eAAY;WAEZ,kBAAC,QAAD;EACE,eAAc;EACd,gBAAe;EACf,aAAa;EACb,GAAE;EACF,CAAA;CACE,CAAA,EAGF,KAAmB,EAAE,mBACzB,kBAAC,OAAD;CACa;CACX,MAAK;CACL,SAAQ;CACR,eAAY;WAEZ,kBAAC,QAAD;EACE,UAAS;EACT,GAAE;EACF,UAAS;EACT,CAAA;CACE,CAAA,EAGF,KAAmB,EAAE,mBACzB,kBAAC,OAAD;CACa;CACX,MAAK;CACL,SAAQ;CACR,eAAY;WAEZ,kBAAC,QAAD;EACE,UAAS;EACT,GAAE;EACF,UAAS;EACT,CAAA;CACE,CAAA,EAGF,KAAe,EAAE,mBACrB,kBAAC,OAAD;CAAgB;CAAW,MAAK;CAAO,SAAQ;CAAY,eAAY;WAAvE,CACE,kBAAC,UAAD;EACE,WAAU;EACV,IAAG;EACH,IAAG;EACH,GAAE;EACF,QAAO;EACP,aAAY;EACZ,CAAA,EACF,kBAAC,QAAD;EACE,WAAU;EACV,MAAK;EACL,GAAE;EACF,CAAA,CACE;IAaF,IAA8B;AAKpC,SAAgB,IAAe;CAC7B,IAAM,EAAE,SAAM,GAAS,EACjB,KAAM,GAAa,MAA6B;EACpD,IAAM,IAAa,EAAE,EAAI;AACzB,SAAO,MAAe,IAAM,IAAW;IAGnC,IAAW,GAAa,EACxB,IAAO,GAAc,MAAU,EAAM,KAAK,EAC1C,EAAE,gBAAY,EAAkB,EACpC,yBAAyB,IAC1B,CAAC,EACI,EAAE,uBAAmB,mBAAe,mBAAgB,kBACxD,GAAsB,EAClB,CAAC,GAAc,KAAmB,EAAS,GAAM,EACjD,CAAC,GAAkB,KAAuB,EAAS,GAAM,EAEzD,KAA6B;EACjC;GACE,MAAM,EAAG,4BAA4B,eAAe;GACpD,aAAa,EACX,gCACA,yCACD;GACD,MAAM;GACN,MAAM;GACN,OAAO;GACP,SAAS;GACV;EACD;GACE,MAAM,EAAG,wBAAwB,4BAA4B;GAC7D,aAAa,EACX,4BACA,gCACD;GACD,MAAM;GACN,MAAM;GACN,OAAO;GACP,SAAS;GACV;EAkBD;GACE,MAAM,EAAG,0BAA0B,QAAQ;GAC3C,aAAa,EAAG,8BAA8B,sBAAsB;GACpE,MAAM;GACN,MAAM;GACN,OAAO;GACP,SAAS;GACT,WAAW;GACZ;EACF,EAEK,KAAe,CACnB;EACE,MAAM,EAAG,wBAAwB,oBAAoB;EACrD,aAAa,EAAG,4BAA4B,4BAA4B;EACxE,MAAM;EACN,MAAM;EACN,OAAO;EACP,SAAS;EACT,WAAW;EACZ,CACF,EAGK,CAAC,GAAqB,KAA0B,EAAS,GAAM,EAC/D,CAAC,GAAiB,KAAsB,EAAS,GAAM,EACvD,CAAC,GAAiB,KAAsB,EAAS,GAAG,EACpD,CAAC,GAAqB,KAA0B,EAAS,GAAG,EAC5D,CAAC,GAAc,KAAmB,EAAwB,KAAK,EAC/D,CAAC,GAAgB,KAAqB,EAAwB,KAAK,EAGnE,IAAoB,GAAO,EAC3B,IAAuB,GAAO,EAC9B,IAAoB,GAAO,EAC3B,IAAgB,GAAO,EACvB,IAAmB,GAAO,EAC1B,IAAkB,GAAO,EACzB,IAAgB,GAAO,EAGvB,IAAuB,EAA0B,KAAK,EACtD,IAAmB,EAA0B,KAAK,EAClD,IAAsB,EAAuB,KAAK,EAClD,IAAkB,EAAuB,KAAK;AAWpD,CARA,QAAgB;AACd,EAAI,IACF,EAAoB,SAAS,OAAO,GAEpC,EAAqB,SAAS,OAAO;IAEtC,CAAC,EAAoB,CAAC,EAEzB,QAAgB;AACd,EAAI,IACF,EAAgB,SAAS,OAAO,GAEhC,EAAiB,SAAS,OAAO;IAElC,CAAC,EAAgB,CAAC;CAErB,IAAM,KAAe,YAAY;AAC/B,IAAgB,GAAK;AACrB,MAAI;AAGF,GAFA,MAAM,IAAS,EACf,EAAS,cAAc,EACvB,EAAoB,GAAM;WACnB,GAAO;AAEd,GADA,QAAQ,MAAM,kBAAkB,EAAM,EACtC,EAAgB,GAAM;;IAIpB,KAA0B,YAAY;AAC1C,IAAgB,KAAK;AACrB,MAAI;GACF,IAAM,IAAS,MAAM,GAAkB,EAAgB;AACvD,GAAI,EAAO,UAET,EAAS,eAAe,EAAE,SAAS,IAAM,CAAC,GAE1C,EACE,EAAO,WACL,EACE,kCACA,+BACD,CACJ;WAEI,GAAO;AACd,KACE,aAAiB,QACb,EAAM,UACN,EACE,kCACA,+BACD,CACN;;IAIC,KAAsB,YAAY;AAEtC,MADA,EAAgB,KAAK,EACjB,MAAwB,GAA6B;AACvD,KACE,EACE,uCACA,+CACD,CACF;AACD;;AAEG,IAAa,SAAS;AAC3B,MAAI;GACF,IAAM,IAAS,MAAM,GAAc,GAAiB,EAAoB;AACxE,GAAI,EAAO,WACJ,EAAa,UAAU,EAE5B,EAAS,eAAe,EAAE,SAAS,IAAM,CAAC,KAErC,EAAa,QAAQ,EAC1B,EACE,EAAO,WACL,EAAG,8BAA8B,2BAA2B,CAC/D;WAEI,GAAO;AAEd,GADK,EAAa,QAAQ,EAC1B,EACE,aAAiB,QACb,EAAM,UACN,EAAG,8BAA8B,2BAA2B,CACjE;;IAIC,UAAoB;AAMxB,EALA,EAAuB,GAAM,EAC7B,EAAmB,GAAM,EACzB,EAAmB,GAAG,EACtB,EAAuB,GAAG,EAC1B,EAAgB,KAAK,EACrB,EAAkB,KAAK;IAGnB,IACJ,GAAM,SAAS,iBACf,GAAM,SAAS,kBACf,GAAM,SAAS,aACX,KAAmB,GAAgB,QACtC,MAAS,CAAC,EAAK,aAAa,EAC9B,EACK,KAAuB,GAAa,QACvC,MAAS,CAAC,EAAK,aAAa,EAC9B;AAED,QACE,kBAAC,OAAD;EAAK,WAAU;YAAf,CACE,kBAAC,IAAD;GACE,MAAM;GACN,cAAc;GACd,OAAO,EAAG,oCAAoC,gBAAgB;GAC9D,aAAa,EACX,0CACA,0EACD;GACD,aAAa,EAAG,sCAAsC,WAAW;GACjE,SAAQ;GACR,WAAW;GACX,WAAW;GACX,CAAA,EACF,kBAAC,QAAD;GAAM,WAAU;aAAhB;IACE,kBAAC,OAAD;KAAK,WAAU;eAAf,CACE,kBAAC,OAAD;MAAK,WAAU;gBACb,kBAAC,GAAD,EAAY,WAAU,qBAAsB,CAAA;MACxC,CAAA,EACN,kBAAC,OAAD,EAAA,UAAA,CACE,kBAAC,MAAD;MAAI,WAAU;gBACX,EAAG,uBAAuB,kBAAkB;MAC1C,CAAA,EACL,kBAAC,KAAD;MAAG,WAAU;gBACV,EAAG,0BAA0B,2BAA2B;MACvD,CAAA,CACA,EAAA,CAAA,CACF;;IAGN,kBAAC,OAAD;KAAK,WAAU;eACb,kBAAC,OAAD;MAAK,WAAU;gBAAf,CACE,kBAAC,OAAD;OAAK,WAAU;iBAAf,CACE,kBAAC,OAAD;QAAK,WAAU;kBACb,kBAAC,GAAD,EAAY,WAAU,qBAAsB,CAAA;QACxC,CAAA,EACN,kBAAC,OAAD,EAAA,UAAA,CACE,kBAAC,MAAD;QAAI,WAAU;kBACX,EAAG,gCAAgC,kBAAkB;QACnD,CAAA,EACL,kBAAC,KAAD;QAAG,WAAU;kBACV,GAAM,aACH,EACE,+BACA,iCACD,GACD,EACE,qCACA,iCACD;QACH,CAAA,CACA,EAAA,CAAA,CACF;UACN,kBAAC,OAAD;OAAK,WAAU;iBACZ,GAAM,aACL,kBAAC,QAAD;QAAM,WAAU;kBAAhB,CACE,kBAAC,GAAD,EAAiB,WAAU,mCAAoC,CAAA,EAC9D,EAAG,4BAA4B,cAAc,CACzC;YAEP,kBAAC,UAAD;QACE,MAAK;QACL,eAAe,EAAS,YAAY;QACpC,WAAU;kBAHZ,CAKE,kBAAC,GAAD,EAAiB,WAAU,mCAAoC,CAAA,EAC9D,EAAG,8BAA8B,iBAAiB,CAC5C;;OAEP,CAAA,CACF;;KACF,CAAA;IAGN,kBAAC,OAAD;KAAK,WAAU;eAAf,CACE,kBAAC,MAAD;MAAI,WAAU;gBACX,EAAG,6BAA6B,sBAAsB;MACpD,CAAA,EACL,kBAAC,MAAD;MAAI,WAAU;gBAAd;OACE,kBAAC,OAAD;QAAK,WAAU;kBAAf,CACE,kBAAC,MAAD;SAAI,WAAU;mBACX,EAAG,uBAAuB,QAAQ;SAChC,CAAA,EACL,kBAAC,MAAD;SAAI,WAAU;mBAAd,CACE,kBAAC,QAAD;UAAM,WAAU;UAAiB,OAAO,GAAM;oBAC3C,GAAM;UACF,CAAA,EACN,GAAM,iBACL,kBAAC,QAAD;UAAM,WAAU;oBAAhB,CACE,kBAAC,GAAD,EAAiB,WAAU,UAAW,CAAA,EACrC,EAAG,0BAA0B,WAAW,CACpC;YAEN;WACD;;OACN,kBAAC,OAAD,EAAA,UAAA,CACE,kBAAC,MAAD;QAAI,WAAU;kBACX,EAAG,0BAA0B,WAAW;QACtC,CAAA,EACL,kBAAC,MAAD;QACE,WAAU;QACV,OAAO,GAAM,YAAY,KAAA;kBAExB,GAAM,YAAY;QAChB,CAAA,CACD,EAAA,CAAA;OACN,kBAAC,OAAD,EAAA,UAAA,CACE,kBAAC,MAAD;QAAI,WAAU;kBACX,EAAG,sBAAsB,OAAO;QAC9B,CAAA,EACL,kBAAC,MAAD;QAAI,WAAU;kBACZ,kBAAC,QAAD;SAAM,WAAU;mBACb,GAAM,QAAQ;SACV,CAAA;QACJ,CAAA,CACD,EAAA,CAAA;OACN,kBAAC,OAAD,EAAA,UAAA,CACE,kBAAC,MAAD;QAAI,WAAU;kBACX,EAAG,6BAA6B,eAAe;QAC7C,CAAA,EACL,kBAAC,MAAD;QAAI,WAAU;kBACX,GAAM,YAAY,GAAW,EAAK,UAAU,GAAG;QAC7C,CAAA,CACD,EAAA,CAAA;OACH;QACD;;IAGN,kBAAC,OAAD;KAAK,WAAU;eAAf,CACE,kBAAC,MAAD;MAAI,WAAU;gBACX,EAAG,8BAA8B,4BAA4B;MAC3D,CAAA,EACL,kBAAC,OAAD;MAAK,WAAU;gBACZ,GAAiB,KAAK,MACrB,kBAAC,UAAD;OAEE,MAAK;OACL,eAAe,EAAS,EAAK,KAAK;OAClC,cAAY,EAAK;OACjB,WAAU;iBAEV,kBAAC,OAAD;QAAK,WAAU;kBAAf;SACE,kBAAC,OAAD;UACE,WAAW,sBAAsB,EAAK,QAAQ;oBAE9C,kBAAC,EAAK,MAAN,EAAW,WAAW,UAAU,EAAK,SAAW,CAAA;UAC5C,CAAA;SACN,kBAAC,OAAD;UAAK,WAAU;oBAAf,CACE,kBAAC,MAAD;WAAI,WAAU;qBACX,EAAK;WACH,CAAA,EACL,kBAAC,KAAD;WAAG,WAAU;qBACV,EAAK;WACJ,CAAA,CACA;;SACN,kBAAC,GAAD,EAAkB,WAAU,yFAA0F,CAAA;SAClH;;OACC,EAtBF,EAAK,KAsBH,CACT;MACE,CAAA,CACF;;IAGN,kBAAC,OAAD;KAAK,WAAU;eAAf,CACE,kBAAC,MAAD;MAAI,WAAU;gBACX,EAAG,8BAA8B,gBAAgB;MAC/C,CAAA,EACL,kBAAC,OAAD;MAAK,WAAU;gBACZ,GAAqB,KAAK,MACzB,kBAAC,UAAD;OAEE,MAAK;OACL,eAAe,EAAS,EAAK,KAAK;OAClC,cAAY,EAAK;OACjB,WAAU;iBAEV,kBAAC,OAAD;QAAK,WAAU;kBAAf;SACE,kBAAC,OAAD;UACE,WAAW,sBAAsB,EAAK,QAAQ;oBAE9C,kBAAC,EAAK,MAAN,EAAW,WAAW,UAAU,EAAK,SAAW,CAAA;UAC5C,CAAA;SACN,kBAAC,OAAD;UAAK,WAAU;oBAAf,CACE,kBAAC,MAAD;WAAI,WAAU;qBACX,EAAK;WACH,CAAA,EACL,kBAAC,KAAD;WAAG,WAAU;qBACV,EAAK;WACJ,CAAA,CACA;;SACN,kBAAC,GAAD,EAAkB,WAAU,yFAA0F,CAAA;SAClH;;OACC,EAtBF,EAAK,KAsBH,CACT;MACE,CAAA,CACF;;IAGN,kBAAC,OAAD;KAAK,WAAU;eAAf,CAEE,kBAAC,OAAD;MAAK,WAAU;gBAAf,CACE,kBAAC,OAAD;OAAK,WAAU;iBACb,kBAAC,OAAD,EAAA,UAAA;QACE,kBAAC,MAAD;SAAI,WAAU;mBACX,EAAG,0BAA0B,WAAW;SACtC,CAAA;QACL,kBAAC,KAAD;SAAG,WAAU;mBACV,EACC,gCACA,mDACD;SACC,CAAA;QACJ,kBAAC,KAAD;SAAG,WAAU;mBACV,EAAG,6BAA6B,sBAAsB;SACrD,CAAA;QACA,EAAA,CAAA;OACF,CAAA,EACN,kBAAC,UAAD;OACE,MAAK;OACL,eAAe,EAAS,uBAAuB;OAC/C,WAAU;iBAET,EAAG,gCAAgC,kBAAkB;OAC/C,CAAA,CACL;SAGN,kBAAC,OAAD;MAAK,WAAU;gBAAf;OACE,kBAAC,MAAD;QAAI,WAAU;kBACX,EAAG,4BAA4B,cAAc;QAC3C,CAAA;OACL,kBAAC,KAAD;QAAG,WAAU;kBACV,EACC,+BACA,2DACD;QACC,CAAA;OACJ,kBAAC,OAAD;QAAK,WAAU;kBAAf,CACE,kBAAC,UAAD;SACE,KAAK;SACL,MAAK;SACL,eAAe,EAAuB,GAAK;SAC3C,WAAU;mBAET,EAAG,mCAAmC,qBAAqB;SACrD,CAAA,EACT,kBAAC,UAAD;SACE,KAAK;SACL,MAAK;SACL,eAAe,EAAmB,GAAK;SACvC,WAAU;mBAET,EAAG,+BAA+B,iBAAiB;SAC7C,CAAA,CACL;;OACF;QACF;;IAGL,KACC,kBAAC,OAAD;KACE,WAAU;KACV,MAAK;KACL,UAAU,MAAM;AACd,MAAI,EAAE,WAAW,EAAE,iBAAe,GAAa;;eAGjD,kBAAC,OAAD;MACE,KAAK;MACL,MAAK;MACL,cAAW;MACX,mBAAiB;MACjB,UAAU;MACV,WAAU;gBANZ;OAQE,kBAAC,MAAD;QACE,IAAI;QACJ,WAAU;kBAET,EAAG,iCAAiC,qBAAqB;QACvD,CAAA;OACL,kBAAC,KAAD;QAAG,WAAU;kBACV,EACC,gCACA,8GACD;QACC,CAAA;OACH,KACC,kBAAC,OAAD;QACE,IAAI;QACJ,MAAK;QACL,WAAU;kBAET;QACG,CAAA;OAEP,KACC,kBAAC,UAAD;QACE,WAAU;kBAET;QACM,CAAA;OAEX,kBAAC,OAAD;QAAK,WAAU;kBAAf,CACE,kBAAC,SAAD;SACE,SAAS;SACT,WAAU;mBAET,EACC,sCACA,iCACD;SACK,CAAA,EACR,kBAAC,SAAD;SACE,IAAI;SACJ,MAAK;SACL,OAAO;SACP,WAAW,MAAM,EAAmB,EAAE,OAAO,MAAM;SACnD,iBAAc;SACd,cAAY,EAAG,sCAAsC,iCAAiC;SACtF,oBACE,IAAe,IAAoB,KAAA;SAErC,gBAAc,CAAC,CAAC;SAChB,cAAa;SACb,WAAU;SACV,aAAa,EACX,8BACA,gBACD;SACD,CAAA,CACE;;OACN,kBAAC,OAAD;QAAK,WAAU;kBAAf,CACE,kBAAC,UAAD;SACE,MAAK;SACL,SAAS;SACT,WAAU;mBAET,EAAG,wBAAwB,SAAS;SAC9B,CAAA,EACT,kBAAC,UAAD;SACE,MAAK;SACL,eAAe,KAAK,IAAyB;SAC7C,UAAU,CAAC,KAAmB;SAC9B,WAAU;mBAJZ,CAMG,KACC,kBAAC,GAAD,EAAa,WAAU,uBAAwB,CAAA,EAEhD,EAAG,+BAA+B,aAAa,CACzC;WACL;;OACF;;KACF,CAAA;IAIP,KACC,kBAAC,OAAD;KACE,WAAU;KACV,MAAK;KACL,UAAU,MAAM;AACd,MAAI,EAAE,WAAW,EAAE,iBAAe,GAAa;;eAGjD,kBAAC,OAAD;MACE,KAAK;MACL,MAAK;MACL,cAAW;MACX,mBAAiB;MACjB,UAAU;MACV,WAAU;gBANZ;OAQE,kBAAC,MAAD;QACE,IAAI;QACJ,WAAU;kBAET,EAAG,6BAA6B,6BAA6B;QAC3D,CAAA;OACL,kBAAC,KAAD;QAAG,WAAU;kBACV,EACC,4BACA,kGACD;QACC,CAAA;OACH,KACC,kBAAC,OAAD;QACE,IAAI;QACJ,MAAK;QACL,WAAU;kBAET;QACG,CAAA;OAEP,KACC,kBAAC,UAAD;QACE,WAAU;kBAET;QACM,CAAA;OAEX,kBAAC,OAAD;QAAK,WAAU;kBAAf,CACE,kBAAC,SAAD;SACE,SAAS;SACT,WAAU;mBAET,EACC,qCACA,sBACD;SACK,CAAA,EACR,kBAAC,SAAD;SACE,IAAI;SACJ,MAAK;SACL,OAAO;SACP,WAAW,MAAM,EAAmB,EAAE,OAAO,MAAM;SACnD,iBAAc;SACd,cAAY,EAAG,qCAAqC,sBAAsB;SAC1E,oBAAkB,IAAe,IAAgB,KAAA;SACjD,gBAAc,CAAC,CAAC;SAChB,cAAa;SACb,WAAU;SACV,aAAa,EACX,8BACA,gBACD;SACD,CAAA,CACE;;OACN,kBAAC,OAAD;QAAK,WAAU;kBAAf,CACE,kBAAC,SAAD;SACE,SAAS;SACT,WAAU;mBAFZ;UAIG,EAAG,sBAAsB,OAAO;UAAE;UACnC,kBAAC,QAAD;WAAM,WAAU;qBACb;WACI,CAAA;UAAC;UACP,EAAG,2BAA2B,aAAa;UACtC;YACR,kBAAC,SAAD;SACE,IAAI;SACJ,MAAK;SACL,OAAO;SACP,WAAW,MAAM,EAAuB,EAAE,OAAO,MAAM;SACvD,iBAAc;SACd,cAAY,EAAG,wCAAwC,oCAAoC;SAC3F,oBAAkB,IAAe,IAAgB,KAAA;SACjD,gBACE,EAAoB,SAAS,KAC7B,MAAwB;SAE1B,cAAa;SACb,WAAU;SACV,aAAa,EACX,0CACA,oBACD;SACD,CAAA,CACE;;OACN,kBAAC,OAAD;QAAK,WAAU;kBAAf,CACE,kBAAC,UAAD;SACE,MAAK;SACL,SAAS;SACT,WAAU;mBAET,EAAG,wBAAwB,SAAS;SAC9B,CAAA,EACT,kBAAC,UAAD;SACE,MAAK;SACL,eAAe,KAAK,IAAqB;SACzC,UACE,CAAC,KACD,MAAwB,KACxB;SAEF,WAAU;mBARZ,CAUG,KACC,kBAAC,GAAD,EAAa,WAAU,uBAAwB,CAAA,EAEhD,EAAG,+BAA+B,iBAAiB,CAC7C;WACL;;OACF;;KACF,CAAA;IAIR,kBAAC,UAAD;KAAQ,WAAU;eAChB,kBAAC,OAAD;MAAK,WAAU;gBAAf,CACE,kBAAC,KAAD,EAAA,UAAA;OACG,EAAG,4BAA4B,eAAe;OAAE;OACjD,kBAAC,QAAD;QAAM,WAAU;kBACb,GAAM;QACF,CAAA;OACL,EAAA,CAAA,EACJ,kBAAC,OAAD;OAAK,WAAU;iBAAf;QACE,kBAAC,UAAD;SACE,MAAK;SACL,eAAe,EAAS,cAAc;SACtC,WAAU;mBAET,EAAG,+BAA+B,iBAAiB;SAC7C,CAAA;QACT,kBAAC,QAAD;SAAM,WAAU;SAAkB,eAAY;mBAAO;SAE9C,CAAA;QACP,kBAAC,UAAD;SACE,MAAK;SACL,eAAe,EAAoB,GAAK;SACxC,WAAU;mBAET,EAAG,yBAAyB,WAAW;SACjC,CAAA;QACL;SACF;;KACC,CAAA;IACJ;KACH"}
@@ -98,9 +98,8 @@ function p() {
98
98
  })
99
99
  })]
100
100
  }),
101
- k && /* @__PURE__ */ f("div", {
102
- role: "status",
103
- className: "mb-6 p-4 rounded-xl bg-status-success-bg-subtle border border-status-success-border",
101
+ k && /* @__PURE__ */ f("output", {
102
+ className: "block mb-6 p-4 rounded-xl bg-status-success-bg-subtle border border-status-success-border",
104
103
  children: [/* @__PURE__ */ d("p", {
105
104
  className: "text-status-success-text",
106
105
  children: k
@@ -141,9 +140,8 @@ function p() {
141
140
  className: "ml-3 text-text-secondary",
142
141
  children: m("auth.sessions.loading", "Loading sessions...")
143
142
  })]
144
- }) : E.length === 0 ? /* @__PURE__ */ f("div", {
145
- className: "text-center py-16 border-2 border-dashed border-border-subtle rounded-xl",
146
- role: "status",
143
+ }) : E.length === 0 ? /* @__PURE__ */ f("output", {
144
+ className: "block text-center py-16 border-2 border-dashed border-border-subtle rounded-xl",
147
145
  children: [/* @__PURE__ */ d("div", {
148
146
  className: "size-16 mx-auto mb-4 rounded-full bg-bg-muted flex items-center justify-center",
149
147
  children: /* @__PURE__ */ d("svg", {
@@ -196,8 +194,7 @@ function p() {
196
194
  children: [/* @__PURE__ */ d("h3", {
197
195
  className: "text-lg font-semibold text-text-primary",
198
196
  children: e.isCurrent && o(e.userAgent) === "Unknown Device" ? m("auth.sessions.thisDevice", "This Device") : o(e.userAgent)
199
- }), e.isCurrent && /* @__PURE__ */ d("span", {
200
- role: "status",
197
+ }), e.isCurrent && /* @__PURE__ */ d("output", {
201
198
  className: "px-2.5 py-1 rounded-full bg-status-success-bg-subtle text-status-success-text text-xs font-medium",
202
199
  children: m("auth.sessions.currentSession", "Current Session")
203
200
  })]