@abstraxn/signer-react 3.3.9 → 4.0.0

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 (114) hide show
  1. package/CHANGELOG.md +44 -0
  2. package/dist/src/ConnectButton.css.d.ts +2 -0
  3. package/dist/src/ConnectButton.css.js +1 -0
  4. package/dist/src/ConnectButton.d.ts +0 -1
  5. package/dist/src/ConnectButton.js +7 -6
  6. package/dist/src/ExternalWalletButtons.css.d.ts +2 -0
  7. package/dist/src/ExternalWalletButtons.css.js +1 -0
  8. package/dist/src/ExternalWalletButtons.d.ts +4 -1
  9. package/dist/src/ExternalWalletButtons.js +6 -1
  10. package/dist/src/WalletModal.css +2 -0
  11. package/dist/src/WalletModal.css.d.ts +2 -0
  12. package/dist/src/WalletModal.css.js +1 -0
  13. package/dist/src/WalletModal.d.ts +2 -2
  14. package/dist/src/WalletModal.js +113 -59
  15. package/dist/src/components/AbstraxnLogo.d.ts +17 -0
  16. package/dist/src/components/AbstraxnLogo.js +29 -0
  17. package/dist/src/components/AbstraxnProvider/AbstraxnProviderInner.js +406 -338
  18. package/dist/src/components/AbstraxnProvider/useAbstraxnProviderBase.d.ts +7 -0
  19. package/dist/src/components/AbstraxnProvider/useAbstraxnProviderBase.js +9 -0
  20. package/dist/src/components/AbstraxnProvider/useWalletInitialization.js +41 -6
  21. package/dist/src/components/OnboardingUI/OnboardingUI.css +99 -4
  22. package/dist/src/components/OnboardingUI/OnboardingUI.css.d.ts +2 -0
  23. package/dist/src/components/OnboardingUI/OnboardingUI.css.js +1 -0
  24. package/dist/src/components/OnboardingUI/OnboardingUIReact.d.ts +0 -1
  25. package/dist/src/components/OnboardingUI/OnboardingUIReact.js +46 -19
  26. package/dist/src/components/OnboardingUI/OnboardingUIWeb.d.ts +24 -1
  27. package/dist/src/components/OnboardingUI/OnboardingUIWeb.js +348 -160
  28. package/dist/src/components/OnboardingUI/components/Divider.d.ts +7 -0
  29. package/dist/src/components/OnboardingUI/components/Divider.js +9 -0
  30. package/dist/src/components/OnboardingUI/components/EmailForm.d.ts +0 -1
  31. package/dist/src/components/OnboardingUI/components/EmailForm.js +1 -2
  32. package/dist/src/components/OnboardingUI/components/MfaForm.d.ts +0 -1
  33. package/dist/src/components/OnboardingUI/components/MfaForm.js +2 -3
  34. package/dist/src/components/OnboardingUI/components/Modal.d.ts +0 -1
  35. package/dist/src/components/OnboardingUI/components/Modal.js +12 -4
  36. package/dist/src/components/OnboardingUI/components/OtpForm.d.ts +0 -1
  37. package/dist/src/components/OnboardingUI/components/OtpForm.js +2 -3
  38. package/dist/src/components/OnboardingUI/components/PasskeyButton.d.ts +0 -1
  39. package/dist/src/components/OnboardingUI/components/PasskeyButton.js +2 -2
  40. package/dist/src/components/OnboardingUI/components/SocialButtons.d.ts +0 -1
  41. package/dist/src/components/OnboardingUI/components/SocialButtons.js +3 -3
  42. package/dist/src/components/OnboardingUI/onboardingShadowContainer.d.ts +9 -0
  43. package/dist/src/components/OnboardingUI/onboardingShadowContainer.js +36 -0
  44. package/dist/src/components/ShadowHost/ShadowHost.d.ts +18 -0
  45. package/dist/src/components/ShadowHost/ShadowHost.js +123 -0
  46. package/dist/src/components/ShadowHost/ShadowHostContext.d.ts +10 -0
  47. package/dist/src/components/ShadowHost/ShadowHostContext.js +14 -0
  48. package/dist/src/components/ShadowHost/index.d.ts +2 -0
  49. package/dist/src/components/ShadowHost/index.js +3 -0
  50. package/dist/src/components/WalletModal/components/ChainSelector.css +9 -0
  51. package/dist/src/components/WalletModal/components/ChainSelector.css.d.ts +2 -0
  52. package/dist/src/components/WalletModal/components/ChainSelector.css.js +1 -0
  53. package/dist/src/components/WalletModal/components/ChainSelector.d.ts +0 -1
  54. package/dist/src/components/WalletModal/components/ChainSelector.js +78 -23
  55. package/dist/src/components/WalletModal/components/CodeInput.d.ts +12 -0
  56. package/dist/src/components/WalletModal/components/CodeInput.js +39 -0
  57. package/dist/src/components/WalletModal/components/ExportKeyModal.css.d.ts +2 -0
  58. package/dist/src/components/WalletModal/components/ExportKeyModal.css.js +1 -0
  59. package/dist/src/components/WalletModal/components/ExportKeyModal.d.ts +0 -2
  60. package/dist/src/components/WalletModal/components/ExportKeyModal.js +2 -4
  61. package/dist/src/components/WalletModal/components/ExportWarningModal.css.d.ts +2 -0
  62. package/dist/src/components/WalletModal/components/ExportWarningModal.css.js +1 -0
  63. package/dist/src/components/WalletModal/components/ExportWarningModal.d.ts +0 -2
  64. package/dist/src/components/WalletModal/components/ExportWarningModal.js +2 -4
  65. package/dist/src/components/WalletModal/components/ManageWalletModal.css +27 -1
  66. package/dist/src/components/WalletModal/components/ManageWalletModal.css.d.ts +2 -0
  67. package/dist/src/components/WalletModal/components/ManageWalletModal.css.js +1 -0
  68. package/dist/src/components/WalletModal/components/ManageWalletModal.d.ts +0 -1
  69. package/dist/src/components/WalletModal/components/ManageWalletModal.js +66 -148
  70. package/dist/src/components/WalletModal/components/MfaVerifyModal.d.ts +15 -0
  71. package/dist/src/components/WalletModal/components/MfaVerifyModal.js +98 -0
  72. package/dist/src/components/WalletModal/components/PreviewTransactionModal.css +2 -12
  73. package/dist/src/components/WalletModal/components/PreviewTransactionModal.css.d.ts +2 -0
  74. package/dist/src/components/WalletModal/components/PreviewTransactionModal.css.js +1 -0
  75. package/dist/src/components/WalletModal/components/PreviewTransactionModal.d.ts +0 -1
  76. package/dist/src/components/WalletModal/components/PreviewTransactionModal.js +0 -1
  77. package/dist/src/components/WalletModal/components/ReceiveModal.css.d.ts +2 -0
  78. package/dist/src/components/WalletModal/components/ReceiveModal.css.js +1 -0
  79. package/dist/src/components/WalletModal/components/ReceiveModal.d.ts +0 -1
  80. package/dist/src/components/WalletModal/components/ReceiveModal.js +2 -2
  81. package/dist/src/components/WalletModal/components/SendModal.css.d.ts +2 -0
  82. package/dist/src/components/WalletModal/components/SendModal.css.js +1 -0
  83. package/dist/src/components/WalletModal/components/SendModal.d.ts +5 -2
  84. package/dist/src/components/WalletModal/components/SendModal.js +25 -82
  85. package/dist/src/components/WalletModal/components/SignMfaModalHost.d.ts +1 -0
  86. package/dist/src/components/WalletModal/components/SignMfaModalHost.js +50 -0
  87. package/dist/src/components/WalletModal/components/SuccessModal.css.d.ts +2 -0
  88. package/dist/src/components/WalletModal/components/SuccessModal.css.js +1 -0
  89. package/dist/src/components/WalletModal/components/SuccessModal.d.ts +0 -1
  90. package/dist/src/components/WalletModal/components/SuccessModal.js +0 -1
  91. package/dist/src/components/WalletModal/components/TokenSelectorModal.css.d.ts +2 -0
  92. package/dist/src/components/WalletModal/components/TokenSelectorModal.css.js +1 -0
  93. package/dist/src/components/WalletModal/components/TokenSelectorModal.d.ts +0 -1
  94. package/dist/src/components/WalletModal/components/TokenSelectorModal.js +0 -1
  95. package/dist/src/components/WalletModal/components/UserAvatar.js +2 -1
  96. package/dist/src/components/WalletModal/components/index.d.ts +3 -0
  97. package/dist/src/components/WalletModal/components/index.js +2 -0
  98. package/dist/src/components/WalletModal/hooks/useSendTransaction.js +18 -6
  99. package/dist/src/components/icons.d.ts +2 -0
  100. package/dist/src/components/icons.js +4 -0
  101. package/dist/src/hooks.d.ts +81 -20
  102. package/dist/src/hooks.js +194 -36
  103. package/dist/src/index.d.ts +2 -2
  104. package/dist/src/index.js +2 -2
  105. package/dist/src/signMfaBridge.d.ts +7 -0
  106. package/dist/src/signMfaBridge.js +20 -0
  107. package/dist/src/types.d.ts +4 -0
  108. package/dist/src/utils/shadowFocus.d.ts +8 -0
  109. package/dist/src/utils/shadowFocus.js +15 -0
  110. package/dist/src/utils/shadowRegistry.d.ts +23 -0
  111. package/dist/src/utils/shadowRegistry.js +36 -0
  112. package/dist/src/walletConnectMobile.d.ts +9 -5
  113. package/dist/src/walletConnectMobile.js +152 -51
  114. package/package.json +9 -4
@@ -1,5 +1,6 @@
1
1
  import type { User, WhoamiResponse } from "@abstraxn/signer-core";
2
2
  import type { AbstraxnProviderConfig } from "../../types";
3
+ import type { TokenData } from "../WalletModal/components/TokenSelectorModal";
3
4
  import { OnboardingUIWeb } from "../OnboardingUI";
4
5
  import type { AbstraxnWallet } from "@abstraxn/signer-core";
5
6
  export declare function useAbstraxnProviderBase(_config: AbstraxnProviderConfig): {
@@ -23,6 +24,12 @@ export declare function useAbstraxnProviderBase(_config: AbstraxnProviderConfig)
23
24
  setResending: import("react").Dispatch<import("react").SetStateAction<boolean>>;
24
25
  walletBalance: bigint | null;
25
26
  setWalletBalance: import("react").Dispatch<import("react").SetStateAction<bigint | null>>;
27
+ tokenBalances: TokenData[];
28
+ setTokenBalances: import("react").Dispatch<import("react").SetStateAction<TokenData[]>>;
29
+ tokenBalancesLoading: boolean;
30
+ setTokenBalancesLoading: import("react").Dispatch<import("react").SetStateAction<boolean>>;
31
+ tokenBalancesError: Error | null;
32
+ setTokenBalancesError: import("react").Dispatch<import("react").SetStateAction<Error | null>>;
26
33
  onboardingRef: import("react").RefObject<OnboardingUIWeb | null>;
27
34
  otpIdRef: import("react").RefObject<string | null>;
28
35
  walletRef: import("react").RefObject<AbstraxnWallet | null>;
@@ -14,6 +14,9 @@ export function useAbstraxnProviderBase(_config) {
14
14
  const [loading, setLoading] = useState(false);
15
15
  const [resending, setResending] = useState(false);
16
16
  const [walletBalance, setWalletBalance] = useState(null);
17
+ const [tokenBalances, setTokenBalances] = useState([]);
18
+ const [tokenBalancesLoading, setTokenBalancesLoading] = useState(false);
19
+ const [tokenBalancesError, setTokenBalancesError] = useState(null);
17
20
  const onboardingRef = useRef(null);
18
21
  const otpIdRef = useRef(null);
19
22
  const walletRef = useRef(null);
@@ -41,6 +44,12 @@ export function useAbstraxnProviderBase(_config) {
41
44
  setResending,
42
45
  walletBalance,
43
46
  setWalletBalance,
47
+ tokenBalances,
48
+ setTokenBalances,
49
+ tokenBalancesLoading,
50
+ setTokenBalancesLoading,
51
+ tokenBalancesError,
52
+ setTokenBalancesError,
44
53
  onboardingRef,
45
54
  otpIdRef,
46
55
  walletRef,
@@ -9,9 +9,29 @@ import { EVM_CHAINS, toCoreChain } from "../../chains";
9
9
  import { hasAuthParams, isLinkAuthCallback } from "./utils";
10
10
  export function useWalletInitialization({ config, walletRef, onboardingRef, otpIdRef, externalWalletsEnabled, setIsConnected, setAddress, setUser, setWhoami, setChainId, setError, setConnectionType, init, }) {
11
11
  useEffect(() => {
12
- // If wallet already exists (from previous mount), reuse it to prevent flicker
12
+ // If wallet already exists (from previous mount), reuse it to prevent flicker.
13
+ // StrictMode still destroys OnboardingUIWeb in cleanup — rebuild its shadow
14
+ // tree here so the OAuth success loader can paint again.
13
15
  if (walletRef.current) {
14
- return;
16
+ const onboarding = onboardingRef.current;
17
+ if (onboarding && !onboarding.hasLiveShadow()) {
18
+ onboarding.init();
19
+ if (typeof window !== "undefined") {
20
+ const urlParams = new URLSearchParams(window.location.search);
21
+ const hasSuccess = urlParams.get("success") === "true";
22
+ const mfaRequired = urlParams.get("mfaRequired") === "true";
23
+ if (hasSuccess &&
24
+ !mfaRequired &&
25
+ !isLinkAuthCallback(urlParams)) {
26
+ onboarding.showLoadingModal();
27
+ }
28
+ }
29
+ }
30
+ return () => {
31
+ if (onboardingRef.current) {
32
+ onboardingRef.current.destroy();
33
+ }
34
+ };
15
35
  }
16
36
  // Compute supported chains from chain config (outside useMemo since we're in useEffect)
17
37
  // This should include ALL chains that might be shown in the UI (availableChains)
@@ -176,10 +196,21 @@ export function useWalletInitialization({ config, walletRef, onboardingRef, otpI
176
196
  walletInstance.on("chainChanged", (newChainId) => {
177
197
  setChainId(newChainId);
178
198
  });
179
- // Initialize OnboardingUI only if not already created (prevents flicker on config change)
180
- if (onboardingRef.current) {
199
+ // Initialize OnboardingUI only if not already created (prevents flicker on config change).
200
+ // A destroyed StrictMode instance leaves a non-null ref with no live shadow — treat that
201
+ // as "not created" so we rebuild instead of skipping OAuth loader setup.
202
+ if (onboardingRef.current?.hasLiveShadow()) {
181
203
  return;
182
204
  }
205
+ if (onboardingRef.current) {
206
+ try {
207
+ onboardingRef.current.destroy();
208
+ }
209
+ catch {
210
+ // Ignore — instance may already be partially torn down.
211
+ }
212
+ onboardingRef.current = null;
213
+ }
183
214
  const uiConfig = config.ui || {};
184
215
  const onboarding = new OnboardingUIWeb({
185
216
  logo: uiConfig.logo,
@@ -484,6 +515,7 @@ export function useWalletInitialization({ config, walletRef, onboardingRef, otpI
484
515
  // Hide immediately - use synchronous approach to prevent flicker
485
516
  // Only hide if NOT handling a callback
486
517
  const onboardingAny = onboarding;
518
+ let oauthLoaderTimeout = null;
487
519
  if (!shouldKeepOpen && onboardingAny.modalOverlay) {
488
520
  // Hide immediately without delay to prevent flicker
489
521
  onboardingAny.modalOverlay.classList.remove("onboarding-modal-open");
@@ -495,9 +527,9 @@ export function useWalletInitialization({ config, walletRef, onboardingRef, otpI
495
527
  // Skip when mfaRequired=true so MFA verification screen can show instead.
496
528
  const mfaRequired = urlParams.get("mfaRequired") === "true";
497
529
  if (!mfaRequired) {
498
- setTimeout(() => {
530
+ oauthLoaderTimeout = setTimeout(() => {
499
531
  const onboardingInstance = onboardingRef.current;
500
- if (onboardingInstance && onboardingInstance.showLoadingModal) {
532
+ if (onboardingInstance) {
501
533
  onboardingInstance.showLoadingModal();
502
534
  }
503
535
  }, 150);
@@ -547,6 +579,9 @@ export function useWalletInitialization({ config, walletRef, onboardingRef, otpI
547
579
  });
548
580
  }
549
581
  return () => {
582
+ if (oauthLoaderTimeout !== null) {
583
+ clearTimeout(oauthLoaderTimeout);
584
+ }
550
585
  if (onboardingRef.current) {
551
586
  onboardingRef.current.destroy();
552
587
  }
@@ -18,9 +18,17 @@
18
18
  .onboarding-container.onboarding-inline {
19
19
  min-height: auto;
20
20
  padding: 0;
21
+ justify-content: flex-start;
21
22
  /* width: 100%; */
22
23
  }
23
24
 
25
+ /* Let the host page scroll the full card (wallet buttons, etc.) instead of
26
+ nesting a second scrollbar inside a short embed. */
27
+ .onboarding-container.onboarding-inline .onboarding-card {
28
+ max-height: none;
29
+ overflow-y: visible;
30
+ }
31
+
24
32
  /* Modal Styles */
25
33
  .onboarding-modal-overlay {
26
34
  position: fixed;
@@ -545,6 +553,20 @@
545
553
  cursor: not-allowed;
546
554
  }
547
555
 
556
+ .onboarding-button-loading {
557
+ display: inline-flex;
558
+ align-items: center;
559
+ justify-content: center;
560
+ gap: 8px;
561
+ }
562
+
563
+ .onboarding-button-spinner {
564
+ flex-shrink: 0;
565
+ width: 16px;
566
+ height: 16px;
567
+ animation: onboarding-spin 1s linear infinite;
568
+ }
569
+
548
570
  .onboarding-button-primary {
549
571
  font-weight: 600;
550
572
  box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05);
@@ -628,6 +650,7 @@
628
650
  .onboarding-social-grid {
629
651
  display: grid;
630
652
  grid-template-columns: repeat(auto-fit, minmax(48px, 1fr));
653
+ justify-items: center;
631
654
  gap: 12px;
632
655
  width: 100%;
633
656
  }
@@ -636,12 +659,13 @@
636
659
  display: flex;
637
660
  align-items: center;
638
661
  justify-content: center;
639
- width: 48px;
662
+ width: 100%;
640
663
  height: 48px;
641
664
  padding: 0;
642
665
  border-radius: 12px;
643
666
  border: 1.5px solid #e5e7eb;
644
667
  background-color: #ffffff;
668
+ color: #111827;
645
669
  cursor: pointer;
646
670
  transition: all 0.2s ease;
647
671
  }
@@ -649,6 +673,7 @@
649
673
  .onboarding-theme-dark .onboarding-button-social-icon {
650
674
  background-color: #374151;
651
675
  border-color: #4b5563;
676
+ color: #ffffff;
652
677
  }
653
678
 
654
679
  .onboarding-button-social-icon:hover:not(:disabled) {
@@ -671,6 +696,60 @@
671
696
  .onboarding-social-icon {
672
697
  width: 20px;
673
698
  height: 20px;
699
+ color: inherit;
700
+ fill: currentColor;
701
+ }
702
+
703
+ /* Passkey Button Styles */
704
+ .onboarding-button-passkey {
705
+ background-color: #374151;
706
+ color: #ffffff;
707
+ border: 1.5px solid #4b5563;
708
+ font-weight: 500;
709
+ box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05);
710
+ font-size: 14px;
711
+ }
712
+
713
+ .onboarding-theme-dark .onboarding-button-passkey {
714
+ background-color: #4b5563;
715
+ color: #ffffff;
716
+ border-color: #6b7280;
717
+ }
718
+
719
+ .onboarding-button-passkey:hover:not(:disabled) {
720
+ background-color: #4b5563;
721
+ border-color: #6b7280;
722
+ box-shadow: 0 2px 4px rgba(0, 0, 0, 0.08);
723
+ transform: translateY(-1px);
724
+ }
725
+
726
+ .onboarding-theme-dark .onboarding-button-passkey:hover:not(:disabled) {
727
+ background-color: #6b7280;
728
+ border-color: #9ca3af;
729
+ }
730
+
731
+ .onboarding-passkey-icon {
732
+ width: 20px;
733
+ height: 20px;
734
+ }
735
+
736
+ .onboarding-passkey-signup-link {
737
+ text-decoration: underline;
738
+ cursor: pointer;
739
+ font-size: 14px;
740
+ font-weight: 500;
741
+ margin-top: 12px;
742
+ display: block;
743
+ text-align: center;
744
+ transition: color 0.15s ease;
745
+ }
746
+
747
+ .onboarding-theme-light .onboarding-passkey-signup-link {
748
+ color: #2170f5;
749
+ }
750
+
751
+ .onboarding-theme-dark .onboarding-passkey-signup-link {
752
+ color: #2170f5;
674
753
  }
675
754
 
676
755
  .onboarding-divider {
@@ -978,6 +1057,9 @@
978
1057
  }
979
1058
 
980
1059
  .onboarding-otp-verification .onboarding-button {
1060
+ /* Match OTP inputs width: 6 × 44px + 5 × 10px gap = 314px */
1061
+ width: 314px;
1062
+ max-width: 100%;
981
1063
  margin-top: 0;
982
1064
  margin-bottom: 0;
983
1065
  margin-left: auto;
@@ -992,6 +1074,7 @@
992
1074
  font-size: 14px;
993
1075
  margin: -6px 0 16px;
994
1076
  color: #6b7280;
1077
+ text-align: center;
995
1078
  }
996
1079
 
997
1080
  .onboarding-theme-dark .onboarding-mfa-trouble-text {
@@ -999,13 +1082,20 @@
999
1082
  }
1000
1083
 
1001
1084
  .onboarding-mfa-backup-link {
1002
- border: none;
1003
- background: transparent;
1004
- padding: 0;
1085
+ border: none !important;
1086
+ background: transparent !important;
1087
+ padding: 0 !important;
1088
+ margin: 0;
1005
1089
  text-decoration: underline;
1006
1090
  cursor: pointer;
1007
1091
  font-weight: 600;
1008
1092
  font-size: 14px;
1093
+ font-family: inherit;
1094
+ line-height: inherit;
1095
+ box-shadow: none !important;
1096
+ outline: none;
1097
+ appearance: none;
1098
+ -webkit-appearance: none;
1009
1099
  }
1010
1100
 
1011
1101
  .onboarding-theme-light .onboarding-mfa-backup-link {
@@ -1242,6 +1332,11 @@
1242
1332
  gap: 8px;
1243
1333
  }
1244
1334
 
1335
+ .onboarding-otp-verification .onboarding-button {
1336
+ /* 6 × 44px + 5 × 8px gap = 304px */
1337
+ width: 304px;
1338
+ }
1339
+
1245
1340
  .onboarding-otp-input {
1246
1341
  width: 44px;
1247
1342
  min-width: 44px;
@@ -0,0 +1,2 @@
1
+ declare const cssText: string;
2
+ export default cssText;
@@ -0,0 +1 @@
1
+ export default "/**\n * OnboardingUI Component Styles\n */\n\n.onboarding-container {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n min-height: 100vh;\n padding: 20px;\n font-family: 'GeistSans', -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', sans-serif;\n -webkit-font-smoothing: antialiased;\n -moz-osx-font-smoothing: grayscale;\n}\n\n/* Inline mode - no extra height */\n.onboarding-container.onboarding-inline {\n min-height: auto;\n padding: 0;\n justify-content: flex-start;\n /* width: 100%; */\n}\n\n/* Let the host page scroll the full card (wallet buttons, etc.) instead of\n nesting a second scrollbar inside a short embed. */\n.onboarding-container.onboarding-inline .onboarding-card {\n max-height: none;\n overflow-y: visible;\n}\n\n/* Modal Styles */\n.onboarding-modal-overlay {\n position: fixed;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n background-color: rgba(0, 0, 0, 0.6);\n backdrop-filter: blur(8px);\n -webkit-backdrop-filter: blur(8px);\n display: none; /* Start hidden by default to prevent flicker */\n align-items: center;\n justify-content: center;\n z-index: 9999;\n opacity: 0;\n transition: opacity 0.3s ease-in-out;\n padding: 16px;\n overflow: hidden;\n overscroll-behavior: contain;\n}\n\n.onboarding-modal-overlay::-webkit-scrollbar {\n display: none;\n}\n\n.onboarding-modal-overlay {\n -ms-overflow-style: none;\n scrollbar-width: none;\n}\n\n.onboarding-modal-overlay.onboarding-modal-open {\n display: flex; /* Show when explicitly opened */\n opacity: 1;\n}\n\n.onboarding-modal-overlay.onboarding-modal-closing {\n opacity: 0;\n}\n\n.onboarding-modal-content {\n position: relative;\n width: 100%;\n max-width: 420px;\n max-height: calc(100vh - 32px);\n overflow: hidden;\n transform: scale(0.95);\n transition: transform 0.3s cubic-bezier(0.4, 0, 0.2, 1);\n display: flex;\n flex-direction: column;\n}\n\n@media (max-width: 480px) {\n .onboarding-modal-content {\n max-width: 100%;\n max-height: 100vh;\n border-radius: 0;\n }\n \n .onboarding-modal-overlay {\n padding: 0;\n }\n}\n\n.onboarding-modal-overlay.onboarding-modal-open .onboarding-modal-content {\n transform: scale(1);\n}\n\n.onboarding-modal-overlay.onboarding-modal-closing .onboarding-modal-content {\n transform: scale(0.95);\n}\n\n.onboarding-modal-close {\n position: absolute;\n top: 8px;\n right: 8px;\n z-index: 20;\n display: flex;\n align-items: center;\n justify-content: center;\n width: 40px;\n height: 40px;\n padding: 0;\n margin: 0;\n border: none;\n border-radius: 8px;\n background: transparent;\n cursor: pointer;\n transition: background-color 0.2s, color 0.2s;\n}\n\n.onboarding-theme-light.onboarding-modal-close {\n color: #6b7280;\n}\n\n.onboarding-theme-dark.onboarding-modal-close {\n color: #9ca3af;\n}\n\n.onboarding-theme-light.onboarding-modal-close:hover {\n background-color: #f3f4f6;\n color: #111827;\n}\n\n.onboarding-theme-dark.onboarding-modal-close:hover {\n background-color: #2a2a2a;\n color: #ffffff;\n}\n\n/* Modal container adjustments */\n.onboarding-modal-content .onboarding-container {\n min-height: auto;\n padding: 0;\n}\n\n/* Light Theme */\n.onboarding-theme-light {\n color: #000000;\n}\n\n/* Dark Theme */\n.onboarding-theme-dark {\n color: #ffffff;\n}\n\n.onboarding-card {\n width: 100%;\n max-width: 420px;\n padding: 20px;\n border-radius: 16px;\n box-shadow: 0 8px 32px rgba(0, 0, 0, 0.12), 0 2px 8px rgba(0, 0, 0, 0.08);\n background-color: inherit;\n position: relative;\n overflow-y: auto;\n overflow-x: visible;\n max-height: calc(100vh - 32px);\n overscroll-behavior: contain;\n}\n\n.onboarding-card.onboarding-card-otp,\n.onboarding-card.onboarding-otp-active {\n overflow-x: visible;\n overflow-y: visible;\n}\n\n.onboarding-card.onboarding-card-otp .onboarding-otp-back-button,\n.onboarding-card.onboarding-otp-active .onboarding-otp-back-button {\n position: absolute !important;\n top: 0 !important;\n left: 0 !important;\n right: auto !important;\n bottom: auto !important;\n}\n\n/* MFA card: ensure stacking so auth code form is on top when modal is used */\n.onboarding-card.onboarding-card-mfa {\n position: relative;\n z-index: 1;\n}\n\n.onboarding-card.onboarding-card-mfa .onboarding-otp-back-button {\n position: absolute !important;\n top: 0 !important;\n left: 0 !important;\n right: auto !important;\n bottom: auto !important;\n}\n\n.onboarding-card::-webkit-scrollbar {\n width: 6px;\n}\n\n.onboarding-card::-webkit-scrollbar-track {\n background: transparent;\n}\n\n.onboarding-card::-webkit-scrollbar-thumb {\n background: rgba(0, 0, 0, 0.2);\n border-radius: 3px;\n}\n\n.onboarding-theme-dark .onboarding-card::-webkit-scrollbar-thumb {\n background: rgba(255, 255, 255, 0.2);\n}\n\n@media (max-width: 480px) {\n .onboarding-card {\n padding: 24px 20px;\n border-radius: 0;\n max-height: 100vh;\n }\n}\n\n.onboarding-theme-light .onboarding-card {\n background-color: #ffffff;\n box-shadow: 0 8px 32px rgba(0, 0, 0, 0.12), 0 2px 8px rgba(0, 0, 0, 0.08);\n border: 1px solid rgba(0, 0, 0, 0.06);\n}\n\n.onboarding-theme-dark .onboarding-card {\n background-color: #1f2937;\n box-shadow: 0 20px 60px rgba(0, 0, 0, 0.6), 0 0 1px rgba(255, 255, 255, 0.1);\n border: 1px solid rgba(255, 255, 255, 0.1);\n}\n\n.onboarding-header {\n text-align: center;\n margin-bottom: 20px;\n}\n\n.onboarding-logo-section {\n display: flex;\n flex-direction: column;\n align-items: center;\n margin-bottom: 12px;\n}\n\n.onboarding-logo-container {\n display: flex;\n justify-content: center;\n align-items: center;\n margin-bottom: 6px;\n gap: 10px;\n}\n\n.onboarding-logo-img {\n max-width: 120px;\n max-height: 60px;\n object-fit: contain;\n}\n\n\n.onboarding-title {\n font-size: 24px;\n font-weight: 500;\n margin: 0;\n color: inherit;\n text-align: center;\n margin-bottom: 4px;\n letter-spacing: -0.01em;\n line-height: 1.2;\n}\n\n@media (max-width: 480px) {\n .onboarding-title {\n font-size: 24px;\n margin-bottom: 24px;\n }\n}\n\n.onboarding-theme-light .onboarding-title {\n color: #111827;\n}\n\n.onboarding-theme-dark .onboarding-title {\n color: #ffffff;\n}\n\n.onboarding-form {\n width: 100%;\n}\n\n.onboarding-input-group {\n margin-bottom: 8px;\n}\n\n.onboarding-input-label {\n display: block;\n font-size: 14px;\n font-weight: 500;\n color: #374151;\n margin-bottom: 4px;\n letter-spacing: -0.01em;\n line-height: 1.5;\n text-align: left;\n width: 100%;\n}\n\n.onboarding-theme-dark .onboarding-input-label {\n color: #e5e7eb;\n}\n\n.onboarding-input-wrapper {\n position: relative;\n display: flex;\n align-items: center;\n}\n\n.onboarding-input-icon {\n position: absolute;\n left: 14px;\n color: #9ca3af;\n pointer-events: none;\n z-index: 1;\n width: 18px;\n height: 18px;\n}\n\n.onboarding-theme-dark .onboarding-input-icon {\n color: #9ca3af;\n}\n\n.onboarding-input {\n width: 100%;\n padding: 10px 14px 10px 44px;\n font-size: 14px;\n border: 1.5px solid #e5e7eb;\n border-radius: 8px;\n background-color: inherit;\n color: inherit;\n transition: all 0.15s ease;\n box-sizing: border-box;\n font-weight: 400;\n letter-spacing: 0;\n line-height: 1.5;\n}\n\n.onboarding-theme-light .onboarding-input {\n background-color: #ffffff;\n border-color: #e5e7eb;\n}\n\n.onboarding-theme-light .onboarding-input:-webkit-autofill,\n.onboarding-theme-light .onboarding-input:-webkit-autofill:hover,\n.onboarding-theme-light .onboarding-input:-webkit-autofill:focus,\n.onboarding-theme-light .onboarding-input:-webkit-autofill:active {\n -webkit-box-shadow: 0 0 0 30px #ffffff inset !important;\n -webkit-text-fill-color: #111827 !important;\n transition: background-color 5000s ease-in-out 0s;\n}\n\n.onboarding-theme-dark .onboarding-input {\n background-color: #374151;\n color: #ffffff;\n}\n\n.onboarding-theme-dark .onboarding-input:-webkit-autofill,\n.onboarding-theme-dark .onboarding-input:-webkit-autofill:hover,\n.onboarding-theme-dark .onboarding-input:-webkit-autofill:focus,\n.onboarding-theme-dark .onboarding-input:-webkit-autofill:active {\n -webkit-box-shadow: 0 0 0 30px #374151 inset !important;\n -webkit-text-fill-color: #ffffff !important;\n color: #ffffff !important;\n transition: background-color 5000s ease-in-out 0s;\n}\n\n.onboarding-input:focus {\n outline: none;\n}\n\n.onboarding-theme-light .onboarding-input:focus {\n border-color: #111827;\n box-shadow: 0 0 0 3px rgba(17, 24, 39, 0.1);\n background-color: #ffffff;\n}\n\n.onboarding-theme-dark .onboarding-input {\n border-color: #4b5563;\n background-color: #374151;\n}\n\n.onboarding-theme-dark .onboarding-input:focus {\n border-color: #9ca3af;\n box-shadow: 0 0 0 3px rgba(156, 163, 175, 0.2);\n background-color: #374151;\n}\n\n.onboarding-input-arrow-button {\n position: absolute;\n right: 8px;\n top: 50%;\n transform: translateY(-50%);\n width: 32px;\n height: 32px;\n border: none;\n background: transparent;\n display: flex;\n align-items: center;\n justify-content: center;\n cursor: pointer;\n color: #9ca3af;\n transition: background-color 0.2s ease, color 0.2s ease, transform 0.15s ease, box-shadow 0.2s ease;\n border-radius: 6px;\n padding: 0;\n z-index: 2;\n}\n\n/* Light mode: default state */\n.onboarding-theme-light .onboarding-input-arrow-button {\n color: #6b7280;\n}\n\n.onboarding-theme-light .onboarding-input-arrow-button:hover:not(:disabled) {\n background-color: rgba(139, 152, 202, 0.35);\n color: #1f2937;\n box-shadow: 0 1px 2px rgba(0, 0, 0, 0.06);\n}\n\n.onboarding-theme-light .onboarding-input-arrow-button:active:not(:disabled) {\n transform: translateY(-50%) scale(0.94);\n background-color: rgba(139, 152, 202, 0.5);\n box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.06);\n}\n\n.onboarding-theme-light .onboarding-input-arrow-button:focus-visible {\n outline: none;\n box-shadow: 0 0 0 2px #ffffff, 0 0 0 4px rgba(139, 152, 202, 0.5);\n}\n\n/* Light mode: filled state (has email) */\n.onboarding-theme-light .onboarding-input-arrow-button-filled {\n background-color: rgba(139, 152, 202, 0.45);\n color: #1f2937;\n box-shadow: 0 1px 2px rgba(0, 0, 0, 0.06);\n}\n\n.onboarding-theme-light .onboarding-input-arrow-button-filled:hover:not(:disabled) {\n background-color: rgba(139, 152, 202, 0.6);\n box-shadow: 0 2px 4px rgba(0, 0, 0, 0.08);\n}\n\n.onboarding-theme-light .onboarding-input-arrow-button-filled:active:not(:disabled) {\n transform: translateY(-50%) scale(0.94);\n background-color: rgba(139, 152, 202, 0.7);\n box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.08);\n}\n\n.onboarding-theme-light .onboarding-input-arrow-button-filled:focus-visible {\n outline: none;\n box-shadow: 0 0 0 2px #ffffff, 0 0 0 4px rgba(139, 152, 202, 0.55);\n}\n\n/* Dark mode */\n.onboarding-theme-dark .onboarding-input-arrow-button:hover:not(:disabled) {\n color: #ffffff;\n background-color: rgba(255, 255, 255, 0.12);\n}\n\n.onboarding-theme-dark .onboarding-input-arrow-button:active:not(:disabled) {\n transform: translateY(-50%) scale(0.94);\n background-color: rgba(255, 255, 255, 0.18);\n}\n\n.onboarding-theme-dark .onboarding-input-arrow-button:focus-visible {\n outline: none;\n box-shadow: 0 0 0 2px #1f2937, 0 0 0 4px rgba(156, 163, 175, 0.4);\n}\n\n.onboarding-theme-dark .onboarding-input-arrow-button-filled {\n color: #ffffff;\n background-color: rgba(255, 255, 255, 0.12);\n}\n\n.onboarding-theme-dark .onboarding-input-arrow-button-filled:hover:not(:disabled) {\n background-color: rgba(255, 255, 255, 0.18);\n}\n\n.onboarding-theme-dark .onboarding-input-arrow-button-filled:active:not(:disabled) {\n transform: translateY(-50%) scale(0.94);\n background-color: rgba(255, 255, 255, 0.22);\n}\n\n.onboarding-input-arrow-button:disabled {\n opacity: 0.35;\n cursor: not-allowed;\n}\n\n.onboarding-input-arrow-icon {\n width: 20px;\n height: 20px;\n}\n\n.onboarding-input:disabled {\n opacity: 0.6;\n cursor: not-allowed;\n}\n\n.onboarding-email-readonly {\n cursor: not-allowed;\n}\n\n.onboarding-error {\n padding: 0;\n margin-top: 8px;\n margin-bottom: 12px;\n background-color: transparent !important;\n color: #dc2626;\n font-size: 13px;\n text-align: center;\n width: 100%;\n font-weight: 500;\n line-height: 1.4;\n word-break: break-word;\n}\n\n.onboarding-theme-dark .onboarding-error {\n background-color: transparent !important;\n color: #fca5a5;\n}\n\n.onboarding-button {\n width: 100%;\n padding: 11px 20px;\n font-size: 14px;\n font-weight: 600;\n border: none;\n border-radius: 8px;\n cursor: pointer;\n transition: all 0.15s ease;\n display: flex;\n align-items: center;\n justify-content: center;\n gap: 8px;\n margin-bottom: 6px;\n letter-spacing: 0;\n line-height: 1.5;\n box-shadow: none;\n min-height: 42px;\n}\n\n.onboarding-button:disabled {\n opacity: 0.6;\n cursor: not-allowed;\n}\n\n.onboarding-button-loading {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n gap: 8px;\n}\n\n.onboarding-button-spinner {\n flex-shrink: 0;\n width: 16px;\n height: 16px;\n animation: onboarding-spin 1s linear infinite;\n}\n\n.onboarding-button-primary {\n font-weight: 600;\n box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05);\n}\n\n/* Light theme button */\n.onboarding-theme-light .onboarding-button-primary {\n background-color: #111827;\n color: #ffffff;\n}\n\n.onboarding-theme-light .onboarding-button-primary:hover:not(:disabled) {\n background-color: #1f2937;\n box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);\n transform: translateY(-1px);\n}\n\n.onboarding-theme-light .onboarding-button-primary:active:not(:disabled) {\n background-color: #374151;\n box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05);\n transform: translateY(0);\n}\n\n/* Dark theme button */\n.onboarding-theme-dark .onboarding-button-primary {\n background-color: #4b5563;\n color: #ffffff;\n}\n\n.onboarding-theme-dark .onboarding-button-primary:hover:not(:disabled) {\n background-color: #6b7280;\n box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2);\n transform: translateY(-1px);\n}\n\n.onboarding-theme-dark .onboarding-button-primary:active:not(:disabled) {\n background-color: #6b7280;\n box-shadow: 0 1px 2px rgba(0, 0, 0, 0.1);\n transform: translateY(0);\n}\n\n.onboarding-button-google {\n background-color: #ffffff;\n color: #1f2937;\n border: 1.5px solid #e5e7eb;\n font-weight: 500;\n box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05);\n font-size: 14px;\n}\n\n.onboarding-theme-dark .onboarding-button-google {\n background-color: #374151;\n color: #ffffff;\n border-color: #4b5563;\n}\n\n.onboarding-button-google:hover:not(:disabled) {\n background-color: #f9fafb;\n border-color: #d1d5db;\n box-shadow: 0 2px 4px rgba(0, 0, 0, 0.08);\n transform: translateY(-1px);\n}\n\n.onboarding-theme-dark .onboarding-button-google:hover:not(:disabled) {\n background-color: #4b5563;\n border-color: #6b7280;\n}\n\n.onboarding-google-icon {\n width: 20px;\n height: 20px;\n}\n\n.onboarding-button-google {\n display: flex;\n align-items: center;\n justify-content: center;\n gap: 8px;\n}\n\n.onboarding-social-grid {\n display: grid;\n grid-template-columns: repeat(auto-fit, minmax(48px, 1fr));\n justify-items: center;\n gap: 12px;\n width: 100%;\n}\n\n.onboarding-button-social-icon {\n display: flex;\n align-items: center;\n justify-content: center;\n width: 100%;\n height: 48px;\n padding: 0;\n border-radius: 12px;\n border: 1.5px solid #e5e7eb;\n background-color: #ffffff;\n color: #111827;\n cursor: pointer;\n transition: all 0.2s ease;\n}\n\n.onboarding-theme-dark .onboarding-button-social-icon {\n background-color: #374151;\n border-color: #4b5563;\n color: #ffffff;\n}\n\n.onboarding-button-social-icon:hover:not(:disabled) {\n background-color: #f9fafb;\n border-color: #d1d5db;\n transform: translateY(-1px);\n box-shadow: 0 2px 4px rgba(0, 0, 0, 0.08);\n}\n\n.onboarding-theme-dark .onboarding-button-social-icon:hover:not(:disabled) {\n background-color: #4b5563;\n border-color: #6b7280;\n}\n\n.onboarding-button-social-icon:disabled {\n opacity: 0.6;\n cursor: not-allowed;\n}\n\n.onboarding-social-icon {\n width: 20px;\n height: 20px;\n color: inherit;\n fill: currentColor;\n}\n\n/* Passkey Button Styles */\n.onboarding-button-passkey {\n background-color: #374151;\n color: #ffffff;\n border: 1.5px solid #4b5563;\n font-weight: 500;\n box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05);\n font-size: 14px;\n}\n\n.onboarding-theme-dark .onboarding-button-passkey {\n background-color: #4b5563;\n color: #ffffff;\n border-color: #6b7280;\n}\n\n.onboarding-button-passkey:hover:not(:disabled) {\n background-color: #4b5563;\n border-color: #6b7280;\n box-shadow: 0 2px 4px rgba(0, 0, 0, 0.08);\n transform: translateY(-1px);\n}\n\n.onboarding-theme-dark .onboarding-button-passkey:hover:not(:disabled) {\n background-color: #6b7280;\n border-color: #9ca3af;\n}\n\n.onboarding-passkey-icon {\n width: 20px;\n height: 20px;\n}\n\n.onboarding-passkey-signup-link {\n text-decoration: underline;\n cursor: pointer;\n font-size: 14px;\n font-weight: 500;\n margin-top: 12px;\n display: block;\n text-align: center;\n transition: color 0.15s ease;\n}\n\n.onboarding-theme-light .onboarding-passkey-signup-link {\n color: #2170f5;\n}\n\n.onboarding-theme-dark .onboarding-passkey-signup-link {\n color: #2170f5;\n}\n\n.onboarding-divider {\n display: flex;\n align-items: center;\n margin: 10px 0;\n position: relative;\n}\n\n.onboarding-divider::before,\n.onboarding-divider::after {\n content: '';\n flex: 1;\n height: 1px;\n background-color: #e5e7eb;\n}\n\n.onboarding-theme-dark .onboarding-divider::before,\n.onboarding-theme-dark .onboarding-divider::after {\n background-color: #4b5563;\n}\n\n.onboarding-divider-text {\n padding: 0 14px;\n font-size: 13px;\n color: #9ca3af;\n font-weight: 400;\n}\n\n.onboarding-theme-dark .onboarding-divider-text {\n color: #9ca3af;\n}\n\n\n.onboarding-footer {\n margin-top: 24px;\n padding: 0;\n text-align: center;\n background: transparent;\n border: none;\n border-radius: 0;\n width: 100%;\n display: flex;\n justify-content: center;\n align-items: center;\n}\n\n.onboarding-footer-text {\n font-size: 11px;\n color: #9ca3af;\n margin: 0;\n line-height: 1.5;\n font-weight: 400;\n letter-spacing: 0.01em;\n display: flex;\n align-items: center;\n justify-content: center;\n gap: 6px;\n flex-wrap: wrap;\n}\n\n.onboarding-theme-dark .onboarding-footer-text {\n color: #6b7280;\n}\n\n.onboarding-footer-brand {\n font-weight: 700;\n text-decoration: none;\n cursor: pointer;\n transition: opacity 0.15s ease;\n display: inline-flex;\n align-items: center;\n gap: 6px;\n}\n\n.onboarding-theme-light .onboarding-footer-brand {\n color: #111827;\n}\n\n.onboarding-theme-dark .onboarding-footer-brand {\n color: #9ca3af;\n}\n\n.onboarding-footer-brand:hover {\n text-decoration: none;\n opacity: 0.8;\n}\n\n/* Modal container adjustments */\n.onboarding-modal-content .onboarding-container {\n min-height: auto;\n padding: 0;\n}\n\n.onboarding-modal-content .onboarding-card {\n margin: 0;\n}\n\n/* OTP Verification Screen */\n.onboarding-otp-verification {\n display: flex !important;\n flex-direction: column;\n align-items: center;\n text-align: center;\n width: 100%;\n visibility: visible;\n opacity: 1;\n position: relative;\n padding-top: 0;\n}\n\n.onboarding-otp-back-button {\n position: absolute;\n top: 0;\n left: 0;\n width: 40px;\n height: 40px;\n min-width: 40px;\n min-height: 40px;\n display: flex !important;\n align-items: center;\n justify-content: center;\n background-color: transparent !important;\n border: none;\n border-radius: 8px;\n cursor: pointer;\n transition: all 0.2s ease;\n color: #6b7280 !important;\n padding: 0;\n margin: 0;\n z-index: 100;\n box-shadow: none !important;\n visibility: visible !important;\n opacity: 1 !important;\n pointer-events: auto !important;\n}\n\n.onboarding-otp-back-button svg {\n width: 20px;\n height: 20px;\n flex-shrink: 0;\n}\n\n@media (max-width: 480px) {\n .onboarding-otp-back-button {\n width: 36px;\n height: 36px;\n }\n\n .onboarding-otp-back-button svg {\n width: 18px;\n height: 18px;\n }\n}\n\n.onboarding-otp-back-button:hover:not(:disabled) {\n background-color: #f3f4f6 !important;\n color: #111827 !important;\n box-shadow: 0 2px 4px rgba(0, 0, 0, 0.05) !important;\n}\n\n.onboarding-otp-back-button:active:not(:disabled) {\n background-color: #e5e7eb !important;\n transform: scale(0.95);\n}\n\n.onboarding-otp-back-button:disabled {\n opacity: 0.3;\n cursor: not-allowed;\n}\n\n.onboarding-theme-dark .onboarding-otp-back-button {\n background-color: transparent !important;\n color: #9ca3af !important;\n box-shadow: none !important;\n}\n\n.onboarding-theme-dark .onboarding-otp-back-button:hover:not(:disabled) {\n background-color: rgba(255, 255, 255, 0.1) !important;\n color: #ffffff !important;\n}\n\n.onboarding-theme-dark .onboarding-otp-back-button:active:not(:disabled) {\n background-color: rgba(255, 255, 255, 0.15) !important;\n}\n\n.onboarding-otp-icon-container {\n width: 64px;\n height: 64px;\n border-radius: 50%;\n display: flex;\n align-items: center;\n justify-content: center;\n margin-bottom: 24px;\n position: relative;\n background: transparent;\n border: 3px solid #eef2ff;\n}\n\n.onboarding-otp-icon-container::after {\n content: '';\n position: absolute;\n top: -3px;\n left: -3px;\n right: -3px;\n bottom: -3px;\n border-radius: 50%;\n border: 3px solid transparent;\n border-top-color: #363ff9;\n animation: onboarding-spin 2s linear infinite;\n}\n\n@keyframes onboarding-spin {\n 0% { transform: rotate(0deg); }\n 100% { transform: rotate(360deg); }\n}\n\n.onboarding-theme-dark .onboarding-otp-icon-container {\n border-color: rgba(156, 163, 175, 0.2);\n}\n\n.onboarding-otp-icon-inner {\n width: 100%;\n height: 100%;\n background-color: transparent;\n display: flex;\n align-items: center;\n justify-content: center;\n z-index: 1;\n}\n\n.onboarding-otp-icon {\n width: 28px;\n height: 28px;\n color: #363ff9;\n}\n\n.onboarding-otp-title {\n font-size: 22px;\n font-weight: 500;\n margin: 0 0 16px 0;\n color: inherit;\n line-height: 1.4;\n letter-spacing: -0.01em;\n}\n\n.onboarding-theme-light .onboarding-otp-title {\n color: #111827;\n}\n\n.onboarding-theme-dark .onboarding-otp-title {\n color: #ffffff;\n}\n\n.onboarding-otp-instruction {\n font-size: 14px;\n color: #6b7280;\n margin: 0 0 8px 0;\n line-height: 1.5;\n font-weight: 400;\n}\n\n.onboarding-theme-dark .onboarding-otp-instruction {\n color: #9ca3af;\n}\n\n.onboarding-otp-email {\n font-size: 15px;\n font-weight: 600;\n color: inherit;\n margin: 0 0 32px 0;\n line-height: 1.5;\n}\n\n.onboarding-theme-light .onboarding-otp-email {\n color: #111827;\n}\n\n.onboarding-theme-dark .onboarding-otp-email {\n color: #ffffff;\n}\n\n.onboarding-otp-inputs-container {\n display: flex !important;\n gap: 10px;\n justify-content: center;\n align-items: center;\n margin-bottom: 24px;\n width: 100%;\n padding: 0 10px;\n box-sizing: border-box;\n visibility: visible !important;\n opacity: 1 !important;\n min-height: 60px;\n flex-wrap: nowrap;\n}\n\n.onboarding-otp-inputs-single {\n padding: 0;\n}\n\n.onboarding-otp-verification .onboarding-form {\n width: 100%;\n margin-top: 0;\n}\n\n.onboarding-otp-verification .onboarding-button {\n /* Match OTP inputs width: 6 × 44px + 5 × 10px gap = 314px */\n width: 314px;\n max-width: 100%;\n margin-top: 0;\n margin-bottom: 0;\n margin-left: auto;\n margin-right: auto;\n}\n\n.onboarding-otp-verification .onboarding-button:disabled {\n cursor: not-allowed;\n}\n\n.onboarding-mfa-trouble-text {\n font-size: 14px;\n margin: -6px 0 16px;\n color: #6b7280;\n text-align: center;\n}\n\n.onboarding-theme-dark .onboarding-mfa-trouble-text {\n color: #9ca3af;\n}\n\n.onboarding-mfa-backup-link {\n border: none !important;\n background: transparent !important;\n padding: 0 !important;\n margin: 0;\n text-decoration: underline;\n cursor: pointer;\n font-weight: 600;\n font-size: 14px;\n font-family: inherit;\n line-height: inherit;\n box-shadow: none !important;\n outline: none;\n appearance: none;\n -webkit-appearance: none;\n}\n\n.onboarding-theme-light .onboarding-mfa-backup-link {\n color: #111827;\n}\n\n.onboarding-theme-dark .onboarding-mfa-backup-link {\n color: #e5e7eb;\n}\n\n.onboarding-mfa-backup-link:hover:not(:disabled) {\n opacity: 0.8;\n}\n\n.onboarding-mfa-backup-link:disabled {\n opacity: 0.6;\n cursor: not-allowed;\n}\n\n.onboarding-mfa-backup-input {\n text-transform: uppercase;\n}\n\n.onboarding-mfa-backup-field {\n width: 100%;\n max-width: 320px;\n height: 52px;\n border: 1.5px solid #e5e7eb;\n border-radius: 8px;\n background-color: inherit;\n color: inherit;\n text-align: center;\n font-size: 18px;\n font-weight: 600;\n letter-spacing: 0.16em;\n padding: 0 14px;\n box-sizing: border-box;\n text-transform: uppercase;\n transition: all 0.15s ease;\n}\n\n.onboarding-theme-light .onboarding-mfa-backup-field {\n background-color: #ffffff;\n border-color: #e5e7eb;\n color: #000000;\n}\n\n.onboarding-theme-light .onboarding-mfa-backup-field:focus {\n outline: none;\n border-color: #111827;\n box-shadow: 0 0 0 3px rgba(17, 24, 39, 0.1);\n}\n\n.onboarding-theme-dark .onboarding-mfa-backup-field {\n border-color: #4b5563;\n background-color: #374151;\n color: #ffffff;\n}\n\n.onboarding-theme-dark .onboarding-mfa-backup-field:focus {\n outline: none;\n border-color: #9ca3af;\n box-shadow: 0 0 0 3px rgba(156, 163, 175, 0.2);\n background-color: #4b5563;\n}\n\n.onboarding-mfa-backup-field:disabled {\n opacity: 0.6;\n cursor: not-allowed;\n}\n\n.onboarding-mfa-backup-example {\n margin: -6px 0 16px;\n font-size: 13px;\n color: #9ca3af;\n}\n\n.onboarding-otp-input {\n width: 44px !important;\n min-width: 44px !important;\n height: 52px !important;\n min-height: 52px !important;\n display: inline-block !important;\n visibility: visible !important;\n opacity: 1 !important;\n text-align: center;\n font-size: 20px;\n font-weight: 600;\n border: 1.5px solid #e5e7eb;\n border-radius: 8px;\n background-color: inherit;\n color: inherit;\n transition: all 0.15s ease;\n box-sizing: border-box;\n line-height: 1;\n flex-shrink: 0;\n padding: 0;\n margin: 0;\n}\n\n.onboarding-theme-light .onboarding-otp-input {\n background-color: #ffffff !important;\n border-color: #e5e7eb !important;\n color: #000000 !important;\n}\n\n.onboarding-otp-input:focus {\n outline: none;\n}\n\n.onboarding-theme-light .onboarding-otp-input:focus {\n border-color: #111827 !important;\n box-shadow: 0 0 0 3px rgba(17, 24, 39, 0.1) !important;\n background-color: #ffffff !important;\n color: #000000 !important;\n}\n\n.onboarding-theme-dark .onboarding-otp-input {\n border-color: #4b5563 !important;\n background-color: #374151 !important;\n color: #ffffff !important;\n}\n\n.onboarding-theme-dark .onboarding-otp-input:focus {\n border-color: #9ca3af !important;\n box-shadow: 0 0 0 3px rgba(156, 163, 175, 0.2) !important;\n background-color: #4b5563 !important;\n color: #ffffff !important;\n}\n\n.onboarding-otp-input:disabled {\n opacity: 0.6;\n cursor: not-allowed;\n}\n\n.onboarding-otp-resend {\n text-align: center;\n margin-top: 24px;\n line-height: 1.5;\n}\n\n.onboarding-otp-resend-text {\n font-size: 13px;\n color: #6b7280;\n margin: 0;\n line-height: 1.5;\n font-weight: 400;\n}\n\n.onboarding-theme-dark .onboarding-otp-resend-text {\n color: #9ca3af;\n}\n\n.onboarding-otp-resend-link {\n color: #dc2626;\n text-decoration: underline;\n cursor: pointer;\n font-weight: 500;\n transition: color 0.15s ease;\n font-size: 13px;\n background: none;\n border: none;\n padding: 0;\n margin: 0;\n font-family: inherit;\n}\n\n.onboarding-otp-resend-link:hover {\n color: #b91c1c;\n text-decoration: underline;\n}\n\n.onboarding-otp-resend-link:active {\n color: #991b1b;\n}\n\n.onboarding-theme-dark .onboarding-otp-resend-link {\n color: #ef4444;\n}\n\n.onboarding-theme-dark .onboarding-otp-resend-link:hover {\n color: #dc2626;\n}\n\n.onboarding-otp-resend-cooldown {\n color: #9ca3af;\n font-size: 13px;\n}\n\n.onboarding-theme-dark .onboarding-otp-resend-cooldown {\n color: #6b7280;\n}\n\n.onboarding-otp-verification .onboarding-error {\n margin-bottom: 24px;\n margin-top: 0;\n text-align: center;\n}\n\n/* Additional Responsive Styles */\n@media (max-width: 480px) {\n .onboarding-container {\n padding: 12px;\n }\n\n .onboarding-card {\n padding: 24px 20px;\n }\n\n .onboarding-title {\n font-size: 24px;\n }\n\n .onboarding-input-group {\n margin-bottom: 16px;\n }\n\n .onboarding-button {\n width: 100%;\n padding: 14px 20px;\n }\n\n .onboarding-social-grid {\n grid-template-columns: 1fr;\n gap: 12px;\n }\n\n .onboarding-button-social-icon {\n width: 100%;\n justify-content: center;\n }\n\n .onboarding-otp-inputs-container {\n gap: 8px;\n }\n\n .onboarding-otp-verification .onboarding-button {\n /* 6 × 44px + 5 × 8px gap = 304px */\n width: 304px;\n }\n\n .onboarding-otp-input {\n width: 44px;\n min-width: 44px;\n height: 56px;\n min-height: 56px;\n font-size: 20px;\n }\n\n .onboarding-footer-text {\n font-size: 10px;\n }\n\n .onboarding-footer-brand {\n font-size: 10px;\n }\n\n .onboarding-footer-brand svg {\n width: 16px;\n height: 16px;\n }\n}\n\n@media (max-width: 360px) {\n .onboarding-card {\n padding: 20px 16px;\n }\n\n .onboarding-title {\n font-size: 22px;\n }\n\n .onboarding-otp-input {\n width: 40px;\n min-width: 40px;\n height: 56px;\n min-height: 56px;\n font-size: 18px;\n }\n}\n\n";
@@ -4,7 +4,6 @@
4
4
  */
5
5
  import React from "react";
6
6
  import type { OnboardingUIConfig } from "@abstraxn/signer-core";
7
- import "./OnboardingUI.css";
8
7
  export interface OnboardingUIReactProps {
9
8
  config?: Partial<OnboardingUIConfig>;
10
9
  modal?: boolean;
@@ -12,9 +12,13 @@ import { MfaForm } from "./components/MfaForm";
12
12
  import { SocialButtons } from "./components/SocialButtons";
13
13
  import { PasskeyButton } from "./components/PasskeyButton";
14
14
  import { Modal } from "./components/Modal";
15
- import { ExternalWalletButtons } from "../../ExternalWalletButtons";
15
+ import { Divider } from "./components/Divider";
16
+ import { ExternalWalletButtons, externalWalletButtonsCss } from "../../ExternalWalletButtons";
16
17
  import { useAbstraxnWallet } from "../../hooks";
17
- import "./OnboardingUI.css";
18
+ import { ShadowHost } from "../ShadowHost";
19
+ import { AbstraxnLogo } from "../AbstraxnLogo";
20
+ import onboardingUiCss from "./OnboardingUI.css.js";
21
+ const ONBOARDING_UI_REACT_CSS_TEXTS = [onboardingUiCss, externalWalletButtonsCss];
18
22
  export const OnboardingUIReact = ({ config = {}, modal = false, onClose, externalWalletsEnabled = false, availableConnectors = [], }) => {
19
23
  const normalizeErrorMessage = (message) => {
20
24
  let trimmed = message.trim();
@@ -109,9 +113,24 @@ export const OnboardingUIReact = ({ config = {}, modal = false, onClose, externa
109
113
  const hasUserData = user && (user.id || user.email);
110
114
  const isAlreadyAuthenticated = hasWhoamiData || hasUserData || isConnected;
111
115
  // Process OAuth callbacks - show loading modal for OAuth flows (skip when MFA required; show MFA screen instead)
112
- if (isOAuthCallback && oauthPending) {
116
+ // Gated on isOAuthCallback (derived from URL params) alone, NOT oauthPending -
117
+ // that localStorage flag is also read-and-cleared by AbstraxnProviderInner.tsx's
118
+ // and useOAuthCallbacks.ts's own callback handlers; whichever of those runs first
119
+ // clears it, so relying on it here raced against them and could silently skip
120
+ // showing the loading modal even on a genuinely successful login.
121
+ console.log("[OnboardingUIReact] OAuth callback check:", { isOAuthCallback, oauthPending, success, isAlreadyAuthenticated, mfaRequired, error });
122
+ if (isOAuthCallback) {
113
123
  if (success === "true" && !isAlreadyAuthenticated && !mfaRequired) {
114
- // Set OAuth loading modal for OAuth callbacks
124
+ // Set OAuth loading modal for OAuth callbacks.
125
+ // The modal only renders when `!isInOtpFlow` (i.e. onboarding.step isn't
126
+ // "email"/"otp") - but a fresh page load after the OAuth redirect always
127
+ // starts step at its default "email", and nothing was moving it off that
128
+ // for the OAuth path (only the OTP-verification flow ever called
129
+ // setStep('loading')). So oauthLoading could be true while the modal still
130
+ // never rendered. isOtpLoadingStep already disambiguates step === "loading"
131
+ // caused by OAuth vs OTP via isOAuthCallback, confirming "loading" is the
132
+ // intended step value here.
133
+ onboarding.setStep("loading");
115
134
  setOauthLoading(true);
116
135
  setOauthError(null);
117
136
  }
@@ -133,7 +152,7 @@ export const OnboardingUIReact = ({ config = {}, modal = false, onClose, externa
133
152
  setOauthLoading(false);
134
153
  }
135
154
  // Also handle config.handleUrlParams if provided (only for OAuth)
136
- if (config.handleUrlParams && isOAuthCallback && oauthPending) {
155
+ if (config.handleUrlParams && isOAuthCallback) {
137
156
  if (success === "true" && !isAlreadyAuthenticated && !mfaRequired) {
138
157
  onboarding.setLoading(true);
139
158
  }
@@ -275,11 +294,11 @@ export const OnboardingUIReact = ({ config = {}, modal = false, onClose, externa
275
294
  onClose?.();
276
295
  };
277
296
  // Helper to render modal content with header and footer
278
- const renderModalContent = (children) => (_jsx("div", { className: `onboarding-container onboarding-theme-${theme} ${config.className || ""}`, children: _jsxs("div", { className: "onboarding-card", children: [_jsxs("div", { className: "onboarding-header", children: [config.logo && (_jsx("div", { className: "onboarding-logo-section", children: _jsx("div", { className: "onboarding-logo-container", children: _jsx("img", { src: config.logo, alt: "Logo", className: "onboarding-logo-img" }) }) })), _jsx("h1", { className: "onboarding-title", id: "onboarding-title", children: config.onboardTitle || "Sign In" })] }), children, config.showFooter !== false && (_jsx("div", { className: "onboarding-footer", children: _jsxs("p", { className: "onboarding-footer-text", children: ["Powered by", " ", _jsxs("a", { href: "https://abstraxn.com", target: "_blank", rel: "noopener noreferrer", className: "onboarding-footer-brand", style: {
297
+ const renderModalContent = (children) => (_jsx("div", { className: `onboarding-container onboarding-theme-${theme} ${config.className || ""}`, part: "container", children: _jsxs("div", { className: "onboarding-card", part: "card", children: [_jsxs("div", { className: "onboarding-header", children: [config.logo && (_jsx("div", { className: "onboarding-logo-section", children: _jsx("div", { className: "onboarding-logo-container", children: _jsx("img", { src: config.logo, alt: "Logo", className: "onboarding-logo-img" }) }) })), _jsx("h1", { className: "onboarding-title", id: "onboarding-title", children: config.onboardTitle || "Sign In" })] }), children, config.showFooter !== false && (_jsx("div", { className: "onboarding-footer", children: _jsxs("p", { className: "onboarding-footer-text", children: ["Powered by", " ", _jsxs("a", { href: "https://abstraxn.com", target: "_blank", rel: "noopener noreferrer", className: "onboarding-footer-brand", style: {
279
298
  display: "inline-flex",
280
299
  alignItems: "center",
281
300
  gap: "6px",
282
- }, children: [_jsxs("svg", { xmlns: "http://www.w3.org/2000/svg", width: "20", height: "20", viewBox: "0 0 48 48", fill: "none", style: { display: "inline-block", verticalAlign: "middle" }, children: [_jsx("path", { d: "M47.9082 37.191L23.9541 23.553L0 9.91504L37.7436 -8.13502e-06L47.9082 37.191Z", fill: "url(#paint0_linear_1242_781)" }), _jsx("path", { d: "M13.5156 46.3594L10.1846 47.2344L8.99219 42.873L12.4365 42.4111L13.5156 46.3594ZM20.4268 44.5566L17.1152 45.4199L16.125 41.8818L19.5566 41.3721L20.4268 44.5566ZM26.9307 42.834L23.6152 43.6982L22.8438 40.9443L26.2744 40.4326L26.9307 42.834ZM33.5078 41.1074L30.1875 41.9727L29.6328 39.9951L33.0635 39.4844L33.5078 41.1074ZM39.998 39.4014L36.6729 40.2686L36.3359 39.0674L39.7656 38.5508L39.998 39.4014ZM10.1406 33.9434L11.6807 39.5762L8.15918 39.7568L6.46094 33.543L10.1406 33.9434ZM17.6582 34.5996L18.8916 39.1113L15.4199 39.3496L14.0078 34.3076L17.6582 34.5996ZM24.8779 35.332L25.8047 38.7227L22.3252 38.959L21.2266 35.0361L24.8779 35.332ZM32.0918 36.0723L32.7119 38.3398L29.2227 38.5723L28.4375 35.7656L32.0918 36.0723ZM43.2373 38.5488L43.1172 38.1172L47.7939 37.3516L43.2373 38.5488ZM39.3047 36.8096L39.6182 37.9561L36.1221 38.1846L35.6484 36.4961L39.3047 36.8096ZM47.7939 37.3516L43.0107 37.7939L42.8516 37.2236L47.7939 37.3516ZM47.8291 37.2988L42.7227 36.7529L42.5547 36.1523L47.8291 37.2988ZM47.8652 37.2412L42.3711 35.3486L42.2031 34.7471L47.8652 37.2412ZM38.748 34.8604L39.0664 36.0254L35.3369 35.4043L34.8594 33.6982L38.748 34.8604ZM31.0576 32.3994L31.6787 34.6709L27.959 34.0566L27.1719 31.2461L31.0576 32.3994ZM38.0811 32.6318L38.4092 33.8301L34.4893 32.3496L34.1543 31.1523C34.1005 30.9591 34.0322 30.7719 33.9531 30.5918L38.0811 32.6318ZM23.3682 29.9385L24.291 33.3164L20.5801 32.71L19.4844 28.7949L23.3682 29.9385ZM15.6641 27.4805L16.8896 31.9629L13.1875 31.3594L11.7812 26.3379L15.6641 27.4805ZM29.9463 28.4678L30.5693 30.748L26.6201 29.2812L25.8633 26.583C25.8534 26.5431 25.8417 26.5028 25.8281 26.4639L29.9463 28.4678ZM7.6875 25.0938L9.21484 30.6816L5.44727 29.959L3.75781 23.7793L7.6875 25.0938ZM21.5312 23.3623L22.4492 26.7227L18.5059 25.2627L17.4141 21.3643L21.5312 23.3623ZM13.6104 20.1602L14.8242 24.6006L10.8887 23.1387L9.49219 18.1553L13.6104 20.1602ZM5.2168 16.0654L6.72559 21.585L2.70703 19.9473L1.06055 13.8701L5.2168 16.0654Z", fill: "url(#paint1_linear_1242_781)" }), _jsxs("defs", { children: [_jsxs("linearGradient", { id: "paint0_linear_1242_781", x1: "7.03362", y1: "6.09543", x2: "47.2003", y2: "57.0656", gradientUnits: "userSpaceOnUse", children: [_jsx("stop", { stopColor: "#F878D2" }), _jsx("stop", { offset: "0.393522", stopColor: "#FDCC81" }), _jsx("stop", { offset: "1", stopColor: "#F9A0D9" })] }), _jsxs("linearGradient", { id: "paint1_linear_1242_781", x1: "2.53739", y1: "21.5136", x2: "48.7969", y2: "38.5742", gradientUnits: "userSpaceOnUse", children: [_jsx("stop", { stopColor: "#F878D2" }), _jsx("stop", { offset: "0.393522", stopColor: "#FDCC81" }), _jsx("stop", { offset: "1", stopColor: "#F9A0D9" })] })] })] }), _jsx("span", { children: "abstraxn" })] })] }) }))] }) }));
301
+ }, children: [_jsx(AbstraxnLogo, { size: 20, gradientId: "abstraxn_logo_oauth_footer" }), _jsx("span", { children: "abstraxn" })] })] }) }))] }) }));
283
302
  const showEmailForm = onboarding.step === "email" &&
284
303
  authMethods.includes("otp") &&
285
304
  !showExternalWallets;
@@ -296,36 +315,44 @@ export const OnboardingUIReact = ({ config = {}, modal = false, onClose, externa
296
315
  const showExternalWalletsSection = onboarding.step === "email" &&
297
316
  externalWalletsEnabled &&
298
317
  availableConnectors.length > 0;
299
- const content = (_jsx("div", { className: `onboarding-container onboarding-theme-${theme} ${config.className || ""}`, children: _jsxs("div", { className: `onboarding-card ${showOtpForm ? "onboarding-card-otp" : ""} ${showMfaForm ? "onboarding-card-mfa" : ""}`, children: [!showOtpForm && !showMfaForm && (_jsxs("div", { className: "onboarding-header", children: [config.logo && (_jsx("div", { className: "onboarding-logo-section", children: _jsx("div", { className: "onboarding-logo-container", children: _jsx("img", { src: config.logo, alt: "Logo", className: "onboarding-logo-img" }) }) })), _jsx("h1", { className: "onboarding-title", id: "onboarding-title", children: config.onboardTitle || "Sign In" })] })), showEmailForm && (_jsx(EmailForm, { email: onboarding.email, onChange: onboarding.setEmail, onSubmit: onboarding.handleEmailSubmit, loading: onboarding.loading, error: onboarding.error, config: config, readOnly: !!emailForOtp })), showOtpForm && (_jsx(OtpForm, { email: onboarding.email, otp: onboarding.otp, onChange: onboarding.setOtp, onSubmit: onboarding.handleOtpSubmit, onResend: onboarding.handleResendOtp, onBack: onboarding.reset, loading: onboarding.loading, resending: onboarding.resending, requireManualVerify: onboarding.requireManualVerify, error: onboarding.error, resendCooldown: onboarding.resendCooldown, config: config })), showMfaForm && (_jsx(MfaForm, { code: onboarding.mfaCode, onChange: onboarding.setMfaCode, onSubmit: onboarding.handleMfaSubmit, onBack: onboarding.otpId
318
+ const content = (_jsx("div", { className: `onboarding-container onboarding-theme-${theme}${modal ? "" : " onboarding-inline"} ${config.className || ""}`.trim(), part: "container", children: _jsxs("div", { className: `onboarding-card ${showOtpForm ? "onboarding-card-otp" : ""} ${showMfaForm ? "onboarding-card-mfa" : ""}`, part: "card", children: [!showOtpForm && !showMfaForm && (_jsxs("div", { className: "onboarding-header", children: [config.logo && (_jsx("div", { className: "onboarding-logo-section", children: _jsx("div", { className: "onboarding-logo-container", children: _jsx("img", { src: config.logo, alt: "Logo", className: "onboarding-logo-img" }) }) })), _jsx("h1", { className: "onboarding-title", id: "onboarding-title", children: config.onboardTitle || "Sign In" })] })), showEmailForm && (_jsx(EmailForm, { email: onboarding.email, onChange: onboarding.setEmail, onSubmit: onboarding.handleEmailSubmit, loading: onboarding.loading, error: onboarding.error, config: config, readOnly: !!emailForOtp })), showOtpForm && (_jsx(OtpForm, { email: onboarding.email, otp: onboarding.otp, onChange: onboarding.setOtp, onSubmit: onboarding.handleOtpSubmit, onResend: onboarding.handleResendOtp, onBack: onboarding.reset, loading: onboarding.loading, resending: onboarding.resending, requireManualVerify: onboarding.requireManualVerify, error: onboarding.error, resendCooldown: onboarding.resendCooldown, config: config })), showMfaForm && (_jsx(MfaForm, { code: onboarding.mfaCode, onChange: onboarding.setMfaCode, onSubmit: onboarding.handleMfaSubmit, onBack: onboarding.otpId
300
319
  ? () => onboarding.setStep("otp")
301
- : () => onboarding.reset(), loading: onboarding.loading, error: onboarding.error, config: config })), onboarding.step === "error" && onboarding.error && (_jsxs("div", { className: "onboarding-error-container", children: [_jsx("div", { className: "onboarding-error", role: "alert", children: normalizeErrorMessage(onboarding.error) }), _jsx("button", { type: "button", className: "onboarding-button onboarding-button-primary", onClick: onboarding.reset, children: "Try Again" })] })), showSocialButtons && (showEmailForm || showOtpForm) && (_jsx("div", { className: "onboarding-divider", children: _jsx("span", { className: "onboarding-divider-text", children: "or" }) })), showSocialButtons && (_jsx(SocialButtons, { onGoogleLogin: authMethodsHook.handleGoogleLogin, onTwitterLogin: authMethodsHook.handleTwitterLogin, onDiscordLogin: authMethodsHook.handleDiscordLogin, loading: authMethodsHook.loading, config: config })), showPasskey && (_jsx(PasskeyButton, { onPasskeyLogin: authMethodsHook.handlePasskeyLogin, onPasskeySignup: authMethodsHook.handlePasskeySignup, loading: authMethodsHook.loading, config: config })), showExternalWalletsSection && (_jsxs(_Fragment, { children: [!showExternalWallets && (_jsx("div", { className: "onboarding-divider", children: _jsx("span", { className: "onboarding-divider-text", children: "or" }) })), _jsx("div", { style: { marginTop: showExternalWallets ? "0" : "12px" }, children: _jsx(ExternalWalletButtons, { onShowMoreWallets: () => setShowExternalWallets(true), onHideMoreWallets: () => setShowExternalWallets(false) }) })] })), config.showFooter !== false && (_jsx("div", { className: "onboarding-footer", children: _jsxs("p", { className: "onboarding-footer-text", children: ["Powered by", " ", _jsxs("a", { href: "https://abstraxn.com", target: "_blank", rel: "noopener noreferrer", className: "onboarding-footer-brand", style: {
320
+ : () => onboarding.reset(), loading: onboarding.loading, error: onboarding.error, config: config })), onboarding.step === "error" && onboarding.error && (_jsxs("div", { className: "onboarding-error-container", children: [_jsx("div", { className: "onboarding-error", role: "alert", children: normalizeErrorMessage(onboarding.error) }), _jsx("button", { type: "button", className: "onboarding-button onboarding-button-primary", part: "button-primary", onClick: onboarding.reset, children: "Try Again" })] })), showSocialButtons && (showEmailForm || showOtpForm) && _jsx(Divider, {}), showSocialButtons && (_jsx(SocialButtons, { onGoogleLogin: authMethodsHook.handleGoogleLogin, onTwitterLogin: authMethodsHook.handleTwitterLogin, onDiscordLogin: authMethodsHook.handleDiscordLogin, loading: authMethodsHook.loading, config: config })), showPasskey && (_jsx(PasskeyButton, { onPasskeyLogin: authMethodsHook.handlePasskeyLogin, onPasskeySignup: authMethodsHook.handlePasskeySignup, loading: authMethodsHook.loading, config: config })), showExternalWalletsSection && (_jsxs(_Fragment, { children: [!showExternalWallets && _jsx(Divider, {}), _jsx("div", { style: { marginTop: showExternalWallets ? "0" : "12px" }, children: _jsx(ExternalWalletButtons, { onShowMoreWallets: () => setShowExternalWallets(true), onHideMoreWallets: () => setShowExternalWallets(false) }) })] })), config.showFooter !== false && (_jsx("div", { className: "onboarding-footer", children: _jsxs("p", { className: "onboarding-footer-text", children: ["Powered by", " ", _jsxs("a", { href: "https://abstraxn.com", target: "_blank", rel: "noopener noreferrer", className: "onboarding-footer-brand", style: {
302
321
  display: "inline-flex",
303
322
  alignItems: "center",
304
323
  gap: "6px",
305
- }, children: [_jsxs("svg", { xmlns: "http://www.w3.org/2000/svg", width: "20", height: "20", viewBox: "0 0 48 48", fill: "none", style: { display: "inline-block", verticalAlign: "middle" }, children: [_jsx("path", { d: "M47.9082 37.191L23.9541 23.553L0 9.91504L37.7436 -8.13502e-06L47.9082 37.191Z", fill: "url(#paint0_linear_1242_781)" }), _jsx("path", { d: "M13.5156 46.3594L10.1846 47.2344L8.99219 42.873L12.4365 42.4111L13.5156 46.3594ZM20.4268 44.5566L17.1152 45.4199L16.125 41.8818L19.5566 41.3721L20.4268 44.5566ZM26.9307 42.834L23.6152 43.6982L22.8438 40.9443L26.2744 40.4326L26.9307 42.834ZM33.5078 41.1074L30.1875 41.9727L29.6328 39.9951L33.0635 39.4844L33.5078 41.1074ZM39.998 39.4014L36.6729 40.2686L36.3359 39.0674L39.7656 38.5508L39.998 39.4014ZM10.1406 33.9434L11.6807 39.5762L8.15918 39.7568L6.46094 33.543L10.1406 33.9434ZM17.6582 34.5996L18.8916 39.1113L15.4199 39.3496L14.0078 34.3076L17.6582 34.5996ZM24.8779 35.332L25.8047 38.7227L22.3252 38.959L21.2266 35.0361L24.8779 35.332ZM32.0918 36.0723L32.7119 38.3398L29.2227 38.5723L28.4375 35.7656L32.0918 36.0723ZM43.2373 38.5488L43.1172 38.1172L47.7939 37.3516L43.2373 38.5488ZM39.3047 36.8096L39.6182 37.9561L36.1221 38.1846L35.6484 36.4961L39.3047 36.8096ZM47.7939 37.3516L43.0107 37.7939L42.8516 37.2236L47.7939 37.3516ZM47.8291 37.2988L42.7227 36.7529L42.5547 36.1523L47.8291 37.2988ZM47.8652 37.2412L42.3711 35.3486L42.2031 34.7471L47.8652 37.2412ZM38.748 34.8604L39.0664 36.0254L35.3369 35.4043L34.8594 33.6982L38.748 34.8604ZM31.0576 32.3994L31.6787 34.6709L27.959 34.0566L27.1719 31.2461L31.0576 32.3994ZM38.0811 32.6318L38.4092 33.8301L34.4893 32.3496L34.1543 31.1523C34.1005 30.9591 34.0322 30.7719 33.9531 30.5918L38.0811 32.6318ZM23.3682 29.9385L24.291 33.3164L20.5801 32.71L19.4844 28.7949L23.3682 29.9385ZM15.6641 27.4805L16.8896 31.9629L13.1875 31.3594L11.7812 26.3379L15.6641 27.4805ZM29.9463 28.4678L30.5693 30.748L26.6201 29.2812L25.8633 26.583C25.8534 26.5431 25.8417 26.5028 25.8281 26.4639L29.9463 28.4678ZM7.6875 25.0938L9.21484 30.6816L5.44727 29.959L3.75781 23.7793L7.6875 25.0938ZM21.5312 23.3623L22.4492 26.7227L18.5059 25.2627L17.4141 21.3643L21.5312 23.3623ZM13.6104 20.1602L14.8242 24.6006L10.8887 23.1387L9.49219 18.1553L13.6104 20.1602ZM5.2168 16.0654L6.72559 21.585L2.70703 19.9473L1.06055 13.8701L5.2168 16.0654Z", fill: "url(#paint1_linear_1242_781)" }), _jsxs("defs", { children: [_jsxs("linearGradient", { id: "paint0_linear_1242_781", x1: "7.03362", y1: "6.09543", x2: "47.2003", y2: "57.0656", gradientUnits: "userSpaceOnUse", children: [_jsx("stop", { stopColor: "#F878D2" }), _jsx("stop", { offset: "0.393522", stopColor: "#FDCC81" }), _jsx("stop", { offset: "1", stopColor: "#F9A0D9" })] }), _jsxs("linearGradient", { id: "paint1_linear_1242_781", x1: "2.53739", y1: "21.5136", x2: "48.7969", y2: "38.5742", gradientUnits: "userSpaceOnUse", children: [_jsx("stop", { stopColor: "#F878D2" }), _jsx("stop", { offset: "0.393522", stopColor: "#FDCC81" }), _jsx("stop", { offset: "1", stopColor: "#F9A0D9" })] })] })] }), _jsx("span", { children: "abstraxn" })] })] }) }))] }) }));
324
+ }, children: [_jsx(AbstraxnLogo, { size: 20, gradientId: "abstraxn_logo_main_footer" }), _jsx("span", { children: "abstraxn" })] })] }) }))] }) }));
306
325
  // OAuth Loading Modal (only show for OAuth flows, never during OTP flow)
307
326
  // Check if we're in OTP flow - only email and otp steps, not loading (loading can be OAuth too)
308
327
  const isInOtpFlow = onboarding.step === "email" || onboarding.step === "otp";
309
328
  // Show OAuth loading modal if oauthLoading is true and not in OTP flow
329
+ //
330
+ // Collapsed from an early-return chain into a single `result` variable so
331
+ // exactly one ShadowHost wrap can be applied at the bottom — same branches,
332
+ // same priority order, just deferred to one final return.
333
+ let result;
310
334
  if (oauthLoading && !isInOtpFlow) {
311
- return (_jsx(Modal, { isOpen: true, onClose: () => {
335
+ result = (_jsx(Modal, { isOpen: true, onClose: () => {
312
336
  setOauthLoading(false);
313
337
  clearQueryParams();
314
- }, closeOnBackdropClick: config.closeOnBackdropClick !== false, showCloseButton: showModalCloseButton, theme: theme, children: renderModalContent(_jsxs("div", { className: "onboarding-loading", style: { textAlign: "center", padding: "40px" }, children: [_jsxs("svg", { width: "48", height: "48", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", style: { animation: "spin 1s linear infinite" }, children: [_jsx("line", { x1: "12", y1: "2", x2: "12", y2: "6" }), _jsx("line", { x1: "12", y1: "18", x2: "12", y2: "22" }), _jsx("line", { x1: "4.93", y1: "4.93", x2: "7.76", y2: "7.76" }), _jsx("line", { x1: "16.24", y1: "16.24", x2: "19.07", y2: "19.07" }), _jsx("line", { x1: "2", y1: "12", x2: "6", y2: "12" }), _jsx("line", { x1: "18", y1: "12", x2: "22", y2: "12" }), _jsx("line", { x1: "4.93", y1: "19.07", x2: "7.76", y2: "16.24" }), _jsx("line", { x1: "16.24", y1: "7.76", x2: "19.07", y2: "4.93" })] }), _jsx("p", { style: { marginTop: "16px" }, children: "Authenticating..." })] })) }));
338
+ }, closeOnBackdropClick: config.closeOnBackdropClick !== false, showCloseButton: showModalCloseButton, theme: theme, children: renderModalContent(_jsxs("div", { className: "onboarding-loading", style: { textAlign: "center", padding: "40px" }, children: [_jsxs("svg", { className: "onboarding-button-spinner", width: "48", height: "48", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": "true", style: { width: 48, height: 48 }, children: [_jsx("line", { x1: "12", y1: "2", x2: "12", y2: "6" }), _jsx("line", { x1: "12", y1: "18", x2: "12", y2: "22" }), _jsx("line", { x1: "4.93", y1: "4.93", x2: "7.76", y2: "7.76" }), _jsx("line", { x1: "16.24", y1: "16.24", x2: "19.07", y2: "19.07" }), _jsx("line", { x1: "2", y1: "12", x2: "6", y2: "12" }), _jsx("line", { x1: "18", y1: "12", x2: "22", y2: "12" }), _jsx("line", { x1: "4.93", y1: "19.07", x2: "7.76", y2: "16.24" }), _jsx("line", { x1: "16.24", y1: "7.76", x2: "19.07", y2: "4.93" })] }), _jsx("p", { style: { marginTop: "16px" }, children: "Authenticating..." })] })) }));
315
339
  }
316
- // OAuth Error Modal
317
- if (oauthError) {
318
- return (_jsx(Modal, { isOpen: true, onClose: () => {
340
+ else if (oauthError) {
341
+ // OAuth Error Modal
342
+ result = (_jsx(Modal, { isOpen: true, onClose: () => {
319
343
  setOauthError(null);
320
344
  clearQueryParams();
321
- }, closeOnBackdropClick: config.closeOnBackdropClick !== false, showCloseButton: showModalCloseButton, theme: theme, children: renderModalContent(_jsxs("div", { className: "onboarding-error-container", style: { padding: "40px", textAlign: "center" }, children: [_jsx("div", { className: "onboarding-error", role: "alert", children: normalizeErrorMessage(oauthError) }), _jsx("button", { type: "button", className: "onboarding-button onboarding-button-primary", onClick: () => {
345
+ }, closeOnBackdropClick: config.closeOnBackdropClick !== false, showCloseButton: showModalCloseButton, theme: theme, children: renderModalContent(_jsxs("div", { className: "onboarding-error-container", style: { padding: "40px", textAlign: "center" }, children: [_jsx("div", { className: "onboarding-error", role: "alert", children: normalizeErrorMessage(oauthError) }), _jsx("button", { type: "button", className: "onboarding-button onboarding-button-primary", part: "button-primary", onClick: () => {
322
346
  setOauthError(null);
323
347
  clearQueryParams();
324
348
  }, style: { marginTop: "24px" }, children: "Close" })] })) }));
325
349
  }
326
- if (modal) {
327
- return (_jsx(Modal, { isOpen: true, onClose: handleClose, closeOnBackdropClick: config.closeOnBackdropClick !== false, showCloseButton: showModalCloseButton, theme: theme, children: content }));
350
+ else if (modal) {
351
+ result = (_jsx(Modal, { isOpen: true, onClose: handleClose, closeOnBackdropClick: config.closeOnBackdropClick !== false, showCloseButton: showModalCloseButton, theme: theme, children: content }));
328
352
  }
329
- return content;
353
+ else {
354
+ result = content;
355
+ }
356
+ return (_jsx(ShadowHost, { cssTexts: ONBOARDING_UI_REACT_CSS_TEXTS, customCSS: config.customCSS, children: result }));
330
357
  };
331
358
  //# sourceMappingURL=OnboardingUIReact.js.map
@@ -6,7 +6,11 @@ import type { OnboardingUIConfig, Theme } from "@abstraxn/signer-core";
6
6
  * Works with vanilla JavaScript - no framework dependencies required.
7
7
  */
8
8
  export declare class OnboardingUIWeb {
9
- private static stylesInjected;
9
+ private stylesInjected;
10
+ private shadowContainer;
11
+ private shadowTeardown;
12
+ /** Pending OAuth loader timer from checkUrlParams — cleared in destroy() so StrictMode cleanup cannot paint into a torn-down shadow root. */
13
+ private pendingLoadingModalTimer;
10
14
  private config;
11
15
  private container;
12
16
  private rootElement;
@@ -55,6 +59,13 @@ export declare class OnboardingUIWeb {
55
59
  * Call this before init() to prevent flicker when external wallets are enabled
56
60
  */
57
61
  showExternalWallets(): void;
62
+ /** True when this instance still owns an attached shadow container. */
63
+ hasLiveShadow(): boolean;
64
+ /**
65
+ * Rebuild the shadow tree if destroy()/StrictMode tore it down.
66
+ * Safe to call before showLoadingModal / showOnboarding recovery paths.
67
+ */
68
+ ensureLiveShadow(): void;
58
69
  /**
59
70
  * Initialize and render the component
60
71
  */
@@ -92,6 +103,18 @@ export declare class OnboardingUIWeb {
92
103
  * Inject CSS styles into the document head (only once)
93
104
  */
94
105
  private injectStyles;
106
+ /**
107
+ * Build a divider element (line + "or" text) matching `.onboarding-divider`
108
+ */
109
+ private createDividerElement;
110
+ /**
111
+ * Footer text/brand colors, derived from config.colors.text with theme-based fallbacks
112
+ */
113
+ private getFooterTextColors;
114
+ /**
115
+ * Passkey button colors, derived from config.colors with theme-based fallbacks
116
+ */
117
+ private getPasskeyButtonColors;
95
118
  /**
96
119
  * Apply custom colors from config
97
120
  */