@strands.gg/accui 2.1.2 → 2.1.4

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 (183) hide show
  1. package/dist/index.d.ts +7 -0
  2. package/dist/index.d.ts.map +1 -0
  3. package/dist/nuxt/module.d.ts +6 -0
  4. package/dist/nuxt/module.d.ts.map +1 -0
  5. package/dist/nuxt/runtime/composables/useAuthenticatedFetch.cjs.js +1 -1
  6. package/dist/nuxt/runtime/composables/useAuthenticatedFetch.cjs.js.map +1 -1
  7. package/dist/nuxt/runtime/composables/useAuthenticatedFetch.d.ts +21 -0
  8. package/dist/nuxt/runtime/composables/useAuthenticatedFetch.d.ts.map +1 -0
  9. package/dist/nuxt/runtime/composables/useAuthenticatedFetch.es.js +5 -2
  10. package/dist/nuxt/runtime/composables/useAuthenticatedFetch.es.js.map +1 -1
  11. package/dist/nuxt/runtime/composables/useStrandsAuth.d.ts +143 -0
  12. package/dist/nuxt/runtime/composables/useStrandsAuth.d.ts.map +1 -0
  13. package/dist/nuxt/runtime/middleware/auth.d.ts +8 -0
  14. package/dist/nuxt/runtime/middleware/auth.d.ts.map +1 -0
  15. package/dist/nuxt/runtime/middleware/auth.global.d.ts +4 -0
  16. package/dist/nuxt/runtime/middleware/auth.global.d.ts.map +1 -0
  17. package/dist/nuxt/runtime/middleware/guest.d.ts +8 -0
  18. package/dist/nuxt/runtime/middleware/guest.d.ts.map +1 -0
  19. package/dist/nuxt/runtime/plugin.client.d.ts +4 -0
  20. package/dist/nuxt/runtime/plugin.client.d.ts.map +1 -0
  21. package/dist/nuxt/runtime/plugin.server.d.ts +4 -0
  22. package/dist/nuxt/runtime/plugin.server.d.ts.map +1 -0
  23. package/dist/nuxt/runtime/plugins/auth-interceptor.client.d.ts +4 -0
  24. package/dist/nuxt/runtime/plugins/auth-interceptor.client.d.ts.map +1 -0
  25. package/dist/nuxt/types.d.ts +46 -0
  26. package/dist/nuxt/types.d.ts.map +1 -0
  27. package/dist/nuxt-v4/module.d.ts +6 -0
  28. package/dist/nuxt-v4/module.d.ts.map +1 -0
  29. package/dist/nuxt-v4/runtime/composables/useAuthenticatedFetch.cjs.js +1 -1
  30. package/dist/nuxt-v4/runtime/composables/useAuthenticatedFetch.cjs.js.map +1 -1
  31. package/dist/nuxt-v4/runtime/composables/useAuthenticatedFetch.d.ts +21 -0
  32. package/dist/nuxt-v4/runtime/composables/useAuthenticatedFetch.d.ts.map +1 -0
  33. package/dist/nuxt-v4/runtime/composables/useAuthenticatedFetch.es.js +5 -2
  34. package/dist/nuxt-v4/runtime/composables/useAuthenticatedFetch.es.js.map +1 -1
  35. package/dist/nuxt-v4/runtime/composables/useStrandsAuth.cjs.js +1 -1
  36. package/dist/nuxt-v4/runtime/composables/useStrandsAuth.cjs.js.map +1 -1
  37. package/dist/nuxt-v4/runtime/composables/useStrandsAuth.d.ts +28 -0
  38. package/dist/nuxt-v4/runtime/composables/useStrandsAuth.d.ts.map +1 -0
  39. package/dist/nuxt-v4/runtime/composables/useStrandsAuth.es.js +1 -0
  40. package/dist/nuxt-v4/runtime/composables/useStrandsAuth.es.js.map +1 -1
  41. package/dist/nuxt-v4/runtime/middleware/auth.global.d.ts +4 -0
  42. package/dist/nuxt-v4/runtime/middleware/auth.global.d.ts.map +1 -0
  43. package/dist/nuxt-v4/runtime/plugin.client.d.ts +4 -0
  44. package/dist/nuxt-v4/runtime/plugin.client.d.ts.map +1 -0
  45. package/dist/nuxt-v4/runtime/plugin.server.d.ts +4 -0
  46. package/dist/nuxt-v4/runtime/plugin.server.d.ts.map +1 -0
  47. package/dist/nuxt-v4/runtime/plugins/auth-interceptor.client.cjs.js.map +1 -1
  48. package/dist/nuxt-v4/runtime/plugins/auth-interceptor.client.d.ts +4 -0
  49. package/dist/nuxt-v4/runtime/plugins/auth-interceptor.client.d.ts.map +1 -0
  50. package/dist/nuxt-v4/runtime/plugins/auth-interceptor.client.es.js.map +1 -1
  51. package/dist/nuxt-v4/types.d.ts +64 -0
  52. package/dist/nuxt-v4/types.d.ts.map +1 -0
  53. package/dist/nuxt-v4.d.ts +5 -0
  54. package/dist/nuxt-v4.d.ts.map +1 -0
  55. package/dist/nuxt.d.ts +5 -0
  56. package/dist/nuxt.d.ts.map +1 -0
  57. package/dist/shared/defaults.d.ts +3 -0
  58. package/dist/shared/defaults.d.ts.map +1 -0
  59. package/dist/strands-auth-ui.cjs.js +1 -1
  60. package/dist/strands-auth-ui.cjs.js.map +1 -1
  61. package/dist/strands-auth-ui.es.js +4 -2
  62. package/dist/strands-auth-ui.es.js.map +1 -1
  63. package/dist/types/index.d.ts +237 -0
  64. package/dist/types/index.d.ts.map +1 -0
  65. package/dist/utils/index.d.ts +2 -0
  66. package/dist/utils/index.d.ts.map +1 -0
  67. package/dist/utils/slots.d.ts +2 -0
  68. package/dist/utils/slots.d.ts.map +1 -0
  69. package/dist/utils/validation.d.ts +13 -0
  70. package/dist/utils/validation.d.ts.map +1 -0
  71. package/dist/vue/components/SignedIn.vue.d.ts +55 -0
  72. package/dist/vue/components/SignedIn.vue.d.ts.map +1 -0
  73. package/dist/vue/components/SignedOut.vue.d.ts +55 -0
  74. package/dist/vue/components/SignedOut.vue.d.ts.map +1 -0
  75. package/dist/vue/components/StrandsAuth.vue.d.ts +26 -0
  76. package/dist/vue/components/StrandsAuth.vue.d.ts.map +1 -0
  77. package/dist/vue/components/StrandsBackupCodesModal.vue.d.ts +13 -0
  78. package/dist/vue/components/StrandsBackupCodesModal.vue.d.ts.map +1 -0
  79. package/dist/vue/components/StrandsCompleteSignUp.vue.d.ts +22 -0
  80. package/dist/vue/components/StrandsCompleteSignUp.vue.d.ts.map +1 -0
  81. package/dist/vue/components/StrandsConfigProvider.vue.d.ts +23 -0
  82. package/dist/vue/components/StrandsConfigProvider.vue.d.ts.map +1 -0
  83. package/dist/vue/components/StrandsConfirmModal.vue.d.ts +23 -0
  84. package/dist/vue/components/StrandsConfirmModal.vue.d.ts.map +1 -0
  85. package/dist/vue/components/StrandsEmailMfaSetupModal.vue.d.ts +13 -0
  86. package/dist/vue/components/StrandsEmailMfaSetupModal.vue.d.ts.map +1 -0
  87. package/dist/vue/components/StrandsHardwareKeySetupModal.vue.d.ts +16 -0
  88. package/dist/vue/components/StrandsHardwareKeySetupModal.vue.d.ts.map +1 -0
  89. package/dist/vue/components/StrandsLogo.vue.d.ts +9 -0
  90. package/dist/vue/components/StrandsLogo.vue.d.ts.map +1 -0
  91. package/dist/vue/components/StrandsMFASetup.vue.d.ts +17 -0
  92. package/dist/vue/components/StrandsMFASetup.vue.d.ts.map +1 -0
  93. package/dist/vue/components/StrandsMfaModal.vue.d.ts +13 -0
  94. package/dist/vue/components/StrandsMfaModal.vue.d.ts.map +1 -0
  95. package/dist/vue/components/StrandsMfaVerification.vue.d.ts +18 -0
  96. package/dist/vue/components/StrandsMfaVerification.vue.d.ts.map +1 -0
  97. package/dist/vue/components/StrandsPasswordReset.vue.d.ts +16 -0
  98. package/dist/vue/components/StrandsPasswordReset.vue.d.ts.map +1 -0
  99. package/dist/vue/components/StrandsSecuredFooter.vue.d.ts +23 -0
  100. package/dist/vue/components/StrandsSecuredFooter.vue.d.ts.map +1 -0
  101. package/dist/vue/components/StrandsSessionsModal.vue.d.ts +15 -0
  102. package/dist/vue/components/StrandsSessionsModal.vue.d.ts.map +1 -0
  103. package/dist/vue/components/StrandsSettingsModal.vue.d.ts +19 -0
  104. package/dist/vue/components/StrandsSettingsModal.vue.d.ts.map +1 -0
  105. package/dist/vue/components/StrandsSignIn.vue.d.ts +22 -0
  106. package/dist/vue/components/StrandsSignIn.vue.d.ts.map +1 -0
  107. package/dist/vue/components/StrandsSignUp.vue.d.ts +20 -0
  108. package/dist/vue/components/StrandsSignUp.vue.d.ts.map +1 -0
  109. package/dist/vue/components/StrandsTotpSetupModal.vue.d.ts +13 -0
  110. package/dist/vue/components/StrandsTotpSetupModal.vue.d.ts.map +1 -0
  111. package/dist/vue/components/StrandsUserButton.vue.d.ts +31 -0
  112. package/dist/vue/components/StrandsUserButton.vue.d.ts.map +1 -0
  113. package/dist/vue/components/StrandsUserProfile.vue.d.ts +27 -0
  114. package/dist/vue/components/StrandsUserProfile.vue.d.ts.map +1 -0
  115. package/dist/vue/components/SvgIcon.vue.d.ts +18 -0
  116. package/dist/vue/components/SvgIcon.vue.d.ts.map +1 -0
  117. package/dist/vue/components/VirtualList.vue.d.ts +38 -0
  118. package/dist/vue/components/VirtualList.vue.d.ts.map +1 -0
  119. package/dist/vue/components/icons/IconGithub.vue.d.ts +4 -0
  120. package/dist/vue/components/icons/IconGithub.vue.d.ts.map +1 -0
  121. package/dist/vue/components/icons/IconGoogle.vue.d.ts +4 -0
  122. package/dist/vue/components/icons/IconGoogle.vue.d.ts.map +1 -0
  123. package/dist/vue/components/icons/index.d.ts +3 -0
  124. package/dist/vue/components/icons/index.d.ts.map +1 -0
  125. package/dist/vue/components/index.d.ts +27 -0
  126. package/dist/vue/components/index.d.ts.map +1 -0
  127. package/dist/vue/composables/useAuthenticatedFetch.d.ts +21 -0
  128. package/dist/vue/composables/useAuthenticatedFetch.d.ts.map +1 -0
  129. package/dist/vue/composables/useOAuthProviders.d.ts +75 -0
  130. package/dist/vue/composables/useOAuthProviders.d.ts.map +1 -0
  131. package/dist/vue/composables/useStrandsAuth.d.ts +131 -0
  132. package/dist/vue/composables/useStrandsAuth.d.ts.map +1 -0
  133. package/dist/vue/composables/useStrandsConfig.d.ts +12 -0
  134. package/dist/vue/composables/useStrandsConfig.d.ts.map +1 -0
  135. package/dist/vue/composables/useStrandsMfa.d.ts +39 -0
  136. package/dist/vue/composables/useStrandsMfa.d.ts.map +1 -0
  137. package/dist/vue/index.d.ts +13 -0
  138. package/dist/vue/index.d.ts.map +1 -0
  139. package/dist/vue/plugins/StrandsUIPlugin.d.ts +20 -0
  140. package/dist/vue/plugins/StrandsUIPlugin.d.ts.map +1 -0
  141. package/dist/vue/ui/UiAlert.vue.d.ts +32 -0
  142. package/dist/vue/ui/UiAlert.vue.d.ts.map +1 -0
  143. package/dist/vue/ui/UiAvatarEditor.vue.d.ts +26 -0
  144. package/dist/vue/ui/UiAvatarEditor.vue.d.ts.map +1 -0
  145. package/dist/vue/ui/UiButton.vue.d.ts +55 -0
  146. package/dist/vue/ui/UiButton.vue.d.ts.map +1 -0
  147. package/dist/vue/ui/UiCard.vue.d.ts +30 -0
  148. package/dist/vue/ui/UiCard.vue.d.ts.map +1 -0
  149. package/dist/vue/ui/UiInput.vue.d.ts +49 -0
  150. package/dist/vue/ui/UiInput.vue.d.ts.map +1 -0
  151. package/dist/vue/ui/UiLevelProgress.vue.d.ts +20 -0
  152. package/dist/vue/ui/UiLevelProgress.vue.d.ts.map +1 -0
  153. package/dist/vue/ui/UiLink.vue.d.ts +43 -0
  154. package/dist/vue/ui/UiLink.vue.d.ts.map +1 -0
  155. package/dist/vue/ui/UiLoader.vue.d.ts +16 -0
  156. package/dist/vue/ui/UiLoader.vue.d.ts.map +1 -0
  157. package/dist/vue/ui/UiModal.vue.d.ts +34 -0
  158. package/dist/vue/ui/UiModal.vue.d.ts.map +1 -0
  159. package/dist/vue/ui/UiTabs.vue.d.ts +18 -0
  160. package/dist/vue/ui/UiTabs.vue.d.ts.map +1 -0
  161. package/dist/vue/ui/UiToggle.vue.d.ts +16 -0
  162. package/dist/vue/ui/UiToggle.vue.d.ts.map +1 -0
  163. package/dist/vue/ui/index.d.ts +30 -0
  164. package/dist/vue/ui/index.d.ts.map +1 -0
  165. package/dist/vue/utils/contrast.d.ts +80 -0
  166. package/dist/vue/utils/contrast.d.ts.map +1 -0
  167. package/dist/vue/utils/debounce.d.ts +13 -0
  168. package/dist/vue/utils/debounce.d.ts.map +1 -0
  169. package/dist/vue/utils/fontPreloader.d.ts +20 -0
  170. package/dist/vue/utils/fontPreloader.d.ts.map +1 -0
  171. package/dist/vue/utils/iconProps.d.ts +10 -0
  172. package/dist/vue/utils/iconProps.d.ts.map +1 -0
  173. package/dist/vue/utils/lazyComponents.d.ts +3 -0
  174. package/dist/vue/utils/lazyComponents.d.ts.map +1 -0
  175. package/dist/vue/utils/levels.d.ts +28 -0
  176. package/dist/vue/utils/levels.d.ts.map +1 -0
  177. package/dist/vue/utils/performanceInit.d.ts +41 -0
  178. package/dist/vue/utils/performanceInit.d.ts.map +1 -0
  179. package/dist/vue/utils/requestCache.d.ts +50 -0
  180. package/dist/vue/utils/requestCache.d.ts.map +1 -0
  181. package/dist/vue/utils/sounds.d.ts +57 -0
  182. package/dist/vue/utils/sounds.d.ts.map +1 -0
  183. package/package.json +1 -1
@@ -1 +1 @@
1
- {"version":3,"file":"strands-auth-ui.cjs.js","sources":["../../../apps/accounts-ui/src/vue/ui/UiAlert.vue","../../../apps/accounts-ui/src/vue/utils/contrast.ts","../../../apps/accounts-ui/src/vue/ui/UiButton.vue","../../../apps/accounts-ui/src/vue/ui/UiCard.vue","../../../apps/accounts-ui/src/vue/ui/UiInput.vue","../../../apps/accounts-ui/src/vue/ui/UiLink.vue","../../../apps/accounts-ui/src/vue/ui/UiTabs.vue","../../../apps/accounts-ui/src/vue/ui/UiLoader.vue","../../../apps/accounts-ui/assets/strands_icon_path.svg?raw","../../../apps/accounts-ui/src/vue/ui/UiToggle.vue","../../../apps/accounts-ui/src/vue/ui/UiAvatarEditor.vue","../../../apps/accounts-ui/src/vue/utils/sounds.ts","../../../apps/accounts-ui/src/vue/ui/UiLevelProgress.vue","../../../apps/accounts-ui/src/vue/ui/UiModal.vue","../../../apps/accounts-ui/src/vue/components/StrandsSecuredFooter.vue","../../../apps/accounts-ui/src/utils/slots.ts","../../../apps/accounts-ui/src/assets/secured_by_strands_services.png","../../../apps/accounts-ui/src/vue/composables/useStrandsMfa.ts","../../../apps/accounts-ui/src/vue/components/StrandsMfaVerification.vue","../../../apps/accounts-ui/src/vue/composables/useOAuthProviders.ts","../../../apps/accounts-ui/src/vue/components/StrandsAuth.vue","../../../apps/accounts-ui/src/vue/components/icons/IconGoogle.vue","../../../apps/accounts-ui/src/vue/components/icons/IconGithub.vue","../../../apps/accounts-ui/src/vue/components/StrandsSignIn.vue","../../../apps/accounts-ui/src/vue/components/StrandsSignUp.vue","../../../apps/accounts-ui/src/vue/components/StrandsCompleteSignUp.vue","../../../apps/accounts-ui/src/vue/components/StrandsTotpSetupModal.vue","../../../apps/accounts-ui/src/vue/components/StrandsEmailMfaSetupModal.vue","../../../apps/accounts-ui/src/vue/components/StrandsHardwareKeySetupModal.vue","../../../apps/accounts-ui/src/vue/components/StrandsBackupCodesModal.vue","../../../apps/accounts-ui/src/vue/components/StrandsConfirmModal.vue","../../../apps/accounts-ui/src/vue/components/StrandsMfaModal.vue","../../../apps/accounts-ui/src/vue/components/StrandsSettingsModal.vue","../../../apps/accounts-ui/src/vue/components/StrandsSessionsModal.vue","../../../apps/accounts-ui/src/vue/components/StrandsUserProfile.vue","../../../apps/accounts-ui/src/vue/components/StrandsPasswordReset.vue","../../../apps/accounts-ui/src/vue/components/SignedIn.vue","../../../apps/accounts-ui/src/vue/components/SignedOut.vue","../../../apps/accounts-ui/src/vue/components/StrandsLogo.vue","../../../apps/accounts-ui/src/vue/components/StrandsConfigProvider.vue","../../../apps/accounts-ui/src/vue/components/SvgIcon.vue","../../../apps/accounts-ui/src/vue/components/StrandsUserButton.vue","../../../apps/accounts-ui/src/vue/components/VirtualList.vue","../../../apps/accounts-ui/src/vue/components/StrandsMFASetup.vue","../../../apps/accounts-ui/src/vue/plugins/StrandsUIPlugin.ts","../../../apps/accounts-ui/src/vue/composables/useAuthenticatedFetch.ts","../../../apps/accounts-ui/src/utils/validation.ts","../../../apps/accounts-ui/src/vue/utils/lazyComponents.ts"],"sourcesContent":["<template>\n <div class=\"accui-component-scope\">\n <div :class=\"alertClasses\" role=\"alert\">\n <div class=\"alert-content\">\n <div class=\"alert-icon-container\">\n <svg class=\"alert-main-icon\" fill=\"currentColor\" viewBox=\"0 0 20 20\" aria-hidden=\"true\">\n <path fill-rule=\"evenodd\" :d=\"iconPath\" clip-rule=\"evenodd\" />\n </svg>\n </div>\n\n <div class=\"alert-text-container\">\n <h3 v-if=\"title\" :class=\"titleClasses\">{{ title }}</h3>\n <div :class=\"messageClasses\">\n <slot>{{ message }}</slot>\n </div>\n </div>\n\n <div v-if=\"dismissible\" class=\"alert-dismiss-container\">\n <button type=\"button\" class=\"alert-dismiss-button\" @click=\"$emit('dismiss')\">\n <span class=\"sr-only\">Dismiss</span>\n <svg class=\"alert-dismiss-icon\" fill=\"currentColor\" viewBox=\"0 0 20 20\">\n <path fill-rule=\"evenodd\"\n d=\"M4.293 4.293a1 1 0 011.414 0L10 8.586l4.293-4.293a1 1 0 111.414 1.414L11.414 10l4.293 4.293a1 1 0 01-1.414 1.414L10 11.414l-4.293 4.293a1 1 0 01-1.414-1.414L8.586 10 4.293 5.707a1 1 0 010-1.414z\"\n clip-rule=\"evenodd\" />\n </svg>\n </button>\n </div>\n </div>\n </div>\n </div>\n</template>\n\n<script setup lang=\"ts\">\nimport { computed } from 'vue'\n\ninterface Props {\n variant?: 'success' | 'error' | 'warning' | 'info'\n title?: string\n message?: string\n dismissible?: boolean\n}\n\nconst props = withDefaults(defineProps<Props>(), {\n variant: 'info',\n dismissible: false\n})\n\ndefineEmits<{\n dismiss: []\n}>()\n\nconst alertClasses = computed(() => {\n const variantClasses = {\n success: 'alert alert-success',\n error: 'alert alert-error',\n warning: 'alert alert-warning',\n info: 'alert alert-info'\n }\n\n return variantClasses[props.variant]\n})\n\nconst titleClasses = computed(() => {\n return 'alert-title'\n})\n\nconst messageClasses = computed(() => {\n return 'alert-message'\n})\n\n\nconst iconPath = computed(() => {\n const icons = {\n success: '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 error: 'M10 18a8 8 0 100-16 8 8 0 000 16zM8.707 7.293a1 1 0 00-1.414 1.414L8.586 10l-1.293 1.293a1 1 0 101.414 1.414L10 11.414l1.293 1.293a1 1 0 001.414-1.414L11.414 10l1.293-1.293a1 1 0 00-1.414-1.414L10 8.586 8.707 7.293z',\n warning: '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 info: 'M18 10a8 8 0 11-16 0 8 8 0 0116 0zm-7-4a1 1 0 11-2 0 1 1 0 012 0zM9 9a1 1 0 000 2v3a1 1 0 001 1h1a1 1 0 100-2v-3a1 1 0 00-1-1H9z'\n }\n\n return icons[props.variant]\n})\n</script>\n\n<style scoped>\n/* Base Alert Container */\n.alert {\n position: relative;\n padding: 1rem;\n border-radius: 0.5rem;\n border: 1px solid;\n font-family: var(--font-sans);\n box-shadow: 0 1px 3px 0 rgb(0 0 0 / 0.05);\n transition: all 0.15s ease;\n animation: alertSlideIn 0.2s ease-out;\n}\n\n.alert:hover {\n box-shadow: 0 1px 3px 0 rgb(0 0 0 / 0.08);\n}\n\n/* Alert Animation */\n@keyframes alertSlideIn {\n from {\n opacity: 0;\n transform: translateY(-4px);\n }\n to {\n opacity: 1;\n transform: translateY(0);\n }\n}\n\n/* Alert base layout styles */\n.alert-content {\n display: flex;\n align-items: flex-start;\n gap: 0.75rem;\n}\n\n.alert-icon-container {\n flex-shrink: 0;\n margin-top: 0.125rem;\n}\n\n.alert-text-container {\n flex: 1;\n min-width: 0; /* Ensure text can wrap */\n}\n\n/* Alert main icon */\n.alert-main-icon {\n width: 1.25rem;\n height: 1.25rem;\n flex-shrink: 0;\n}\n\n/* Alert typography */\n.alert-title {\n font-size: 0.875rem;\n font-weight: 600;\n margin: 0 0 0.25rem 0;\n line-height: 1.4;\n}\n\n.alert-message {\n font-size: 0.875rem;\n line-height: 1.5;\n margin: 0;\n}\n\n/* Dismiss container */\n.alert-dismiss-container {\n margin-left: auto;\n padding-left: 0.75rem;\n flex-shrink: 0;\n}\n\n/* Dismiss button */\n.alert-dismiss-button {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n border-radius: 0.375rem;\n width: 1.75rem;\n height: 1.75rem;\n background: none;\n border: none;\n cursor: pointer;\n opacity: 0.6;\n transition: all 0.15s ease;\n}\n\n.alert-dismiss-button:hover {\n opacity: 1;\n background: rgba(0, 0, 0, 0.05);\n}\n\n.alert-dismiss-button:focus-visible {\n outline: 2px solid var(--strands-500);\n outline-offset: 2px;\n opacity: 1;\n}\n\n/* Alert dismiss icon */\n.alert-dismiss-icon {\n width: 1rem;\n height: 1rem;\n flex-shrink: 0;\n}\n\n/* SUCCESS VARIANT */\n.alert-success {\n background: #f0fdf4;\n border-color: #bbf7d0;\n color: #166534;\n}\n\n.alert-success .alert-main-icon {\n color: #16a34a;\n}\n\n/* ERROR VARIANT */\n.alert-error {\n background: #fef2f2;\n border-color: #fecaca;\n color: #991b1b;\n}\n\n.alert-error .alert-main-icon {\n color: #dc2626;\n}\n\n/* WARNING VARIANT */\n.alert-warning {\n background: #fefce8;\n border-color: #fde68a;\n color: #92400e;\n}\n\n.alert-warning .alert-main-icon {\n color: #d97706;\n}\n\n/* INFO VARIANT */\n.alert-info {\n background: #eff6ff;\n border-color: #bfdbfe;\n color: #1e40af;\n}\n\n.alert-info .alert-main-icon {\n color: #2563eb;\n}\n\n/* Accessibility enhancements */\n@media (prefers-reduced-motion: reduce) {\n .alert {\n animation: none;\n transition: none;\n }\n}\n\n/* Screen reader only text */\n.sr-only {\n position: absolute;\n width: 1px;\n height: 1px;\n padding: 0;\n margin: -1px;\n overflow: hidden;\n clip: rect(0, 0, 0, 0);\n white-space: nowrap;\n border: 0;\n}\n</style>\n","/**\n * WCAG 3.0 APCA-based contrast calculation utilities\n * Provides perceptually accurate text contrast determination for accessibility\n */\n\n// APCA constants (WCAG 3.0)\nconst mainTRC = 2.4 // 2.4 exponent emulates actual monitor perception\nconst sRco = 0.2126729, sGco = 0.7151522, sBco = 0.0721750 // sRGB coefficients\nconst normBG = 0.56, normTXT = 0.57, revTXT = 0.62, revBG = 0.65 // G-4g constants\nconst blkThrs = 0.022, blkClmp = 1.414, scaleBoW = 1.14, scaleWoB = 1.14\n\n// Color map for base colors\nconst colorMap: Record<string, string> = {\n 'red': '#ef4444', 'blue': '#3b82f6', 'green': '#10b981', 'yellow': '#eab308',\n 'purple': '#8b5cf6', 'pink': '#ec4899', 'gray': '#6b7280', 'indigo': '#6366f1',\n 'orange': '#f97316', 'teal': '#14b8a6', 'cyan': '#06b6d4', 'emerald': '#10b981',\n 'lime': '#84cc16', 'amber': '#f59e0b', 'rose': '#f43f5e', 'slate': '#64748b',\n 'zinc': '#71717a', 'neutral': '#737373', 'stone': '#78716c', 'strands': '#EA00A8',\n 'primary': '#EA00A8'\n}\n\n/**\n * Convert hex color to RGB values\n */\nexport const hexToRgb = (hex: string): { r: number; g: number; b: number } | null => {\n const result = /^#?([a-f\\d]{2})([a-f\\d]{2})([a-f\\d]{2})$/i.exec(hex)\n return result ? {\n r: parseInt(result[1], 16),\n g: parseInt(result[2], 16),\n b: parseInt(result[3], 16)\n } : null\n}\n\n/**\n * APCA sRGB to Y (luminance) conversion - WCAG 3.0 method\n */\nexport const sRGBtoY = (r: number, g: number, b: number): number => {\n // Normalize to 0-1 and apply 2.4 gamma (APCA method)\n const rLin = Math.pow(r / 255, mainTRC)\n const gLin = Math.pow(g / 255, mainTRC)\n const bLin = Math.pow(b / 255, mainTRC)\n \n // Calculate Y using APCA coefficients\n let y = sRco * rLin + sGco * gLin + sBco * bLin\n \n // APCA black level adjustment\n if (y < blkThrs) {\n y += Math.pow(blkThrs - y, blkClmp)\n }\n \n return y\n}\n\n/**\n * APCA contrast calculation\n * Returns contrast value between -108 and 105\n */\nexport const calcAPCA = (txtY: number, bgY: number): number => {\n let sapc = 0\n\n // Determine polarity and calculate contrast\n if (bgY > txtY) {\n // White text on dark background\n sapc = (Math.pow(bgY, normBG) - Math.pow(txtY, normTXT)) * scaleWoB\n return (sapc * 100) < 15 ? 0 : (sapc * 100) - 15\n } else {\n // Dark text on light background \n sapc = (Math.pow(bgY, revBG) - Math.pow(txtY, revTXT)) * scaleBoW\n return (sapc * 100) > -15 ? 0 : (sapc * 100) + 15\n }\n}\n\n/**\n * Get effective RGB color considering shades and opacity modifications\n */\nexport const getEffectiveRgb = (colorProp: string): { r: number; g: number; b: number } => {\n const baseColorName = colorProp.includes('-') ? colorProp.split('-')[0] : \n colorProp.includes('/') ? colorProp.split('/')[0] : colorProp\n \n const baseColorHex = colorMap[baseColorName] || '#6b7280'\n const baseRgb = hexToRgb(baseColorHex) || { r: 107, g: 114, b: 128 }\n \n let effectiveRgb = { ...baseRgb }\n \n // Handle shade modifications\n if (colorProp.includes('-')) {\n const shade = parseInt(colorProp.split('-')[1], 10)\n if (!isNaN(shade) && shade !== 500) {\n if (shade < 500) {\n // Lighter shades - mix with white (gentle progression)\n const mixPercent = ((500 - shade) / 400) * 0.45\n effectiveRgb.r = Math.round(baseRgb.r + (255 - baseRgb.r) * mixPercent)\n effectiveRgb.g = Math.round(baseRgb.g + (255 - baseRgb.g) * mixPercent)\n effectiveRgb.b = Math.round(baseRgb.b + (255 - baseRgb.b) * mixPercent)\n } else {\n // Darker shades - mix with black (gentle progression)\n const mixPercent = ((shade - 500) / 450) * 0.45\n effectiveRgb.r = Math.round(baseRgb.r * (1 - mixPercent))\n effectiveRgb.g = Math.round(baseRgb.g * (1 - mixPercent))\n effectiveRgb.b = Math.round(baseRgb.b * (1 - mixPercent))\n }\n }\n }\n \n // Handle opacity modifications\n if (colorProp.includes('/')) {\n const opacity = parseInt(colorProp.split('/')[1], 10)\n if (!isNaN(opacity)) {\n const opacityRatio = opacity / 100\n const whiteRgb = { r: 255, g: 255, b: 255 }\n effectiveRgb.r = Math.round(effectiveRgb.r * opacityRatio + whiteRgb.r * (1 - opacityRatio))\n effectiveRgb.g = Math.round(effectiveRgb.g * opacityRatio + whiteRgb.g * (1 - opacityRatio))\n effectiveRgb.b = Math.round(effectiveRgb.b * opacityRatio + whiteRgb.b * (1 - opacityRatio))\n }\n }\n \n return effectiveRgb\n}\n\n/**\n * Calculate APCA contrast score between two colors\n * @param textColor RGB object or hex string for text color\n * @param backgroundColor RGB object or hex string for background color\n * @returns APCA contrast score (-108 to 105)\n */\nexport const getAPCAContrast = (\n textColor: { r: number; g: number; b: number } | string,\n backgroundColor: { r: number; g: number; b: number } | string\n): number => {\n const textRgb = typeof textColor === 'string' ? hexToRgb(textColor) : textColor\n const bgRgb = typeof backgroundColor === 'string' ? hexToRgb(backgroundColor) : backgroundColor\n \n if (!textRgb || !bgRgb) return 0\n \n const textY = sRGBtoY(textRgb.r, textRgb.g, textRgb.b)\n const bgY = sRGBtoY(bgRgb.r, bgRgb.g, bgRgb.b)\n \n return calcAPCA(textY, bgY)\n}\n\n/**\n * Get APCA contrast threshold based on font weight and size\n * WCAG 3.0 APCA thresholds vary based on font characteristics\n */\nexport const getAPCAThreshold = (fontWeight: number = 400, fontSize: number = 16): number => {\n // WCAG 3.0 APCA thresholds based on font weight and size\n // Higher font weights require less contrast\n \n if (fontWeight >= 700) {\n // Bold text (700+)\n if (fontSize >= 24) return 30 // Large bold text\n if (fontSize >= 18) return 35 // Medium bold text \n return 40 // Regular bold text\n } else if (fontWeight >= 600) {\n // Semi-bold text (600-699)\n if (fontSize >= 24) return 35 // Large semi-bold text\n if (fontSize >= 18) return 40 // Medium semi-bold text\n return 45 // Regular semi-bold text\n } else if (fontWeight >= 500) {\n // Medium text (500-599) - typical for buttons\n if (fontSize >= 24) return 40 // Large medium text\n if (fontSize >= 18) return 45 // Medium medium text\n return 50 // Regular medium text (buttons)\n } else {\n // Normal text (400 and below)\n if (fontSize >= 24) return 45 // Large normal text\n if (fontSize >= 18) return 50 // Medium normal text\n return 60 // Regular normal text\n }\n}\n\n/**\n * Determine optimal text color (black or white) for a given background\n * Uses WCAG 3.0 APCA algorithm for accurate contrast assessment\n * @param colorProp Color property string (e.g., 'red-500', 'blue/50')\n * @param fontWeight Font weight (300-900, default 400)\n * @param fontSize Font size in pixels (default 16)\n * @returns '#000000' for black text or '#ffffff' for white text\n */\nexport const getContrastTextColor = (\n colorProp: string, \n fontWeight: number = 400, \n fontSize: number = 16\n): string => {\n // Get background color RGB\n const bgRgb = getEffectiveRgb(colorProp)\n const bgY = sRGBtoY(bgRgb.r, bgRgb.g, bgRgb.b)\n \n // Test black text (0,0,0) and white text (255,255,255)\n const blackY = sRGBtoY(0, 0, 0)\n const whiteY = sRGBtoY(255, 255, 255)\n \n const blackContrast = Math.abs(calcAPCA(blackY, bgY))\n const whiteContrast = Math.abs(calcAPCA(whiteY, bgY))\n \n // Get appropriate threshold based on font characteristics\n const threshold = getAPCAThreshold(fontWeight, fontSize)\n \n // Choose text color based on which provides better contrast\n if (blackContrast >= threshold && whiteContrast >= threshold) {\n // Both work, choose the one with higher contrast\n return blackContrast > whiteContrast ? '#000000' : '#ffffff'\n } else if (blackContrast >= threshold) {\n return '#000000'\n } else if (whiteContrast >= threshold) {\n return '#ffffff'\n } else {\n // Neither meets ideal threshold, choose the better one\n return blackContrast > whiteContrast ? '#000000' : '#ffffff'\n }\n}\n\n/**\n * Check if a color combination meets WCAG 3.0 APCA standards\n * @param textColor Text color (RGB object or hex string)\n * @param backgroundColor Background color (RGB object or hex string)\n * @param fontWeight Font weight (300-900, default 400)\n * @param fontSize Font size in pixels (default 16)\n * @returns boolean indicating if contrast is sufficient\n */\nexport const meetsAPCAStandard = (\n textColor: { r: number; g: number; b: number } | string,\n backgroundColor: { r: number; g: number; b: number } | string,\n fontWeight: number = 400,\n fontSize: number = 16\n): boolean => {\n const contrast = Math.abs(getAPCAContrast(textColor, backgroundColor))\n const threshold = getAPCAThreshold(fontWeight, fontSize)\n \n return contrast >= threshold\n}\n\n/**\n * Generate color value from color prop (for CSS generation)\n */\nexport const getColorValue = (color: string): string => {\n // Handle color with shade (e.g., 'red-600')\n if (color.includes('-')) {\n const [colorName, shade] = color.split('-')\n const baseColor = colorMap[colorName]\n if (baseColor && shade) {\n const shadeNum = parseInt(shade, 10)\n \n // Generate proper shade variations with fallbacks\n if (shadeNum === 500) {\n return baseColor // Base color\n }\n \n // Use CSS color-mix for better browser support with fallbacks\n if (shadeNum < 500) {\n // Lighter shades - mix with white (gentle progression)\n const mixPercent = Math.round(((500 - shadeNum) / 400) * 45) // Gentler progression\n const clampedPercent = Math.min(Math.max(mixPercent, 3), 45) // Reduced extremes\n return `color-mix(in srgb, ${baseColor} ${100 - clampedPercent}%, white ${clampedPercent}%)`\n } else {\n // Darker shades - mix with black (gentle progression)\n const mixPercent = Math.round(((shadeNum - 500) / 450) * 45) // Gentler progression\n const clampedPercent = Math.min(Math.max(mixPercent, 3), 45) // Reduced extremes\n return `color-mix(in srgb, ${baseColor} ${100 - clampedPercent}%, black ${clampedPercent}%)`\n }\n }\n }\n \n // Handle color with opacity (e.g., 'red/50')\n if (color.includes('/')) {\n const [colorName, opacity] = color.split('/')\n const baseColor = colorMap[colorName] || colorName\n const opacityPercent = parseInt(opacity, 10)\n // Provide fallback for browsers without relative color support\n const fallbackColor = colorMap[colorName] || colorName\n return `light-dark(hsl(from ${baseColor} h s l / ${opacityPercent}%), color-mix(in srgb, ${fallbackColor} ${opacityPercent}%, transparent))`\n }\n \n // Return base color or fallback to CSS custom property\n return colorMap[color] || `var(--color-${color}, ${color})`\n}","<template>\n <button \n :type=\"type\" \n :disabled=\"disabled || loading\" \n :class=\"buttonClasses\" \n :style=\"buttonStyles\"\n @click=\"$emit('click', $event)\"\n >\n <span v-if=\"loading\" class=\"button-loading-content\">\n <svg class=\"button-loading-icon\" fill=\"none\" viewBox=\"0 0 24 24\">\n <circle class=\"button-loading-track\" cx=\"12\" cy=\"12\" r=\"10\" stroke=\"currentColor\" stroke-width=\"4\" />\n <path class=\"button-loading-spinner\" fill=\"currentColor\"\n d=\"m4 12a8 8 0 0 1 8-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 0 1 4 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z\" />\n </svg>\n <span>{{ loadingText || 'Loading...' }}</span>\n </span>\n <span v-else class=\"button-content\">\n <slot name=\"icon\" />\n <slot />\n </span>\n </button>\n</template>\n\n<script setup lang=\"ts\">\nimport { computed } from 'vue'\nimport { getContrastTextColor, getColorValue } from '../utils/contrast'\n\ninterface Props {\n variant?: 'primary' | 'secondary' | 'ghost' | 'outline'\n size?: 'sm' | 'md' | 'lg'\n type?: 'button' | 'submit' | 'reset'\n disabled?: boolean\n loading?: boolean\n loadingText?: string\n fullWidth?: boolean\n /** \n * Color prop supports multiple formats:\n * - Base colors: 'red', 'blue', 'green', 'strands', etc.\n * - Shades: 'red-600', 'blue-500', etc. (100-950)\n * - Opacity: 'red/50', 'blue/80', etc. (0-100)\n * Uses CSS relative color syntax for dynamic shading and opacity\n */\n color?: string\n /**\n * Font weight for the button text\n * Affects WCAG 3.0 APCA contrast calculation thresholds\n * Higher weights require less contrast\n */\n fontWeight?: 400 | 500 | 600 | 700\n}\n\nconst props = withDefaults(defineProps<Props>(), {\n variant: 'primary',\n size: 'md',\n type: 'button',\n disabled: false,\n loading: false,\n fullWidth: false,\n fontWeight: 600\n})\n\ndefineEmits<{\n click: [event: MouseEvent]\n}>()\n\n// Get hover color using color-mix for better browser support\nconst getHoverColor = (color: string): string => {\n const baseColor = getColorValue(color)\n // Use color-mix to darken by mixing with black for better browser support\n return `color-mix(in srgb, ${baseColor} 85%, black 15%)`\n}\n\n// Get hover contrast color for the darker hover state\nconst getHoverContrastColor = (color: string, fontWeight: number, fontSize: number): string => {\n // For hover state, we calculate contrast against a darker version\n const hoverColorForContrast = color.includes('-') \n ? `${color.split('-')[0]}-${Math.min(parseInt(color.split('-')[1]) + 100, 950)}` \n : `${color}-600`\n return getContrastTextColor(hoverColorForContrast, fontWeight, fontSize)\n}\n\n// Get light variant for ghost/outline hover states\nconst getLightColor = (color: string): string => {\n const baseColor = getColorValue(color)\n // Use relative color with high lightness and low opacity\n return `hsl(from ${baseColor} h s 95% / 0.8)`\n}\n\nconst buttonClasses = computed(() => {\n const classes = [\n 'ui-button',\n `ui-button-${props.variant}`,\n `ui-button-${props.size}`,\n props.fullWidth ? 'ui-button-full-width' : '',\n props.color ? 'ui-button-custom-color' : ''\n ].filter(Boolean).join(' ')\n\n return classes\n})\n\n// Get font characteristics based on button size\nconst getFontCharacteristics = (size: string) => {\n switch (size) {\n case 'sm':\n return { fontSize: 14 } // 0.875rem = 14px\n case 'lg':\n return { fontSize: 16 } // 1rem = 16px\n default: // 'md'\n return { fontSize: 14 } // 0.875rem = 14px\n }\n}\n\n// Computed styles for dynamic color support\nconst buttonStyles = computed(() => {\n if (!props.color) return {}\n \n const { fontSize } = getFontCharacteristics(props.size)\n const fontWeight = props.fontWeight || 600\n \n const primaryColor = getColorValue(props.color)\n const hoverColor = getHoverColor(props.color)\n const lightColor = getLightColor(props.color)\n const contrastColor = getContrastTextColor(props.color || 'gray', fontWeight, fontSize)\n const hoverContrastColor = getHoverContrastColor(props.color || 'gray', fontWeight, fontSize)\n \n // For secondary buttons, we need to calculate contrast against the light background\n // The light background is very light, so we'll use a much lighter version for contrast calculation\n const lightColorForContrast = `${props.color}-100` // Use the 100 shade for contrast calculation\n const lightContrastColor = getContrastTextColor(lightColorForContrast, fontWeight, fontSize)\n \n const baseStyles = {\n '--button-color': primaryColor,\n '--button-hover-color': hoverColor,\n '--button-light-color': lightColor,\n '--button-contrast-color': contrastColor,\n '--button-hover-contrast-color': hoverContrastColor,\n '--button-light-contrast-color': lightContrastColor,\n fontWeight: fontWeight\n }\n \n switch (props.variant) {\n case 'primary':\n return {\n ...baseStyles,\n backgroundColor: primaryColor,\n color: contrastColor,\n boxShadow: '0 1px 2px 0 rgb(0 0 0 / 0.05)',\n '--button-text-color': contrastColor\n }\n case 'secondary':\n return {\n ...baseStyles,\n backgroundColor: lightColor,\n color: lightContrastColor,\n border: `1px solid ${getLightColor(props.color)}`,\n '--button-text-color': lightContrastColor\n }\n case 'ghost':\n return {\n ...baseStyles,\n color: primaryColor,\n backgroundColor: 'transparent',\n '--button-text-color': primaryColor\n }\n case 'outline':\n return {\n ...baseStyles,\n borderColor: primaryColor,\n color: primaryColor,\n backgroundColor: 'transparent',\n borderWidth: '1px',\n borderStyle: 'solid',\n '--button-text-color': primaryColor\n }\n default:\n return {\n ...baseStyles,\n backgroundColor: primaryColor,\n color: contrastColor,\n '--button-text-color': contrastColor\n }\n }\n})\n</script>\n\n<style scoped>\n/* Base button styles */\n.ui-button {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n font-weight: 600;\n transition: all 0.15s ease;\n border: none;\n cursor: pointer;\n text-decoration: none;\n outline: none;\n position: relative;\n}\n\n.ui-button:focus-visible {\n outline: 2px solid var(--strands-primary, #EA00A8);\n outline-offset: 2px;\n}\n\n.ui-button:disabled {\n opacity: 0.5;\n cursor: not-allowed;\n}\n\n/* Size variants */\n.ui-button-sm {\n padding: 0.5rem 0.75rem;\n font-size: 0.875rem;\n border-radius: 0.375rem;\n}\n\n.ui-button-md {\n padding: 0.75rem 1rem;\n font-size: 0.875rem;\n border-radius: 0.5rem;\n}\n\n.ui-button-lg {\n padding: 0.75rem 1.5rem;\n font-size: 1rem;\n border-radius: 0.5rem;\n}\n\n/* Width variant */\n.ui-button-full-width {\n width: 100%;\n}\n\n/* Color variants */\n.ui-button-primary {\n background-color: #EA00A8;\n color: white;\n box-shadow: 0 1px 2px 0 rgba(0, 0, 0, 0.05);\n}\n\n.ui-button-primary:hover:not(:disabled) {\n background-color: #B8006F;\n box-shadow: 0 4px 12px 0 rgba(0, 0, 0, 0.15);\n transform: translateY(-1px);\n}\n\n.ui-button-secondary {\n background-color: #f3f4f6;\n color: #374151;\n border: 1px solid #d1d5db;\n}\n\n.ui-button-secondary:hover:not(:disabled) {\n background-color: #e5e7eb;\n border-color: #9ca3af;\n box-shadow: 0 2px 6px 0 rgba(0, 0, 0, 0.08);\n transform: translateY(-0.5px);\n}\n\n.ui-button-ghost {\n background-color: transparent;\n color: var(--strands-primary, #EA00A8);\n}\n\n.ui-button-ghost:hover:not(:disabled) {\n background-color: rgba(234, 0, 168, 0.15);\n color: #B8006F;\n transform: translateY(-0.5px);\n}\n\n.ui-button-outline {\n background-color: transparent;\n color: var(--strands-primary, #EA00A8);\n border: 1px solid var(--strands-primary, #EA00A8);\n}\n\n.ui-button-outline:hover:not(:disabled) {\n background-color: var(--strands-primary, #EA00A8);\n color: white;\n box-shadow: 0 2px 6px 0 rgba(234, 0, 168, 0.25);\n transform: translateY(-0.5px);\n}\n\n/* Custom color support with relative colors */\n.ui-button-custom-color {\n /* Styles will be applied via the style attribute using CSS custom properties */\n}\n\n.ui-button-custom-color:hover:not(:disabled) {\n background-color: var(--button-hover-color) !important;\n color: var(--button-hover-contrast-color) !important;\n box-shadow: 0 4px 8px 0 rgba(0, 0, 0, 0.12) !important;\n transform: translateY(-1px);\n}\n\n.ui-button-custom-color.ui-button-primary:hover:not(:disabled) {\n box-shadow: 0 4px 12px 0 rgba(0, 0, 0, 0.15) !important;\n}\n\n.ui-button-custom-color.ui-button-ghost:hover:not(:disabled) {\n background-color: var(--button-light-color) !important;\n color: var(--button-color) !important;\n}\n\n.ui-button-custom-color.ui-button-outline:hover:not(:disabled) {\n background-color: var(--button-color) !important;\n color: white !important;\n}\n\n.ui-button-custom-color.ui-button-secondary:hover:not(:disabled) {\n background-color: var(--button-color) !important;\n color: white !important;\n}\n\n/* Content styles */\n.button-content {\n display: flex;\n align-items: center;\n justify-content: center;\n gap: 0.5rem;\n color: inherit;\n}\n\n.button-loading-content {\n display: flex;\n align-items: center;\n justify-content: center;\n gap: 0.5rem;\n color: inherit;\n}\n\n.button-loading-icon {\n width: 1rem;\n height: 1rem;\n animation: spin 1s linear infinite;\n}\n\n.button-loading-track {\n opacity: 0.25;\n}\n\n.button-loading-spinner {\n opacity: 0.75;\n}\n\n/* Animations */\n@keyframes spin {\n from {\n transform: rotate(0deg);\n }\n to {\n transform: rotate(360deg);\n }\n}\n\n/* Active state */\n.ui-button:active:not(:disabled) {\n transform: translateY(1px);\n}\n\n/* Loading state */\n.ui-button:has(.button-loading-content) {\n position: relative;\n}\n\n/* Utility classes for compatibility */\n.ui-button.w-full {\n width: 100%;\n}\n\n.ui-button.mt-4 {\n margin-top: 1rem;\n}\n\n.ui-button.mr-2 {\n margin-right: 0.5rem;\n}\n\n.ui-button.ml-3 {\n margin-left: 0.75rem;\n}\n\n@media (min-width: 640px) {\n .ui-button.sm\\:w-auto {\n width: auto;\n }\n}\n\n/* Additional utility support */\n.ui-button.mfa-setup-method-button {\n width: 100%;\n margin-top: 1rem;\n}\n\n.ui-button.hardware-key-setup-method-button {\n width: 100%;\n margin-top: 1rem;\n}\n\n.ui-button.profile-method-button {\n width: 100%;\n margin-top: 1rem;\n}\n</style>","<template>\n <div \n class=\"ui-card\"\n :class=\"[\n `ui-card-${variant}`,\n `ui-card-padding-${padding}`,\n `ui-card-shadow-${shadow}`\n ]\">\n <div v-if=\"$slots['header']\" class=\"ui-card-header\">\n <slot name=\"header\" />\n </div>\n\n <div class=\"ui-card-content\">\n <slot />\n </div>\n\n <div v-if=\"$slots['footer']\" class=\"ui-card-footer\">\n <slot name=\"footer\" />\n </div>\n </div>\n</template>\n\n<script setup lang=\"ts\">\nimport { computed } from 'vue'\n\ninterface Props {\n variant?: 'default' | 'modern' | 'minimal' | 'clean'\n padding?: 'sm' | 'md' | 'lg'\n shadow?: 'none' | 'sm' | 'md' | 'lg'\n}\n\nconst props = withDefaults(defineProps<Props>(), {\n variant: 'default',\n padding: 'md',\n shadow: 'sm'\n})\n\n// Card styling is handled by CSS classes\n</script>\n\n<style scoped>\n.ui-card {\n background: white;\n color: black;\n border: 1px solid #e5e7eb;\n display: flex;\n flex-direction: column;\n gap: 0.75rem;\n}\n\n/* Variants */\n.ui-card-default {\n border-radius: 0.5rem;\n}\n\n.ui-card-modern {\n border-radius: 1rem;\n box-shadow: 0 10px 15px -3px rgb(0 0 0 / 0.1);\n backdrop-filter: blur(16px);\n}\n\n.ui-card-minimal {\n border-radius: 0.375rem;\n}\n\n.ui-card-clean {\n background: transparent;\n border: none;\n box-shadow: none;\n}\n\n/* Padding */\n.ui-card-padding-sm {\n padding: 1rem;\n}\n\n.ui-card-padding-md {\n padding: 1.5rem;\n}\n\n.ui-card-padding-lg {\n padding: 2rem;\n}\n\n/* Shadows */\n.ui-card-shadow-none {\n box-shadow: none;\n}\n\n.ui-card-shadow-sm {\n box-shadow: 0 1px 2px 0 rgb(0 0 0 / 0.05);\n}\n\n.ui-card-shadow-md {\n box-shadow: 0 4px 6px -1px rgb(0 0 0 / 0.1);\n}\n\n.ui-card-shadow-lg {\n box-shadow: 0 10px 15px -3px rgb(0 0 0 / 0.1);\n}\n\n/* Header and Footer */\n.ui-card-header {\n border-bottom: 1px solid #e5e7eb;\n padding-bottom: 1rem;\n}\n\n.ui-card-footer {\n border-top: 1px solid #e5e7eb;\n padding-top: 1rem;\n}\n\n.ui-card-content {\n display: flex;\n flex-direction: column;\n gap: 1.5rem;\n}\n</style>","<template>\n <div class=\"accui-component-scope\">\n <div class=\"input-container\">\n <label v-if=\"label\" :for=\"inputId\" class=\"input-label\">\n {{ label }}\n <span v-if=\"required\" class=\"input-required\">*</span>\n </label>\n\n <div class=\"input-wrapper\">\n <input :id=\"inputId\" :type=\"computedType\" :value=\"modelValue\" :placeholder=\"placeholder\" :disabled=\"disabled\"\n :required=\"required\" :autocomplete=\"autocomplete\" :name=\"name\" :inputmode=\"inputmode\" :maxlength=\"maxlength\" :class=\"inputClasses\" @input=\"handleInput\"\n @blur=\"$emit('blur', $event)\" @focus=\"$emit('focus', $event)\" @keydown=\"$emit('keydown', $event)\" />\n\n <!-- Password visibility toggle -->\n <button v-if=\"type === 'password'\" type=\"button\"\n class=\"input-password-toggle\"\n @click=\"togglePasswordVisibility\">\n <svg v-if=\"showPassword\" class=\"input-toggle-icon\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\"\n d=\"M13.875 18.825A10.05 10.05 0 0112 19c-4.478 0-8.268-2.943-9.543-7a9.97 9.97 0 011.563-3.029m5.858.908a3 3 0 114.243 4.243M9.878 9.878l4.242 4.242M9.878 9.878L3 3m6.878 6.878L21 21\" />\n </svg>\n <svg v-else class=\"input-toggle-icon\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M15 12a3 3 0 11-6 0 3 3 0 016 0z\" />\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\"\n d=\"M2.458 12C3.732 7.943 7.523 5 12 5c4.478 0 8.268 2.943 9.542 7-1.274 4.057-5.064 7-9.542 7-4.477 0-8.268-2.943-9.542-7z\" />\n </svg>\n </button>\n\n <!-- Icon slot -->\n <div v-if=\"$slots['icon']\" class=\"input-icon-container\">\n <slot name=\"icon\" />\n </div>\n </div>\n\n <!-- Help text or error message -->\n <p v-if=\"error\" class=\"input-error-text\">{{ typeof error === 'string' ? error : error.message }}</p>\n <p v-else-if=\"helpText\" class=\"input-help-text\">{{ helpText }}</p>\n </div>\n </div>\n</template>\n\n<script setup lang=\"ts\">\nimport { computed, ref, useSlots } from 'vue'\n\ninterface Props {\n modelValue?: string | number\n type?: 'text' | 'email' | 'password' | 'number' | 'tel' | 'url'\n label?: string\n placeholder?: string\n disabled?: boolean\n required?: boolean\n error?: string | { message: string }\n helpText?: string\n autocomplete?: string\n name?: string\n inputmode?: 'text' | 'numeric' | 'decimal' | 'tel' | 'search' | 'email' | 'url'\n maxlength?: number | string\n size?: 'sm' | 'md' | 'lg'\n}\n\nconst props = withDefaults(defineProps<Props>(), {\n type: 'text',\n size: 'md'\n})\n\nconst emit = defineEmits<{\n 'update:modelValue': [value: string]\n blur: [event: FocusEvent]\n focus: [event: FocusEvent]\n keydown: [event: KeyboardEvent]\n}>()\n\nconst slots = useSlots()\nconst showPassword = ref(false)\nconst inputId = ref(`input-${Math.random().toString(36).substr(2, 9)}`)\n\nconst computedType = computed(() => {\n if (props.type === 'password') {\n return showPassword.value ? 'text' : 'password'\n }\n return props.type\n})\n\nconst inputClasses = computed(() => {\n const baseClasses = [\n 'input-field'\n ]\n\n // Size classes\n const sizeClasses = {\n sm: 'input-size-sm',\n md: 'input-size-md', // default styling\n lg: 'input-size-lg'\n }\n\n // Error state\n const errorClasses = props.error\n ? 'input-error'\n : ''\n\n // Icon padding\n const iconPadding = slots['icon'] ? 'input-with-icon' : ''\n const passwordPadding = props.type === 'password' ? 'input-with-password' : ''\n\n return [\n ...baseClasses,\n sizeClasses[props.size],\n errorClasses,\n iconPadding,\n passwordPadding\n ].filter(Boolean).join(' ')\n})\n\nconst handleInput = (event: Event) => {\n const target = event.target as HTMLInputElement\n emit('update:modelValue', target.value)\n}\n\nconst togglePasswordVisibility = () => {\n showPassword.value = !showPassword.value\n}\n</script>\n\n<style scoped>\n/* Input Component Semantic CSS */\n.input-container {\n display: flex;\n flex-direction: column;\n gap: 0.25rem;\n}\n\n.input-label {\n display: block;\n font-size: 0.875rem;\n font-weight: 500;\n color: #374151;\n margin-bottom: 0.5rem;\n}\n\n.input-required {\n color: #dc2626;\n}\n\n.input-wrapper {\n position: relative;\n}\n\n.input-field {\n width: 100%;\n padding: 0.75rem 1rem;\n border: 1px solid #d1d5db;\n border-radius: 0.5rem;\n background-color: white;\n color: #111827;\n transition: border-color 0.2s ease, box-shadow 0.2s ease;\n outline: none;\n}\n\n.input-size-sm {\n padding: 0.5rem 0.75rem;\n font-size: 0.875rem;\n}\n\n.input-size-md {\n padding: 0.75rem 1rem;\n font-size: 0.875rem;\n}\n\n.input-size-lg {\n padding: 0.75rem 1rem;\n font-size: 1rem;\n}\n\n.input-error {\n border-color: #fca5a5;\n}\n\n.input-with-icon {\n padding-left: 2.5rem;\n}\n\n.input-with-password {\n padding-right: 2.5rem;\n}\n\n.input-icon-container {\n position: absolute;\n inset: 0 auto 0 0;\n padding-left: 0.75rem;\n display: flex;\n align-items: center;\n pointer-events: none;\n}\n\n.input-error-text {\n font-size: 0.875rem;\n color: #dc2626;\n}\n\n.input-help-text {\n font-size: 0.875rem;\n color: #6b7280;\n}\n\n/* \n BITWARDEN & PASSWORD MANAGER STYLE PREVENTION\n =============================================\n \n These styles use !important to prevent password managers (Bitwarden, 1Password, etc.)\n from overriding our input styling. Password managers often inject their own CSS that\n can break our design system.\n \n If you need to modify input styles, edit these CSS rules rather than just the Tailwind\n classes, as password managers may override the Tailwind classes.\n*/\n\n/* Base input styles - override password manager modifications */\ninput[type=\"email\"],\ninput[type=\"password\"],\ninput[type=\"text\"],\ninput[type=\"number\"],\ninput[type=\"tel\"],\ninput[type=\"url\"] {\n /* Force our styles to take precedence over password manager modifications */\n background-color: white !important;\n background-image: none !important;\n border: 1px solid var(--gray-300) !important;\n border-radius: var(--radius-lg) !important;\n box-shadow: var(--shadow-sm) !important;\n color: var(--gray-900) !important;\n font-family: inherit !important;\n font-size: var(--text-sm) !important;\n line-height: 1.25rem !important;\n padding: var(--space-3) var(--space-4) !important;\n transition: border-color 0.2s, box-shadow 0.2s !important;\n width: 100% !important;\n}\n\n/* Focus state overrides */\ninput[type=\"email\"]:focus,\ninput[type=\"password\"]:focus,\ninput[type=\"text\"]:focus,\ninput[type=\"number\"]:focus,\ninput[type=\"tel\"]:focus,\ninput[type=\"url\"]:focus {\n border-color: var(--strands-500) !important;\n box-shadow: 0 0 0 2px rgba(234, 0, 168, 0.25) !important;\n outline: none !important;\n}\n\n/* Error state overrides */\ninput.input-error {\n border-color: var(--red-300) !important;\n}\n\ninput.input-error:focus {\n border-color: var(--red-500) !important;\n box-shadow: 0 0 0 2px rgba(239, 68, 68, 0.2) !important;\n}\n\n/* Disabled state overrides */\ninput:disabled {\n background-color: var(--gray-50) !important;\n color: var(--gray-500) !important;\n cursor: not-allowed !important;\n}\n\n/* Bitwarden and other password manager specific overrides */\ninput[data-bwautofill],\ninput[data-lpignore],\ninput[data-form-type],\ninput[data-1p-ignore] {\n background-color: white !important;\n background-image: none !important;\n border: 1px solid rgb(209 213 219) !important;\n box-shadow: 0 1px 2px 0 rgb(0 0 0 / 0.05) !important;\n}\n\n/* Override webkit autofill styling */\ninput:-webkit-autofill,\ninput:-webkit-autofill:hover,\ninput:-webkit-autofill:focus,\ninput:-webkit-autofill:active {\n -webkit-box-shadow: 0 0 0 30px white inset !important;\n -webkit-text-fill-color: black !important;\n border: 1px solid rgb(209 213 219) !important;\n border-radius: 0.5rem !important;\n transition: background-color 5000s ease-in-out 0s !important;\n}\n\n/* Ensure password inputs have proper padding for our eye icon */\ninput[type=\"password\"] {\n padding-right: 2.5rem !important; /* pr-10 for our eye icon */\n}\n\n/* Hide browser password reveal buttons */\ninput::-ms-reveal,\ninput::-ms-clear {\n display: none !important;\n}\n\n/* Additional size-specific overrides to maintain consistency */\ninput.px-3.py-2 {\n padding: 0.5rem 0.75rem !important; /* sm size */\n}\n\ninput.px-3.py-2\\.5 {\n padding: 0.625rem 0.75rem !important; /* md size - default */\n}\n\ninput.px-4.py-3 {\n padding: 0.75rem 1rem !important; /* lg size */\n}\n\n/* Icon padding overrides */\ninput.pl-10 {\n padding-left: 2.5rem !important;\n}\n\ninput.pr-10 {\n padding-right: 2.5rem !important;\n}\n\n/* Password toggle button styling */\n.input-password-toggle {\n position: absolute;\n top: 0;\n right: 0;\n bottom: 0;\n display: flex;\n align-items: center;\n padding-right: 0.75rem;\n color: #9ca3af;\n background: none;\n border: none;\n cursor: pointer;\n border-radius: 0.375rem;\n transition: color 0.2s ease;\n}\n\n.input-password-toggle:hover {\n color: #6b7280;\n}\n\n.input-password-toggle:focus-visible {\n outline: 2px solid var(--strands-500);\n outline-offset: 2px;\n}\n\n.input-toggle-icon {\n width: 1.25rem;\n height: 1.25rem;\n flex-shrink: 0;\n}\n</style>\n","<template>\n <component :is=\"tag\" \n class=\"ui-link\"\n :class=\"[\n `ui-link-${variant}`,\n `ui-link-${size}`,\n { 'ui-link-disabled': disabled },\n { 'ui-link-custom-color': color }\n ]\"\n :style=\"linkStyles\"\n v-bind=\"linkProps\" \n @click=\"handleClick\">\n <slot />\n </component>\n</template>\n\n<script setup lang=\"ts\">\nimport { computed } from 'vue'\nimport { getContrastTextColor, getColorValue } from '../utils/contrast'\n\ninterface Props {\n href?: string\n to?: string | object\n variant?: 'primary' | 'secondary' | 'ghost' | 'underline'\n size?: 'sm' | 'md' | 'lg'\n disabled?: boolean\n external?: boolean\n /** \n * Color prop supports multiple formats (similar to UiButton):\n * - Base colors: 'red', 'blue', 'green', 'strands', etc.\n * - Shades: 'red-600', 'blue-500', etc. (100-950)\n * - Opacity: 'red/50', 'blue/80', etc. (0-100)\n */\n color?: string\n}\n\nconst props = withDefaults(defineProps<Props>(), {\n variant: 'primary',\n size: 'md',\n disabled: false,\n external: false\n})\n\nconst emit = defineEmits<{\n click: [event: MouseEvent]\n}>()\n\nconst tag = computed(() => {\n if (props.to) return 'router-link'\n if (props.href) return 'a'\n return 'button'\n})\n\nconst linkProps = computed(() => {\n const baseProps: Record<string, any> = {}\n\n if (props.to) {\n baseProps['to'] = props.to\n } else if (props.href) {\n baseProps['href'] = props.href\n if (props.external) {\n baseProps['target'] = '_blank'\n baseProps['rel'] = 'noopener noreferrer'\n }\n } else {\n baseProps['type'] = 'button'\n }\n\n if (props.disabled) {\n baseProps['disabled'] = true\n baseProps['aria-disabled'] = true\n }\n\n return baseProps\n})\n\n// Color generation is now handled by the utility\n\n// Get hover color using color-mix for better browser support\nconst getHoverColor = (color: string): string => {\n const baseColor = getColorValue(color)\n // Use color-mix to darken by mixing with black for better browser support\n return `color-mix(in srgb, ${baseColor} 85%, black 15%)`\n}\n\n// Contrast and color generation now handled by utility imports\n\n// Computed styles for dynamic color support\nconst linkStyles = computed(() => {\n if (!props.color) return {}\n \n const primaryColor = getColorValue(props.color)\n const hoverColor = getHoverColor(props.color)\n \n const baseStyles = {\n '--link-color': primaryColor,\n '--link-hover-color': hoverColor,\n color: primaryColor\n }\n \n if (props.variant === 'underline') {\n return {\n ...baseStyles,\n textDecorationColor: primaryColor\n }\n }\n \n return baseStyles\n})\n\nconst handleClick = (event: MouseEvent) => {\n if (!props.disabled) {\n emit('click', event)\n }\n}\n</script>\n\n<style scoped>\n.ui-link {\n display: inline-flex;\n align-items: center;\n font-weight: 500;\n text-decoration: none;\n transition: color 0.2s ease, text-decoration 0.2s ease;\n cursor: pointer;\n background: none;\n border: none;\n padding: 0;\n line-height: inherit;\n}\n\n.ui-link:focus-visible {\n outline: 2px solid #EA00A8;\n outline-offset: 2px;\n border-radius: 2px;\n}\n\n.ui-link-disabled {\n opacity: 0.5;\n cursor: not-allowed;\n pointer-events: none;\n}\n\n/* Sizes */\n.ui-link-sm {\n font-size: 0.75rem;\n}\n\n.ui-link-md {\n font-size: 0.875rem;\n}\n\n.ui-link-lg {\n font-size: 1rem;\n}\n\n/* Variants */\n.ui-link-primary {\n color: #EA00A8;\n background: none;\n border: none;\n padding: 0;\n}\n\n.ui-link-primary:hover {\n color: #B8006F;\n text-decoration: underline;\n text-underline-offset: 2px;\n}\n\n.ui-link-secondary {\n color: #6b7280;\n background: none;\n border: none;\n padding: 0;\n}\n\n.ui-link-secondary:hover {\n color: #1f2937;\n text-decoration: underline;\n text-underline-offset: 2px;\n}\n\n.ui-link-ghost {\n color: #6b7280;\n background: none;\n border: none;\n padding: 0;\n position: relative;\n}\n\n.ui-link-ghost:hover {\n color: #374151;\n}\n\n.ui-link-ghost::after {\n content: '';\n position: absolute;\n bottom: -2px;\n left: 0;\n width: 0;\n height: 1px;\n background-color: #374151;\n transition: width 0.3s ease;\n}\n\n.ui-link-ghost:hover::after {\n width: 100%;\n}\n\n.ui-link-underline {\n color: #EA00A8;\n text-decoration: underline;\n text-decoration-color: #EA00A8;\n text-underline-offset: 2px;\n background: none;\n border: none;\n padding: 0;\n}\n\n.ui-link-underline:hover {\n color: #B8006F;\n text-decoration-color: #B8006F;\n}\n\n/* Icon support */\n.ui-link svg {\n flex-shrink: 0;\n}\n\n/* Custom color support with relative colors */\n.ui-link-custom-color {\n color: var(--link-color);\n}\n\n.ui-link-custom-color:hover:not(.ui-link-disabled) {\n color: var(--link-hover-color);\n}\n\n.ui-link-custom-color.ui-link-underline {\n text-decoration-color: var(--link-color);\n}\n\n.ui-link-custom-color.ui-link-underline:hover:not(.ui-link-disabled) {\n text-decoration-color: var(--link-hover-color);\n}\n</style>\n","<template>\n <div class=\"tabs-container\">\n <div class=\"tabs-wrapper\">\n <!-- Tab List -->\n <div class=\"tabs-list\" role=\"tablist\">\n <button v-for=\"(tab, index) in tabs\" :key=\"tab.value\" ref=\"tabButtons\" \n class=\"tab-button\"\n :class=\"{ 'tab-button-active': modelValue === tab.value }\"\n :aria-selected=\"modelValue === tab.value\" \n :aria-controls=\"`tabpanel-${tab.value}`\" \n :id=\"`tab-${tab.value}`\"\n role=\"tab\" \n @click=\"handleTabClick(tab.value, index)\">\n {{ tab.label }}\n </button>\n\n <!-- Animated stretching underline -->\n <div class=\"tab-underline\" :style=\"underlineStyle\" />\n </div>\n </div>\n </div>\n</template>\n\n<script setup lang=\"ts\">\nimport { ref, computed, nextTick, onMounted, watch, toRefs } from 'vue'\n\ninterface Tab {\n label: string\n value: string\n}\n\ninterface Props {\n modelValue: string\n tabs: Tab[]\n}\n\ninterface Emits {\n (e: 'update:modelValue', value: string): void\n}\n\nconst props = defineProps<Props>()\nconst emit = defineEmits<Emits>()\n\nconst tabButtons = ref<HTMLElement[]>([])\nconst underlineStyle = ref({\n width: '0px',\n left: '0px',\n opacity: '0'\n})\n\nlet currentTabIndex = -1\nlet isAnimating = false\n\nconst handleTabClick = async (value: string, index: number) => {\n if (isAnimating) return\n\n emit('update:modelValue', value)\n await nextTick()\n animateUnderlineStretch(index)\n}\n\nconst animateUnderlineStretch = async (newIndex: number) => {\n if (!tabButtons.value[newIndex] || newIndex === currentTabIndex) return\n\n isAnimating = true\n const newTab = tabButtons.value[newIndex]\n const container = newTab.parentElement\n\n if (!container) return\n\n const newRect = newTab.getBoundingClientRect()\n const containerRect = container.getBoundingClientRect()\n const newLeft = newRect.left - containerRect.left\n const newWidth = newRect.width\n\n if (currentTabIndex === -1) {\n // Initial load - just appear at the new position\n underlineStyle.value = {\n width: `${newWidth}px`,\n left: `${newLeft}px`,\n opacity: '1'\n }\n currentTabIndex = newIndex\n isAnimating = false\n return\n }\n\n const currentTab = tabButtons.value[currentTabIndex]\n const currentRect = currentTab.getBoundingClientRect()\n const currentLeft = currentRect.left - containerRect.left\n const currentWidth = currentRect.width\n\n // Determine stretch direction and calculate stretch dimensions\n const isMovingRight = newIndex > currentTabIndex\n const stretchLeft = isMovingRight ? currentLeft : newLeft\n const stretchWidth = isMovingRight\n ? (newLeft + newWidth) - currentLeft\n : (currentLeft + currentWidth) - newLeft\n\n // Phase 1: Stretch to span both tabs\n underlineStyle.value = {\n width: `${stretchWidth}px`,\n left: `${stretchLeft}px`,\n opacity: '1'\n }\n\n // Phase 2: After stretch animation, contract to new position\n setTimeout(() => {\n underlineStyle.value = {\n width: `${newWidth}px`,\n left: `${newLeft}px`,\n opacity: '1'\n }\n currentTabIndex = newIndex\n setTimeout(() => {\n isAnimating = false\n }, 150) // Match the CSS transition duration\n }, 120) // Stretch duration\n}\n\n// Initialize underline position\nonMounted(async () => {\n await nextTick()\n const activeIndex = props.tabs.findIndex(tab => tab.value === props.modelValue)\n if (activeIndex !== -1) {\n animateUnderlineStretch(activeIndex)\n }\n})\n\n// Watch for external prop changes\nconst activeTabIndex = computed(() =>\n props.tabs.findIndex(tab => tab.value === props.modelValue)\n)\n\n// Update underline when active tab changes externally\nconst { modelValue } = toRefs(props)\nwatch(modelValue, async () => {\n await nextTick()\n const activeIndex = props.tabs.findIndex(tab => tab.value === props.modelValue)\n if (activeIndex !== -1) {\n animateUnderlineStretch(activeIndex)\n }\n})\n</script>\n\n<style scoped>\n.tabs-container {\n /* Container styling if needed */\n}\n\n.tabs-wrapper {\n position: relative;\n}\n\n.tabs-list {\n position: relative;\n display: flex;\n border-bottom: 1px solid #e5e7eb;\n}\n\n.tab-button {\n position: relative;\n flex: 1;\n padding: 1rem 1.5rem;\n font-weight: 500;\n font-size: 0.875rem;\n color: #6b7280;\n background: none;\n border: none;\n cursor: pointer;\n transition: color 0.15s ease;\n}\n\n.tab-button:hover {\n color: #EA00A8;\n}\n\n.tab-button:focus-visible {\n outline: none;\n color: #EA00A8;\n}\n\n.tab-button-active {\n color: #EA00A8;\n}\n\n.tab-underline {\n position: absolute;\n bottom: -3px;\n height: 5px;\n background-color: #EA00A8;\n border-radius: 9999px;\n transition: all 0.15s ease;\n}\n</style>\n","<template>\n <div class=\"loader-container\" :class=\"{ 'loader-centered': centered }\">\n <div class=\"loader-icon\">\n <!-- Simple SVG with fun animated path -->\n <svg :width=\"size\" :height=\"size\" viewBox=\"0 0 500 500\">\n <!-- Fun wavy path inspired by Strands -->\n <path\n :d=\"d\"\n fill=\"none\"\n :stroke=\"semiColor\"\n :stroke-width=\"weight\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n transform=\"translate(81, 13) scale(1.0)\"\n />\n \n <path\n :d=\"d\"\n fill=\"none\"\n :stroke=\"solidColor\"\n :stroke-width=\"weight\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n class=\"loader-animated-path\"\n transform=\"translate(81, 13) scale(1.0)\"\n />\n </svg>\n </div>\n \n <!-- Optional text -->\n <p v-if=\"text\" class=\"loader-text\" :class=\"{ [`loader-text-${variant}`]: variant !== 'auto' }\">{{ text }}</p>\n </div>\n</template>\n\n<script setup lang=\"ts\">\nimport { computed, ref } from 'vue'\n\nimport logo from '../../../assets/strands_icon_path.svg?raw'\n\nconst path = logo.replace(/<svg[^>]*>/, '').replace(/<\\/svg>/, '').trim()\nconst d = path.match(/d=\"([^\"]*)\"/)?.[1] || ''\n\ninterface Props {\n size?: number\n variant?: 'light' | 'dark' | 'auto'\n text?: string\n centered?: boolean\n weight?: number\n}\n\nconst props = withDefaults(defineProps<Props>(), {\n size: 80,\n variant: 'auto',\n centered: true,\n weight: 30,\n});\n\n// Computed colors for the loader animation\n\nconst semiColor = computed(() => \n props.variant === 'light' ? '#EA00A810'\n : props.variant === 'dark' ? '#ffffff10'\n : '#ffffff10'\n)\n\nconst solidColor = computed(() => \n props.variant === 'light' ? '#EA00A8'\n : props.variant === 'dark' ? '#ffffff'\n : '#ffffff'\n)\n</script>\n\n<style scoped>\n.loader-container {\n display: flex;\n flex-direction: column;\n align-items: center;\n gap: 1rem;\n}\n\n.loader-centered {\n justify-content: center;\n}\n\n.loader-icon {\n position: relative;\n}\n\n.loader-text {\n font-size: 0.875rem;\n font-weight: 500;\n color: #6b7280;\n}\n\n.loader-text-light {\n color: #6b7280;\n}\n\n.loader-text-dark {\n color: #d1d5db;\n}\n\n@keyframes draw-line {\n 0% {\n stroke-dasharray: 100 1000;\n stroke-dashoffset: 1000;\n }\n 100% {\n stroke-dasharray: 100 1000;\n stroke-dashoffset: -100;\n }\n}\n\n.loader-animated-path {\n animation: draw-line 0.8s linear infinite;\n}\n</style>","export default \"<svg width=\\\"302\\\" height=\\\"438\\\" viewBox=\\\"0 0 302 438\\\" fill=\\\"none\\\" xmlns=\\\"http://www.w3.org/2000/svg\\\">\\n<path d=\\\"M71.5001 96C71.5001 96 132 106 137 61.5C142 17 117.5 3.50005 94.5001 1.50003C71.5001 -0.499996 16.0001 8.5 2.00014 72.5C-6.5 130.5 71.5003 227.5 165 218C258.5 208.5 280.758 148.5 283.5 121C286.242 93.5 277.5 61.5 238.5 61.5C153 61.5 150.501 185 170.5 235C190.5 285 199 279 213 314C227.001 349 217.296 411.458 183 427C129.456 450.65 92 426 78.5 407.5C65 389 68.0003 357 94.5001 344.5C121 332 212.41 393.5 301.5 361\\\" stroke=\\\"black\\\"/>\\n</svg>\\n\"","<template>\n <button\n type=\"button\"\n :class=\"toggleClasses\"\n :aria-pressed=\"modelValue\"\n :aria-labelledby=\"id ? `${id}-label` : undefined\"\n @click=\"handleToggle\"\n >\n <span class=\"ui-toggle-thumb\" :class=\"thumbClasses\" />\n </button>\n</template>\n\n<script setup lang=\"ts\">\nimport { computed } from 'vue'\n\ninterface Props {\n modelValue?: boolean\n disabled?: boolean\n id?: string\n}\n\ninterface Emits {\n (e: 'update:modelValue', value: boolean): void\n}\n\nconst props = withDefaults(defineProps<Props>(), {\n modelValue: false,\n disabled: false\n})\n\nconst emit = defineEmits<Emits>()\n\nconst toggleClasses = computed(() => [\n 'ui-toggle',\n {\n 'ui-toggle--on': props.modelValue,\n 'ui-toggle--off': !props.modelValue,\n 'ui-toggle--disabled': props.disabled\n }\n])\n\nconst thumbClasses = computed(() => [\n {\n 'ui-toggle-thumb--on': props.modelValue,\n 'ui-toggle-thumb--off': !props.modelValue\n }\n])\n\nconst handleToggle = () => {\n if (props.disabled) return\n emit('update:modelValue', !props.modelValue)\n}\n</script>\n\n<style scoped>\n.ui-toggle {\n position: relative;\n display: inline-flex;\n align-items: center;\n width: 2.75rem;\n height: 1.5rem;\n border: 2px solid transparent;\n border-radius: 9999px;\n cursor: pointer;\n transition: all 0.2s ease-in-out;\n outline: none;\n background-color: transparent;\n padding: 0;\n}\n\n.ui-toggle:focus {\n box-shadow: 0 0 0 3px rgba(234, 0, 168, 0.2);\n}\n\n.ui-toggle--off {\n background-color: #d1d5db;\n}\n\n.ui-toggle--on {\n background-color: #ea00a8;\n}\n\n.ui-toggle--disabled {\n opacity: 0.5;\n cursor: not-allowed;\n}\n\n.ui-toggle-thumb {\n display: inline-block;\n width: 1.25rem;\n height: 1.25rem;\n background-color: white;\n border-radius: 50%;\n box-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.1), 0 1px 2px 0 rgba(0, 0, 0, 0.06);\n transition: transform 0.2s ease-in-out;\n}\n\n.ui-toggle-thumb--off {\n transform: translateX(0);\n}\n\n.ui-toggle-thumb--on {\n transform: translateX(1.25rem);\n}\n\n/* Dark mode support */\n@media (prefers-color-scheme: dark) {\n .ui-toggle--off {\n background-color: #4b5563;\n }\n \n .ui-toggle-thumb {\n background-color: #f9fafb;\n }\n}\n</style>","<template>\n <div class=\"accui-component-scope\">\n <div class=\"avatar-editor-simple\">\n <!-- Hidden file input (always available) -->\n <input\n ref=\"fileInput\"\n type=\"file\"\n accept=\"image/*\"\n class=\"hidden-input\"\n @change=\"handleFileSelect\"\n />\n \n <!-- File Upload Area -->\n <div v-if=\"!imageData\" \n class=\"upload-area\"\n @click=\"triggerFileUpload\" \n @drop=\"handleDrop\" \n @dragover.prevent \n @dragenter.prevent>\n <div class=\"upload-content\">\n <svg class=\"upload-icon\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"1.5\" \n d=\"M4 16l4.586-4.586a2 2 0 012.828 0L16 16m-2-2l1.586-1.586a2 2 0 012.828 0L20 14m-6-6h.01M6 20h12a2 2 0 002-2V6a2 2 0 00-2-2H6a2 2 0 00-2 2v12a2 2 0 002 2z\" />\n </svg>\n <h3 class=\"upload-title\">Upload your photo</h3>\n <p class=\"upload-subtitle\">Drag and drop or click to browse</p>\n <div class=\"upload-formats\">\n <span class=\"format-tag\">JPG</span>\n <span class=\"format-tag\">PNG</span>\n <span class=\"format-tag\">GIF</span>\n </div>\n </div>\n </div>\n\n <!-- Image Editor -->\n <div v-else class=\"editor-container\">\n <div class=\"editor-main\">\n <!-- Canvas with fixed circular crop -->\n <div class=\"canvas-container\">\n <canvas\n ref=\"canvas\"\n :width=\"canvasSize\"\n :height=\"canvasSize\"\n class=\"canvas\"\n @mousedown=\"startDrag\"\n @wheel=\"handleWheel\"\n />\n <!-- Fixed circular overlay -->\n <div class=\"crop-overlay\">\n <!-- Blurred backdrop overlay -->\n <div class=\"crop-backdrop\">\n <svg class=\"crop-svg\">\n <defs>\n <mask id=\"backdrop-mask\">\n <rect x=\"0\" y=\"0\" :width=\"canvasSize\" :height=\"canvasSize\" fill=\"white\" />\n <circle \n :cx=\"canvasSize / 2\" \n :cy=\"canvasSize / 2\" \n :r=\"cropRadius\" \n fill=\"black\" \n />\n </mask>\n </defs>\n <rect \n x=\"0\" \n y=\"0\" \n :width=\"canvasSize\" \n :height=\"canvasSize\" \n fill=\"black\" \n opacity=\"0.5\" \n mask=\"url(#backdrop-mask)\" \n />\n </svg>\n </div>\n <!-- Circle border -->\n <svg class=\"crop-svg\">\n <circle \n :cx=\"canvasSize / 2\" \n :cy=\"canvasSize / 2\" \n :r=\"cropRadius\" \n fill=\"none\" \n stroke=\"white\" \n stroke-width=\"2\"\n class=\"crop-circle\"\n />\n </svg>\n </div>\n </div>\n\n <!-- Simple Controls -->\n <div class=\"controls\">\n <!-- Zoom Slider -->\n <div class=\"zoom-control\">\n <button @click=\"zoom = Math.max(minZoom, zoom - 0.1); constrainImagePosition(); updateCanvas()\" \n class=\"zoom-button\">\n <svg class=\"zoom-icon\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M20 12H4\" />\n </svg>\n </button>\n <input\n type=\"range\"\n v-model.number=\"zoom\"\n :min=\"minZoom\"\n :max=\"maxZoom\"\n :step=\"0.01\"\n class=\"zoom-slider\"\n @input=\"constrainImagePosition(); updateCanvas()\"\n />\n <button @click=\"zoom = Math.min(maxZoom, zoom + 0.1); constrainImagePosition(); updateCanvas()\" \n class=\"zoom-button\">\n <svg class=\"zoom-icon\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M12 4v16m8-8H4\" />\n </svg>\n </button>\n </div>\n\n <!-- Action Buttons -->\n <div class=\"action-buttons\">\n <button @click=\"resetImage\" class=\"btn-secondary\">\n Reset\n </button>\n <button @click=\"changePhoto\" class=\"btn-secondary\">\n Change Photo\n </button>\n <button @click=\"cropAndUpload\" :disabled=\"uploading\" class=\"btn-primary\">\n {{ uploading ? 'Saving...' : 'Save Avatar' }}\n </button>\n </div>\n </div>\n </div>\n\n <!-- Preview -->\n <div class=\"preview-section\">\n <h3 class=\"preview-title\">Preview</h3>\n <div class=\"preview-container\">\n <canvas\n ref=\"previewCanvas\"\n :width=\"previewSize\"\n :height=\"previewSize\"\n class=\"preview-canvas\"\n />\n </div>\n <p class=\"preview-instructions\">\n Drag image to reposition<br>\n Scroll to zoom\n </p>\n </div>\n </div>\n </div>\n </div>\n</template>\n\n<script setup lang=\"ts\">\nimport { ref, reactive, onMounted, nextTick, watch } from 'vue'\n\ninterface Props {\n size?: number\n previewSize?: number\n maxFileSize?: number\n uploading?: boolean\n preselectedFile?: File | null\n}\n\ninterface Emits {\n (e: 'upload', file: File): void\n (e: 'error', error: string): void\n}\n\nconst props = withDefaults(defineProps<Props>(), {\n size: 300,\n previewSize: 100,\n maxFileSize: 5 * 1024 * 1024, // 5MB\n uploading: false\n})\n\nconst emit = defineEmits<Emits>()\n\n// Refs\nconst fileInput = ref<HTMLInputElement>()\nconst canvas = ref<HTMLCanvasElement>()\nconst previewCanvas = ref<HTMLCanvasElement>()\n\n// State\nconst imageData = ref<string>('')\nconst originalImage = ref<HTMLImageElement>()\nconst canvasSize = ref(props.size)\nconst previewSize = ref(props.previewSize)\nconst cropRadius = ref(props.size / 2.5) // Fixed circular crop area\n\n// Image position and zoom\nconst imagePos = reactive({ x: 0, y: 0 })\nconst zoom = ref(1)\nconst minZoom = ref(0.1)\nconst maxZoom = ref(3)\n\n// Drag state\nconst isDragging = ref(false)\nconst isResetting = ref(false)\nconst isWheelZooming = ref(false)\nconst dragStart = reactive({ x: 0, y: 0, imageX: 0, imageY: 0 })\n\nonMounted(() => {\n if (canvas.value) {\n const ctx = canvas.value.getContext('2d')\n if (ctx) {\n ctx.fillStyle = '#f9fafb'\n ctx.fillRect(0, 0, canvasSize.value, canvasSize.value)\n }\n }\n})\n\nconst triggerFileUpload = () => {\n fileInput.value?.click()\n}\n\nconst handleFileSelect = (event: Event) => {\n const target = event.target as HTMLInputElement\n const file = target.files?.[0]\n if (file) {\n processFile(file)\n }\n}\n\nconst handleDrop = (event: DragEvent) => {\n event.preventDefault()\n const file = event.dataTransfer?.files[0]\n if (file) {\n processFile(file)\n }\n}\n\nconst processFile = (file: File) => {\n // Validate file\n if (!file.type.startsWith('image/')) {\n emit('error', 'Please select an image file')\n return\n }\n\n if (file.size > props.maxFileSize) {\n emit('error', `File size must be less than ${Math.round(props.maxFileSize / 1024 / 1024)}MB`)\n return\n }\n\n // Read file\n const reader = new FileReader()\n reader.onload = (e) => {\n const result = e.target?.result as string\n loadImage(result)\n }\n reader.readAsDataURL(file)\n}\n\nconst loadImage = (dataUrl: string) => {\n imageData.value = dataUrl\n \n const img = new Image()\n img.onload = () => {\n originalImage.value = img\n \n // Disable watcher during initial load\n isResetting.value = true\n \n // Calculate initial zoom to ensure image completely fills the circular crop\n // Use the larger dimension to ensure the circle is completely filled\n const scale = Math.max(\n (cropRadius.value * 2) / img.width,\n (cropRadius.value * 2) / img.height\n )\n \n const initialZoom = scale // Start with exact scale to fill the circle\n minZoom.value = scale // Minimum zoom must fill the circle completely\n \n // Set max zoom to prevent going beyond original image size (1.0 = 100% of original)\n // But ensure we can at least fill the circle if the image is smaller than the crop area\n maxZoom.value = Math.max(1.0, scale)\n \n // Calculate and set position directly\n const scaledWidth = img.width * initialZoom\n const scaledHeight = img.height * initialZoom\n \n imagePos.x = (canvasSize.value - scaledWidth) / 2\n imagePos.y = (canvasSize.value - scaledHeight) / 2\n \n // Set the zoom\n zoom.value = initialZoom\n \n // Apply position constraints to ensure image covers the circle\n constrainImagePosition()\n \n // Re-enable watcher\n nextTick(() => {\n isResetting.value = false\n })\n \n // Update canvas\n nextTick(() => {\n updateCanvas()\n })\n }\n \n img.src = dataUrl\n}\n\nconst centerImage = () => {\n if (!originalImage.value) return\n \n const img = originalImage.value\n const scaledWidth = img.width * zoom.value\n const scaledHeight = img.height * zoom.value\n \n // Center the image to the canvas center\n imagePos.x = (canvasSize.value - scaledWidth) / 2\n imagePos.y = (canvasSize.value - scaledHeight) / 2\n \n // Apply position constraints to ensure image covers the circle\n constrainImagePosition()\n}\n\nconst updateCanvas = () => {\n if (!originalImage.value || !canvas.value) return\n \n const ctx = canvas.value.getContext('2d')\n if (!ctx) return\n \n // Clear canvas\n ctx.fillStyle = '#f9fafb'\n ctx.fillRect(0, 0, canvasSize.value, canvasSize.value)\n \n // Draw image\n const img = originalImage.value\n const scaledWidth = img.width * zoom.value\n const scaledHeight = img.height * zoom.value\n \n ctx.drawImage(img, imagePos.x, imagePos.y, scaledWidth, scaledHeight)\n \n // Update preview\n updatePreview()\n}\n\nconst updatePreview = () => {\n if (!originalImage.value || !previewCanvas.value || !canvas.value) return\n \n const previewCtx = previewCanvas.value.getContext('2d')\n if (!previewCtx) return\n \n // Clear preview\n previewCtx.fillStyle = '#ffffff'\n previewCtx.fillRect(0, 0, previewSize.value, previewSize.value)\n \n // Create circular clipping\n previewCtx.save()\n previewCtx.beginPath()\n previewCtx.arc(previewSize.value / 2, previewSize.value / 2, previewSize.value / 2, 0, Math.PI * 2)\n previewCtx.clip()\n \n // Calculate the crop area from the center of the canvas\n const cropX = canvasSize.value / 2 - cropRadius.value\n const cropY = canvasSize.value / 2 - cropRadius.value\n const cropSize = cropRadius.value * 2\n \n // Draw the cropped area to preview\n previewCtx.drawImage(\n canvas.value,\n cropX, cropY, cropSize, cropSize,\n 0, 0, previewSize.value, previewSize.value\n )\n \n previewCtx.restore()\n}\n\nconst startDrag = (event: MouseEvent) => {\n if (!originalImage.value) return\n \n isDragging.value = true\n dragStart.x = event.clientX\n dragStart.y = event.clientY\n dragStart.imageX = imagePos.x\n dragStart.imageY = imagePos.y\n \n document.addEventListener('mousemove', handleDrag)\n document.addEventListener('mouseup', stopDrag)\n}\n\nconst constrainImagePosition = () => {\n if (!originalImage.value) return\n \n const img = originalImage.value\n const scaledWidth = img.width * zoom.value\n const scaledHeight = img.height * zoom.value\n \n // Calculate the bounds to ensure the image always covers the circle\n const circleLeft = canvasSize.value / 2 - cropRadius.value\n const circleTop = canvasSize.value / 2 - cropRadius.value\n const circleRight = canvasSize.value / 2 + cropRadius.value\n const circleBottom = canvasSize.value / 2 + cropRadius.value\n \n // The image's right edge must be at least at the circle's right edge\n const maxX = circleRight - scaledWidth\n // The image's left edge must be at most at the circle's left edge\n const minX = circleLeft\n \n // The image's bottom edge must be at least at the circle's bottom edge\n const maxY = circleBottom - scaledHeight\n // The image's top edge must be at most at the circle's top edge\n const minY = circleTop\n \n // Apply constraints\n imagePos.x = Math.min(minX, Math.max(maxX, imagePos.x))\n imagePos.y = Math.min(minY, Math.max(maxY, imagePos.y))\n}\n\nconst handleDrag = (event: MouseEvent) => {\n if (!isDragging.value) return\n \n const deltaX = event.clientX - dragStart.x\n const deltaY = event.clientY - dragStart.y\n \n imagePos.x = dragStart.imageX + deltaX\n imagePos.y = dragStart.imageY + deltaY\n \n // Apply position constraints to keep image within bounds\n constrainImagePosition()\n \n updateCanvas()\n}\n\nconst stopDrag = () => {\n isDragging.value = false\n document.removeEventListener('mousemove', handleDrag)\n document.removeEventListener('mouseup', stopDrag)\n}\n\nconst handleWheel = (event: WheelEvent) => {\n event.preventDefault()\n \n const delta = event.deltaY > 0 ? -0.05 : 0.05\n const newZoom = Math.max(minZoom.value, Math.min(maxZoom.value, zoom.value + delta))\n \n if (newZoom !== zoom.value && originalImage.value) {\n // Set flag to prevent zoom watcher from interfering\n isWheelZooming.value = true\n \n // Always zoom from the center of the canvas (where the crop circle is centered)\n const img = originalImage.value\n const canvasCenter = canvasSize.value / 2\n \n // Calculate current dimensions\n const currentWidth = img.width * zoom.value\n const currentHeight = img.height * zoom.value\n \n // Calculate new dimensions\n const newWidth = img.width * newZoom\n const newHeight = img.height * newZoom\n \n // Calculate current position relative to canvas center\n const currentCenterOffsetX = (imagePos.x + currentWidth / 2) - canvasCenter\n const currentCenterOffsetY = (imagePos.y + currentHeight / 2) - canvasCenter\n \n // Scale the offset by the zoom ratio to maintain the same relative position\n const zoomRatio = newZoom / zoom.value\n const newCenterOffsetX = currentCenterOffsetX * zoomRatio\n const newCenterOffsetY = currentCenterOffsetY * zoomRatio\n \n // Calculate new position that keeps the same point under the canvas center\n imagePos.x = canvasCenter + newCenterOffsetX - newWidth / 2\n imagePos.y = canvasCenter + newCenterOffsetY - newHeight / 2\n \n zoom.value = newZoom\n \n // Apply position constraints after zoom\n constrainImagePosition()\n \n updateCanvas()\n \n // Clear flag after a short delay\n setTimeout(() => {\n isWheelZooming.value = false\n }, 16) // One frame delay\n }\n}\n\nconst resetImage = () => {\n if (!originalImage.value) return\n \n const img = originalImage.value\n \n // Disable watcher during reset\n isResetting.value = true\n \n // Reset to initial zoom that ensures the image fills the crop circle\n const scale = Math.max(\n (cropRadius.value * 2) / img.width,\n (cropRadius.value * 2) / img.height\n )\n \n const targetZoom = scale // Exact scale to fill the circle\n \n // Update zoom constraints\n minZoom.value = scale // Minimum zoom must fill the circle completely\n maxZoom.value = Math.max(1.0, scale) // Prevent going beyond original image size\n \n // Calculate and set position directly\n const scaledWidth = img.width * targetZoom\n const scaledHeight = img.height * targetZoom\n \n imagePos.x = (canvasSize.value - scaledWidth) / 2\n imagePos.y = (canvasSize.value - scaledHeight) / 2\n \n // Set the zoom\n zoom.value = targetZoom\n \n // Apply position constraints\n constrainImagePosition()\n \n // Re-enable watcher\n nextTick(() => {\n isResetting.value = false\n })\n \n updateCanvas()\n}\n\nconst cropAndUpload = async () => {\n if (!originalImage.value || !canvas.value) return\n \n // Create a new canvas for the cropped result\n const cropCanvas = document.createElement('canvas')\n cropCanvas.width = 256\n cropCanvas.height = 256\n const cropCtx = cropCanvas.getContext('2d')\n if (!cropCtx) return\n \n // White background\n cropCtx.fillStyle = '#ffffff'\n cropCtx.fillRect(0, 0, 256, 256)\n \n // Create circular clipping\n cropCtx.save()\n cropCtx.beginPath()\n cropCtx.arc(128, 128, 128, 0, Math.PI * 2)\n cropCtx.clip()\n \n // Calculate the crop area\n const cropX = canvasSize.value / 2 - cropRadius.value\n const cropY = canvasSize.value / 2 - cropRadius.value\n const cropSize = cropRadius.value * 2\n \n // Draw the cropped area\n cropCtx.drawImage(\n canvas.value,\n cropX, cropY, cropSize, cropSize,\n 0, 0, 256, 256\n )\n \n cropCtx.restore()\n \n // Convert to blob\n cropCanvas.toBlob((blob) => {\n if (blob) {\n const file = new File([blob], 'avatar.jpg', { type: 'image/jpeg' })\n emit('upload', file)\n }\n }, 'image/jpeg', 0.9)\n}\n\nconst changePhoto = () => {\n // Trigger file input to select a new photo\n triggerFileUpload()\n}\n\nconst clearImage = () => {\n imageData.value = ''\n originalImage.value = undefined\n \n // Reset all state to defaults\n zoom.value = 1\n minZoom.value = 0.1\n imagePos.x = 0\n imagePos.y = 0\n \n if (fileInput.value) {\n fileInput.value.value = ''\n }\n}\n\n// Watch zoom changes and maintain canvas center-based zoom\nwatch(zoom, (newZoom, oldZoom) => {\n if (isResetting.value || isWheelZooming.value) {\n // Skip during reset operations or wheel zooming\n return\n }\n \n if (newZoom !== oldZoom && originalImage.value && oldZoom > 0 && oldZoom !== 1) {\n // Only adjust position if this isn't the initial load (oldZoom !== 1)\n // This handles zoom changes from the slider - always zoom from canvas center\n const img = originalImage.value\n const canvasCenter = canvasSize.value / 2\n \n // Calculate current dimensions\n const oldWidth = img.width * oldZoom\n const oldHeight = img.height * oldZoom\n \n // Calculate new dimensions\n const newWidth = img.width * newZoom\n const newHeight = img.height * newZoom\n \n // Calculate current position relative to canvas center\n const currentCenterOffsetX = (imagePos.x + oldWidth / 2) - canvasCenter\n const currentCenterOffsetY = (imagePos.y + oldHeight / 2) - canvasCenter\n \n // Scale the offset by the zoom ratio to maintain the same relative position\n const zoomRatio = newZoom / oldZoom\n const newCenterOffsetX = currentCenterOffsetX * zoomRatio\n const newCenterOffsetY = currentCenterOffsetY * zoomRatio\n \n // Calculate new position that keeps the same point under the canvas center\n imagePos.x = canvasCenter + newCenterOffsetX - newWidth / 2\n imagePos.y = canvasCenter + newCenterOffsetY - newHeight / 2\n }\n \n updateCanvas()\n})\n\n// Watch for preselected file\nwatch(() => props.preselectedFile, (file) => {\n if (file) {\n processFile(file)\n }\n}, { immediate: true })\n</script>\n\n<style>\n.avatar-editor-simple {\n width: 100%;\n}\n\n/* Upload Area */\n.upload-area {\n border: 2px dashed #e5e7eb;\n border-radius: 12px;\n padding: 3rem;\n text-align: center;\n cursor: pointer;\n transition: all 0.2s;\n background: white;\n}\n\n.upload-area:hover {\n border-color: #ea00a8;\n background: #fef2f9;\n}\n\n.upload-content {\n display: flex;\n flex-direction: column;\n align-items: center;\n}\n\n.upload-icon {\n width: 3rem;\n height: 3rem;\n color: #9ca3af;\n margin-bottom: 1rem;\n}\n\n.upload-title {\n font-size: 1.125rem;\n font-weight: 600;\n color: #111827;\n margin-bottom: 0.25rem;\n}\n\n.upload-subtitle {\n font-size: 0.875rem;\n color: #6b7280;\n margin-bottom: 1rem;\n}\n\n.upload-formats {\n display: flex;\n gap: 0.5rem;\n justify-content: center;\n font-size: 0.75rem;\n color: #9ca3af;\n}\n\n.format-tag {\n padding: 0.25rem 0.5rem;\n background-color: #f3f4f6;\n border-radius: 0.25rem;\n}\n\n.hidden-input {\n display: none;\n}\n\n/* Editor Container */\n.editor-container {\n display: flex;\n gap: 2rem;\n}\n\n.editor-main {\n flex: 1;\n}\n\n/* Canvas Container */\n.canvas-container {\n position: relative;\n width: 300px;\n height: 300px;\n margin: 0 auto;\n border-radius: 12px;\n overflow: hidden;\n background: #f9fafb;\n box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1);\n}\n\n.canvas {\n display: block;\n cursor: move;\n}\n\n.crop-overlay {\n position: absolute;\n inset: 0;\n pointer-events: none;\n}\n\n.crop-backdrop {\n position: absolute;\n inset: 0;\n}\n\n.crop-svg {\n position: absolute;\n inset: 0;\n width: 100%;\n height: 100%;\n pointer-events: none;\n}\n\n.crop-circle {\n filter: drop-shadow(0 4px 3px rgba(0, 0, 0, 0.07)) drop-shadow(0 2px 2px rgba(0, 0, 0, 0.06));\n}\n\n.zoom-icon {\n width: 1rem;\n height: 1rem;\n}\n\n.preview-title {\n font-size: 0.875rem;\n font-weight: 500;\n color: #374151;\n margin-bottom: 0.75rem;\n}\n\n.preview-instructions {\n font-size: 0.75rem;\n color: #6b7280;\n margin-top: 0.75rem;\n text-align: center;\n}\n\n/* Controls */\n.controls {\n margin-top: 1.5rem;\n space-y: 1rem;\n}\n\n.zoom-control {\n display: flex;\n align-items: center;\n gap: 0.75rem;\n background: white;\n padding: 0.75rem;\n border-radius: 8px;\n border: 1px solid #e5e7eb;\n}\n\n.zoom-button {\n width: 32px;\n height: 32px;\n display: flex;\n align-items: center;\n justify-content: center;\n background: #f3f4f6;\n border: 1px solid #e5e7eb;\n border-radius: 6px;\n color: #4b5563;\n cursor: pointer;\n transition: all 0.15s;\n}\n\n.zoom-button:hover {\n background: #e5e7eb;\n color: #1f2937;\n}\n\n.zoom-slider {\n flex: 1;\n height: 6px;\n background: #e5e7eb;\n border-radius: 3px;\n outline: none;\n -webkit-appearance: none;\n}\n\n.zoom-slider::-webkit-slider-thumb {\n -webkit-appearance: none;\n width: 18px;\n height: 18px;\n background: #ea00a8;\n border: 2px solid white;\n border-radius: 50%;\n cursor: pointer;\n box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);\n}\n\n.zoom-slider::-moz-range-thumb {\n width: 18px;\n height: 18px;\n background: #ea00a8;\n border: 2px solid white;\n border-radius: 50%;\n cursor: pointer;\n box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);\n}\n\n/* Action Buttons */\n.action-buttons {\n display: flex;\n gap: 0.75rem;\n margin-top: 1rem;\n}\n\n.btn-primary,\n.btn-secondary {\n padding: 0.625rem 1.25rem;\n border-radius: 8px;\n font-size: 0.875rem;\n font-weight: 500;\n cursor: pointer;\n transition: all 0.15s;\n border: 1px solid transparent;\n}\n\n.btn-primary {\n background: #ea00a8;\n color: white;\n flex: 1;\n}\n\n.btn-primary:hover:not(:disabled) {\n background: #d10096;\n}\n\n.btn-primary:disabled {\n opacity: 0.5;\n cursor: not-allowed;\n}\n\n.btn-secondary {\n background: white;\n color: #4b5563;\n border-color: #e5e7eb;\n}\n\n.btn-secondary:hover {\n background: #f9fafb;\n color: #1f2937;\n}\n\n/* Preview Section */\n.preview-section {\n width: 150px;\n padding: 1rem;\n background: white;\n border: 1px solid #e5e7eb;\n border-radius: 12px;\n height: fit-content;\n}\n\n.preview-container {\n width: 100px;\n height: 100px;\n margin: 0 auto;\n border-radius: 50%;\n overflow: hidden;\n border: 2px solid #e5e7eb;\n background: white;\n}\n\n.preview-canvas {\n display: block;\n width: 100%;\n height: 100%;\n}\n</style>","/**\n * Sound effects utility functions using Web Audio API\n * These generate sounds programmatically without needing external audio files\n */\n\nexport class SoundEffects {\n private static audioContext: AudioContext | null = null;\n\n /**\n * Get or create a shared AudioContext\n */\n private static getAudioContext(): AudioContext | null {\n try {\n if (!this.audioContext) {\n this.audioContext = new (window.AudioContext || (window as any).webkitAudioContext)();\n }\n // Resume context if it's suspended (some browsers require user interaction)\n if (this.audioContext.state === 'suspended') {\n this.audioContext.resume();\n }\n return this.audioContext;\n } catch (error) {\n console.warn('Audio context not available:', error);\n return null;\n }\n }\n\n /**\n * Play a level up sound effect\n * A pleasant major chord with arpeggio and bell overtones\n */\n static playLevelUp(level?: number, userSettings?: any): void {\n const milestones = [10, 25, 50, 100, 150, 200];\n const isMilestone = level && milestones.includes(level);\n \n // Check user settings for audio preferences\n if (userSettings) {\n // For milestone levels, check milestone sounds setting\n if (isMilestone && userSettings.milestoneSounds === false) {\n return;\n }\n // For regular levels, check level up sounds setting\n if (!isMilestone && userSettings.levelUpSounds === false) {\n return;\n }\n }\n \n if (isMilestone) {\n this.playMilestoneLevelUp();\n } else {\n this.playRegularLevelUp();\n }\n }\n\n /**\n * Play regular level up sound for normal levels\n */\n private static playRegularLevelUp(): void {\n const audioContext = this.getAudioContext();\n if (!audioContext) return;\n\n const duration = 0.8;\n const now = audioContext.currentTime;\n \n // Create three oscillators for a pleasant C major chord\n const frequencies = [523.25, 659.25, 783.99]; // C5, E5, G5\n \n frequencies.forEach((freq, index) => {\n const oscillator = audioContext.createOscillator();\n const gainNode = audioContext.createGain();\n \n oscillator.connect(gainNode);\n gainNode.connect(audioContext.destination);\n \n // Use sine wave for a clean, pleasant sound\n oscillator.type = 'sine';\n oscillator.frequency.setValueAtTime(freq, now);\n \n // Add a slight pitch bend up for a magical effect\n oscillator.frequency.exponentialRampToValueAtTime(freq * 1.05, now + duration * 0.1);\n oscillator.frequency.exponentialRampToValueAtTime(freq * 1.02, now + duration);\n \n // Volume envelope with delay for each note (arpeggio effect)\n const delay = index * 0.05;\n gainNode.gain.setValueAtTime(0, now);\n gainNode.gain.linearRampToValueAtTime(0.15, now + delay + 0.02);\n gainNode.gain.exponentialRampToValueAtTime(0.01, now + delay + duration);\n \n oscillator.start(now + delay);\n oscillator.stop(now + delay + duration);\n });\n \n // Add a subtle bell/chime overtone\n const bellOscillator = audioContext.createOscillator();\n const bellGain = audioContext.createGain();\n \n bellOscillator.connect(bellGain);\n bellGain.connect(audioContext.destination);\n \n bellOscillator.type = 'triangle';\n bellOscillator.frequency.setValueAtTime(1046.5, now); // C6\n \n bellGain.gain.setValueAtTime(0, now);\n bellGain.gain.linearRampToValueAtTime(0.08, now + 0.01);\n bellGain.gain.exponentialRampToValueAtTime(0.001, now + 0.3);\n \n bellOscillator.start(now);\n bellOscillator.stop(now + 0.3);\n }\n\n /**\n * Play epic milestone level up sound for special levels (10, 25, 50, 100, 150, 200)\n * A longer, more elaborate celebration with multiple chord progressions\n */\n private static playMilestoneLevelUp(): void {\n const audioContext = this.getAudioContext();\n if (!audioContext) return;\n\n const now = audioContext.currentTime;\n \n // Extended duration for milestone celebration\n const totalDuration = 2.5;\n \n // First chord progression: C Major -> F Major -> G Major -> C Major\n const chordProgression = [\n { time: 0.0, frequencies: [523.25, 659.25, 783.99] }, // C Major (C5, E5, G5)\n { time: 0.4, frequencies: [587.33, 698.46, 880.00] }, // F Major (D5, F5, A5)\n { time: 0.8, frequencies: [622.25, 783.99, 987.77] }, // G Major (D#5, G5, B5)\n { time: 1.2, frequencies: [523.25, 659.25, 783.99] }, // C Major (C5, E5, G5)\n ];\n \n // Play chord progression\n chordProgression.forEach((chord, chordIndex) => {\n chord.frequencies.forEach((freq, noteIndex) => {\n const oscillator = audioContext.createOscillator();\n const gainNode = audioContext.createGain();\n \n oscillator.connect(gainNode);\n gainNode.connect(audioContext.destination);\n \n oscillator.type = 'sine';\n oscillator.frequency.setValueAtTime(freq, now + chord.time);\n \n // Add slight pitch bend for magic\n oscillator.frequency.exponentialRampToValueAtTime(freq * 1.03, now + chord.time + 0.05);\n oscillator.frequency.exponentialRampToValueAtTime(freq * 1.01, now + chord.time + 0.35);\n \n // Staggered note delays for arpeggio effect\n const noteDelay = noteIndex * 0.03;\n gainNode.gain.setValueAtTime(0, now + chord.time);\n gainNode.gain.linearRampToValueAtTime(0.12, now + chord.time + noteDelay + 0.02);\n gainNode.gain.exponentialRampToValueAtTime(0.02, now + chord.time + 0.35);\n gainNode.gain.exponentialRampToValueAtTime(0.001, now + chord.time + 0.4);\n \n oscillator.start(now + chord.time + noteDelay);\n oscillator.stop(now + chord.time + 0.45);\n });\n });\n \n // High-frequency sparkle effects throughout\n for (let i = 0; i < 8; i++) {\n const sparkleTime = now + 0.2 + (i * 0.15);\n const sparkleOsc = audioContext.createOscillator();\n const sparkleGain = audioContext.createGain();\n \n sparkleOsc.connect(sparkleGain);\n sparkleGain.connect(audioContext.destination);\n \n sparkleOsc.type = 'sine';\n const sparkleFreq = 1568 + (Math.random() * 800); // High frequencies for sparkle\n sparkleOsc.frequency.setValueAtTime(sparkleFreq, sparkleTime);\n sparkleOsc.frequency.exponentialRampToValueAtTime(sparkleFreq * 1.5, sparkleTime + 0.1);\n \n sparkleGain.gain.setValueAtTime(0, sparkleTime);\n sparkleGain.gain.linearRampToValueAtTime(0.06, sparkleTime + 0.01);\n sparkleGain.gain.exponentialRampToValueAtTime(0.001, sparkleTime + 0.12);\n \n sparkleOsc.start(sparkleTime);\n sparkleOsc.stop(sparkleTime + 0.15);\n }\n \n // Grand finale - triumphant high C chord\n const finaleTime = now + 1.6;\n const finaleFrequencies = [1046.5, 1318.5, 1567.98]; // C6, E6, G6\n \n finaleFrequencies.forEach((freq, index) => {\n const oscillator = audioContext.createOscillator();\n const gainNode = audioContext.createGain();\n \n oscillator.connect(gainNode);\n gainNode.connect(audioContext.destination);\n \n oscillator.type = 'triangle'; // Triangle wave for bell-like quality\n oscillator.frequency.setValueAtTime(freq, finaleTime);\n oscillator.frequency.exponentialRampToValueAtTime(freq * 1.02, finaleTime + 0.8);\n \n const delay = index * 0.02;\n gainNode.gain.setValueAtTime(0, finaleTime);\n gainNode.gain.linearRampToValueAtTime(0.15, finaleTime + delay + 0.03);\n gainNode.gain.exponentialRampToValueAtTime(0.001, finaleTime + 0.9);\n \n oscillator.start(finaleTime + delay);\n oscillator.stop(finaleTime + 0.95);\n });\n }\n\n /**\n * Play a success/completion sound\n * A short, bright confirmation tone\n */\n static playSuccess(): void {\n const audioContext = this.getAudioContext();\n if (!audioContext) return;\n\n const now = audioContext.currentTime;\n \n // Two quick ascending notes\n const frequencies = [659.25, 830.61]; // E5, G#5\n \n frequencies.forEach((freq, index) => {\n const oscillator = audioContext.createOscillator();\n const gainNode = audioContext.createGain();\n \n oscillator.connect(gainNode);\n gainNode.connect(audioContext.destination);\n \n oscillator.type = 'sine';\n oscillator.frequency.setValueAtTime(freq, now);\n \n const delay = index * 0.1;\n const duration = 0.15;\n \n gainNode.gain.setValueAtTime(0, now);\n gainNode.gain.linearRampToValueAtTime(0.2, now + delay + 0.01);\n gainNode.gain.exponentialRampToValueAtTime(0.01, now + delay + duration);\n \n oscillator.start(now + delay);\n oscillator.stop(now + delay + duration);\n });\n }\n\n /**\n * Play an error/failure sound\n * A low, descending tone\n */\n static playError(): void {\n const audioContext = this.getAudioContext();\n if (!audioContext) return;\n\n const now = audioContext.currentTime;\n const oscillator = audioContext.createOscillator();\n const gainNode = audioContext.createGain();\n \n oscillator.connect(gainNode);\n gainNode.connect(audioContext.destination);\n \n oscillator.type = 'sawtooth';\n oscillator.frequency.setValueAtTime(200, now);\n oscillator.frequency.exponentialRampToValueAtTime(100, now + 0.3);\n \n gainNode.gain.setValueAtTime(0.15, now);\n gainNode.gain.exponentialRampToValueAtTime(0.01, now + 0.3);\n \n oscillator.start(now);\n oscillator.stop(now + 0.3);\n }\n\n /**\n * Play a click/button press sound\n * A very short, soft click\n */\n static playClick(): void {\n const audioContext = this.getAudioContext();\n if (!audioContext) return;\n\n const now = audioContext.currentTime;\n const oscillator = audioContext.createOscillator();\n const gainNode = audioContext.createGain();\n \n oscillator.connect(gainNode);\n gainNode.connect(audioContext.destination);\n \n oscillator.type = 'sine';\n oscillator.frequency.setValueAtTime(1000, now);\n \n gainNode.gain.setValueAtTime(0.1, now);\n gainNode.gain.exponentialRampToValueAtTime(0.01, now + 0.03);\n \n oscillator.start(now);\n oscillator.stop(now + 0.03);\n }\n\n /**\n * Play a notification sound\n * A gentle two-tone chime\n */\n static playNotification(): void {\n const audioContext = this.getAudioContext();\n if (!audioContext) return;\n\n const now = audioContext.currentTime;\n const frequencies = [880, 1174.66]; // A5, D6\n \n frequencies.forEach((freq, index) => {\n const oscillator = audioContext.createOscillator();\n const gainNode = audioContext.createGain();\n \n oscillator.connect(gainNode);\n gainNode.connect(audioContext.destination);\n \n oscillator.type = 'sine';\n oscillator.frequency.setValueAtTime(freq, now);\n \n const delay = index * 0.15;\n gainNode.gain.setValueAtTime(0, now);\n gainNode.gain.linearRampToValueAtTime(0.12, now + delay + 0.02);\n gainNode.gain.exponentialRampToValueAtTime(0.01, now + delay + 0.4);\n \n oscillator.start(now + delay);\n oscillator.stop(now + delay + 0.4);\n });\n }\n\n /**\n * Play an XP gain sound\n * A quick, ascending glissando\n */\n static playXpGain(): void {\n const audioContext = this.getAudioContext();\n if (!audioContext) return;\n\n const now = audioContext.currentTime;\n const oscillator = audioContext.createOscillator();\n const gainNode = audioContext.createGain();\n \n oscillator.connect(gainNode);\n gainNode.connect(audioContext.destination);\n \n oscillator.type = 'sine';\n oscillator.frequency.setValueAtTime(440, now); // A4\n oscillator.frequency.exponentialRampToValueAtTime(880, now + 0.15); // A5\n \n gainNode.gain.setValueAtTime(0, now);\n gainNode.gain.linearRampToValueAtTime(0.15, now + 0.01);\n gainNode.gain.exponentialRampToValueAtTime(0.01, now + 0.2);\n \n oscillator.start(now);\n oscillator.stop(now + 0.2);\n }\n}\n\n// Export individual functions for convenience\nexport const playLevelUp = (level?: number, userSettings?: any) => SoundEffects.playLevelUp(level, userSettings);\nexport const playSuccess = () => SoundEffects.playSuccess();\nexport const playError = () => SoundEffects.playError();\nexport const playClick = () => SoundEffects.playClick();\nexport const playNotification = () => SoundEffects.playNotification();\nexport const playXpGain = () => SoundEffects.playXpGain();","<template>\n <div class=\"level-progress-container\">\n <svg :width=\"size\" :height=\"size\" :viewBox=\"`0 0 ${viewBox} ${viewBox}`\" style=\"position: relative;\">\n <!-- Level Up Overlay -->\n <g v-if=\"levelUpActive\">\n <circle\n :cx=\"center\"\n :cy=\"center\"\n :r=\"innerCircleRadius\"\n fill=\"#a800ff\"\n opacity=\"0.92\"\n />\n <text\n :x=\"center\"\n :y=\"center + 15\"\n text-anchor=\"middle\"\n font-size=\"38\"\n font-weight=\"bold\"\n fill=\"#fff\"\n style=\"font-family: 'Montserrat', sans-serif;\"\n >Level Up</text>\n </g>\n \n <!-- Background Arc (gray portion) -->\n <path\n v-if=\"animatedValue >= 0 && animatedValue < props.max\"\n :d=\"backgroundArcPath\"\n stroke=\"#ddd\"\n :stroke-width=\"thickness\"\n fill=\"none\"\n stroke-linecap=\"round\"\n />\n \n <!-- Label Arc (top, thicker) -->\n <path\n :d=\"staticArcPath\"\n :stroke=\"staticArcGradient\"\n :stroke-width=\"labelThickness\"\n fill=\"none\"\n stroke-linecap=\"round\"\n />\n \n <!-- Invisible arc for curved label text -->\n <path\n :id=\"'labelTextArc'\"\n :d=\"labelTextArcPath\"\n stroke=\"transparent\"\n fill=\"none\"\n transform=\"scale(-1, 1) translate(-400, 0)\"\n />\n \n <!-- Progress Arc (XP bar) -->\n <path\n v-if=\"animatedValue > 0 && animatedValue < props.max\"\n :d=\"progressArcPath\"\n :stroke=\"progressArcGradient\"\n :stroke-width=\"thickness\"\n fill=\"none\"\n stroke-linecap=\"round\"\n />\n \n <!-- Curved Label Text -->\n <text \n font-size=\"30\" \n font-weight=\"bold\" \n fill=\"var(--purple-100)\" \n style=\"font-family: 'Montserrat', sans-serif; letter-spacing: 8px;\"\n >\n <textPath\n xlink:href=\"#labelTextArc\"\n startOffset=\"50%\"\n text-anchor=\"middle\"\n alignment-baseline=\"hanging\"\n dominant-baseline=\"hanging\"\n text-length=\"100%\"\n >\n {{ levelLabel }}\n </textPath>\n </text>\n \n <!-- Gradient Definitions -->\n <defs>\n <linearGradient id=\"staticGradient\" x1=\"0\" y1=\"0\" x2=\"1\" y2=\"0\">\n <stop offset=\"0%\" stop-color=\"var(--strands-500)\" />\n <stop offset=\"100%\" stop-color=\"var(--strands-600)\" />\n </linearGradient>\n\n <linearGradient \n id=\"progressGradient\" \n gradientUnits=\"userSpaceOnUse\" \n :x1=\"progressGradientStart.x\" \n :y1=\"progressGradientStart.y\" \n :x2=\"progressGradientEnd.x\" \n :y2=\"progressGradientEnd.y\"\n >\n <stop offset=\"0%\" stop-color=\"var(--strands-600)\" />\n <stop offset=\"100%\" stop-color=\"var(--strands-400)\" />\n </linearGradient>\n </defs>\n </svg>\n </div>\n</template>\n\n<script setup lang=\"ts\">\nimport { computed, ref, watch } from 'vue';\nimport { playLevelUp } from '../utils/sounds';\n\n// ============================================================================\n// Props & Emits\n// ============================================================================\nconst props = defineProps<{\n value: number;\n max: number;\n level: number;\n levelLabel?: string;\n size?: number;\n thickness?: number;\n labelThickness?: number;\n staticArcAngle?: number;\n gapAngle?: number;\n userSettings?: any;\n}>();\n\nconst emit = defineEmits(['levelup']);\n\n// ============================================================================\n// Constants & Configuration\n// ============================================================================\nconst VIEW_BOX_SIZE = 400;\nconst ARC_PADDING = 18; // Extra space from edge\nconst INNER_GAP = 18; // Gap between progress ring and inner circle\nconst ANIMATION_DURATION = 600; // ms\n\n// Label arc configuration\nconst LABEL_SPACING = 8; // px, matches letter-spacing in template\nconst LABEL_FONT_SIZE = 30; // px, matches font-size in template\nconst LABEL_EXTRA_DEGREES = 12; // Extra spacing in degrees\nconst LABEL_CHAR_DEGREES = 8; // Degrees per character\n\n// ============================================================================\n// Component State\n// ============================================================================\nconst levelUpActive = ref(false);\nconst animatedValue = ref(props.value);\nconst animationDirection = ref<'forward' | 'backward'>('forward');\nlet animationFrame: number | null = null;\nlet prevValue = props.value;\nlet prevLevel = props.level;\n\n// ============================================================================\n// Computed Properties - Dimensions\n// ============================================================================\nconst viewBox = VIEW_BOX_SIZE;\nconst size = props.size ?? VIEW_BOX_SIZE;\nconst center = VIEW_BOX_SIZE / 2;\nconst thickness = computed(() => props.thickness ?? 24);\nconst labelThickness = computed(() => props.labelThickness ?? 46);\nconst gapAngle = computed(() => props.gapAngle ?? 16);\n\n// Radius calculations\nconst radius = computed(() => (VIEW_BOX_SIZE - thickness.value) / 2 - ARC_PADDING);\nconst labelRadius = computed(() => (VIEW_BOX_SIZE - labelThickness.value) / 1.9 - ARC_PADDING);\nconst textLabelRadius = computed(() => labelRadius.value + 10);\nconst innerCircleRadius = computed(() => radius.value - thickness.value / 2 - INNER_GAP);\n\n// ============================================================================\n// Computed Properties - Arc Angles\n// ============================================================================\nconst labelLength = computed(() => props.levelLabel?.length ?? 0);\nconst staticArcAngle = computed(() => {\n // Estimate arc angle needed for label\n return labelLength.value * LABEL_CHAR_DEGREES + LABEL_EXTRA_DEGREES;\n});\n\nconst labelStart = computed(() => -staticArcAngle.value / 2);\nconst labelEnd = computed(() => staticArcAngle.value / 2);\n\n// ============================================================================\n// Computed Properties - Arc Paths\n// ============================================================================\nconst staticArcPath = computed(() =>\n describeArc(center, center, labelRadius.value, labelStart.value, labelEnd.value)\n);\n\nconst labelTextArcPath = computed(() =>\n // Top arc: right to left, so text is right-side up at the top after rotation\n describeArc(center, center, textLabelRadius.value, -90, 90)\n);\n\nconst progressArcPath = computed(() => {\n const xpArcStart = labelEnd.value + gapAngle.value;\n const availableSweep = 360 - staticArcAngle.value - 3 * gapAngle.value;\n const progress = Math.max(0, Math.min(1, animatedValue.value / props.max));\n const xpArcSweep = availableSweep * progress;\n const xpArcEnd = xpArcStart + xpArcSweep;\n return describeArc(center, center, radius.value, xpArcStart, xpArcEnd);\n});\n\nconst backgroundArcPath = computed(() => {\n const xpArcStart = labelEnd.value + gapAngle.value;\n const availableSweep = 360 - staticArcAngle.value - 3 * gapAngle.value;\n const progress = Math.max(0, Math.min(1, animatedValue.value / props.max));\n const xpArcSweep = availableSweep * progress;\n const xpArcEnd = xpArcStart + xpArcSweep;\n const grayArcStart = progress === 0 ? xpArcStart : xpArcEnd + gapAngle.value;\n const grayArcEnd = labelStart.value - gapAngle.value + 360;\n return describeArc(center, center, radius.value, grayArcStart, grayArcEnd);\n});\n\n// ============================================================================\n// Computed Properties - Gradients\n// ============================================================================\nconst staticArcGradient = computed(() => 'url(#staticGradient)');\nconst progressArcGradient = computed(() => 'url(#progressGradient)');\n\nconst progressGradientStart = computed(() => {\n const xpArcStart = labelEnd.value + gapAngle.value;\n return polarToCartesian(center, center, radius.value, xpArcStart);\n});\n\nconst progressGradientEnd = computed(() => {\n const xpArcStart = labelEnd.value + gapAngle.value;\n const availableSweep = 360 - staticArcAngle.value - 3 * gapAngle.value;\n const progress = Math.max(0, Math.min(1, animatedValue.value / props.max));\n const xpArcSweep = availableSweep * progress;\n const xpArcEnd = xpArcStart + xpArcSweep;\n return polarToCartesian(center, center, radius.value, xpArcEnd);\n});\n\n// ============================================================================\n// Helper Functions\n// ============================================================================\nfunction polarToCartesian(cx: number, cy: number, r: number, angle: number) {\n const rad = (angle - 90) * Math.PI / 180.0;\n return {\n x: cx + r * Math.cos(rad),\n y: cy + r * Math.sin(rad),\n };\n}\n\nfunction describeArc(cx: number, cy: number, r: number, startAngle: number, endAngle: number) {\n const start = polarToCartesian(cx, cy, r, endAngle % 360);\n const end = polarToCartesian(cx, cy, r, startAngle % 360);\n const sweep = ((endAngle - startAngle + 360) % 360);\n const largeArcFlag = sweep <= 180 ? '0' : '1';\n return [\n 'M', start.x, start.y,\n 'A', r, r, 0, largeArcFlag, 0, end.x, end.y\n ].join(' ');\n}\n\nfunction easeInOut(t: number) {\n return t < 0.5 ? 2 * t * t : -1 + (4 - 2 * t) * t;\n}\n\n// ============================================================================\n// Animation Functions\n// ============================================================================\nfunction animateProgress(newValue: number, oldValue: number) {\n if (animationFrame) cancelAnimationFrame(animationFrame);\n \n const start = oldValue;\n const change = newValue - start;\n const startTime = performance.now();\n \n function step(now: number) {\n const elapsed = now - startTime;\n const t = Math.min(elapsed / ANIMATION_DURATION, 1);\n const eased = easeInOut(t);\n animatedValue.value = start + change * eased;\n \n if (t < 1) {\n animationFrame = requestAnimationFrame(step);\n } else {\n animatedValue.value = newValue;\n animationFrame = null;\n }\n }\n \n animationFrame = requestAnimationFrame(step);\n}\n\nfunction triggerLevelUp() {\n levelUpActive.value = true;\n playLevelUp(props.level, props.userSettings);\n emit('levelup');\n \n // Check if this is a milestone level for longer display\n const milestones = [10, 25, 50, 100, 150, 200];\n const isMilestone = milestones.includes(props.level);\n \n setTimeout(() => {\n levelUpActive.value = false;\n }, isMilestone ? 2000 : 1200);\n}\n\n// ============================================================================\n// Watchers\n// ============================================================================\nwatch(() => props.value, (newValue) => {\n animationDirection.value = newValue >= prevValue ? 'forward' : 'backward';\n animateProgress(newValue, prevValue);\n prevValue = newValue;\n});\n\nwatch(() => props.level, (newLevel) => {\n if (newLevel !== prevLevel && newLevel > prevLevel) {\n triggerLevelUp();\n }\n prevLevel = newLevel;\n});\n</script>\n\n<style scoped>\n.level-progress-container {\n display: flex;\n align-items: center;\n justify-content: center;\n padding: 12px;\n}\n</style>","<template>\n <div class=\"accui-component-scope\">\n\t<teleport to=\"body\">\n\t\t<div v-if=\"open\" class=\"modal-overlay\" @click=\"handleOverlayClick\">\n\t\t\t<div \n\t\t\t\tclass=\"modal-container\" \n\t\t\t\t:class=\"{ 'modal-container-fullscreen-mobile': fullscreenOnMobile }\"\n\t\t\t\t@click.stop\n\t\t\t>\n\t\t\t\t<div class=\"modal-card\">\n\t\t\t\t\t<div v-if=\"$slots['header']\" class=\"modal-header\">\n\t\t\t\t\t\t<slot name=\"header\" />\n\t\t\t\t\t</div>\n\t\t\t\t\t\n\t\t\t\t\t<div class=\"modal-content\">\n\t\t\t\t\t\t<slot />\n\t\t\t\t\t</div>\n\t\t\t\t\t\n\t\t\t\t\t<div v-if=\"$slots['footer']\" class=\"modal-footer\">\n\t\t\t\t\t\t<slot name=\"footer\" />\n\t\t\t\t\t</div>\n\t\t\t\t</div>\n\t\t\t</div>\n\t\t</div>\n\t</teleport>\n </div>\n</template>\n\n<script setup lang=\"ts\">\ninterface Props {\n\topen?: boolean\n\tcloseOnOverlayClick?: boolean\n\tfullscreenOnMobile?: boolean\n}\n\nconst props = withDefaults(defineProps<Props>(), {\n\topen: false,\n\tcloseOnOverlayClick: true,\n\tfullscreenOnMobile: true\n})\n\nconst emit = defineEmits<{\n\tclose: []\n}>()\n\nconst handleOverlayClick = () => {\n\tif (props.closeOnOverlayClick) {\n\t\temit('close')\n\t}\n}\n</script>\n\n<style scoped>\n.modal-overlay {\n\tposition: fixed;\n\ttop: 0;\n\tleft: 0;\n\tright: 0;\n\tbottom: 0;\n\tbackground: rgba(0, 0, 0, 0.8);\n\tdisplay: flex;\n\talign-items: center;\n\tjustify-content: center;\n\tpadding: 1rem;\n\tz-index: 9999999999;\n\tfont-family: var(--font-sans);\n\t-webkit-font-smoothing: antialiased;\n}\n\n.modal-container {\n\tbackground: white;\n\tborder-radius: 0.5rem;\n\tbox-shadow: 0 25px 50px -12px rgba(0, 0, 0, 0.25);\n\tpadding: 1.5rem;\n\tmax-width: calc(100vw - 2rem);\n\tmax-height: calc(100vh - 2rem);\n\toverflow-y: auto;\n\twidth: auto;\n}\n\n.modal-header {\n\tpadding-bottom: 1rem;\n\tborder-bottom: 1px solid #e5e7eb;\n\tmargin-bottom: 1.5rem;\n}\n\n.modal-footer {\n\tpadding-top: 1rem;\n\tborder-top: 1px solid #e5e7eb;\n\tmargin-top: 1.5rem;\n}\n\n/* Fullscreen on mobile */\n@media (max-width: 768px) {\n\t.modal-container-fullscreen-mobile {\n\t\twidth: 100vw;\n\t\theight: 100vh;\n\t\tmax-width: 100vw;\n\t\tmax-height: 100vh;\n\t\tborder-radius: 0;\n\t\tpadding: 1rem;\n\t}\n}\n\n/* Scrollbar styling */\n.modal-container::-webkit-scrollbar {\n\twidth: 6px;\n}\n\n.modal-container::-webkit-scrollbar-track {\n\tbackground: #f1f5f9;\n\tborder-radius: 3px;\n}\n\n.modal-container::-webkit-scrollbar-thumb {\n\tbackground: #cbd5e1;\n\tborder-radius: 3px;\n}\n\n.modal-container::-webkit-scrollbar-thumb:hover {\n\tbackground: #94a3b8;\n}\n</style>","<template>\n <div class=\"accui-component-scope\">\n <div v-if=\"shouldShowSecuredBy\"\n class=\"secured-footer\"\n :class=\"{ 'secured-footer-with-content': hasDefaultSlot, 'secured-footer-centered': !hasDefaultSlot }\">\n <slot name=\"default\" />\n\n <!-- Secured by logo - Right side when sign out present, center when alone -->\n <div v-if=\"shouldShowSecuredBy\" class=\"secured-logo\">\n <img :src=\"securedByLogo\" class=\"secured-logo-image\" />\n </div>\n </div>\n </div>\n</template>\n\n<script setup lang=\"ts\">\nimport { computed, useSlots } from 'vue'\nimport { useStrandsConfig, type StrandsAuthConfig } from '../composables/useStrandsConfig'\nimport { slotHasContent } from '../../utils/slots'\nimport securedByLogo from '@/assets/secured_by_strands_services.png'\n\ninterface Props {\n config?: StrandsAuthConfig\n}\n\nconst props = withDefaults(defineProps<Props>(), {})\n\n// Get configuration\nconst { config } = useStrandsConfig(props.config)\n\n// Hide \"Secured by\" logo when using Strands' own domain\nconst shouldShowSecuredBy = computed(() => {\n const baseUrl = config.value.baseUrl\n return baseUrl !== 'https://accounts.strands.gg'\n})\n\nconst slots = useSlots()\nconst hasDefaultSlot = computed(() => slotHasContent('default', slots))\n</script>\n\n<style scoped>\n.secured-footer {\n display: flex;\n align-items: center;\n gap: 0.5rem;\n padding-top: 1rem;\n border-top: 1px solid #e5e7eb;\n}\n\n.secured-footer-with-content {\n justify-content: space-between;\n}\n\n.secured-footer-centered {\n justify-content: center;\n}\n\n.secured-logo {\n flex-shrink: 0;\n}\n\n.secured-logo-image {\n height: 2rem;\n}\n</style>","export const slotHasContent = (slotName: string, slots: any) => {\n const slot = slots[slotName];\n if (!slot) return false;\n if (typeof slot === 'function') {\n const vnodes = slot();\n return Array.isArray(vnodes) && vnodes.length > 0;\n }\n return Array.isArray(slot) && slot.length > 0;\n};","export default \"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAABVgAAAHgCAYAAABQLAbaAAAEt2lUWHRYTUw6Y29tLmFkb2JlLnhtcAAAAAAAPD94cGFja2V0IGJlZ2luPSLvu78iIGlkPSJXNU0wTXBDZWhpSHpyZVN6TlRjemtjOWQiPz4KPHg6eG1wbWV0YSB4bWxuczp4PSJhZG9iZTpuczptZXRhLyIgeDp4bXB0az0iWE1QIENvcmUgNS41LjAiPgogPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4KICA8cmRmOkRlc2NyaXB0aW9uIHJkZjphYm91dD0iIgogICAgeG1sbnM6dGlmZj0iaHR0cDovL25zLmFkb2JlLmNvbS90aWZmLzEuMC8iCiAgICB4bWxuczpleGlmPSJodHRwOi8vbnMuYWRvYmUuY29tL2V4aWYvMS4wLyIKICAgIHhtbG5zOnBob3Rvc2hvcD0iaHR0cDovL25zLmFkb2JlLmNvbS9waG90b3Nob3AvMS4wLyIKICAgIHhtbG5zOnhtcD0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wLyIKICAgIHhtbG5zOnhtcE1NPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvbW0vIgogICAgeG1sbnM6c3RFdnQ9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZUV2ZW50IyIKICAgdGlmZjpJbWFnZUxlbmd0aD0iNDgwIgogICB0aWZmOkltYWdlV2lkdGg9IjEzNjgiCiAgIHRpZmY6UmVzb2x1dGlvblVuaXQ9IjIiCiAgIHRpZmY6WFJlc29sdXRpb249IjcyLzEiCiAgIHRpZmY6WVJlc29sdXRpb249IjcyLzEiCiAgIGV4aWY6UGl4ZWxYRGltZW5zaW9uPSIxMzY4IgogICBleGlmOlBpeGVsWURpbWVuc2lvbj0iNDgwIgogICBleGlmOkNvbG9yU3BhY2U9IjEiCiAgIHBob3Rvc2hvcDpDb2xvck1vZGU9IjMiCiAgIHBob3Rvc2hvcDpJQ0NQcm9maWxlPSJzUkdCIElFQzYxOTY2LTIuMSIKICAgeG1wOk1vZGlmeURhdGU9IjIw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rYdCFBEBYXQHawB8r7uGOCph1YlP9yoKH2PS1V0EEREREREREZlFW8B6BZN5xLgbTELOcR5rdATEp7prOIeru4A4qiAxjZh0rwYAxwMQERERERER0Xu0BawAUIWc0vn4nZIQ66UY7G7fDSSk0R2sYMDasnr36ozuOpqVhNzQXQMRERERERERmUdrwFpfbrv4/7N3P8lNJGvb/79Z5l/E+/ziyBEHA6MuVoBYAWIF2JPGGiFWgFmBzQqAFWBGkj2xWYHFClCvgOoRjdwd0om3z/NiZFX+BlUC4baxZEvKzKrrE8HpPnRj3w1SqerKO+90WcMlVQaYPR16tRCx6wJ+5gomcV1DaAaYN65rmEI/77oXEREREREREfmB04AV4CrXt4C+6zouoTrg6KXrIkogdl3Az1jSkF/DC9el2QBqjsuYhrpXRURERERERORUzgPWZdb6KYR84BVAQ4delduxRgRMrEczNpigFiUizDvXNYiIiIiIiIiIn4zrAka6tA4Iq6PtH1J4fpv1V67rKJpPNOMlzEfXdfzMCuvevJd816X1Aai6rmMK/RXWl10XISIiIiIiIiJ+ct7BOmKwoXexEsHLQ5o113UUzRXPxwMQ9oiLhco7vUMKV0HjAURERERERETkJ7wJWPMDZEI+8AoAi9nr0Yxd1yELlbguIASHNGsWu+W6jmkZ7FvXNYiIiIiIiIiIv7wJWKEQB14BVAaYA4Wss2OIKq5rOEfor9m569GMLeaN6zouIMkXf0RERERERERETuVVwLrMWj/CPHVdxwzECllnJyX1OmBN4T+ua/BZj73KAHOA/6MeThH+6BIRERERERERmS+vAlaAf/N4H2i7rmMG8pB1z+twMAQG4/XvYQQ91zX47JivbwgyXIVhMa5FIiIiIiIiIjJH3gWsAEPsU4qx7ToecKSQ9ZJSrNe/fxb7u+safHXIzkuLXXVdxwVt36GeuC5CRERERERERPzmZcB6h3qSQlG25lYVskoZHbKzabEbruu4qKHGA4iIiIiIiIjIBLwMWAFus/6K4mzPVch6Cb6PCLCYInRbz1Qerm65ruMS2upeFREREREREZFJeBuwQqFGBYBC1guzno8IiLBFeY3ORAHCVYy6V0VERERERERkQl4HrAUbFQAKWaXgihCuAu2b1NuuixARERERERGRMHgdsEI2KsBg9l3XMUPV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\"","import { ref, computed } from 'vue'\nimport type { \n MfaDevice, \n MfaDevicesResponse, \n TotpSetupResponse, \n BackupCodesResponse \n} from '../../types'\nimport { useStrandsConfig } from './useStrandsConfig'\nimport { useStrandsAuth } from './useStrandsAuth'\n\nconst mfaDevices = ref<MfaDevice[]>([])\nconst mfaEnabled = ref(false)\nconst loading = ref(false)\n\nexport function useStrandsMfa() {\n const { getUrl } = useStrandsConfig()\n const { currentSession } = useStrandsAuth()\n\n const hasMfaDevices = computed(() => mfaDevices.value.length > 0)\n // Filter out hardware keys and passkeys temporarily until cross-domain support is implemented\n const activeMfaDevices = computed(() => \n mfaDevices.value.filter(d => \n d.is_active && \n d.device_type !== 'hardware' && \n d.device_type !== 'passkey'\n )\n )\n\n // Helper function to make authenticated requests\n const makeAuthenticatedRequest = async (url: string, options: RequestInit = {}) => {\n if (!currentSession.value?.accessToken) {\n throw new Error('No access token available')\n }\n\n const response = await fetch(url, {\n ...options,\n headers: {\n 'Content-Type': 'application/json',\n 'Authorization': `Bearer ${currentSession.value.accessToken}`,\n ...options.headers,\n },\n })\n\n if (!response.ok) {\n const errorText = await response.text()\n let errorMessage = `Request failed: ${response.status} ${response.statusText}`\n \n try {\n const errorData = JSON.parse(errorText)\n errorMessage = errorData.message || errorMessage\n } catch {\n // If parsing fails, use the original error text\n if (errorText) {\n errorMessage = errorText\n }\n }\n \n throw new Error(errorMessage)\n }\n\n return response.json()\n }\n\n // Get all MFA devices for the user\n const fetchMfaDevices = async (): Promise<MfaDevicesResponse> => {\n loading.value = true\n try {\n const response = await makeAuthenticatedRequest(getUrl('mfaDevices'), {\n method: 'GET',\n })\n\n mfaDevices.value = response.devices || []\n mfaEnabled.value = response.mfa_enabled || false\n\n return response\n } finally {\n loading.value = false\n }\n }\n\n // Setup TOTP (authenticator app)\n const setupTotp = async (deviceName: string): Promise<TotpSetupResponse> => {\n loading.value = true\n try {\n const response = await makeAuthenticatedRequest(getUrl('mfaTotpSetup'), {\n method: 'POST',\n body: JSON.stringify({ device_name: deviceName }),\n })\n\n // Refresh devices list\n await fetchMfaDevices()\n\n return response\n } finally {\n loading.value = false\n }\n }\n\n // Verify TOTP setup\n const verifyTotpSetup = async (deviceId: string, totpCode: string): Promise<void> => {\n loading.value = true\n try {\n await makeAuthenticatedRequest(getUrl('mfaTotpVerify'), {\n method: 'POST',\n body: JSON.stringify({\n device_id: deviceId,\n totp_code: totpCode,\n }),\n })\n\n // Refresh devices list\n await fetchMfaDevices()\n } finally {\n loading.value = false\n }\n }\n\n // Setup email-based MFA\n const setupEmailMfa = async (deviceName: string): Promise<{ device_id: string; email: string }> => {\n loading.value = true\n try {\n const response = await makeAuthenticatedRequest(getUrl('mfaEmailSetup'), {\n method: 'POST',\n body: JSON.stringify({ device_name: deviceName }),\n })\n\n // Refresh devices list\n await fetchMfaDevices()\n\n return response\n } finally {\n loading.value = false\n }\n }\n\n // Send email verification code\n const sendEmailMfaCode = async (deviceId: string): Promise<void> => {\n loading.value = true\n try {\n await makeAuthenticatedRequest(getUrl('mfaEmailSend'), {\n method: 'POST',\n body: JSON.stringify({ device_id: deviceId }),\n })\n } finally {\n loading.value = false\n }\n }\n\n // Verify email MFA code\n const verifyEmailMfaCode = async (deviceId: string, code: string): Promise<boolean> => {\n loading.value = true\n try {\n const response = await makeAuthenticatedRequest(getUrl('mfaEmailVerify'), {\n method: 'POST',\n body: JSON.stringify({\n device_id: deviceId,\n code: code,\n }),\n })\n\n return response.verified || false\n } finally {\n loading.value = false\n }\n }\n\n // Disable an MFA device\n const disableMfaDevice = async (deviceId: string): Promise<void> => {\n loading.value = true\n try {\n await makeAuthenticatedRequest(getUrl('mfaDeviceDisable'), {\n method: 'POST',\n body: JSON.stringify({ device_id: deviceId }),\n })\n\n // Refresh devices list\n await fetchMfaDevices()\n } finally {\n loading.value = false\n }\n }\n\n // Regenerate backup codes for TOTP device\n const regenerateBackupCodes = async (deviceId: string): Promise<BackupCodesResponse> => {\n loading.value = true\n try {\n const response = await makeAuthenticatedRequest(getUrl('mfaBackupCodes'), {\n method: 'POST',\n body: JSON.stringify({ device_id: deviceId }),\n })\n\n return response\n } finally {\n loading.value = false\n }\n }\n\n // Helper function to get device type icon\n const getDeviceTypeIcon = (deviceType: string): string => {\n switch (deviceType) {\n case 'totp':\n return '📱' // Authenticator app\n case 'email':\n return '📧' // Email\n case 'hardware':\n return '🔑' // Hardware key\n case 'passkey':\n return '🔐' // Passkey\n default:\n return '🔒' // Generic security\n }\n }\n\n // Helper function to get device type name\n const getDeviceTypeName = (deviceType: string): string => {\n switch (deviceType) {\n case 'totp':\n return 'Authenticator App'\n case 'email':\n return 'Email Verification'\n case 'hardware':\n return 'Hardware Key'\n case 'passkey':\n return 'Passkey'\n default:\n return 'Unknown'\n }\n }\n\n // Helper function to format last used date\n const formatLastUsed = (lastUsedAt?: string | Date): string => {\n if (!lastUsedAt) return 'Never'\n \n const date = new Date(lastUsedAt)\n const now = new Date()\n const diffMs = now.getTime() - date.getTime()\n const diffDays = Math.floor(diffMs / (1000 * 60 * 60 * 24))\n \n if (diffDays === 0) return 'Today'\n if (diffDays === 1) return 'Yesterday'\n if (diffDays < 30) return `${diffDays} days ago`\n \n return date.toLocaleDateString()\n }\n\n return {\n // State\n mfaDevices: computed(() => mfaDevices.value),\n mfaEnabled: computed(() => mfaEnabled.value),\n loading: computed(() => loading.value),\n hasMfaDevices,\n activeMfaDevices,\n\n // Methods\n fetchMfaDevices,\n setupTotp,\n verifyTotpSetup,\n setupEmailMfa,\n sendEmailMfaCode,\n verifyEmailMfaCode,\n disableMfaDevice,\n regenerateBackupCodes,\n\n // Helper methods\n getDeviceTypeIcon,\n getDeviceTypeName,\n formatLastUsed,\n }\n}","<template>\n <div class=\"accui-component-scope\">\n <UiModal :open=\"show\" card-class=\"mfa-verification-modal\" class=\"mfa-verification-modal-wrapper\">\n <template #header>\n <div class=\"mfa-verification-header\">\n <h2 class=\"mfa-verification-title\">Two-Factor Authentication</h2>\n <p class=\"mfa-verification-subtitle\">Enter your verification code to continue</p>\n </div>\n </template>\n\n <div class=\"mfa-verification-content\">\n <!-- Loading State -->\n <div v-if=\"loading && !emailCodeSent\" class=\"mfa-verification-loading\">\n <StrandsUiLoader :size=\"24\" />\n <span class=\"mfa-verification-loading-text\">{{ isSendingMfaEmail || isVerifyingMfa ? authLoadingMessage :\n 'Loading...' }}</span>\n </div>\n\n <!-- Verification Form -->\n <div v-else class=\"mfa-verification-form\">\n <!-- Available MFA Methods -->\n <div v-if=\"availableMethods.length > 1\" class=\"mfa-methods-section\">\n <p class=\"mfa-methods-title\">Choose verification method:</p>\n <div class=\"mfa-methods-grid\">\n <button v-for=\"method in availableMethods\" :key=\"method.id\" @click=\"selectMethod(method)\" :class=\"[\n 'mfa-method-button',\n selectedMethod?.id === method.id ? 'mfa-method-button-selected' : 'mfa-method-button-default'\n ]\">\n <component :is=\"getDeviceIconComponent(method.device_type)\" :size=\"20\" class=\"mfa-method-icon\" />\n <div class=\"mfa-method-info\">\n <p class=\"mfa-method-name\">{{ method.device_name }}</p>\n <p class=\"mfa-method-type\">{{ getDeviceTypeName(method.device_type) }}</p>\n </div>\n <div v-if=\"selectedMethod?.id === method.id\" class=\"mfa-method-check\">\n <IconCheckCircle :size=\"20\" />\n </div>\n </button>\n </div>\n </div>\n\n <!-- Single Method Display -->\n <div v-else-if=\"selectedMethod\" class=\"mfa-single-method\">\n <div class=\"mfa-single-method-content\">\n <component :is=\"getDeviceIconComponent(selectedMethod.device_type)\" :size=\"24\" class=\"mfa-single-method-icon\" />\n <div>\n <h3 class=\"mfa-single-method-name\">{{ selectedMethod.device_name }}</h3>\n <p class=\"mfa-single-method-type\">{{ getDeviceTypeName(selectedMethod.device_type) }}</p>\n </div>\n </div>\n </div>\n\n <!-- Email MFA Code Request -->\n <div v-if=\"selectedMethod?.device_type === 'email' && !emailCodeSent\" class=\"mfa-email-request\">\n <p class=\"mfa-email-request-text\">Click below to receive your verification code</p>\n <StrandsUiButton variant=\"primary\" @click=\"sendEmailCode\" :disabled=\"loading\" :loading=\"loading\">\n Send Verification Code\n </StrandsUiButton>\n </div>\n\n <!-- Hardware Key & Passkey Authentication -->\n <div v-if=\"selectedMethod?.device_type === 'hardware' || selectedMethod?.device_type === 'passkey'\"\n class=\"mfa-hardware-section\">\n <div class=\"mfa-hardware-prompt\">\n <div class=\"mfa-hardware-prompt-content\">\n <div class=\"mfa-hardware-prompt-icon\">\n <component :is=\"selectedMethod.device_type === 'passkey' ? IconShield : IconKeyRound\" :size=\"24\" class=\"mfa-hardware-icon-svg\" />\n </div>\n <div class=\"mfa-hardware-prompt-text\">\n <h4 class=\"mfa-hardware-prompt-title\">{{ selectedMethod.device_type === 'passkey' ? 'Use your passkey'\n :\n 'Touch your hardware key' }}</h4>\n <p class=\"mfa-hardware-prompt-description\">{{ selectedMethod.device_type === 'passkey' ? 'Use biometrics, PIN, or device security to authenticate' : 'Insert and touch your hardware key to authenticate' }}</p>\n </div>\n </div>\n </div>\n <StrandsUiButton variant=\"primary\" @click=\"authenticateHardwareKey\" :disabled=\"loading\" :loading=\"loading\">\n {{ selectedMethod.device_type === 'passkey' ? 'Authenticate with Passkey' : 'Authenticate with Hardware Key' }}\n </StrandsUiButton>\n\n <!-- Backup Codes Option for Hardware Keys -->\n <div class=\"mfa-backup-option\">\n <StrandsUiButton\n variant=\"ghost\"\n size=\"sm\"\n @click=\"showBackupCodeInput = !showBackupCodeInput\"\n class=\"mfa-backup-toggle-button\">\n <IconKeyRound :size=\"16\" class=\"mfa-backup-toggle-icon\" />\n {{ showBackupCodeInput ? 'Hide backup code' : (selectedMethod.device_type === 'passkey' ? 'Can\\'t access your passkey? Use backup code' : 'Can\\'t access your key? Use backup code') }}\n </StrandsUiButton>\n </div>\n\n <!-- Backup Code Input for Hardware Keys -->\n <div v-if=\"showBackupCodeInput\" class=\"mfa-backup-input-section\">\n <div class=\"mfa-backup-warning\">\n <IconAlertTriangle :size=\"20\" class=\"mfa-backup-warning-icon\" />\n <div>\n <p class=\"mfa-backup-warning-title\">Backup Code Recovery</p>\n <p class=\"mfa-backup-warning-description\">\n Enter one of your backup codes. Each code can only be used once.\n </p>\n </div>\n </div>\n\n <StrandsUiInput v-model=\"backupCode\" label=\"Backup Code\" placeholder=\"abcd-1234\" :error=\"backupCodeError\"\n :disabled=\"loading\" @input=\"onBackupCodeInput\" @paste=\"onBackupCodePaste\" @keydown.enter=\"verifyBackupCode\" class=\"mfa-backup-input\" \n name=\"backup-code-1\" autocomplete=\"off\" inputmode=\"text\" \n data-lpignore=\"false\" data-form-type=\"other\" spellcheck=\"false\" />\n </div>\n </div>\n\n <!-- Code Input -->\n <form\n v-if=\"selectedMethod && selectedMethod.device_type !== 'hardware' && selectedMethod.device_type !== 'passkey' && (selectedMethod.device_type !== 'email' || emailCodeSent)\"\n class=\"mfa-code-section\" @submit.prevent=\"verify\"\n novalidate\n autocomplete=\"off\">\n <!-- Email confirmation -->\n <div v-if=\"selectedMethod.device_type === 'email' && emailCodeSent\"\n class=\"mfa-email-confirmation\">\n <div class=\"mfa-email-confirmation-content\">\n <IconCheckCircle :size=\"20\" class=\"mfa-email-confirmation-icon\" />\n <div>\n <p class=\"mfa-email-confirmation-title\">Code Sent!</p>\n <p class=\"mfa-email-confirmation-description\">Check your email for the verification code</p>\n </div>\n </div>\n </div>\n\n <!-- Code Input Field -->\n <StrandsUiInput v-model=\"verificationCode\" label=\"Verification Code\"\n :placeholder=\"selectedMethod.device_type === 'totp' ? '123456' : '123456'\" maxlength=\"6\"\n :error=\"verificationError\" :disabled=\"loading\" @input=\"onCodeInput\" @keydown.enter=\"verify\" @paste=\"onCodePaste\" autofocus\n name=\"totp\"\n id=\"totp-input\"\n autocomplete=\"one-time-code\"\n inputmode=\"numeric\" \n data-lpignore=\"false\" \n data-form-type=\"other\"\n data-bwignore=\"false\"\n data-1p-ignore=\"false\"\n data-testid=\"totp-input\"\n spellcheck=\"false\"\n aria-label=\"Enter your verification code\"\n aria-describedby=\"totp-description\"\n role=\"textbox\"\n tabindex=\"0\"\n pattern=\"[0-9]{6}\"\n minlength=\"6\"\n title=\"Enter 6-digit verification code\" />\n\n <!-- TOTP Help -->\n <div v-if=\"selectedMethod.device_type === 'totp'\" class=\"mfa-totp-help\" id=\"totp-description\">\n Open your authenticator app and enter the 6-digit code for \n <span class=\"mfa-device-name-text\">\"{{ selectedMethod.device_name }}\"</span>\n </div>\n\n <!-- Email Resend -->\n <div v-if=\"selectedMethod.device_type === 'email'\" class=\"mfa-email-resend\">\n <StrandsUiButton\n variant=\"ghost\"\n size=\"sm\"\n @click=\"sendEmailCode\"\n :disabled=\"loading || cooldownActive\"\n class=\"mfa-resend-button\">\n {{ cooldownActive ? `Resend in ${cooldownSeconds}s` : 'Resend Code' }}\n </StrandsUiButton>\n </div>\n\n <!-- Backup Codes Option -->\n <div class=\"mfa-backup-option\">\n <StrandsUiButton\n variant=\"ghost\"\n size=\"sm\"\n @click=\"showBackupCodeInput = !showBackupCodeInput\"\n class=\"mfa-backup-toggle-button\">\n <IconKeyRound :size=\"16\" class=\"mfa-backup-toggle-icon\" />\n {{ showBackupCodeInput ? 'Hide backup code' : 'Use backup code instead' }}\n </StrandsUiButton>\n </div>\n\n <!-- Backup Code Input -->\n <div v-if=\"showBackupCodeInput\" class=\"mfa-backup-input-section\">\n <div class=\"mfa-backup-warning\">\n <IconAlertTriangle :size=\"20\" class=\"mfa-backup-warning-icon\" />\n <div>\n <p class=\"mfa-backup-warning-title\">Backup Code Recovery</p>\n <p class=\"mfa-backup-warning-description\">\n Enter one of your backup codes. Each code can only be used once.\n </p>\n </div>\n </div>\n\n <StrandsUiInput v-model=\"backupCode\" label=\"Backup Code\" placeholder=\"abcd-1234\" :error=\"backupCodeError\"\n :disabled=\"loading\" @input=\"onBackupCodeInput\" @paste=\"onBackupCodePaste\" @keydown.enter=\"verifyBackupCode\" class=\"mfa-backup-input\" \n name=\"backup-code-2\" autocomplete=\"off\" inputmode=\"text\" \n data-lpignore=\"false\" data-form-type=\"other\" spellcheck=\"false\" />\n </div>\n </form>\n </div>\n </div>\n\n <template #footer>\n <div class=\"mfa-verification-footer\">\n <StrandsUiButton variant=\"secondary\" @click=\"closeModal\" :disabled=\"loading\">\n Cancel\n </StrandsUiButton>\n\n <StrandsUiButton\n v-if=\"(selectedMethod && selectedMethod.device_type !== 'hardware' && selectedMethod.device_type !== 'passkey' && (selectedMethod.device_type !== 'email' || emailCodeSent)) || ((selectedMethod?.device_type === 'hardware' || selectedMethod?.device_type === 'passkey') && showBackupCodeInput)\"\n variant=\"primary\" @click=\"showBackupCodeInput ? verifyBackupCode() : verify()\"\n :disabled=\"(!verificationCode.trim() && !backupCode.trim()) || loading\" :loading=\"loading\">\n {{ showBackupCodeInput ? 'Verify Backup Code' : 'Verify' }}\n </StrandsUiButton>\n </div>\n </template>\n </UiModal>\n </div>\n</template>\n\n<script setup lang=\"ts\">\nimport { ref, computed, watch, onBeforeUnmount, h } from 'vue'\nimport { StrandsUiButton, StrandsUiInput, StrandsUiLoader } from '../ui'\nimport UiModal from '../ui/UiModal.vue'\nimport { useStrandsMfa } from '../composables/useStrandsMfa'\nimport { useStrandsAuth } from '../composables/useStrandsAuth'\nimport type { MfaDevice } from '../../types'\n\n// Simple SVG icon components using render functions (no runtime compilation needed)\nconst IconSmartphone = {\n props: ['size'],\n render(this: any) {\n return h('svg', { \n width: this.size, \n height: this.size, \n fill: 'none', \n stroke: 'currentColor', \n viewBox: '0 0 24 24' \n }, [\n h('rect', { x: '5', y: '2', width: '14', height: '20', rx: '2', ry: '2' }),\n h('line', { x1: '12', y1: '18', x2: '12.01', y2: '18' })\n ])\n }\n}\n\nconst IconMail = {\n props: ['size'],\n render(this: any) {\n return h('svg', { \n width: this.size, \n height: this.size, \n fill: 'none', \n stroke: 'currentColor', \n viewBox: '0 0 24 24' \n }, [\n h('path', { d: 'm4 4 16 0 0 16 -16 0 z' }),\n h('path', { d: 'm22 6-10 7L2 6' })\n ])\n }\n}\n\nconst IconKeyRound = {\n props: ['size'],\n render(this: any) {\n return h('svg', { \n width: this.size, \n height: this.size, \n fill: 'none', \n stroke: 'currentColor', \n viewBox: '0 0 24 24' \n }, [\n h('circle', { cx: '7.5', cy: '15.5', r: '5.5' }),\n h('path', { d: 'm21 2-9.6 9.6' }),\n h('path', { d: 'm15.5 7.5 3 3L22 7l-3-3' })\n ])\n }\n}\n\nconst IconShield = {\n props: ['size'],\n render(this: any) {\n return h('svg', { \n width: this.size, \n height: this.size, \n fill: 'none', \n stroke: 'currentColor', \n viewBox: '0 0 24 24' \n }, [\n h('path', { d: 'M12 22s8-4 8-10V5l-8-3-8 3v7c0 6 8 10 8 10z' })\n ])\n }\n}\n\nconst IconCheckCircle = {\n props: ['size'],\n render(this: any) {\n return h('svg', { \n width: this.size, \n height: this.size, \n fill: 'none', \n stroke: 'currentColor', \n viewBox: '0 0 24 24' \n }, [\n h('path', { d: 'M22 11.08V12a10 10 0 1 1-5.93-9.14' }),\n h('polyline', { points: '22,4 12,14.01 9,11.01' })\n ])\n }\n}\n\nconst IconCheck = {\n props: ['size'],\n render(this: any) {\n return h('svg', { \n width: this.size, \n height: this.size, \n fill: 'none', \n stroke: 'currentColor', \n viewBox: '0 0 24 24' \n }, [\n h('polyline', { points: '20,6 9,17 4,12' })\n ])\n }\n}\n\nconst IconAlertTriangle = {\n props: ['size'],\n render(this: any) {\n return h('svg', { \n width: this.size, \n height: this.size, \n fill: 'none', \n stroke: 'currentColor', \n viewBox: '0 0 24 24' \n }, [\n h('path', { d: 'm21.73 18-8-14a2 2 0 0 0-3.48 0l-8 14A2 2 0 0 0 4 21h16a2 2 0 0 0 1.73-3Z' }),\n h('path', { d: 'M12 9v4' }),\n h('path', { d: 'm12 17 .01 0' })\n ])\n }\n}\n\ninterface Props {\n show: boolean\n availableMfaMethods?: MfaDevice[]\n sessionId?: string | null\n}\n\ninterface Emits {\n (e: 'close'): void\n (e: 'success'): void\n (e: 'error', error: string): void\n}\n\nconst props = defineProps<Props>()\nconst emit = defineEmits<Emits>()\n\nconst {\n loading: mfaLoading,\n getDeviceTypeIcon,\n getDeviceTypeName,\n} = useStrandsMfa()\n\nconst {\n verifyMfa,\n sendMfaEmailCode,\n getMfaWebAuthnChallenge,\n mfaSessionId: authMfaSessionId,\n loading: authLoading,\n loadingMessage: authLoadingMessage,\n isSendingMfaEmail,\n isVerifyingMfa,\n} = useStrandsAuth()\n\nconst loading = computed(() => mfaLoading.value || authLoading.value)\n\n// State\nconst selectedMethod = ref<MfaDevice | null>(null)\nconst verificationCode = ref('')\nconst verificationError = ref('')\nconst backupCode = ref('')\nconst backupCodeError = ref('')\nconst showBackupCodeInput = ref(false)\nconst emailCodeSent = ref(false)\nconst cooldownActive = ref(false)\nconst cooldownSeconds = ref(0)\n\nlet cooldownInterval: NodeJS.Timeout | null = null\n\n// Computed - filter out WebAuthn methods temporarily until cross-domain support is implemented\nconst availableMethods = computed(() => {\n const methods = props.availableMfaMethods || []\n // Temporarily disable hardware keys and passkeys until cross-domain WebAuthn is resolved\n return methods.filter(method =>\n method.device_type !== 'hardware' &&\n method.device_type !== 'passkey'\n )\n})\n\n// Auto-select if only one method available\nwatch(() => availableMethods.value, (methods) => {\n if (methods.length === 1) {\n selectedMethod.value = methods[0]\n } else if (methods.length === 0) {\n selectedMethod.value = null\n }\n}, { immediate: true })\n\n// Reset when modal opens/closes\nwatch(() => props.show, async (newShow) => {\n if (newShow) {\n // Reset state\n verificationCode.value = ''\n verificationError.value = ''\n backupCode.value = ''\n backupCodeError.value = ''\n showBackupCodeInput.value = false\n emailCodeSent.value = false\n cooldownActive.value = false\n cooldownSeconds.value = 0\n\n if (cooldownInterval) {\n clearInterval(cooldownInterval)\n cooldownInterval = null\n }\n\n // Loading state is already handled in useStrandsAuth when MFA is required\n\n // Auto-select method if only one available\n if (availableMethods.value.length === 1) {\n selectedMethod.value = availableMethods.value[0]\n\n // If the only method is email, automatically send the code\n if (selectedMethod.value.device_type === 'email') {\n // Small delay to ensure UI is ready\n setTimeout(async () => {\n try {\n await sendMfaEmailCode(selectedMethod.value!.id)\n emailCodeSent.value = true\n startCooldown()\n } catch (error) {\n emit('error', error instanceof Error ? error.message : 'Failed to send email code')\n // Even if auto-send fails, show the manual send button by not setting emailCodeSent to true\n }\n }, 100)\n }\n }\n } else {\n selectedMethod.value = null\n }\n})\n\nonBeforeUnmount(() => {\n if (cooldownInterval) {\n clearInterval(cooldownInterval)\n }\n})\n\nconst closeModal = () => {\n emit('close')\n}\n\nconst selectMethod = (method: MfaDevice) => {\n selectedMethod.value = method\n verificationCode.value = ''\n verificationError.value = ''\n emailCodeSent.value = false\n showBackupCodeInput.value = false\n}\n\nconst onCodeInput = (value: string) => {\n // Only allow digits for verification codes\n verificationCode.value = value.replace(/\\D/g, '').slice(0, 6)\n verificationError.value = ''\n}\n\nconst onCodePaste = (event: ClipboardEvent) => {\n event.preventDefault()\n const pastedData = event.clipboardData?.getData('text/plain') || ''\n // Extract only digits from pasted data and limit to 6 characters\n const cleanedData = pastedData.replace(/\\D/g, '').slice(0, 6)\n verificationCode.value = cleanedData\n verificationError.value = ''\n}\n\nconst onBackupCodeInput = (value: string) => {\n // Allow alphanumeric and hyphens for backup codes, normalize to lowercase\n // Remove any characters except letters, numbers, and hyphens\n let cleaned = value.replace(/[^a-zA-Z0-9-]/g, '').toLowerCase()\n\n // If the user is typing continuously without hyphens, auto-format with hyphens for xxxx-xxxx pattern\n if (!/[-]/.test(cleaned) && cleaned.length > 4) {\n // Format as xxxx-xxxx pattern\n const part1 = cleaned.substring(0, 4)\n const part2 = cleaned.substring(4, 8)\n cleaned = part2 ? `${part1}-${part2}` : part1\n }\n\n // Limit to xxxx-xxxx format (8 characters plus 1 hyphen = 9 total)\n if (cleaned.replace(/-/g, '').length <= 8) {\n backupCode.value = cleaned\n }\n\n backupCodeError.value = ''\n}\n\nconst onBackupCodePaste = (event: ClipboardEvent) => {\n event.preventDefault()\n const pastedData = event.clipboardData?.getData('text/plain') || ''\n // Process pasted backup code data with the same logic as typing\n let cleaned = pastedData.replace(/[^a-zA-Z0-9-]/g, '').toLowerCase()\n \n // If the pasted data doesn't have hyphens and is longer than 4 chars, auto-format\n if (!/[-]/.test(cleaned) && cleaned.length > 4) {\n const part1 = cleaned.substring(0, 4)\n const part2 = cleaned.substring(4, 8)\n cleaned = part2 ? `${part1}-${part2}` : part1\n }\n \n // Limit to xxxx-xxxx format (8 characters plus 1 hyphen = 9 total)\n if (cleaned.replace(/-/g, '').length <= 8) {\n backupCode.value = cleaned\n }\n backupCodeError.value = ''\n}\n\nconst sendEmailCode = async () => {\n if (!selectedMethod.value || selectedMethod.value.device_type !== 'email') return\n\n try {\n // Use the sign-in specific MFA email code method\n await sendMfaEmailCode(selectedMethod.value.id)\n emailCodeSent.value = true\n startCooldown()\n } catch (error) {\n emit('error', error instanceof Error ? error.message : 'Failed to send email code')\n }\n}\n\nconst startCooldown = () => {\n cooldownActive.value = true\n cooldownSeconds.value = 30\n\n cooldownInterval = setInterval(() => {\n cooldownSeconds.value -= 1\n if (cooldownSeconds.value <= 0) {\n cooldownActive.value = false\n if (cooldownInterval) {\n clearInterval(cooldownInterval)\n cooldownInterval = null\n }\n }\n }, 1000)\n}\n\nconst verify = async () => {\n if (!selectedMethod.value || !verificationCode.value) return\n\n verificationError.value = ''\n\n try {\n await verifyMfa(selectedMethod.value.id, verificationCode.value)\n emit('success')\n } catch (error) {\n verificationError.value = error instanceof Error ? error.message : 'Invalid verification code'\n }\n}\n\nconst verifyBackupCode = async () => {\n if (!backupCode.value) return\n\n backupCodeError.value = ''\n\n try {\n await verifyMfa('', backupCode.value, true) // deviceId not needed for backup codes\n emit('success')\n } catch (error) {\n backupCodeError.value = error instanceof Error ? error.message : 'Invalid backup code'\n }\n}\n\nconst getDeviceIconComponent = (deviceType: string) => {\n switch (deviceType) {\n case 'totp':\n return IconSmartphone\n case 'email':\n return IconMail\n case 'hardware':\n return IconKeyRound\n case 'passkey':\n return IconShield\n default:\n return IconShield\n }\n}\n\nconst authenticateHardwareKey = async () => {\n // Use sessionId from props or auth composable\n const sessionId = props.sessionId || authMfaSessionId.value\n\n if (!selectedMethod.value || (selectedMethod.value.device_type !== 'hardware' && selectedMethod.value.device_type !== 'passkey') || !sessionId) {\n emit('error', 'Missing requirements for hardware key authentication')\n return\n }\n\n try {\n // Check if WebAuthn is supported\n if (!window.navigator.credentials || !window.PublicKeyCredential) {\n throw new Error('Hardware keys are not supported in this browser')\n }\n\n // Get WebAuthn challenge from backend\n const challengeResponse = await getMfaWebAuthnChallenge(selectedMethod.value.id)\n\n // Extract the publicKey from the challenge response\n const challengeData = challengeResponse.challenge.publicKey || challengeResponse.challenge\n\n // Helper function to convert base64 to Uint8Array\n const base64ToUint8Array = (base64: string) => {\n if (!base64 || typeof base64 !== 'string') {\n return new Uint8Array(0)\n }\n const padding = '='.repeat((4 - base64.length % 4) % 4)\n const b64 = (base64 + padding).replace(/-/g, '+').replace(/_/g, '/')\n const rawData = window.atob(b64)\n const outputArray = new Uint8Array(rawData.length)\n for (let i = 0; i < rawData.length; ++i) {\n outputArray[i] = rawData.charCodeAt(i)\n }\n return outputArray\n }\n\n // Use the challenge from backend with device-optimized parameters\n const isPasskey = selectedMethod.value.device_type === 'passkey'\n\n // Convert challenge and other binary fields from base64 to Uint8Array\n const publicKeyCredentialRequestOptions: any = {\n ...challengeData,\n challenge: challengeData.challenge ? base64ToUint8Array(challengeData.challenge) : new Uint8Array(32),\n timeout: isPasskey ? 300000 : (challengeData.timeout || 60000),\n userVerification: (isPasskey ? 'required' : 'discouraged') as UserVerificationRequirement\n }\n\n // Convert allowCredentials if present\n if (challengeData.allowCredentials && Array.isArray(challengeData.allowCredentials)) {\n publicKeyCredentialRequestOptions.allowCredentials = challengeData.allowCredentials.map((cred: any) => ({\n ...cred,\n id: base64ToUint8Array(cred.id)\n }))\n }\n\n // Get WebAuthn credential from hardware key\n const credential = await navigator.credentials.get({\n publicKey: publicKeyCredentialRequestOptions\n }) as PublicKeyCredential\n\n if (!credential) {\n throw new Error(`${selectedMethod.value.device_type === 'passkey' ? 'Passkey' : 'Hardware key'} authentication was cancelled`)\n }\n\n // Try to get device information from the authenticator data\n const authenticatorData = new Uint8Array((credential.response as AuthenticatorAssertionResponse).authenticatorData)\n\n // Extract AAGUID (Authenticator Attestation Globally Unique Identifier) for device identification\n // AAGUID is at bytes 37-52 of authenticator data\n let deviceInfo = 'Security Key'\n if (authenticatorData.length >= 53) {\n const aaguid = Array.from(authenticatorData.slice(37, 53))\n const aaguidHex = aaguid.map(b => b.toString(16).padStart(2, '0')).join('')\n\n // Common AAGUID to device name mapping\n const knownAAGUIDs: Record<string, string> = {\n '00000000000000000000000000000000': 'Generic Security Key',\n 'ee882879721c491397753dfcce97072a': 'YubiKey 5 Series',\n 'f8a011f38c0a4d15800617111f9edc7d': 'YubiKey 5 Series',\n '2fc0579f811347eab116bb5a8db9202a': 'YubiKey 5 Series',\n 'c5ef55ffad9a4b9fb580adcb7c15e233': 'YubiKey 5 Series',\n '6d44ba9bf6ec2e49b9300200c9a3376d': 'Google Titan Security Key',\n 'de1e552d14e14b1f9390f6d61b56e4d1': 'Feitian Security Key',\n '12ded745aa4e4b4f84be2736d6b1b2a5': 'SoloKeys Solo',\n '8876631bd4a0427f57730ec71c9e0279': 'Nitrokey FIDO2'\n }\n\n deviceInfo = knownAAGUIDs[aaguidHex] || `Security Key (${aaguidHex.substring(0, 8)}...)`\n }\n\n // Format the credential for the backend\n const credentialData = {\n id: credential.id,\n rawId: Array.from(new Uint8Array(credential.rawId)),\n response: {\n clientDataJSON: Array.from(new Uint8Array(credential.response.clientDataJSON)),\n authenticatorData: Array.from(new Uint8Array((credential.response as AuthenticatorAssertionResponse).authenticatorData)),\n signature: Array.from(new Uint8Array((credential.response as AuthenticatorAssertionResponse).signature)),\n userHandle: (credential.response as AuthenticatorAssertionResponse).userHandle ?\n Array.from(new Uint8Array((credential.response as AuthenticatorAssertionResponse).userHandle!)) : null\n },\n type: credential.type,\n deviceInfo: deviceInfo // Include detected device info\n }\n\n // Send the credential data to the backend using the frontend device ID\n await verifyMfa(selectedMethod.value.id, JSON.stringify(credentialData))\n\n emit('success')\n\n } catch (error) {\n console.error('Hardware key authentication error:', error)\n emit('error', error instanceof Error ? error.message : 'Hardware key authentication failed')\n }\n}\n</script>\n\n<style scoped>\n/* Modal width control - Extreme override for MFA verification */\n.mfa-verification-modal-wrapper :deep(.modal-overlay) {\n align-items: center !important;\n justify-content: center !important;\n}\n\n.mfa-verification-modal-wrapper :deep(.modal-container) {\n width: 32rem !important;\n max-width: 32rem !important;\n min-width: 32rem !important;\n /* Critical: Force the modal to maintain fixed width */\n flex-shrink: 0 !important;\n flex-grow: 0 !important;\n flex-basis: auto !important;\n box-sizing: border-box !important;\n /* Override any auto width */\n width: 512px !important;\n}\n\n@media (max-width: 36rem) {\n .mfa-verification-modal-wrapper :deep(.modal-container) {\n width: calc(100vw - 2rem) !important;\n min-width: auto !important;\n max-width: calc(100vw - 2rem) !important;\n }\n}\n\n/* Force content to respect modal bounds */\n.mfa-verification-modal-wrapper :deep(.modal-content) {\n width: 100% !important;\n max-width: 100% !important;\n overflow: hidden !important;\n box-sizing: border-box !important;\n}\n\n/* Force all descendant elements to wrap and not overflow */\n.mfa-verification-modal-wrapper :deep(.modal-content *) {\n max-width: 100% !important;\n word-wrap: break-word !important;\n overflow-wrap: break-word !important;\n box-sizing: border-box !important;\n}</style>\n\n<!-- Additional global style to ensure it overrides everything -->\n<style>\n/* Global override for MFA verification modal width issue */\n.mfa-verification-modal-wrapper .modal-container {\n width: 32rem !important;\n max-width: 32rem !important;\n min-width: 32rem !important;\n flex-shrink: 0 !important;\n flex-grow: 0 !important;\n box-sizing: border-box !important;\n}\n\n@media (max-width: 36rem) {\n .mfa-verification-modal-wrapper .modal-container {\n width: calc(100vw - 2rem) !important;\n min-width: auto !important;\n max-width: calc(100vw - 2rem) !important;\n }\n}\n\n/* Force text wrapping globally for this modal */\n.mfa-verification-modal-wrapper .modal-content * {\n max-width: 100% !important;\n word-wrap: break-word !important;\n overflow-wrap: break-word !important;\n box-sizing: border-box !important;\n}\n\n/* Header */\n.mfa-verification-header {\n text-align: center;\n}\n\n.mfa-verification-title {\n font-size: 1.25rem;\n font-weight: 700;\n color: #111827;\n}\n\n.mfa-verification-subtitle {\n color: #4b5563;\n margin-top: 0.5rem;\n}\n\n/* Content */\n.mfa-verification-content {\n display: flex;\n flex-direction: column;\n gap: 1.5rem;\n max-width: 100%;\n overflow: hidden;\n}\n\n/* Loading */\n.mfa-verification-loading {\n display: flex;\n align-items: center;\n justify-content: center;\n padding: 2rem 0;\n}\n\n.mfa-verification-loading-text {\n margin-left: 0.75rem;\n color: #4b5563;\n}\n\n/* Form */\n.mfa-verification-form {\n display: flex;\n flex-direction: column;\n gap: 1rem;\n max-width: 100%;\n overflow: hidden;\n}\n\n/* Methods section */\n.mfa-methods-section {\n display: flex;\n flex-direction: column;\n gap: 0.75rem;\n}\n\n.mfa-methods-title {\n font-size: 0.875rem;\n font-weight: 500;\n color: #374151;\n}\n\n.mfa-methods-grid {\n display: grid;\n gap: 0.5rem;\n}\n\n/* Method buttons */\n.mfa-method-button {\n display: flex;\n align-items: center;\n gap: 0.75rem;\n padding: 0.75rem;\n border: 1px solid;\n border-radius: 0.5rem;\n transition: all 0.2s ease;\n cursor: pointer;\n background: none;\n text-align: left;\n width: 100%;\n}\n\n.mfa-method-button-default {\n border-color: #e5e7eb;\n background-color: transparent;\n}\n\n.mfa-method-button-default:hover {\n border-color: #d1d5db;\n background-color: #f9fafb;\n}\n\n.mfa-method-button-selected {\n border-color: var(--strands-primary, #EA00A8);\n background-color: rgba(234, 0, 168, 0.05);\n color: var(--strands-primary, #EA00A8);\n}\n\n.mfa-method-icon {\n color: var(--strands-primary, #EA00A8);\n}\n\n.mfa-method-info {\n text-align: left;\n flex: 1;\n}\n\n.mfa-method-name {\n font-weight: 500;\n margin: 0;\n}\n\n.mfa-method-type {\n font-size: 0.875rem;\n color: #6b7280;\n margin: 0;\n}\n\n.mfa-method-check {\n color: var(--strands-primary, #EA00A8);\n}\n\n/* Single method display */\n.mfa-single-method {\n background-color: #f9fafb;\n border-radius: 0.5rem;\n padding: 1rem;\n}\n\n.mfa-single-method-content {\n display: flex;\n align-items: center;\n gap: 0.75rem;\n}\n\n.mfa-single-method-icon {\n color: var(--strands-primary, #EA00A8);\n}\n\n.mfa-single-method-name {\n font-weight: 500;\n color: #111827;\n margin: 0;\n}\n\n.mfa-single-method-type {\n font-size: 0.875rem;\n color: #6b7280;\n margin: 0;\n}\n\n/* Email request */\n.mfa-email-request {\n text-align: center;\n}\n\n.mfa-email-request-text {\n font-size: 0.875rem;\n color: #4b5563;\n margin-bottom: 1rem;\n}\n\n/* Hardware section */\n.mfa-hardware-section {\n text-align: center;\n display: flex;\n flex-direction: column;\n gap: 1rem;\n}\n\n.mfa-hardware-prompt {\n background-color: #eff6ff;\n border: 1px solid #bfdbfe;\n border-radius: 0.5rem;\n padding: 1rem;\n}\n\n.mfa-hardware-prompt-content {\n display: flex;\n align-items: center;\n gap: 0.75rem;\n}\n\n.mfa-hardware-prompt-icon {\n width: 3rem;\n height: 3rem;\n background-color: #dbeafe;\n border-radius: 50%;\n display: flex;\n align-items: center;\n justify-content: center;\n}\n\n.mfa-hardware-icon-svg {\n width: 1.5rem;\n height: 1.5rem;\n color: #2563eb;\n}\n\n.mfa-hardware-prompt-text {\n text-align: left;\n}\n\n.mfa-hardware-prompt-title {\n font-weight: 500;\n color: #1e3a8a;\n margin: 0;\n}\n\n.mfa-hardware-prompt-description {\n font-size: 0.875rem;\n color: #1d4ed8;\n margin: 0;\n}\n\n/* Backup option */\n.mfa-backup-option {\n padding-top: 1rem;\n border-top: 1px solid #e5e7eb;\n display: flex;\n justify-content: center;\n}\n\n.mfa-backup-toggle-button {\n font-size: 0.875rem;\n color: #6b7280;\n justify-content: flex-start;\n gap: 0.5rem;\n}\n\n.mfa-backup-toggle-button:hover {\n color: #374151;\n background-color: #f9fafb;\n}\n\n.mfa-backup-toggle-icon {\n flex-shrink: 0;\n}\n\n/* Backup input section */\n.mfa-backup-input-section {\n display: flex;\n flex-direction: column;\n gap: 1rem;\n background-color: #fffbeb;\n border: 1px solid #fde68a;\n border-radius: 0.5rem;\n padding: 1rem;\n}\n\n.mfa-backup-warning {\n display: flex;\n align-items: flex-start;\n gap: 0.5rem;\n margin-bottom: 0.75rem;\n}\n\n.mfa-backup-warning-icon {\n width: 1.25rem;\n height: 1.25rem;\n color: #d97706;\n margin-top: 0.125rem;\n flex-shrink: 0;\n}\n\n.mfa-backup-warning-title {\n font-size: 0.875rem;\n font-weight: 500;\n color: #92400e;\n margin: 0;\n}\n\n.mfa-backup-warning-description {\n font-size: 0.875rem;\n color: #b45309;\n margin-top: 0.25rem;\n}\n\n.mfa-backup-input {\n font-family: ui-monospace, SFMono-Regular, 'SF Mono', Consolas, 'Liberation Mono', Menlo, monospace;\n}\n\n/* Code section */\n.mfa-code-section {\n display: flex;\n flex-direction: column;\n gap: 1rem;\n max-width: 100%;\n overflow: hidden;\n}\n\n/* Email confirmation */\n.mfa-email-confirmation {\n background-color: #f0fdf4;\n border: 1px solid #bbf7d0;\n border-radius: 0.5rem;\n padding: 1rem;\n}\n\n.mfa-email-confirmation-content {\n display: flex;\n align-items: flex-start;\n gap: 0.5rem;\n}\n\n.mfa-email-confirmation-icon {\n width: 1.25rem;\n height: 1.25rem;\n color: #059669;\n margin-top: 0.125rem;\n flex-shrink: 0;\n}\n\n.mfa-email-confirmation-title {\n font-size: 0.875rem;\n font-weight: 500;\n color: #166534;\n margin: 0;\n}\n\n.mfa-email-confirmation-description {\n font-size: 0.875rem;\n color: #15803d;\n margin-top: 0.25rem;\n}\n\n/* TOTP help - Force aggressive text wrapping */\n.mfa-totp-help {\n font-size: 0.875rem;\n color: #4b5563;\n line-height: 1.5;\n /* Force wrapping at all costs */\n word-wrap: break-word !important;\n overflow-wrap: anywhere !important;\n word-break: break-word !important;\n hyphens: auto !important;\n white-space: normal !important;\n /* Ensure no overflow */\n max-width: 100% !important;\n width: 100% !important;\n overflow: hidden !important;\n display: block !important;\n box-sizing: border-box !important;\n}\n\n.mfa-device-name-text {\n /* Break device names aggressively to prevent expansion */\n word-break: break-all !important;\n overflow-wrap: anywhere !important;\n word-wrap: break-word !important;\n display: inline !important;\n max-width: 100% !important;\n overflow: hidden !important;\n}\n\n/* Email resend */\n.mfa-email-resend {\n display: flex;\n justify-content: flex-end;\n font-size: 0.875rem;\n}\n\n.mfa-resend-button {\n color: var(--strands-primary, #EA00A8);\n font-size: 0.875rem;\n}\n\n.mfa-resend-button:hover:not(:disabled) {\n color: #B8006F;\n background-color: rgba(234, 0, 168, 0.05);\n}\n\n.mfa-resend-button:disabled {\n color: #9ca3af;\n cursor: not-allowed;\n}\n\n/* Footer */\n.mfa-verification-footer {\n display: flex;\n justify-content: space-between;\n}\n\n/* Backup input field */\n.mfa-backup-input {\n font-family: ui-monospace, SFMono-Regular, 'SF Mono', Consolas, 'Liberation Mono', Menlo, monospace;\n}\n</style>","import { ref, computed } from 'vue'\nimport { useStrandsConfig } from './useStrandsConfig'\n\nexport interface OAuthProvider {\n id: string\n name: string\n displayName?: string\n icon?: string\n iconUrl?: string\n auth_url: string\n scopes: string[]\n enabled: boolean\n metadata?: Record<string, string>\n}\n\nexport interface OAuthProvidersResponse {\n providers: OAuthProvider[]\n redirect_url: string\n}\n\nexport interface OAuthProviderDetailsResponse {\n success: boolean\n data: {\n provider: OAuthProvider\n authUrl: string\n state?: string\n }\n error?: {\n code: string\n message: string\n details?: any\n }\n}\n\nexport interface UseOAuthProvidersOptions {\n redirectUrl?: string\n scopes?: string[]\n}\n\nexport function useOAuthProviders(options: UseOAuthProvidersOptions = {}) {\n const { getUrl, config } = useStrandsConfig()\n \n const providers = ref<OAuthProvider[]>([])\n const loading = ref(false)\n const error = ref<string | null>(null)\n\n const enabledProviders = computed(() => \n providers.value.filter(provider => provider.enabled)\n )\n\n const fetchProviders = async () => {\n loading.value = true\n error.value = null\n\n try {\n let url = getUrl('oauthProviders')\n \n // Add redirect_url parameter if configured\n const redirectUrl = options.redirectUrl || config.value?.oauth2RedirectUrl\n if (redirectUrl) {\n const params = new URLSearchParams()\n \n // Convert relative URLs to absolute URLs\n let absoluteRedirectUrl = redirectUrl\n if (redirectUrl.startsWith('/')) {\n // Get the current origin\n const currentOrigin = window.location.origin\n absoluteRedirectUrl = `${currentOrigin}${redirectUrl}`\n }\n \n params.append('redirect_url', absoluteRedirectUrl)\n url = `${url}?${params.toString()}`\n }\n \n const response = await fetch(url, {\n method: 'GET',\n headers: {\n 'Content-Type': 'application/json',\n },\n })\n\n if (!response.ok) {\n const errorData = await response.json().catch(() => ({}))\n throw new Error(errorData.error?.message || `HTTP ${response.status}: ${response.statusText}`)\n }\n\n const result: OAuthProvidersResponse = await response.json()\n \n // The API returns { providers: [...], redirect_url: \"...\" }\n providers.value = result.providers || []\n } catch (err) {\n const errorMessage = err instanceof Error ? err.message : 'Failed to fetch OAuth providers'\n error.value = errorMessage\n } finally {\n loading.value = false\n }\n }\n\n const getProviderAuthUrl = async (\n providerId: string, \n customOptions?: Partial<UseOAuthProvidersOptions>\n ): Promise<string> => {\n const mergedOptions = { ...options, ...customOptions }\n \n // Build query parameters\n const params = new URLSearchParams()\n \n if (mergedOptions.redirectUrl) {\n // Convert relative URLs to absolute URLs\n let absoluteRedirectUrl = mergedOptions.redirectUrl\n if (mergedOptions.redirectUrl.startsWith('/')) {\n const currentOrigin = window.location.origin\n absoluteRedirectUrl = `${currentOrigin}${mergedOptions.redirectUrl}`\n }\n params.append('redirect_url', absoluteRedirectUrl)\n }\n \n if (mergedOptions.scopes && mergedOptions.scopes.length > 0) {\n params.append('scopes', mergedOptions.scopes.join(','))\n }\n\n const queryString = params.toString()\n const providerUrl = getUrl('oauthProvider').replace('{provider_id}', providerId)\n const fullUrl = queryString ? `${providerUrl}?${queryString}` : providerUrl\n\n try {\n const response = await fetch(fullUrl, {\n method: 'GET',\n headers: {\n 'Content-Type': 'application/json',\n },\n })\n\n if (!response.ok) {\n const errorData = await response.json().catch(() => ({}))\n throw new Error(errorData.error?.message || `HTTP ${response.status}: ${response.statusText}`)\n }\n\n const result: OAuthProviderDetailsResponse = await response.json()\n \n if (!result.success) {\n throw new Error(result.error?.message || 'Failed to get OAuth auth URL')\n }\n\n return result.data.authUrl\n } catch (err) {\n const errorMessage = err instanceof Error ? err.message : 'Failed to get OAuth auth URL'\n throw new Error(errorMessage)\n }\n }\n\n const redirectToProvider = async (\n providerId: string, \n customOptions?: Partial<UseOAuthProvidersOptions>\n ) => {\n try {\n // Find the provider and use its auth_url directly\n const provider = providers.value.find(p => p.id === providerId)\n if (!provider) {\n throw new Error(`OAuth provider '${providerId}' not found`)\n }\n \n if (!provider.auth_url) {\n throw new Error(`No auth URL configured for provider '${providerId}'`)\n }\n \n window.location.href = provider.auth_url\n } catch (err) {\n error.value = err instanceof Error ? err.message : 'Failed to redirect to OAuth provider'\n throw err\n }\n }\n\n const getProviderById = (providerId: string) => {\n return providers.value.find(provider => provider.id === providerId)\n }\n\n const getProviderIcon = (provider: OAuthProvider): string => {\n // Return custom icon URL if provided, otherwise use built-in icons\n if (provider.iconUrl) {\n return provider.iconUrl\n }\n\n // Built-in SVG icons for common providers\n switch (provider.id.toLowerCase()) {\n case 'google':\n return 'data:image/svg+xml;base64,PHN2ZyB2aWV3Qm94PSIwIDAgMjQgMjQiPjxwYXRoIGZpbGw9IiM0Mjg1RjQiIGQ9Ik0yMi41NiAxMi4yNWMwLS43OC0uMDctMS41My0uMi0yLjI1SDEydjQuMjZoNS45MmMtLjI2IDEuMzctMS4wNCAyLjUzLTIuMjEgMy4zMXYyLjc3aDMuNTdjMi4wOC0xLjkyIDMuMjgtNC43NCAzLjI4LTguMDl6Ii8+PHBhdGggZmlsbD0iIzM0QTg1MyIgZD0iTTEyIDIzYzIuOTcgMCA1LjQ2LS45OCA3LjI4LTIuNjZsLTMuNTctMi43N2MtLjk4LjY2LTIuMjMgMS4wNi0zLjcxIDEuMDYtMi44NiAwLTUuMjktMS45My02LjE2LTQuNTNIMi4xOHYyLjg0QzMuOTkgMjAuNTMgNy43IDIzIDEyIDIzeiIvPjxwYXRoIGZpbGw9IiNGQkJDMDUiIGQ9Ik01Ljg0IDE0LjA5Yy0uMjItLjY2LS4zNS0xLjM2LS4zNS0yLjA5cy4xMy0xLjQzLjM1LTIuMDlWNy4wN0gyLjE4QzEuNDMgOC41NSAxIDEwLjIyIDEgMTJzLjQzIDMuNDUgMS4xOCA0LjkzbDIuODUtMi4yMi44MS0uNjJ6Ii8+PHBhdGggZmlsbD0iI0VBNDMzNSIgZD0iTTEyIDUuMzhjMS42MiAwIDMuMDYuNTYgNC4yMSAxLjY0bDMuMTUtMy4xNUMxNy40NSAyLjA5IDE0Ljk3IDEgMTIgMSA3LjcgMSAzLjk5IDMuNDcgMi4xOCA3LjA3bDMuNjYgMi44NGMuODctMi42IDMuMy00LjUzIDYuMTYtNC41M3oiLz48L3N2Zz4='\n case 'github':\n return 'data:image/svg+xml;base64,PHN2ZyBmaWxsPSJjdXJyZW50Q29sb3IiIHZpZXdCb3g9IjAgMCAyNCAyNCI+PHBhdGggZD0iTTEyIDBoLTEyYy02LjYyNiAwLTEyIDUuMzczLTEyIDEyIDAgNS4zMDIgMy40MzggOS44IDguMjA3IDExLjM4Ny41OTkuMTExLjc5My0uMjYxLjc5My0uNTc3di0yLjIzNGMtMy4zMzguNzI2LTQuMDMzLTEuNDE2LTQuMDMzLTEuNDE2LS41NDYtMS4zODctMS4zMzMtMS43NTYtMS4zMzMtMS43NTYtMS4wODktLjc0NS4wODMtLjcyOS4wODMtLjcyOSAxLjIwNS4wODQgMS44MzkgMS4yMzcgMS44MzkgMS4yMzcgMS4wNyAxLjgzNCAyLjgwNyAxLjMwNCAzLjQ5Mi45OTcuMTA3LS43NzUuNDE4LTEuMzA1Ljc2Mi0xLjYwNC0yLjY2NS0uMzA1LTUuNDY3LTEuMzM0LTUuNDY3LTUuOTMxIDAtMS4zMTEuNDY5LTIuMzgxIDEuMjM2LTMuMjIxLS4xMjQtLjMwMy0uNTM1LTEuNTI0LjExNy0zLjE3NiAwIDAgMS4wMDgtLjMyMiAzLjMwMSAxLjIzLjk1Ny0uMjY2IDEuOTgzLS4zOTkgMy4wMDMtLjQwNCAxLjAyLjAwNSAyLjA0Ny4xMzggMy4wMDYuNDA0IDIuMjkxLTEuNTUyIDMuMjk3LTEuMjMgMy4yOTctMS4yMy42NTMgMS42NTMuMjQyIDIuODc0LjExOCAzLjE3Ni43Ny44NCAxLjIzNSAxLjkxMSAxLjIzNSAzLjIyMSAwIDQuNjA5LTIuODA3IDUuNjI0LTUuNDc5IDUuOTIxLjQzLjM3Mi44MjMgMS4xMDIuODIzIDIuMjIydjMuMjkzYzAgLjMxOS4xOTIuNjk0LjgwMS41NzYgNC43NjUtMS41ODkgOC4xOTktNi4wODYgOC4xOTktMTEuMzg2IDAtNi42MjctNS4zNzMtMTItMTItMTJ6Ii8+PC9zdmc+'\n case 'microsoft':\n case 'azure':\n return 'data:image/svg+xml;base64,PHN2ZyB2aWV3Qm94PSIwIDAgMjQgMjQiPjxyZWN0IGZpbGw9IiNmMjUwMjIiIHdpZHRoPSIxMSIgaGVpZ2h0PSIxMSIvPjxyZWN0IGZpbGw9IiM3ZmJhMDAiIHg9IjEzIiB3aWR0aD0iMTEiIGhlaWdodD0iMTEiLz48cmVjdCBmaWxsPSIjMDBhNGVmIiB5PSIxMyIgd2lkdGg9IjExIiBoZWlnaHQ9IjExIi8+PHJlY3QgZmlsbD0iI2ZmYjkwMCIgeD0iMTMiIHk9IjEzIiB3aWR0aD0iMTEiIGhlaWdodD0iMTEiLz48L3N2Zz4='\n case 'discord':\n return 'data:image/svg+xml;base64,PHN2ZyB2aWV3Qm94PSIwIDAgMjQgMjQiIGZpbGw9IiM1ODY1RjIiPjxwYXRoIGQ9Ik0yMC4zMTcgNC4zNjk2QTE5Ljc5MTMgMTkuNzkxMyAwIDAgMCAxOC4yMDU4IDMuMzY5NmMtLjk2NDIuMzU2NC0xLjk5NTguNjE1NC0zLjA1OC43NzNhMTQuNzI0NCAxNC43MjQ0IDAgMCAwLTYuMjk1NCAwIDEzLjU0OTQgMTMuNTQ5NCAwIDAgMC0zLjA1OC0uNzczIDEzLjY5MyAxMy42OTMgMCAwIDAtNS4wNjc2LTEuMjc5NCAyMC4xOTg0IDIwLjE5ODQgMCAwIDAtMi42NDk3IDkuMTE2MyAyMC4yODE4IDIwLjI4MTggMCAwIDAgMi4zNzU4IDIuNjNjMS4zMzIyLjEyNTggMi42NjUuMTcyMiA0LjA0NC4xNzIyaDEuMzE1NGMxLjM3OSAwIDIuNzExOC0uMDQ2NCA0LjA0NC0uMTcyMmEyMC4yODE4IDIwLjI4MTggMCAwIDAgMi4zNzU4LTIuNjMgMjAuMTk4NCAyMC4xOTg0IDAgMCAwIDIuNjQ5Ny05LjExNjNBMTkuNzkxMyAxOS43OTEzIDAgMCAwIDIwLjMxNyA0LjM2OTZ6TTE4LjE5IDEyQzE3LjY3IDE0LjQ5IDEzLjk5IDE2IDEyIDE2UzYuMzMgMTQuNDkgNS44MSAxMmMuNTItMi40OSA0LjE5LTQgNi4xOS00UzE3LjY3IDkuNTEgMTguMTkgMTJ6Ii8+PC9zdmc+'\n default:\n // Return a generic icon for unknown providers\n return 'data:image/svg+xml;base64,PHN2ZyB2aWV3Qm94PSIwIDAgMjQgMjQiIGZpbGw9ImN1cnJlbnRDb2xvciI+PGNpcmNsZSBjeD0iMTIiIGN5PSIxMiIgcj0iMTAiLz48dGV4dCB4PSIxMiIgeT0iMTciIHRleHQtYW5jaG9yPSJtaWRkbGUiIGZpbGw9IndoaXRlIiBmb250LXNpemU9IjEyIj57cHJvdmlkZXIuaWQuY2hhckF0KDApLnRvVXBwZXJDYXNlKCl9PC90ZXh0Pjwvc3ZnPg=='\n }\n }\n\n return {\n providers: computed(() => providers.value),\n enabledProviders,\n loading: computed(() => loading.value),\n error: computed(() => error.value),\n fetchProviders,\n getProviderAuthUrl,\n redirectToProvider,\n getProviderById,\n getProviderIcon\n }\n}\n","<template>\n <div class=\"accui-component-scope\">\n <div :class=\"props.inModal ? 'auth-container-modal auth-full-width auth-min-width' : 'auth-container auth-full-width auth-min-width auth-max-width auth-center auth-slide-up'\">\n <div :class=\"props.inModal ? 'auth-content-modal' : 'auth-content auth-card-modern'\">\n <!-- Header -->\n <div class=\"auth-header\">\n <Transition name=\"fade\" mode=\"out-in\">\n <h1 :key=\"currentMode\" class=\"auth-title\">\n {{ isPasswordReset ? 'Reset password' : isSignUp ? 'Create account' : 'Welcome back' }}\n </h1>\n </Transition>\n <Transition name=\"fade\" mode=\"out-in\">\n <p :key=\"currentMode\" class=\"auth-subtitle\">\n {{ isPasswordReset ? 'Enter your email address and we\\'ll send you a link' : isSignUp\n ?\n 'We\\'ll send you a magic link to get started' : 'Sign in to your account to continue' }}\n </p>\n </Transition>\n </div>\n\n <!-- Tab Switcher (only show for signin/signup) -->\n <Transition \n name=\"smooth-height\" \n @before-enter=\"onBeforeEnter\" \n @enter=\"onEnter\" \n @before-leave=\"onBeforeLeave\" \n @leave=\"onLeave\" \n @after-leave=\"onAfterLeave\"\n >\n <div v-if=\"!isPasswordReset\" class=\"auth-tabs-container\">\n <StrandsUiTabs v-model=\"currentMode\" :tabs=\"[\n { label: 'Sign In', value: 'signin' },\n { label: 'Sign Up', value: 'signup' }\n ]\" />\n </div>\n </Transition>\n\n <!-- OAuth Providers (not shown for password reset) -->\n <Transition \n name=\"smooth-height\" \n @before-enter=\"onBeforeEnter\" \n @enter=\"onEnter\" \n @before-leave=\"onBeforeLeave\" \n @leave=\"onLeave\" \n @after-leave=\"onAfterLeave\"\n >\n <div v-if=\"!isPasswordReset && displayProviders?.length\" class=\"auth-oauth-providers\">\n <StrandsUiButton \n v-for=\"provider in displayProviders\" \n :key=\"provider.id\" \n variant=\"outline\" \n full-width\n :disabled=\"oauthLoading\"\n @click=\"handleOAuthAuth(provider.id)\" \n class=\"auth-oauth-button\"\n >\n <div class=\"auth-oauth-icon-container\">\n <!-- Dynamic provider icons -->\n <div v-if=\"provider.icon || provider.iconUrl\" class=\"auth-oauth-icon\">\n <img :src=\"provider.icon || provider.iconUrl\" :alt=\"`${provider.displayName || provider.name} icon`\" class=\"auth-oauth-icon\" />\n </div>\n <!-- Built-in SVG icons for common providers -->\n <svg v-else-if=\"provider.id === 'google'\" viewBox=\"0 0 24 24\" class=\"auth-oauth-icon\">\n <path fill=\"#4285F4\"\n d=\"M22.56 12.25c0-.78-.07-1.53-.2-2.25H12v4.26h5.92c-.26 1.37-1.04 2.53-2.21 3.31v2.77h3.57c2.08-1.92 3.28-4.74 3.28-8.09z\" />\n <path fill=\"#34A853\"\n d=\"M12 23c2.97 0 5.46-.98 7.28-2.66l-3.57-2.77c-.98.66-2.23 1.06-3.71 1.06-2.86 0-5.29-1.93-6.16-4.53H2.18v2.84C3.99 20.53 7.7 23 12 23z\" />\n <path fill=\"#FBBC05\"\n d=\"M5.84 14.09c-.22-.66-.35-1.36-.35-2.09s.13-1.43.35-2.09V7.07H2.18C1.43 8.55 1 10.22 1 12s.43 3.45 1.18 4.93l2.85-2.22.81-.62z\" />\n <path fill=\"#EA4335\"\n d=\"M12 5.38c1.62 0 3.06.56 4.21 1.64l3.15-3.15C17.45 2.09 14.97 1 12 1 7.7 1 3.99 3.47 2.18 7.07l3.66 2.84c.87-2.6 3.3-4.53 6.16-4.53z\" />\n </svg>\n <svg v-else-if=\"provider.id === 'github'\" class=\"auth-oauth-icon auth-oauth-github\" viewBox=\"0 0 24 24\">\n <path\n d=\"M12 0c-6.626 0-12 5.373-12 12 0 5.302 3.438 9.8 8.207 11.387.599.111.793-.261.793-.577v-2.234c-3.338.726-4.033-1.416-4.033-1.416-.546-1.387-1.333-1.756-1.333-1.756-1.089-.745.083-.729.083-.729 1.205.084 1.839 1.237 1.839 1.237 1.07 1.834 2.807 1.304 3.492.997.107-.775.418-1.305.762-1.604-2.665-.305-5.467-1.334-5.467-5.931 0-1.311.469-2.381 1.236-3.221-.124-.303-.535-1.524.117-3.176 0 0 1.008-.322 3.301 1.23.957-.266 1.983-.399 3.003-.404 1.02.005 2.047.138 3.006.404 2.291-1.552 3.297-1.23 3.297-1.23.653 1.653.242 2.874.118 3.176.77.84 1.235 1.911 1.235 3.221 0 4.609-2.807 5.624-5.479 5.921.43.372.823 1.102.823 2.222v3.293c0 .319.192.694.801.576 4.765-1.589 8.199-6.086 8.199-11.386 0-6.627-5.373-12-12-12z\" />\n </svg>\n <!-- Generic icon for other providers -->\n <div v-else class=\"auth-oauth-generic-icon\">\n <span class=\"auth-oauth-generic-text\">{{ (provider.displayName || provider.name).charAt(0).toUpperCase() }}</span>\n </div>\n </div>\n <span class=\"auth-oauth-text\">\n Continue with {{ provider.displayName || provider.name.charAt(0).toUpperCase() + provider.name.slice(1) }}\n </span>\n </StrandsUiButton>\n </div>\n </Transition>\n\n <!-- Divider (not shown for password reset) -->\n <Transition \n name=\"smooth-height\" \n @before-enter=\"onBeforeEnter\" \n @enter=\"onEnter\" \n @before-leave=\"onBeforeLeave\" \n @leave=\"onLeave\" \n @after-leave=\"onAfterLeave\"\n >\n <div v-if=\"!isPasswordReset && displayProviders?.length\" class=\"auth-divider\">\n <span class=\"auth-divider-text\">Or {{ isSignUp ? 'create account' : 'sign in' }} with email</span>\n </div>\n </Transition>\n\n <!-- Auth Form -->\n <form @submit.prevent=\"handleAuth\" class=\"auth-form\">\n <div>\n <!-- Email -->\n <div :class=\"['email-field-spacing', (!isPasswordReset && !isSignUp) ? 'has-password' : 'no-password']\">\n <StrandsUiInput v-model=\"form.email\" type=\"email\" label=\"Email address\" placeholder=\"Enter your email\" required\n autocomplete=\"email\" :error=\"error && !form.email ? 'Email is required' : ''\" />\n </div>\n\n <!-- Password (Sign In Only) -->\n <Transition \n name=\"smooth-height\" \n @before-enter=\"onBeforeEnter\" \n @enter=\"onEnter\" \n @before-leave=\"onBeforeLeave\" \n @leave=\"onLeave\" \n @after-leave=\"onAfterLeave\"\n >\n <div v-if=\"!isPasswordReset && !isSignUp\" class=\"auth-password-field\">\n <div class=\"auth-password-header\">\n <span class=\"auth-password-label\">Password</span>\n <StrandsUiLink variant=\"primary\" size=\"sm\" @click=\"currentMode = 'reset-password'\">\n Forgot password?\n </StrandsUiLink>\n </div>\n\n <StrandsUiInput v-model=\"form.password\" type=\"password\"\n placeholder=\"Enter your password\" required\n autocomplete=\"current-password\"\n :error=\"error && !form.password ? 'Password is required' : ''\" />\n </div>\n </Transition>\n </div>\n\n <StrandsUiButton type=\"submit\" variant=\"primary\" full-width :disabled=\"buttonLoading || !isFormValid\" :loading=\"buttonLoading\"\n :loading-text=\"loadingMessage\">\n {{ isPasswordReset\n ? (isPasswordResetSubmitted\n ? 'Link sent!'\n : 'Send reset link')\n : isSignUp\n ? 'Send magic link'\n : 'Sign in'\n }}\n </StrandsUiButton>\n </form>\n\n <!-- Success Message for Password Reset -->\n <Transition name=\"expand\" mode=\"out-in\">\n <StrandsUiAlert v-if=\"isPasswordReset && isPasswordResetSubmitted\" key=\"reset-success\" variant=\"success\"\n :message=\"`Check your email - We've sent a password reset link to ${form.email}`\"\n class=\"auth-success-alert\" />\n </Transition>\n\n <!-- Back to Sign In (Password Reset Only) -->\n <Transition \n name=\"smooth-height\" \n @before-enter=\"onBeforeEnter\" \n @enter=\"onEnter\" \n @before-leave=\"onBeforeLeave\" \n @leave=\"onLeave\" \n @after-leave=\"onAfterLeave\"\n >\n <div v-if=\"isPasswordReset\" class=\"auth-back-link-container\">\n <StrandsUiLink @click=\"currentMode = 'signin'\" class=\"auth-back-link\">\n <svg class=\"auth-back-icon\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M15 19l-7-7 7-7\" />\n </svg>\n Back to sign in\n </StrandsUiLink>\n </div>\n </Transition>\n\n <!-- Error Alert -->\n <StrandsUiAlert v-if=\"error\" variant=\"error\" :message=\"error\" class=\"auth-error-alert\" dismissible\n @dismiss=\"error = ''\" />\n\n <!-- Secured by footer -->\n <StrandsSecuredFooter :config=\"props.config\">\n <!-- Need help -->\n <Transition name=\"support-fade\" v-if=\"getSupportEmail()\">\n <p class=\"auth-support-text\">\n Need help?\n <StrandsUiLink variant=\"primary\" :href=\"`mailto:${getSupportEmail()}`\">\n Contact Support\n </StrandsUiLink>\n </p>\n </Transition>\n </StrandsSecuredFooter>\n </div>\n </div>\n \n <!-- MFA Verification Modal -->\n <StrandsMfaVerification\n :show=\"showMfaVerification\"\n :available-mfa-methods=\"availableMfaMethods\"\n @success=\"handleMfaSuccess\"\n @close=\"handleMfaClose\"\n @error=\"handleMfaError\"\n />\n </div>\n</template>\n\n<script setup lang=\"ts\">\nimport { ref, reactive, computed, watch, onMounted } from 'vue'\nimport { StrandsUiCard, StrandsUiButton, StrandsUiInput, StrandsUiAlert, StrandsUiLink, StrandsUiTabs } from '../ui'\nimport StrandsSecuredFooter from './StrandsSecuredFooter.vue'\nimport StrandsMfaVerification from './StrandsMfaVerification.vue'\nimport { useStrandsConfig, type StrandsAuthConfig } from '../composables/useStrandsConfig'\nimport { useOAuthProviders } from '../composables/useOAuthProviders'\nimport { useStrandsAuth } from '../composables/useStrandsAuth'\nimport type { AuthResponse } from '../../types'\n\ninterface Props {\n mode?: 'signin' | 'signup' | 'reset-password'\n redirectUrl?: string\n inModal?: boolean\n // Fallback config if no global config is provided\n config?: StrandsAuthConfig\n}\n\ninterface Emits {\n (e: 'success', user: any): void\n (e: 'error', error: string): void\n (e: 'forgot-password'): void\n (e: 'password-reset-sent', email: string): void\n (e: 'mode-changed', mode: 'signin' | 'signup' | 'reset-password'): void\n}\n\nconst props = withDefaults(defineProps<Props>(), {\n mode: 'signin',\n inModal: false,\n})\n\nconst emit = defineEmits<Emits>()\n\n// Get configuration\nconst { getUrl, getSupportEmail } = useStrandsConfig(props.config)\n\n// Authentication state management\nconst { \n signIn, \n setAuthData, \n mfaRequired, \n availableMfaMethods,\n verifyMfa,\n sendMfaEmailCode,\n currentUser,\n loadingMessage\n} = useStrandsAuth()\n\n// OAuth providers management\nconst { \n enabledProviders, \n loading: oauthLoading, \n error: oauthError,\n fetchProviders,\n redirectToProvider,\n getProviderIcon\n} = useOAuthProviders({\n redirectUrl: props.redirectUrl,\n})\n\n// Fetch OAuth providers on component mount\nonMounted(() => {\n fetchProviders().catch(err => {\n console.warn('Failed to fetch OAuth providers:', err)\n })\n})\n\n// Computed property to determine which providers to show\nconst displayProviders = computed(() => {\n // Only show providers from API\n return enabledProviders.value\n})\n\n// Auth API functions\nconst authApi = {\n async signIn(email: string, password: string): Promise<AuthResponse> {\n const response = await fetch(getUrl('signIn'), {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify({ email, password }),\n })\n\n if (!response.ok) {\n if (response.status === 401) {\n throw new Error('Invalid email or password')\n } else if (response.status === 403) {\n throw new Error('Please verify your email address before signing in')\n } else {\n throw new Error(`Sign in failed: ${response.status} ${response.statusText}`)\n }\n }\n\n const result: AuthResponse = await response.json()\n return result\n },\n\n async signUp(email: string, password: string, firstName: string, lastName: string) {\n const response = await fetch(getUrl('signUp'), {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify({ email, password, firstName, lastName }),\n })\n\n if (!response.ok) {\n const errorData = await response.json().catch(() => ({}))\n throw new Error(errorData.error?.message || `HTTP ${response.status}: ${response.statusText}`)\n }\n\n const result = await response.json()\n \n return result.message\n },\n\n async requestPasswordReset(email: string) {\n // Integration point: This endpoint needs to be added to the accounts-api\n // For now, we'll show a placeholder message\n throw new Error('Password reset functionality is not yet implemented in the API. Please contact support.')\n \n /* When the endpoint is added, use this:\n const response = await fetch(getUrl('passwordReset'), {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify({ email }),\n })\n\n if (!response.ok) {\n const errorData = await response.json().catch(() => ({}))\n throw new Error(errorData.error?.message || `HTTP ${response.status}: ${response.statusText}`)\n }\n\n const result = await response.json()\n if (!result.success) {\n throw new Error(result.error?.message || 'Password reset request failed')\n }\n\n return result.data\n */\n }\n}\n\nconst currentMode = ref(props.mode)\nconst buttonLoading = ref(false)\nconst error = ref('')\nconst isPasswordResetSubmitted = ref(false)\nconst showMfaVerification = ref(false)\n\nconst form = reactive({\n firstName: '',\n lastName: '',\n email: '',\n password: '',\n confirmPassword: ''\n})\n\nconst isSignUp = computed(() => currentMode.value === 'signup')\nconst isPasswordReset = computed(() => currentMode.value === 'reset-password')\n\nconst isPasswordMatch = computed(() => {\n return form.password === form.confirmPassword\n})\n\nconst isFormValid = computed(() => {\n if (isPasswordReset.value) {\n return form.email.trim() && !isPasswordResetSubmitted.value\n }\n\n if (isSignUp.value) {\n return form.email.trim()\n }\n\n return form.email.trim() && form.password\n})\n\n// Password strength constants for better performance\nconst PASSWORD_STRENGTH_CONFIGS = {\n weak: {\n label: 'Weak',\n color: 'border-red-300',\n bgColor: 'bg-red-400',\n textColor: 'text-red-600',\n width: 33\n },\n medium: {\n label: 'Medium',\n color: 'border-yellow-300',\n bgColor: 'bg-yellow-400',\n textColor: 'text-yellow-600',\n width: 66\n },\n strong: {\n label: 'Strong',\n color: 'border-emerald-300',\n bgColor: 'bg-emerald-400',\n textColor: 'text-emerald-600',\n width: 100\n }\n} as const\n\nconst getPasswordStrength = (password: string) => {\n let score = 0\n\n if (password.length >= 8) score += 1\n if (password.length >= 12) score += 1\n if (/[a-z]/.test(password)) score += 1\n if (/[A-Z]/.test(password)) score += 1\n if (/[0-9]/.test(password)) score += 1\n if (/[^A-Za-z0-9]/.test(password)) score += 1\n\n const config = score <= 2 ? PASSWORD_STRENGTH_CONFIGS.weak \n : score <= 4 ? PASSWORD_STRENGTH_CONFIGS.medium \n : PASSWORD_STRENGTH_CONFIGS.strong\n\n return { score, ...config }\n}\n\n// Watch for MFA requirement\nwatch(mfaRequired, (required) => {\n if (required) {\n showMfaVerification.value = true\n }\n}, { immediate: true })\n\n// MFA handlers\nconst handleMfaSuccess = () => {\n showMfaVerification.value = false\n // The auth composable will have updated the user state\n emit('success', currentUser.value)\n}\n\nconst handleMfaClose = () => {\n showMfaVerification.value = false\n // Reset form or allow user to try again\n}\n\nconst handleMfaError = (errorMessage: string) => {\n error.value = errorMessage\n emit('error', errorMessage)\n}\n\nconst handleAuth = async () => {\n buttonLoading.value = true\n error.value = ''\n\n try {\n if (isPasswordReset.value) {\n // Handle password reset\n await authApi.requestPasswordReset(form.email)\n isPasswordResetSubmitted.value = true\n emit('password-reset-sent', form.email)\n } else if (isSignUp.value) {\n // Handle sign up\n const response = await authApi.signUp(\n form.email,\n form.password,\n form.firstName,\n form.lastName\n )\n emit('success', response.user)\n } else {\n // Handle sign in using MFA-enabled composable\n const response = await signIn({\n email: form.email,\n password: form.password\n })\n \n // If MFA is not required, emit success immediately\n if (!response.mfa_required) {\n emit('success', response.user)\n }\n // If MFA is required, the MFA modal will be shown automatically\n }\n } catch (err) {\n const errorMessage = err instanceof Error ? err.message : 'An unexpected error occurred'\n error.value = errorMessage\n emit('error', errorMessage)\n } finally {\n buttonLoading.value = false\n }\n}\n\nconst handleOAuthAuth = async (providerId: string) => {\n try {\n await redirectToProvider(providerId, {\n redirectUrl: props.redirectUrl,\n })\n } catch (err) {\n const errorMessage = err instanceof Error ? err.message : `Failed to ${isSignUp.value ? 'sign up' : 'sign in'} with ${providerId}`\n error.value = errorMessage\n emit('error', errorMessage)\n }\n}\n\n// Watch for prop changes\nwatch(() => props.mode, (newMode) => {\n currentMode.value = newMode\n})\n\n// Watch for mode changes to clear form\nwatch(currentMode, (newMode) => {\n error.value = ''\n isPasswordResetSubmitted.value = false\n // Clear form when switching modes\n form.firstName = ''\n form.lastName = ''\n form.email = ''\n form.password = ''\n form.confirmPassword = ''\n emit('mode-changed', newMode)\n})\n\n// Enhanced transition handlers with staggered timing for multiple elements\nlet transitionCounter = 0\n\nconst onBeforeEnter = (el: Element) => {\n const element = el as HTMLElement\n // Set initial state immediately without any margins or padding\n element.style.height = '0'\n element.style.opacity = '0'\n element.style.marginTop = '0'\n element.style.marginBottom = '0'\n element.style.paddingTop = '0'\n element.style.paddingBottom = '0'\n element.style.overflow = 'hidden'\n}\n\nconst onEnter = (el: Element, done: () => void) => {\n const element = el as HTMLElement\n \n // Add small stagger delay for multiple elements\n const currentIndex = transitionCounter++\n const staggerDelay = currentIndex * 50 // 50ms stagger\n \n setTimeout(() => {\n // Force a reflow to ensure the initial state is applied\n element.offsetHeight\n \n // Get the natural height by temporarily removing height constraint\n element.style.height = 'auto'\n const height = element.offsetHeight\n element.style.height = '0'\n \n // Force another reflow\n element.offsetHeight\n \n // Start the transition\n element.style.transition = 'height 350ms cubic-bezier(0.23, 1, 0.32, 1), opacity 350ms cubic-bezier(0.23, 1, 0.32, 1), margin 350ms cubic-bezier(0.23, 1, 0.32, 1), padding 350ms cubic-bezier(0.23, 1, 0.32, 1)'\n \n // Apply final state\n requestAnimationFrame(() => {\n element.style.height = height + 'px'\n element.style.opacity = '1'\n element.style.marginTop = ''\n element.style.marginBottom = ''\n element.style.paddingTop = ''\n element.style.paddingBottom = ''\n })\n \n // Clean up after transition\n setTimeout(() => {\n element.style.height = ''\n element.style.transition = ''\n element.style.overflow = ''\n done()\n }, 350)\n }, staggerDelay)\n}\n\nconst onBeforeLeave = (el: Element) => {\n const element = el as HTMLElement\n // Set the current height explicitly before starting transition\n const height = element.offsetHeight\n element.style.height = height + 'px'\n element.style.overflow = 'hidden'\n \n // Reset counter when elements start leaving\n transitionCounter = 0\n}\n\nconst onLeave = (el: Element, done: () => void) => {\n const element = el as HTMLElement\n \n // Add small stagger delay for leave transitions too\n const currentIndex = transitionCounter++\n const staggerDelay = currentIndex * 30 // 30ms stagger for leaving\n \n setTimeout(() => {\n // Force a reflow\n element.offsetHeight\n \n // Start the transition with slightly faster leave animation\n element.style.transition = 'height 300ms cubic-bezier(0.23, 1, 0.32, 1), opacity 300ms cubic-bezier(0.23, 1, 0.32, 1), margin 300ms cubic-bezier(0.23, 1, 0.32, 1), padding 300ms cubic-bezier(0.23, 1, 0.32, 1)'\n \n // Apply final state\n requestAnimationFrame(() => {\n element.style.height = '0'\n element.style.opacity = '0'\n element.style.marginTop = '0'\n element.style.marginBottom = '0'\n element.style.paddingTop = '0'\n element.style.paddingBottom = '0'\n })\n \n // Clean up after transition\n setTimeout(() => {\n element.style.height = ''\n element.style.opacity = ''\n element.style.margin = ''\n element.style.padding = ''\n element.style.transition = ''\n element.style.overflow = ''\n done()\n }, 300)\n }, staggerDelay)\n}\n\nconst onAfterLeave = (el: Element) => {\n const element = el as HTMLElement\n // Final cleanup - ensure all inline styles are removed\n element.style.height = ''\n element.style.opacity = ''\n element.style.margin = ''\n element.style.padding = ''\n element.style.transition = ''\n element.style.overflow = ''\n}\n</script>\n\n<style scoped>\n/* Simple fade transition - gentle and smooth */\n.fade-enter-active,\n.fade-leave-active {\n transition: opacity 350ms cubic-bezier(0.16, 1, 0.3, 1);\n}\n\n.fade-enter-from,\n.fade-leave-to {\n opacity: 0;\n}\n\n/* Smooth height transitions - handled entirely by JavaScript */\n.smooth-height-enter-active,\n.smooth-height-leave-active {\n /* JavaScript handles all transition logic */\n}\n\n/* Support block transition - gentle fade with subtle scale */\n.support-fade-enter-active,\n.support-fade-leave-active {\n transition: all 400ms cubic-bezier(0.16, 1, 0.3, 1);\n}\n\n.support-fade-enter-from {\n opacity: 0;\n transform: scale(0.97) translateY(8px);\n}\n\n.support-fade-leave-to {\n opacity: 0;\n transform: scale(0.99) translateY(-4px);\n}\n\n.support-fade-enter-to,\n.support-fade-leave-from {\n opacity: 1;\n transform: scale(1) translateY(0);\n}\n\n/* Expand transition - for alerts using modern height animation */\n.expand-enter-active,\n.expand-leave-active {\n overflow: hidden;\n}\n\n/* Modern browsers with interpolate-size support for expand */\n@supports (interpolate-size: allow-keywords) {\n .expand-enter-active,\n .expand-leave-active {\n interpolate-size: allow-keywords;\n }\n \n .expand-enter-active {\n transition: \n opacity 550ms cubic-bezier(0.16, 1, 0.3, 1),\n height 550ms cubic-bezier(0.16, 1, 0.3, 1),\n transform 550ms cubic-bezier(0.16, 1, 0.3, 1);\n }\n \n .expand-leave-active {\n transition: \n opacity 550ms cubic-bezier(0.16, 1, 0.3, 1),\n height 550ms cubic-bezier(0.16, 1, 0.3, 1),\n transform 550ms cubic-bezier(0.16, 1, 0.3, 1);\n }\n \n .expand-enter-from {\n opacity: 0;\n height: 0;\n transform: scale(0.99) translateY(-2px);\n }\n \n .expand-leave-to {\n opacity: 0;\n height: 0;\n transform: scale(0.997) translateY(1px);\n }\n \n .expand-enter-to,\n .expand-leave-from {\n opacity: 1;\n height: auto;\n transform: scale(1) translateY(0);\n }\n}\n\n/* Fallback for expand in older browsers */\n@supports not (interpolate-size: allow-keywords) {\n .expand-enter-active {\n transition: \n opacity 550ms cubic-bezier(0.16, 1, 0.3, 1),\n max-height 550ms cubic-bezier(0.16, 1, 0.3, 1),\n transform 550ms cubic-bezier(0.16, 1, 0.3, 1);\n }\n \n .expand-leave-active {\n transition: \n opacity 550ms cubic-bezier(0.16, 1, 0.3, 1),\n max-height 550ms cubic-bezier(0.16, 1, 0.3, 1),\n transform 550ms cubic-bezier(0.16, 1, 0.3, 1);\n }\n \n .expand-enter-from {\n opacity: 0;\n max-height: 0;\n transform: scale(0.99) translateY(-2px);\n }\n \n .expand-leave-to {\n opacity: 0;\n max-height: 0;\n transform: scale(0.997) translateY(1px);\n }\n \n .expand-enter-to,\n .expand-leave-from {\n opacity: 1;\n max-height: 150px;\n transform: scale(1) translateY(0);\n }\n}\n\n/* Loading pulse animation */\n@keyframes pulse {\n 0%, 100% {\n opacity: 1;\n }\n 50% {\n opacity: 0.5;\n }\n}\n\n.animate-pulse {\n animation: pulse 2s cubic-bezier(0.4, 0, 0.6, 1) infinite;\n}\n\n/* Slide up animation for main container - elegant entrance */\n@keyframes slide-up {\n from {\n opacity: 0;\n transform: translateY(24px) scale(0.96);\n filter: blur(2px);\n }\n to {\n opacity: 1;\n transform: translateY(0) scale(1);\n filter: blur(0px);\n }\n}\n\n.animate-slide-up {\n animation: slide-up 600ms cubic-bezier(0.25, 0.46, 0.45, 0.94);\n}\n\n/* Fade in animation for alerts - gentle appearance */\n@keyframes fade-in {\n from {\n opacity: 0;\n transform: scale(0.97) translateY(6px);\n }\n to {\n opacity: 1;\n transform: scale(1) translateY(0);\n }\n}\n\n.animate-fade-in {\n animation: fade-in 400ms cubic-bezier(0.25, 0.46, 0.45, 0.94);\n}\n\n/* Email field spacing animation */\n.email-field-spacing {\n transition: margin-bottom 500ms cubic-bezier(0.16, 1, 0.3, 1);\n}\n\n.email-field-spacing.has-password {\n margin-bottom: 1rem; /* mb-4 equivalent */\n}\n\n.email-field-spacing.no-password {\n margin-bottom: 0;\n}\n\n/* Password field transitions now handled by JavaScript smooth-height system */\n\n/* Auth Container Styles */\n.auth-full-width {\n width: 100%;\n}\n\n.auth-min-width {\n min-width: 420px;\n}\n\n.auth-max-width {\n max-width: 28rem;\n}\n\n.auth-center {\n margin-left: auto;\n margin-right: auto;\n}\n\n.auth-slide-up {\n animation: slide-up 600ms cubic-bezier(0.25, 0.46, 0.45, 0.94);\n}\n\n.auth-card-modern {\n background: white;\n border-radius: 0.5rem;\n padding: 2rem;\n box-shadow: 0 10px 25px -5px rgba(0, 0, 0, 0.1), 0 10px 10px -5px rgba(0, 0, 0, 0.04);\n}\n\n/* Header Styles */\n.auth-header {\n text-align: center;\n margin-bottom: 2rem;\n}\n\n.auth-title {\n font-size: 1.875rem;\n font-weight: 700;\n background: linear-gradient(135deg, #EA00A8 0%, #FF6B9D 100%);\n background-clip: text;\n -webkit-background-clip: text;\n -webkit-text-fill-color: transparent;\n margin-bottom: 0.5rem;\n}\n\n.auth-subtitle {\n color: #737373;\n}\n\n/* Tabs Container */\n.auth-tabs-container {\n margin-bottom: 2rem;\n}\n\n/* OAuth Provider Styles */\n.auth-oauth-providers {\n display: flex;\n flex-direction: column;\n gap: 0.75rem;\n margin-bottom: 1.5rem;\n}\n\n.auth-oauth-button {\n /* Button styles will be handled by the UiButton component */\n}\n\n.auth-oauth-icon-container {\n width: 1.25rem;\n height: 1.25rem;\n display: flex;\n align-items: center;\n justify-content: center;\n}\n\n.auth-oauth-icon {\n width: 1.25rem;\n height: 1.25rem;\n}\n\n.auth-oauth-github {\n fill: currentColor;\n}\n\n.auth-oauth-generic-icon {\n width: 1.25rem;\n height: 1.25rem;\n border-radius: 50%;\n background-color: #d4d4d8;\n display: flex;\n align-items: center;\n justify-content: center;\n}\n\n.auth-oauth-generic-text {\n font-size: 0.75rem;\n font-weight: 600;\n color: #525252;\n}\n\n.auth-oauth-text {\n font-weight: 500;\n}\n\n/* Divider Styles */\n.auth-divider {\n position: relative;\n margin: 1.5rem 0;\n text-align: center;\n}\n\n.auth-divider::before {\n content: '';\n position: absolute;\n top: 50%;\n left: 0;\n right: 0;\n height: 1px;\n background: #e5e5e5;\n}\n\n.auth-divider-text {\n background: white;\n padding: 0 1rem;\n color: #737373;\n font-size: 0.875rem;\n position: relative;\n z-index: 1;\n}\n\n/* Form Styles */\n.auth-form {\n display: flex;\n flex-direction: column;\n gap: 1.5rem;\n}\n\n.auth-password-field {\n margin-bottom: 1rem;\n}\n\n.auth-password-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n margin-bottom: 0.5rem;\n}\n\n.auth-password-label {\n font-size: 0.875rem;\n font-weight: 500;\n color: #374151;\n}\n\n/* Alert Styles */\n.auth-success-alert {\n margin-top: 1.5rem;\n animation: fade-in 400ms cubic-bezier(0.25, 0.46, 0.45, 0.94);\n}\n\n.auth-error-alert {\n margin-top: 1.5rem;\n animation: fade-in 400ms cubic-bezier(0.25, 0.46, 0.45, 0.94);\n}\n\n/* Back Link Styles */\n.auth-back-link-container {\n margin-top: 2rem;\n text-align: center;\n}\n\n.auth-back-link {\n display: inline-flex;\n align-items: center;\n gap: 0.5rem;\n}\n\n.auth-back-icon {\n width: 1rem;\n height: 1rem;\n}\n\n/* Support Text */\n.auth-support-text {\n color: #a3a3a3;\n font-size: 0.875rem;\n}\n\n/* Modal-specific styles - removes border, radius, background, and padding */\n.auth-container-modal {\n}\n\n.auth-content-modal {\n /* Remove card styling when in modal */\n background: transparent;\n border: none;\n border-radius: 0;\n padding: 0;\n box-shadow: none;\n}\n\n</style>","<template>\n <svg viewBox=\"0 0 24 24\" class=\"accui-w-5 accui-h-5\">\n <path fill=\"#4285F4\"\n d=\"M22.56 12.25c0-.78-.07-1.53-.2-2.25H12v4.26h5.92c-.26 1.37-1.04 2.53-2.21 3.31v2.77h3.57c2.08-1.92 3.28-4.74 3.28-8.09z\" />\n <path fill=\"#34A853\"\n d=\"M12 23c2.97 0 5.46-.98 7.28-2.66l-3.57-2.77c-.98.66-2.23 1.06-3.71 1.06-2.86 0-5.29-1.93-6.16-4.53H2.18v2.84C3.99 20.53 7.7 23 12 23z\" />\n <path fill=\"#FBBC05\"\n d=\"M5.84 14.09c-.22-.66-.35-1.36-.35-2.09s.13-1.43.35-2.09V7.07H2.18C1.43 8.55 1 10.22 1 12s.43 3.45 1.18 4.93l2.85-2.22.81-.62z\" />\n <path fill=\"#EA4335\"\n d=\"M12 5.38c1.62 0 3.06.56 4.21 1.64l3.15-3.15C17.45 2.09 14.97 1 12 1 7.7 1 3.99 3.47 2.18 7.07l3.66 2.84c.87-2.6 3.3-4.53 6.16-4.53z\" />\n </svg>\n</template>\n\n<script setup lang=\"ts\">\n// Optimized Google icon component\n</script>","<template>\n <svg class=\"accui-w-5 accui-h-5 accui-fill-current\" viewBox=\"0 0 24 24\">\n <path\n d=\"M12 0c-6.626 0-12 5.373-12 12 0 5.302 3.438 9.8 8.207 11.387.599.111.793-.261.793-.577v-2.234c-3.338.726-4.033-1.416-4.033-1.416-.546-1.387-1.333-1.756-1.333-1.756-1.089-.745.083-.729.083-.729 1.205.084 1.839 1.237 1.839 1.237 1.07 1.834 2.807 1.304 3.492.997.107-.775.418-1.305.762-1.604-2.665-.305-5.467-1.334-5.467-5.931 0-1.311.469-2.381 1.236-3.221-.124-.303-.535-1.524.117-3.176 0 0 1.008-.322 3.301 1.23.957-.266 1.983-.399 3.003-.404 1.02.005 2.047.138 3.006.404 2.291-1.552 3.297-1.23 3.297-1.23.653 1.653.242 2.874.118 3.176.77.84 1.235 1.911 1.235 3.221 0 4.609-2.807 5.624-5.479 5.921.43.372.823 1.102.823 2.222v3.293c0 .319.192.694.801.576 4.765-1.589 8.199-6.086 8.199-11.386 0-6.627-5.373-12-12-12z\" />\n </svg>\n</template>\n\n<script setup lang=\"ts\">\n// Optimized GitHub icon component\n</script>","<template>\n <div class=\"accui-component-scope\">\n <div class=\"accui-w-full accui-min-w-100 accui-max-w-md accui-mx-auto accui-animate-slide-up\">\n <StrandsUiCard variant=\"modern\">\n <!-- Header -->\n <div class=\"accui-text-center accui-mb-8\">\n <h1 class=\"accui-text-3xl accui-font-bold accui-text-gradient accui-mb-2\">Welcome back</h1>\n <p class=\"accui-text-neutral-600\">Sign in to your account to continue</p>\n </div>\n\n <!-- OAuth Providers with v-memo optimization -->\n <div v-if=\"enabledProviders?.length\" class=\"accui-space-y-3 accui-mb-6\">\n <StrandsUiButton \n v-for=\"provider in enabledProviders\" \n v-memo=\"[provider.id, provider.name, provider.displayName, oauthLoading]\"\n :key=\"provider.id\" \n variant=\"outline\" \n full-width\n :disabled=\"oauthLoading\"\n @click=\"handleOAuthSignIn(provider.id)\" \n class=\"btn-oauth accui-group\"\n >\n <div class=\"accui-w-5 accui-h-5 accui-flex accui-items-center accui-justify-center\">\n <!-- Dynamic provider icons -->\n <div v-if=\"provider.icon || provider.iconUrl\" class=\"accui-w-5 accui-h-5\">\n <img :src=\"provider.icon || provider.iconUrl\" :alt=\"`${provider.displayName || provider.name} icon`\" class=\"accui-w-5 accui-h-5\" />\n </div>\n <!-- Optimized built-in icons for common providers -->\n <IconGoogle v-else-if=\"provider.id === 'google'\" />\n <IconGithub v-else-if=\"provider.id === 'github'\" />\n <div v-else class=\"accui-w-5 accui-h-5 accui-rounded-full accui-bg-neutral-300 accui-flex accui-items-center accui-justify-center\">\n <span class=\"accui-text-xs accui-font-semibold accui-text-neutral-600\">{{ (provider.displayName || provider.name).charAt(0).toUpperCase() }}</span>\n </div>\n </div>\n <span class=\"accui-font-medium\">Continue with {{ provider.displayName || provider.name }}</span>\n </StrandsUiButton>\n </div>\n\n <!-- Divider -->\n <div v-if=\"enabledProviders?.length\" class=\"divider-with-text\">\n <span class=\"divider-text\">Or sign in with email</span>\n </div>\n\n <!-- Email/Password Form -->\n <form @submit.prevent=\"handleSignIn\" class=\"accui-gap-6 accui-flex accui-flex-col\">\n <div>\n <!-- Email -->\n <div class=\"email-field-spacing has-password\">\n <StrandsUiInput id=\"email\" v-model=\"form.email\" type=\"email\" label=\"Email address\"\n placeholder=\"Enter your email address\" autocomplete=\"email\" required\n :error=\"error ? 'Invalid email or password' : undefined\" />\n </div>\n\n <!-- Password -->\n <div class=\"accui-mb-4\">\n <span class=\"accui-text-sm accui-font-medium accui-text-neutral-700 accui-block accui-mb-2\">Password</span>\n <StrandsUiInput id=\"password\" v-model=\"form.password\" type=\"password\" placeholder=\"Enter your password\"\n autocomplete=\"current-password\" required :error=\"error ? 'Invalid email or password' : undefined\" />\n </div>\n </div>\n\n <StrandsUiButton type=\"submit\" variant=\"primary\" full-width :disabled=\"loading || !form.email || !form.password\"\n :loading=\"loading\" :loading-text=\"'Signing in...'\">\n Sign in\n </StrandsUiButton>\n </form>\n\n <!-- Forgot password link - moved outside form to control tab order -->\n <div class=\"accui-text-center accui-mt-4\">\n <StrandsUiLink @click=\"$emit('forgot-password')\" class=\"accui-text-sm\">\n Forgot password?\n </StrandsUiLink>\n </div>\n\n <!-- Error Alert -->\n <StrandsUiAlert v-if=\"error\" variant=\"error\" :message=\"error\" class=\"accui-mt-6 accui-animate-fade-in\" dismissible\n @dismiss=\"error = ''\" />\n\n <!-- Sign up link -->\n <div class=\"accui-mt-8 accui-text-center\">\n <p class=\"accui-text-sm accui-text-neutral-600\">\n Don't have an account?\n <StrandsUiLink @click=\"$emit('switch-to-signup')\">\n Sign up\n </StrandsUiLink>\n </p>\n </div>\n\n \n <!-- Secured by footer -->\n <StrandsSecuredFooter :config=\"props.config\">\n <!-- Need help -->\n <div v-if=\"getSupportEmail()\">\n <p class=\"accui-text-neutral-400 accui-text-sm\">\n Need help?\n <StrandsUiLink variant=\"primary\" :href=\"`mailto:${getSupportEmail()}`\">\n Contact Support\n </StrandsUiLink>\n </p>\n </div>\n </StrandsSecuredFooter>\n </StrandsUiCard>\n \n <!-- MFA Verification Modal -->\n <StrandsMfaVerification\n :show=\"showMfaVerification\"\n :available-mfa-methods=\"availableMfaMethods\"\n :session-id=\"mfaSessionId\"\n @success=\"handleMfaSuccess\"\n @close=\"handleMfaClose\"\n @error=\"handleMfaError\"\n />\n \n </div>\n </div>\n</template>\n\n<script setup lang=\"ts\">\nimport { ref, reactive, computed, onMounted, watch } from 'vue'\nimport { StrandsUiCard, StrandsUiButton, StrandsUiInput, StrandsUiAlert, StrandsUiLink } from '../ui'\nimport StrandsSecuredFooter from './StrandsSecuredFooter.vue'\nimport StrandsMfaVerification from './StrandsMfaVerification.vue'\nimport { IconGoogle, IconGithub } from './icons'\nimport { useStrandsConfig, type StrandsAuthConfig } from '../composables/useStrandsConfig'\nimport { useOAuthProviders } from '../composables/useOAuthProviders'\nimport { useStrandsAuth } from '../composables/useStrandsAuth'\nimport type { AuthResponse } from '../../types'\n\ninterface Props {\n redirectUrl?: string\n oauthScopes?: string[]\n config?: StrandsAuthConfig\n}\n\ninterface Emits {\n (e: 'success', user: any): void\n (e: 'error', error: string): void\n (e: 'forgot-password'): void\n (e: 'switch-to-signup'): void\n}\n\nconst props = withDefaults(defineProps<Props>(), {\n oauthScopes: () => []\n})\n\nconst emit = defineEmits<Emits>()\n\n// Get configuration\nconst { getUrl, getSupportEmail } = useStrandsConfig(props.config)\n\n// Authentication state management\nconst { \n signIn,\n mfaRequired,\n mfaSessionId,\n availableMfaMethods,\n loading: authLoading,\n currentUser,\n sendMfaEmailCode \n} = useStrandsAuth()\n\n// OAuth providers management\nconst { \n enabledProviders, \n loading: oauthLoading, \n error: oauthError,\n fetchProviders,\n redirectToProvider\n} = useOAuthProviders({\n redirectUrl: props.redirectUrl,\n scopes: props.oauthScopes\n})\n\n// Fetch OAuth providers on component mount\nonMounted(() => {\n fetchProviders().catch(err => {\n console.warn('Failed to fetch OAuth providers:', err)\n })\n})\n\nconst loading = computed(() => authLoading.value)\nconst error = ref('')\nconst showMfaVerification = ref(false)\n\n// Watch for MFA requirement\nwatch(mfaRequired, (required) => {\n if (required) {\n showMfaVerification.value = true\n }\n})\n\nconst form = reactive({\n email: '',\n password: ''\n})\n\nconst handleSignIn = async () => {\n error.value = ''\n \n try {\n const authData = await signIn({\n email: form.email,\n password: form.password,\n })\n \n // If MFA is not required, emit success immediately\n if (!authData.mfa_required) {\n emit('success', authData.user)\n }\n // If MFA is required, the watch on mfaRequired will show the MFA modal\n } catch (err) {\n const errorMessage = err instanceof Error ? err.message : 'Sign in failed'\n error.value = errorMessage\n emit('error', errorMessage)\n }\n}\n\nconst handleMfaSuccess = () => {\n showMfaVerification.value = false\n // The auth composable will have updated the user state\n emit('success', currentUser.value)\n}\n\nconst handleMfaClose = () => {\n showMfaVerification.value = false\n // Reset form or allow user to try again\n}\n\nconst handleMfaError = (errorMessage: string) => {\n error.value = errorMessage\n emit('error', errorMessage)\n}\n\nconst handleOAuthSignIn = async (providerId: string) => {\n try {\n await redirectToProvider(providerId, {\n redirectUrl: props.redirectUrl,\n scopes: props.oauthScopes\n })\n } catch (err) {\n const errorMessage = err instanceof Error ? err.message : `Failed to sign in with ${providerId}`\n error.value = errorMessage\n emit('error', errorMessage)\n }\n}\n</script>\n\n<style scoped>\n/* Email field spacing to match StrandsAuth */\n.email-field-spacing {\n transition: margin-bottom 500ms cubic-bezier(0.16, 1, 0.3, 1);\n}\n\n.email-field-spacing.has-password {\n margin-bottom: 1rem; /* mb-4 equivalent */\n}\n\n.email-field-spacing.no-password {\n margin-bottom: 0;\n}\n\n/* Override accui- prefixed Tailwind classes with CSS properties */\n.accui-w-full {\n width: 100%;\n}\n\n.accui-min-w-100 {\n min-width: 25rem;\n}\n\n.accui-max-w-md {\n max-width: 28rem;\n}\n\n.accui-mx-auto {\n margin-left: auto;\n margin-right: auto;\n}\n\n.accui-animate-slide-up {\n animation: slideUp 0.3s ease-out;\n}\n\n.accui-text-center {\n text-align: center;\n}\n\n.accui-mb-8 {\n margin-bottom: 2rem;\n}\n\n.accui-text-3xl {\n font-size: 1.875rem;\n}\n\n.accui-font-bold {\n font-weight: 700;\n}\n\n.accui-text-gradient {\n background: linear-gradient(to right, var(--strands-500, #EA00A8), var(--strands-600, #db2777));\n background-clip: text;\n -webkit-background-clip: text;\n color: transparent;\n}\n\n.accui-mb-2 {\n margin-bottom: 0.5rem;\n}\n\n.accui-text-neutral-600 {\n color: var(--neutral-600, #525252);\n}\n\n.accui-space-y-3 > * + * {\n margin-top: 0.75rem;\n}\n\n.accui-mb-6 {\n margin-bottom: 1.5rem;\n}\n\n.accui-w-5 {\n width: 1.25rem;\n}\n\n.accui-h-5 {\n height: 1.25rem;\n}\n\n.accui-flex {\n display: flex;\n}\n\n.accui-items-center {\n align-items: center;\n}\n\n.accui-justify-center {\n justify-content: center;\n}\n\n.accui-rounded-full {\n border-radius: 50%;\n}\n\n.accui-bg-neutral-300 {\n background-color: var(--neutral-300, #d4d4d4);\n}\n\n.accui-text-xs {\n font-size: 0.75rem;\n}\n\n.accui-font-semibold {\n font-weight: 600;\n}\n\n.accui-text-neutral-600 {\n color: var(--neutral-600, #525252);\n}\n\n.accui-font-medium {\n font-weight: 500;\n}\n\n.accui-gap-6 {\n gap: 1.5rem;\n}\n\n.accui-flex-col {\n flex-direction: column;\n}\n\n.accui-mb-4 {\n margin-bottom: 1rem;\n}\n\n.accui-text-sm {\n font-size: 0.875rem;\n}\n\n.accui-text-neutral-700 {\n color: var(--neutral-700, #404040);\n}\n\n.accui-block {\n display: block;\n}\n\n.accui-mt-4 {\n margin-top: 1rem;\n}\n\n.accui-mt-6 {\n margin-top: 1.5rem;\n}\n\n.accui-animate-fade-in {\n animation: fadeIn 0.2s ease-out;\n}\n\n.accui-mt-8 {\n margin-top: 2rem;\n}\n\n.accui-text-neutral-400 {\n color: var(--neutral-400, #a3a3a3);\n}\n\n.accui-fill-current {\n fill: currentColor;\n}\n\n@keyframes slideUp {\n from {\n opacity: 0;\n transform: translateY(20px);\n }\n to {\n opacity: 1;\n transform: translateY(0);\n }\n}\n\n@keyframes fadeIn {\n from {\n opacity: 0;\n }\n to {\n opacity: 1;\n }\n}\n</style>","<template>\n <div class=\"accui-component-scope\">\n <div class=\"signup-container\">\n <!-- Success State -->\n <StrandsUiCard v-if=\"signupSuccess\" variant=\"modern\">\n <div class=\"signup-success\">\n <div class=\"signup-success-icon\">📧</div>\n <h1 class=\"signup-success-title\">{{ successTitle }}</h1>\n <p class=\"signup-success-message\">{{ successMessage }}</p>\n <div v-if=\"successEmail\" class=\"signup-success-email\">\n <strong>{{ successEmail }}</strong>\n </div>\n <p class=\"signup-success-instructions\">\n Click the link in your email to complete your account setup. The link will expire in 24 hours.\n </p>\n <StrandsUiButton\n variant=\"outline\"\n full-width\n @click=\"resetToForm\"\n >\n Send Another Link\n </StrandsUiButton>\n </div>\n </StrandsUiCard>\n\n <!-- Signup Form -->\n <StrandsUiCard v-else variant=\"modern\">\n <!-- Header -->\n <div class=\"signup-header\">\n <h1 class=\"signup-title\">Create account</h1>\n <p class=\"signup-subtitle\">We'll send you a magic link to get started</p>\n </div>\n\n <!-- OAuth Providers -->\n <div v-if=\"enabledProviders?.length\" class=\"oauth-providers\">\n <StrandsUiButton \n v-for=\"provider in enabledProviders\" \n :key=\"provider.id\" \n variant=\"outline\" \n full-width\n :disabled=\"oauthLoading\"\n @click=\"handleOAuthSignUp(provider.id)\" \n class=\"btn-oauth group\"\n >\n <div class=\"oauth-icon-container\">\n <!-- Dynamic provider icons -->\n <div v-if=\"provider.icon || provider.iconUrl\" class=\"oauth-icon\">\n <img :src=\"provider.icon || provider.iconUrl\" :alt=\"`${provider.displayName || provider.name} icon`\" class=\"oauth-icon-image\" />\n </div>\n <!-- Built-in SVG icons for common providers -->\n <svg v-else-if=\"provider.id === 'google'\" viewBox=\"0 0 24 24\" class=\"oauth-icon\">\n <path fill=\"#4285F4\"\n d=\"M22.56 12.25c0-.78-.07-1.53-.2-2.25H12v4.26h5.92c-.26 1.37-1.04 2.53-2.21 3.31v2.77h3.57c2.08-1.92 3.28-4.74 3.28-8.09z\" />\n <path fill=\"#34A853\"\n d=\"M12 23c2.97 0 5.46-.98 7.28-2.66l-3.57-2.77c-.98.66-2.23 1.06-3.71 1.06-2.86 0-5.29-1.93-6.16-4.53H2.18v2.84C3.99 20.53 7.7 23 12 23z\" />\n <path fill=\"#FBBC05\"\n d=\"M5.84 14.09c-.22-.66-.35-1.36-.35-2.09s.13-1.43.35-2.09V7.07H2.18C1.43 8.55 1 10.22 1 12s.43 3.45 1.18 4.93l2.85-2.22.81-.62z\" />\n <path fill=\"#EA4335\"\n d=\"M12 5.38c1.62 0 3.06.56 4.21 1.64l3.15-3.15C17.45 2.09 14.97 1 12 1 7.7 1 3.99 3.47 2.18 7.07l3.66 2.84c.87-2.6 3.3-4.53 6.16-4.53z\" />\n </svg>\n <svg v-else-if=\"provider.id === 'github'\" class=\"oauth-icon oauth-icon-github\" viewBox=\"0 0 24 24\">\n <path\n d=\"M12 0c-6.626 0-12 5.373-12 12 0 5.302 3.438 9.8 8.207 11.387.599.111.793-.261.793-.577v-2.234c-3.338.726-4.033-1.416-4.033-1.416-.546-1.387-1.333-1.756-1.333-1.756-1.089-.745.083-.729.083-.729 1.205.084 1.839 1.237 1.839 1.237 1.07 1.834 2.807 1.304 3.492.997.107-.775.418-1.305.762-1.604-2.665-.305-5.467-1.334-5.467-5.931 0-1.311.469-2.381 1.236-3.221-.124-.303-.535-1.524.117-3.176 0 0 1.008-.322 3.301 1.23.957-.266 1.983-.399 3.003-.404 1.02.005 2.047.138 3.006.404 2.291-1.552 3.297-1.23 3.297-1.23.653 1.653.242 2.874.118 3.176.77.84 1.235 1.911 1.235 3.221 0 4.609-2.807 5.624-5.479 5.921.43.372.823 1.102.823 2.222v3.293c0 .319.192.694.801.576 4.765-1.589 8.199-6.086 8.199-11.386 0-6.627-5.373-12-12-12z\" />\n </svg>\n <div v-else class=\"oauth-icon-fallback\">\n <span class=\"oauth-icon-fallback-text\">{{ (provider.displayName || provider.name).charAt(0).toUpperCase() }}</span>\n </div>\n </div>\n <span class=\"oauth-button-text\">Continue with {{ provider.displayName || provider.name }}</span>\n </StrandsUiButton>\n </div>\n\n <!-- Divider -->\n <div v-if=\"enabledProviders?.length\" class=\"divider-with-text\">\n <span class=\"divider-text\">Or create account with email</span>\n </div>\n\n <!-- Sign Up Form -->\n <form @submit.prevent=\"handleSignUp\" class=\"signup-form\">\n <!-- Email -->\n <div>\n <StrandsUiInput\n id=\"email\"\n v-model=\"form.email\"\n type=\"email\"\n label=\"Email address\"\n placeholder=\"Enter your email address\"\n autocomplete=\"email\"\n required\n :error=\"error\"\n />\n </div>\n\n <StrandsUiButton\n type=\"submit\"\n variant=\"primary\"\n full-width\n :disabled=\"loading\"\n :loading=\"loading\"\n loading-text=\"Sending magic link...\"\n >\n Send magic link\n </StrandsUiButton>\n </form>\n\n <!-- Error Alert -->\n <div v-if=\"error\" class=\"signup-error\">\n <div class=\"signup-error-content\">\n <div class=\"signup-error-icon-container\">\n <svg class=\"signup-error-icon\" fill=\"currentColor\" viewBox=\"0 0 20 20\">\n <path fill-rule=\"evenodd\"\n d=\"M10 18a8 8 0 100-16 8 8 0 000 16zM8.28 7.22a.75.75 0 00-1.06 1.06L8.94 10l-1.72 1.72a.75.75 0 101.06 1.06L10 11.06l1.72 1.72a.75.75 0 101.06-1.06L11.06 10l1.72-1.72a.75.75 0 00-1.06-1.06L10 8.94 8.28 7.22z\"\n clip-rule=\"evenodd\" />\n </svg>\n <p class=\"signup-error-message\">{{ error }}</p>\n </div>\n </div>\n </div>\n\n <!-- Sign in link -->\n <div class=\"signup-signin-link\">\n <p class=\"signup-signin-text\">\n Already have an account?\n <button type=\"button\"\n class=\"signup-signin-button\"\n @click=\"$emit('switch-to-signin')\">\n Sign in\n </button>\n </p>\n </div>\n\n <!-- Secured by footer -->\n <StrandsSecuredFooter :config=\"props.config\">\n <!-- Need help -->\n <div v-if=\"getSupportEmail()\">\n <p class=\"signup-support-text\">\n Need help?\n <StrandsUiLink variant=\"primary\" :href=\"`mailto:${getSupportEmail()}`\">\n Contact Support\n </StrandsUiLink>\n </p>\n </div>\n </StrandsSecuredFooter>\n </StrandsUiCard>\n </div>\n </div>\n</template>\n\n<script setup lang=\"ts\">\nimport { ref, reactive, computed, onMounted } from 'vue'\nimport { StrandsUiCard, StrandsUiButton, StrandsUiInput, StrandsUiAlert, StrandsUiLink } from '../ui'\nimport StrandsSecuredFooter from './StrandsSecuredFooter.vue'\nimport { useStrandsConfig, type StrandsAuthConfig } from '../composables/useStrandsConfig'\nimport { useOAuthProviders } from '../composables/useOAuthProviders'\n\ninterface Props {\n redirectUrl?: string\n oauthScopes?: string[]\n config?: StrandsAuthConfig\n}\n\ninterface Emits {\n (e: 'success', user: any): void\n (e: 'error', error: string): void\n (e: 'switch-to-signin'): void\n}\n\nconst props = withDefaults(defineProps<Props>(), {\n oauthScopes: () => []\n})\n\nconst emit = defineEmits<Emits>()\n\n// Get configuration\nconst { getUrl, getSupportEmail } = useStrandsConfig(props.config)\n\n// OAuth providers management\nconst { \n enabledProviders, \n loading: oauthLoading, \n error: oauthError,\n fetchProviders,\n redirectToProvider\n} = useOAuthProviders({\n redirectUrl: props.redirectUrl,\n scopes: props.oauthScopes\n})\n\n// Fetch OAuth providers on component mount\nonMounted(() => {\n fetchProviders().catch(err => {\n console.warn('Failed to fetch OAuth providers:', err)\n })\n})\n\nconst loading = ref(false)\nconst error = ref('')\nconst signupSuccess = ref(false)\nconst successMessage = ref('')\nconst successTitle = ref('Magic Link Sent!')\nconst successEmail = ref('')\n\nconst form = reactive({\n email: ''\n})\n\nconst isFormValid = computed(() => {\n return form.email.trim() && form.email.includes('@')\n})\n\nconst handleSignUp = async () => {\n loading.value = true\n error.value = ''\n\n try {\n const signUpUrl = getUrl('signUp')\n console.log('Attempting sign up to URL:', signUpUrl)\n \n const response = await fetch(signUpUrl, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify({\n email: form.email\n }),\n })\n\n if (process.env['NODE_ENV'] === 'development') {\n console.log('Sign up response status:', response.status)\n }\n\n if (!response.ok) {\n let errorMessage = `Sign up failed (${response.status})`\n try {\n const errorData = await response.json()\n errorMessage = errorData.message || errorData.error || errorMessage\n } catch {\n const errorText = await response.text()\n errorMessage = errorText || errorMessage\n }\n throw new Error(errorMessage)\n }\n\n const result = await response.json()\n console.log('Magic link sign up success:', result)\n \n // Handle success state internally\n signupSuccess.value = true\n successEmail.value = form.email\n successMessage.value = result.message || 'Magic link sent! Check your email.'\n \n // Set appropriate title based on message content\n if (result.message) {\n if (result.message.includes('already have an account') || result.message.includes('Welcome back')) {\n successTitle.value = 'Welcome Back!'\n } else if (result.message.includes('Magic link sent') || result.message.includes('Check your email')) {\n successTitle.value = 'Magic Link Sent!'\n } else {\n successTitle.value = 'Success!'\n }\n }\n \n // Still emit for any parent that might need it\n emit('success', {\n email: form.email,\n message: result.message || 'Magic link sent! Check your email.'\n })\n } catch (err) {\n console.error('Sign up error:', err)\n \n let errorMessage = 'Unable to send magic link. Please try again.'\n \n if (err instanceof Error) {\n if (err.message.includes('fetch')) {\n errorMessage = 'Unable to connect to authentication service. Please check your internet connection and try again.'\n } else if (err.message.includes('CORS')) {\n const supportEmail = getSupportEmail()\n errorMessage = supportEmail \n ? `Authentication service configuration error. Please contact ${supportEmail}.`\n : 'Authentication service configuration error.'\n } else {\n errorMessage = err.message\n }\n }\n \n error.value = errorMessage\n emit('error', errorMessage)\n } finally {\n loading.value = false\n }\n}\n\nconst resetToForm = () => {\n signupSuccess.value = false\n successMessage.value = ''\n successTitle.value = 'Magic Link Sent!'\n successEmail.value = ''\n form.email = ''\n error.value = ''\n}\n\nconst handleOAuthSignUp = async (providerId: string) => {\n try {\n await redirectToProvider(providerId, {\n redirectUrl: props.redirectUrl,\n scopes: props.oauthScopes\n })\n } catch (err) {\n const errorMessage = err instanceof Error ? err.message : `Failed to sign up with ${providerId}`\n error.value = errorMessage\n emit('error', errorMessage)\n }\n}\n</script>\n\n<style scoped>\n.signup-container {\n width: 100%;\n min-width: 25rem;\n max-width: 28rem;\n margin: 0 auto;\n animation: slideUp 0.3s ease-out;\n}\n\n@keyframes slideUp {\n from {\n opacity: 0;\n transform: translateY(20px);\n }\n to {\n opacity: 1;\n transform: translateY(0);\n }\n}\n\n/* Success State */\n.signup-success {\n text-align: center;\n}\n\n.signup-success-icon {\n color: #10b981;\n font-size: 3.75rem;\n margin-bottom: 1rem;\n}\n\n.signup-success-title {\n font-size: 1.5rem;\n font-weight: 700;\n color: #111827;\n margin-bottom: 0.5rem;\n}\n\n.signup-success-message {\n color: #6b7280;\n margin-bottom: 1rem;\n}\n\n.signup-success-email {\n font-size: 0.875rem;\n color: #6b7280;\n margin-bottom: 1rem;\n}\n\n.signup-success-instructions {\n font-size: 0.875rem;\n color: #6b7280;\n margin-bottom: 1.5rem;\n}\n\n/* Header */\n.signup-header {\n text-align: center;\n margin-bottom: 2rem;\n}\n\n.signup-title {\n font-size: 1.875rem;\n font-weight: 700;\n background: linear-gradient(135deg, #EA00A8 0%, #FF6B9D 50%, #B8006F 100%);\n -webkit-background-clip: text;\n background-clip: text;\n -webkit-text-fill-color: transparent;\n margin-bottom: 0.5rem;\n}\n\n.signup-subtitle {\n color: #6b7280;\n}\n\n/* OAuth Providers */\n.oauth-providers {\n display: flex;\n flex-direction: column;\n gap: 0.75rem;\n margin-bottom: 1.5rem;\n}\n\n.oauth-icon-container {\n width: 1.25rem;\n height: 1.25rem;\n display: flex;\n align-items: center;\n justify-content: center;\n}\n\n.oauth-icon {\n width: 1.25rem;\n height: 1.25rem;\n}\n\n.oauth-icon-image {\n width: 1.25rem;\n height: 1.25rem;\n}\n\n.oauth-icon-github {\n fill: currentColor;\n}\n\n.oauth-icon-fallback {\n width: 1.25rem;\n height: 1.25rem;\n border-radius: 50%;\n background-color: #d1d5db;\n display: flex;\n align-items: center;\n justify-content: center;\n}\n\n.oauth-icon-fallback-text {\n font-size: 0.75rem;\n font-weight: 600;\n color: #6b7280;\n}\n\n.oauth-button-text {\n font-weight: 500;\n}\n\n/* Form */\n.signup-form {\n display: flex;\n flex-direction: column;\n gap: 1.5rem;\n}\n\n/* Error Alert */\n.signup-error {\n margin-top: 1.5rem;\n animation: fadeIn 0.3s ease-out;\n}\n\n@keyframes fadeIn {\n from {\n opacity: 0;\n }\n to {\n opacity: 1;\n }\n}\n\n.signup-error-content {\n background-color: #fef2f2;\n border: 1px solid #fecaca;\n border-radius: 0.5rem;\n padding: 1rem;\n}\n\n.signup-error-icon-container {\n display: flex;\n align-items: flex-start;\n gap: 0.75rem;\n}\n\n.signup-error-icon {\n width: 1rem;\n height: 1rem;\n margin-top: 0.125rem;\n flex-shrink: 0;\n color: #dc2626;\n}\n\n.signup-error-message {\n font-weight: 500;\n color: #dc2626;\n}\n\n/* Sign in link */\n.signup-signin-link {\n margin-top: 2rem;\n text-align: center;\n}\n\n.signup-signin-text {\n font-size: 0.875rem;\n color: #6b7280;\n}\n\n.signup-signin-button {\n font-weight: 600;\n color: #EA00A8;\n background: none;\n border: none;\n cursor: pointer;\n transition: color 0.2s ease;\n margin-left: 0.25rem;\n}\n\n.signup-signin-button:hover {\n color: #B8006F;\n}\n\n/* Support text */\n.signup-support-text {\n color: #9ca3af;\n font-size: 0.875rem;\n}\n\n/* Responsive */\n@media (max-width: 640px) {\n .signup-container {\n min-width: auto;\n max-width: none;\n width: 100%;\n }\n \n .signup-title {\n font-size: 1.5rem;\n }\n}\n</style>","<template>\n <div class=\"accui-component-scope\">\n <!-- Success State -->\n <div v-if=\"registrationComplete\" class=\"complete-signup-container\">\n <StrandsUiCard variant=\"modern\">\n <div class=\"complete-signup-success\">\n <div class=\"complete-signup-success-icon\">🎉</div>\n <h1 class=\"complete-signup-success-title\">Welcome to Strands!</h1>\n <p class=\"complete-signup-success-message\">\n Your account has been created successfully.\n </p>\n <p class=\"complete-signup-success-instructions\">\n You are now signed in and can access your dashboard.\n </p>\n <StrandsUiButton \n variant=\"primary\" \n full-width \n @click=\"redirectToReferrer\"\n >\n Go to Dashboard\n </StrandsUiButton>\n </div>\n <StrandsSecuredFooter />\n </StrandsUiCard>\n </div>\n\n <!-- Invalid Token State -->\n <div v-else-if=\"invalidToken\" class=\"complete-signup-container\">\n <StrandsUiCard variant=\"modern\">\n <div class=\"complete-signup-error\">\n <div class=\"complete-signup-error-icon\">❌</div>\n <h1 class=\"complete-signup-error-title\">Invalid Link</h1>\n <p class=\"complete-signup-error-message\">\n This registration link is invalid or has expired.\n </p>\n <p class=\"complete-signup-error-instructions\">\n Please request a new magic link to complete your registration.\n </p>\n <StrandsUiButton\n variant=\"primary\"\n full-width\n @click=\"$emit('request-new-link')\"\n >\n Request New Link\n </StrandsUiButton>\n </div>\n <StrandsSecuredFooter />\n </StrandsUiCard>\n </div>\n\n <!-- Registration Form -->\n <div v-else-if=\"token\" class=\"complete-signup-container\">\n <StrandsUiCard variant=\"modern\">\n <!-- Header -->\n <div class=\"complete-signup-header\">\n <h1 class=\"complete-signup-title\">Complete Your Registration</h1>\n <p class=\"complete-signup-subtitle\">Set up your account details to finish registration</p>\n <div v-if=\"email\" class=\"complete-signup-email-info\">\n <p class=\"complete-signup-email-text\">Creating account for: <span class=\"complete-signup-email-highlight\">{{ email }}</span></p>\n </div>\n </div>\n\n <!-- Registration Form -->\n <form @submit.prevent=\"handleCompleteSignUp\" class=\"complete-signup-form\">\n\n <!-- First Name -->\n <div>\n <StrandsUiInput\n id=\"firstName\"\n v-model=\"form.firstName\"\n type=\"text\"\n label=\"First Name (Optional)\"\n placeholder=\"Enter your first name\"\n autocomplete=\"given-name\"\n :error=\"fieldErrors.firstName\"\n />\n </div>\n\n <!-- Last Name -->\n <div>\n <StrandsUiInput\n id=\"lastName\"\n v-model=\"form.lastName\"\n type=\"text\"\n label=\"Last Name (Optional)\"\n placeholder=\"Enter your last name\"\n autocomplete=\"family-name\"\n :error=\"fieldErrors.lastName\"\n />\n </div>\n\n <!-- Password -->\n <div>\n <StrandsUiInput\n id=\"password\"\n v-model=\"form.password\"\n type=\"password\"\n label=\"Password\"\n placeholder=\"Create a strong password\"\n autocomplete=\"new-password\"\n required\n minlength=\"8\"\n :error=\"fieldErrors.password\"\n />\n <div class=\"complete-signup-password-hint\">\n Password must be at least 8 characters long\n </div>\n </div>\n\n <StrandsUiButton\n type=\"submit\"\n variant=\"primary\"\n full-width\n :disabled=\"loading || !isFormValid\"\n :loading=\"loading\"\n loading-text=\"Creating account...\"\n >\n Complete Registration\n </StrandsUiButton>\n </form>\n\n <!-- Error Alert -->\n <StrandsUiAlert \n v-if=\"error\" \n variant=\"error\" \n :message=\"error\" \n class=\"complete-signup-error-alert\" \n dismissible \n @dismiss=\"error = ''\"\n />\n \n <!-- Secured by footer -->\n <StrandsSecuredFooter :config=\"props.config\">\n <!-- Need help -->\n <div v-if=\"getSupportEmail()\" class=\"complete-signup-support\">\n <p class=\"complete-signup-support-text\">\n Need help?\n <StrandsUiLink variant=\"primary\" :href=\"`mailto:${getSupportEmail()}`\">\n Contact Support\n </StrandsUiLink>\n </p>\n </div>\n </StrandsSecuredFooter>\n </StrandsUiCard>\n\n </div>\n\n <!-- No Token State -->\n <div v-else class=\"complete-signup-container\">\n <StrandsUiCard variant=\"modern\">\n <div class=\"complete-signup-warning\">\n <div class=\"complete-signup-warning-icon\">⚠️</div>\n <h1 class=\"complete-signup-warning-title\">Missing Token</h1>\n <p class=\"complete-signup-warning-message\">\n No registration token was provided.\n </p>\n <p class=\"complete-signup-warning-instructions\">\n This page requires a valid registration token from the magic link in your email.\n </p>\n <StrandsUiButton\n variant=\"primary\"\n full-width\n @click=\"$emit('start-registration')\"\n >\n Start Registration\n </StrandsUiButton>\n </div>\n <StrandsSecuredFooter />\n </StrandsUiCard>\n </div>\n </div>\n</template>\n\n<script setup lang=\"ts\">\nimport { ref, reactive, computed, onMounted, watch } from 'vue'\nimport { StrandsUiCard, StrandsUiButton, StrandsUiInput, StrandsUiAlert, StrandsUiLink } from '../ui'\nimport StrandsSecuredFooter from './StrandsSecuredFooter.vue'\nimport { useStrandsConfig, type StrandsAuthConfig } from '../composables/useStrandsConfig'\nimport { useStrandsAuth } from '../composables/useStrandsAuth'\nimport type { AuthResponse } from '../../types'\n\ninterface Props {\n token?: string\n redirectUrl?: string\n config?: StrandsAuthConfig\n}\n\ninterface Emits {\n (e: 'success', result: any): void\n (e: 'error', error: string): void\n (e: 'invalid-token'): void\n (e: 'request-new-link'): void\n (e: 'start-registration'): void\n}\n\nconst props = defineProps<Props>()\n\nconst emit = defineEmits<Emits>()\n\n// Get configuration\nconst { getUrl, getSupportEmail } = useStrandsConfig(props.config)\n\n// Auth composable for token storage\nconst { setAuthData } = useStrandsAuth()\n\n// State management\nconst registrationComplete = ref(false)\nconst invalidToken = ref(false)\nconst loading = ref(false)\nconst error = ref('')\nconst email = ref('')\n\nconst form = reactive({\n firstName: '',\n lastName: '',\n password: ''\n})\n\nconst fieldErrors = reactive({\n firstName: '',\n lastName: '',\n password: ''\n})\n\n// Validate form\nconst isFormValid = computed(() => {\n const hasRequiredFields = form.password.trim()\n const passwordMinLength = form.password.length >= 8\n const hasValidToken = !!props.token\n \n return hasRequiredFields && passwordMinLength && hasValidToken\n})\n\n// Watch for password length\nwatch(\n () => form.password,\n (password) => {\n if (password && password.length < 8) {\n fieldErrors.password = 'Password must be at least 8 characters long'\n } else {\n fieldErrors.password = ''\n }\n }\n)\n\n\n// Redirect URL fallback\nconst redirectUrl = computed(() => props.redirectUrl || window.location.origin)\n\n// Extract email from JWT token for display\nonMounted(() => {\n if (props.token) {\n try {\n const parts = props.token.split('.')\n if (parts.length === 3) {\n const payload = JSON.parse(atob(parts[1]))\n if (payload.email) {\n email.value = payload.email\n }\n }\n } catch (err) {\n console.warn('Could not decode token for email display:', err)\n }\n }\n})\n\nconst redirectToReferrer = () => {\n if (redirectUrl.value) {\n console.log('Redirecting to referrer:', redirectUrl.value)\n window.location.href = redirectUrl.value\n }\n}\n\nconst handleCompleteSignUp = async () => {\n if (!props.token) {\n error.value = 'Registration token is required'\n return\n }\n\n // Clear all errors\n error.value = ''\n Object.keys(fieldErrors).forEach(key => {\n fieldErrors[key as keyof typeof fieldErrors] = ''\n })\n\n // Validate form\n if (!isFormValid.value) {\n error.value = 'Please fill in all required fields correctly'\n return\n }\n\n loading.value = true\n\n try {\n // Prepare headers with session context information\n const headers: Record<string, string> = {\n 'Content-Type': 'application/json',\n }\n \n // Note: User-Agent is set automatically by the browser and cannot be overridden for security reasons\n // The browser will send the correct User-Agent header automatically\n \n // Add Origin header for session tracking\n if (typeof window !== 'undefined' && window.location) {\n headers['Origin'] = window.location.origin\n }\n \n const response = await fetch(getUrl('completeRegistration'), {\n method: 'POST',\n headers,\n body: JSON.stringify({\n token: props.token,\n password: form.password,\n first_name: form.firstName || null,\n last_name: form.lastName || null\n }),\n })\n\n if (!response.ok) {\n const errorText = await response.text()\n throw new Error(`Failed to complete registration: ${errorText}`)\n }\n\n const result: AuthResponse = await response.json()\n console.log('Registration success:', result)\n \n // Store authentication data if tokens are present\n if (result.access_token && result.refresh_token && result.user) {\n setAuthData(result)\n console.log('Auth tokens stored successfully for user:', result.user.email)\n } else {\n console.warn('Registration response missing auth tokens or user data')\n }\n \n registrationComplete.value = true\n emit('success', result)\n \n // Redirect to referrer URL after successful registration\n setTimeout(() => {\n redirectToReferrer()\n }, 2000) // Give user 2 seconds to see the success message\n } catch (err) {\n if (err instanceof Error) {\n if (err.message.includes('CONFLICT') || err.message.includes('409')) {\n error.value = 'This account already exists. Please try signing in instead.'\n } else if (err.message.includes('BAD_REQUEST') || err.message.includes('400')) {\n error.value = 'Invalid or expired registration link. Please request a new one.'\n invalidToken.value = true\n emit('invalid-token')\n } else {\n error.value = err.message\n }\n } else {\n error.value = 'Failed to complete registration. Please try again.'\n }\n emit('error', error.value)\n } finally {\n loading.value = false\n }\n}\n</script>\n\n<style scoped>\n.complete-signup-container {\n width: 100%;\n min-width: 25rem;\n max-width: 28rem;\n margin: 0 auto;\n animation: slideUp 0.3s ease-out;\n}\n\n@keyframes slideUp {\n from {\n opacity: 0;\n transform: translateY(20px);\n }\n to {\n opacity: 1;\n transform: translateY(0);\n }\n}\n\n@keyframes fadeIn {\n from {\n opacity: 0;\n }\n to {\n opacity: 1;\n }\n}\n\n/* Success State */\n.complete-signup-success {\n text-align: center;\n}\n\n.complete-signup-success-icon {\n color: #10b981;\n font-size: 3.75rem;\n margin-bottom: 1rem;\n}\n\n.complete-signup-success-title {\n font-size: 1.875rem;\n font-weight: 700;\n background: linear-gradient(135deg, #EA00A8 0%, #FF6B9D 50%, #B8006F 100%);\n -webkit-background-clip: text;\n background-clip: text;\n -webkit-text-fill-color: transparent;\n margin-bottom: 0.5rem;\n}\n\n.complete-signup-success-message {\n color: #6b7280;\n margin-bottom: 1rem;\n}\n\n.complete-signup-success-instructions {\n font-size: 0.875rem;\n color: #6b7280;\n margin-bottom: 1.5rem;\n}\n\n/* Error State */\n.complete-signup-error {\n text-align: center;\n}\n\n.complete-signup-error-icon {\n color: #dc2626;\n font-size: 3.75rem;\n margin-bottom: 1rem;\n}\n\n.complete-signup-error-title {\n font-size: 1.875rem;\n font-weight: 700;\n background: linear-gradient(135deg, #EA00A8 0%, #FF6B9D 50%, #B8006F 100%);\n -webkit-background-clip: text;\n background-clip: text;\n -webkit-text-fill-color: transparent;\n margin-bottom: 0.5rem;\n}\n\n.complete-signup-error-message {\n color: #6b7280;\n margin-bottom: 1rem;\n}\n\n.complete-signup-error-instructions {\n font-size: 0.875rem;\n color: #6b7280;\n margin-bottom: 1.5rem;\n}\n\n/* Warning State */\n.complete-signup-warning {\n text-align: center;\n}\n\n.complete-signup-warning-icon {\n color: #f59e0b;\n font-size: 3.75rem;\n margin-bottom: 1rem;\n}\n\n.complete-signup-warning-title {\n font-size: 1.875rem;\n font-weight: 700;\n background: linear-gradient(135deg, #EA00A8 0%, #FF6B9D 50%, #B8006F 100%);\n -webkit-background-clip: text;\n background-clip: text;\n -webkit-text-fill-color: transparent;\n margin-bottom: 0.5rem;\n}\n\n.complete-signup-warning-message {\n color: #6b7280;\n margin-bottom: 1rem;\n}\n\n.complete-signup-warning-instructions {\n font-size: 0.875rem;\n color: #6b7280;\n margin-bottom: 1.5rem;\n}\n\n/* Header */\n.complete-signup-header {\n text-align: center;\n margin-bottom: 2rem;\n}\n\n.complete-signup-title {\n font-size: 1.875rem;\n font-weight: 700;\n background: linear-gradient(135deg, #EA00A8 0%, #FF6B9D 50%, #B8006F 100%);\n -webkit-background-clip: text;\n background-clip: text;\n -webkit-text-fill-color: transparent;\n margin-bottom: 0.5rem;\n}\n\n.complete-signup-subtitle {\n color: #6b7280;\n}\n\n.complete-signup-email-info {\n margin-top: 0.5rem;\n}\n\n.complete-signup-email-text {\n font-size: 0.875rem;\n color: #6b7280;\n}\n\n.complete-signup-email-highlight {\n font-weight: 500;\n color: #374151;\n}\n\n/* Form */\n.complete-signup-form {\n display: flex;\n flex-direction: column;\n gap: 1.5rem;\n}\n\n.complete-signup-password-hint {\n margin-top: 0.5rem;\n font-size: 0.75rem;\n color: #6b7280;\n}\n\n/* Error Alert */\n.complete-signup-error-alert {\n margin-top: 1.5rem;\n animation: fadeIn 0.3s ease-out;\n}\n\n/* Support */\n.complete-signup-support {\n margin-top: 1.5rem;\n text-align: center;\n}\n\n.complete-signup-support-text {\n color: #9ca3af;\n font-size: 0.875rem;\n}\n\n/* Responsive */\n@media (max-width: 640px) {\n .complete-signup-container {\n min-width: auto;\n max-width: none;\n width: 100%;\n }\n \n .complete-signup-title,\n .complete-signup-success-title,\n .complete-signup-error-title,\n .complete-signup-warning-title {\n font-size: 1.5rem;\n }\n \n .complete-signup-success-icon,\n .complete-signup-error-icon,\n .complete-signup-warning-icon {\n font-size: 3rem;\n }\n}\n</style>","<template>\n <div class=\"accui-component-scope\">\n <UiModal :open=\"show\" @close=\"closeModal\" card-class=\"modal-card\">\n <template #header>\n <div class=\"modal-header\">\n <h2 class=\"modal-title\">Setup Authenticator App</h2>\n <button @click=\"closeModal\" class=\"modal-close-button\">\n <svg class=\"modal-close-icon\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M6 18L18 6M6 6l12 12\" />\n </svg>\n </button>\n </div>\n </template>\n <!-- Step 1: Device Name -->\n <div v-if=\"step === 1\" class=\"step-container\">\n <div>\n <h3 class=\"step-title\">Name Your Device</h3>\n <p class=\"step-description\">\n Give this authenticator a memorable name (e.g., \"iPhone\", \"Work Phone\")\n </p>\n </div>\n\n <StrandsUiInput v-model=\"deviceName\" label=\"Device Name\" placeholder=\"My Authenticator\" :error=\"deviceNameError\"\n :disabled=\"loading\" />\n\n <div class=\"step-actions\">\n <StrandsUiButton variant=\"secondary\" @click=\"closeModal\" :disabled=\"loading\">\n Cancel\n </StrandsUiButton>\n <StrandsUiButton variant=\"primary\" @click=\"startSetup\" :disabled=\"!deviceName.trim() || loading\"\n :loading=\"loading\">\n Continue\n </StrandsUiButton>\n </div>\n </div>\n\n <!-- Step 2: QR Code and Setup -->\n <div v-if=\"step === 2\" class=\"step-container\">\n <div>\n <h3 class=\"step-title\">Scan QR Code</h3>\n <p class=\"step-description\">\n Scan this QR code with your authenticator app (Google Authenticator, Authy, etc.)\n </p>\n </div>\n\n <!-- QR Code -->\n <div class=\"qr-container\">\n <div v-if=\"qrCodeDataUrl\" class=\"qr-wrapper\">\n <img :src=\"qrCodeDataUrl\" alt=\"TOTP QR Code\" class=\"qr-image\" />\n </div>\n <div v-else class=\"qr-loading\">\n <StrandsUiLoader :size=\"24\" />\n </div>\n </div>\n\n <!-- Manual Entry -->\n <div class=\"manual-entry\">\n <p class=\"manual-label\">\n Can't scan? Enter this code manually:\n </p>\n <code class=\"manual-code\">\n {{ totpSetupData?.secret || '...' }}\n </code>\n </div>\n\n <!-- Backup Codes Preview -->\n <div v-if=\"totpSetupData?.backup_codes\" class=\"bg-yellow-50 border border-yellow-200 rounded-lg p-4\">\n <div class=\"flex items-start space-x-2\">\n <svg class=\"w-5 h-5 text-yellow-600 mt-0.5 flex-shrink-0\" fill=\"currentColor\" viewBox=\"0 0 20 20\">\n <path fill-rule=\"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 clip-rule=\"evenodd\" />\n </svg>\n <div>\n <p class=\"text-sm font-medium text-yellow-800\">Save Your Backup Codes</p>\n <p class=\"text-sm text-yellow-700 mt-1\">\n After setup, you'll receive backup codes. Store them safely - they're your only way to recover access if\n you\n lose your device.\n </p>\n </div>\n </div>\n </div>\n\n <div class=\"flex justify-end space-x-3 pt-4\">\n <StrandsUiButton variant=\"secondary\" @click=\"step = 1\" :disabled=\"loading\">\n Back\n </StrandsUiButton>\n <StrandsUiButton variant=\"primary\" @click=\"step = 3\" :disabled=\"loading\">\n I've Added It\n </StrandsUiButton>\n </div>\n </div>\n\n <!-- Step 3: Verification -->\n <div v-if=\"step === 3\" class=\"space-y-4\">\n <div>\n <h3 class=\"text-lg font-semibold text-gray-900 mb-2\">Verify Setup</h3>\n <p class=\"text-sm text-gray-600 mb-4\">\n Enter the 6-digit code from your authenticator app to complete setup\n </p>\n </div>\n\n <StrandsUiInput v-model=\"verificationCode\" label=\"Verification Code\" placeholder=\"123456\" maxlength=\"6\"\n :error=\"verificationError\" :disabled=\"loading\" @input=\"onVerificationCodeInput\" />\n\n <div class=\"totp-setup-step-actions\">\n <StrandsUiButton variant=\"secondary\" @click=\"step = 2\" :disabled=\"loading\">\n Back\n </StrandsUiButton>\n <StrandsUiButton variant=\"primary\" @click=\"verifySetup\" :disabled=\"verificationCode.length !== 6 || loading\"\n :loading=\"loading\">\n Verify & Enable\n </StrandsUiButton>\n </div>\n </div>\n\n <!-- Step 4: Success & Backup Codes -->\n <div v-if=\"step === 4\" class=\"totp-setup-step\">\n <div class=\"totp-setup-success\">\n <div class=\"totp-setup-success-icon\">\n <svg class=\"totp-setup-check-icon\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M5 13l4 4L19 7\" />\n </svg>\n </div>\n <h3 class=\"totp-setup-step-title\">TOTP Setup Complete!</h3>\n <p class=\"totp-setup-success-description\">\n Your authenticator app is now active for two-factor authentication.\n </p>\n </div>\n\n <!-- Backup Codes -->\n <div class=\"totp-setup-backup-codes\">\n <div class=\"totp-setup-backup-header\">\n <svg class=\"totp-setup-backup-warning-icon\" fill=\"currentColor\" viewBox=\"0 0 20 20\">\n <path fill-rule=\"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 clip-rule=\"evenodd\" />\n </svg>\n <div>\n <p class=\"totp-setup-backup-header-title\">Save These Backup Codes</p>\n <p class=\"totp-setup-backup-header-description\">\n Store these codes in a safe place. Each code can only be used once.\n </p>\n </div>\n </div>\n\n <div class=\"totp-setup-backup-grid-wrapper\">\n <div class=\"totp-setup-backup-grid\">\n <div v-for=\"(code, index) in totpSetupData?.backup_codes\" :key=\"index\" class=\"totp-setup-backup-code\">\n {{ code }}\n </div>\n </div>\n </div>\n\n <div class=\"totp-setup-backup-actions\">\n <StrandsUiButton variant=\"secondary\" size=\"sm\" @click=\"copyBackupCodes\">\n 📋 Copy Codes\n </StrandsUiButton>\n </div>\n </div>\n\n <div class=\"totp-setup-final-actions\">\n <StrandsUiButton variant=\"primary\" @click=\"finish\">\n Done\n </StrandsUiButton>\n </div>\n </div>\n </UiModal>\n </div>\n</template>\n\n<script setup lang=\"ts\">\nimport { ref, watch, nextTick } from 'vue'\n// QRCode library removed - using external QR service or manual display\nimport { StrandsUiButton, StrandsUiInput, StrandsUiLoader } from '../ui'\nimport UiModal from '../ui/UiModal.vue'\nimport { useStrandsMfa } from '../composables/useStrandsMfa'\nimport type { TotpSetupResponse } from '../../types'\n\ninterface Props {\n show: boolean\n}\n\ninterface Emits {\n (e: 'close'): void\n (e: 'success'): void\n}\n\nconst props = defineProps<Props>()\nconst emit = defineEmits<Emits>()\n\nconst { setupTotp, verifyTotpSetup, loading } = useStrandsMfa()\n\n// State\nconst step = ref(1)\nconst deviceName = ref('')\nconst deviceNameError = ref('')\nconst verificationCode = ref('')\nconst verificationError = ref('')\nconst totpSetupData = ref<TotpSetupResponse | null>(null)\nconst qrCodeDataUrl = ref('')\n\n// Reset when modal opens/closes\nwatch(() => props.show, (newShow) => {\n if (newShow) {\n // Reset state\n step.value = 1\n deviceName.value = ''\n deviceNameError.value = ''\n verificationCode.value = ''\n verificationError.value = ''\n totpSetupData.value = null\n qrCodeDataUrl.value = ''\n }\n})\n\n// Generate QR code using external service when TOTP setup data is available\nwatch(() => totpSetupData.value, async (newData) => {\n if (newData?.qr_code_url) {\n try {\n // Use a QR code generation service\n const qrUrl = `https://api.qrserver.com/v1/create-qr-code/?size=192x192&data=${encodeURIComponent(newData.qr_code_url)}&bgcolor=ffffff&color=000000`\n qrCodeDataUrl.value = qrUrl\n } catch (error) {\n console.error('Failed to generate QR code:', error)\n }\n }\n})\n\nconst closeModal = () => {\n emit('close')\n}\n\nconst startSetup = async () => {\n if (!deviceName.value.trim()) {\n deviceNameError.value = 'Device name is required'\n return\n }\n\n deviceNameError.value = ''\n\n try {\n const response = await setupTotp(deviceName.value.trim())\n totpSetupData.value = response\n step.value = 2\n } catch (error) {\n deviceNameError.value = error instanceof Error ? error.message : 'Failed to setup TOTP'\n }\n}\n\nconst onVerificationCodeInput = (value: string) => {\n // Only allow digits\n verificationCode.value = value.replace(/\\D/g, '').slice(0, 6)\n verificationError.value = ''\n}\n\nconst verifySetup = async () => {\n if (!totpSetupData.value || !verificationCode.value) {\n return\n }\n\n verificationError.value = ''\n\n try {\n await verifyTotpSetup(totpSetupData.value.device_id, verificationCode.value)\n step.value = 4\n } catch (error) {\n verificationError.value = error instanceof Error ? error.message : 'Invalid verification code'\n }\n}\n\nconst copyBackupCodes = async () => {\n if (!totpSetupData.value?.backup_codes) return\n\n try {\n const codesText = totpSetupData.value.backup_codes.join('\\n')\n await navigator.clipboard.writeText(codesText)\n // Could show a toast here\n console.log('Backup codes copied to clipboard')\n } catch (error) {\n console.error('Failed to copy backup codes:', error)\n }\n}\n\nconst finish = () => {\n emit('success')\n}\n</script>\n\n<style scoped>\n/* Modal container */\n.totp-setup-modal {\n max-width: 28rem;\n}\n\n/* Header */\n.totp-setup-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n}\n\n.totp-setup-title {\n font-size: 1.25rem;\n font-weight: 700;\n color: #111827;\n}\n\n.totp-setup-close-button {\n color: #9ca3af;\n transition: color 0.2s ease;\n background: none;\n border: none;\n cursor: pointer;\n padding: 0.25rem;\n}\n\n.totp-setup-close-button:hover {\n color: #4b5563;\n}\n\n.totp-setup-close-icon {\n width: 1.25rem;\n height: 1.25rem;\n}\n\n/* Steps */\n.totp-setup-step {\n display: flex;\n flex-direction: column;\n gap: 1rem;\n}\n\n.totp-setup-step-title {\n font-size: 1.125rem;\n font-weight: 600;\n color: #111827;\n margin-bottom: 0.5rem;\n}\n\n.totp-setup-step-description {\n font-size: 0.875rem;\n color: #6b7280;\n margin-bottom: 1rem;\n}\n\n.totp-setup-step-actions {\n display: flex;\n justify-content: flex-end;\n gap: 0.75rem;\n padding-top: 1rem;\n}\n\n/* QR Code */\n.totp-setup-qr-container {\n display: flex;\n justify-content: center;\n background-color: #f9fafb;\n padding: 1rem;\n border-radius: 0.5rem;\n}\n\n.totp-setup-qr-wrapper {\n background-color: white;\n padding: 1rem;\n border-radius: 0.5rem;\n box-shadow: 0 1px 2px 0 rgba(0, 0, 0, 0.05);\n}\n\n.totp-setup-qr-image {\n width: 12rem;\n height: 12rem;\n}\n\n.totp-setup-qr-loading {\n display: flex;\n align-items: center;\n justify-content: center;\n width: 12rem;\n height: 12rem;\n}\n\n/* Manual Entry */\n.totp-setup-manual-entry {\n background-color: #f9fafb;\n padding: 1rem;\n border-radius: 0.5rem;\n}\n\n.totp-setup-manual-label {\n font-size: 0.75rem;\n color: #6b7280;\n margin-bottom: 0.5rem;\n}\n\n.totp-setup-manual-code {\n font-size: 0.75rem;\n font-family: 'SF Mono', Monaco, Inconsolata, 'Roboto Mono', Consolas, 'Courier New', monospace;\n background-color: white;\n padding: 0.5rem;\n border-radius: 0.25rem;\n border: 1px solid #e5e7eb;\n word-break: break-all;\n color: #111827;\n display: block;\n}\n\n/* Backup Preview */\n.totp-setup-backup-preview {\n background-color: #fefce8;\n border: 1px solid #fde047;\n border-radius: 0.5rem;\n padding: 1rem;\n}\n\n.totp-setup-backup-warning {\n display: flex;\n align-items: flex-start;\n gap: 0.5rem;\n}\n\n.totp-setup-warning-icon {\n width: 1.25rem;\n height: 1.25rem;\n color: #d97706;\n margin-top: 0.125rem;\n flex-shrink: 0;\n}\n\n.totp-setup-backup-title {\n font-size: 0.875rem;\n font-weight: 500;\n color: #92400e;\n}\n\n.totp-setup-backup-description {\n font-size: 0.875rem;\n color: #a16207;\n margin-top: 0.25rem;\n}\n\n/* Success */\n.totp-setup-success {\n text-align: center;\n}\n\n.totp-setup-success-icon {\n width: 3rem;\n height: 3rem;\n background-color: #dcfce7;\n border-radius: 50%;\n display: flex;\n align-items: center;\n justify-content: center;\n margin: 0 auto 1rem;\n}\n\n.totp-setup-check-icon {\n width: 1.5rem;\n height: 1.5rem;\n color: #16a34a;\n}\n\n.totp-setup-success-description {\n font-size: 0.875rem;\n color: #6b7280;\n margin-bottom: 1.5rem;\n}\n\n/* Backup Codes */\n.totp-setup-backup-codes {\n background-color: #fef2f2;\n border: 1px solid #fecaca;\n border-radius: 0.5rem;\n padding: 1rem;\n}\n\n.totp-setup-backup-header {\n display: flex;\n align-items: flex-start;\n gap: 0.5rem;\n margin-bottom: 0.75rem;\n}\n\n.totp-setup-backup-warning-icon {\n width: 1.25rem;\n height: 1.25rem;\n color: #dc2626;\n margin-top: 0.125rem;\n flex-shrink: 0;\n}\n\n.totp-setup-backup-header-title {\n font-size: 0.875rem;\n font-weight: 500;\n color: #991b1b;\n}\n\n.totp-setup-backup-header-description {\n font-size: 0.875rem;\n color: #b91c1c;\n margin-top: 0.25rem;\n}\n\n.totp-setup-backup-grid-wrapper {\n background-color: white;\n border-radius: 0.25rem;\n border: 1px solid #e5e7eb;\n padding: 0.75rem;\n}\n\n.totp-setup-backup-grid {\n display: grid;\n grid-template-columns: repeat(2, 1fr);\n gap: 0.5rem;\n font-size: 0.875rem;\n font-family: 'SF Mono', Monaco, Inconsolata, 'Roboto Mono', Consolas, 'Courier New', monospace;\n color: #111827;\n}\n\n.totp-setup-backup-code {\n text-align: center;\n padding: 0.25rem 0;\n}\n\n.totp-setup-backup-actions {\n display: flex;\n justify-content: center;\n margin-top: 0.75rem;\n}\n\n.totp-setup-final-actions {\n display: flex;\n justify-content: flex-end;\n padding-top: 1rem;\n}\n\n/* Semantic CSS classes replacing Tailwind */\n.modal-card {\n max-width: 28rem;\n}\n\n.modal-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n}\n\n.modal-title {\n font-size: 1.25rem;\n font-weight: 700;\n color: #111827;\n}\n\n.modal-close-button {\n color: #9ca3af;\n transition: color 0.2s ease;\n background: none;\n border: none;\n cursor: pointer;\n padding: 0.25rem;\n}\n\n.modal-close-button:hover {\n color: #6b7280;\n}\n\n.modal-close-icon {\n width: 1.25rem;\n height: 1.25rem;\n}\n\n.step-container {\n display: flex;\n flex-direction: column;\n gap: 1rem;\n}\n\n.step-title {\n font-size: 1.125rem;\n font-weight: 600;\n color: #111827;\n margin-bottom: 0.5rem;\n}\n\n.step-description {\n font-size: 0.875rem;\n color: #6b7280;\n margin-bottom: 1rem;\n}\n\n.step-actions {\n display: flex;\n justify-content: flex-end;\n gap: 0.75rem;\n padding-top: 1rem;\n}\n\n.qr-container {\n display: flex;\n justify-content: center;\n background-color: #f9fafb;\n padding: 1rem;\n border-radius: 0.5rem;\n}\n\n.qr-wrapper {\n background-color: white;\n padding: 1rem;\n border-radius: 0.5rem;\n box-shadow: 0 1px 2px 0 rgba(0, 0, 0, 0.05);\n}\n\n.qr-image {\n width: 12rem;\n height: 12rem;\n}\n\n.qr-loading {\n display: flex;\n align-items: center;\n justify-content: center;\n width: 12rem;\n height: 12rem;\n}\n\n.manual-entry {\n background-color: #f9fafb;\n padding: 1rem;\n border-radius: 0.5rem;\n}\n\n.manual-label {\n font-size: 0.75rem;\n color: #6b7280;\n margin-bottom: 0.5rem;\n}\n\n.manual-code {\n font-size: 0.75rem;\n font-family: ui-monospace, SFMono-Regular, \"SF Mono\", Consolas, \"Liberation Mono\", Menlo, monospace;\n background-color: white;\n padding: 0.5rem;\n border-radius: 0.25rem;\n border: 1px solid #e5e7eb;\n word-break: break-all;\n color: #111827;\n display: block;\n}\n\n.backup-preview {\n background-color: #fefce8;\n border: 1px solid #fde047;\n border-radius: 0.5rem;\n padding: 1rem;\n}\n\n.backup-warning {\n display: flex;\n align-items: flex-start;\n gap: 0.5rem;\n}\n\n.warning-icon {\n width: 1.25rem;\n height: 1.25rem;\n color: #d97706;\n margin-top: 0.125rem;\n flex-shrink: 0;\n}\n\n.backup-title {\n font-size: 0.875rem;\n font-weight: 500;\n color: #92400e;\n}\n\n.backup-description {\n font-size: 0.875rem;\n color: #a16207;\n margin-top: 0.25rem;\n}\n\n.success-container {\n text-align: center;\n}\n\n.success-icon {\n width: 3rem;\n height: 3rem;\n background-color: #dcfce7;\n border-radius: 50%;\n display: flex;\n align-items: center;\n justify-content: center;\n margin: 0 auto 1rem;\n}\n\n.success-check-icon {\n width: 1.5rem;\n height: 1.5rem;\n color: #16a34a;\n}\n\n.success-description {\n font-size: 0.875rem;\n color: #6b7280;\n margin-bottom: 1.5rem;\n}\n\n.backup-codes-container {\n background-color: #fef2f2;\n border: 1px solid #fecaca;\n border-radius: 0.5rem;\n padding: 1rem;\n}\n\n.backup-codes-header {\n display: flex;\n align-items: flex-start;\n gap: 0.5rem;\n margin-bottom: 0.75rem;\n}\n\n.backup-codes-warning-icon {\n width: 1.25rem;\n height: 1.25rem;\n color: #dc2626;\n margin-top: 0.125rem;\n flex-shrink: 0;\n}\n\n.backup-codes-title {\n font-size: 0.875rem;\n font-weight: 500;\n color: #991b1b;\n}\n\n.backup-codes-description {\n font-size: 0.875rem;\n color: #b91c1c;\n margin-top: 0.25rem;\n}\n\n.backup-codes-grid-wrapper {\n background-color: white;\n border-radius: 0.25rem;\n border: 1px solid #e5e7eb;\n padding: 0.75rem;\n}\n\n.backup-codes-grid {\n display: grid;\n grid-template-columns: repeat(2, 1fr);\n gap: 0.5rem;\n font-size: 0.875rem;\n font-family: ui-monospace, SFMono-Regular, \"SF Mono\", Consolas, \"Liberation Mono\", Menlo, monospace;\n color: #111827;\n}\n\n.backup-code {\n text-align: center;\n padding: 0.25rem 0;\n}\n\n.backup-actions {\n display: flex;\n justify-content: center;\n margin-top: 0.75rem;\n}\n\n.final-actions {\n display: flex;\n justify-content: flex-end;\n padding-top: 1rem;\n}\n</style>\n","<template>\n <div class=\"accui-component-scope\">\n <UiModal :open=\"show\" @close=\"closeModal\" card-class=\"email-mfa-setup-modal\">\n <template #header>\n <div class=\"email-mfa-setup-header\">\n <h2 class=\"email-mfa-setup-title\">Setup Email 2FA</h2>\n <button @click=\"closeModal\" class=\"email-mfa-setup-close-button\">\n <svg class=\"email-mfa-setup-close-icon\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M6 18L18 6M6 6l12 12\" />\n </svg>\n </button>\n </div>\n </template>\n <!-- Step 1: Device Name -->\n <div v-if=\"step === 1\" class=\"email-mfa-setup-step\">\n <div>\n <h3 class=\"email-mfa-setup-step-title\">Name Your Email 2FA</h3>\n <p class=\"email-mfa-setup-step-description\">\n Give this email 2FA method a memorable name (e.g., \"Personal Email\", \"Work Email\")\n </p>\n </div>\n\n <StrandsUiInput v-model=\"deviceName\" label=\"Device Name\" placeholder=\"Personal Email\" :error=\"deviceNameError\"\n :disabled=\"loading\" />\n\n <div class=\"email-mfa-setup-info\">\n <div class=\"email-mfa-setup-info-content\">\n <svg class=\"email-mfa-setup-info-icon\" fill=\"currentColor\" viewBox=\"0 0 20 20\">\n <path fill-rule=\"evenodd\"\n d=\"M18 10a8 8 0 11-16 0 8 8 0 0116 0zm-7-4a1 1 0 11-2 0 1 1 0 012 0zM9 9a1 1 0 000 2v3a1 1 0 001 1h1a1 1 0 100-2v-3a1 1 0 00-1-1H9z\"\n clip-rule=\"evenodd\" />\n </svg>\n <div>\n <p class=\"email-mfa-setup-info-title\">Email 2FA</p>\n <p class=\"email-mfa-setup-info-description\">\n Verification codes will be sent to your registered email address when logging in.\n </p>\n </div>\n </div>\n </div>\n\n <div class=\"email-mfa-setup-step-actions\">\n <StrandsUiButton variant=\"secondary\" @click=\"closeModal\" :disabled=\"loading\">\n Cancel\n </StrandsUiButton>\n <StrandsUiButton variant=\"primary\" @click=\"startSetup\" :disabled=\"!deviceName.trim() || loading\"\n :loading=\"loading\">\n Setup Email 2FA\n </StrandsUiButton>\n </div>\n </div>\n\n <!-- Step 2: Test Verification -->\n <div v-if=\"step === 2\" class=\"email-mfa-setup-step\">\n <div>\n <h3 class=\"email-mfa-setup-step-title\">Test Email 2FA</h3>\n <p class=\"email-mfa-setup-step-description\">\n We've sent a test verification code to your email. Enter it below to complete setup.\n </p>\n </div>\n\n <div class=\"email-mfa-setup-success-notification\">\n <div class=\"email-mfa-setup-success-content\">\n <svg class=\"email-mfa-setup-success-icon\" fill=\"currentColor\" viewBox=\"0 0 20 20\">\n <path fill-rule=\"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 clip-rule=\"evenodd\" />\n </svg>\n <div>\n <p class=\"email-mfa-setup-success-title\">Code Sent!</p>\n <p class=\"email-mfa-setup-success-description\">\n Check your email inbox for the verification code.\n </p>\n </div>\n </div>\n </div>\n\n <StrandsUiInput v-model=\"verificationCode\" label=\"Verification Code\" placeholder=\"123456\" maxlength=\"6\"\n :error=\"verificationError\" :disabled=\"loading\" @input=\"onVerificationCodeInput\" />\n\n <div class=\"email-mfa-setup-resend-section\">\n <StrandsUiButton variant=\"secondary\" size=\"sm\" @click=\"resendCode\" :disabled=\"loading || cooldownActive\">\n {{ cooldownActive ? `Resend in ${cooldownSeconds}s` : 'Resend Code' }}\n </StrandsUiButton>\n </div>\n\n <div class=\"email-mfa-setup-step-actions\">\n <StrandsUiButton variant=\"secondary\" @click=\"step = 1\" :disabled=\"loading\">\n Back\n </StrandsUiButton>\n <StrandsUiButton variant=\"primary\" @click=\"verifySetup\" :disabled=\"verificationCode.length !== 6 || loading\"\n :loading=\"loading\">\n Verify & Enable\n </StrandsUiButton>\n </div>\n </div>\n\n <!-- Step 3: Success -->\n <div v-if=\"step === 3\" class=\"email-mfa-setup-step\">\n <div class=\"email-mfa-setup-completion\">\n <div class=\"email-mfa-setup-completion-icon\">\n <svg class=\"email-mfa-setup-check-icon\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M5 13l4 4L19 7\" />\n </svg>\n </div>\n <h3 class=\"email-mfa-setup-step-title\">Email 2FA Setup Complete!</h3>\n <p class=\"email-mfa-setup-completion-description\">\n Email verification is now active for your account. You'll receive codes at your registered email address.\n </p>\n </div>\n\n <div class=\"email-mfa-setup-info\">\n <div class=\"email-mfa-setup-info-content\">\n <svg class=\"email-mfa-setup-info-icon\" fill=\"currentColor\" viewBox=\"0 0 20 20\">\n <path fill-rule=\"evenodd\"\n d=\"M18 10a8 8 0 11-16 0 8 8 0 0116 0zm-7-4a1 1 0 11-2 0 1 1 0 012 0zM9 9a1 1 0 000 2v3a1 1 0 001 1h1a1 1 0 100-2v-3a1 1 0 00-1-1H9z\"\n clip-rule=\"evenodd\" />\n </svg>\n <div>\n <p class=\"email-mfa-setup-info-title\">How it works</p>\n <p class=\"email-mfa-setup-info-description\">\n When logging in, you'll receive a 6-digit code at your email address. Enter this code to complete\n authentication.\n </p>\n </div>\n </div>\n </div>\n\n <div class=\"email-mfa-setup-final-actions\">\n <StrandsUiButton variant=\"primary\" @click=\"finish\">\n Done\n </StrandsUiButton>\n </div>\n </div>\n </UiModal>\n </div>\n</template>\n\n<script setup lang=\"ts\">\nimport { ref, watch, onBeforeUnmount } from 'vue'\nimport { StrandsUiButton, StrandsUiInput } from '../ui'\nimport UiModal from '../ui/UiModal.vue'\nimport { useStrandsMfa } from '../composables/useStrandsMfa'\n\ninterface Props {\n show: boolean\n}\n\ninterface Emits {\n (e: 'close'): void\n (e: 'success'): void\n}\n\nconst props = defineProps<Props>()\nconst emit = defineEmits<Emits>()\n\nconst { setupEmailMfa, sendEmailMfaCode, verifyEmailMfaCode, loading } = useStrandsMfa()\n\n// State\nconst step = ref(1)\nconst deviceName = ref('')\nconst deviceNameError = ref('')\nconst verificationCode = ref('')\nconst verificationError = ref('')\nconst emailMfaDeviceId = ref<string | null>(null)\nconst cooldownActive = ref(false)\nconst cooldownSeconds = ref(0)\n\nlet cooldownInterval: NodeJS.Timeout | null = null\n\n// Reset when modal opens/closes\nwatch(() => props.show, (newShow) => {\n if (newShow) {\n // Reset state\n step.value = 1\n deviceName.value = ''\n deviceNameError.value = ''\n verificationCode.value = ''\n verificationError.value = ''\n emailMfaDeviceId.value = null\n cooldownActive.value = false\n cooldownSeconds.value = 0\n if (cooldownInterval) {\n clearInterval(cooldownInterval)\n cooldownInterval = null\n }\n }\n})\n\nonBeforeUnmount(() => {\n if (cooldownInterval) {\n clearInterval(cooldownInterval)\n }\n})\n\nconst closeModal = () => {\n emit('close')\n}\n\nconst startSetup = async () => {\n if (!deviceName.value.trim()) {\n deviceNameError.value = 'Device name is required'\n return\n }\n\n deviceNameError.value = ''\n\n try {\n const response = await setupEmailMfa(deviceName.value.trim())\n emailMfaDeviceId.value = response.device_id\n\n // Now send the first verification code\n await sendEmailMfaCode(response.device_id)\n\n step.value = 2\n startCooldown()\n } catch (error) {\n deviceNameError.value = error instanceof Error ? error.message : 'Failed to setup email MFA'\n }\n}\n\nconst onVerificationCodeInput = (value: string) => {\n // Only allow digits\n verificationCode.value = value.replace(/\\D/g, '').slice(0, 6)\n verificationError.value = ''\n}\n\nconst verifySetup = async () => {\n if (!emailMfaDeviceId.value || !verificationCode.value) {\n return\n }\n\n verificationError.value = ''\n\n try {\n const verified = await verifyEmailMfaCode(emailMfaDeviceId.value, verificationCode.value)\n if (verified) {\n step.value = 3\n } else {\n verificationError.value = 'Invalid verification code'\n }\n } catch (error) {\n verificationError.value = error instanceof Error ? error.message : 'Invalid verification code'\n }\n}\n\nconst resendCode = async () => {\n if (!emailMfaDeviceId.value || cooldownActive.value) {\n return\n }\n\n try {\n await sendEmailMfaCode(emailMfaDeviceId.value)\n startCooldown()\n } catch (error) {\n console.error('Failed to resend code:', error)\n }\n}\n\nconst startCooldown = () => {\n cooldownActive.value = true\n cooldownSeconds.value = 30\n\n cooldownInterval = setInterval(() => {\n cooldownSeconds.value -= 1\n if (cooldownSeconds.value <= 0) {\n cooldownActive.value = false\n if (cooldownInterval) {\n clearInterval(cooldownInterval)\n cooldownInterval = null\n }\n }\n }, 1000)\n}\n\nconst finish = () => {\n emit('success')\n}\n</script>\n\n<style scoped>\n/* Modal container */\n.email-mfa-setup-modal {\n max-width: 28rem;\n}\n\n/* Header */\n.email-mfa-setup-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n}\n\n.email-mfa-setup-title {\n font-size: 1.25rem;\n font-weight: 700;\n color: #111827;\n}\n\n.email-mfa-setup-close-button {\n color: #9ca3af;\n transition: color 0.2s ease;\n background: none;\n border: none;\n cursor: pointer;\n padding: 0.25rem;\n}\n\n.email-mfa-setup-close-button:hover {\n color: #4b5563;\n}\n\n.email-mfa-setup-close-icon {\n width: 1.25rem;\n height: 1.25rem;\n}\n\n/* Steps */\n.email-mfa-setup-step {\n display: flex;\n flex-direction: column;\n gap: 1rem;\n}\n\n.email-mfa-setup-step-title {\n font-size: 1.125rem;\n font-weight: 600;\n color: #111827;\n margin-bottom: 0.5rem;\n}\n\n.email-mfa-setup-step-description {\n font-size: 0.875rem;\n color: #4b5563;\n margin-bottom: 1rem;\n}\n\n.email-mfa-setup-step-actions {\n display: flex;\n justify-content: flex-end;\n gap: 0.75rem;\n padding-top: 1rem;\n}\n\n/* Info box */\n.email-mfa-setup-info {\n background-color: #eff6ff;\n border: 1px solid #bfdbfe;\n border-radius: 0.5rem;\n padding: 1rem;\n}\n\n.email-mfa-setup-info-content {\n display: flex;\n align-items: flex-start;\n gap: 0.5rem;\n}\n\n.email-mfa-setup-info-icon {\n width: 1.25rem;\n height: 1.25rem;\n color: #2563eb;\n margin-top: 0.125rem;\n flex-shrink: 0;\n}\n\n.email-mfa-setup-info-title {\n font-size: 0.875rem;\n font-weight: 500;\n color: #1e3a8a;\n margin: 0;\n}\n\n.email-mfa-setup-info-description {\n font-size: 0.875rem;\n color: #1d4ed8;\n margin-top: 0.25rem;\n}\n\n/* Success notification */\n.email-mfa-setup-success-notification {\n background-color: #f0fdf4;\n border: 1px solid #bbf7d0;\n border-radius: 0.5rem;\n padding: 1rem;\n}\n\n.email-mfa-setup-success-content {\n display: flex;\n align-items: flex-start;\n gap: 0.5rem;\n}\n\n.email-mfa-setup-success-icon {\n width: 1.25rem;\n height: 1.25rem;\n color: #059669;\n margin-top: 0.125rem;\n flex-shrink: 0;\n}\n\n.email-mfa-setup-success-title {\n font-size: 0.875rem;\n font-weight: 500;\n color: #166534;\n margin: 0;\n}\n\n.email-mfa-setup-success-description {\n font-size: 0.875rem;\n color: #15803d;\n margin-top: 0.25rem;\n}\n\n/* Resend section */\n.email-mfa-setup-resend-section {\n display: flex;\n justify-content: space-between;\n}\n\n/* Completion */\n.email-mfa-setup-completion {\n text-align: center;\n}\n\n.email-mfa-setup-completion-icon {\n width: 3rem;\n height: 3rem;\n background-color: #dcfce7;\n border-radius: 50%;\n display: flex;\n align-items: center;\n justify-content: center;\n margin: 0 auto 1rem;\n}\n\n.email-mfa-setup-check-icon {\n width: 1.5rem;\n height: 1.5rem;\n color: #16a34a;\n}\n\n.email-mfa-setup-completion-description {\n font-size: 0.875rem;\n color: #4b5563;\n margin-bottom: 1.5rem;\n}\n\n/* Final actions */\n.email-mfa-setup-final-actions {\n display: flex;\n justify-content: flex-end;\n padding-top: 1rem;\n}\n</style>\n","<template>\n <div class=\"accui-component-scope\">\n <UiModal :open=\"show\" @close=\"closeModal\" card-class=\"hardware-key-setup-modal\">\n <template #header>\n <div class=\"hardware-key-setup-header\">\n <h2 class=\"hardware-key-setup-title\">Setup Hardware Key</h2>\n <button @click=\"closeModal\" class=\"hardware-key-setup-close\">\n <svg class=\"hardware-key-setup-close-icon\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M6 18L18 6M6 6l12 12\" />\n </svg>\n </button>\n </div>\n </template>\n\n <!-- Step 1: Device Name -->\n <div v-if=\"step === 1\" class=\"hardware-key-setup-step\">\n <div>\n <h3 class=\"hardware-key-setup-step-title\">Name Your Hardware Key</h3>\n <p class=\"hardware-key-setup-step-description\">\n Give your hardware key a memorable name (e.g., \"YubiKey 5\", \"Work Security Key\")\n </p>\n </div>\n\n <StrandsUiInput v-model=\"deviceName\" label=\"Device Name\" placeholder=\"My Hardware Key\" :error=\"deviceNameError\"\n :disabled=\"loading\" />\n\n <div class=\"hardware-key-setup-actions\">\n <StrandsUiButton variant=\"secondary\" @click=\"closeModal\" :disabled=\"loading\">\n Cancel\n </StrandsUiButton>\n <StrandsUiButton variant=\"primary\" @click=\"startSetup\" :disabled=\"!deviceName.trim() || loading\"\n :loading=\"loading\">\n Continue\n </StrandsUiButton>\n </div>\n </div>\n\n <!-- Step 2: Hardware Key Registration -->\n <div v-if=\"step === 2\" class=\"hardware-key-setup-step\">\n <div>\n <h3 class=\"hardware-key-setup-step-title\">Register Hardware Key</h3>\n <p class=\"hardware-key-setup-step-description\">\n Insert your hardware key and follow your browser's prompts to complete registration.\n </p>\n </div>\n\n <!-- Hardware Key Illustration -->\n <div class=\"hardware-key-setup-illustration\">\n <div class=\"hardware-key-setup-illustration-content\">\n <div class=\"hardware-key-setup-icon-container\">\n <svg class=\"hardware-key-setup-icon\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\"\n d=\"M15 7a2 2 0 012 2m0 0a2 2 0 012 2v6a2 2 0 01-2 2H9a2 2 0 01-2-2V9a2 2 0 012-2m0 0V7a2 2 0 012-2m0 0V5a2 2 0 012-2h6a2 2 0 012 2v2M7 7h3m0 0v8m0-8h8m-8 8h8\" />\n </svg>\n </div>\n <p class=\"hardware-key-setup-status\">Hardware Key Ready</p>\n <p class=\"hardware-key-setup-substatus\">Click \"Register Key\" when ready</p>\n </div>\n </div>\n\n <!-- Instructions -->\n <div class=\"hardware-key-setup-instructions\">\n <div class=\"hardware-key-setup-instructions-header\">\n <svg class=\"hardware-key-setup-info-icon\" fill=\"currentColor\" viewBox=\"0 0 20 20\">\n <path fill-rule=\"evenodd\"\n d=\"M18 10a8 8 0 11-16 0 8 8 0 0116 0zm-7-4a1 1 0 11-2 0 1 1 0 012 0zM9 9a1 1 0 000 2v3a1 1 0 001 1h1a1 1 0 100-2v-3a1 1 0 00-1-1H9z\"\n clip-rule=\"evenodd\" />\n </svg>\n <div>\n <p class=\"hardware-key-setup-instructions-title\">Setup Instructions</p>\n <ul class=\"hardware-key-setup-instructions-list\">\n <template v-if=\"props.deviceType === 'passkey'\">\n <li>• Your browser will prompt you to create a passkey</li>\n <li>• Use Touch ID, Face ID, Windows Hello, or PIN</li>\n <li>• Follow the prompts to complete setup</li>\n </template>\n <template v-else>\n <li>• Insert your hardware key into a USB port</li>\n <li>• Your browser will prompt you to interact with the key</li>\n <li>• Touch the key's button or sensor when prompted</li>\n </template>\n </ul>\n </div>\n </div>\n </div>\n\n <div class=\"hardware-key-setup-actions\">\n <StrandsUiButton variant=\"secondary\" @click=\"step = 1\" :disabled=\"loading\">\n Back\n </StrandsUiButton>\n <StrandsUiButton variant=\"primary\" @click=\"handleRegisterHardwareKey\" :disabled=\"loading\" :loading=\"loading\">\n Register Key\n </StrandsUiButton>\n </div>\n </div>\n\n <!-- Step 3: Registration In Progress -->\n <div v-if=\"step === 3\" class=\"hardware-key-setup-step\">\n <div class=\"hardware-key-setup-progress\">\n <div class=\"hardware-key-setup-progress-icon\">\n <StrandsUiLoader :size=\"24\" class=\"hardware-key-setup-loader\" />\n </div>\n <h3 class=\"hardware-key-setup-step-title\">Registering Hardware Key</h3>\n <p class=\"hardware-key-setup-progress-message\">\n {{ registrationMessage }}\n </p>\n </div>\n\n <!-- Dynamic Progress Indicator -->\n <div class=\"hardware-key-setup-progress-indicator\">\n <div class=\"hardware-key-setup-progress-content\">\n <div class=\"hardware-key-setup-progress-check\">\n <div class=\"hardware-key-setup-check-icon\">\n <svg class=\"hardware-key-setup-check\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M5 13l4 4L19 7\" />\n </svg>\n </div>\n </div>\n <p class=\"hardware-key-setup-progress-text\">Touch your hardware key to complete registration</p>\n </div>\n </div>\n </div>\n\n <!-- Step 4: Success & Backup Codes -->\n <div v-if=\"step === 4\" class=\"hardware-key-setup-step\">\n <div class=\"hardware-key-setup-success\">\n <div class=\"hardware-key-setup-success-icon\">\n <svg class=\"hardware-key-setup-success-check\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M5 13l4 4L19 7\" />\n </svg>\n </div>\n <h3 class=\"hardware-key-setup-step-title\">Hardware Key Setup Complete!</h3>\n <p class=\"hardware-key-setup-success-message\">\n Your hardware key is now active for two-factor authentication.\n </p>\n </div>\n\n <!-- Backup Codes -->\n <div class=\"hardware-key-setup-backup-codes\">\n <div class=\"hardware-key-setup-backup-codes-header\">\n <svg class=\"hardware-key-setup-warning-icon\" fill=\"currentColor\" viewBox=\"0 0 20 20\">\n <path fill-rule=\"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 clip-rule=\"evenodd\" />\n </svg>\n <div>\n <p class=\"hardware-key-setup-backup-codes-title\">Save These Backup Codes</p>\n <p class=\"hardware-key-setup-backup-codes-description\">\n Store these codes in a safe place. Each code can only be used once if you lose your hardware key.\n </p>\n </div>\n </div>\n\n <div class=\"hardware-key-setup-codes-container\">\n <div class=\"hardware-key-setup-codes-grid\">\n <div v-for=\"(code, index) in backupCodes\" :key=\"index\" class=\"hardware-key-setup-code\">\n {{ code }}\n </div>\n </div>\n </div>\n\n <div class=\"hardware-key-setup-copy-action\">\n <StrandsUiButton variant=\"secondary\" size=\"sm\" @click=\"copyBackupCodes\">\n 📋 Copy Codes\n </StrandsUiButton>\n </div>\n </div>\n\n <div class=\"hardware-key-setup-final-action\">\n <StrandsUiButton variant=\"primary\" @click=\"finish\">\n Done\n </StrandsUiButton>\n </div>\n </div>\n\n <!-- Step 5: Error State -->\n <div v-if=\"step === 5\" class=\"hardware-key-setup-step\">\n <div class=\"hardware-key-setup-error\">\n <div class=\"hardware-key-setup-error-icon\">\n <svg class=\"hardware-key-setup-error-x\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M6 18L18 6M6 6l12 12\" />\n </svg>\n </div>\n <h3 class=\"hardware-key-setup-step-title\">Registration Failed</h3>\n <p class=\"hardware-key-setup-error-message\">\n {{ errorMessage }}\n </p>\n </div>\n\n <div class=\"hardware-key-setup-actions\">\n <StrandsUiButton variant=\"secondary\" @click=\"step = 1\">\n Start Over\n </StrandsUiButton>\n <StrandsUiButton variant=\"primary\" @click=\"closeModal\">\n Close\n </StrandsUiButton>\n </div>\n </div>\n </UiModal>\n </div>\n</template>\n\n<script setup lang=\"ts\">\nimport { ref, watch, computed, withDefaults } from 'vue'\nimport { useStrandsAuth } from '../composables/useStrandsAuth'\nimport { StrandsUiButton, StrandsUiInput, StrandsUiLoader } from '../ui'\nimport UiModal from '../ui/UiModal.vue'\nimport { useStrandsMfa } from '../composables/useStrandsMfa'\n\ninterface Props {\n show: boolean\n deviceType?: 'passkey' | 'hardware'\n}\n\ninterface Emits {\n (e: 'close'): void\n (e: 'success'): void\n}\n\nconst props = withDefaults(defineProps<Props>(), {\n deviceType: 'hardware'\n})\nconst emit = defineEmits<Emits>()\n\nconst { loading: mfaLoading } = useStrandsMfa()\nconst { registerHardwareKey, completeHardwareKeyRegistration, currentSession } = useStrandsAuth()\n\n// Internal loading state for this component\nconst internalLoading = ref(false)\nconst loading = computed(() => mfaLoading.value || internalLoading.value)\n\n// State\nconst step = ref(1)\nconst deviceName = ref('')\nconst deviceNameError = ref('')\nconst registrationMessage = ref('Please touch your hardware key when prompted')\nconst errorMessage = ref('')\nconst backupCodes = ref<string[]>([])\n\n// Reset when modal opens/closes\nwatch(() => props.show, (newShow) => {\n if (newShow) {\n // Reset state\n step.value = 1\n deviceName.value = ''\n deviceNameError.value = ''\n registrationMessage.value = 'Please touch your hardware key when prompted'\n errorMessage.value = ''\n backupCodes.value = []\n }\n})\n\nconst closeModal = () => {\n emit('close')\n}\n\n// Get optimal authenticator selection based on device type\nconst getOptimalAuthenticatorSelection = (deviceType: 'hardware' | 'passkey') => {\n if (deviceType === 'passkey') {\n return {\n authenticatorAttachment: undefined, // Allow both platform and cross-platform for passkeys\n requireResidentKey: true, // Passkeys are resident credentials\n residentKey: 'required',\n userVerification: 'required' // Passkeys should always verify user\n }\n } else {\n // Hardware keys (YubiKey, etc.)\n return {\n authenticatorAttachment: 'cross-platform', // Prefer external authenticators like YubiKey\n requireResidentKey: false,\n residentKey: 'discouraged',\n userVerification: 'discouraged' // YubiKeys work better with discouraged\n }\n }\n}\n\n// Helper function to create a device-optimized WebAuthn challenge\nconst createOptimizedWebAuthnChallenge = (challenge: any, deviceType: 'hardware' | 'passkey') => {\n // Safe buffer conversion that creates new clean objects\n const safeBufferConvert = (data: any): Uint8Array => {\n try {\n if (!data) {\n return new Uint8Array(32) // Default 32-byte random challenge\n }\n\n // If it's already a Uint8Array, create a new clean copy\n if (data instanceof Uint8Array) {\n return new Uint8Array(data)\n }\n\n // If it has a buffer property, extract it safely\n if (data && typeof data === 'object' && data.buffer) {\n return new Uint8Array(data.buffer)\n }\n\n // If it's an array of numbers\n if (Array.isArray(data)) {\n return new Uint8Array(data)\n }\n\n // If it's a string, try base64 decode\n if (typeof data === 'string') {\n const binary = atob(data)\n const bytes = new Uint8Array(binary.length)\n for (let i = 0; i < binary.length; i++) {\n bytes[i] = binary.charCodeAt(i)\n }\n return bytes\n }\n\n // Fallback: create random bytes\n console.warn('Unknown data format, using random bytes:', data)\n return crypto.getRandomValues(new Uint8Array(32))\n\n } catch (error) {\n console.error('Buffer conversion failed:', error)\n return crypto.getRandomValues(new Uint8Array(32))\n }\n }\n\n try {\n // Create a completely new clean object to avoid extension conflicts\n const cleanChallenge: any = {\n rp: challenge.rp || { name: 'Strands Accounts' },\n user: {\n id: safeBufferConvert(challenge.user?.id),\n name: challenge.user?.name || 'user',\n displayName: challenge.user?.displayName || challenge.user?.name || 'User'\n },\n challenge: safeBufferConvert(challenge.challenge),\n pubKeyCredParams: challenge.pubKeyCredParams || [\n { type: 'public-key', alg: -7 }, // ES256 (ECDSA w/ SHA-256)\n { type: 'public-key', alg: -35 }, // ES384 (ECDSA w/ SHA-384) \n { type: 'public-key', alg: -36 }, // ES512 (ECDSA w/ SHA-512)\n { type: 'public-key', alg: -257 }, // RS256 (RSASSA-PKCS1-v1_5 w/ SHA-256)\n { type: 'public-key', alg: -258 }, // RS384 (RSASSA-PKCS1-v1_5 w/ SHA-384)\n { type: 'public-key', alg: -259 }, // RS512 (RSASSA-PKCS1-v1_5 w/ SHA-512)\n { type: 'public-key', alg: -37 }, // PS256 (RSASSA-PSS w/ SHA-256)\n { type: 'public-key', alg: -38 }, // PS384 (RSASSA-PSS w/ SHA-384)\n { type: 'public-key', alg: -39 }, // PS512 (RSASSA-PSS w/ SHA-512)\n { type: 'public-key', alg: -8 } // EdDSA (Ed25519)\n ],\n timeout: challenge.timeout || (deviceType === 'passkey' ? 300000 : 120000), // Longer timeout for passkeys\n authenticatorSelection: challenge.authenticatorSelection || getOptimalAuthenticatorSelection(deviceType),\n attestation: challenge.attestation || (deviceType === 'passkey' ? 'none' : 'direct') // Different attestation preferences\n }\n\n // Only add excludeCredentials if it exists and has valid data\n if (challenge.excludeCredentials && Array.isArray(challenge.excludeCredentials) && challenge.excludeCredentials.length > 0) {\n cleanChallenge.excludeCredentials = challenge.excludeCredentials.map((cred: any) => ({\n type: 'public-key' as PublicKeyCredentialType,\n id: safeBufferConvert(cred.id)\n }))\n }\n\n return cleanChallenge as PublicKeyCredentialCreationOptions\n } catch (error) {\n console.error('Failed to create clean challenge:', error)\n throw new Error('Unable to process WebAuthn challenge data')\n }\n}\n\nconst startSetup = async () => {\n if (!deviceName.value.trim()) {\n deviceNameError.value = 'Device name is required'\n return\n }\n\n deviceNameError.value = ''\n step.value = 2\n}\n\nconst handleRegisterHardwareKey = async () => {\n internalLoading.value = true\n step.value = 3\n registrationMessage.value = `Starting ${props.deviceType === 'passkey' ? 'passkey' : 'hardware key'} registration...`\n\n try {\n // Check if WebAuthn is supported\n if (!window.navigator.credentials || !window.PublicKeyCredential) {\n throw new Error('WebAuthn is not supported in this browser')\n }\n\n // Check for platform authenticator support (better YubiKey detection)\n try {\n const available = await PublicKeyCredential.isUserVerifyingPlatformAuthenticatorAvailable?.()\n console.log('Platform authenticator available:', available)\n\n // Also check if conditional mediation is supported (indicates modern WebAuthn support)\n if (PublicKeyCredential.isConditionalMediationAvailable) {\n const conditionalMediationAvailable = await PublicKeyCredential.isConditionalMediationAvailable()\n console.log('Conditional mediation available:', conditionalMediationAvailable)\n }\n } catch (checkError) {\n console.warn('Could not check authenticator availability:', checkError)\n // Continue anyway as this is not critical\n }\n\n // Use composable for API call\n if (!currentSession.value?.accessToken) {\n throw new Error('Not authenticated. Please sign in again.')\n }\n\n const { device_id, challenge } = await registerHardwareKey(deviceName.value.trim(), currentSession.value.accessToken)\n\n console.log('WebAuthn challenge received:', JSON.stringify(challenge, null, 2))\n console.log('Device ID:', device_id)\n\n // Validate challenge structure\n if (!challenge || typeof challenge !== 'object') {\n throw new Error('Invalid challenge received from server')\n }\n\n // Log the raw challenge properties to debug the extension issue\n console.log('Challenge properties:', Object.keys(challenge))\n console.log('Challenge.challenge type:', typeof challenge.challenge, challenge.challenge)\n console.log('Challenge.user type:', typeof challenge.user, challenge.user)\n if (challenge.user) {\n console.log('Challenge.user.id type:', typeof challenge.user.id, challenge.user.id)\n }\n\n // Try to create a device-specific challenge optimized for the device type\n const processedChallenge = createOptimizedWebAuthnChallenge(challenge, props.deviceType)\n console.log('Processed challenge for WebAuthn:', processedChallenge)\n\n registrationMessage.value = 'Please touch your hardware key now...'\n\n // Create WebAuthn credential\n const credential = await navigator.credentials.create({\n publicKey: processedChallenge\n }) as PublicKeyCredential\n\n if (!credential) {\n throw new Error('Hardware key registration was cancelled')\n }\n\n console.log('WebAuthn credential created:', credential)\n registrationMessage.value = 'Completing registration...'\n\n // Complete registration via API using composable\n const response = credential.response as AuthenticatorAttestationResponse\n\n try {\n // Validate credential components before processing\n console.log('Credential structure:', {\n id: credential.id,\n rawId: credential.rawId,\n response: response,\n type: credential.type\n })\n\n if (!credential.rawId) {\n throw new Error('Missing rawId in credential')\n }\n if (!response.clientDataJSON) {\n throw new Error('Missing clientDataJSON in credential response')\n }\n if (!response.attestationObject) {\n throw new Error('Missing attestationObject in credential response')\n }\n\n // Safe ArrayBuffer to Array conversion\n const rawIdArray = credential.rawId instanceof ArrayBuffer ?\n Array.from(new Uint8Array(credential.rawId)) :\n Array.from(credential.rawId)\n\n const clientDataArray = response.clientDataJSON instanceof ArrayBuffer ?\n Array.from(new Uint8Array(response.clientDataJSON)) :\n Array.from(response.clientDataJSON)\n\n const attestationArray = response.attestationObject instanceof ArrayBuffer ?\n Array.from(new Uint8Array(response.attestationObject)) :\n Array.from(response.attestationObject)\n\n const credentialPayload = {\n id: credential.id,\n rawId: rawIdArray,\n response: {\n clientDataJSON: clientDataArray,\n attestationObject: attestationArray\n },\n type: credential.type\n }\n\n console.log('Sending credential payload:', credentialPayload)\n const result = await completeHardwareKeyRegistration(device_id, credentialPayload, currentSession.value.accessToken)\n console.log('Registration completed successfully:', result)\n backupCodes.value = result.backup_codes || []\n step.value = 4\n } catch (credError) {\n console.error('Error processing WebAuthn credential:', credError)\n throw new Error(`Failed to process hardware key data: ${credError instanceof Error ? credError.message : String(credError)}`)\n }\n\n } catch (error) {\n console.error('Hardware key registration error:', error)\n\n // Provide user-friendly error messages for common YubiKey issues\n let userErrorMessage = 'Hardware key registration failed'\n\n if (error instanceof Error) {\n const errorMsg = error.message.toLowerCase()\n\n if (errorMsg.includes('not supported') || errorMsg.includes('webauthn')) {\n userErrorMessage = 'WebAuthn is not supported in this browser. Please use Chrome, Firefox, Safari, or Edge.'\n } else if (errorMsg.includes('cancelled') || errorMsg.includes('aborted')) {\n userErrorMessage = 'Hardware key registration was cancelled. Please try again and touch your key when prompted.'\n } else if (errorMsg.includes('timeout')) {\n userErrorMessage = 'Hardware key registration timed out. Please ensure your key is connected and try again.'\n } else if (errorMsg.includes('not allowed') || errorMsg.includes('invalid state')) {\n userErrorMessage = 'This hardware key may already be registered or cannot be used. Try a different key or contact support.'\n } else if (errorMsg.includes(\"can't be used\") || errorMsg.includes('newer or different')) {\n userErrorMessage = 'Your hardware key is not compatible. Please ensure you have a FIDO2/WebAuthn compatible key like YubiKey 5 Series, and that it\\'s properly connected.'\n } else if (errorMsg.includes('user verification') || errorMsg.includes('pin')) {\n userErrorMessage = 'Hardware key verification failed. If your key has a PIN, please enter it when prompted.'\n } else {\n userErrorMessage = error.message\n }\n }\n\n errorMessage.value = userErrorMessage\n step.value = 5\n } finally {\n internalLoading.value = false\n }\n}\n\nconst copyBackupCodes = async () => {\n if (!backupCodes.value.length) return\n\n try {\n const codesText = backupCodes.value.join('\\n')\n await navigator.clipboard.writeText(codesText)\n // Could show a toast here\n console.log('Backup codes copied to clipboard')\n } catch (error) {\n console.error('Failed to copy backup codes:', error)\n }\n}\n\nconst finish = () => {\n emit('success')\n}\n</script>\n\n<style scoped>\n/* Modal container */\n.hardware-key-setup-modal {\n max-width: 28rem;\n}\n\n/* Header */\n.hardware-key-setup-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n}\n\n.hardware-key-setup-title {\n font-size: 1.25rem;\n font-weight: 700;\n color: #111827;\n}\n\n.hardware-key-setup-close {\n color: #9ca3af;\n transition: color 0.2s ease;\n background: none;\n border: none;\n cursor: pointer;\n padding: 0.25rem;\n border-radius: 0.25rem;\n}\n\n.hardware-key-setup-close:hover {\n color: #4b5563;\n}\n\n.hardware-key-setup-close-icon {\n width: 1.25rem;\n height: 1.25rem;\n}\n\n/* Step container */\n.hardware-key-setup-step {\n display: flex;\n flex-direction: column;\n gap: 1rem;\n}\n\n.hardware-key-setup-step-title {\n font-size: 1.125rem;\n font-weight: 600;\n color: #111827;\n margin-bottom: 0.5rem;\n}\n\n.hardware-key-setup-step-description {\n font-size: 0.875rem;\n color: #6b7280;\n margin-bottom: 1rem;\n}\n\n/* Actions */\n.hardware-key-setup-actions {\n display: flex;\n justify-content: flex-end;\n gap: 0.75rem;\n padding-top: 1rem;\n}\n\n.hardware-key-setup-final-action {\n display: flex;\n justify-content: flex-end;\n padding-top: 1rem;\n}\n\n/* Illustration */\n.hardware-key-setup-illustration {\n display: flex;\n justify-content: center;\n background-color: #f9fafb;\n padding: 1.5rem;\n border-radius: 0.5rem;\n}\n\n.hardware-key-setup-illustration-content {\n text-align: center;\n}\n\n.hardware-key-setup-icon-container {\n width: 4rem;\n height: 4rem;\n background-color: #dbeafe;\n border-radius: 0.5rem;\n display: flex;\n align-items: center;\n justify-content: center;\n margin: 0 auto 1rem auto;\n}\n\n.hardware-key-setup-icon {\n width: 2rem;\n height: 2rem;\n color: #2563eb;\n}\n\n.hardware-key-setup-status {\n font-size: 0.875rem;\n font-weight: 500;\n color: #111827;\n}\n\n.hardware-key-setup-substatus {\n font-size: 0.75rem;\n color: #6b7280;\n margin-top: 0.25rem;\n}\n\n/* Instructions */\n.hardware-key-setup-instructions {\n background-color: #eff6ff;\n border: 1px solid #bfdbfe;\n border-radius: 0.5rem;\n padding: 1rem;\n}\n\n.hardware-key-setup-instructions-header {\n display: flex;\n align-items: flex-start;\n gap: 0.5rem;\n}\n\n.hardware-key-setup-info-icon {\n width: 1.25rem;\n height: 1.25rem;\n color: #2563eb;\n margin-top: 0.125rem;\n flex-shrink: 0;\n}\n\n.hardware-key-setup-instructions-title {\n font-size: 0.875rem;\n font-weight: 500;\n color: #1e40af;\n}\n\n.hardware-key-setup-instructions-list {\n font-size: 0.875rem;\n color: #1d4ed8;\n margin-top: 0.25rem;\n display: flex;\n flex-direction: column;\n gap: 0.25rem;\n}\n\n/* Progress states */\n.hardware-key-setup-progress {\n text-align: center;\n}\n\n.hardware-key-setup-progress-icon {\n width: 3rem;\n height: 3rem;\n background-color: #dbeafe;\n border-radius: 50%;\n display: flex;\n align-items: center;\n justify-content: center;\n margin: 0 auto 1rem auto;\n}\n\n.hardware-key-setup-loader {\n color: #2563eb;\n}\n\n.hardware-key-setup-progress-message {\n font-size: 0.875rem;\n color: #6b7280;\n margin-bottom: 1.5rem;\n}\n\n.hardware-key-setup-progress-indicator {\n background-color: #f9fafb;\n padding: 1rem;\n border-radius: 0.5rem;\n}\n\n.hardware-key-setup-progress-content {\n display: flex;\n align-items: center;\n gap: 0.75rem;\n}\n\n.hardware-key-setup-progress-check {\n flex-shrink: 0;\n}\n\n.hardware-key-setup-check-icon {\n width: 1.5rem;\n height: 1.5rem;\n background-color: #2563eb;\n border-radius: 50%;\n display: flex;\n align-items: center;\n justify-content: center;\n}\n\n.hardware-key-setup-check {\n width: 1rem;\n height: 1rem;\n color: white;\n}\n\n.hardware-key-setup-progress-text {\n font-size: 0.875rem;\n color: #374151;\n}\n\n/* Success state */\n.hardware-key-setup-success {\n text-align: center;\n}\n\n.hardware-key-setup-success-icon {\n width: 3rem;\n height: 3rem;\n background-color: #dcfce7;\n border-radius: 50%;\n display: flex;\n align-items: center;\n justify-content: center;\n margin: 0 auto 1rem auto;\n}\n\n.hardware-key-setup-success-check {\n width: 1.5rem;\n height: 1.5rem;\n color: #16a34a;\n}\n\n.hardware-key-setup-success-message {\n font-size: 0.875rem;\n color: #6b7280;\n margin-bottom: 1.5rem;\n}\n\n/* Backup codes */\n.hardware-key-setup-backup-codes {\n background-color: #fef2f2;\n border: 1px solid #fecaca;\n border-radius: 0.5rem;\n padding: 1rem;\n}\n\n.hardware-key-setup-backup-codes-header {\n display: flex;\n align-items: flex-start;\n gap: 0.5rem;\n margin-bottom: 0.75rem;\n}\n\n.hardware-key-setup-warning-icon {\n width: 1.25rem;\n height: 1.25rem;\n color: #dc2626;\n margin-top: 0.125rem;\n flex-shrink: 0;\n}\n\n.hardware-key-setup-backup-codes-title {\n font-size: 0.875rem;\n font-weight: 500;\n color: #991b1b;\n}\n\n.hardware-key-setup-backup-codes-description {\n font-size: 0.875rem;\n color: #b91c1c;\n margin-top: 0.25rem;\n}\n\n.hardware-key-setup-codes-container {\n background-color: white;\n border-radius: 0.25rem;\n border: 1px solid #d1d5db;\n padding: 0.75rem;\n}\n\n.hardware-key-setup-codes-grid {\n display: grid;\n grid-template-columns: repeat(2, 1fr);\n gap: 0.5rem;\n font-size: 0.875rem;\n font-family: ui-monospace, SFMono-Regular, \"SF Mono\", Consolas, \"Liberation Mono\", Menlo, monospace;\n color: #111827;\n}\n\n.hardware-key-setup-code {\n text-align: center;\n padding: 0.25rem 0;\n}\n\n.hardware-key-setup-copy-action {\n display: flex;\n justify-content: center;\n margin-top: 0.75rem;\n}\n\n/* Error state */\n.hardware-key-setup-error {\n text-align: center;\n}\n\n.hardware-key-setup-error-icon {\n width: 3rem;\n height: 3rem;\n background-color: #fee2e2;\n border-radius: 50%;\n display: flex;\n align-items: center;\n justify-content: center;\n margin: 0 auto 1rem auto;\n}\n\n.hardware-key-setup-error-x {\n width: 1.5rem;\n height: 1.5rem;\n color: #dc2626;\n}\n\n.hardware-key-setup-error-message {\n font-size: 0.875rem;\n color: #6b7280;\n margin-bottom: 1.5rem;\n}\n</style>","<template>\n <div class=\"accui-component-scope\">\n <UiModal :open=\"show\" @close=\"closeModal\" card-class=\"backup-codes-modal\">\n <template #header>\n <div class=\"backup-codes-header\">\n <h2 class=\"backup-codes-title\">Backup Codes</h2>\n <button @click=\"closeModal\" class=\"backup-codes-close-button\">\n <svg class=\"backup-codes-close-icon\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M6 18L18 6M6 6l12 12\" />\n </svg>\n </button>\n </div>\n </template>\n <div v-if=\"loading\" class=\"backup-codes-loading\">\n <StrandsUiLoader :size=\"24\" />\n <span class=\"backup-codes-loading-text\">Loading backup codes...</span>\n </div>\n\n <div v-else class=\"backup-codes-content\">\n <!-- Device Info -->\n <div v-if=\"device\" class=\"backup-codes-device-info\">\n <div class=\"backup-codes-device-content\">\n <span class=\"backup-codes-device-icon\">📱</span>\n <div>\n <h3 class=\"backup-codes-device-name\">{{ device.device_name }}</h3>\n <p class=\"backup-codes-device-type\">{{ getDeviceTypeName(device.device_type) }}</p>\n </div>\n </div>\n </div>\n\n <!-- Warning -->\n <div class=\"backup-codes-warning\">\n <div class=\"backup-codes-warning-content\">\n <svg class=\"backup-codes-warning-icon\" fill=\"currentColor\" viewBox=\"0 0 20 20\">\n <path fill-rule=\"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 clip-rule=\"evenodd\" />\n </svg>\n <div>\n <p class=\"backup-codes-warning-title\">Important Security Information</p>\n <ul class=\"backup-codes-warning-list\">\n <li>• Each backup code can only be used once</li>\n <li>• Store these codes in a safe place</li>\n <li>• Use backup codes if you lose access to your authenticator</li>\n <li>• Regenerating codes will invalidate all previous codes</li>\n </ul>\n </div>\n </div>\n </div>\n\n <!-- Backup Codes -->\n <div v-if=\"backupCodes.length > 0\">\n <h3 class=\"backup-codes-section-title\">Your Backup Codes</h3>\n <div class=\"backup-codes-grid-wrapper\">\n <div class=\"backup-codes-grid\">\n <div v-for=\"(code, index) in backupCodes\" :key=\"index\" class=\"backup-codes-code-item\">\n {{ code }}\n </div>\n </div>\n </div>\n\n <div class=\"backup-codes-actions\">\n <StrandsUiButton variant=\"secondary\" size=\"sm\" @click=\"copyBackupCodes\">\n 📋 Copy All Codes\n </StrandsUiButton>\n <StrandsUiButton variant=\"secondary\" size=\"sm\" @click=\"downloadBackupCodes\">\n 💾 Download\n </StrandsUiButton>\n </div>\n </div>\n\n <!-- Actions -->\n <div class=\"backup-codes-main-actions\">\n <div class=\"backup-codes-main-actions-content\">\n <StrandsUiButton variant=\"secondary\" @click=\"regenerateCodes\" :disabled=\"loading\" :loading=\"loading\">\n 🔄 Regenerate Codes\n </StrandsUiButton>\n <StrandsUiButton variant=\"primary\" @click=\"closeModal\">\n Done\n </StrandsUiButton>\n </div>\n </div>\n\n <!-- Regeneration Warning -->\n <div v-if=\"showRegenerateWarning\" class=\"backup-codes-regenerate-warning\">\n <div class=\"backup-codes-regenerate-content\">\n <svg class=\"backup-codes-regenerate-icon\" fill=\"currentColor\" viewBox=\"0 0 20 20\">\n <path fill-rule=\"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 clip-rule=\"evenodd\" />\n </svg>\n <div>\n <p class=\"backup-codes-regenerate-title\">Regenerate Backup Codes?</p>\n <p class=\"backup-codes-regenerate-description\">\n This will invalidate all current backup codes. Make sure to save the new ones.\n </p>\n <div class=\"backup-codes-regenerate-actions\">\n <StrandsUiButton variant=\"primary\" size=\"sm\" @click=\"confirmRegenerate\" :disabled=\"loading\"\n :loading=\"loading\">\n Yes, Regenerate\n </StrandsUiButton>\n <StrandsUiButton variant=\"secondary\" size=\"sm\" @click=\"showRegenerateWarning = false\">\n Cancel\n </StrandsUiButton>\n </div>\n </div>\n </div>\n </div>\n </div>\n </UiModal>\n </div>\n</template>\n\n<script setup lang=\"ts\">\nimport { ref, watch, onMounted } from 'vue'\nimport { StrandsUiButton, StrandsUiLoader } from '../ui'\nimport UiModal from '../ui/UiModal.vue'\nimport { useStrandsMfa } from '../composables/useStrandsMfa'\nimport type { MfaDevice } from '../../types'\n\ninterface Props {\n show: boolean\n device?: MfaDevice | null\n}\n\ninterface Emits {\n (e: 'close'): void\n}\n\nconst props = defineProps<Props>()\nconst emit = defineEmits<Emits>()\n\nconst { regenerateBackupCodes, loading, getDeviceTypeName } = useStrandsMfa()\n\n// State\nconst backupCodes = ref<string[]>([])\nconst showRegenerateWarning = ref(false)\n\n// Load backup codes when modal opens\nwatch(() => props.show, async (newShow) => {\n if (newShow && props.device) {\n showRegenerateWarning.value = false\n // For now, we'll use the device's backup codes if available\n // In a real implementation, you might fetch fresh codes or show cached ones\n backupCodes.value = []\n }\n})\n\nonMounted(async () => {\n if (props.show && props.device) {\n // Initialize with empty codes - user needs to regenerate to see them\n backupCodes.value = []\n }\n})\n\nconst closeModal = () => {\n emit('close')\n}\n\nconst regenerateCodes = () => {\n showRegenerateWarning.value = true\n}\n\nconst confirmRegenerate = async () => {\n if (!props.device) return\n\n try {\n const response = await regenerateBackupCodes(props.device.id)\n backupCodes.value = response.backup_codes\n showRegenerateWarning.value = false\n } catch (error) {\n console.error('Failed to regenerate backup codes:', error)\n // Show error message\n }\n}\n\nconst copyBackupCodes = async () => {\n if (backupCodes.value.length === 0) return\n\n try {\n const codesText = backupCodes.value.join('\\n')\n await navigator.clipboard.writeText(codesText)\n // Could show a toast here\n console.log('Backup codes copied to clipboard')\n } catch (error) {\n console.error('Failed to copy backup codes:', error)\n }\n}\n\nconst downloadBackupCodes = () => {\n if (backupCodes.value.length === 0) return\n\n const deviceName = props.device?.device_name || 'device'\n const timestamp = new Date().toISOString().split('T')[0]\n const filename = `strands-backup-codes-${deviceName}-${timestamp}.txt`\n\n const content = [\n 'Strands Account Backup Codes',\n '============================',\n '',\n `Device: ${props.device?.device_name}`,\n `Generated: ${new Date().toLocaleString()}`,\n '',\n 'IMPORTANT:',\n '- Each code can only be used once',\n '- Store these codes in a safe place',\n '- Use these if you lose access to your authenticator',\n '',\n 'Backup Codes:',\n ...backupCodes.value.map((code, index) => `${index + 1}. ${code}`),\n '',\n '============================',\n ].join('\\n')\n\n const blob = new Blob([content], { type: 'text/plain' })\n const url = URL.createObjectURL(blob)\n const link = document.createElement('a')\n link.href = url\n link.download = filename\n document.body.appendChild(link)\n link.click()\n document.body.removeChild(link)\n URL.revokeObjectURL(url)\n}\n</script>\n\n<style scoped>\n/* Modal container */\n.backup-codes-modal {\n max-width: 28rem;\n}\n\n/* Header */\n.backup-codes-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n}\n\n.backup-codes-title {\n font-size: 1.25rem;\n font-weight: 700;\n color: #111827;\n}\n\n.backup-codes-close-button {\n color: #9ca3af;\n transition: color 0.2s ease;\n background: none;\n border: none;\n cursor: pointer;\n padding: 0.25rem;\n}\n\n.backup-codes-close-button:hover {\n color: #4b5563;\n}\n\n.backup-codes-close-icon {\n width: 1.25rem;\n height: 1.25rem;\n}\n\n/* Loading */\n.backup-codes-loading {\n display: flex;\n align-items: center;\n justify-content: center;\n padding: 2rem 0;\n}\n\n.backup-codes-loading-text {\n margin-left: 0.75rem;\n color: #4b5563;\n}\n\n/* Content */\n.backup-codes-content {\n display: flex;\n flex-direction: column;\n gap: 1.5rem;\n}\n\n/* Device info */\n.backup-codes-device-info {\n background-color: #f9fafb;\n border-radius: 0.5rem;\n padding: 1rem;\n}\n\n.backup-codes-device-content {\n display: flex;\n align-items: center;\n gap: 0.75rem;\n}\n\n.backup-codes-device-icon {\n font-size: 1.5rem;\n}\n\n.backup-codes-device-name {\n font-weight: 500;\n color: #111827;\n margin: 0;\n}\n\n.backup-codes-device-type {\n font-size: 0.875rem;\n color: #6b7280;\n margin: 0;\n}\n\n/* Warning */\n.backup-codes-warning {\n background-color: #fef2f2;\n border: 1px solid #fecaca;\n border-radius: 0.5rem;\n padding: 1rem;\n}\n\n.backup-codes-warning-content {\n display: flex;\n align-items: flex-start;\n gap: 0.5rem;\n}\n\n.backup-codes-warning-icon {\n width: 1.25rem;\n height: 1.25rem;\n color: #dc2626;\n margin-top: 0.125rem;\n flex-shrink: 0;\n}\n\n.backup-codes-warning-title {\n font-size: 0.875rem;\n font-weight: 500;\n color: #991b1b;\n margin: 0;\n}\n\n.backup-codes-warning-list {\n font-size: 0.875rem;\n color: #b91c1c;\n margin-top: 0.25rem;\n display: flex;\n flex-direction: column;\n gap: 0.25rem;\n list-style: none;\n padding: 0;\n}\n\n/* Section title */\n.backup-codes-section-title {\n font-size: 1.125rem;\n font-weight: 600;\n color: #111827;\n margin-bottom: 0.75rem;\n}\n\n/* Codes grid */\n.backup-codes-grid-wrapper {\n background-color: white;\n border: 1px solid #e5e7eb;\n border-radius: 0.5rem;\n padding: 1rem;\n}\n\n.backup-codes-grid {\n display: grid;\n grid-template-columns: repeat(2, 1fr);\n gap: 0.5rem;\n font-size: 0.875rem;\n font-family: 'SF Mono', Monaco, Inconsolata, 'Roboto Mono', Consolas, 'Courier New', monospace;\n}\n\n.backup-codes-code-item {\n text-align: center;\n padding: 0.5rem 0;\n background-color: #f9fafb;\n border-radius: 0.25rem;\n}\n\n/* Actions */\n.backup-codes-actions {\n display: flex;\n justify-content: center;\n margin-top: 1rem;\n gap: 0.75rem;\n}\n\n.backup-codes-main-actions {\n padding-top: 1rem;\n border-top: 1px solid #e5e7eb;\n}\n\n.backup-codes-main-actions-content {\n display: flex;\n justify-content: space-between;\n}\n\n/* Regenerate warning */\n.backup-codes-regenerate-warning {\n background-color: #fefce8;\n border: 1px solid #fde047;\n border-radius: 0.5rem;\n padding: 1rem;\n}\n\n.backup-codes-regenerate-content {\n display: flex;\n align-items: flex-start;\n gap: 0.5rem;\n}\n\n.backup-codes-regenerate-icon {\n width: 1.25rem;\n height: 1.25rem;\n color: #d97706;\n margin-top: 0.125rem;\n flex-shrink: 0;\n}\n\n.backup-codes-regenerate-title {\n font-size: 0.875rem;\n font-weight: 500;\n color: #92400e;\n margin: 0;\n}\n\n.backup-codes-regenerate-description {\n font-size: 0.875rem;\n color: #a16207;\n margin-top: 0.25rem;\n}\n\n.backup-codes-regenerate-actions {\n display: flex;\n gap: 0.5rem;\n margin-top: 0.75rem;\n}\n</style>\n","<template>\n <div class=\"accui-component-scope\">\n <UiModal :open=\"show\" card-class=\"confirm-modal\">\n <template #header>\n <h2 class=\"confirm-modal-title\">{{ title }}</h2>\n </template>\n \n <p class=\"confirm-modal-message\">{{ message }}</p>\n\n <div class=\"confirm-modal-actions\">\n <StrandsUiButton\n variant=\"secondary\"\n @click=\"handleCancel\"\n :disabled=\"loading\"\n >\n {{ cancelText }}\n </StrandsUiButton>\n <StrandsUiButton\n :variant=\"variant\"\n @click=\"handleConfirm\"\n :disabled=\"loading\"\n :loading=\"loading\"\n >\n {{ confirmText }}\n </StrandsUiButton>\n </div>\n </UiModal>\n </div>\n</template>\n\n<script setup lang=\"ts\">\nimport { ref } from 'vue'\nimport { StrandsUiButton } from '../ui'\nimport UiModal from '../ui/UiModal.vue'\n\ntype ButtonVariant = 'primary' | 'secondary' | 'ghost' | 'outline'\n\ninterface Props {\n show: boolean\n title: string\n message: string\n confirmText?: string\n cancelText?: string\n variant?: ButtonVariant\n}\n\ninterface Emits {\n (e: 'confirm'): void\n (e: 'cancel'): void\n}\n\nconst props = withDefaults(defineProps<Props>(), {\n confirmText: 'Confirm',\n cancelText: 'Cancel',\n variant: 'primary'\n})\n\nconst emit = defineEmits<Emits>()\n\nconst loading = ref(false)\n\nconst handleConfirm = () => {\n loading.value = true\n emit('confirm')\n // Note: Parent component should handle resetting loading state\n // by either closing the modal or setting loading to false\n}\n\nconst handleCancel = () => {\n emit('cancel')\n}\n</script>\n\n<style scoped>\n.confirm-modal {\n max-width: 24rem;\n}\n\n.confirm-modal-title {\n font-size: 1.125rem;\n font-weight: 700;\n color: #111827;\n}\n\n.confirm-modal-message {\n font-size: 0.875rem;\n color: #6b7280;\n margin-bottom: 1.5rem;\n}\n\n.confirm-modal-actions {\n display: flex;\n justify-content: flex-end;\n gap: 0.75rem;\n}\n</style>\n","<template>\n <div class=\"accui-component-scope\">\n <UiModal :open=\"showModal\" @close=\"closeModal\" card-class=\"mfa-modal-card\">\n <template #header>\n <div class=\"mfa-modal-header\">\n <h2 class=\"mfa-modal-title\">Two-Factor Authentication</h2>\n <button @click=\"closeModal\" class=\"mfa-modal-close\">\n <svg class=\"mfa-modal-close-icon\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M6 18L18 6M6 6l12 12\" />\n </svg>\n </button>\n </div>\n </template>\n <!-- Loading State -->\n <div v-if=\"mfaLoading\" class=\"mfa-loading\">\n <StrandsUiLoader :size=\"32\" />\n <span class=\"mfa-loading-text\">Loading MFA settings...</span>\n </div>\n\n <!-- Tab Navigation -->\n <div v-else class=\"mfa-content\">\n <!-- MFA Status Overview -->\n <div class=\"mfa-status-overview\">\n <div class=\"mfa-status-content\">\n <div>\n <h3 class=\"mfa-status-title\">Two-Factor Authentication</h3>\n <p class=\"mfa-status-subtitle\">\n {{ mfaEnabled ? 'Enabled' : 'Add extra security to your account' }}\n </p>\n </div>\n <div class=\"mfa-status-badges\">\n <span v-if=\"mfaEnabled\" class=\"mfa-status-badge mfa-status-badge-enabled\">\n <Shield :size=\"12\" class=\"mfa-badge-icon\" />\n Enabled\n </span>\n <span v-else class=\"mfa-status-badge mfa-status-badge-disabled\">\n Not Enabled\n </span>\n </div>\n </div>\n </div>\n\n <!-- Tab Navigation -->\n <div class=\"mfa-tabs-container\">\n <nav class=\"mfa-tabs-nav\" aria-label=\"Tabs\">\n <button @click=\"activeTab = 'add'\" :class=\"[\n 'mfa-tab-button',\n activeTab === 'add' ? 'mfa-tab-button-active' : 'mfa-tab-button-inactive'\n ]\">\n Add New Device\n </button>\n <button v-if=\"activeMfaDevices.length > 0\" @click=\"activeTab = 'manage'\" :class=\"[\n 'mfa-tab-button',\n activeTab === 'manage' ? 'mfa-tab-button-active' : 'mfa-tab-button-inactive'\n ]\">\n Active Devices ({{ activeMfaDevices.length }})\n </button>\n </nav>\n </div>\n\n <!-- Tab Content: Add New Device -->\n <div v-if=\"activeTab === 'add'\" class=\"mfa-add-devices\">\n <div>\n <h3 class=\"mfa-section-title\">Choose Your Authentication Method</h3>\n <div class=\"mfa-device-options\">\n <!-- TOTP Setup -->\n <div class=\"mfa-device-option\" @click=\"startTotpSetup\">\n <div class=\"mfa-device-layout\">\n <div class=\"mfa-device-icon-container mfa-device-icon-totp\">\n <Smartphone :size=\"24\" class=\"mfa-device-icon\" />\n </div>\n <div class=\"mfa-device-content\">\n <div class=\"mfa-device-info\">\n <h4 class=\"mfa-device-title\">Authenticator App</h4>\n <p class=\"mfa-device-description\">\n Use Google Authenticator, Authy, or any TOTP-compatible app to generate secure codes\n </p>\n </div>\n </div>\n <div class=\"mfa-device-action\">\n <StrandsUiButton variant=\"primary\" size=\"md\" @click.stop=\"startTotpSetup\" :disabled=\"mfaLoading\">\n Setup\n </StrandsUiButton>\n </div>\n </div>\n </div>\n\n <!-- Email MFA Setup -->\n <div class=\"mfa-device-option\" @click=\"startEmailMfaSetup\">\n <div class=\"mfa-device-layout\">\n <div class=\"mfa-device-icon-container mfa-device-icon-email\">\n <Mail :size=\"24\" class=\"mfa-device-icon\" />\n </div>\n <div class=\"mfa-device-content\">\n <div class=\"mfa-device-info\">\n <h4 class=\"mfa-device-title\">Email Verification</h4>\n <p class=\"mfa-device-description\">\n Receive verification codes directly in your email inbox for easy access\n </p>\n </div>\n </div>\n <div class=\"mfa-device-action\">\n <StrandsUiButton variant=\"primary\" size=\"md\" @click.stop=\"startEmailMfaSetup\"\n :disabled=\"mfaLoading\">\n Setup\n </StrandsUiButton>\n </div>\n </div>\n </div>\n\n <!-- Hardware Key Setup - Temporarily Disabled -->\n <!-- \n <div class=\"group p-6 bg-white border border-gray-200 rounded-xl hover:border-gray-300 hover:shadow-md transition-all duration-200 cursor-pointer\" @click=\"startHardwareKeySetup\">\n <div class=\"flex items-center justify-between\">\n <div class=\"flex-shrink-0 w-14 h-14 bg-[var(--strands-primary)] bg-opacity-10 rounded-xl flex items-center justify-center group-hover:bg-[var(--strands-primary)] group-hover:bg-opacity-15 transition-colors\">\n <KeyRound :size=\"24\" class=\"text-[var(--strands-primary)]\" />\n </div>\n <div class=\"flex items-start space-x-4\">\n <div class=\"min-w-0 flex-1\">\n <h4 class=\"font-semibold text-gray-900 text-lg\">Hardware Security Key</h4>\n <p class=\"text-xs text-gray-500 mt-2\">\n Use YubiKey, FIDO2, or other physical security keys for ultimate protection\n </p>\n </div>\n </div>\n <div class=\"flex flex-col space-y-2 ml-4\">\n <StrandsUiButton\n variant=\"primary\"\n size=\"md\"\n @click.stop=\"startHardwareKeySetup\"\n :disabled=\"mfaLoading\"\n >\n Setup\n </StrandsUiButton>\n </div>\n </div>\n </div>\n\n <-- Passkey Setup - Temporarily Disabled -->\n <!-- \n <div class=\"group p-6 bg-white border border-gray-200 rounded-xl hover:border-gray-300 hover:shadow-md transition-all duration-200 cursor-pointer\" @click=\"startPasskeySetup\">\n <div class=\"flex items-center justify-between\">\n <div class=\"flex-shrink-0 w-14 h-14 bg-[var(--strands-primary)] bg-opacity-10 rounded-xl flex items-center justify-center group-hover:bg-[var(--strands-primary)] group-hover:bg-opacity-15 transition-colors\">\n <Shield :size=\"24\" class=\"text-[var(--strands-primary)]\" />\n </div>\n <div class=\"flex items-start space-x-4\">\n <div class=\"min-w-0 flex-1\">\n <h4 class=\"font-semibold text-gray-900 text-lg\">Passkey</h4>\n <p class=\"text-xs text-gray-500 mt-2\">\n Use your device's built-in biometrics, PIN, or cross-device passkeys\n </p>\n </div>\n </div>\n <div class=\"flex flex-col space-y-2 ml-4\">\n <StrandsUiButton\n variant=\"primary\"\n size=\"md\"\n @click.stop=\"startPasskeySetup\"\n :disabled=\"mfaLoading\"\n >\n Setup\n </StrandsUiButton>\n </div>\n </div>\n </div>\n -->\n </div>\n </div>\n </div>\n\n <!-- Tab Content: Active Devices -->\n <div v-else-if=\"activeTab === 'manage' && activeMfaDevices.length > 0\" class=\"mfa-manage-devices\">\n <div>\n <h3 class=\"mfa-section-title\">Manage Your Active Devices</h3>\n <div class=\"mfa-devices-list\">\n <div v-for=\"device in activeMfaDevices\" :key=\"device.id\" class=\"mfa-device-card\">\n <div class=\"mfa-device-card-content\">\n <div class=\"mfa-device-card-info\">\n <div class=\"mfa-device-card-icon-container\" :class=\"getDeviceIconBackground(device.device_type)\">\n <component :is=\"getDeviceIconComponent(device.device_type)\" :size=\"24\"\n class=\"mfa-device-card-icon\" />\n </div>\n <div class=\"mfa-device-card-details\">\n <h4 class=\"mfa-device-card-name\">{{ device.device_name }}</h4>\n <p class=\"mfa-device-card-type\">\n {{ getDeviceTypeName(device.device_type) }}\n </p>\n <p class=\"mfa-device-card-last-used\">\n Last used {{ formatLastUsed(device.last_used_at) }}\n </p>\n </div>\n </div>\n <div class=\"mfa-device-card-actions\">\n <!-- Backup codes button for TOTP, Hardware Key, and Passkey devices -->\n <StrandsUiButton\n v-if=\"device.device_type === 'totp' || device.device_type === 'hardware' || device.device_type === 'passkey'\"\n variant=\"secondary\" size=\"sm\" @click=\"showBackupCodes(device)\" :disabled=\"mfaLoading\">\n <KeyRound :size=\"14\" class=\"mfa-button-icon\" />\n Backup Codes\n </StrandsUiButton>\n\n <!-- Test email MFA -->\n <StrandsUiButton v-if=\"device.device_type === 'email'\" variant=\"secondary\" size=\"sm\"\n @click=\"testEmailMfa(device)\" :disabled=\"mfaLoading\">\n <Mail :size=\"14\" class=\"mfa-button-icon\" />\n Send Test Code\n </StrandsUiButton>\n\n <!-- Remove device -->\n <StrandsUiButton variant=\"secondary\" size=\"sm\" @click=\"confirmDisableDevice(device)\"\n :disabled=\"mfaLoading\" class=\"mfa-remove-button\">\n <Trash2 :size=\"14\" class=\"mfa-button-icon\" />\n Remove\n </StrandsUiButton>\n </div>\n </div>\n </div>\n </div>\n </div>\n </div>\n </div>\n\n <!-- TOTP Setup Modal -->\n <StrandsTotpSetupModal v-if=\"showTotpSetup\" :show=\"showTotpSetup\" @close=\"showTotpSetup = false\"\n @success=\"handleTotpSetupSuccess\" />\n\n <!-- Email MFA Setup Modal -->\n <StrandsEmailMfaSetupModal v-if=\"showEmailMfaSetup\" :show=\"showEmailMfaSetup\" @close=\"showEmailMfaSetup = false\"\n @success=\"handleEmailMfaSetupSuccess\" />\n\n <!-- Hardware Key Setup Modal -->\n <StrandsHardwareKeySetupModal v-if=\"showHardwareKeySetup\" :show=\"showHardwareKeySetup\" :device-type=\"'hardware'\"\n @close=\"showHardwareKeySetup = false\" @success=\"handleHardwareKeySetupSuccess\" />\n\n <!-- Passkey Setup Modal -->\n <StrandsHardwareKeySetupModal v-if=\"showPasskeySetup\" :show=\"showPasskeySetup\" :device-type=\"'passkey'\"\n @close=\"showPasskeySetup = false\" @success=\"handlePasskeySetupSuccess\" />\n\n <!-- Backup Codes Modal -->\n <StrandsBackupCodesModal v-if=\"showBackupCodesModal\" :show=\"showBackupCodesModal\" :device=\"selectedDevice\"\n @close=\"showBackupCodesModal = false\" />\n\n </UiModal>\n\n <!-- Confirm Disable Modal -->\n <StrandsConfirmModal v-if=\"showConfirmDisable\" :show=\"showConfirmDisable\" title=\"Remove MFA Device\"\n :message=\"`Are you sure you want to remove '${selectedDevice?.device_name}'? This action cannot be undone.`\"\n confirm-text=\"Remove Device\" cancel-text=\"Keep Device\" variant=\"secondary\" @confirm=\"handleDisableDevice\"\n @cancel=\"showConfirmDisable = false\" />\n </div>\n</template>\n\n<script setup lang=\"ts\">\nimport { ref, computed, onMounted, watch, h } from 'vue'\nimport { StrandsUiButton, StrandsUiLoader } from '../ui'\n\n// Inline SVG icon components using render functions (no runtime compilation needed)\nconst Smartphone = {\n props: { size: { type: [String, Number], default: 24 } },\n render(this: any) {\n return h('svg', { \n width: this.size, \n height: this.size, \n fill: 'none', \n stroke: 'currentColor', \n viewBox: '0 0 24 24' \n }, [\n h('rect', { x: '5', y: '2', width: '14', height: '20', rx: '2', ry: '2' }),\n h('line', { x1: '12', y1: '18', x2: '12.01', y2: '18' })\n ])\n }\n}\n\nconst Mail = {\n props: { size: { type: [String, Number], default: 24 } },\n render(this: any) {\n return h('svg', { \n width: this.size, \n height: this.size, \n fill: 'none', \n stroke: 'currentColor', \n viewBox: '0 0 24 24' \n }, [\n h('path', { d: 'm4 4 16 0c1.1 0 2 .9 2 2l0 12c0 1.1-.9 2-2 2l-16 0c-1.1 0-2-.9-2-2l0-12c0-1.1.9-2 2-2z' }),\n h('polyline', { points: '22,6 12,13 2,6' })\n ])\n }\n}\n\nconst KeyRound = {\n props: { size: { type: [String, Number], default: 24 } },\n render(this: any) {\n return h('svg', { \n width: this.size, \n height: this.size, \n fill: 'none', \n stroke: 'currentColor', \n viewBox: '0 0 24 24' \n }, [\n h('path', { d: 'M2.586 17.414A2 2 0 0 0 2 18.828V21a1 1 0 0 0 1 1h3a1 1 0 0 0 1-1v-1a1 1 0 0 1 1-1h1a1 1 0 0 0 1-1v-1a1 1 0 0 1 1-1h.172a2 2 0 0 0 1.414-.586l.814-.814a6.5 6.5 0 1 0-4-4z' }),\n h('circle', { cx: '16.5', cy: '7.5', r: '.5', fill: 'currentColor' })\n ])\n }\n}\n\nconst Shield = {\n props: { size: { type: [String, Number], default: 24 } },\n render(this: any) {\n return h('svg', { \n width: this.size, \n height: this.size, \n fill: 'none', \n stroke: 'currentColor', \n viewBox: '0 0 24 24' \n }, [\n h('path', { d: 'M20 13c0 5-3.5 7.5-7.66 8.95a1 1 0 0 1-.67-.01C7.5 20.5 4 18 4 13V6a1 1 0 0 1 1-1c2 0 4.5-1.2 6.24-2.72a1.17 1.17 0 0 1 1.52 0C14.51 3.81 17 5 19 5a1 1 0 0 1 1 1z' })\n ])\n }\n}\n\nconst Trash2 = {\n props: { size: { type: [String, Number], default: 24 } },\n render(this: any) {\n return h('svg', { \n width: this.size, \n height: this.size, \n fill: 'none', \n stroke: 'currentColor', \n viewBox: '0 0 24 24' \n }, [\n h('path', { d: 'm3 6 18 0' }),\n h('path', { d: 'm19 6-1 14c0 1-1 2-2 2l-8 0c-1 0-2-1-2-2l-1-14' }),\n h('path', { d: 'm8 6V4c0-1 1-2 2-2h4c1 0 2 1 2 2v2' }),\n h('line', { x1: '10', x2: '10', y1: '11', y2: '17' }),\n h('line', { x1: '14', x2: '14', y1: '11', y2: '17' })\n ])\n }\n}\nimport UiModal from '../ui/UiModal.vue'\nimport StrandsTotpSetupModal from './StrandsTotpSetupModal.vue'\nimport StrandsEmailMfaSetupModal from './StrandsEmailMfaSetupModal.vue'\nimport StrandsHardwareKeySetupModal from './StrandsHardwareKeySetupModal.vue'\nimport StrandsBackupCodesModal from './StrandsBackupCodesModal.vue'\nimport StrandsConfirmModal from './StrandsConfirmModal.vue'\nimport { useStrandsMfa } from '../composables/useStrandsMfa'\nimport type { MfaDevice } from '../../types'\n\ninterface Props {\n show: boolean\n}\n\ninterface Emits {\n (e: 'close'): void\n (e: 'mfa-updated'): void\n}\n\nconst props = defineProps<Props>()\nconst emit = defineEmits<Emits>()\n\n// MFA composable\nconst {\n mfaDevices,\n mfaEnabled,\n loading: mfaLoading,\n activeMfaDevices,\n fetchMfaDevices,\n disableMfaDevice,\n sendEmailMfaCode,\n getDeviceTypeIcon,\n getDeviceTypeName,\n formatLastUsed,\n} = useStrandsMfa()\n\n// Modal states\nconst showModal = computed(() => props.show)\nconst activeTab = ref<'add' | 'manage'>('add')\nconst showTotpSetup = ref(false)\nconst showEmailMfaSetup = ref(false)\nconst showHardwareKeySetup = ref(false)\nconst showPasskeySetup = ref(false)\nconst showBackupCodesModal = ref(false)\nconst showConfirmDisable = ref(false)\nconst selectedDevice = ref<MfaDevice | null>(null)\n\n// Load MFA devices when modal opens\nwatch(() => props.show, async (newShow) => {\n if (newShow) {\n await fetchMfaDevices()\n }\n})\n\nonMounted(async () => {\n if (props.show) {\n await fetchMfaDevices()\n }\n})\n\nconst closeModal = () => {\n emit('close')\n}\n\nconst startTotpSetup = () => {\n showTotpSetup.value = true\n}\n\nconst startEmailMfaSetup = () => {\n showEmailMfaSetup.value = true\n}\n\nconst startHardwareKeySetup = () => {\n showHardwareKeySetup.value = true\n}\n\nconst startPasskeySetup = () => {\n showPasskeySetup.value = true\n}\n\nconst showBackupCodes = (device: MfaDevice) => {\n selectedDevice.value = device\n showBackupCodesModal.value = true\n}\n\nconst testEmailMfa = async (device: MfaDevice) => {\n try {\n await sendEmailMfaCode(device.id)\n // Show success message or toast\n console.log('Test code sent to email')\n } catch (error) {\n console.error('Failed to send test code:', error)\n // Show error message\n }\n}\n\nconst confirmDisableDevice = (device: MfaDevice) => {\n selectedDevice.value = device\n showConfirmDisable.value = true\n}\n\nconst handleDisableDevice = async () => {\n if (selectedDevice.value) {\n try {\n await disableMfaDevice(selectedDevice.value.id)\n showConfirmDisable.value = false\n selectedDevice.value = null\n emit('mfa-updated')\n } catch (error) {\n console.error('Failed to disable MFA device:', error)\n // Show error message\n }\n }\n}\n\nconst handleTotpSetupSuccess = async () => {\n showTotpSetup.value = false\n await fetchMfaDevices()\n activeTab.value = 'manage' // Switch to manage tab after setup\n emit('mfa-updated')\n}\n\nconst handleEmailMfaSetupSuccess = async () => {\n showEmailMfaSetup.value = false\n await fetchMfaDevices()\n activeTab.value = 'manage' // Switch to manage tab after setup\n emit('mfa-updated')\n}\n\nconst handleHardwareKeySetupSuccess = async () => {\n showHardwareKeySetup.value = false\n await fetchMfaDevices()\n activeTab.value = 'manage' // Switch to manage tab after setup\n emit('mfa-updated')\n}\n\nconst handlePasskeySetupSuccess = async () => {\n showPasskeySetup.value = false\n await fetchMfaDevices()\n activeTab.value = 'manage' // Switch to manage tab after setup\n emit('mfa-updated')\n}\n\nconst getDeviceIconBackground = (deviceType: string) => {\n switch (deviceType) {\n case 'totp':\n return 'mfa-device-bg-blue'\n case 'email':\n return 'mfa-device-bg-green'\n case 'hardware':\n return 'mfa-device-bg-purple'\n case 'passkey':\n return 'mfa-device-bg-indigo'\n default:\n return 'mfa-device-bg-gray'\n }\n}\n\nconst getDeviceIconComponent = (deviceType: string) => {\n switch (deviceType) {\n case 'totp':\n return Smartphone\n case 'email':\n return Mail\n case 'hardware':\n return KeyRound\n case 'passkey':\n return Shield\n default:\n return Shield\n }\n}\n</script>\n\n<style scoped>\n/* Modal styles */\n.mfa-modal-card {\n max-width: 56rem;\n}\n\n.mfa-modal-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n}\n\n.mfa-modal-title {\n font-size: 1.5rem;\n font-weight: 700;\n color: #111827;\n}\n\n.mfa-modal-close {\n color: #9ca3af;\n background: none;\n border: none;\n cursor: pointer;\n transition: color 0.2s ease;\n}\n\n.mfa-modal-close:hover {\n color: #4b5563;\n}\n\n.mfa-modal-close-icon {\n width: 1.5rem;\n height: 1.5rem;\n}\n\n/* Loading state */\n.mfa-loading {\n display: flex;\n align-items: center;\n justify-content: center;\n padding: 3rem 0;\n}\n\n.mfa-loading-text {\n margin-left: 0.75rem;\n color: #4b5563;\n}\n\n/* Main content */\n.mfa-content {\n display: flex;\n flex-direction: column;\n gap: 1.5rem;\n}\n\n/* Status overview */\n.mfa-status-overview {\n background-color: #f9fafb;\n border-radius: 0.75rem;\n padding: 1rem;\n}\n\n.mfa-status-content {\n display: flex;\n align-items: center;\n justify-content: space-between;\n}\n\n.mfa-status-title {\n font-weight: 600;\n color: #111827;\n}\n\n.mfa-status-subtitle {\n font-size: 0.875rem;\n color: #4b5563;\n}\n\n.mfa-status-badges {\n display: flex;\n align-items: center;\n}\n\n.mfa-status-badge {\n display: inline-flex;\n align-items: center;\n padding: 0.125rem 0.625rem;\n border-radius: 9999px;\n font-size: 0.75rem;\n font-weight: 500;\n}\n\n.mfa-status-badge-enabled {\n background-color: #dcfce7;\n color: #166534;\n}\n\n.mfa-status-badge-disabled {\n background-color: #f3f4f6;\n color: #4b5563;\n}\n\n.mfa-badge-icon {\n margin-right: 0.25rem;\n}\n\n/* Tab navigation */\n.mfa-tabs-container {\n border-bottom: 1px solid #e5e7eb;\n}\n\n.mfa-tabs-nav {\n margin-bottom: -1px;\n display: flex;\n gap: 2rem;\n}\n\n.mfa-tab-button {\n white-space: nowrap;\n padding: 0.5rem 0.25rem;\n border-bottom: 2px solid transparent;\n font-weight: 500;\n font-size: 0.875rem;\n background: none;\n border-top: none;\n border-left: none;\n border-right: none;\n cursor: pointer;\n transition: all 0.2s ease;\n}\n\n.mfa-tab-button-active {\n border-bottom-color: var(--strands-primary, #EA00A8);\n color: var(--strands-primary, #EA00A8);\n}\n\n.mfa-tab-button-inactive {\n border-bottom-color: transparent;\n color: #6b7280;\n}\n\n.mfa-tab-button-inactive:hover {\n color: #374151;\n border-bottom-color: #d1d5db;\n}\n\n/* Section titles */\n.mfa-section-title {\n font-size: 1.25rem;\n font-weight: 600;\n color: #111827;\n margin-bottom: 1.5rem;\n}\n\n/* Add devices section */\n.mfa-add-devices {\n display: flex;\n flex-direction: column;\n gap: 1.5rem;\n}\n\n.mfa-device-options {\n display: flex;\n flex-direction: column;\n gap: 1rem;\n}\n\n.mfa-device-option {\n padding: 1.5rem;\n background-color: #ffffff;\n border: 1px solid #e5e7eb;\n border-radius: 0.75rem;\n cursor: pointer;\n transition: all 0.2s ease;\n group: hover;\n}\n\n.mfa-device-option:hover {\n border-color: #d1d5db;\n box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1);\n}\n\n.mfa-device-layout {\n display: flex;\n align-items: center;\n justify-content: space-between;\n}\n\n.mfa-device-icon-container {\n flex-shrink: 0;\n width: 3.5rem;\n height: 3.5rem;\n border-radius: 0.75rem;\n display: flex;\n align-items: center;\n justify-content: center;\n transition: background-color 0.2s ease;\n}\n\n.mfa-device-icon-totp {\n background-color: rgba(59, 130, 246, 0.1);\n}\n\n.mfa-device-option:hover .mfa-device-icon-totp {\n background-color: rgba(59, 130, 246, 0.15);\n}\n\n.mfa-device-icon-email {\n background-color: rgba(16, 185, 129, 0.1);\n}\n\n.mfa-device-option:hover .mfa-device-icon-email {\n background-color: rgba(16, 185, 129, 0.15);\n}\n\n.mfa-device-icon {\n color: var(--strands-primary, #EA00A8);\n}\n\n.mfa-device-content {\n display: flex;\n align-items: flex-start;\n gap: 1rem;\n margin-left: 1rem;\n margin-right: 1rem;\n}\n\n.mfa-device-info {\n min-width: 0;\n flex: 1;\n}\n\n.mfa-device-title {\n font-weight: 600;\n color: #111827;\n font-size: 1.125rem;\n}\n\n.mfa-device-description {\n font-size: 0.75rem;\n color: #6b7280;\n margin-top: 0.5rem;\n}\n\n.mfa-device-action {\n display: flex;\n flex-direction: column;\n gap: 0.5rem;\n margin-left: 1rem;\n}\n\n/* Manage devices section */\n.mfa-manage-devices {\n display: flex;\n flex-direction: column;\n gap: 1.5rem;\n}\n\n.mfa-devices-list {\n max-height: 24rem;\n overflow-y: auto;\n display: flex;\n flex-direction: column;\n gap: 1rem;\n padding-right: 0.5rem;\n}\n\n.mfa-device-card {\n padding: 1.5rem;\n background-color: #ffffff;\n border: 1px solid #e5e7eb;\n border-radius: 0.75rem;\n transition: all 0.2s ease;\n}\n\n.mfa-device-card:hover {\n border-color: #d1d5db;\n box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1);\n}\n\n.mfa-device-card-content {\n display: flex;\n align-items: flex-start;\n justify-content: space-between;\n}\n\n.mfa-device-card-info {\n display: flex;\n align-items: flex-start;\n gap: 1rem;\n}\n\n.mfa-device-card-icon-container {\n flex-shrink: 0;\n width: 3.5rem;\n height: 3.5rem;\n border-radius: 0.75rem;\n display: flex;\n align-items: center;\n justify-content: center;\n}\n\n.mfa-device-card-icon {\n color: #4b5563;\n}\n\n.mfa-device-card-details {\n min-width: 0;\n flex: 1;\n}\n\n.mfa-device-card-name {\n font-weight: 600;\n color: #111827;\n font-size: 1.125rem;\n}\n\n.mfa-device-card-type {\n font-size: 0.875rem;\n color: #4b5563;\n margin-top: 0.25rem;\n}\n\n.mfa-device-card-last-used {\n font-size: 0.75rem;\n color: #6b7280;\n margin-top: 0.5rem;\n}\n\n.mfa-device-card-actions {\n display: flex;\n flex-direction: column;\n gap: 0.5rem;\n margin-left: 1rem;\n}\n\n.mfa-button-icon {\n margin-right: 0.5rem;\n}\n\n.mfa-remove-button {\n color: #dc2626;\n border-color: #fecaca;\n}\n\n.mfa-remove-button:hover {\n background-color: #fef2f2;\n color: #b91c1c;\n}\n\n/* Device type background colors */\n.mfa-device-bg-blue {\n background-color: #eff6ff;\n}\n\n.mfa-device-card:hover .mfa-device-bg-blue {\n background-color: #dbeafe;\n}\n\n.mfa-device-bg-green {\n background-color: #f0fdf4;\n}\n\n.mfa-device-card:hover .mfa-device-bg-green {\n background-color: #dcfce7;\n}\n\n.mfa-device-bg-purple {\n background-color: #faf5ff;\n}\n\n.mfa-device-card:hover .mfa-device-bg-purple {\n background-color: #f3e8ff;\n}\n\n.mfa-device-bg-indigo {\n background-color: #eef2ff;\n}\n\n.mfa-device-card:hover .mfa-device-bg-indigo {\n background-color: #e0e7ff;\n}\n\n.mfa-device-bg-gray {\n background-color: #f9fafb;\n}\n\n.mfa-device-card:hover .mfa-device-bg-gray {\n background-color: #f3f4f6;\n}\n\n/* Responsive design */\n@media (max-width: 768px) {\n .mfa-device-layout {\n flex-direction: column;\n align-items: flex-start;\n gap: 1rem;\n }\n\n .mfa-device-content {\n margin-left: 0;\n margin-right: 0;\n width: 100%;\n }\n\n .mfa-device-action {\n margin-left: 0;\n width: 100%;\n }\n\n .mfa-device-card-content {\n flex-direction: column;\n gap: 1rem;\n }\n\n .mfa-device-card-actions {\n margin-left: 0;\n width: 100%;\n }\n}\n\n</style>\n","<template>\n <div class=\"accui-component-scope\">\n <UiModal :open=\"true\" @close=\"$emit('close')\" card-class=\"max-w-lg\">\n <template #header>\n <div class=\"settings-header\">\n <h2 class=\"settings-title\">Settings</h2>\n <button \n class=\"settings-close-button\"\n @click=\"$emit('close')\"\n type=\"button\"\n >\n <svg class=\"settings-close-icon\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M6 18L18 6M6 6l12 12\" />\n </svg>\n </button>\n </div>\n </template>\n\n <!-- Audio Preferences Section -->\n <div class=\"settings-content\">\n <div class=\"settings-section\">\n <h3 class=\"settings-section-title\">Audio Preferences</h3>\n \n <!-- Level Up Sounds Toggle -->\n <div class=\"settings-option\">\n <div class=\"settings-option-content\">\n <div class=\"settings-option-info\">\n <label for=\"level-up-sounds\" class=\"settings-option-label\">\n Level Up Sounds\n </label>\n <p class=\"settings-option-description\">\n Play sound effects when you level up\n </p>\n </div>\n <UiToggle\n id=\"level-up-sounds\"\n v-model=\"localSettings.levelUpSounds\"\n @update:model-value=\"updateSetting('levelUpSounds', $event)\"\n />\n </div>\n </div>\n\n <!-- Milestone Level Up Sounds Toggle -->\n <div class=\"settings-option\">\n <div class=\"settings-option-content\">\n <div class=\"settings-option-info\">\n <label for=\"milestone-sounds\" class=\"settings-option-label\">\n Milestone Level Sounds\n </label>\n <p class=\"settings-option-description\">\n Play special celebration sounds for milestone levels (10, 25, 50, 100, 150, 200)\n </p>\n </div>\n <UiToggle\n id=\"milestone-sounds\"\n v-model=\"localSettings.milestoneSounds\"\n @update:model-value=\"updateSetting('milestoneSounds', $event)\"\n />\n </div>\n </div>\n </div>\n </div>\n\n <template #footer>\n <div class=\"settings-footer\">\n <UiButton \n variant=\"secondary\" \n @click=\"$emit('close')\"\n >\n Close\n </UiButton>\n <UiButton \n variant=\"primary\" \n @click=\"saveSettings\"\n :loading=\"saving\"\n >\n {{ saving ? 'Saving...' : 'Save Settings' }}\n </UiButton>\n </div>\n </template>\n </UiModal>\n </div>\n</template>\n\n<script setup lang=\"ts\">\nimport { ref, reactive, watch } from 'vue'\nimport { useStrandsAuth } from '../composables/useStrandsAuth'\nimport UiButton from '../ui/UiButton.vue'\nimport UiToggle from '../ui/UiToggle.vue'\nimport UiModal from '../ui/UiModal.vue'\n\ninterface AudioSettings {\n levelUpSounds: boolean\n milestoneSounds: boolean\n}\n\ninterface Props {\n open?: boolean\n}\n\ninterface Emits {\n (e: 'close'): void\n (e: 'settings-updated', settings: AudioSettings): void\n}\n\nconst props = withDefaults(defineProps<Props>(), {\n open: false\n})\n\nconst emit = defineEmits<Emits>()\n\nconst { currentUser, updateUserSettings } = useStrandsAuth()\nconst saving = ref(false)\n\n// Initialize local settings from user settings or defaults\nconst localSettings = reactive<AudioSettings>({\n levelUpSounds: currentUser.value?.settings?.levelUpSounds ?? true,\n milestoneSounds: currentUser.value?.settings?.milestoneSounds ?? true\n})\n\n// Watch for changes in user settings\nwatch(() => currentUser.value?.settings, (newSettings) => {\n if (newSettings) {\n localSettings.levelUpSounds = newSettings.levelUpSounds ?? true\n localSettings.milestoneSounds = newSettings.milestoneSounds ?? true\n }\n}, { deep: true })\n\nconst handleOverlayClick = () => {\n emit('close')\n}\n\nconst updateSetting = (key: keyof AudioSettings, value: boolean) => {\n localSettings[key] = value\n}\n\nconst saveSettings = async () => {\n if (saving.value) return\n \n saving.value = true\n \n try {\n // Update settings on server\n await updateUserSettings({\n ...currentUser.value?.settings,\n ...localSettings\n })\n \n // Emit updated settings to parent\n emit('settings-updated', { ...localSettings })\n \n // Close modal\n emit('close')\n } catch (error) {\n console.error('Failed to save settings:', error)\n // TODO: Show error message to user\n } finally {\n saving.value = false\n }\n}\n</script>\n\n<style scoped>\n.settings-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n}\n\n.settings-title {\n font-size: 1.25rem;\n font-weight: 700;\n color: #111827;\n}\n\n.settings-close-button {\n color: #9ca3af;\n background: none;\n border: none;\n padding: 0;\n cursor: pointer;\n transition: color 0.2s ease;\n}\n\n.settings-close-button:hover {\n color: #6b7280;\n}\n\n.settings-close-icon {\n width: 1.5rem;\n height: 1.5rem;\n}\n\n.settings-content {\n display: flex;\n flex-direction: column;\n gap: 1.5rem;\n}\n\n.settings-section {\n /* Section container */\n}\n\n.settings-section-title {\n font-size: 1.125rem;\n font-weight: 600;\n color: #111827;\n margin-bottom: 1rem;\n}\n\n.settings-option {\n background-color: #f9fafb;\n border: 1px solid #e5e7eb;\n border-radius: 0.5rem;\n padding: 1rem;\n margin-bottom: 1rem;\n}\n\n.settings-option:last-child {\n margin-bottom: 0;\n}\n\n.settings-option-content {\n display: flex;\n align-items: center;\n justify-content: space-between;\n}\n\n.settings-option-info {\n flex: 1;\n}\n\n.settings-option-label {\n display: block;\n font-size: 0.875rem;\n font-weight: 500;\n color: #111827;\n margin-bottom: 0.25rem;\n}\n\n.settings-option-description {\n font-size: 0.75rem;\n color: #6b7280;\n}\n\n.settings-footer {\n display: flex;\n justify-content: flex-end;\n gap: 0.75rem;\n}\n\n/* Override Tailwind classes with CSS properties */\n.max-w-lg {\n max-width: 32rem;\n}\n</style>\n\n","<template>\n <StrandsUiModal \n :open=\"visible\" \n @close=\"handleClose\"\n >\n <template #header>\n <div class=\"modal-header-content\">\n <h2 class=\"modal-title\">Active Sessions</h2>\n <p class=\"modal-subtitle\">Manage your {{ sessions.length }} active device{{ sessions.length !== 1 ? 's' : '' }}</p>\n </div>\n </template>\n \n <div class=\"strands-sessions-modal\">\n <!-- Loading State -->\n <div v-if=\"loading\" class=\"sessions-loading\">\n <StrandsUiLoader :size=\"40\" />\n <p class=\"loading-text\">Loading sessions...</p>\n </div>\n\n <!-- Empty State -->\n <div v-else-if=\"sessions.length === 0\" class=\"sessions-empty\">\n <div class=\"empty-icon\">\n <svg width=\"48\" height=\"48\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.5\">\n <rect x=\"2\" y=\"4\" width=\"20\" height=\"16\" rx=\"2\" />\n <line x1=\"8\" y1=\"10\" x2=\"16\" y2=\"10\" />\n <line x1=\"8\" y1=\"14\" x2=\"12\" y2=\"14\" />\n </svg>\n </div>\n <h3 class=\"empty-title\">No Active Sessions</h3>\n <p class=\"empty-description\">You don't have any active sessions at the moment.</p>\n </div>\n\n <!-- Sessions List -->\n <div v-else class=\"sessions-container\">\n <!-- Session Statistics -->\n <div v-if=\"stats\" class=\"session-stats\">\n <div class=\"stat-card\">\n <span class=\"stat-label\">Total Sessions</span>\n <span class=\"stat-value\">{{ stats.total_sessions }}</span>\n </div>\n <div class=\"stat-card\">\n <span class=\"stat-label\">Active Devices</span>\n <span class=\"stat-value\">{{ stats.active_sessions }}</span>\n </div>\n <div v-if=\"stats.unique_locations && stats.unique_locations.length > 0\" class=\"stat-card\">\n <span class=\"stat-label\">Locations</span>\n <span class=\"stat-value\">{{ stats.unique_locations.length }}</span>\n </div>\n </div>\n\n <!-- Sessions List -->\n <div class=\"sessions-list\">\n <div\n v-for=\"session in sessions\"\n :key=\"session.id\"\n class=\"session-card\"\n :class=\"{ 'current-session': session.is_current }\"\n >\n <!-- Session Header -->\n <div class=\"session-header\">\n <div class=\"session-device\">\n <div class=\"device-icon\">\n <component \n :is=\"getDeviceIcon(session.device_type)\" \n :size=\"20\"\n />\n </div>\n <div class=\"device-info\">\n <h4 class=\"device-name\">\n {{ session.device_name || 'Unknown Device' }}\n <span v-if=\"session.is_current\" class=\"current-badge\">Current</span>\n </h4>\n <p class=\"device-type\">{{ session.device_type || 'Unknown type' }}</p>\n </div>\n </div>\n \n <StrandsUiButton\n v-if=\"session.is_current\"\n variant=\"outline\"\n size=\"sm\"\n @click=\"handleRevokeCurrentSession(session.id)\"\n :disabled=\"revokingSession === session.id\"\n class=\"current-session-button\"\n >\n <StrandsUiLoader v-if=\"revokingSession === session.id\" :size=\"16\" />\n <span v-else>Sign Out</span>\n </StrandsUiButton>\n \n <StrandsUiButton\n v-else\n variant=\"outline\"\n size=\"sm\"\n @click=\"handleRevokeSession(session.id)\"\n :disabled=\"revokingSession === session.id\"\n >\n <StrandsUiLoader v-if=\"revokingSession === session.id\" :size=\"16\" />\n <span v-else>End Session</span>\n </StrandsUiButton>\n </div>\n\n <!-- Session Details -->\n <div class=\"session-details\">\n <div class=\"detail-row\">\n <span class=\"detail-icon\">\n <MapPin :size=\"14\" />\n </span>\n <span class=\"detail-text\">\n <template v-if=\"session.city && session.country\">\n {{ session.city }}, {{ session.country }}\n </template>\n <template v-else-if=\"session.country\">\n {{ session.country }}\n </template>\n <template v-else>\n Location unknown\n </template>\n </span>\n </div>\n\n <div v-if=\"session.ip_address\" class=\"detail-row\">\n <span class=\"detail-icon\">\n <Globe :size=\"14\" />\n </span>\n <span class=\"detail-text\">{{ session.ip_address }}</span>\n </div>\n\n <div class=\"detail-row\">\n <span class=\"detail-icon\">\n <Clock :size=\"14\" />\n </span>\n <span class=\"detail-text\">\n Last active {{ formatTimeAgo(session.last_activity_at || session.created_at) }}\n </span>\n </div>\n\n <div class=\"detail-row\">\n <span class=\"detail-icon\">\n <Calendar :size=\"14\" />\n </span>\n <span class=\"detail-text\">\n Started {{ formatDate(session.created_at) }}\n </span>\n </div>\n </div>\n </div>\n </div>\n\n <!-- Bulk Actions -->\n <div v-if=\"sessions.length > 1\" class=\"bulk-actions\">\n <StrandsUiButton\n variant=\"outline\"\n @click=\"handleRevokeAllOther\"\n :disabled=\"revokingAll\"\n >\n <StrandsUiLoader v-if=\"revokingAll\" :size=\"16\" />\n <span v-else>End All Other Sessions</span>\n </StrandsUiButton>\n <p class=\"bulk-actions-hint\">\n This will sign you out on all other devices\n </p>\n </div>\n </div>\n </div>\n </StrandsUiModal>\n</template>\n\n<script setup lang=\"ts\">\nimport { ref, watch } from 'vue'\nimport { StrandsUiModal, StrandsUiButton, StrandsUiLoader } from '../ui'\nimport { useStrandsAuth } from '../composables/useStrandsAuth'\nimport type { SessionInfo, SessionStats } from '../../types'\n\n// Inline SVG icon components using render functions (no runtime compilation needed)\nimport { h } from 'vue'\n\nconst Monitor = {\n props: ['size'],\n render(this: any) {\n return h('svg', { \n width: this.size, \n height: this.size, \n fill: 'none', \n stroke: 'currentColor', \n viewBox: '0 0 24 24' \n }, [\n h('rect', { x: '2', y: '7', width: '20', height: '10', rx: '2', ry: '2' }),\n h('line', { x1: '8', y1: '21', x2: '16', y2: '21' }),\n h('line', { x1: '12', y1: '17', x2: '12', y2: '21' })\n ])\n }\n}\n\nconst Smartphone = {\n props: ['size'],\n render(this: any) {\n return h('svg', { \n width: this.size, \n height: this.size, \n fill: 'none', \n stroke: 'currentColor', \n viewBox: '0 0 24 24' \n }, [\n h('rect', { x: '5', y: '2', width: '14', height: '20', rx: '2', ry: '2' }),\n h('line', { x1: '12', y1: '18', x2: '12.01', y2: '18' })\n ])\n }\n}\n\nconst Tablet = {\n props: ['size'],\n render(this: any) {\n return h('svg', { \n width: this.size, \n height: this.size, \n fill: 'none', \n stroke: 'currentColor', \n viewBox: '0 0 24 24' \n }, [\n h('rect', { x: '4', y: '2', width: '16', height: '20', rx: '2', ry: '2' }),\n h('line', { x1: '12', y1: '18', x2: '12.01', y2: '18' })\n ])\n }\n}\n\nconst MapPin = {\n props: ['size'],\n render(this: any) {\n return h('svg', { \n width: this.size, \n height: this.size, \n fill: 'none', \n stroke: 'currentColor', \n viewBox: '0 0 24 24' \n }, [\n h('path', { d: 'M21 10c0 7-9 13-9 13s-9-6-9-13a9 9 0 0118 0z' }),\n h('circle', { cx: '12', cy: '10', r: '3' })\n ])\n }\n}\n\nconst Globe = {\n props: ['size'],\n render(this: any) {\n return h('svg', { \n width: this.size, \n height: this.size, \n fill: 'none', \n stroke: 'currentColor', \n viewBox: '0 0 24 24' \n }, [\n h('circle', { cx: '12', cy: '12', r: '10' }),\n h('line', { x1: '2', y1: '12', x2: '22', y2: '12' }),\n h('path', { d: 'M12 2a15.3 15.3 0 014 10 15.3 15.3 0 01-4 10 15.3 15.3 0 01-4-10 15.3 15.3 0 014-10z' })\n ])\n }\n}\n\nconst Clock = {\n props: ['size'],\n render(this: any) {\n return h('svg', { \n width: this.size, \n height: this.size, \n fill: 'none', \n stroke: 'currentColor', \n viewBox: '0 0 24 24' \n }, [\n h('circle', { cx: '12', cy: '12', r: '10' }),\n h('polyline', { points: '12 6 12 12 16 14' })\n ])\n }\n}\n\nconst Calendar = {\n props: ['size'],\n render(this: any) {\n return h('svg', { \n width: this.size, \n height: this.size, \n fill: 'none', \n stroke: 'currentColor', \n viewBox: '0 0 24 24' \n }, [\n h('rect', { x: '3', y: '4', width: '18', height: '18', rx: '2', ry: '2' }),\n h('line', { x1: '16', y1: '2', x2: '16', y2: '6' }),\n h('line', { x1: '8', y1: '2', x2: '8', y2: '6' }),\n h('line', { x1: '3', y1: '10', x2: '21', y2: '10' })\n ])\n }\n}\n\ninterface Props {\n modelValue: boolean\n}\n\ninterface Emits {\n (e: 'update:modelValue', value: boolean): void\n (e: 'sessionsUpdated'): void\n (e: 'currentSessionRevoked'): void\n}\n\nconst props = defineProps<Props>()\nconst emit = defineEmits<Emits>()\n\n// Auth composable\nconst { getUserSessions, getSessionStats, revokeSession, revokeAllOtherSessions, signOut } = useStrandsAuth()\n\n// State\nconst visible = ref(props.modelValue)\nconst loading = ref(false)\nconst sessions = ref<SessionInfo[]>([])\nconst stats = ref<SessionStats | null>(null)\nconst revokingSession = ref<string | null>(null)\nconst revokingAll = ref(false)\nconst error = ref<string | null>(null)\n\n// Watch for prop changes\nwatch(() => props.modelValue, (newVal) => {\n visible.value = newVal\n if (newVal) {\n loadSessions()\n }\n})\n\n// Load sessions and stats\nconst loadSessions = async () => {\n loading.value = true\n error.value = null\n \n try {\n const [sessionsData, statsData] = await Promise.all([\n getUserSessions(),\n getSessionStats()\n ])\n \n sessions.value = sessionsData || []\n stats.value = statsData || null\n } catch (err) {\n console.error('Failed to load sessions:', err)\n error.value = 'Failed to load sessions. Please try again.'\n sessions.value = []\n } finally {\n loading.value = false\n }\n}\n\n// Handle closing the modal\nconst handleClose = () => {\n visible.value = false\n emit('update:modelValue', false)\n}\n\n// Revoke a single session\nconst handleRevokeSession = async (sessionId: string) => {\n if (!confirm('Are you sure you want to end this session? The device will be signed out.')) {\n return\n }\n \n revokingSession.value = sessionId\n \n try {\n await revokeSession(sessionId)\n await loadSessions() // Reload the list\n emit('sessionsUpdated')\n } catch (err) {\n console.error('Failed to revoke session:', err)\n alert('Failed to end session. Please try again.')\n } finally {\n revokingSession.value = null\n }\n}\n\n// Revoke all other sessions\nconst handleRevokeAllOther = async () => {\n if (!confirm('Are you sure you want to end all other sessions? You will be signed out on all other devices.')) {\n return\n }\n \n revokingAll.value = true\n \n try {\n await revokeAllOtherSessions()\n await loadSessions() // Reload the list\n emit('sessionsUpdated')\n } catch (err) {\n console.error('Failed to revoke sessions:', err)\n alert('Failed to end sessions. Please try again.')\n } finally {\n revokingAll.value = false\n }\n}\n\n// Revoke current session (signs user out)\nconst handleRevokeCurrentSession = async (sessionId: string) => {\n if (!confirm('Are you sure you want to sign out? You will need to sign in again to access your account.')) {\n return\n }\n \n revokingSession.value = sessionId\n \n try {\n // First revoke the session\n await revokeSession(sessionId)\n \n // Then sign out the user (clears local state and tokens)\n await signOut()\n \n // Close the modal\n visible.value = false\n emit('update:modelValue', false)\n emit('sessionsUpdated')\n \n // Optionally emit a special event for current session revocation\n emit('currentSessionRevoked')\n } catch (err) {\n console.error('Failed to revoke current session:', err)\n alert('Failed to sign out. Please try again.')\n } finally {\n revokingSession.value = null\n }\n}\n\n// Get device icon based on type\nconst getDeviceIcon = (deviceType?: string) => {\n switch(deviceType?.toLowerCase()) {\n case 'mobile':\n return Smartphone\n case 'tablet':\n return Tablet\n default:\n return Monitor\n }\n}\n\n// Format time ago\nconst formatTimeAgo = (date: string | Date) => {\n if (!date) return 'Unknown'\n \n const now = new Date()\n const then = new Date(date)\n const seconds = Math.floor((now.getTime() - then.getTime()) / 1000)\n \n if (seconds < 60) return 'just now'\n if (seconds < 3600) return `${Math.floor(seconds / 60)} minutes ago`\n if (seconds < 86400) return `${Math.floor(seconds / 3600)} hours ago`\n if (seconds < 604800) return `${Math.floor(seconds / 86400)} days ago`\n return then.toLocaleDateString()\n}\n\n// Format date\nconst formatDate = (date: string | Date) => {\n if (!date) return 'Unknown'\n return new Date(date).toLocaleDateString('en-US', {\n month: 'short',\n day: 'numeric',\n year: 'numeric',\n hour: '2-digit',\n minute: '2-digit'\n })\n}\n\n// Load sessions on mount if visible\nif (visible.value) {\n loadSessions()\n}\n</script>\n\n<style scoped>\n/* Modal Header */\n.modal-header-content {\n text-align: center;\n}\n\n.modal-title {\n font-size: 1.25rem;\n font-weight: 600;\n color: #111827;\n margin: 0 0 0.5rem 0;\n}\n\n.modal-subtitle {\n font-size: 0.875rem;\n color: #6b7280;\n margin: 0;\n}\n\n.strands-sessions-modal {\n max-width: 42rem;\n min-width: 32rem;\n}\n\n/* Loading State */\n.sessions-loading {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n padding: 3rem;\n gap: 1rem;\n}\n\n.loading-text {\n color: #6b7280;\n font-size: 0.875rem;\n}\n\n/* Empty State */\n.sessions-empty {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n padding: 3rem;\n text-align: center;\n}\n\n.empty-icon {\n color: #d1d5db;\n margin-bottom: 1rem;\n}\n\n.empty-title {\n font-size: 1.125rem;\n font-weight: 600;\n color: #111827;\n margin-bottom: 0.5rem;\n}\n\n.empty-description {\n color: #6b7280;\n font-size: 0.875rem;\n}\n\n/* Session Statistics */\n.session-stats {\n display: grid;\n grid-template-columns: repeat(auto-fit, minmax(120px, 1fr));\n gap: 1rem;\n margin-bottom: 1.5rem;\n padding: 1rem;\n background-color: #f9fafb;\n border-radius: 0.5rem;\n}\n\n.stat-card {\n display: flex;\n flex-direction: column;\n gap: 0.25rem;\n}\n\n.stat-label {\n font-size: 0.75rem;\n color: #6b7280;\n text-transform: uppercase;\n letter-spacing: 0.05em;\n}\n\n.stat-value {\n font-size: 1.5rem;\n font-weight: 600;\n color: #111827;\n}\n\n/* Sessions List */\n.sessions-list {\n display: flex;\n flex-direction: column;\n gap: 1rem;\n}\n\n.session-card {\n padding: 1rem;\n border: 1px solid #e5e7eb;\n border-radius: 0.5rem;\n background: white;\n transition: all 0.15s ease;\n}\n\n.session-card:hover {\n border-color: #d1d5db;\n box-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.1);\n}\n\n.session-card.current-session {\n border-color: #a7f3d0;\n background-color: #f0fdf9;\n}\n\n/* Session Header */\n.session-header {\n display: flex;\n justify-content: space-between;\n align-items: flex-start;\n margin-bottom: 0.75rem;\n}\n\n.session-device {\n display: flex;\n gap: 0.75rem;\n align-items: flex-start;\n flex: 1;\n}\n\n.device-icon {\n padding: 0.5rem;\n background-color: #f3f4f6;\n border-radius: 0.375rem;\n color: #6b7280;\n}\n\n.current-session .device-icon {\n background-color: #dcfce7;\n color: #16a34a;\n}\n\n.device-info {\n flex: 1;\n}\n\n.device-name {\n font-size: 0.875rem;\n font-weight: 600;\n color: #111827;\n display: flex;\n align-items: center;\n gap: 0.5rem;\n}\n\n.current-badge {\n display: inline-flex;\n align-items: center;\n padding: 0.125rem 0.5rem;\n background-color: #dcfce7;\n color: #15803d;\n font-size: 0.75rem;\n font-weight: 500;\n border-radius: 9999px;\n border: 1px solid #bbf7d0;\n}\n\n.device-type {\n font-size: 0.75rem;\n color: #6b7280;\n margin-top: 0.125rem;\n text-transform: capitalize;\n}\n\n/* Session Details */\n.session-details {\n display: flex;\n flex-direction: column;\n gap: 0.5rem;\n padding-left: 3rem;\n}\n\n.detail-row {\n display: flex;\n align-items: center;\n gap: 0.5rem;\n font-size: 0.8125rem;\n color: #6b7280;\n}\n\n.detail-icon {\n display: flex;\n align-items: center;\n color: #9ca3af;\n}\n\n.detail-text {\n flex: 1;\n}\n\n/* Bulk Actions */\n.bulk-actions {\n margin-top: 1.5rem;\n padding-top: 1.5rem;\n border-top: 1px solid #e5e7eb;\n display: flex;\n flex-direction: column;\n align-items: center;\n gap: 0.5rem;\n}\n\n.bulk-actions-hint {\n font-size: 0.75rem;\n color: #6b7280;\n text-align: center;\n}\n\n/* Responsive */\n@media (max-width: 640px) {\n .strands-sessions-modal {\n min-width: unset;\n width: 100%;\n }\n \n .session-stats {\n grid-template-columns: 1fr 1fr;\n }\n \n .session-details {\n padding-left: 0;\n margin-top: 0.75rem;\n padding-top: 0.75rem;\n border-top: 1px solid #f3f4f6;\n }\n}\n\n/* Current Session Button Styling */\n.current-session-button {\n border-color: #dc2626 !important;\n color: #dc2626 !important;\n}\n\n.current-session-button:hover {\n background-color: #dc2626 !important;\n color: white !important;\n}\n</style>","<template>\n <div class=\"accui-component-scope\">\n <div :class=\"inModal ? 'profile-container-modal profile-container-width' : 'profile-container profile-container-width profile-max-width profile-centered profile-animated'\">\n <div :class=\"inModal ? 'profile-content-modal profile-content-layout' : 'profile-content profile-card-modern profile-content-layout'\">\n <!-- Header -->\n <div class=\"profile-header\">\n <h1 class=\"profile-title\">Profile Settings</h1>\n <p class=\"profile-subtitle\">Manage your account information and preferences</p>\n </div>\n\n <!-- Profile Image Section -->\n <div class=\"profile-image-section\">\n <div class=\"profile-image-container\">\n <!-- Progress Ring Container -->\n <div class=\"profile-image-wrapper\">\n <!-- Progress Ring SVG -->\n <StrandsUiLevelProgress\n :size=\"140\" \n :value=\"currentUser?.xp || 0\" \n :max=\"currentUser?.next_level_xp || 1\" \n :level=\"currentUser?.level || 0\" \n :level-label=\"`LEVEL ${currentUser?.level || 0}`\"\n :user-settings=\"currentUser?.settings\"\n class=\"profile-progress-ring\" \n />\n\n <!-- Avatar -->\n <div \n v-if=\"currentUser?.avatar\"\n class=\"profile-avatar profile-avatar-with-image\"\n >\n <img \n :src=\"currentUser.avatar\" \n :alt=\"`${currentUser.firstName} ${currentUser.lastName}`\"\n class=\"profile-avatar-image\"\n />\n </div>\n <div \n v-else\n class=\"profile-avatar profile-avatar-initials\"\n >\n {{ getInitials(currentUser?.firstName, currentUser?.lastName) }}\n </div>\n \n <!-- Upload Overlay -->\n <button\n class=\"profile-upload-overlay\"\n @click=\"triggerAvatarUpload\"\n :disabled=\"uploading\"\n >\n <StrandsUiLoader v-if=\"uploading\" :size=\"24\" variant=\"dark\" />\n <svg v-else class=\"profile-upload-icon\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M3 9a2 2 0 012-2h.93a2 2 0 001.664-.89l.812-1.22A2 2 0 0110.07 4h3.86a2 2 0 011.664.89l.812 1.22A2 2 0 0018.07 7H19a2 2 0 012 2v9a2 2 0 01-2 2H5a2 2 0 01-2-2V9z\" />\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M15 13a3 3 0 11-6 0 3 3 0 616 0z\" />\n </svg>\n </button>\n </div>\n </div>\n \n <!-- Hidden file input for avatar selection -->\n <input\n ref=\"avatarFileInput\"\n type=\"file\"\n accept=\"image/*\"\n class=\"profile-file-input\"\n @change=\"handleAvatarFileSelect\"\n />\n </div>\n\n <!-- Profile Form -->\n <form @submit.prevent=\"handleUpdateProfile\" class=\"profile-form\">\n <div class=\"profile-form-grid\">\n <!-- Personal Information -->\n <div class=\"profile-section\">\n <h3 class=\"profile-section-title\">Personal Information</h3>\n \n <StrandsUiInput\n id=\"firstName\"\n v-model=\"form.firstName\"\n type=\"text\"\n label=\"First name\"\n placeholder=\"Enter your first name\"\n autocomplete=\"given-name\"\n :disabled=\"loading || fetchingProfile\"\n :error=\"errors.firstName\"\n />\n\n <StrandsUiInput\n id=\"lastName\"\n v-model=\"form.lastName\"\n type=\"text\"\n label=\"Last name\"\n placeholder=\"Enter your last name\"\n autocomplete=\"family-name\"\n :disabled=\"loading || fetchingProfile\"\n :error=\"errors.lastName\"\n />\n\n <!-- Email Change Section -->\n <div class=\"profile-setting-card\">\n <div class=\"profile-setting-header\">\n <div>\n <h4 class=\"profile-setting-title\">Email Address</h4>\n <p class=\"profile-setting-subtitle\">{{ currentUser?.email }}</p>\n </div>\n <StrandsUiButton\n variant=\"secondary\"\n size=\"sm\"\n @click=\"showEmailChange = !showEmailChange\"\n >\n {{ showEmailChange ? 'Cancel' : 'Change' }}\n </StrandsUiButton>\n </div>\n\n <Transition name=\"expand\">\n <div v-if=\"showEmailChange\" class=\"profile-change-form\">\n <StrandsUiInput\n v-model=\"emailChangeForm.newEmail\"\n type=\"email\"\n placeholder=\"New email address\"\n autocomplete=\"email\"\n :error=\"emailChangeForm.errors.newEmail\"\n />\n <StrandsUiInput\n v-model=\"emailChangeForm.password\"\n type=\"password\"\n placeholder=\"Current password\"\n autocomplete=\"current-password\"\n :error=\"emailChangeForm.errors.password\"\n />\n <StrandsUiButton\n variant=\"primary\"\n size=\"sm\"\n @click=\"handleEmailChange\"\n :disabled=\"!isEmailChangeFormValid || emailChangeLoading\"\n >\n {{ emailChangeLoading ? 'Updating...' : 'Update Email' }}\n </StrandsUiButton>\n </div>\n </Transition>\n </div>\n\n <!-- Username Change Section -->\n <div class=\"profile-field-section\">\n <div class=\"profile-field-header\">\n <div>\n <h4 class=\"profile-field-title\">Username</h4>\n <p class=\"profile-field-subtitle\">\n {{ currentUser?.username || 'No username set' }}\n </p>\n </div>\n <StrandsUiButton\n variant=\"secondary\"\n size=\"sm\"\n :disabled=\"!usernameChangeData.canChange || usernameChangeLoading\"\n @click=\"handleToggleUsernameChange\"\n >\n {{\n usernameChangeData.cooldownEnd\n ? `Wait ${usernameChangeData.daysRemaining} day${usernameChangeData.daysRemaining === 1 ? '' : 's'} to change`\n : showUsernameChange\n ? 'Cancel'\n : (currentUser?.username\n ? 'Change'\n : 'Set Username')\n }}\n </StrandsUiButton>\n </div>\n\n <Transition name=\"expand\">\n <div v-if=\"showUsernameChange\" class=\"profile-change-form\">\n <StrandsUiInput\n v-model=\"usernameForm.username\"\n type=\"text\"\n placeholder=\"Enter username (3-30 characters)\"\n autocomplete=\"username\"\n :error=\"usernameForm.errors.username\"\n />\n <div v-if=\"usernameAvailability.message\" class=\"profile-availability-message\" :class=\"usernameAvailability.available ? 'success' : 'error'\">\n {{ usernameAvailability.message }}\n </div>\n <StrandsUiButton\n variant=\"primary\"\n size=\"sm\"\n @click=\"handleUsernameChange\"\n :disabled=\"!isUsernameChangeFormValid || usernameChangeLoading\"\n >\n {{ usernameChangeLoading ? 'Updating...' : 'Update Username' }}\n </StrandsUiButton>\n </div>\n </Transition>\n </div>\n </div>\n\n <!-- Security Settings -->\n <div class=\"profile-password-section\">\n <h3 class=\"profile-section-title\">Security Settings</h3>\n \n <!-- Password Change -->\n <div class=\"profile-field-section\">\n <div class=\"profile-field-header\">\n <div>\n <h4 class=\"profile-field-title\">Password</h4>\n <p class=\"profile-field-subtitle\">Last updated {{ passwordLastUpdated }}</p>\n </div>\n <StrandsUiButton\n variant=\"secondary\"\n size=\"sm\"\n @click=\"showPasswordChange = !showPasswordChange\"\n >\n {{ showPasswordChange ? 'Cancel' : 'Change' }}\n </StrandsUiButton>\n </div>\n\n <Transition name=\"expand\">\n <div v-if=\"showPasswordChange\" class=\"profile-change-form\">\n <StrandsUiInput\n v-model=\"passwordForm.current\"\n type=\"password\"\n placeholder=\"Current password\"\n autocomplete=\"current-password\"\n />\n <StrandsUiInput\n v-model=\"passwordForm.new\"\n type=\"password\"\n placeholder=\"New password\"\n autocomplete=\"new-password\"\n />\n <StrandsUiInput\n v-model=\"passwordForm.confirm\"\n type=\"password\"\n placeholder=\"Confirm new password\"\n autocomplete=\"new-password\"\n />\n <StrandsUiButton\n variant=\"primary\"\n size=\"sm\"\n @click=\"handlePasswordChange\"\n :disabled=\"!isPasswordFormValid\"\n >\n Update Password\n </StrandsUiButton>\n </div>\n </Transition>\n </div>\n\n <!-- Two-Factor Authentication -->\n <div class=\"profile-field-section\">\n <div class=\"profile-field-header profile-field-header-vertical\">\n <div class=\"profile-mfa-content\">\n <div>\n <h4 class=\"profile-field-title\">Two-Factor Authentication</h4>\n <p class=\"profile-field-subtitle\">\n {{ currentUser?.mfaEnabled ? 'Enabled' : 'Add extra security to your account' }}\n </p>\n </div>\n \n <!-- Device Type Chips -->\n <div v-if=\"mfaDeviceChips.length > 0\" class=\"profile-mfa-chips\">\n <div\n v-for=\"chip in mfaDeviceChips\"\n :key=\"chip.type\"\n :class=\"[\n 'mfa-device-chip',\n chip.color\n ]\"\n >\n <component :is=\"chip.icon\" :size=\"12\" />\n <span>{{ chip.count }}</span>\n <span>{{ chip.label }}</span>\n </div>\n </div>\n </div>\n <StrandsUiButton\n :variant=\"currentUser?.mfaEnabled ? 'secondary' : 'primary'\"\n size=\"sm\"\n @click=\"showMfaModal = true\"\n class=\"profile-toggle-container\"\n >\n {{ currentUser?.mfaEnabled ? 'Manage' : 'Setup' }}\n </StrandsUiButton>\n </div>\n </div>\n\n <!-- Active Sessions -->\n <div class=\"profile-field-section\">\n <div class=\"profile-field-header\">\n <div>\n <h4 class=\"profile-field-title\">Active Sessions</h4>\n <p class=\"profile-field-subtitle\">\n <span v-if=\"loadingSessions\">Loading sessions...</span>\n <span v-else>{{ activeSessions.length }} active device{{ activeSessions.length !== 1 ? 's' : '' }}</span>\n </p>\n </div>\n <div class=\"profile-field-actions\">\n <StrandsUiButton\n variant=\"secondary\"\n size=\"sm\"\n @click=\"showSessionsModal = true\"\n :disabled=\"loadingSessions\"\n >\n Manage\n </StrandsUiButton>\n </div>\n </div>\n </div>\n </div>\n </div>\n\n <!-- Action Buttons - Only show when changes are made -->\n <div v-if=\"hasChanges\" class=\"profile-actions-section\">\n <StrandsUiButton\n type=\"submit\"\n variant=\"primary\"\n :disabled=\"loading\"\n :loading=\"loading\"\n >\n {{ loading ? 'Saving changes...' : 'Save changes' }}\n </StrandsUiButton>\n\n <StrandsUiButton\n variant=\"secondary\"\n @click=\"handleCancel\"\n :disabled=\"loading\"\n >\n Cancel\n </StrandsUiButton>\n </div>\n </form>\n\n <!-- Success/Error Messages -->\n <div v-if=\"successMessage\" class=\"animate-fade-in\">\n <div class=\"alert-success\">\n <div class=\"profile-help-item\">\n <svg class=\"profile-help-icon\" fill=\"currentColor\" viewBox=\"0 0 20 20\">\n <path fill-rule=\"evenodd\" d=\"M10 18a8 8 0 100-16 8 8 0 000 16zm3.857-9.809a.75.75 0 00-1.214-.882l-3.236 4.53L7.53 10.173a.75.75 0 00-1.06 1.061l2.5 2.5a.75.75 0 001.137-.089l4-5.5z\" clip-rule=\"evenodd\" />\n </svg>\n <p class=\"profile-alert-message\">{{ successMessage }}</p>\n </div>\n </div>\n </div>\n\n <div v-if=\"errorMessage\" class=\"animate-fade-in\">\n <div class=\"alert-error\">\n <div class=\"profile-help-item\">\n <svg class=\"profile-help-icon\" fill=\"currentColor\" viewBox=\"0 0 20 20\">\n <path fill-rule=\"evenodd\" d=\"M10 18a8 8 0 100-16 8 8 0 000 16zM8.28 7.22a.75.75 0 00-1.06 1.06L8.94 10l-1.72 1.72a.75.75 0 101.06 1.06L10 11.06l1.72 1.72a.75.75 0 101.06-1.06L11.06 10l1.72-1.72a.75.75 0 00-1.06-1.06L10 8.94 8.28 7.22z\" clip-rule=\"evenodd\" />\n </svg>\n <p class=\"profile-alert-message\">{{ errorMessage }}</p>\n </div>\n </div>\n </div>\n\n \n <!-- Secured by footer -->\n <StrandsSecuredFooter :config=\"props.config\">\n <div class=\"profile-footer-actions\">\n <!-- Sign Out button -->\n <StrandsUiButton\n color=\"red\"\n @click=\"handleSignOut\"\n :disabled=\"signingOut\"\nclass=\"profile-sign-out-button\"\n >\n {{ signingOut ? 'Signing out...' : 'Sign Out' }}\n </StrandsUiButton>\n\n <!-- Settings button -->\n <StrandsUiButton\n variant=\"secondary\"\n @click=\"showSettingsModal = true\"\nclass=\"profile-sign-out-button\"\n >\n <svg class=\"profile-action-icon\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M10.325 4.317c.426-1.756 2.924-1.756 3.35 0a1.724 1.724 0 002.573 1.066c1.543-.94 3.31.826 2.37 2.37a1.724 1.724 0 001.065 2.572c1.756.426 1.756 2.924 0 3.35a1.724 1.724 0 00-1.066 2.573c.94 1.543-.826 3.31-2.37 2.37a1.724 1.724 0 00-2.572 1.065c-.426 1.756-2.924 1.756-3.35 0a1.724 1.724 0 00-2.573-1.066c-1.543.94-3.31-.826-2.37-2.37a1.724 1.724 0 00-1.065-2.572c-1.756-.426-1.756-2.924 0-3.35a1.724 1.724 0 001.066-2.573c-.94-1.543.826-3.31 2.37-2.37.996.608 2.296.07 2.572-1.065z\" />\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M15 12a3 3 0 11-6 0 3 3 0 016 0z\" />\n </svg>\n </StrandsUiButton>\n </div>\n\n <!-- Need help -->\n <div v-if=\"getSupportEmail()\">\n <p class=\"profile-footer-text\">\n Need help?\n <StrandsUiLink variant=\"primary\" :href=\"`mailto:${getSupportEmail()}`\">\n Contact Support\n </StrandsUiLink>\n </p>\n </div>\n </StrandsSecuredFooter>\n </div>\n\n <!-- MFA Management Modal -->\n <StrandsMfaModal\n :show=\"showMfaModal\"\n @close=\"showMfaModal = false\"\n @mfa-updated=\"handleMfaUpdated\"\n />\n\n <!-- Settings Modal -->\n <StrandsSettingsModal\n v-if=\"showSettingsModal\"\n @close=\"showSettingsModal = false\"\n @settings-updated=\"handleSettingsUpdated\"\n />\n\n <!-- Sessions Management Modal -->\n <StrandsSessionsModal \n v-model=\"showSessionsModal\" \n @sessions-updated=\"handleSessionsUpdated\"\n />\n\n <!-- Avatar Editor Modal -->\n <div v-if=\"showAvatarEditor\" class=\"profile-avatar-modal-overlay\">\n <div class=\"profile-avatar-modal\">\n <div class=\"profile-avatar-modal-content\">\n <div class=\"profile-avatar-modal-header\">\n <h2 class=\"profile-modal-title\">Edit Avatar</h2>\n <button\n @click=\"handleAvatarEditorClose\"\n class=\"profile-avatar-modal-close\"\n >\n <svg class=\"profile-avatar-modal-close-icon\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M6 18L18 6M6 6l12 12\" />\n </svg>\n </button>\n </div>\n \n <StrandsUiAvatarEditor\n :uploading=\"uploading\"\n :preselected-file=\"selectedImageFile\"\n @upload=\"handleAvatarUpload\"\n @error=\"handleAvatarError\"\n />\n </div>\n </div>\n </div>\n </div>\n </div>\n</template>\n\n<script setup lang=\"ts\">\nimport { ref, reactive, computed, onMounted, watch, h } from 'vue'\nimport { StrandsUiButton, StrandsUiInput, StrandsUiLink, StrandsUiLoader, StrandsUiLevelProgress, StrandsUiModal, StrandsUiAvatarEditor } from '../ui'\nimport StrandsSecuredFooter from './StrandsSecuredFooter.vue'\nimport StrandsMfaModal from './StrandsMfaModal.vue'\nimport StrandsSettingsModal from './StrandsSettingsModal.vue'\nimport StrandsSessionsModal from './StrandsSessionsModal.vue'\nimport { useStrandsConfig, type StrandsAuthConfig } from '../composables/useStrandsConfig'\nimport { useStrandsAuth } from '../composables/useStrandsAuth'\nimport { useStrandsMfa } from '../composables/useStrandsMfa'\n\n// Inline SVG icon components using render functions (no runtime compilation needed)\nconst Smartphone = {\n props: ['size'],\n render(this: any) {\n return h('svg', { \n width: this.size, \n height: this.size, \n fill: 'none', \n stroke: 'currentColor', \n viewBox: '0 0 24 24' \n }, [\n h('rect', { x: '5', y: '2', width: '14', height: '20', rx: '2', ry: '2' }),\n h('line', { x1: '12', y1: '18', x2: '12.01', y2: '18' })\n ])\n }\n}\n\nconst Mail = {\n props: ['size'],\n render(this: any) {\n return h('svg', { \n width: this.size, \n height: this.size, \n fill: 'none', \n stroke: 'currentColor', \n viewBox: '0 0 24 24' \n }, [\n h('path', { d: 'm4 4 16 0c1.1 0 2 .9 2 2l0 12c0 1.1-.9 2-2 2l-16 0c-1.1 0-2-.9-2-2l0-12c0-1.1.9-2 2-2z' }),\n h('polyline', { points: '22,6 12,13 2,6' })\n ])\n }\n}\n\nconst KeyRound = {\n props: ['size'],\n render(this: any) {\n return h('svg', { \n width: this.size, \n height: this.size, \n fill: 'none', \n stroke: 'currentColor', \n viewBox: '0 0 24 24' \n }, [\n h('path', { d: 'M2.586 17.414A2 2 0 0 0 2 18.828V21a1 1 0 0 0 1 1h3a1 1 0 0 0 1-1v-1a1 1 0 0 1 1-1h1a1 1 0 0 0 1-1v-1a1 1 0 0 1 1-1h.172a2 2 0 0 0 1.414-.586l.814-.814a6.5 6.5 0 1 0-4-4z' }),\n h('circle', { cx: '16.5', cy: '7.5', r: '.5', fill: 'currentColor' })\n ])\n }\n}\nimport type { User, SessionInfo } from '../../types'\n\ninterface Props {\n user?: User\n config?: StrandsAuthConfig\n autoFetch?: boolean // Whether to automatically fetch user profile on mount\n inModal?: boolean // Whether the component is being displayed inside a modal\n}\n\ninterface Emits {\n (e: 'profile-updated', user: User): void\n (e: 'error', error: string): void\n (e: 'manage-sessions'): void\n (e: 'mfa-toggle', enabled: boolean): void\n}\n\nconst props = withDefaults(defineProps<Props>(), {\n autoFetch: true,\n inModal: false\n})\nconst emit = defineEmits<Emits>()\n\n// Get configuration and authentication \nconst { getSupportEmail, getUrl } = useStrandsConfig(props.config)\nconst { fetchProfile, updateProfile, changeEmail, changeUsername, getUsernameCooldown, checkUsernameAvailability, getUserSessions, currentUser: authUser, currentSession, isAuthenticated, refreshToken, signOut } = useStrandsAuth()\nconst { activeMfaDevices, fetchMfaDevices } = useStrandsMfa()\n\n// Internal user state\nconst internalUser = ref<User | null>(null)\nconst fetchingProfile = ref(false)\n\n// Use authenticated user from composable, fallback to prop, then internal state\nconst currentUser = computed(() => {\n const user = authUser.value || props.user || internalUser.value\n console.log('Current user computed:', {\n hasAuthUser: !!authUser.value,\n hasPropUser: !!props.user,\n hasInternalUser: !!internalUser.value,\n selectedUser: user,\n avatar: user?.avatar\n })\n return user\n})\n\nconst loading = ref(false)\nconst uploading = ref(false)\nconst signingOut = ref(false)\nconst showPasswordChange = ref(false)\nconst showEmailChange = ref(false)\nconst emailChangeLoading = ref(false)\nconst showUsernameChange = ref(false)\nconst usernameChangeLoading = ref(false)\nconst showMfaModal = ref(false)\nconst showSettingsModal = ref(false)\nconst showAvatarEditor = ref(false)\nconst selectedImageFile = ref<File | null>(null)\nconst successMessage = ref('')\nconst errorMessage = ref('')\nconst activeSessions = ref<SessionInfo[]>([])\nconst loadingSessions = ref(false)\nconst showSessionsModal = ref(false)\n\n// Username change state\nconst usernameChangeData = reactive({\n canChange: true,\n cooldownEnd: null as Date | null,\n daysRemaining: 0\n})\n\nconst usernameAvailability = reactive({\n available: false,\n message: '',\n checking: false\n})\n\n// Temporary total XP state for testing (accumulates infinitely)\n\n// Refs\nconst avatarFileInput = ref<HTMLInputElement>()\n\nconst form = reactive({\n firstName: '',\n lastName: '',\n email: ''\n})\n\nconst emailChangeForm = reactive({\n newEmail: '',\n password: '',\n errors: {\n newEmail: '',\n password: ''\n }\n})\n\nconst passwordForm = reactive({\n current: '',\n new: '',\n confirm: ''\n})\n\nconst usernameForm = reactive({\n username: '',\n errors: {\n username: ''\n }\n})\n\nconst errors = reactive({\n firstName: '',\n lastName: '',\n email: ''\n})\n\nconst hasChanges = computed(() => {\n const user = currentUser.value\n if (!user) return false\n return (\n form.firstName !== (user.firstName || '') ||\n form.lastName !== (user.lastName || '')\n )\n})\n\nconst isPasswordFormValid = computed(() => {\n return (\n passwordForm.current &&\n passwordForm.new &&\n passwordForm.confirm &&\n passwordForm.new === passwordForm.confirm &&\n passwordForm.new.length >= 8\n )\n})\n\nconst isEmailChangeFormValid = computed(() => {\n return (\n emailChangeForm.newEmail &&\n emailChangeForm.password &&\n emailChangeForm.newEmail !== currentUser.value?.email &&\n emailChangeForm.newEmail.includes('@')\n )\n})\n\nconst isUsernameChangeFormValid = computed(() => {\n const usernameRegex = /^[a-zA-Z0-9_-]{3,30}$/\n return (\n usernameForm.username &&\n usernameRegex.test(usernameForm.username) &&\n usernameForm.username !== currentUser.value?.username &&\n !usernameAvailability.checking\n )\n})\n\nconst passwordLastUpdated = computed(() => {\n const user = currentUser.value\n if (!user) return 'Never'\n \n // Use passwordUpdatedAt if available, otherwise fall back to createdAt\n const updateDate = user.passwordUpdatedAt || user.createdAt\n if (!updateDate) return 'Never'\n \n const date = new Date(updateDate)\n const now = new Date()\n const diffMs = now.getTime() - date.getTime()\n const diffDays = Math.floor(diffMs / (1000 * 60 * 60 * 24))\n \n if (diffDays === 0) return 'Today'\n if (diffDays === 1) return 'Yesterday'\n if (diffDays < 30) return `${diffDays} days ago`\n if (diffDays < 365) {\n const months = Math.floor(diffDays / 30)\n return months === 1 ? '1 month ago' : `${months} months ago`\n }\n const years = Math.floor(diffDays / 365)\n return years === 1 ? '1 year ago' : `${years} years ago`\n})\n\nconst deviceTypeCounts = computed(() => {\n const devices = activeMfaDevices.value || []\n const counts = {\n totp: 0,\n email: 0,\n hardware: 0,\n passkey: 0\n }\n \n devices.forEach(device => {\n if (device.device_type in counts) {\n counts[device.device_type as keyof typeof counts]++\n }\n })\n \n return counts\n})\n\nconst mfaDeviceChips = computed(() => {\n const chips = []\n const counts = deviceTypeCounts.value\n \n if (counts.totp > 0) {\n chips.push({\n type: 'totp',\n count: counts.totp,\n label: counts.totp === 1 ? 'Auth app' : 'Auth apps',\n icon: Smartphone,\n color: 'chip-blue'\n })\n }\n \n if (counts.email > 0) {\n chips.push({\n type: 'email',\n count: counts.email,\n label: 'Email',\n icon: Mail,\n color: 'chip-green'\n })\n }\n \n if (counts.hardware > 0 || counts.passkey > 0) {\n const totalHardware = counts.hardware + counts.passkey\n chips.push({\n type: 'hardware',\n count: totalHardware,\n label: totalHardware === 1 ? 'Key' : 'Keys',\n icon: KeyRound,\n color: 'chip-purple'\n })\n }\n \n return chips\n})\n\n// Calculate XP required for a specific level using the provided formula\nconst getXpForLevel = (level: number): number => {\n if (level <= 1) return 0\n \n let totalXp = 0\n for (let i = 1; i < level; i++) {\n // Formula: xp = 4 * i + Math.pow(1.5, i / 4) + xp\n // This accumulates XP required for each level\n totalXp += 4 * i + Math.pow(1.5, i / 4)\n }\n return Math.floor(totalXp)\n}\n\n// Calculate level from total XP\nconst getLevelFromXp = (totalXp: number): number => {\n let level = 1\n let cumulativeXp = 0\n \n // Keep incrementing level while totalXp is greater than required\n while (true) {\n const xpForNextLevel = getXpForLevel(level + 1)\n if (totalXp < xpForNextLevel) {\n break\n }\n level++\n // Safety check to prevent infinite loops\n if (level > 1000) break\n }\n \n return level\n}\n\n// Leveling system computed properties\nconst userLevel = computed(() => {\n return getLevelFromXp(currentUser.value?.xp || 0)\n})\n\nconst currentExp = computed(() => {\n const level = userLevel.value\n const xpForCurrentLevel = getXpForLevel(level)\n // Current XP within the level (progress toward next level)\n return (currentUser.value?.xp || 0) - xpForCurrentLevel\n})\n\nconst expToNextLevel = computed(() => {\n const level = userLevel.value\n const xpForCurrentLevel = getXpForLevel(level)\n const xpForNextLevel = getXpForLevel(level + 1)\n // XP needed to complete this level\n return xpForNextLevel - xpForCurrentLevel\n})\n\nconst progressPercentage = computed(() => {\n return Math.round((currentExp.value / expToNextLevel.value) * 100)\n})\n\nconst totalCircumference = computed(() => {\n const radius = 54\n return 2 * Math.PI * radius\n})\n\nconst progressLength = computed(() => {\n const progress = progressPercentage.value / 100\n return progress * totalCircumference.value\n})\n\nconst progressGapLength = computed(() => {\n // Create visible gap between progress and remaining background\n const smallGap = (totalCircumference.value * 5) / 360 // 5 degree gap\n const remaining = totalCircumference.value - progressLength.value - smallGap\n return remaining\n})\n\nconst getInitials = (firstName?: string, lastName?: string) => {\n if (!firstName && !lastName) return 'U'\n return `${firstName?.[0] || ''}${lastName?.[0] || ''}`.toUpperCase()\n}\n\n// Format time ago utility function\nconst formatTimeAgo = (dateString?: string | Date) => {\n if (!dateString) return 'Unknown'\n \n const date = new Date(dateString)\n const now = new Date()\n const diffMs = now.getTime() - date.getTime()\n const diffMinutes = Math.floor(diffMs / (1000 * 60))\n const diffHours = Math.floor(diffMs / (1000 * 60 * 60))\n const diffDays = Math.floor(diffMs / (1000 * 60 * 60 * 24))\n \n if (diffMinutes < 1) return 'Just now'\n if (diffMinutes < 60) return `${diffMinutes}m ago`\n if (diffHours < 24) return `${diffHours}h ago`\n if (diffDays < 7) return `${diffDays}d ago`\n if (diffDays < 30) return `${Math.floor(diffDays / 7)}w ago`\n if (diffDays < 365) return `${Math.floor(diffDays / 30)}mo ago`\n return `${Math.floor(diffDays / 365)}y ago`\n}\n\n// Fetch user profile from API\nconst fetchUserProfile = async () => {\n if (!props.autoFetch || props.user || !isAuthenticated.value) return // Skip if disabled, user prop provided, or not authenticated\n \n fetchingProfile.value = true\n try {\n await fetchProfile()\n // Also fetch MFA devices when profile is loaded\n if (isAuthenticated.value) {\n await fetchMfaDevices()\n }\n // The fetchProfile from composable will update authUser, so currentUser computed will reflect the change\n } catch (err) {\n const errorMsg = err instanceof Error ? err.message : 'Failed to load profile'\n errorMessage.value = errorMsg\n emit('error', errorMsg)\n } finally {\n fetchingProfile.value = false\n }\n}\n\n// Load user sessions\nconst loadUserSessions = async () => {\n console.log('loadUserSessions called, isAuthenticated:', isAuthenticated.value)\n if (!isAuthenticated.value) {\n console.log('Not authenticated, skipping session load')\n return\n }\n \n loadingSessions.value = true\n try {\n console.log('Calling getUserSessions...')\n const sessions = await getUserSessions()\n console.log('Sessions loaded:', sessions)\n activeSessions.value = sessions || []\n } catch (err) {\n console.error('Failed to load sessions:', err)\n // Don't show error to user for sessions as it's not critical\n } finally {\n loadingSessions.value = false\n }\n}\n\n// Initialize form with user data\nwatch(() => currentUser.value, (user) => {\n if (user) {\n form.firstName = user.firstName || ''\n form.lastName = user.lastName || ''\n form.email = user.email // Keep for display but not for editing\n }\n}, { immediate: true })\n\n// Watch for authentication state changes and load sessions\nwatch(() => isAuthenticated.value, (authenticated, wasAuthenticated) => {\n console.log('Authentication state changed from', wasAuthenticated, 'to', authenticated)\n if (authenticated && !wasAuthenticated) {\n // User just signed in, load sessions after a small delay to ensure tokens are set\n console.log('User just signed in, loading sessions...')\n setTimeout(() => {\n loadUserSessions()\n }, 500)\n } else if (!authenticated) {\n console.log('User signed out, clearing sessions')\n activeSessions.value = []\n }\n}, { immediate: false })\n\n// Also watch for session changes (when tokens are refreshed)\nwatch(() => currentSession.value, (session) => {\n console.log('Session changed:', session)\n if (session && isAuthenticated.value) {\n setTimeout(() => {\n loadUserSessions()\n }, 100)\n }\n})\n\n// Fetch profile and sessions on mount if needed\nonMounted(() => {\n console.log('StrandsUserProfile mounted')\n fetchUserProfile()\n loadUserSessions()\n})\n\nconst clearMessages = () => {\n successMessage.value = ''\n errorMessage.value = ''\n Object.keys(errors).forEach(key => {\n errors[key as keyof typeof errors] = ''\n })\n}\n\nconst handleUpdateProfile = async () => {\n clearMessages()\n loading.value = true\n\n try {\n const updatedUser = await updateProfile({\n firstName: form.firstName,\n lastName: form.lastName,\n })\n \n if (updatedUser) {\n successMessage.value = 'Profile updated successfully'\n emit('profile-updated', updatedUser)\n }\n } catch (err) {\n const error = err instanceof Error ? err.message : 'Failed to update profile'\n errorMessage.value = error\n emit('error', error)\n } finally {\n loading.value = false\n }\n}\n\nconst handlePasswordChange = async () => {\n if (!isPasswordFormValid.value) return\n\n clearMessages()\n loading.value = true\n\n try {\n // Integration point: Replace with actual password change call\n // Example: await authSDK.changePassword(passwordForm.current, passwordForm.new)\n \n // Simulate API call for demo\n await new Promise(resolve => setTimeout(resolve, 1000))\n \n successMessage.value = 'Password updated successfully'\n showPasswordChange.value = false\n passwordForm.current = ''\n passwordForm.new = ''\n passwordForm.confirm = ''\n } catch (err) {\n errorMessage.value = 'Failed to update password'\n } finally {\n loading.value = false\n }\n}\n\nconst handleEmailChange = async () => {\n if (!isEmailChangeFormValid.value) return\n\n // Clear previous errors\n emailChangeForm.errors.newEmail = ''\n emailChangeForm.errors.password = ''\n clearMessages()\n emailChangeLoading.value = true\n\n try {\n const result = await changeEmail(emailChangeForm.newEmail, emailChangeForm.password)\n \n successMessage.value = result.message || 'Email updated successfully. Please verify your new email address.'\n showEmailChange.value = false\n emailChangeForm.newEmail = ''\n emailChangeForm.password = ''\n \n // Emit profile updated event\n if (currentUser.value) {\n emit('profile-updated', currentUser.value)\n }\n } catch (err) {\n const error = err instanceof Error ? err.message : 'Failed to update email'\n \n // Try to parse specific field errors\n if (error.includes('password')) {\n emailChangeForm.errors.password = 'Invalid password'\n } else if (error.includes('email')) {\n emailChangeForm.errors.newEmail = error\n } else {\n errorMessage.value = error\n }\n \n emit('error', error)\n } finally {\n emailChangeLoading.value = false\n }\n}\n\nconst handleToggleUsernameChange = async () => {\n if (!showUsernameChange.value) {\n // When opening, check cooldown status\n usernameChangeLoading.value = true\n try {\n const cooldownData = await getUsernameCooldown()\n usernameChangeData.canChange = cooldownData.can_change\n usernameChangeData.cooldownEnd = cooldownData.cooldown_end ? new Date(cooldownData.cooldown_end) : null\n usernameChangeData.daysRemaining = cooldownData.days_remaining || 0\n \n if (usernameChangeData.canChange) {\n showUsernameChange.value = true\n usernameForm.username = currentUser.value?.username || ''\n } else {\n errorMessage.value = `You can change your username again in ${usernameChangeData.daysRemaining} days`\n }\n } catch (err) {\n errorMessage.value = 'Failed to check username cooldown'\n showUsernameChange.value = true // Allow opening anyway\n } finally {\n usernameChangeLoading.value = false\n }\n } else {\n // When closing, reset form\n showUsernameChange.value = false\n usernameForm.username = ''\n usernameForm.errors.username = ''\n usernameAvailability.available = false\n usernameAvailability.message = ''\n }\n}\n\nconst handleUsernameChange = async () => {\n if (!isUsernameChangeFormValid.value) {\n // First check if username is valid format\n const usernameRegex = /^[a-zA-Z0-9_-]{3,30}$/\n if (!usernameRegex.test(usernameForm.username)) {\n usernameForm.errors.username = 'Username must be 3-30 characters and contain only letters, numbers, hyphens, and underscores'\n return\n }\n \n // Check availability before attempting to update\n usernameAvailability.checking = true\n usernameAvailability.message = 'Checking availability...'\n \n try {\n const result = await checkUsernameAvailability(usernameForm.username)\n usernameAvailability.available = result.available\n usernameAvailability.message = result.message\n \n if (!result.available) {\n usernameForm.errors.username = 'Username is not available'\n return\n }\n } catch (err) {\n usernameForm.errors.username = 'Failed to check username availability'\n return\n } finally {\n usernameAvailability.checking = false\n }\n }\n\n clearMessages()\n usernameChangeLoading.value = true\n\n try {\n const result = await changeUsername(usernameForm.username)\n \n successMessage.value = result.message || 'Username updated successfully'\n showUsernameChange.value = false\n usernameForm.username = ''\n usernameForm.errors.username = ''\n usernameAvailability.available = false\n usernameAvailability.message = ''\n \n // Emit profile updated event\n if (currentUser.value) {\n emit('profile-updated', currentUser.value)\n }\n } catch (err) {\n const error = err instanceof Error ? err.message : 'Failed to update username'\n \n if (error.includes('taken')) {\n usernameForm.errors.username = 'Username is already taken'\n } else if (error.includes('cooldown') || error.includes('30 days')) {\n errorMessage.value = error\n showUsernameChange.value = false\n } else {\n usernameForm.errors.username = error\n }\n \n emit('error', error)\n } finally {\n usernameChangeLoading.value = false\n }\n}\n\nconst triggerAvatarUpload = () => {\n if (uploading.value) return\n avatarFileInput.value?.click()\n}\n\nconst handleAvatarFileSelect = (event: Event) => {\n const target = event.target as HTMLInputElement\n const file = target.files?.[0]\n if (file) {\n // Validate file\n if (!file.type.startsWith('image/')) {\n errorMessage.value = 'Please select an image file'\n return\n }\n \n if (file.size > 5 * 1024 * 1024) { // 5MB limit\n errorMessage.value = 'File size must be less than 5MB'\n return\n }\n \n // Store the selected file and open editor\n selectedImageFile.value = file\n showAvatarEditor.value = true\n }\n \n // Reset the input\n if (target) {\n target.value = ''\n }\n}\n\nconst handleAvatarUpload = async (file: File) => {\n await uploadAvatar(file)\n showAvatarEditor.value = false\n selectedImageFile.value = null\n}\n\nconst handleAvatarError = (error: string) => {\n errorMessage.value = error\n}\n\nconst handleAvatarEditorClose = () => {\n showAvatarEditor.value = false\n selectedImageFile.value = null\n}\n\nconst uploadAvatar = async (file: File) => {\n uploading.value = true\n clearMessages()\n \n try {\n // Check if we have an access token\n if (!currentSession.value?.accessToken) {\n throw new Error('No access token available. Please sign in again.')\n }\n \n // Create form data\n const formData = new FormData()\n formData.append('avatar', file)\n \n // Upload to API endpoint\n const response = await fetch(getUrl('avatar'), {\n method: 'POST',\n body: formData,\n headers: {\n 'Authorization': `Bearer ${currentSession.value.accessToken}`\n }\n })\n \n if (!response.ok) {\n // Handle authentication errors\n if (response.status === 401) {\n // Try to refresh token and retry once\n try {\n console.log('Access token expired, attempting to refresh...')\n const refreshed = await refreshToken()\n if (refreshed && currentSession.value?.accessToken) {\n console.log('Token refreshed successfully, retrying avatar upload...')\n // Retry the upload with new token\n const retryResponse = await fetch(getUrl('avatar'), {\n method: 'POST',\n body: formData,\n headers: {\n 'Authorization': `Bearer ${currentSession.value.accessToken}`\n }\n })\n \n if (!retryResponse.ok) {\n const errorData = await retryResponse.json().catch(() => ({}))\n throw new Error(errorData.message || `Upload failed: ${retryResponse.status} ${retryResponse.statusText}`)\n }\n \n // Use the retry response for processing\n const retryResult = await retryResponse.json()\n console.log('Avatar upload retry success:', retryResult)\n \n // Update user avatar in the current user state\n if (authUser.value) {\n console.log('Updating authUser avatar from:', authUser.value.avatar, 'to:', retryResult.avatar_url)\n authUser.value.avatar = retryResult.avatar_url\n \n // Also update localStorage\n if (typeof window !== 'undefined') {\n localStorage.setItem('strands_auth_user', JSON.stringify(authUser.value))\n }\n }\n \n // Also update internal user state if present\n if (internalUser.value) {\n internalUser.value.avatar = retryResult.avatar_url\n }\n \n // Refresh user profile from API to ensure we have the latest data\n try {\n await fetchProfile()\n console.log('Profile refreshed after avatar upload retry')\n } catch (refreshError) {\n console.warn('Failed to refresh profile after avatar upload retry:', refreshError)\n }\n \n successMessage.value = 'Avatar updated successfully'\n \n // Emit with current user data\n if (currentUser.value) {\n emit('profile-updated', currentUser.value)\n }\n return\n } else {\n throw new Error('Authentication expired. Please sign in again.')\n }\n } catch (refreshError) {\n throw new Error('Authentication expired. Please sign in again.')\n }\n } else {\n const errorData = await response.json().catch(() => ({}))\n throw new Error(errorData.message || `Upload failed: ${response.status} ${response.statusText}`)\n }\n }\n \n const result = await response.json()\n console.log('Avatar upload success:', result)\n \n // Update user avatar in the current user state\n if (authUser.value) {\n console.log('Updating authUser avatar from:', authUser.value.avatar, 'to:', result.avatar_url)\n authUser.value.avatar = result.avatar_url\n \n // Also update localStorage\n if (typeof window !== 'undefined') {\n localStorage.setItem('strands_auth_user', JSON.stringify(authUser.value))\n }\n }\n \n // Also update internal user state if present\n if (internalUser.value) {\n internalUser.value.avatar = result.avatar_url\n }\n \n // Refresh user profile from API to ensure we have the latest data\n try {\n await fetchProfile()\n console.log('Profile refreshed after avatar upload')\n } catch (refreshError) {\n console.warn('Failed to refresh profile after avatar upload:', refreshError)\n }\n \n successMessage.value = 'Avatar updated successfully'\n \n // Emit with current user data\n if (currentUser.value) {\n emit('profile-updated', currentUser.value)\n }\n \n } catch (err) {\n const error = err instanceof Error ? err.message : 'Failed to upload avatar'\n errorMessage.value = error\n emit('error', error)\n } finally {\n uploading.value = false\n }\n}\n\nconst handleMfaUpdated = async () => {\n // Refresh the user profile and MFA devices to get updated status\n try {\n await fetchProfile()\n await fetchMfaDevices()\n successMessage.value = 'MFA settings updated successfully'\n emit('mfa-toggle', currentUser.value?.mfaEnabled || false)\n } catch (err) {\n console.error('Failed to refresh profile after MFA update:', err)\n }\n}\n\nconst handleSettingsUpdated = (settings: any) => {\n successMessage.value = 'Settings updated successfully'\n // Settings are automatically updated in the auth composable\n // The modal already handles the API call and state updates\n}\n\nconst handleSessionsUpdated = () => {\n // Refresh session count when sessions are updated\n loadUserSessions()\n}\n\nconst handleCancel = () => {\n const user = currentUser.value\n if (user) {\n form.firstName = user.firstName || ''\n form.lastName = user.lastName || ''\n form.email = user.email\n }\n clearMessages()\n showPasswordChange.value = false\n showEmailChange.value = false\n passwordForm.current = ''\n passwordForm.new = ''\n passwordForm.confirm = ''\n emailChangeForm.newEmail = ''\n emailChangeForm.password = ''\n emailChangeForm.errors.newEmail = ''\n emailChangeForm.errors.password = ''\n}\n\nconst handleSignOut = async () => {\n signingOut.value = true\n clearMessages()\n \n try {\n await signOut()\n // The signOut function from useStrandsAuth will handle navigation and token clearing\n successMessage.value = 'Signed out successfully'\n } catch (err) {\n const error = err instanceof Error ? err.message : 'Failed to sign out'\n errorMessage.value = error\n emit('error', error)\n signingOut.value = false\n }\n}\n\n\n// Initialize username cooldown data when component mounts\nonMounted(async () => {\n if (currentUser.value && isAuthenticated.value) {\n try {\n const cooldownData = await getUsernameCooldown()\n usernameChangeData.canChange = cooldownData.can_change\n usernameChangeData.cooldownEnd = cooldownData.cooldown_end ? new Date(cooldownData.cooldown_end) : null\n usernameChangeData.daysRemaining = cooldownData.days_remaining || 0\n } catch (err) {\n console.error('Failed to fetch username cooldown:', err)\n }\n }\n})\n\n</script>\n\n<style scoped>\n/* Container Styles */\n.profile-container-width {\n width: 100%;\n}\n\n.profile-max-width {\n max-width: 56rem;\n}\n\n.profile-centered {\n margin: 0 auto;\n}\n\n.profile-animated {\n animation: slideUp 0.3s ease-out;\n}\n\n@keyframes slideUp {\n from {\n opacity: 0;\n transform: translateY(20px);\n }\n to {\n opacity: 1;\n transform: translateY(0);\n }\n}\n\n.profile-content-layout {\n display: flex;\n flex-direction: column;\n gap: 1.5rem;\n}\n\n.profile-card-modern {\n background: #ffffff;\n border: 1px solid #e5e7eb;\n border-radius: 1rem;\n padding: 2rem;\n box-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.1);\n}\n\n/* Modal-specific styles */\n.profile-container-modal {\n /* Remove any container-specific styles when in modal */\n}\n\n.profile-content-modal {\n /* Remove card styling when in modal */\n background: transparent;\n border: none;\n border-radius: 0;\n padding: 0;\n box-shadow: none;\n}\n\n/* Header */\n.profile-header {\n text-align: center;\n display: flex;\n flex-direction: column;\n gap: 0.5rem;\n}\n\n.profile-title {\n font-size: 1.5rem;\n font-weight: 700;\n color: #EA00A8;\n}\n\n.profile-subtitle {\n color: #4b5563;\n font-size: 0.875rem;\n}\n\n/* Profile Image Section */\n.profile-image-section {\n display: flex;\n flex-direction: column;\n align-items: center;\n}\n\n.profile-image-container {\n position: relative;\n}\n\n.profile-image-wrapper {\n position: relative;\n display: inline-block;\n}\n\n.profile-image-wrapper:hover .profile-upload-overlay {\n opacity: 1;\n}\n\n.profile-progress-ring {\n position: absolute;\n z-index: 10;\n top: 50%;\n left: 50%;\n transform: translate(-50%, -50%);\n pointer-events: none;\n}\n\n.profile-avatar {\n width: 6rem;\n height: 6rem;\n border-radius: 50%;\n position: relative;\n}\n\n.profile-avatar-with-image {\n box-shadow: 0 20px 25px -5px rgba(0, 0, 0, 0.1);\n overflow: hidden;\n}\n\n.profile-avatar-image {\n width: 100%;\n height: 100%;\n object-fit: cover;\n}\n\n.profile-avatar-initials {\n background-color: #EA00A8;\n display: flex;\n align-items: center;\n justify-content: center;\n color: white;\n font-size: 1.5rem;\n font-weight: 700;\n box-shadow: 0 20px 25px -5px rgba(0, 0, 0, 0.1);\n z-index: 10;\n}\n\n.profile-upload-overlay {\n position: absolute;\n inset: 0;\n border-radius: 50%;\n background: rgba(0, 0, 0, 0.4);\n display: flex;\n align-items: center;\n justify-content: center;\n opacity: 0;\n transition: opacity 0.2s ease;\n z-index: 20;\n border: none;\n cursor: pointer;\n}\n\n.profile-upload-overlay:disabled {\n cursor: not-allowed;\n}\n\n.profile-upload-icon {\n width: 1.5rem;\n height: 1.5rem;\n color: white;\n}\n\n.profile-file-input {\n display: none;\n}\n\n/* Profile Form */\n.profile-form {\n display: flex;\n flex-direction: column;\n gap: 1rem;\n}\n\n.profile-form-grid {\n display: grid;\n grid-template-columns: 1fr;\n gap: 1rem;\n}\n\n@media (min-width: 768px) {\n .profile-form {\n gap: 1.5rem;\n }\n \n .profile-form-grid {\n grid-template-columns: 1fr 1fr;\n gap: 1.5rem;\n }\n \n .profile-title {\n font-size: 1.875rem;\n }\n \n .profile-subtitle {\n font-size: 1rem;\n }\n}\n\n/* Section Styles */\n.profile-section {\n display: flex;\n flex-direction: column;\n gap: 0.75rem;\n}\n\n@media (min-width: 768px) {\n .profile-section {\n gap: 1rem;\n }\n}\n\n.profile-section-title {\n font-size: 1.125rem;\n font-weight: 600;\n color: #111827;\n}\n\n/* Setting Cards */\n.profile-setting-card {\n display: flex;\n flex-direction: column;\n gap: 1rem;\n padding: 1rem;\n background-color: #f9fafb;\n border-radius: 0.75rem;\n}\n\n.profile-setting-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: 0.5rem;\n}\n\n.profile-setting-title {\n font-weight: 500;\n color: #111827;\n}\n\n.profile-setting-subtitle {\n font-size: 0.875rem;\n color: #4b5563;\n}\n\n/* Transitions */\n.expand-enter-active {\n transition: all 0.4s cubic-bezier(0.4, 0, 0.2, 1);\n overflow: hidden;\n}\n\n.expand-leave-active {\n transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);\n overflow: hidden;\n}\n\n.expand-enter-from {\n max-height: 0;\n opacity: 0;\n transform: translateY(-10px);\n}\n\n.expand-leave-to {\n max-height: 0;\n opacity: 0;\n transform: translateY(-10px);\n}\n\n.expand-enter-to,\n.expand-leave-from {\n max-height: 300px;\n opacity: 1;\n transform: translateY(0);\n}\n\n/* MFA Device Chip */\n.mfa-device-chip {\n display: inline-flex;\n align-items: center;\n gap: 0.375rem;\n padding: 0.25rem 0.625rem;\n border-radius: 0.5rem;\n font-size: 0.75rem;\n font-weight: 500;\n border: 1px solid;\n transition: color 0.15s ease, background-color 0.15s ease, border-color 0.15s ease;\n}\n\n/* MFA Chip Color Variants */\n.mfa-device-chip.chip-blue {\n background-color: #eff6ff;\n color: #1d4ed8;\n border-color: #bfdbfe;\n}\n\n.mfa-device-chip.chip-green {\n background-color: #f0fdf4;\n color: #15803d;\n border-color: #bbf7d0;\n}\n\n.mfa-device-chip.chip-purple {\n background-color: #faf5ff;\n color: #7c3aed;\n border-color: #e9d5ff;\n}\n\n\n/* New semantic classes for Tailwind conversion */\n.profile-change-form {\n display: flex;\n flex-direction: column;\n gap: 0.75rem;\n overflow: hidden;\n}\n\n.profile-field-section {\n display: flex;\n flex-direction: column;\n gap: 1rem;\n padding: 1rem;\n background-color: #f9fafb;\n border-radius: 0.75rem;\n}\n\n.profile-field-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: 0.5rem;\n}\n\n.profile-field-header-vertical {\n align-items: flex-start;\n gap: 1rem;\n}\n\n.profile-password-section {\n display: flex;\n flex-direction: column;\n gap: 0.75rem;\n}\n\n@media (min-width: 768px) {\n .profile-password-section {\n gap: 1rem;\n }\n}\n\n.profile-mfa-content {\n flex: 1;\n display: flex;\n flex-direction: column;\n gap: 0.75rem;\n}\n\n.profile-mfa-chips {\n display: flex;\n flex-wrap: wrap;\n gap: 0.5rem;\n}\n\n.profile-actions-section {\n display: flex;\n flex-direction: column;\n gap: 0.75rem;\n padding-top: 1.5rem;\n border-top: 1px solid #e5e7eb;\n animation: slideUp 0.3s ease-out;\n}\n\n@media (min-width: 640px) {\n .profile-actions-section {\n flex-direction: row;\n }\n}\n\n.profile-help-item {\n display: flex;\n align-items: flex-start;\n gap: 0.75rem;\n}\n\n.profile-help-icon {\n width: 1rem;\n height: 1rem;\n flex-shrink: 0;\n}\n\n.profile-footer-actions {\n display: flex;\n gap: 1rem;\n align-items: stretch;\n}\n\n.profile-action-icon {\n width: 1rem;\n height: 1rem;\n}\n\n.profile-footer-text {\n color: #9ca3af;\n font-size: 0.875rem;\n}\n\n/* Avatar Editor Modal */\n.profile-avatar-modal-overlay {\n position: fixed;\n inset: 0;\n background-color: rgba(0, 0, 0, 0.5);\n display: flex;\n align-items: center;\n justify-content: center;\n z-index: 50;\n padding: 1rem;\n}\n\n.profile-avatar-modal {\n background-color: #ffffff;\n border-radius: 0.75rem;\n box-shadow: 0 25px 50px -12px rgba(0, 0, 0, 0.25);\n max-width: 56rem;\n width: 100%;\n max-height: 90vh;\n overflow-y: auto;\n}\n\n.profile-avatar-modal-content {\n padding: 1.5rem;\n display: flex;\n flex-direction: column;\n gap: 1.5rem;\n}\n\n.profile-avatar-modal-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n}\n\n.profile-avatar-modal-close {\n color: #9ca3af;\n transition: color 0.2s ease;\n background: none;\n border: none;\n cursor: pointer;\n padding: 0.25rem;\n border-radius: 0.25rem;\n}\n\n.profile-avatar-modal-close:hover {\n color: #4b5563;\n}\n\n.profile-avatar-modal-close-icon {\n width: 1.5rem;\n height: 1.5rem;\n}\n\n/* Profile field styles */\n.profile-field-title {\n font-weight: 500;\n color: #111827;\n}\n\n.profile-field-subtitle {\n font-size: 0.875rem;\n color: #6b7280;\n}\n\n.profile-availability-message {\n font-size: 0.75rem;\n}\n\n.profile-availability-message.success {\n color: #16a34a;\n}\n\n.profile-availability-message.error {\n color: #dc2626;\n}\n\n.profile-toggle-container {\n flex-shrink: 0;\n}\n\n.profile-alert-message {\n font-weight: 500;\n}\n\n.profile-modal-title {\n font-size: 1.25rem;\n font-weight: 700;\n color: #111827;\n}\n\n/* Sign out button styles */\n.profile-sign-out-button {\n width: 100%;\n}\n\n@media (min-width: 640px) {\n .profile-sign-out-button {\n width: auto;\n }\n}\n\n/* Sessions Modal Styles */\n.sessions-modal {\n min-width: 32rem;\n max-width: 48rem;\n}\n\n.session-current-badge {\n background-color: #dcfdf7;\n color: #065f46;\n font-size: 0.75rem;\n font-weight: 500;\n padding: 0.125rem 0.5rem;\n border-radius: 9999px;\n border: 1px solid #a7f3d0;\n}\n\n.modal-header {\n margin-bottom: 1.5rem;\n}\n\n.modal-title {\n font-size: 1.5rem;\n font-weight: 700;\n color: #111827;\n margin-bottom: 0.5rem;\n}\n\n.modal-subtitle {\n color: #6b7280;\n}\n\n.sessions-content {\n display: flex;\n flex-direction: column;\n gap: 1.5rem;\n}\n\n.session-stats {\n display: flex;\n gap: 1rem;\n padding: 1rem;\n background-color: #f9fafb;\n border-radius: 0.5rem;\n}\n\n.stat-item {\n display: flex;\n flex-direction: column;\n align-items: center;\n gap: 0.25rem;\n}\n\n.stat-label {\n font-size: 0.875rem;\n color: #6b7280;\n}\n\n.stat-value {\n font-size: 1.5rem;\n font-weight: 700;\n color: #111827;\n}\n\n.sessions-list {\n display: flex;\n flex-direction: column;\n gap: 1rem;\n}\n\n.sessions-loading {\n display: flex;\n align-items: center;\n gap: 0.5rem;\n padding: 2rem;\n justify-content: center;\n color: #6b7280;\n}\n\n.sessions-empty {\n text-align: center;\n padding: 2rem;\n color: #6b7280;\n}\n\n.session-card {\n border: 1px solid #e5e7eb;\n border-radius: 0.5rem;\n padding: 1rem;\n background-color: #ffffff;\n}\n\n.session-card-header {\n display: flex;\n justify-content: space-between;\n align-items: flex-start;\n margin-bottom: 0.75rem;\n}\n\n.session-device-info {\n flex: 1;\n}\n\n.session-device-name {\n font-size: 1.125rem;\n font-weight: 600;\n color: #111827;\n margin-bottom: 0.25rem;\n}\n\n.session-card-details {\n display: flex;\n flex-direction: column;\n gap: 0.5rem;\n}\n\n.session-detail-row {\n display: flex;\n gap: 0.5rem;\n}\n\n.detail-label {\n font-weight: 500;\n color: #6b7280;\n min-width: 6rem;\n}\n\n.detail-value {\n color: #111827;\n}\n\n.session-actions {\n display: flex;\n justify-content: center;\n padding-top: 1rem;\n border-top: 1px solid #e5e7eb;\n}\n\n@media (max-width: 640px) {\n .sessions-modal {\n min-width: auto;\n width: 100%;\n margin: 1rem;\n }\n \n .session-stats {\n flex-direction: column;\n gap: 0.5rem;\n }\n \n .session-card-header {\n flex-direction: column;\n gap: 0.75rem;\n }\n \n .detail-label {\n min-width: 5rem;\n }\n}\n</style>\n\n","<template>\n <div class=\"accui-component-scope\">\n <div class=\"accui-w-full accui-min-w-100 accui-max-w-md accui-mx-auto accui-animate-slide-up\">\n <StrandsUiCard variant=\"modern\">\n <!-- Header -->\n <div class=\"accui-text-center accui-mb-8\">\n <h1 class=\"accui-text-3xl accui-font-bold accui-text-gradient accui-mb-2\">Reset password</h1>\n <p class=\"accui-text-neutral-600\">Enter your email address and we'll send you a link to reset your password</p>\n </div>\n\n <!-- Reset Form -->\n <form @submit.prevent=\"handlePasswordReset\" class=\"accui-space-y-6\">\n <StrandsUiInput id=\"email\" v-model=\"form.email\" type=\"email\" label=\"Email address\"\n placeholder=\"Enter your email address\" autocomplete=\"email\" required :disabled=\"loading || isSubmitted\"\n :error=\"error ? 'Email address not found' : undefined\" />\n\n <StrandsUiButton type=\"submit\" variant=\"primary\" full-width :disabled=\"loading || !form.email.trim() || isSubmitted\"\n :loading=\"loading\" :loading-text=\"'Sending link...'\">\n {{ isSubmitted ? 'Link sent!' : 'Send reset link' }}\n </StrandsUiButton>\n </form>\n\n <!-- Success Message -->\n <StrandsUiAlert v-if=\"isSubmitted\" variant=\"success\"\n :message=\"`Check your email - We've sent a password reset link to ${form.email}`\"\n class=\"accui-mt-6 accui-animate-fade-in\" />\n\n <!-- Error Message -->\n <StrandsUiAlert v-if=\"error\" variant=\"error\" :message=\"error\" class=\"accui-mt-6 accui-animate-fade-in\" dismissible\n @dismiss=\"error = ''\" />\n\n <!-- Back to Sign In -->\n <div class=\"accui-mt-8 accui-text-center\">\n <StrandsUiLink @click=\"$emit('back-to-signin')\" class=\"accui-inline-flex accui-items-center accui-gap-2\">\n <svg class=\"accui-w-4 accui-h-4\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M15 19l-7-7 7-7\" />\n </svg>\n Back to sign in\n </StrandsUiLink>\n </div>\n\n <!-- Secured by footer -->\n <StrandsSecuredFooter :config=\"props.config\">\n <!-- Need help -->\n <div v-if=\"getSupportEmail()\" class=\"accui-mt-6 accui-text-center\">\n <p class=\"accui-text-neutral-400 accui-text-sm\">\n Need help?\n <StrandsUiLink variant=\"primary\" :href=\"`mailto:${getSupportEmail()}`\">\n Contact Support\n </StrandsUiLink>\n </p>\n </div>\n </StrandsSecuredFooter>\n </StrandsUiCard>\n </div>\n </div>\n</template>\n\n<script setup lang=\"ts\">\nimport { ref, reactive } from 'vue'\nimport { StrandsUiCard, StrandsUiButton, StrandsUiInput, StrandsUiAlert, StrandsUiLink } from '../ui'\nimport StrandsSecuredFooter from './StrandsSecuredFooter.vue'\nimport { useStrandsConfig, type StrandsAuthConfig } from '../composables/useStrandsConfig'\n\ninterface Props {\n config?: StrandsAuthConfig\n}\n\ninterface Emits {\n (e: 'success', email: string): void\n (e: 'error', error: string): void\n (e: 'back-to-signin'): void\n}\n\nconst props = withDefaults(defineProps<Props>(), {})\nconst emit = defineEmits<Emits>()\n\n// Get configuration\nconst { getSupportEmail } = useStrandsConfig(props.config)\n\nconst loading = ref(false)\nconst error = ref('')\nconst isSubmitted = ref(false)\n\nconst form = reactive({\n email: ''\n})\n\nconst handlePasswordReset = async () => {\n loading.value = true\n error.value = ''\n\n try {\n // Integration point: Replace with actual password reset API call\n console.log('Password reset request:', { email: form.email })\n\n // Simulate API call\n await new Promise(resolve => setTimeout(resolve, 1000))\n\n isSubmitted.value = true\n emit('success', form.email)\n } catch (err) {\n error.value = 'Failed to send password reset email. Please try again.'\n emit('error', error.value)\n } finally {\n loading.value = false\n }\n}\n</script>\n\n<style scoped>\n/* Override accui- prefixed Tailwind classes with CSS properties */\n.accui-w-full {\n width: 100%;\n}\n\n.accui-min-w-100 {\n min-width: 25rem;\n}\n\n.accui-max-w-md {\n max-width: 28rem;\n}\n\n.accui-mx-auto {\n margin-left: auto;\n margin-right: auto;\n}\n\n.accui-animate-slide-up {\n animation: slideUp 0.3s ease-out;\n}\n\n.accui-text-center {\n text-align: center;\n}\n\n.accui-mb-8 {\n margin-bottom: 2rem;\n}\n\n.accui-text-3xl {\n font-size: 1.875rem;\n}\n\n.accui-font-bold {\n font-weight: 700;\n}\n\n.accui-text-gradient {\n background: linear-gradient(to right, var(--strands-500, #EA00A8), var(--strands-600, #db2777));\n background-clip: text;\n -webkit-background-clip: text;\n color: transparent;\n}\n\n.accui-mb-2 {\n margin-bottom: 0.5rem;\n}\n\n.accui-text-neutral-600 {\n color: var(--neutral-600, #525252);\n}\n\n.accui-space-y-6 > * + * {\n margin-top: 1.5rem;\n}\n\n.accui-mt-6 {\n margin-top: 1.5rem;\n}\n\n.accui-animate-fade-in {\n animation: fadeIn 0.2s ease-out;\n}\n\n.accui-mt-8 {\n margin-top: 2rem;\n}\n\n.accui-inline-flex {\n display: inline-flex;\n}\n\n.accui-items-center {\n align-items: center;\n}\n\n.accui-gap-2 {\n gap: 0.5rem;\n}\n\n.accui-w-4 {\n width: 1rem;\n}\n\n.accui-h-4 {\n height: 1rem;\n}\n\n.accui-text-neutral-400 {\n color: var(--neutral-400, #a3a3a3);\n}\n\n.accui-text-sm {\n font-size: 0.875rem;\n}\n\n@keyframes slideUp {\n from {\n opacity: 0;\n transform: translateY(20px);\n }\n to {\n opacity: 1;\n transform: translateY(0);\n }\n}\n\n@keyframes fadeIn {\n from {\n opacity: 0;\n }\n to {\n opacity: 1;\n }\n}\n</style>","<template>\n <div v-if=\"signedInOrInverted\" class=\"animate-fade-in\">\n <slot :user=\"user\" :signOut=\"signOut\" :invert=\"invert\" />\n </div>\n <div v-else-if=\"signedOutOrInverted\" class=\"animate-fade-in\">\n <slot name=\"fallback\" :signIn=\"signIn\">\n <!-- Default fallback content -->\n <div class=\"signed-in-fallback\">\n <div class=\"signed-in-icon-container\">\n <svg class=\"signed-in-icon\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" 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 </svg>\n </div>\n <h3 class=\"signed-in-title\">Sign in required</h3>\n <p class=\"signed-in-subtitle\">You need to be signed in to access this content.</p>\n <button\n @click=\"signIn\"\n class=\"signed-in-button\"\n >\n Sign in\n </button>\n </div>\n </slot>\n </div>\n <div v-else-if=\"showLoading\" class=\"animate-fade-in\">\n <slot name=\"loading\">\n <StrandsUiLoader\n :size=\"64\" \n text=\"Checking authentication...\" \n variant=\"auto\" \n :show-particles=\"true\" \n />\n </slot>\n </div>\n</template>\n\n<script setup lang=\"ts\">\nimport { ref, computed, onMounted } from 'vue'\nimport { useStrandsAuth } from '../composables/useStrandsAuth'\nimport { StrandsUiLoader } from '../ui'\n\ninterface Props {\n showFallback?: boolean\n invert?: boolean\n}\n\ninterface Emits {\n (e: 'sign-in-required'): void\n}\n\nconst props = withDefaults(defineProps<Props>(), {\n showFallback: true,\n invert: false\n})\n\nconst invert = props.invert ?? false\n\nconst signedInOrInverted = computed(() => ((isAuthenticated.value && !invert) || (!isAuthenticated.value && invert)) && !showLoading.value)\nconst signedOutOrInverted = computed(() => ((isAuthenticated.value && invert) || (!isAuthenticated.value && !invert)) && props.showFallback && !showLoading.value)\n\nconst emit = defineEmits<Emits>()\n\n// Local loading state to ensure loading shows on first render\nconst isComponentReady = ref(false)\n\nconst { isAuthenticated, isInitializing, isSigningIn, user, signOut } = useStrandsAuth()\n\n// Show loading until both auth is initialized AND component is ready\n// Don't show loading during sign-in attempts - let StrandsAuth handle its own loading\nconst showLoading = computed(() => (isInitializing.value && !isSigningIn.value) || !isComponentReady.value)\n\nonMounted(() => {\n // Add a small delay to ensure we show loading state\n setTimeout(() => {\n isComponentReady.value = true\n }, 100)\n})\n\nconst signIn = () => {\n emit('sign-in-required')\n}\n</script>\n\n<style scoped>\n.signed-in-fallback {\n text-align: center;\n padding: 2rem 0;\n}\n\n.signed-in-icon-container {\n width: 4rem;\n height: 4rem;\n margin: 0 auto 1rem;\n background-color: #f5f5f5;\n border-radius: 50%;\n display: flex;\n align-items: center;\n justify-content: center;\n}\n\n.signed-in-icon {\n width: 2rem;\n height: 2rem;\n color: #a3a3a3;\n}\n\n.signed-in-title {\n font-size: 1.125rem;\n font-weight: 600;\n color: #171717;\n margin-bottom: 0.5rem;\n}\n\n.signed-in-subtitle {\n color: #525252;\n margin-bottom: 1rem;\n}\n\n.signed-in-button {\n background-color: #EA00A8;\n color: white;\n width: auto;\n padding: 0.5rem 1.5rem;\n border: none;\n border-radius: 0.5rem;\n cursor: pointer;\n font-weight: 600;\n transition: background-color 0.2s ease;\n}\n\n.signed-in-button:hover {\n background-color: #B8006F;\n}\n</style>","<template>\n <div v-if=\"!isAuthenticated && !isLoading\" class=\"animate-fade-in\">\n <slot :signIn=\"signIn\" :signUp=\"signUp\" />\n </div>\n <div v-else-if=\"showFallback && isAuthenticated && !isLoading\" class=\"animate-fade-in\">\n <slot name=\"fallback\" :user=\"user\" :signOut=\"signOut\">\n <!-- Default fallback content for signed in users -->\n <div class=\"signed-out-fallback\">\n <div class=\"signed-out-icon-container\">\n <svg class=\"signed-out-icon\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" 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 </svg>\n </div>\n <h3 class=\"signed-out-title\">Already signed in</h3>\n <p class=\"signed-out-subtitle\">You're currently signed in as {{ user?.email }}.</p>\n <button\n @click=\"signOut\"\n class=\"signed-out-button\"\n >\n Sign out\n </button>\n </div>\n </slot>\n </div>\n <div v-else-if=\"isLoading\" class=\"animate-fade-in\">\n <slot name=\"loading\">\n <StrandsUiLoader \n :size=\"64\"\n text=\"Checking authentication...\"\n variant=\"auto\"\n :show-particles=\"true\"\n />\n </slot>\n </div>\n</template>\n\n<script setup lang=\"ts\">\nimport { useStrandsAuth } from '../composables/useStrandsAuth'\nimport { StrandsUiLoader } from '../ui'\n\ninterface Props {\n showFallback?: boolean\n}\n\ninterface Emits {\n (e: 'sign-in-clicked'): void\n (e: 'sign-up-clicked'): void\n}\n\nconst props = withDefaults(defineProps<Props>(), {\n showFallback: true\n})\n\nconst emit = defineEmits<Emits>()\n\nconst { isAuthenticated, isLoading, user, signOut } = useStrandsAuth()\n\nconst signIn = () => {\n emit('sign-in-clicked')\n}\n\nconst signUp = () => {\n emit('sign-up-clicked')\n}\n</script>\n\n<style scoped>\n.signed-out-fallback {\n text-align: center;\n padding: 2rem 0;\n}\n\n.signed-out-icon-container {\n width: 4rem;\n height: 4rem;\n margin: 0 auto 1rem;\n background-color: #fce7f3;\n border-radius: 50%;\n display: flex;\n align-items: center;\n justify-content: center;\n}\n\n.signed-out-icon {\n width: 2rem;\n height: 2rem;\n color: #db2777;\n}\n\n.signed-out-title {\n font-size: 1.125rem;\n font-weight: 600;\n color: #171717;\n margin-bottom: 0.5rem;\n}\n\n.signed-out-subtitle {\n color: #525252;\n margin-bottom: 1rem;\n}\n\n.signed-out-button {\n background-color: #f3f4f6;\n color: #374151;\n width: auto;\n padding: 0.5rem 1.5rem;\n border: 1px solid #d1d5db;\n border-radius: 0.5rem;\n cursor: pointer;\n font-weight: 600;\n transition: all 0.2s ease;\n}\n\n.signed-out-button:hover {\n background-color: #e5e7eb;\n border-color: #9ca3af;\n}\n</style>","<template>\n <div class=\"accui-component-scope\">\n <svg \n viewBox=\"0 0 22571 9413\" \n xmlns=\"http://www.w3.org/2000/svg\" \n :class=\"class\"\n role=\"img\"\n aria-label=\"Strands Services Logo\"\n >\n <g>\n <text \n x=\"3798.06\" \n y=\"7203.65\" \n style=\"font-family:'CourierNewPS-BoldMT', 'Courier New', monospace;font-weight:700;font-size:5295.12px;fill:currentColor;\"\n >\n trands\n </text>\n </g>\n <g>\n <path \n d=\"M2370.75,8047.43c-172.831,0 -349.758,-28.381 -520.19,-86.274c-362.325,-122.988 -626.515,-354.842 -724.651,-635.835c-94.464,-270.121 -70.883,-674.383 204.038,-923.606c318.411,-288.759 731.429,-170.714 1168.59,-45.891c186.811,53.375 395.367,112.962 625.668,152.923c-0.424,-11.579 -0.988,-21.181 -1.412,-28.806c-14.12,-228.042 -92.911,-347.217 -223.524,-544.618c-83.592,-126.376 -178.48,-269.696 -272.097,-466.956c-74.978,-158.006 -138.096,-327.308 -188.082,-502.822c-408.216,-4.095 -801.606,-101.666 -1135.83,-290.313c-874.468,-493.079 -1531.48,-1711.66 -1068.34,-2543.62c195.283,-350.747 599.829,-639.082 1030.5,-734.394c321.095,-71.166 618.185,-23.298 836.343,134.707c228.183,165.207 391.131,461.309 425.16,772.66c29.371,267.862 -42.784,514.825 -203.049,695.423c-247.669,279.016 -675.371,371.786 -1089.66,236.232l175.515,-536.852c194.295,63.541 396.497,32.9 491.809,-74.414c68.059,-76.673 72.436,-183.14 64.105,-259.107c-18.356,-167.889 -111.973,-316.576 -195,-376.728c-85.569,-61.988 -221.547,-76.532 -382.8,-40.666c-271.533,60.152 -542.641,248.375 -659.133,457.778c-126.942,228.042 -103.784,560.433 63.541,912.027c171.137,359.643 465.968,682.997 788.616,865.007c216.181,121.999 473.593,192.882 744.843,211.097c-19.91,-172.69 -27.111,-345.522 -20.475,-513.977c23.864,-608.865 225.642,-1098.41 567.917,-1378.28c338.604,-276.898 921.487,-426.997 1334.79,-159.7c453.119,293.136 534.452,990.394 350.041,1468.36c-164.077,425.444 -583.307,786.075 -1150.24,989.406c-130.048,46.738 -262.355,83.451 -395.226,110.28c35.583,109.432 77.379,215.192 125.105,315.446c76.673,161.253 156.17,281.558 233.126,397.767c150.521,227.619 292.854,442.67 316.152,821.517c1.694,28.522 3.248,65.659 3.53,109.431c88.534,-1.694 179.61,-7.766 273.086,-19.344c234.819,-28.947 692.521,-185.215 954.251,-408.635l202.34,499.143c-286.222,212.469 -804.15,435.189 -1087.4,470.066c-144.592,17.791 -283.817,24.851 -417.395,24.004c-75.684,261.648 -223.665,536.852 -507.34,722.674c-206.438,135.272 -466.251,204.885 -736.795,204.885l-0.424,0Zm-542.076,-1260.51c-52.669,-0 -93.617,9.743 -119.316,33.182c-79.073,71.731 -79.78,234.114 -50.127,318.977c38.69,110.702 185.116,223.523 373.057,287.347c271.956,92.346 572.576,70.319 765.882,-56.34c114.374,-74.837 189.353,-185.258 238.209,-303.303c-263.484,-45.185 -495.48,-111.409 -693.022,-167.89c-205.873,-58.881 -391.978,-111.973 -514.683,-111.973Zm1872.91,-4019.61c-153.346,0 -336.768,62.27 -471.193,172.126c-212.227,173.538 -343.828,524.708 -361.055,963.283c-5.93,149.393 1.271,302.88 20.192,455.802c110.421,-21.463 219.994,-51.257 327.167,-89.805c406.239,-145.721 710.531,-392.966 814.032,-661.11c98.842,-256.141 62.835,-666.052 -130.047,-790.875c-51.963,-33.606 -121.717,-49.421 -199.096,-49.421Z\" \n style=\"fill:currentColor;fill-rule:nonzero;\" \n />\n </g>\n </svg>\n </div>\n</template>\n\n<script setup lang=\"ts\">\ninterface Props {\n class?: string\n}\n\nwithDefaults(defineProps<Props>(), {\n class: ''\n})\n</script>","<template>\n <slot />\n</template>\n\n<script setup lang=\"ts\">\nimport { onMounted } from 'vue'\nimport { provideStrandsConfig, type StrandsAuthConfig } from '../composables/useStrandsConfig'\n\ninterface Props {\n config: StrandsAuthConfig\n}\n\nconst props = defineProps<Props>()\n\n// Provide the configuration to all child components\nonMounted(() => {\n provideStrandsConfig(props.config)\n})\n\n// Also provide immediately for SSR compatibility\nprovideStrandsConfig(props.config)\n</script>\n","<template>\n <svg :class=\"iconClass\" :fill=\"fill\" :stroke=\"stroke\" :viewBox=\"viewBox\" :aria-hidden=\"ariaHidden\">\n <component :is=\"iconComponent\" />\n </svg>\n</template>\n\n<script setup lang=\"ts\">\nimport { computed, h as createElement } from 'vue'\n\ninterface Props {\n name: string\n class?: string\n size?: 'xs' | 'sm' | 'md' | 'lg' | 'xl'\n fill?: string\n stroke?: string\n ariaHidden?: boolean\n}\n\nconst props = withDefaults(defineProps<Props>(), {\n class: '',\n size: 'md',\n fill: 'none',\n stroke: 'currentColor',\n ariaHidden: true\n})\n\nconst sizeClasses = {\n xs: 'w-3 h-3',\n sm: 'w-4 h-4',\n md: 'w-5 h-5',\n lg: 'w-6 h-6',\n xl: 'w-8 h-8'\n}\n\nconst iconClass = computed(() => `${sizeClasses[props.size]} ${props.class}`)\nconst viewBox = computed(() => '0 0 24 24')\n\nconst icons = {\n 'eye': () => createElement('g', [\n createElement('path', { \n 'stroke-linecap': 'round', \n 'stroke-linejoin': 'round', \n 'stroke-width': '2', \n d: 'M15 12a3 3 0 11-6 0 3 3 0 016 0z' \n }),\n createElement('path', { \n 'stroke-linecap': 'round', \n 'stroke-linejoin': 'round', \n 'stroke-width': '2',\n d: 'M2.458 12C3.732 7.943 7.523 5 12 5c4.478 0 8.268 2.943 9.542 7-1.274 4.057-5.064 7-9.542 7-4.477 0-8.268-2.943-9.542-7z' \n })\n ]),\n 'eye-slash': () => createElement('g', [\n createElement('path', { \n 'stroke-linecap': 'round', \n 'stroke-linejoin': 'round', \n 'stroke-width': '2',\n d: 'M13.875 18.825A10.05 10.05 0 0112 19c-4.478 0-8.268-2.943-9.543-7a9.97 9.97 0 011.563-3.029m5.858.908a3 3 0 114.243 4.243M9.878 9.878l4.242 4.242M9.878 9.878L3 3m6.878 6.878L21 21' \n })\n ]),\n 'camera': () => createElement('path', { \n 'stroke-linecap': 'round', \n 'stroke-linejoin': 'round', \n 'stroke-width': '2', \n d: 'M3 9a2 2 0 012-2h.93a2 2 0 001.664-.89l.812-1.22A2 2 0 0710.07 4h3.86a2 2 0 011.664.89l.812 1.22A2 2 0 0018.07 7H19a2 2 0 012 2v9a2 2 0 01-2 2H5a2 2 0 01-2-2V9z' \n }),\n 'chevron-left': () => createElement('path', { \n 'stroke-linecap': 'round', \n 'stroke-linejoin': 'round', \n 'stroke-width': '2', \n d: 'M15 19l-7-7 7-7' \n }),\n 'loading': () => createElement('g', [\n createElement('circle', { \n class: 'opacity-25', \n cx: '12', \n cy: '12', \n r: '10', \n stroke: 'currentColor', \n 'stroke-width': '4' \n }),\n createElement('path', { \n class: 'opacity-75', \n fill: 'currentColor', \n d: 'm4 12a8 8 0 0 1 8-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 0 1 4 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z' \n })\n ]),\n 'check-circle': () => createElement('path', { \n 'fill-rule': 'evenodd', \n d: 'M10 18a8 8 0 100-16 8 8 0 000 16zm3.857-9.809a.75.75 0 00-1.214-.882l-3.236 4.53L7.53 10.173a.75.75 0 00-1.06 1.061l2.5 2.5a.75.75 0 001.137-.089l4-5.5z', \n 'clip-rule': 'evenodd' \n }),\n 'x-circle': () => createElement('path', { \n 'fill-rule': 'evenodd', \n d: 'M10 18a8 8 0 100-16 8 8 0 000 16zM8.28 7.22a.75.75 0 00-1.06 1.06L8.94 10l-1.72 1.72a.75.75 0 101.06 1.06L10 11.06l1.72 1.72a.75.75 0 101.06-1.06L11.06 10l1.72-1.72a.75.75 0 00-1.06-1.06L10 8.94 8.28 7.22z', \n 'clip-rule': 'evenodd' \n }),\n 'lock': () => createElement('path', { \n 'stroke-linecap': 'round', \n 'stroke-linejoin': 'round', \n 'stroke-width': '2', \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 'user': () => createElement('path', { \n 'stroke-linecap': 'round', \n 'stroke-linejoin': 'round', \n 'stroke-width': '2', \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 'google': () => createElement('g', { fill: 'currentColor' }, [\n createElement('path', { \n fill: '#4285F4', \n d: 'M22.56 12.25c0-.78-.07-1.53-.2-2.25H12v4.26h5.92c-.26 1.37-1.04 2.53-2.21 3.31v2.77h3.57c2.08-1.92 3.28-4.74 3.28-8.09z' \n }),\n createElement('path', { \n fill: '#34A853', \n d: 'M12 23c2.97 0 5.46-.98 7.28-2.66l-3.57-2.77c-.98.66-2.23 1.06-3.71 1.06-2.86 0-5.29-1.93-6.16-4.53H2.18v2.84C3.99 20.53 7.7 23 12 23z' \n }),\n createElement('path', { \n fill: '#FBBC05', \n d: 'M5.84 14.09c-.22-.66-.35-1.36-.35-2.09s.13-1.43.35-2.09V7.07H2.18C1.43 8.55 1 10.22 1 12s.43 3.45 1.18 4.93l2.85-2.22.81-.62z' \n }),\n createElement('path', { \n fill: '#EA4335', \n d: 'M12 5.38c1.62 0 3.06.56 4.21 1.64l3.15-3.15C17.45 2.09 14.97 1 12 1 7.7 1 3.99 3.47 2.18 7.07l3.66 2.84c.87-2.6 3.3-4.53 6.16-4.53z' \n })\n ]),\n 'github': () => createElement('path', { \n 'fill-rule': 'evenodd', \n d: 'M12 2C6.477 2 2 6.484 2 12.017c0 4.425 2.865 8.18 6.839 9.504.5.092.682-.217.682-.483 0-.237-.008-.868-.013-1.703-2.782.605-3.369-1.343-3.369-1.343-.454-1.158-1.11-1.466-1.11-1.466-.908-.62.069-.608.069-.608 1.003.07 1.531 1.032 1.531 1.032.892 1.53 2.341 1.088 2.91.832.092-.647.35-1.088.636-1.338-2.22-.253-4.555-1.113-4.555-4.951 0-1.093.39-1.988 1.029-2.688-.103-.253-.446-1.272.098-2.65 0 0 .84-.27 2.75 1.026A9.564 9.564 0 0112 6.844c.85.004 1.705.115 2.504.337 1.909-1.296 2.747-1.027 2.747-1.027.546 1.379.202 2.398.1 2.651.64.7 1.028 1.595 1.028 2.688 0 3.848-2.339 4.695-4.566 4.943.359.309.678.92.678 1.855 0 1.338-.012 2.419-.012 2.747 0 .268.18.58.688.482A10.019 10.019 0 0022 12.017C22 6.484 17.522 2 12 2z', \n 'clip-rule': 'evenodd' \n })\n}\n\nconst iconComponent = computed(() => {\n const icon = icons[props.name as keyof typeof icons]\n return icon ? icon() : createElement('path', { d: '' })\n})\n</script>\n","<template>\n <div class=\"accui-component-scope\" ref=\"containerRef\">\n <SignedIn :invert=\"!!props.user\">\n <!-- Signed In State - User Button Trigger -->\n <button @click=\"toggleDropdown\" @keydown.enter=\"toggleDropdown\" @keydown.space.prevent=\"toggleDropdown\"\n @keydown.escape=\"closeDropdown\" @keydown.arrow-down.prevent=\"openDropdown\"\n class=\"user-button\"\n aria-haspopup=\"true\" :aria-expanded=\"showDropdown\" aria-label=\"User menu\">\n <div class=\"user-button-content\">\n <!-- User Info -->\n <div v-if=\"!hideUser\" class=\"user-info\">\n <div class=\"user-name\">\n {{ displayName }}\n </div>\n </div>\n\n <!-- Avatar with Level Progress Ring -->\n <div class=\"avatar-container\">\n <div class=\"avatar-wrapper\">\n <!-- Avatar Image -->\n <img v-if=\"user?.avatar\" :src=\"user.avatar\" :alt=\"`${user.firstName || user.email}'s avatar`\"\n class=\"avatar-image\" />\n\n <!-- Default Avatar -->\n <div v-else class=\"avatar-default\">\n <svg class=\"avatar-icon\" fill=\"currentColor\" viewBox=\"0 0 20 20\">\n <path fill-rule=\"evenodd\" d=\"M10 9a3 3 0 100-6 3 3 0 000 6zm-7 9a7 7 0 1114 0H3z\"\n clip-rule=\"evenodd\" />\n </svg>\n </div>\n </div>\n </div>\n\n <!-- Dropdown Arrow -->\n <svg class=\"dropdown-arrow\" :class=\"{ 'dropdown-arrow-open': showDropdown }\" fill=\"none\" stroke=\"currentColor\"\n viewBox=\"0 0 24 24\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M19 9l-7 7-7-7\" />\n </svg>\n </div>\n\n <!-- Dropdown Menu -->\n <Transition name=\"dropdown\">\n <div v-if=\"showDropdown\"\n :class=\"[\n 'dropdown-menu',\n `dropdown-menu-align-${props.menuAlign}`,\n `dropdown-menu-vertical-${props.menuVerticalAlign}`\n ]\"\n role=\"menu\" aria-orientation=\"vertical\" @keydown.escape=\"closeDropdown\"\n @keydown.arrow-up.prevent=\"focusPrevious\" @keydown.arrow-down.prevent=\"focusNext\"\n @keydown.home.prevent=\"focusFirst\" @keydown.end.prevent=\"focusLast\">\n <div class=\"dropdown-content\">\n <!-- User Info Header -->\n <div class=\"dropdown-header\">\n <div v-if=\"user\" class=\"dropdown-avatar-container\">\n <StrandsUiLevelProgress :size=\"80\" :value=\"user.xp\" :max=\"user.next_level_xp\" :level=\"user.level\"\n :level-label=\"`LEVEL ${user.level}`\" :user-settings=\"user.settings\"\n class=\"level-progress-overlay\" />\n <img v-if=\"user?.avatar\" :src=\"user.avatar\" :alt=\"`${user.firstName || user.email}'s avatar`\"\n class=\"dropdown-avatar-image\" />\n <div v-else class=\"dropdown-avatar-default\">\n <svg class=\"dropdown-avatar-icon\" fill=\"currentColor\" viewBox=\"0 0 20 20\">\n <path fill-rule=\"evenodd\" d=\"M10 9a3 3 0 100-6 3 3 0 000 6zm-7 9a7 7 0 1114 0H3z\"\n clip-rule=\"evenodd\" />\n </svg>\n </div>\n </div>\n <div class=\"dropdown-user-details\">\n <div class=\"dropdown-user-name\">{{ displayName }}</div>\n <div class=\"dropdown-user-email\">{{ user?.email }}</div>\n </div>\n </div>\n\n <div class=\"dropdown-divider\"></div>\n\n <!-- Menu Items -->\n <div class=\"dropdown-menu-items\">\n <button ref=\"profileButtonRef\" @click=\"openProfile\"\n class=\"dropdown-menu-item\"\n role=\"menuitem\" tabindex=\"-1\">\n <svg class=\"dropdown-menu-icon\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\"\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 </svg>\n Profile\n </button>\n\n <button @click=\"handleSignOut\"\n class=\"dropdown-menu-item dropdown-menu-item-danger\"\n role=\"menuitem\" tabindex=\"-1\">\n <svg class=\"dropdown-menu-icon dropdown-menu-icon-danger\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\"\n d=\"M17 16l4-4m0 0l-4-4m4 4H7m6 4v1a3 3 0 01-3 3H6a3 3 0 01-3-3V7a3 3 0 013-3h4a3 3 0 013 3v1\" />\n </svg>\n Sign Out\n </button>\n </div>\n </div>\n </div>\n </Transition>\n </button>\n\n <!-- Profile Modal -->\n <StrandsUiModal :open=\"showProfileModal\" @close=\"closeProfile\" :fullscreen-on-mobile=\"false\">\n <template #header>\n <div class=\"modal-header\">\n <h2 class=\"modal-title\">User Profile</h2>\n <button @click=\"closeProfile\"\n class=\"modal-close-button\"\n aria-label=\"Close profile\">\n <svg class=\"modal-close-icon\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M6 18L18 6M6 6l12 12\" />\n </svg>\n </button>\n </div>\n </template>\n\n <StrandsUserProfile :user=\"user\" @profile-updated=\"handleProfileUpdated\" @error=\"handleProfileError\" in-modal />\n </StrandsUiModal>\n\n <!-- Fallback Slot - Sign In Button (shown when not authenticated) -->\n <template #fallback>\n <button @click=\"openSignIn\"\n class=\"sign-in-button\"\n aria-label=\"Sign in\">\n <svg class=\"sign-in-icon\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\"\n d=\"M11 16l-4-4m0 0l4-4m-4 4h14m-5 4v1a3 3 0 01-3 3H6a3 3 0 01-3-3V7a3 3 0 013-3h7a3 3 0 013 3v1\" />\n </svg>\n <span>Sign In</span>\n </button>\n\n <!-- Sign In Modal -->\n <StrandsUiModal :open=\"showSignInModal\" @close=\"closeSignIn\" :fullscreen-on-mobile=\"false\">\n <template #header>\n <div class=\"modal-header\">\n <h2 class=\"modal-title\">Sign In</h2>\n <button @click=\"closeSignIn\"\n class=\"modal-close-button\"\n aria-label=\"Close sign in\">\n <svg class=\"modal-close-icon\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M6 18L18 6M6 6l12 12\" />\n </svg>\n </button>\n </div>\n </template>\n\n <StrandsAuth @signed-in=\"handleSignedIn\" @error=\"handleSignInError\" :redirect-url=\"redirectUrl\" in-modal />\n </StrandsUiModal>\n </template>\n </SignedIn>\n </div>\n</template>\n\n<script setup lang=\"ts\">\nimport { ref, computed, nextTick, onMounted, onUnmounted } from 'vue'\nimport { useStrandsAuth } from '../composables/useStrandsAuth'\nimport { StrandsUiLevelProgress, StrandsUiModal } from '../ui'\nimport { StrandsAuth, StrandsUserProfile, SignedIn } from '.'\nimport { User } from '../../types'\n\ninterface Props {\n hideUser?: boolean\n variant?: 'minimal' | 'compact' | 'full'\n redirectUrl?: string\n user?: User,\n menuAlign?: 'left' | 'right' | 'center'\n menuVerticalAlign?: 'bottom' | 'top'\n}\n\nconst props = withDefaults(defineProps<Props>(), {\n hideUser: false,\n variant: 'minimal',\n redirectUrl: '/',\n user: undefined,\n menuAlign: 'right',\n menuVerticalAlign: 'bottom'\n})\n\nconst emit = defineEmits<{\n 'profile-updated': []\n 'signed-out': []\n 'signed-in': []\n}>()\n\n// Auth composable\nconst { currentUser, signOut } = useStrandsAuth()\n\n// Component state\nconst showDropdown = ref(false)\nconst showProfileModal = ref(false)\nconst showSignInModal = ref(false)\nconst containerRef = ref<HTMLElement>()\nconst profileButtonRef = ref<HTMLButtonElement>()\n\nconst user = computed(() => props.user || currentUser.value)\n\n// User display logic\nconst displayName = computed(() => {\n if (!user.value) return 'User'\n\n if (user.value.username) {\n return user.value.username\n }\n\n if (user.value.firstName && user.value.lastName) {\n return `${user.value.firstName} ${user.value.lastName}`\n }\n\n if (user.value.firstName) {\n return user.value.firstName\n }\n\n return user.value.email || 'User'\n})\n\n// Dropdown management\nconst toggleDropdown = () => {\n showDropdown.value = !showDropdown.value\n\n if (showDropdown.value) {\n nextTick(() => {\n profileButtonRef.value?.focus()\n })\n }\n}\n\nconst openDropdown = () => {\n showDropdown.value = true\n nextTick(() => {\n profileButtonRef.value?.focus()\n })\n}\n\nconst closeDropdown = () => {\n showDropdown.value = false\n}\n\n// Keyboard navigation for dropdown\nconst focusNext = () => {\n // Simple implementation - can be enhanced\n}\n\nconst focusPrevious = () => {\n // Simple implementation - can be enhanced\n}\n\nconst focusFirst = () => {\n profileButtonRef.value?.focus()\n}\n\nconst focusLast = () => {\n // Focus the last item (sign out button)\n}\n\n// Profile modal management\nconst openProfile = () => {\n showProfileModal.value = true\n closeDropdown()\n}\n\nconst closeProfile = () => {\n showProfileModal.value = false\n}\n\nconst handleProfileUpdated = () => {\n emit('profile-updated')\n}\n\nconst handleProfileError = (error: string) => {\n console.error('Profile error:', error)\n}\n\n// Sign in modal management\nconst openSignIn = () => {\n showSignInModal.value = true\n}\n\nconst closeSignIn = () => {\n showSignInModal.value = false\n}\n\nconst handleSignedIn = () => {\n closeSignIn()\n emit('signed-in')\n}\n\nconst handleSignInError = (error: string) => {\n console.error('Sign in error:', error)\n}\n\n// Sign out handler\nconst handleSignOut = async () => {\n try {\n await signOut()\n closeDropdown()\n emit('signed-out')\n } catch (error) {\n console.error('Sign out error:', error)\n }\n}\n\n// Click outside to close dropdown\nconst handleClickOutside = (event: Event) => {\n if (containerRef.value && !containerRef.value.contains(event.target as Node)) {\n closeDropdown()\n }\n}\n\nonMounted(() => {\n document.addEventListener('click', handleClickOutside)\n})\n\nonUnmounted(() => {\n document.removeEventListener('click', handleClickOutside)\n})\n</script>\n\n<style scoped>\n/* User Button */\n.user-button {\n position: relative;\n display: flex;\n align-items: center;\n padding: 0.5rem 0.75rem;\n border-radius: 9999px;\n background-color: #f3f4f6;\n color: #111827;\n font-size: 0.875rem;\n font-weight: 500;\n border: none;\n cursor: pointer;\n transition: all 0.15s;\n}\n\n.user-button:hover {\n background-color: #d1d5db;\n}\n\n.user-button:focus {\n outline: none;\n box-shadow: 0 0 0 2px #EA00A8;\n}\n\n.user-button-content {\n display: flex;\n align-items: center;\n gap: 0.75rem;\n}\n\n.user-info {\n display: flex;\n flex-direction: column;\n align-items: flex-start;\n}\n\n.user-name {\n font-size: 0.875rem;\n font-weight: 500;\n color: #111827;\n}\n\n.avatar-container {\n position: relative;\n flex-shrink: 0;\n}\n\n.avatar-wrapper {\n position: relative;\n width: 2rem;\n height: 2rem;\n}\n\n.avatar-image {\n width: 2rem;\n height: 2rem;\n border-radius: 50%;\n object-fit: cover;\n}\n\n.avatar-default {\n width: 2rem;\n height: 2rem;\n border-radius: 50%;\n background-color: #e5e7eb;\n display: flex;\n align-items: center;\n justify-content: center;\n}\n\n.avatar-icon {\n width: 1.25rem;\n height: 1.25rem;\n color: #6b7280;\n}\n\n.dropdown-arrow {\n width: 1rem;\n height: 1rem;\n color: #9ca3af;\n transition: transform 0.15s;\n}\n\n.dropdown-arrow-open {\n transform: rotate(180deg);\n}\n\n/* Dropdown Menu */\n.dropdown-menu {\n position: absolute;\n width: 18rem;\n background: white;\n border-radius: 0.5rem;\n box-shadow: 0 10px 15px -3px rgb(0 0 0 / 0.1), 0 4px 6px -2px rgb(0 0 0 / 0.05);\n border: 1px solid #e5e7eb;\n z-index: 50;\n}\n\n/* Horizontal alignment */\n.dropdown-menu-align-left {\n left: 0;\n}\n\n.dropdown-menu-align-right {\n right: 0;\n}\n\n.dropdown-menu-align-center {\n left: 50%;\n transform: translateX(-50%);\n}\n\n/* Vertical alignment */\n.dropdown-menu-vertical-bottom {\n top: 100%;\n margin-top: 0.5rem;\n}\n\n.dropdown-menu-vertical-top {\n bottom: 100%;\n margin-bottom: 0.5rem;\n}\n\n/* Center horizontal alignment needs special handling for transforms */\n.dropdown-menu-align-center.dropdown-menu-vertical-bottom {\n transform: translateX(-50%);\n}\n\n.dropdown-menu-align-center.dropdown-menu-vertical-top {\n transform: translateX(-50%);\n}\n\n.dropdown-content {\n padding: 0.5rem;\n}\n\n.dropdown-header {\n display: flex;\n align-items: center;\n gap: 1rem;\n padding: 0.75rem;\n border-radius: 0.5rem;\n background-color: #f9fafb;\n}\n\n.dropdown-avatar-container {\n position: relative;\n}\n\n.level-progress-overlay {\n position: absolute;\n z-index: 10;\n top: 50%;\n left: 50%;\n transform: translate(-50%, -50%);\n pointer-events: none;\n}\n\n.dropdown-avatar-image {\n width: 3.5rem;\n height: 3.5rem;\n border-radius: 50%;\n object-fit: cover;\n}\n\n.dropdown-avatar-default {\n width: 3.5rem;\n height: 3.5rem;\n border-radius: 50%;\n background-color: #e5e7eb;\n display: flex;\n align-items: center;\n justify-content: center;\n}\n\n.dropdown-avatar-icon {\n width: 1.25rem;\n height: 1.25rem;\n color: #6b7280;\n}\n\n.dropdown-user-details {\n flex: 1;\n min-width: 0;\n text-align: left;\n}\n\n.dropdown-user-name {\n font-size: 0.875rem;\n font-weight: 500;\n color: #111827;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n.dropdown-user-email {\n font-size: 0.875rem;\n color: #6b7280;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n.dropdown-divider {\n height: 1px;\n background-color: #e5e7eb;\n margin: 0.5rem 0;\n}\n\n.dropdown-menu-items {\n display: flex;\n flex-direction: column;\n gap: 0.25rem;\n}\n\n.dropdown-menu-item {\n width: 100%;\n display: flex;\n align-items: center;\n gap: 0.75rem;\n padding: 0.5rem 0.75rem;\n font-size: 0.875rem;\n color: #374151;\n border-radius: 0.5rem;\n border: none;\n background: none;\n cursor: pointer;\n transition: all 0.15s;\n text-align: left;\n}\n\n.dropdown-menu-item:hover,\n.dropdown-menu-item:focus {\n background-color: #f3f4f6;\n outline: none;\n}\n\n.dropdown-menu-item-danger {\n color: #dc2626;\n}\n\n.dropdown-menu-item-danger:hover,\n.dropdown-menu-item-danger:focus {\n background-color: #fef2f2;\n}\n\n.dropdown-menu-icon {\n width: 1rem;\n height: 1rem;\n color: #9ca3af;\n}\n\n.dropdown-menu-icon-danger {\n color: #ef4444;\n}\n\n/* Sign In Button */\n.sign-in-button {\n position: relative;\n display: flex;\n align-items: center;\n gap: 0.5rem;\n padding: 0.5rem 1rem;\n border-radius: 9999px;\n background-color: #EA00A8;\n color: white;\n font-size: 0.875rem;\n font-weight: 500;\n border: none;\n cursor: pointer;\n transition: all 0.15s;\n}\n\n.sign-in-button:hover {\n background-color: #B8006F;\n}\n\n.sign-in-button:focus {\n outline: none;\n box-shadow: 0 0 0 2px #EA00A8, 0 0 0 4px white;\n}\n\n.sign-in-icon {\n width: 1rem;\n height: 1rem;\n}\n\n/* Modal Styles */\n.modal-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n}\n\n.modal-title {\n font-size: 1.25rem;\n font-weight: 600;\n color: #111827;\n}\n\n.modal-close-button {\n padding: 0.25rem;\n border-radius: 0.5rem;\n color: #9ca3af;\n background: none;\n border: none;\n cursor: pointer;\n transition: all 0.2s;\n}\n\n.modal-close-button:hover {\n color: #6b7280;\n background-color: #f3f4f6;\n}\n\n.modal-close-icon {\n width: 1.25rem;\n height: 1.25rem;\n}\n\n/* Transitions */\n.dropdown-enter-active,\n.dropdown-leave-active {\n transition: all 0.15s ease;\n}\n\n.dropdown-enter-from,\n.dropdown-leave-to {\n opacity: 0;\n}\n\n.dropdown-enter-to,\n.dropdown-leave-from {\n opacity: 1;\n}\n\n/* Transform-based transitions for different alignments */\n.dropdown-menu-align-left.dropdown-enter-from,\n.dropdown-menu-align-left.dropdown-leave-to {\n transform: scale(0.95) translateY(4px);\n}\n\n.dropdown-menu-align-left.dropdown-enter-to,\n.dropdown-menu-align-left.dropdown-leave-from {\n transform: scale(1) translateY(0);\n}\n\n.dropdown-menu-align-right.dropdown-enter-from,\n.dropdown-menu-align-right.dropdown-leave-to {\n transform: scale(0.95) translateY(4px);\n}\n\n.dropdown-menu-align-right.dropdown-enter-to,\n.dropdown-menu-align-right.dropdown-leave-from {\n transform: scale(1) translateY(0);\n}\n\n.dropdown-menu-align-center.dropdown-enter-from,\n.dropdown-menu-align-center.dropdown-leave-to {\n transform: translateX(-50%) scale(0.95) translateY(4px);\n}\n\n.dropdown-menu-align-center.dropdown-enter-to,\n.dropdown-menu-align-center.dropdown-leave-from {\n transform: translateX(-50%) scale(1) translateY(0);\n}\n\n/* Responsive adjustments */\n@media (max-width: 640px) {\n .dropdown-menu {\n width: 16rem;\n }\n \n .user-info {\n display: none;\n }\n}\n</style>","<template>\n <div \n ref=\"scrollContainer\" \n :style=\"{ height: containerHeight + 'px', overflowY: 'auto' }\"\n @scroll=\"handleScroll\"\n class=\"accui-virtual-list\"\n >\n <div :style=\"{ height: totalHeight + 'px', position: 'relative' }\">\n <div \n v-for=\"item in visibleItems\" \n :key=\"getItemKey(item.data)\"\n :style=\"{\n position: 'absolute',\n top: item.top + 'px',\n left: 0,\n right: 0,\n height: itemHeight + 'px'\n }\"\n >\n <slot :item=\"item.data\" :index=\"item.index\">\n <!-- Default fallback -->\n <div class=\"accui-p-2 accui-border-b\">\n {{ JSON.stringify(item.data) }}\n </div>\n </slot>\n </div>\n </div>\n </div>\n</template>\n\n<script setup lang=\"ts\">\nimport { ref, computed, onMounted, onUnmounted, nextTick } from 'vue'\n\ninterface Props {\n items: any[]\n itemHeight: number\n containerHeight: number\n itemKey?: string | ((item: any) => string | number)\n overscan?: number\n}\n\nconst props = withDefaults(defineProps<Props>(), {\n itemKey: 'id',\n overscan: 5\n})\n\nconst scrollContainer = ref<HTMLElement>()\nconst scrollTop = ref(0)\n\n// Calculate visible range\nconst visibleRange = computed(() => {\n const start = Math.floor(scrollTop.value / props.itemHeight)\n const end = Math.min(\n start + Math.ceil(props.containerHeight / props.itemHeight),\n props.items.length - 1\n )\n \n return {\n start: Math.max(0, start - props.overscan),\n end: Math.min(props.items.length - 1, end + props.overscan)\n }\n})\n\n// Get visible items with positioning\nconst visibleItems = computed(() => {\n const { start, end } = visibleRange.value\n const items = []\n \n for (let i = start; i <= end; i++) {\n items.push({\n index: i,\n data: props.items[i],\n top: i * props.itemHeight\n })\n }\n \n return items\n})\n\n// Total height of all items\nconst totalHeight = computed(() => props.items.length * props.itemHeight)\n\n// Get item key function\nconst getItemKey = (item: any): string | number => {\n if (typeof props.itemKey === 'function') {\n return props.itemKey(item)\n }\n return item[props.itemKey] || item.id || Math.random()\n}\n\n// Handle scroll events with throttling\nlet scrollTimer: NodeJS.Timeout | null = null\nconst handleScroll = (event: Event) => {\n if (scrollTimer) {\n clearTimeout(scrollTimer)\n }\n \n scrollTimer = setTimeout(() => {\n const target = event.target as HTMLElement\n scrollTop.value = target.scrollTop\n }, 16) // ~60fps\n}\n\n// Cleanup\nonUnmounted(() => {\n if (scrollTimer) {\n clearTimeout(scrollTimer)\n }\n})\n\n// Scroll to item function\nconst scrollToItem = (index: number, align: 'start' | 'center' | 'end' = 'start') => {\n if (!scrollContainer.value) return\n \n let scrollTo = index * props.itemHeight\n \n if (align === 'center') {\n scrollTo -= props.containerHeight / 2 - props.itemHeight / 2\n } else if (align === 'end') {\n scrollTo -= props.containerHeight - props.itemHeight\n }\n \n scrollContainer.value.scrollTop = Math.max(0, scrollTo)\n}\n\n// Expose methods\ndefineExpose({\n scrollToItem\n})\n</script>\n\n<style scoped>\n.accui-virtual-list {\n /* Improve scrolling performance */\n will-change: scroll-position;\n -webkit-overflow-scrolling: touch;\n}\n\n.accui-virtual-list::-webkit-scrollbar {\n width: 8px;\n}\n\n.accui-virtual-list::-webkit-scrollbar-track {\n background: rgba(0, 0, 0, 0.1);\n border-radius: 4px;\n}\n\n.accui-virtual-list::-webkit-scrollbar-thumb {\n background: rgba(0, 0, 0, 0.3);\n border-radius: 4px;\n}\n\n.accui-virtual-list::-webkit-scrollbar-thumb:hover {\n background: rgba(0, 0, 0, 0.5);\n}\n</style>","<template>\n <div class=\"accui-component-scope\">\n <UiModal :open=\"show\" @close=\"closeModal\" card-class=\"mfa-setup-modal\">\n <template #header>\n <div class=\"mfa-setup-header\">\n <div>\n <h2 class=\"mfa-setup-title\">Two-Factor Authentication</h2>\n <p class=\"mfa-setup-subtitle\">Add extra security to your account</p>\n </div>\n <div class=\"mfa-setup-status-container\">\n <span class=\"mfa-setup-status-badge\"\n :class=\"mfaEnabled || activeMfaDevices.length > 0 ? 'mfa-setup-status-enabled' : 'mfa-setup-status-disabled'\">\n {{ mfaEnabled || activeMfaDevices.length > 0 ? 'Enabled' : 'Not Enabled' }}\n </span>\n </div>\n </div>\n </template>\n\n <div class=\"mfa-setup-content\">\n <!-- Loading State -->\n <div v-if=\"loading\" class=\"mfa-setup-loading\">\n <StrandsUiLoader :size=\"32\" />\n <span class=\"mfa-setup-loading-text\">Loading MFA settings...</span>\n </div>\n\n <!-- MFA Options -->\n <div v-else class=\"mfa-setup-sections\">\n <!-- Current MFA Status -->\n <div v-if=\"mfaEnabled || activeMfaDevices.length > 0\" class=\"mfa-setup-status-alert\">\n <div class=\"mfa-setup-status-content\">\n <div class=\"mfa-setup-status-icon\">\n <Shield :size=\"20\" class=\"mfa-setup-shield-icon\" />\n </div>\n <div>\n <span class=\"mfa-setup-status-title\">2FA is currently enabled on your account</span>\n <p class=\"mfa-setup-status-description\">Your account has additional security protection</p>\n </div>\n </div>\n </div>\n\n <!-- Setup Options -->\n <div>\n <h3 class=\"mfa-setup-methods-title\">Choose Your Authentication Method</h3>\n <div class=\"mfa-setup-methods-grid\">\n <!-- TOTP Setup -->\n <div class=\"mfa-setup-method-card\" @click=\"startTotpSetup\">\n <div class=\"mfa-setup-method-content\">\n <div class=\"mfa-setup-method-icon mfa-setup-totp-icon\">\n <Smartphone :size=\"28\" class=\"mfa-setup-icon-svg\" />\n </div>\n <div class=\"mfa-setup-method-info\">\n <h4 class=\"mfa-setup-method-title\">Authenticator App</h4>\n <p class=\"mfa-setup-method-description\">Use Google Authenticator, Authy, or any TOTP-compatible app\n to\n generate secure codes</p>\n </div>\n <StrandsUiButton variant=\"primary\" size=\"md\" @click.stop=\"startTotpSetup\" :disabled=\"loading\"\n class=\"mfa-setup-method-button\">\n Setup Authenticator\n </StrandsUiButton>\n </div>\n </div>\n\n <!-- Email MFA Setup -->\n <div class=\"mfa-setup-method-card\" @click=\"startEmailMfaSetup\">\n <div class=\"mfa-setup-method-content\">\n <div class=\"mfa-setup-method-icon mfa-setup-email-icon\">\n <Mail :size=\"28\" class=\"mfa-setup-icon-svg\" />\n </div>\n <div class=\"mfa-setup-method-info\">\n <h4 class=\"mfa-setup-method-title\">Email Verification</h4>\n <p class=\"mfa-setup-method-description\">Receive verification codes directly in your email inbox for\n easy\n access</p>\n </div>\n <StrandsUiButton variant=\"primary\" size=\"md\" @click.stop=\"startEmailMfaSetup\" :disabled=\"loading\"\n class=\"mfa-setup-method-button\">\n Setup Email 2FA\n </StrandsUiButton>\n </div>\n </div>\n </div>\n </div>\n\n <!-- Manage Existing -->\n <div v-if=\"activeMfaDevices.length > 0\" class=\"mfa-setup-manage-section\">\n <div class=\"mfa-setup-manage-header\">\n <div>\n <h3 class=\"mfa-setup-manage-title\">Manage Existing Methods</h3>\n <p class=\"mfa-setup-manage-description\">{{ activeMfaDevices.length }} device(s) currently active</p>\n </div>\n <StrandsUiButton variant=\"secondary\" size=\"md\" @click=\"openMfaModal\" :disabled=\"loading\">\n <Settings :size=\"16\" class=\"mfa-setup-manage-icon\" />\n Manage Devices\n </StrandsUiButton>\n </div>\n </div>\n </div>\n </div>\n\n <template #footer>\n <div class=\"mfa-setup-footer\">\n <StrandsUiButton variant=\"secondary\" @click=\"closeModal\" :disabled=\"loading\">\n Cancel\n </StrandsUiButton>\n </div>\n </template>\n </UiModal>\n\n <!-- TOTP Setup Modal -->\n <StrandsTotpSetupModal v-if=\"showTotpSetup\" :show=\"showTotpSetup\" @close=\"showTotpSetup = false\"\n @success=\"handleSetupSuccess\" />\n\n <!-- Email MFA Setup Modal -->\n <StrandsEmailMfaSetupModal v-if=\"showEmailMfaSetup\" :show=\"showEmailMfaSetup\" @close=\"showEmailMfaSetup = false\"\n @success=\"handleSetupSuccess\" />\n\n <!-- Hardware Key Setup Modal -->\n <StrandsHardwareKeySetupModal v-if=\"showHardwareKeySetup\" :show=\"showHardwareKeySetup\"\n @close=\"showHardwareKeySetup = false\" @success=\"handleSetupSuccess\" />\n\n <!-- Full MFA Management Modal -->\n <StrandsMfaModal v-if=\"showMfaModal\" :show=\"showMfaModal\" @close=\"showMfaModal = false\"\n @mfa-updated=\"handleMfaUpdated\" />\n </div>\n</template>\n\n<script setup lang=\"ts\">\nimport { ref, watch, onMounted, h } from 'vue'\nimport { StrandsUiButton, StrandsUiLoader } from '../ui'\nimport UiModal from '../ui/UiModal.vue'\nimport StrandsTotpSetupModal from './StrandsTotpSetupModal.vue'\nimport StrandsEmailMfaSetupModal from './StrandsEmailMfaSetupModal.vue'\nimport StrandsHardwareKeySetupModal from './StrandsHardwareKeySetupModal.vue'\nimport StrandsMfaModal from './StrandsMfaModal.vue'\nimport { useStrandsMfa } from '../composables/useStrandsMfa'\n\n// Inline SVG icon components using render functions (no runtime compilation needed)\nconst Smartphone = {\n props: {\n size: {\n type: [String, Number],\n default: 24\n }\n },\n render(this: any) {\n return h('svg', { \n width: this.size, \n height: this.size, \n fill: 'none', \n stroke: 'currentColor', \n viewBox: '0 0 24 24' \n }, [\n h('rect', { x: '5', y: '2', width: '14', height: '20', rx: '2', ry: '2' }),\n h('line', { x1: '12', y1: '18', x2: '12.01', y2: '18' })\n ])\n }\n}\n\nconst Mail = {\n props: {\n size: {\n type: [String, Number],\n default: 24\n }\n },\n render(this: any) {\n return h('svg', { \n width: this.size, \n height: this.size, \n fill: 'none', \n stroke: 'currentColor', \n viewBox: '0 0 24 24' \n }, [\n h('path', { d: 'm4 4 16 0c1.1 0 2 .9 2 2l0 12c0 1.1-.9 2-2 2l-16 0c-1.1 0-2-.9-2-2l0-12c0-1.1.9-2 2-2z' }),\n h('polyline', { points: '22,6 12,13 2,6' })\n ])\n }\n}\n\nconst KeyRound = {\n props: {\n size: {\n type: [String, Number],\n default: 24\n }\n },\n render(this: any) {\n return h('svg', { \n width: this.size, \n height: this.size, \n fill: 'none', \n stroke: 'currentColor', \n viewBox: '0 0 24 24' \n }, [\n h('path', { d: 'M2.586 17.414A2 2 0 0 0 2 18.828V21a1 1 0 0 0 1 1h3a1 1 0 0 0 1-1v-1a1 1 0 0 1 1-1h1a1 1 0 0 0 1-1v-1a1 1 0 0 1 1-1h.172a2 2 0 0 0 1.414-.586l.814-.814a6.5 6.5 0 1 0-4-4z' }),\n h('circle', { cx: '16.5', cy: '7.5', r: '.5', fill: 'currentColor' })\n ])\n }\n}\n\nconst Shield = {\n props: {\n size: {\n type: [String, Number],\n default: 24\n }\n },\n render(this: any) {\n return h('svg', { \n width: this.size, \n height: this.size, \n fill: 'none', \n stroke: 'currentColor', \n viewBox: '0 0 24 24' \n }, [\n h('path', { d: 'M20 13c0 5-3.5 7.5-7.66 8.95a1 1 0 0 1-.67-.01C7.5 20.5 4 18 4 13V6a1 1 0 0 1 1-1c2 0 4.5-1.2 6.24-2.72a1.17 1.17 0 0 1 1.52 0C14.51 3.81 17 5 19 5a1 1 0 0 1 1 1z' })\n ])\n }\n}\n\nconst Settings = {\n props: {\n size: {\n type: [String, Number],\n default: 24\n }\n },\n render(this: any) {\n return h('svg', { \n width: this.size, \n height: this.size, \n fill: 'none', \n stroke: 'currentColor', \n viewBox: '0 0 24 24' \n }, [\n h('path', { d: 'M12.22 2h-.44a2 2 0 0 0-2 2v.18a2 2 0 0 1-1 1.73l-.43.25a2 2 0 0 1-2 0l-.15-.08a2 2 0 0 0-2.73.73l-.22.38a2 2 0 0 0 .73 2.73l.15.1a2 2 0 0 1 1 1.72v.51a2 2 0 0 1-1 1.74l-.15.09a2 2 0 0 0-.73 2.73l.22.38a2 2 0 0 0 2.73.73l.15-.08a2 2 0 0 1 2 0l.43.25a2 2 0 0 1 1 1.73V20a2 2 0 0 0 2 2h.44a2 2 0 0 0 2-2v-.18a2 2 0 0 1 1-1.73l.43-.25a2 2 0 0 1 2 0l.15.08a2 2 0 0 0 2.73-.73l.22-.39a2 2 0 0 0-.73-2.73l-.15-.08a2 2 0 0 1-1-1.74v-.5a2 2 0 0 1 1-1.74l.15-.09a2 2 0 0 0 .73-2.73l-.22-.38a2 2 0 0 0-2.73-.73l-.15.08a2 2 0 0 1-2 0l-.43-.25a2 2 0 0 1-1-1.73V4a2 2 0 0 0-2-2z' }),\n h('circle', { cx: '12', cy: '12', r: '3' })\n ])\n }\n}\n\ninterface Props {\n show?: boolean\n}\n\ninterface Emits {\n (e: 'success'): void\n (e: 'error', error: string): void\n (e: 'close'): void\n}\n\nconst props = withDefaults(defineProps<Props>(), {\n show: false\n})\n\nconst emit = defineEmits<Emits>()\n\nconst {\n mfaDevices,\n mfaEnabled,\n loading,\n activeMfaDevices,\n fetchMfaDevices,\n} = useStrandsMfa()\n\n// Modal states\nconst showTotpSetup = ref(false)\nconst showEmailMfaSetup = ref(false)\nconst showHardwareKeySetup = ref(false)\nconst showMfaModal = ref(false)\n\n// Load MFA devices when modal opens\nwatch(() => props.show, async (newShow) => {\n if (newShow) {\n await fetchMfaDevices()\n }\n})\n\nonMounted(async () => {\n if (props.show) {\n await fetchMfaDevices()\n }\n})\n\nconst closeModal = () => {\n emit('close')\n}\n\nconst startTotpSetup = () => {\n showTotpSetup.value = true\n}\n\nconst startEmailMfaSetup = () => {\n showEmailMfaSetup.value = true\n}\n\nconst startHardwareKeySetup = () => {\n showHardwareKeySetup.value = true\n}\n\nconst openMfaModal = () => {\n showMfaModal.value = true\n}\n\nconst handleSetupSuccess = async () => {\n showTotpSetup.value = false\n showEmailMfaSetup.value = false\n showHardwareKeySetup.value = false\n await fetchMfaDevices()\n emit('success')\n}\n\nconst handleMfaUpdated = async () => {\n await fetchMfaDevices()\n}\n</script>\n\n<style scoped>\n/* Header */\n.mfa-setup-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n}\n\n.mfa-setup-title {\n font-size: 1.5rem;\n font-weight: 700;\n color: #111827;\n}\n\n.mfa-setup-subtitle {\n color: #6b7280;\n margin-top: 0.25rem;\n}\n\n.mfa-setup-status-container {\n text-align: right;\n}\n\n.mfa-setup-status-badge {\n display: inline-flex;\n align-items: center;\n padding: 0.25rem 0.75rem;\n border-radius: 9999px;\n font-size: 0.875rem;\n font-weight: 500;\n}\n\n.mfa-setup-status-enabled {\n background-color: #dcfce7;\n color: #166534;\n}\n\n.mfa-setup-status-disabled {\n background-color: #f3f4f6;\n color: #374151;\n}\n\n/* Content */\n.mfa-setup-content {\n display: flex;\n flex-direction: column;\n gap: 2rem;\n}\n\n.mfa-setup-loading {\n display: flex;\n align-items: center;\n justify-content: center;\n padding: 4rem 0;\n}\n\n.mfa-setup-loading-text {\n margin-left: 0.75rem;\n color: #6b7280;\n}\n\n.mfa-setup-sections {\n display: flex;\n flex-direction: column;\n gap: 2rem;\n}\n\n/* Status alert */\n.mfa-setup-status-alert {\n background-color: #f0fdf4;\n border: 1px solid #bbf7d0;\n border-radius: 0.75rem;\n padding: 1.5rem;\n}\n\n.mfa-setup-status-content {\n display: flex;\n align-items: center;\n gap: 0.75rem;\n}\n\n.mfa-setup-status-icon {\n width: 2.5rem;\n height: 2.5rem;\n background-color: #dcfce7;\n border-radius: 50%;\n display: flex;\n align-items: center;\n justify-content: center;\n}\n\n.mfa-setup-shield-icon {\n color: #16a34a;\n}\n\n.mfa-setup-status-title {\n color: #166534;\n font-weight: 500;\n font-size: 1.125rem;\n}\n\n.mfa-setup-status-description {\n color: #15803d;\n font-size: 0.875rem;\n margin-top: 0.25rem;\n}\n\n/* Methods section */\n.mfa-setup-methods-title {\n font-size: 1.25rem;\n font-weight: 600;\n color: #111827;\n margin-bottom: 1.5rem;\n}\n\n.mfa-setup-methods-grid {\n display: grid;\n grid-template-columns: repeat(1, 1fr);\n gap: 1.5rem;\n}\n\n/* Method cards */\n.mfa-setup-method-card {\n padding: 2rem;\n border: 1px solid #e5e7eb;\n border-radius: 0.75rem;\n cursor: pointer;\n transition: all 0.2s ease;\n}\n\n.mfa-setup-method-card:hover {\n box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -2px rgba(0, 0, 0, 0.05);\n border-color: #EA00A8;\n}\n\n.mfa-setup-method-disabled {\n border-color: #d1d5db;\n background-color: #f9fafb;\n opacity: 0.6;\n cursor: not-allowed;\n}\n\n.mfa-setup-method-disabled:hover {\n box-shadow: none;\n border-color: #d1d5db;\n}\n\n.mfa-setup-method-content {\n display: flex !important;\n flex-direction: column !important;\n align-items: center !important;\n justify-content: flex-start !important;\n text-align: center;\n gap: 1rem;\n}\n\n.mfa-setup-method-icon {\n width: 4rem;\n height: 4rem;\n border-radius: 0.75rem;\n display: flex;\n align-items: center;\n justify-content: center;\n transition: all 0.2s ease;\n}\n\n.mfa-setup-totp-icon {\n background-color: rgba(234, 0, 168, 0.15);\n}\n\n.mfa-setup-method-card:hover .mfa-setup-totp-icon {\n background-color: rgba(234, 0, 168, 0.25);\n}\n\n.mfa-setup-email-icon {\n background-color: rgba(234, 0, 168, 0.15);\n}\n\n.mfa-setup-method-card:hover .mfa-setup-email-icon {\n background-color: rgba(234, 0, 168, 0.25);\n}\n\n.mfa-setup-hardware-icon {\n background-color: #e5e7eb;\n}\n\n.mfa-setup-icon-svg {\n color: #EA00A8;\n}\n\n.mfa-setup-icon-disabled {\n color: #9ca3af;\n}\n\n.mfa-setup-method-info {\n display: flex;\n flex-direction: column;\n gap: 0.5rem;\n}\n\n.mfa-setup-method-title {\n font-weight: 600;\n color: #111827;\n font-size: 1.125rem;\n margin: 0;\n}\n\n.mfa-setup-method-title-disabled {\n color: #6b7280;\n}\n\n.mfa-setup-method-description {\n max-width: 300px;\n text-wrap: balance;\n font-size: 0.875rem;\n color: #6b7280;\n line-height: 1.625;\n margin: 0;\n}\n\n.mfa-setup-method-description-disabled {\n color: #9ca3af;\n}\n\n.mfa-setup-method-button {\n width: 100%;\n margin-top: 1rem;\n}\n\n/* Manage section */\n.mfa-setup-manage-section {\n border-top: 1px solid #e5e7eb;\n padding-top: 2rem;\n}\n\n.mfa-setup-manage-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n}\n\n.mfa-setup-manage-title {\n font-size: 1.125rem;\n font-weight: 600;\n color: #111827;\n}\n\n.mfa-setup-manage-description {\n color: #6b7280;\n font-size: 0.875rem;\n margin-top: 0.25rem;\n}\n\n.mfa-setup-manage-icon {\n margin-right: 0.5rem;\n}\n\n/* Footer */\n.mfa-setup-footer {\n display: flex;\n justify-content: flex-end;\n gap: 0.75rem;\n}\n</style>","import type { App } from 'vue'\n\n// Import all UI components\nimport StrandsUiAlert from '../ui/UiAlert.vue'\nimport StrandsUiButton from '../ui/UiButton.vue'\nimport StrandsUiCard from '../ui/UiCard.vue'\nimport StrandsUiInput from '../ui/UiInput.vue'\nimport StrandsUiLink from '../ui/UiLink.vue'\nimport StrandsUiTabs from '../ui/UiTabs.vue'\nimport StrandsUiLoader from '../ui/UiLoader.vue'\n\n// Placeholder function for compatibility\nfunction injectSquircleStyles() {\n // No-op - squircle functionality removed\n}\n\n// Global components map\nconst components = {\n StrandsUiAlert,\n StrandsUiButton,\n StrandsUiCard,\n StrandsUiInput,\n StrandsUiLink,\n StrandsUiTabs,\n StrandsUiLoader,\n}\n\nexport interface StrandsUIOptions {\n prefix?: string\n}\n\nexport default {\n install(app: App, options: StrandsUIOptions = {}) {\n const { prefix = '' } = options\n\n // Inject squircle CSS styles globally\n injectSquircleStyles()\n\n // Register all components globally\n Object.entries(components).forEach(([name, component]) => {\n const componentName = prefix ? `${prefix}${name}` : name\n app.component(componentName, component)\n })\n }\n}\n\n// Export individual components for tree-shaking\nexport {\n StrandsUiAlert,\n StrandsUiButton,\n StrandsUiCard,\n StrandsUiInput,\n StrandsUiLink,\n StrandsUiTabs,\n StrandsUiLoader,\n}\n\n// Export utility functions\nexport { injectSquircleStyles }\n\n// Export types\nexport type {\n ButtonVariant,\n ButtonSize,\n InputType,\n CardVariant,\n LinkVariant,\n AlertVariant,\n} from '../ui/index'","import { useStrandsAuth } from './useStrandsAuth'\nimport type { AuthenticatedFetchOptions } from '../../types'\n\n/**\n * Enhanced fetch composable that automatically includes auth headers\n * and handles token refresh for API requests (Vue version)\n */\nexport function useAuthenticatedFetch() {\n const { currentSession, refreshToken, getAuthHeaders } = useStrandsAuth()\n\n const authenticatedFetch = async (\n url: string | URL,\n options: AuthenticatedFetchOptions = {}\n ): Promise<Response> => {\n const {\n autoRefresh = true,\n requireAuth = true,\n baseURL,\n ...fetchOptions\n } = options\n\n // Check if user is authenticated when required\n if (requireAuth && !currentSession.value?.accessToken) {\n throw new Error('User is not authenticated')\n }\n\n // Construct full URL if baseURL is provided\n let fullUrl: string | URL = url\n if (baseURL && typeof url === 'string' && !url.startsWith('http')) {\n fullUrl = new URL(url, baseURL).toString()\n }\n\n // Prepare headers\n const headers = new Headers(fetchOptions.headers)\n \n // Add auth headers if available\n if (currentSession.value?.accessToken) {\n try {\n const authHeaders = getAuthHeaders()\n Object.entries(authHeaders).forEach(([key, value]) => {\n headers.set(key, value)\n })\n } catch (error) {\n console.warn('[Strands Auth] Failed to get auth headers:', error)\n if (requireAuth) {\n throw error\n }\n }\n }\n\n // Make the request\n const enhancedOptions: RequestInit = {\n ...fetchOptions,\n headers\n }\n\n let response = await fetch(fullUrl, enhancedOptions)\n\n // Handle 401 with auto-refresh\n if (response.status === 401 && autoRefresh && currentSession.value?.refreshToken) {\n console.log('[Strands Auth] Request failed with 401, attempting token refresh...')\n \n try {\n // Attempt to refresh token\n const refreshed = await refreshToken()\n \n if (refreshed && currentSession.value?.accessToken) {\n // Update headers with new token\n const newAuthHeaders = getAuthHeaders()\n Object.entries(newAuthHeaders).forEach(([key, value]) => {\n headers.set(key, value)\n })\n\n // Retry the request with new token\n console.log('[Strands Auth] Retrying request with refreshed token')\n response = await fetch(fullUrl, { ...enhancedOptions, headers })\n }\n } catch (refreshError) {\n console.error('[Strands Auth] Token refresh failed:', refreshError)\n // Return the original 401 response\n }\n }\n\n return response\n }\n\n /**\n * Convenience method for making authenticated GET requests\n */\n const get = (url: string | URL, options?: AuthenticatedFetchOptions) => {\n return authenticatedFetch(url, { ...options, method: 'GET' })\n }\n\n /**\n * Convenience method for making authenticated POST requests\n */\n const post = (url: string | URL, body?: any, options?: AuthenticatedFetchOptions) => {\n const headers = new Headers(options?.headers)\n \n // Auto-set content type for JSON requests\n if (body && typeof body === 'object' && !headers.has('Content-Type')) {\n headers.set('Content-Type', 'application/json')\n }\n\n return authenticatedFetch(url, {\n ...options,\n method: 'POST',\n headers,\n body: typeof body === 'object' ? JSON.stringify(body) : body\n })\n }\n\n /**\n * Convenience method for making authenticated PUT requests\n */\n const put = (url: string | URL, body?: any, options?: AuthenticatedFetchOptions) => {\n const headers = new Headers(options?.headers)\n \n if (body && typeof body === 'object' && !headers.has('Content-Type')) {\n headers.set('Content-Type', 'application/json')\n }\n\n return authenticatedFetch(url, {\n ...options,\n method: 'PUT',\n headers,\n body: typeof body === 'object' ? JSON.stringify(body) : body\n })\n }\n\n /**\n * Convenience method for making authenticated DELETE requests\n */\n const del = (url: string | URL, options?: AuthenticatedFetchOptions) => {\n return authenticatedFetch(url, { ...options, method: 'DELETE' })\n }\n\n /**\n * Convenience method for making authenticated PATCH requests\n */\n const patch = (url: string | URL, body?: any, options?: AuthenticatedFetchOptions) => {\n const headers = new Headers(options?.headers)\n \n if (body && typeof body === 'object' && !headers.has('Content-Type')) {\n headers.set('Content-Type', 'application/json')\n }\n\n return authenticatedFetch(url, {\n ...options,\n method: 'PATCH',\n headers,\n body: typeof body === 'object' ? JSON.stringify(body) : body\n })\n }\n\n return {\n authenticatedFetch,\n get,\n post,\n put,\n delete: del,\n patch\n }\n}\n\n// Export convenience functions for non-composable usage\nexport const $authFetch = {\n get: async (url: string | URL, options?: AuthenticatedFetchOptions) => {\n const { get } = useAuthenticatedFetch()\n return get(url, options)\n },\n post: async (url: string | URL, body?: any, options?: AuthenticatedFetchOptions) => {\n const { post } = useAuthenticatedFetch()\n return post(url, body, options)\n },\n put: async (url: string | URL, body?: any, options?: AuthenticatedFetchOptions) => {\n const { put } = useAuthenticatedFetch()\n return put(url, body, options)\n },\n delete: async (url: string | URL, options?: AuthenticatedFetchOptions) => {\n const { delete: del } = useAuthenticatedFetch()\n return del(url, options)\n },\n patch: async (url: string | URL, body?: any, options?: AuthenticatedFetchOptions) => {\n const { patch } = useAuthenticatedFetch()\n return patch(url, body, options)\n }\n}","// Email validation\nexport const isValidEmail = (email: string): boolean => {\n const emailRegex = /^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$/\n return emailRegex.test(email)\n}\n\n// Password strength validation\nexport const validatePassword = (password: string): {\n isValid: boolean\n strength: 'weak' | 'medium' | 'strong'\n errors: string[]\n} => {\n const errors: string[] = []\n let score = 0\n\n if (password.length < 8) {\n errors.push('Password must be at least 8 characters long')\n } else {\n score += 1\n }\n\n if (!/[A-Z]/.test(password)) {\n errors.push('Password must contain at least one uppercase letter')\n } else {\n score += 1\n }\n\n if (!/[a-z]/.test(password)) {\n errors.push('Password must contain at least one lowercase letter')\n } else {\n score += 1\n }\n\n if (!/\\d/.test(password)) {\n errors.push('Password must contain at least one number')\n } else {\n score += 1\n }\n\n if (!/[!@#$%^&*(),.?\":{}|<>]/.test(password)) {\n errors.push('Password must contain at least one special character')\n } else {\n score += 1\n }\n\n const isValid = errors.length === 0\n let strength: 'weak' | 'medium' | 'strong' = 'weak'\n\n if (score >= 4) {\n strength = 'strong'\n } else if (score >= 3) {\n strength = 'medium'\n }\n\n return { isValid, strength, errors }\n}\n\n// Name validation\nexport const isValidName = (name: string): boolean => {\n return name.trim().length >= 2\n}\n\n\n// Generic required field validation\nexport const isRequired = (value: string): boolean => {\n return value.trim().length > 0\n}\n\n// Password confirmation validation\nexport const passwordsMatch = (password: string, confirmation: string): boolean => {\n return password === confirmation\n}\n\n// Generate user initials\nexport const getInitials = (firstName?: string, lastName?: string): string => {\n const first = firstName?.charAt(0).toUpperCase() || ''\n const last = lastName?.charAt(0).toUpperCase() || ''\n return first + last || 'U'\n}\n\n// Format date for display\nexport const formatDate = (date: string | Date): string => {\n const d = typeof date === 'string' ? new Date(date) : date\n return d.toLocaleDateString('en-US', {\n year: 'numeric',\n month: 'long',\n day: 'numeric'\n })\n}\n\n// Debounce utility for input validation\nexport const debounce = <T extends (...args: any[]) => any>(\n func: T,\n wait: number\n): ((...args: Parameters<T>) => void) => {\n let timeout: NodeJS.Timeout\n return (...args: Parameters<T>) => {\n clearTimeout(timeout)\n timeout = setTimeout(() => func(...args), wait)\n }\n}\n","/**\n * Lazy loading configuration for heavy components\n */\nimport { defineAsyncComponent } from 'vue'\n\n// Loading component for better UX during component load\nconst LoadingComponent = {\n template: `\n <div class=\"accui-flex accui-items-center accui-justify-center accui-p-4\">\n <div class=\"accui-animate-spin accui-rounded-full accui-h-6 accui-w-6 accui-border-b-2 accui-border-primary-500\"></div>\n </div>\n `\n}\n\n// Error component for failed loads\nconst ErrorComponent = {\n template: `\n <div class=\"accui-flex accui-items-center accui-justify-center accui-p-4 accui-text-red-600\">\n <span class=\"accui-text-sm\">Failed to load component</span>\n </div>\n `\n}\n\n// Lazy loading components have been removed due to static import conflicts\n// All components that were previously lazy-loaded are now directly exported \n// from components/index.ts to avoid TypeScript TS4023 declaration errors\n\n// This file now only contains utility functions for potential future lazy loading\n\n// Pre-load function for components that will likely be used\nexport const preloadComponent = (componentLoader: () => Promise<any>) => {\n // Preload when idle or after user interaction\n if ('requestIdleCallback' in window) {\n requestIdleCallback(() => {\n componentLoader()\n })\n } else {\n // Fallback for browsers without requestIdleCallback\n setTimeout(() => {\n componentLoader()\n }, 100)\n }\n}\n\n// Preload critical components that might be needed soon \nexport const preloadCriticalComponents = () => {\n // All components are now statically imported, so preloading is not needed\n // This function is kept for backwards compatibility\n}"],"names":["props","__props","alertClasses","computed","success","error","warning","info","variant","titleClasses","messageClasses","iconPath","_openBlock","_createElementBlock","_hoisted_1","_createElementVNode","class","value","role","_hoisted_2","_hoisted_3","_hoisted_4","d","_hoisted_6","title","_renderSlot","_ctx","message","dismissible","_hoisted_7","type","onClick","$emit","fill","viewBox","colorMap","red","blue","green","yellow","purple","pink","gray","indigo","orange","teal","cyan","emerald","lime","amber","rose","slate","zinc","neutral","stone","strands","primary","sRGBtoY","r","g","b","y","Math","pow","calcAPCA","txtY","bgY","sapc","getEffectiveRgb","colorProp","baseColorName","includes","split","baseRgb","hex","result","exec","parseInt","hexToRgb","effectiveRgb","shade","isNaN","mixPercent","round","opacity","opacityRatio","whiteRgb","getContrastTextColor","fontWeight","fontSize","bgRgb","blackY","whiteY","blackContrast","abs","whiteContrast","threshold","getAPCAThreshold","getColorValue","color","colorName","baseColor","shadeNum","clampedPercent","min","max","opacityPercent","getLightColor","buttonClasses","size","fullWidth","filter","Boolean","join","buttonStyles","getFontCharacteristics","primaryColor","hoverColor","lightColor","contrastColor","hoverContrastColor","hoverColorForContrast","getHoverContrastColor","lightColorForContrast","lightContrastColor","baseStyles","backgroundColor","boxShadow","border","borderColor","borderWidth","borderStyle","disabled","loading","style","_cache","$event","cx","cy","stroke","loadingText","$slots","padding","shadow","emit","__emit","slots","useSlots","showPassword","ref","inputId","random","toString","substr","computedType","inputClasses","errorClasses","iconPadding","passwordPadding","sm","md","lg","handleInput","event","target","togglePasswordVisibility","label","for","required","_hoisted_5","id","modelValue","placeholder","autocomplete","name","inputmode","maxlength","onInput","onBlur","onFocus","onKeydown","_hoisted_8","_hoisted_9","_hoisted_10","_toDisplayString","helpText","_hoisted_11","tag","to","href","linkProps","baseProps","external","linkStyles","textDecorationColor","handleClick","_createBlock","_resolveDynamicComponent","_mergeProps","tabButtons","underlineStyle","width","left","currentTabIndex","isAnimating","animateUnderlineStretch","async","newIndex","newTab","container","parentElement","newRect","getBoundingClientRect","containerRect","newLeft","newWidth","currentRect","currentLeft","currentWidth","isMovingRight","stretchLeft","stretchWidth","setTimeout","onMounted","nextTick","activeIndex","tabs","findIndex","tab","toRefs","watch","_Fragment","_renderList","index","key","_unref","handleTabClick","path","replace","trim","match","semiColor","solidColor","_normalizeClass","centered","height","weight","transform","text","toggleClasses","thumbClasses","handleToggle","fileInput","canvas","previewCanvas","imageData","originalImage","canvasSize","previewSize","cropRadius","imagePos","reactive","x","zoom","minZoom","maxZoom","isDragging","isResetting","isWheelZooming","dragStart","imageX","imageY","ctx","getContext","fillStyle","fillRect","triggerFileUpload","click","handleFileSelect","file","files","processFile","handleDrop","preventDefault","dataTransfer","startsWith","maxFileSize","reader","FileReader","onload","e","loadImage","readAsDataURL","dataUrl","img","Image","scale","initialZoom","scaledWidth","scaledHeight","constrainImagePosition","updateCanvas","src","drawImage","updatePreview","previewCtx","save","beginPath","arc","PI","clip","cropX","cropY","cropSize","restore","startDrag","clientX","clientY","document","addEventListener","handleDrag","stopDrag","circleLeft","circleTop","maxX","minX","maxY","minY","deltaX","deltaY","removeEventListener","handleWheel","delta","newZoom","canvasCenter","currentHeight","newHeight","currentCenterOffsetX","currentCenterOffsetY","zoomRatio","newCenterOffsetX","newCenterOffsetY","resetImage","targetZoom","cropAndUpload","cropCanvas","createElement","cropCtx","toBlob","blob","File","changePhoto","oldZoom","oldWidth","oldHeight","preselectedFile","immediate","accept","onChange","onMousedown","onWheel","mask","_hoisted_14","_hoisted_16","_hoisted_17","step","number","_hoisted_19","uploading","_hoisted_20","_hoisted_21","_hoisted_22","onDrop","onDragover","onDragenter","SoundEffects","static","getAudioContext","this","audioContext","window","AudioContext","webkitAudioContext","state","resume","playLevelUp","level","userSettings","isMilestone","milestoneSounds","levelUpSounds","playMilestoneLevelUp","playRegularLevelUp","duration","now","currentTime","forEach","freq","oscillator","createOscillator","gainNode","createGain","connect","destination","frequency","setValueAtTime","exponentialRampToValueAtTime","delay","gain","linearRampToValueAtTime","start","stop","bellOscillator","bellGain","time","frequencies","chord","chordIndex","noteIndex","noteDelay","i","sparkleTime","sparkleOsc","sparkleGain","sparkleFreq","finaleTime","playSuccess","playError","playClick","playNotification","playXpGain","VIEW_BOX_SIZE","levelUpActive","animatedValue","animationDirection","animationFrame","prevValue","prevLevel","center","thickness","labelThickness","gapAngle","radius","labelRadius","textLabelRadius","innerCircleRadius","labelLength","levelLabel","length","staticArcAngle","labelStart","labelEnd","staticArcPath","describeArc","labelTextArcPath","progressArcPath","xpArcStart","xpArcEnd","backgroundArcPath","availableSweep","progress","grayArcStart","grayArcEnd","staticArcGradient","progressArcGradient","progressGradientStart","polarToCartesian","progressGradientEnd","angle","rad","cos","sin","startAngle","endAngle","end","largeArcFlag","triggerLevelUp","newValue","oldValue","change","startTime","performance","requestAnimationFrame","elapsed","t","eased","easeInOut","animateProgress","newLevel","position","x1","y1","x2","y2","offset","gradientUnits","handleOverlayClick","closeOnOverlayClick","_Teleport","open","fullscreenOnMobile","config","useStrandsConfig","shouldShowSecuredBy","baseUrl","hasDefaultSlot","slotName","slot","vnodes","Array","isArray","slotHasContent","mfaDevices","mfaEnabled","useStrandsMfa","getUrl","currentSession","useStrandsAuth","hasMfaDevices","activeMfaDevices","is_active","device_type","makeAuthenticatedRequest","url","options","accessToken","Error","response","fetch","headers","Authorization","ok","errorText","errorMessage","status","statusText","JSON","parse","json","fetchMfaDevices","method","devices","mfa_enabled","setupTotp","deviceName","body","stringify","device_name","verifyTotpSetup","deviceId","totpCode","device_id","totp_code","setupEmailMfa","sendEmailMfaCode","verifyEmailMfaCode","code","verified","disableMfaDevice","regenerateBackupCodes","getDeviceTypeIcon","deviceType","getDeviceTypeName","formatLastUsed","lastUsedAt","date","Date","diffMs","getTime","diffDays","floor","toLocaleDateString","IconSmartphone","render","h","rx","ry","IconMail","IconKeyRound","IconShield","IconCheckCircle","points","IconAlertTriangle","mfaLoading","verifyMfa","sendMfaEmailCode","getMfaWebAuthnChallenge","mfaSessionId","authMfaSessionId","authLoading","loadingMessage","authLoadingMessage","isSendingMfaEmail","isVerifyingMfa","selectedMethod","verificationCode","verificationError","backupCode","backupCodeError","showBackupCodeInput","emailCodeSent","cooldownActive","cooldownSeconds","cooldownInterval","availableMethods","availableMfaMethods","methods","show","newShow","clearInterval","startCooldown","onBeforeUnmount","closeModal","onCodeInput","slice","onCodePaste","cleanedData","clipboardData","getData","onBackupCodeInput","cleaned","toLowerCase","test","part1","substring","part2","onBackupCodePaste","sendEmailCode","setInterval","verify","verifyBackupCode","getDeviceIconComponent","authenticateHardwareKey","sessionId","navigator","credentials","PublicKeyCredential","challengeResponse","challengeData","challenge","publicKey","base64ToUint8Array","base64","Uint8Array","b64","repeat","rawData","atob","outputArray","charCodeAt","isPasskey","publicKeyCredentialRequestOptions","timeout","userVerification","allowCredentials","map","cred","credential","get","authenticatorData","deviceInfo","aaguidHex","from","padStart","ee882879721c491397753dfcce97072a","f8a011f38c0a4d15800617111f9edc7d","c5ef55ffad9a4b9fb580adcb7c15e233","de1e552d14e14b1f9390f6d61b56e4d1","credentialData","rawId","clientDataJSON","signature","userHandle","_createVNode","UiModal","header","footer","_hoisted_36","StrandsUiButton","StrandsUiLoader","selectMethod","_hoisted_12","_hoisted_13","_hoisted_15","_hoisted_18","_hoisted_23","_hoisted_24","_createTextVNode","_hoisted_25","_hoisted_26","_hoisted_27","StrandsUiInput","onPaste","spellcheck","onSubmit","novalidate","_hoisted_28","_hoisted_29","autofocus","tabindex","pattern","minlength","_hoisted_30","_hoisted_31","_hoisted_32","_hoisted_33","_hoisted_34","_hoisted_35","useOAuthProviders","providers","enabledProviders","provider","enabled","fetchProviders","redirectUrl","oauth2RedirectUrl","params","URLSearchParams","absoluteRedirectUrl","location","origin","append","errorData","catch","err","getProviderAuthUrl","providerId","customOptions","mergedOptions","scopes","queryString","providerUrl","fullUrl","data","authUrl","redirectToProvider","find","p","auth_url","getProviderById","getProviderIcon","iconUrl","getSupportEmail","signIn","setAuthData","mfaRequired","currentUser","oauthLoading","oauthError","displayProviders","authApi","email","password","signUp","firstName","lastName","requestPasswordReset","currentMode","mode","buttonLoading","isPasswordResetSubmitted","showMfaVerification","form","confirmPassword","isSignUp","isPasswordReset","isFormValid","handleMfaSuccess","handleMfaClose","handleMfaError","handleAuth","user","mfa_required","newMode","transitionCounter","onBeforeEnter","el","element","marginTop","marginBottom","paddingTop","paddingBottom","overflow","onEnter","done","currentIndex","offsetHeight","transition","onBeforeLeave","onLeave","margin","onAfterLeave","inModal","_Transition","StrandsUiTabs","handleOAuthAuth","icon","alt","displayName","charAt","toUpperCase","StrandsUiLink","StrandsUiAlert","onDismiss","StrandsSecuredFooter","StrandsMfaVerification","onSuccess","onClose","onError","oauthScopes","handleSignIn","authData","StrandsUiCard","__","___","_cached","_isMemoSame","_memo","handleOAuthSignIn","IconGoogle","IconGithub","signupSuccess","successMessage","successTitle","successEmail","handleSignUp","signUpUrl","process","env","supportEmail","resetToForm","handleOAuthSignUp","registrationComplete","invalidToken","fieldErrors","hasRequiredFields","passwordMinLength","hasValidToken","token","parts","payload","redirectToReferrer","handleCompleteSignUp","Object","keys","first_name","last_name","access_token","refresh_token","deviceNameError","totpSetupData","qrCodeDataUrl","newData","qr_code_url","qrUrl","encodeURIComponent","startSetup","onVerificationCodeInput","verifySetup","copyBackupCodes","backup_codes","codesText","clipboard","writeText","finish","secret","emailMfaDeviceId","resendCode","registerHardwareKey","completeHardwareKeyRegistration","internalLoading","registrationMessage","backupCodes","getOptimalAuthenticatorSelection","authenticatorAttachment","requireResidentKey","residentKey","handleRegisterHardwareKey","isUserVerifyingPlatformAuthenticatorAvailable","isConditionalMediationAvailable","checkError","processedChallenge","safeBufferConvert","buffer","binary","bytes","crypto","getRandomValues","cleanChallenge","rp","pubKeyCredParams","alg","authenticatorSelection","attestation","excludeCredentials","createOptimizedWebAuthnChallenge","create","attestationObject","rawIdArray","ArrayBuffer","clientDataArray","attestationArray","credentialPayload","credError","String","userErrorMessage","errorMsg","showRegenerateWarning","device","regenerateCodes","confirmRegenerate","downloadBackupCodes","filename","toISOString","content","toLocaleString","Blob","URL","createObjectURL","link","download","appendChild","removeChild","revokeObjectURL","handleConfirm","handleCancel","cancelText","confirmText","Smartphone","Number","default","Mail","KeyRound","Shield","Trash2","showModal","activeTab","showTotpSetup","showEmailMfaSetup","showHardwareKeySetup","showPasskeySetup","showBackupCodesModal","showConfirmDisable","selectedDevice","startTotpSetup","startEmailMfaSetup","handleDisableDevice","handleTotpSetupSuccess","handleEmailMfaSetupSuccess","handleHardwareKeySetupSuccess","handlePasskeySetupSuccess","getDeviceIconBackground","last_used_at","showBackupCodes","testEmailMfa","confirmDisableDevice","StrandsTotpSetupModal","StrandsEmailMfaSetupModal","StrandsHardwareKeySetupModal","StrandsBackupCodesModal","StrandsConfirmModal","onConfirm","onCancel","updateUserSettings","saving","localSettings","settings","newSettings","deep","updateSetting","saveSettings","UiButton","UiToggle","Monitor","Tablet","MapPin","Globe","Clock","Calendar","getUserSessions","getSessionStats","revokeSession","revokeAllOtherSessions","signOut","visible","sessions","stats","revokingSession","revokingAll","newVal","loadSessions","sessionsData","statsData","Promise","all","handleClose","handleRevokeAllOther","confirm","alert","getDeviceIcon","formatTimeAgo","then","seconds","StrandsUiModal","total_sessions","active_sessions","unique_locations","session","is_current","handleRevokeCurrentSession","handleRevokeSession","city","country","ip_address","last_activity_at","created_at","month","day","year","hour","minute","_hoisted_37","fetchProfile","updateProfile","changeEmail","changeUsername","getUsernameCooldown","checkUsernameAvailability","authUser","isAuthenticated","refreshToken","internalUser","fetchingProfile","signingOut","showPasswordChange","showEmailChange","emailChangeLoading","showUsernameChange","usernameChangeLoading","showMfaModal","showSettingsModal","showAvatarEditor","selectedImageFile","activeSessions","loadingSessions","showSessionsModal","usernameChangeData","canChange","cooldownEnd","daysRemaining","usernameAvailability","available","checking","avatarFileInput","emailChangeForm","newEmail","errors","passwordForm","current","new","usernameForm","username","hasChanges","isPasswordFormValid","isEmailChangeFormValid","isUsernameChangeFormValid","passwordLastUpdated","updateDate","passwordUpdatedAt","createdAt","months","years","deviceTypeCounts","counts","totp","hardware","passkey","mfaDeviceChips","chips","push","count","totalHardware","getXpForLevel","totalXp","userLevel","getLevelFromXp","xp","currentExp","xpForCurrentLevel","expToNextLevel","progressPercentage","totalCircumference","progressLength","smallGap","loadUserSessions","authenticated","wasAuthenticated","autoFetch","fetchUserProfile","clearMessages","handleUpdateProfile","updatedUser","handlePasswordChange","resolve","handleEmailChange","handleToggleUsernameChange","cooldownData","can_change","cooldown_end","days_remaining","handleUsernameChange","triggerAvatarUpload","handleAvatarFileSelect","handleAvatarUpload","uploadAvatar","handleAvatarError","handleAvatarEditorClose","formData","FormData","retryResponse","retryResult","avatar","avatar_url","localStorage","setItem","refreshError","handleMfaUpdated","handleSettingsUpdated","handleSessionsUpdated","handleSignOut","StrandsUiLevelProgress","next_level_xp","chip","_hoisted_38","_hoisted_39","_hoisted_40","_hoisted_41","_hoisted_42","_hoisted_43","_hoisted_44","_hoisted_45","_hoisted_46","_hoisted_47","StrandsMfaModal","onMfaUpdated","StrandsSettingsModal","onSettingsUpdated","StrandsSessionsModal","onSessionsUpdated","_hoisted_48","_hoisted_49","_hoisted_50","StrandsUiAvatarEditor","onUpload","isSubmitted","handlePasswordReset","invert","signedInOrInverted","showLoading","signedOutOrInverted","showFallback","isComponentReady","isInitializing","isSigningIn","isLoading","args","xmlns","provideStrandsConfig","sizeClasses","xs","xl","iconClass","icons","eye","camera","lock","google","github","iconComponent","ariaHidden","showDropdown","showProfileModal","showSignInModal","containerRef","profileButtonRef","toggleDropdown","focus","openDropdown","closeDropdown","focusNext","focusPrevious","focusFirst","focusLast","openProfile","closeProfile","handleProfileUpdated","handleProfileError","openSignIn","closeSignIn","handleSignedIn","handleSignInError","handleClickOutside","contains","onUnmounted","SignedIn","fallback","StrandsAuth","onSignedIn","hideUser","menuAlign","menuVerticalAlign","StrandsUserProfile","onProfileUpdated","scrollContainer","scrollTop","visibleRange","itemHeight","ceil","containerHeight","items","overscan","visibleItems","top","totalHeight","getItemKey","item","itemKey","scrollTimer","handleScroll","clearTimeout","__expose","scrollToItem","align","scrollTo","overflowY","onScroll","_normalizeStyle","Settings","openMfaModal","handleSetupSuccess","components","StrandsUIPlugin","install","app","prefix","entries","component","componentName","useAuthenticatedFetch","getAuthHeaders","authenticatedFetch","autoRefresh","requireAuth","baseURL","fetchOptions","Headers","authHeaders","set","enhancedOptions","newAuthHeaders","post","has","put","delete","patch","$authFetch","del","func","wait","confirmation","score","strength","isValid"],"mappings":"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"}
1
+ {"version":3,"file":"strands-auth-ui.cjs.js","sources":["../../../apps/accounts-ui/src/vue/ui/UiAlert.vue","../../../apps/accounts-ui/src/vue/utils/contrast.ts","../../../apps/accounts-ui/src/vue/ui/UiButton.vue","../../../apps/accounts-ui/src/vue/ui/UiCard.vue","../../../apps/accounts-ui/src/vue/ui/UiInput.vue","../../../apps/accounts-ui/src/vue/ui/UiLink.vue","../../../apps/accounts-ui/src/vue/ui/UiTabs.vue","../../../apps/accounts-ui/src/vue/ui/UiLoader.vue","../../../apps/accounts-ui/assets/strands_icon_path.svg?raw","../../../apps/accounts-ui/src/vue/ui/UiToggle.vue","../../../apps/accounts-ui/src/vue/ui/UiAvatarEditor.vue","../../../apps/accounts-ui/src/vue/utils/sounds.ts","../../../apps/accounts-ui/src/vue/ui/UiLevelProgress.vue","../../../apps/accounts-ui/src/vue/ui/UiModal.vue","../../../apps/accounts-ui/src/vue/components/StrandsSecuredFooter.vue","../../../apps/accounts-ui/src/utils/slots.ts","../../../apps/accounts-ui/src/assets/secured_by_strands_services.png","../../../apps/accounts-ui/src/vue/composables/useStrandsMfa.ts","../../../apps/accounts-ui/src/vue/components/StrandsMfaVerification.vue","../../../apps/accounts-ui/src/vue/composables/useOAuthProviders.ts","../../../apps/accounts-ui/src/vue/components/StrandsAuth.vue","../../../apps/accounts-ui/src/vue/components/icons/IconGoogle.vue","../../../apps/accounts-ui/src/vue/components/icons/IconGithub.vue","../../../apps/accounts-ui/src/vue/components/StrandsSignIn.vue","../../../apps/accounts-ui/src/vue/components/StrandsSignUp.vue","../../../apps/accounts-ui/src/vue/components/StrandsCompleteSignUp.vue","../../../apps/accounts-ui/src/vue/components/StrandsTotpSetupModal.vue","../../../apps/accounts-ui/src/vue/components/StrandsEmailMfaSetupModal.vue","../../../apps/accounts-ui/src/vue/components/StrandsHardwareKeySetupModal.vue","../../../apps/accounts-ui/src/vue/components/StrandsBackupCodesModal.vue","../../../apps/accounts-ui/src/vue/components/StrandsConfirmModal.vue","../../../apps/accounts-ui/src/vue/components/StrandsMfaModal.vue","../../../apps/accounts-ui/src/vue/components/StrandsSettingsModal.vue","../../../apps/accounts-ui/src/vue/components/StrandsSessionsModal.vue","../../../apps/accounts-ui/src/vue/components/StrandsUserProfile.vue","../../../apps/accounts-ui/src/vue/components/StrandsPasswordReset.vue","../../../apps/accounts-ui/src/vue/components/SignedIn.vue","../../../apps/accounts-ui/src/vue/components/SignedOut.vue","../../../apps/accounts-ui/src/vue/components/StrandsLogo.vue","../../../apps/accounts-ui/src/vue/components/StrandsConfigProvider.vue","../../../apps/accounts-ui/src/vue/components/SvgIcon.vue","../../../apps/accounts-ui/src/vue/components/StrandsUserButton.vue","../../../apps/accounts-ui/src/vue/components/VirtualList.vue","../../../apps/accounts-ui/src/vue/components/StrandsMFASetup.vue","../../../apps/accounts-ui/src/vue/plugins/StrandsUIPlugin.ts","../../../apps/accounts-ui/src/vue/composables/useAuthenticatedFetch.ts","../../../apps/accounts-ui/src/utils/validation.ts","../../../apps/accounts-ui/src/vue/utils/lazyComponents.ts"],"sourcesContent":["<template>\n <div class=\"accui-component-scope\">\n <div :class=\"alertClasses\" role=\"alert\">\n <div class=\"alert-content\">\n <div class=\"alert-icon-container\">\n <svg class=\"alert-main-icon\" fill=\"currentColor\" viewBox=\"0 0 20 20\" aria-hidden=\"true\">\n <path fill-rule=\"evenodd\" :d=\"iconPath\" clip-rule=\"evenodd\" />\n </svg>\n </div>\n\n <div class=\"alert-text-container\">\n <h3 v-if=\"title\" :class=\"titleClasses\">{{ title }}</h3>\n <div :class=\"messageClasses\">\n <slot>{{ message }}</slot>\n </div>\n </div>\n\n <div v-if=\"dismissible\" class=\"alert-dismiss-container\">\n <button type=\"button\" class=\"alert-dismiss-button\" @click=\"$emit('dismiss')\">\n <span class=\"sr-only\">Dismiss</span>\n <svg class=\"alert-dismiss-icon\" fill=\"currentColor\" viewBox=\"0 0 20 20\">\n <path fill-rule=\"evenodd\"\n d=\"M4.293 4.293a1 1 0 011.414 0L10 8.586l4.293-4.293a1 1 0 111.414 1.414L11.414 10l4.293 4.293a1 1 0 01-1.414 1.414L10 11.414l-4.293 4.293a1 1 0 01-1.414-1.414L8.586 10 4.293 5.707a1 1 0 010-1.414z\"\n clip-rule=\"evenodd\" />\n </svg>\n </button>\n </div>\n </div>\n </div>\n </div>\n</template>\n\n<script setup lang=\"ts\">\nimport { computed } from 'vue'\n\ninterface Props {\n variant?: 'success' | 'error' | 'warning' | 'info'\n title?: string\n message?: string\n dismissible?: boolean\n}\n\nconst props = withDefaults(defineProps<Props>(), {\n variant: 'info',\n dismissible: false\n})\n\ndefineEmits<{\n dismiss: []\n}>()\n\nconst alertClasses = computed(() => {\n const variantClasses = {\n success: 'alert alert-success',\n error: 'alert alert-error',\n warning: 'alert alert-warning',\n info: 'alert alert-info'\n }\n\n return variantClasses[props.variant]\n})\n\nconst titleClasses = computed(() => {\n return 'alert-title'\n})\n\nconst messageClasses = computed(() => {\n return 'alert-message'\n})\n\n\nconst iconPath = computed(() => {\n const icons = {\n success: '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 error: 'M10 18a8 8 0 100-16 8 8 0 000 16zM8.707 7.293a1 1 0 00-1.414 1.414L8.586 10l-1.293 1.293a1 1 0 101.414 1.414L10 11.414l1.293 1.293a1 1 0 001.414-1.414L11.414 10l1.293-1.293a1 1 0 00-1.414-1.414L10 8.586 8.707 7.293z',\n warning: '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 info: 'M18 10a8 8 0 11-16 0 8 8 0 0116 0zm-7-4a1 1 0 11-2 0 1 1 0 012 0zM9 9a1 1 0 000 2v3a1 1 0 001 1h1a1 1 0 100-2v-3a1 1 0 00-1-1H9z'\n }\n\n return icons[props.variant]\n})\n</script>\n\n<style scoped>\n/* Base Alert Container */\n.alert {\n position: relative;\n padding: 1rem;\n border-radius: 0.5rem;\n border: 1px solid;\n font-family: var(--font-sans);\n box-shadow: 0 1px 3px 0 rgb(0 0 0 / 0.05);\n transition: all 0.15s ease;\n animation: alertSlideIn 0.2s ease-out;\n}\n\n.alert:hover {\n box-shadow: 0 1px 3px 0 rgb(0 0 0 / 0.08);\n}\n\n/* Alert Animation */\n@keyframes alertSlideIn {\n from {\n opacity: 0;\n transform: translateY(-4px);\n }\n to {\n opacity: 1;\n transform: translateY(0);\n }\n}\n\n/* Alert base layout styles */\n.alert-content {\n display: flex;\n align-items: flex-start;\n gap: 0.75rem;\n}\n\n.alert-icon-container {\n flex-shrink: 0;\n margin-top: 0.125rem;\n}\n\n.alert-text-container {\n flex: 1;\n min-width: 0; /* Ensure text can wrap */\n}\n\n/* Alert main icon */\n.alert-main-icon {\n width: 1.25rem;\n height: 1.25rem;\n flex-shrink: 0;\n}\n\n/* Alert typography */\n.alert-title {\n font-size: 0.875rem;\n font-weight: 600;\n margin: 0 0 0.25rem 0;\n line-height: 1.4;\n}\n\n.alert-message {\n font-size: 0.875rem;\n line-height: 1.5;\n margin: 0;\n}\n\n/* Dismiss container */\n.alert-dismiss-container {\n margin-left: auto;\n padding-left: 0.75rem;\n flex-shrink: 0;\n}\n\n/* Dismiss button */\n.alert-dismiss-button {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n border-radius: 0.375rem;\n width: 1.75rem;\n height: 1.75rem;\n background: none;\n border: none;\n cursor: pointer;\n opacity: 0.6;\n transition: all 0.15s ease;\n}\n\n.alert-dismiss-button:hover {\n opacity: 1;\n background: rgba(0, 0, 0, 0.05);\n}\n\n.alert-dismiss-button:focus-visible {\n outline: 2px solid var(--strands-500);\n outline-offset: 2px;\n opacity: 1;\n}\n\n/* Alert dismiss icon */\n.alert-dismiss-icon {\n width: 1rem;\n height: 1rem;\n flex-shrink: 0;\n}\n\n/* SUCCESS VARIANT */\n.alert-success {\n background: #f0fdf4;\n border-color: #bbf7d0;\n color: #166534;\n}\n\n.alert-success .alert-main-icon {\n color: #16a34a;\n}\n\n/* ERROR VARIANT */\n.alert-error {\n background: #fef2f2;\n border-color: #fecaca;\n color: #991b1b;\n}\n\n.alert-error .alert-main-icon {\n color: #dc2626;\n}\n\n/* WARNING VARIANT */\n.alert-warning {\n background: #fefce8;\n border-color: #fde68a;\n color: #92400e;\n}\n\n.alert-warning .alert-main-icon {\n color: #d97706;\n}\n\n/* INFO VARIANT */\n.alert-info {\n background: #eff6ff;\n border-color: #bfdbfe;\n color: #1e40af;\n}\n\n.alert-info .alert-main-icon {\n color: #2563eb;\n}\n\n/* Accessibility enhancements */\n@media (prefers-reduced-motion: reduce) {\n .alert {\n animation: none;\n transition: none;\n }\n}\n\n/* Screen reader only text */\n.sr-only {\n position: absolute;\n width: 1px;\n height: 1px;\n padding: 0;\n margin: -1px;\n overflow: hidden;\n clip: rect(0, 0, 0, 0);\n white-space: nowrap;\n border: 0;\n}\n</style>\n","/**\n * WCAG 3.0 APCA-based contrast calculation utilities\n * Provides perceptually accurate text contrast determination for accessibility\n */\n\n// APCA constants (WCAG 3.0)\nconst mainTRC = 2.4 // 2.4 exponent emulates actual monitor perception\nconst sRco = 0.2126729, sGco = 0.7151522, sBco = 0.0721750 // sRGB coefficients\nconst normBG = 0.56, normTXT = 0.57, revTXT = 0.62, revBG = 0.65 // G-4g constants\nconst blkThrs = 0.022, blkClmp = 1.414, scaleBoW = 1.14, scaleWoB = 1.14\n\n// Color map for base colors\nconst colorMap: Record<string, string> = {\n 'red': '#ef4444', 'blue': '#3b82f6', 'green': '#10b981', 'yellow': '#eab308',\n 'purple': '#8b5cf6', 'pink': '#ec4899', 'gray': '#6b7280', 'indigo': '#6366f1',\n 'orange': '#f97316', 'teal': '#14b8a6', 'cyan': '#06b6d4', 'emerald': '#10b981',\n 'lime': '#84cc16', 'amber': '#f59e0b', 'rose': '#f43f5e', 'slate': '#64748b',\n 'zinc': '#71717a', 'neutral': '#737373', 'stone': '#78716c', 'strands': '#EA00A8',\n 'primary': '#EA00A8'\n}\n\n/**\n * Convert hex color to RGB values\n */\nexport const hexToRgb = (hex: string): { r: number; g: number; b: number } | null => {\n const result = /^#?([a-f\\d]{2})([a-f\\d]{2})([a-f\\d]{2})$/i.exec(hex)\n return result ? {\n r: parseInt(result[1], 16),\n g: parseInt(result[2], 16),\n b: parseInt(result[3], 16)\n } : null\n}\n\n/**\n * APCA sRGB to Y (luminance) conversion - WCAG 3.0 method\n */\nexport const sRGBtoY = (r: number, g: number, b: number): number => {\n // Normalize to 0-1 and apply 2.4 gamma (APCA method)\n const rLin = Math.pow(r / 255, mainTRC)\n const gLin = Math.pow(g / 255, mainTRC)\n const bLin = Math.pow(b / 255, mainTRC)\n \n // Calculate Y using APCA coefficients\n let y = sRco * rLin + sGco * gLin + sBco * bLin\n \n // APCA black level adjustment\n if (y < blkThrs) {\n y += Math.pow(blkThrs - y, blkClmp)\n }\n \n return y\n}\n\n/**\n * APCA contrast calculation\n * Returns contrast value between -108 and 105\n */\nexport const calcAPCA = (txtY: number, bgY: number): number => {\n let sapc = 0\n\n // Determine polarity and calculate contrast\n if (bgY > txtY) {\n // White text on dark background\n sapc = (Math.pow(bgY, normBG) - Math.pow(txtY, normTXT)) * scaleWoB\n return (sapc * 100) < 15 ? 0 : (sapc * 100) - 15\n } else {\n // Dark text on light background \n sapc = (Math.pow(bgY, revBG) - Math.pow(txtY, revTXT)) * scaleBoW\n return (sapc * 100) > -15 ? 0 : (sapc * 100) + 15\n }\n}\n\n/**\n * Get effective RGB color considering shades and opacity modifications\n */\nexport const getEffectiveRgb = (colorProp: string): { r: number; g: number; b: number } => {\n const baseColorName = colorProp.includes('-') ? colorProp.split('-')[0] : \n colorProp.includes('/') ? colorProp.split('/')[0] : colorProp\n \n const baseColorHex = colorMap[baseColorName] || '#6b7280'\n const baseRgb = hexToRgb(baseColorHex) || { r: 107, g: 114, b: 128 }\n \n let effectiveRgb = { ...baseRgb }\n \n // Handle shade modifications\n if (colorProp.includes('-')) {\n const shade = parseInt(colorProp.split('-')[1], 10)\n if (!isNaN(shade) && shade !== 500) {\n if (shade < 500) {\n // Lighter shades - mix with white (gentle progression)\n const mixPercent = ((500 - shade) / 400) * 0.45\n effectiveRgb.r = Math.round(baseRgb.r + (255 - baseRgb.r) * mixPercent)\n effectiveRgb.g = Math.round(baseRgb.g + (255 - baseRgb.g) * mixPercent)\n effectiveRgb.b = Math.round(baseRgb.b + (255 - baseRgb.b) * mixPercent)\n } else {\n // Darker shades - mix with black (gentle progression)\n const mixPercent = ((shade - 500) / 450) * 0.45\n effectiveRgb.r = Math.round(baseRgb.r * (1 - mixPercent))\n effectiveRgb.g = Math.round(baseRgb.g * (1 - mixPercent))\n effectiveRgb.b = Math.round(baseRgb.b * (1 - mixPercent))\n }\n }\n }\n \n // Handle opacity modifications\n if (colorProp.includes('/')) {\n const opacity = parseInt(colorProp.split('/')[1], 10)\n if (!isNaN(opacity)) {\n const opacityRatio = opacity / 100\n const whiteRgb = { r: 255, g: 255, b: 255 }\n effectiveRgb.r = Math.round(effectiveRgb.r * opacityRatio + whiteRgb.r * (1 - opacityRatio))\n effectiveRgb.g = Math.round(effectiveRgb.g * opacityRatio + whiteRgb.g * (1 - opacityRatio))\n effectiveRgb.b = Math.round(effectiveRgb.b * opacityRatio + whiteRgb.b * (1 - opacityRatio))\n }\n }\n \n return effectiveRgb\n}\n\n/**\n * Calculate APCA contrast score between two colors\n * @param textColor RGB object or hex string for text color\n * @param backgroundColor RGB object or hex string for background color\n * @returns APCA contrast score (-108 to 105)\n */\nexport const getAPCAContrast = (\n textColor: { r: number; g: number; b: number } | string,\n backgroundColor: { r: number; g: number; b: number } | string\n): number => {\n const textRgb = typeof textColor === 'string' ? hexToRgb(textColor) : textColor\n const bgRgb = typeof backgroundColor === 'string' ? hexToRgb(backgroundColor) : backgroundColor\n \n if (!textRgb || !bgRgb) return 0\n \n const textY = sRGBtoY(textRgb.r, textRgb.g, textRgb.b)\n const bgY = sRGBtoY(bgRgb.r, bgRgb.g, bgRgb.b)\n \n return calcAPCA(textY, bgY)\n}\n\n/**\n * Get APCA contrast threshold based on font weight and size\n * WCAG 3.0 APCA thresholds vary based on font characteristics\n */\nexport const getAPCAThreshold = (fontWeight: number = 400, fontSize: number = 16): number => {\n // WCAG 3.0 APCA thresholds based on font weight and size\n // Higher font weights require less contrast\n \n if (fontWeight >= 700) {\n // Bold text (700+)\n if (fontSize >= 24) return 30 // Large bold text\n if (fontSize >= 18) return 35 // Medium bold text \n return 40 // Regular bold text\n } else if (fontWeight >= 600) {\n // Semi-bold text (600-699)\n if (fontSize >= 24) return 35 // Large semi-bold text\n if (fontSize >= 18) return 40 // Medium semi-bold text\n return 45 // Regular semi-bold text\n } else if (fontWeight >= 500) {\n // Medium text (500-599) - typical for buttons\n if (fontSize >= 24) return 40 // Large medium text\n if (fontSize >= 18) return 45 // Medium medium text\n return 50 // Regular medium text (buttons)\n } else {\n // Normal text (400 and below)\n if (fontSize >= 24) return 45 // Large normal text\n if (fontSize >= 18) return 50 // Medium normal text\n return 60 // Regular normal text\n }\n}\n\n/**\n * Determine optimal text color (black or white) for a given background\n * Uses WCAG 3.0 APCA algorithm for accurate contrast assessment\n * @param colorProp Color property string (e.g., 'red-500', 'blue/50')\n * @param fontWeight Font weight (300-900, default 400)\n * @param fontSize Font size in pixels (default 16)\n * @returns '#000000' for black text or '#ffffff' for white text\n */\nexport const getContrastTextColor = (\n colorProp: string, \n fontWeight: number = 400, \n fontSize: number = 16\n): string => {\n // Get background color RGB\n const bgRgb = getEffectiveRgb(colorProp)\n const bgY = sRGBtoY(bgRgb.r, bgRgb.g, bgRgb.b)\n \n // Test black text (0,0,0) and white text (255,255,255)\n const blackY = sRGBtoY(0, 0, 0)\n const whiteY = sRGBtoY(255, 255, 255)\n \n const blackContrast = Math.abs(calcAPCA(blackY, bgY))\n const whiteContrast = Math.abs(calcAPCA(whiteY, bgY))\n \n // Get appropriate threshold based on font characteristics\n const threshold = getAPCAThreshold(fontWeight, fontSize)\n \n // Choose text color based on which provides better contrast\n if (blackContrast >= threshold && whiteContrast >= threshold) {\n // Both work, choose the one with higher contrast\n return blackContrast > whiteContrast ? '#000000' : '#ffffff'\n } else if (blackContrast >= threshold) {\n return '#000000'\n } else if (whiteContrast >= threshold) {\n return '#ffffff'\n } else {\n // Neither meets ideal threshold, choose the better one\n return blackContrast > whiteContrast ? '#000000' : '#ffffff'\n }\n}\n\n/**\n * Check if a color combination meets WCAG 3.0 APCA standards\n * @param textColor Text color (RGB object or hex string)\n * @param backgroundColor Background color (RGB object or hex string)\n * @param fontWeight Font weight (300-900, default 400)\n * @param fontSize Font size in pixels (default 16)\n * @returns boolean indicating if contrast is sufficient\n */\nexport const meetsAPCAStandard = (\n textColor: { r: number; g: number; b: number } | string,\n backgroundColor: { r: number; g: number; b: number } | string,\n fontWeight: number = 400,\n fontSize: number = 16\n): boolean => {\n const contrast = Math.abs(getAPCAContrast(textColor, backgroundColor))\n const threshold = getAPCAThreshold(fontWeight, fontSize)\n \n return contrast >= threshold\n}\n\n/**\n * Generate color value from color prop (for CSS generation)\n */\nexport const getColorValue = (color: string): string => {\n // Handle color with shade (e.g., 'red-600')\n if (color.includes('-')) {\n const [colorName, shade] = color.split('-')\n const baseColor = colorMap[colorName]\n if (baseColor && shade) {\n const shadeNum = parseInt(shade, 10)\n \n // Generate proper shade variations with fallbacks\n if (shadeNum === 500) {\n return baseColor // Base color\n }\n \n // Use CSS color-mix for better browser support with fallbacks\n if (shadeNum < 500) {\n // Lighter shades - mix with white (gentle progression)\n const mixPercent = Math.round(((500 - shadeNum) / 400) * 45) // Gentler progression\n const clampedPercent = Math.min(Math.max(mixPercent, 3), 45) // Reduced extremes\n return `color-mix(in srgb, ${baseColor} ${100 - clampedPercent}%, white ${clampedPercent}%)`\n } else {\n // Darker shades - mix with black (gentle progression)\n const mixPercent = Math.round(((shadeNum - 500) / 450) * 45) // Gentler progression\n const clampedPercent = Math.min(Math.max(mixPercent, 3), 45) // Reduced extremes\n return `color-mix(in srgb, ${baseColor} ${100 - clampedPercent}%, black ${clampedPercent}%)`\n }\n }\n }\n \n // Handle color with opacity (e.g., 'red/50')\n if (color.includes('/')) {\n const [colorName, opacity] = color.split('/')\n const baseColor = colorMap[colorName] || colorName\n const opacityPercent = parseInt(opacity, 10)\n // Provide fallback for browsers without relative color support\n const fallbackColor = colorMap[colorName] || colorName\n return `light-dark(hsl(from ${baseColor} h s l / ${opacityPercent}%), color-mix(in srgb, ${fallbackColor} ${opacityPercent}%, transparent))`\n }\n \n // Return base color or fallback to CSS custom property\n return colorMap[color] || `var(--color-${color}, ${color})`\n}","<template>\n <button \n :type=\"type\" \n :disabled=\"disabled || loading\" \n :class=\"buttonClasses\" \n :style=\"buttonStyles\"\n @click=\"$emit('click', $event)\"\n >\n <span v-if=\"loading\" class=\"button-loading-content\">\n <svg class=\"button-loading-icon\" fill=\"none\" viewBox=\"0 0 24 24\">\n <circle class=\"button-loading-track\" cx=\"12\" cy=\"12\" r=\"10\" stroke=\"currentColor\" stroke-width=\"4\" />\n <path class=\"button-loading-spinner\" fill=\"currentColor\"\n d=\"m4 12a8 8 0 0 1 8-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 0 1 4 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z\" />\n </svg>\n <span>{{ loadingText || 'Loading...' }}</span>\n </span>\n <span v-else class=\"button-content\">\n <slot name=\"icon\" />\n <slot />\n </span>\n </button>\n</template>\n\n<script setup lang=\"ts\">\nimport { computed } from 'vue'\nimport { getContrastTextColor, getColorValue } from '../utils/contrast'\n\ninterface Props {\n variant?: 'primary' | 'secondary' | 'ghost' | 'outline'\n size?: 'sm' | 'md' | 'lg'\n type?: 'button' | 'submit' | 'reset'\n disabled?: boolean\n loading?: boolean\n loadingText?: string\n fullWidth?: boolean\n /** \n * Color prop supports multiple formats:\n * - Base colors: 'red', 'blue', 'green', 'strands', etc.\n * - Shades: 'red-600', 'blue-500', etc. (100-950)\n * - Opacity: 'red/50', 'blue/80', etc. (0-100)\n * Uses CSS relative color syntax for dynamic shading and opacity\n */\n color?: string\n /**\n * Font weight for the button text\n * Affects WCAG 3.0 APCA contrast calculation thresholds\n * Higher weights require less contrast\n */\n fontWeight?: 400 | 500 | 600 | 700\n}\n\nconst props = withDefaults(defineProps<Props>(), {\n variant: 'primary',\n size: 'md',\n type: 'button',\n disabled: false,\n loading: false,\n fullWidth: false,\n fontWeight: 600\n})\n\ndefineEmits<{\n click: [event: MouseEvent]\n}>()\n\n// Get hover color using color-mix for better browser support\nconst getHoverColor = (color: string): string => {\n const baseColor = getColorValue(color)\n // Use color-mix to darken by mixing with black for better browser support\n return `color-mix(in srgb, ${baseColor} 85%, black 15%)`\n}\n\n// Get hover contrast color for the darker hover state\nconst getHoverContrastColor = (color: string, fontWeight: number, fontSize: number): string => {\n // For hover state, we calculate contrast against a darker version\n const hoverColorForContrast = color.includes('-') \n ? `${color.split('-')[0]}-${Math.min(parseInt(color.split('-')[1]) + 100, 950)}` \n : `${color}-600`\n return getContrastTextColor(hoverColorForContrast, fontWeight, fontSize)\n}\n\n// Get light variant for ghost/outline hover states\nconst getLightColor = (color: string): string => {\n const baseColor = getColorValue(color)\n // Use relative color with high lightness and low opacity\n return `hsl(from ${baseColor} h s 95% / 0.8)`\n}\n\nconst buttonClasses = computed(() => {\n const classes = [\n 'ui-button',\n `ui-button-${props.variant}`,\n `ui-button-${props.size}`,\n props.fullWidth ? 'ui-button-full-width' : '',\n props.color ? 'ui-button-custom-color' : ''\n ].filter(Boolean).join(' ')\n\n return classes\n})\n\n// Get font characteristics based on button size\nconst getFontCharacteristics = (size: string) => {\n switch (size) {\n case 'sm':\n return { fontSize: 14 } // 0.875rem = 14px\n case 'lg':\n return { fontSize: 16 } // 1rem = 16px\n default: // 'md'\n return { fontSize: 14 } // 0.875rem = 14px\n }\n}\n\n// Computed styles for dynamic color support\nconst buttonStyles = computed(() => {\n if (!props.color) return {}\n \n const { fontSize } = getFontCharacteristics(props.size)\n const fontWeight = props.fontWeight || 600\n \n const primaryColor = getColorValue(props.color)\n const hoverColor = getHoverColor(props.color)\n const lightColor = getLightColor(props.color)\n const contrastColor = getContrastTextColor(props.color || 'gray', fontWeight, fontSize)\n const hoverContrastColor = getHoverContrastColor(props.color || 'gray', fontWeight, fontSize)\n \n // For secondary buttons, we need to calculate contrast against the light background\n // The light background is very light, so we'll use a much lighter version for contrast calculation\n const lightColorForContrast = `${props.color}-100` // Use the 100 shade for contrast calculation\n const lightContrastColor = getContrastTextColor(lightColorForContrast, fontWeight, fontSize)\n \n const baseStyles = {\n '--button-color': primaryColor,\n '--button-hover-color': hoverColor,\n '--button-light-color': lightColor,\n '--button-contrast-color': contrastColor,\n '--button-hover-contrast-color': hoverContrastColor,\n '--button-light-contrast-color': lightContrastColor,\n fontWeight: fontWeight\n }\n \n switch (props.variant) {\n case 'primary':\n return {\n ...baseStyles,\n backgroundColor: primaryColor,\n color: contrastColor,\n boxShadow: '0 1px 2px 0 rgb(0 0 0 / 0.05)',\n '--button-text-color': contrastColor\n }\n case 'secondary':\n return {\n ...baseStyles,\n backgroundColor: lightColor,\n color: lightContrastColor,\n border: `1px solid ${getLightColor(props.color)}`,\n '--button-text-color': lightContrastColor\n }\n case 'ghost':\n return {\n ...baseStyles,\n color: primaryColor,\n backgroundColor: 'transparent',\n '--button-text-color': primaryColor\n }\n case 'outline':\n return {\n ...baseStyles,\n borderColor: primaryColor,\n color: primaryColor,\n backgroundColor: 'transparent',\n borderWidth: '1px',\n borderStyle: 'solid',\n '--button-text-color': primaryColor\n }\n default:\n return {\n ...baseStyles,\n backgroundColor: primaryColor,\n color: contrastColor,\n '--button-text-color': contrastColor\n }\n }\n})\n</script>\n\n<style scoped>\n/* Base button styles */\n.ui-button {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n font-weight: 600;\n transition: all 0.15s ease;\n border: none;\n cursor: pointer;\n text-decoration: none;\n outline: none;\n position: relative;\n}\n\n.ui-button:focus-visible {\n outline: 2px solid var(--strands-primary, #EA00A8);\n outline-offset: 2px;\n}\n\n.ui-button:disabled {\n opacity: 0.5;\n cursor: not-allowed;\n}\n\n/* Size variants */\n.ui-button-sm {\n padding: 0.5rem 0.75rem;\n font-size: 0.875rem;\n border-radius: 0.375rem;\n}\n\n.ui-button-md {\n padding: 0.75rem 1rem;\n font-size: 0.875rem;\n border-radius: 0.5rem;\n}\n\n.ui-button-lg {\n padding: 0.75rem 1.5rem;\n font-size: 1rem;\n border-radius: 0.5rem;\n}\n\n/* Width variant */\n.ui-button-full-width {\n width: 100%;\n}\n\n/* Color variants */\n.ui-button-primary {\n background-color: #EA00A8;\n color: white;\n box-shadow: 0 1px 2px 0 rgba(0, 0, 0, 0.05);\n}\n\n.ui-button-primary:hover:not(:disabled) {\n background-color: #B8006F;\n box-shadow: 0 4px 12px 0 rgba(0, 0, 0, 0.15);\n transform: translateY(-1px);\n}\n\n.ui-button-secondary {\n background-color: #f3f4f6;\n color: #374151;\n border: 1px solid #d1d5db;\n}\n\n.ui-button-secondary:hover:not(:disabled) {\n background-color: #e5e7eb;\n border-color: #9ca3af;\n box-shadow: 0 2px 6px 0 rgba(0, 0, 0, 0.08);\n transform: translateY(-0.5px);\n}\n\n.ui-button-ghost {\n background-color: transparent;\n color: var(--strands-primary, #EA00A8);\n}\n\n.ui-button-ghost:hover:not(:disabled) {\n background-color: rgba(234, 0, 168, 0.15);\n color: #B8006F;\n transform: translateY(-0.5px);\n}\n\n.ui-button-outline {\n background-color: transparent;\n color: var(--strands-primary, #EA00A8);\n border: 1px solid var(--strands-primary, #EA00A8);\n}\n\n.ui-button-outline:hover:not(:disabled) {\n background-color: var(--strands-primary, #EA00A8);\n color: white;\n box-shadow: 0 2px 6px 0 rgba(234, 0, 168, 0.25);\n transform: translateY(-0.5px);\n}\n\n/* Custom color support with relative colors */\n.ui-button-custom-color {\n /* Styles will be applied via the style attribute using CSS custom properties */\n}\n\n.ui-button-custom-color:hover:not(:disabled) {\n background-color: var(--button-hover-color) !important;\n color: var(--button-hover-contrast-color) !important;\n box-shadow: 0 4px 8px 0 rgba(0, 0, 0, 0.12) !important;\n transform: translateY(-1px);\n}\n\n.ui-button-custom-color.ui-button-primary:hover:not(:disabled) {\n box-shadow: 0 4px 12px 0 rgba(0, 0, 0, 0.15) !important;\n}\n\n.ui-button-custom-color.ui-button-ghost:hover:not(:disabled) {\n background-color: var(--button-light-color) !important;\n color: var(--button-color) !important;\n}\n\n.ui-button-custom-color.ui-button-outline:hover:not(:disabled) {\n background-color: var(--button-color) !important;\n color: white !important;\n}\n\n.ui-button-custom-color.ui-button-secondary:hover:not(:disabled) {\n background-color: var(--button-color) !important;\n color: white !important;\n}\n\n/* Content styles */\n.button-content {\n display: flex;\n align-items: center;\n justify-content: center;\n gap: 0.5rem;\n color: inherit;\n}\n\n.button-loading-content {\n display: flex;\n align-items: center;\n justify-content: center;\n gap: 0.5rem;\n color: inherit;\n}\n\n.button-loading-icon {\n width: 1rem;\n height: 1rem;\n animation: spin 1s linear infinite;\n}\n\n.button-loading-track {\n opacity: 0.25;\n}\n\n.button-loading-spinner {\n opacity: 0.75;\n}\n\n/* Animations */\n@keyframes spin {\n from {\n transform: rotate(0deg);\n }\n to {\n transform: rotate(360deg);\n }\n}\n\n/* Active state */\n.ui-button:active:not(:disabled) {\n transform: translateY(1px);\n}\n\n/* Loading state */\n.ui-button:has(.button-loading-content) {\n position: relative;\n}\n\n/* Utility classes for compatibility */\n.ui-button.w-full {\n width: 100%;\n}\n\n.ui-button.mt-4 {\n margin-top: 1rem;\n}\n\n.ui-button.mr-2 {\n margin-right: 0.5rem;\n}\n\n.ui-button.ml-3 {\n margin-left: 0.75rem;\n}\n\n@media (min-width: 640px) {\n .ui-button.sm\\:w-auto {\n width: auto;\n }\n}\n\n/* Additional utility support */\n.ui-button.mfa-setup-method-button {\n width: 100%;\n margin-top: 1rem;\n}\n\n.ui-button.hardware-key-setup-method-button {\n width: 100%;\n margin-top: 1rem;\n}\n\n.ui-button.profile-method-button {\n width: 100%;\n margin-top: 1rem;\n}\n</style>","<template>\n <div \n class=\"ui-card\"\n :class=\"[\n `ui-card-${variant}`,\n `ui-card-padding-${padding}`,\n `ui-card-shadow-${shadow}`\n ]\">\n <div v-if=\"$slots['header']\" class=\"ui-card-header\">\n <slot name=\"header\" />\n </div>\n\n <div class=\"ui-card-content\">\n <slot />\n </div>\n\n <div v-if=\"$slots['footer']\" class=\"ui-card-footer\">\n <slot name=\"footer\" />\n </div>\n </div>\n</template>\n\n<script setup lang=\"ts\">\nimport { computed } from 'vue'\n\ninterface Props {\n variant?: 'default' | 'modern' | 'minimal' | 'clean'\n padding?: 'sm' | 'md' | 'lg'\n shadow?: 'none' | 'sm' | 'md' | 'lg'\n}\n\nconst props = withDefaults(defineProps<Props>(), {\n variant: 'default',\n padding: 'md',\n shadow: 'sm'\n})\n\n// Card styling is handled by CSS classes\n</script>\n\n<style scoped>\n.ui-card {\n background: white;\n color: black;\n border: 1px solid #e5e7eb;\n display: flex;\n flex-direction: column;\n gap: 0.75rem;\n}\n\n/* Variants */\n.ui-card-default {\n border-radius: 0.5rem;\n}\n\n.ui-card-modern {\n border-radius: 1rem;\n box-shadow: 0 10px 15px -3px rgb(0 0 0 / 0.1);\n backdrop-filter: blur(16px);\n}\n\n.ui-card-minimal {\n border-radius: 0.375rem;\n}\n\n.ui-card-clean {\n background: transparent;\n border: none;\n box-shadow: none;\n}\n\n/* Padding */\n.ui-card-padding-sm {\n padding: 1rem;\n}\n\n.ui-card-padding-md {\n padding: 1.5rem;\n}\n\n.ui-card-padding-lg {\n padding: 2rem;\n}\n\n/* Shadows */\n.ui-card-shadow-none {\n box-shadow: none;\n}\n\n.ui-card-shadow-sm {\n box-shadow: 0 1px 2px 0 rgb(0 0 0 / 0.05);\n}\n\n.ui-card-shadow-md {\n box-shadow: 0 4px 6px -1px rgb(0 0 0 / 0.1);\n}\n\n.ui-card-shadow-lg {\n box-shadow: 0 10px 15px -3px rgb(0 0 0 / 0.1);\n}\n\n/* Header and Footer */\n.ui-card-header {\n border-bottom: 1px solid #e5e7eb;\n padding-bottom: 1rem;\n}\n\n.ui-card-footer {\n border-top: 1px solid #e5e7eb;\n padding-top: 1rem;\n}\n\n.ui-card-content {\n display: flex;\n flex-direction: column;\n gap: 1.5rem;\n}\n</style>","<template>\n <div class=\"accui-component-scope\">\n <div class=\"input-container\">\n <label v-if=\"label\" :for=\"inputId\" class=\"input-label\">\n {{ label }}\n <span v-if=\"required\" class=\"input-required\">*</span>\n </label>\n\n <div class=\"input-wrapper\">\n <input :id=\"inputId\" :type=\"computedType\" :value=\"modelValue\" :placeholder=\"placeholder\" :disabled=\"disabled\"\n :required=\"required\" :autocomplete=\"autocomplete\" :name=\"name\" :inputmode=\"inputmode\" :maxlength=\"maxlength\" :class=\"inputClasses\" @input=\"handleInput\"\n @blur=\"$emit('blur', $event)\" @focus=\"$emit('focus', $event)\" @keydown=\"$emit('keydown', $event)\" />\n\n <!-- Password visibility toggle -->\n <button v-if=\"type === 'password'\" type=\"button\"\n class=\"input-password-toggle\"\n @click=\"togglePasswordVisibility\">\n <svg v-if=\"showPassword\" class=\"input-toggle-icon\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\"\n d=\"M13.875 18.825A10.05 10.05 0 0112 19c-4.478 0-8.268-2.943-9.543-7a9.97 9.97 0 011.563-3.029m5.858.908a3 3 0 114.243 4.243M9.878 9.878l4.242 4.242M9.878 9.878L3 3m6.878 6.878L21 21\" />\n </svg>\n <svg v-else class=\"input-toggle-icon\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M15 12a3 3 0 11-6 0 3 3 0 016 0z\" />\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\"\n d=\"M2.458 12C3.732 7.943 7.523 5 12 5c4.478 0 8.268 2.943 9.542 7-1.274 4.057-5.064 7-9.542 7-4.477 0-8.268-2.943-9.542-7z\" />\n </svg>\n </button>\n\n <!-- Icon slot -->\n <div v-if=\"$slots['icon']\" class=\"input-icon-container\">\n <slot name=\"icon\" />\n </div>\n </div>\n\n <!-- Help text or error message -->\n <p v-if=\"error\" class=\"input-error-text\">{{ typeof error === 'string' ? error : error.message }}</p>\n <p v-else-if=\"helpText\" class=\"input-help-text\">{{ helpText }}</p>\n </div>\n </div>\n</template>\n\n<script setup lang=\"ts\">\nimport { computed, ref, useSlots } from 'vue'\n\ninterface Props {\n modelValue?: string | number\n type?: 'text' | 'email' | 'password' | 'number' | 'tel' | 'url'\n label?: string\n placeholder?: string\n disabled?: boolean\n required?: boolean\n error?: string | { message: string }\n helpText?: string\n autocomplete?: string\n name?: string\n inputmode?: 'text' | 'numeric' | 'decimal' | 'tel' | 'search' | 'email' | 'url'\n maxlength?: number | string\n size?: 'sm' | 'md' | 'lg'\n}\n\nconst props = withDefaults(defineProps<Props>(), {\n type: 'text',\n size: 'md'\n})\n\nconst emit = defineEmits<{\n 'update:modelValue': [value: string]\n blur: [event: FocusEvent]\n focus: [event: FocusEvent]\n keydown: [event: KeyboardEvent]\n}>()\n\nconst slots = useSlots()\nconst showPassword = ref(false)\nconst inputId = ref(`input-${Math.random().toString(36).substr(2, 9)}`)\n\nconst computedType = computed(() => {\n if (props.type === 'password') {\n return showPassword.value ? 'text' : 'password'\n }\n return props.type\n})\n\nconst inputClasses = computed(() => {\n const baseClasses = [\n 'input-field'\n ]\n\n // Size classes\n const sizeClasses = {\n sm: 'input-size-sm',\n md: 'input-size-md', // default styling\n lg: 'input-size-lg'\n }\n\n // Error state\n const errorClasses = props.error\n ? 'input-error'\n : ''\n\n // Icon padding\n const iconPadding = slots['icon'] ? 'input-with-icon' : ''\n const passwordPadding = props.type === 'password' ? 'input-with-password' : ''\n\n return [\n ...baseClasses,\n sizeClasses[props.size],\n errorClasses,\n iconPadding,\n passwordPadding\n ].filter(Boolean).join(' ')\n})\n\nconst handleInput = (event: Event) => {\n const target = event.target as HTMLInputElement\n emit('update:modelValue', target.value)\n}\n\nconst togglePasswordVisibility = () => {\n showPassword.value = !showPassword.value\n}\n</script>\n\n<style scoped>\n/* Input Component Semantic CSS */\n.input-container {\n display: flex;\n flex-direction: column;\n gap: 0.25rem;\n}\n\n.input-label {\n display: block;\n font-size: 0.875rem;\n font-weight: 500;\n color: #374151;\n margin-bottom: 0.5rem;\n}\n\n.input-required {\n color: #dc2626;\n}\n\n.input-wrapper {\n position: relative;\n}\n\n.input-field {\n width: 100%;\n padding: 0.75rem 1rem;\n border: 1px solid #d1d5db;\n border-radius: 0.5rem;\n background-color: white;\n color: #111827;\n transition: border-color 0.2s ease, box-shadow 0.2s ease;\n outline: none;\n}\n\n.input-size-sm {\n padding: 0.5rem 0.75rem;\n font-size: 0.875rem;\n}\n\n.input-size-md {\n padding: 0.75rem 1rem;\n font-size: 0.875rem;\n}\n\n.input-size-lg {\n padding: 0.75rem 1rem;\n font-size: 1rem;\n}\n\n.input-error {\n border-color: #fca5a5;\n}\n\n.input-with-icon {\n padding-left: 2.5rem;\n}\n\n.input-with-password {\n padding-right: 2.5rem;\n}\n\n.input-icon-container {\n position: absolute;\n inset: 0 auto 0 0;\n padding-left: 0.75rem;\n display: flex;\n align-items: center;\n pointer-events: none;\n}\n\n.input-error-text {\n font-size: 0.875rem;\n color: #dc2626;\n}\n\n.input-help-text {\n font-size: 0.875rem;\n color: #6b7280;\n}\n\n/* \n BITWARDEN & PASSWORD MANAGER STYLE PREVENTION\n =============================================\n \n These styles use !important to prevent password managers (Bitwarden, 1Password, etc.)\n from overriding our input styling. Password managers often inject their own CSS that\n can break our design system.\n \n If you need to modify input styles, edit these CSS rules rather than just the Tailwind\n classes, as password managers may override the Tailwind classes.\n*/\n\n/* Base input styles - override password manager modifications */\ninput[type=\"email\"],\ninput[type=\"password\"],\ninput[type=\"text\"],\ninput[type=\"number\"],\ninput[type=\"tel\"],\ninput[type=\"url\"] {\n /* Force our styles to take precedence over password manager modifications */\n background-color: white !important;\n background-image: none !important;\n border: 1px solid var(--gray-300) !important;\n border-radius: var(--radius-lg) !important;\n box-shadow: var(--shadow-sm) !important;\n color: var(--gray-900) !important;\n font-family: inherit !important;\n font-size: var(--text-sm) !important;\n line-height: 1.25rem !important;\n padding: var(--space-3) var(--space-4) !important;\n transition: border-color 0.2s, box-shadow 0.2s !important;\n width: 100% !important;\n}\n\n/* Focus state overrides */\ninput[type=\"email\"]:focus,\ninput[type=\"password\"]:focus,\ninput[type=\"text\"]:focus,\ninput[type=\"number\"]:focus,\ninput[type=\"tel\"]:focus,\ninput[type=\"url\"]:focus {\n border-color: var(--strands-500) !important;\n box-shadow: 0 0 0 2px rgba(234, 0, 168, 0.25) !important;\n outline: none !important;\n}\n\n/* Error state overrides */\ninput.input-error {\n border-color: var(--red-300) !important;\n}\n\ninput.input-error:focus {\n border-color: var(--red-500) !important;\n box-shadow: 0 0 0 2px rgba(239, 68, 68, 0.2) !important;\n}\n\n/* Disabled state overrides */\ninput:disabled {\n background-color: var(--gray-50) !important;\n color: var(--gray-500) !important;\n cursor: not-allowed !important;\n}\n\n/* Bitwarden and other password manager specific overrides */\ninput[data-bwautofill],\ninput[data-lpignore],\ninput[data-form-type],\ninput[data-1p-ignore] {\n background-color: white !important;\n background-image: none !important;\n border: 1px solid rgb(209 213 219) !important;\n box-shadow: 0 1px 2px 0 rgb(0 0 0 / 0.05) !important;\n}\n\n/* Override webkit autofill styling */\ninput:-webkit-autofill,\ninput:-webkit-autofill:hover,\ninput:-webkit-autofill:focus,\ninput:-webkit-autofill:active {\n -webkit-box-shadow: 0 0 0 30px white inset !important;\n -webkit-text-fill-color: black !important;\n border: 1px solid rgb(209 213 219) !important;\n border-radius: 0.5rem !important;\n transition: background-color 5000s ease-in-out 0s !important;\n}\n\n/* Ensure password inputs have proper padding for our eye icon */\ninput[type=\"password\"] {\n padding-right: 2.5rem !important; /* pr-10 for our eye icon */\n}\n\n/* Hide browser password reveal buttons */\ninput::-ms-reveal,\ninput::-ms-clear {\n display: none !important;\n}\n\n/* Additional size-specific overrides to maintain consistency */\ninput.px-3.py-2 {\n padding: 0.5rem 0.75rem !important; /* sm size */\n}\n\ninput.px-3.py-2\\.5 {\n padding: 0.625rem 0.75rem !important; /* md size - default */\n}\n\ninput.px-4.py-3 {\n padding: 0.75rem 1rem !important; /* lg size */\n}\n\n/* Icon padding overrides */\ninput.pl-10 {\n padding-left: 2.5rem !important;\n}\n\ninput.pr-10 {\n padding-right: 2.5rem !important;\n}\n\n/* Password toggle button styling */\n.input-password-toggle {\n position: absolute;\n top: 0;\n right: 0;\n bottom: 0;\n display: flex;\n align-items: center;\n padding-right: 0.75rem;\n color: #9ca3af;\n background: none;\n border: none;\n cursor: pointer;\n border-radius: 0.375rem;\n transition: color 0.2s ease;\n}\n\n.input-password-toggle:hover {\n color: #6b7280;\n}\n\n.input-password-toggle:focus-visible {\n outline: 2px solid var(--strands-500);\n outline-offset: 2px;\n}\n\n.input-toggle-icon {\n width: 1.25rem;\n height: 1.25rem;\n flex-shrink: 0;\n}\n</style>\n","<template>\n <component :is=\"tag\" \n class=\"ui-link\"\n :class=\"[\n `ui-link-${variant}`,\n `ui-link-${size}`,\n { 'ui-link-disabled': disabled },\n { 'ui-link-custom-color': color }\n ]\"\n :style=\"linkStyles\"\n v-bind=\"linkProps\" \n @click=\"handleClick\">\n <slot />\n </component>\n</template>\n\n<script setup lang=\"ts\">\nimport { computed } from 'vue'\nimport { getContrastTextColor, getColorValue } from '../utils/contrast'\n\ninterface Props {\n href?: string\n to?: string | object\n variant?: 'primary' | 'secondary' | 'ghost' | 'underline'\n size?: 'sm' | 'md' | 'lg'\n disabled?: boolean\n external?: boolean\n /** \n * Color prop supports multiple formats (similar to UiButton):\n * - Base colors: 'red', 'blue', 'green', 'strands', etc.\n * - Shades: 'red-600', 'blue-500', etc. (100-950)\n * - Opacity: 'red/50', 'blue/80', etc. (0-100)\n */\n color?: string\n}\n\nconst props = withDefaults(defineProps<Props>(), {\n variant: 'primary',\n size: 'md',\n disabled: false,\n external: false\n})\n\nconst emit = defineEmits<{\n click: [event: MouseEvent]\n}>()\n\nconst tag = computed(() => {\n if (props.to) return 'router-link'\n if (props.href) return 'a'\n return 'button'\n})\n\nconst linkProps = computed(() => {\n const baseProps: Record<string, any> = {}\n\n if (props.to) {\n baseProps['to'] = props.to\n } else if (props.href) {\n baseProps['href'] = props.href\n if (props.external) {\n baseProps['target'] = '_blank'\n baseProps['rel'] = 'noopener noreferrer'\n }\n } else {\n baseProps['type'] = 'button'\n }\n\n if (props.disabled) {\n baseProps['disabled'] = true\n baseProps['aria-disabled'] = true\n }\n\n return baseProps\n})\n\n// Color generation is now handled by the utility\n\n// Get hover color using color-mix for better browser support\nconst getHoverColor = (color: string): string => {\n const baseColor = getColorValue(color)\n // Use color-mix to darken by mixing with black for better browser support\n return `color-mix(in srgb, ${baseColor} 85%, black 15%)`\n}\n\n// Contrast and color generation now handled by utility imports\n\n// Computed styles for dynamic color support\nconst linkStyles = computed(() => {\n if (!props.color) return {}\n \n const primaryColor = getColorValue(props.color)\n const hoverColor = getHoverColor(props.color)\n \n const baseStyles = {\n '--link-color': primaryColor,\n '--link-hover-color': hoverColor,\n color: primaryColor\n }\n \n if (props.variant === 'underline') {\n return {\n ...baseStyles,\n textDecorationColor: primaryColor\n }\n }\n \n return baseStyles\n})\n\nconst handleClick = (event: MouseEvent) => {\n if (!props.disabled) {\n emit('click', event)\n }\n}\n</script>\n\n<style scoped>\n.ui-link {\n display: inline-flex;\n align-items: center;\n font-weight: 500;\n text-decoration: none;\n transition: color 0.2s ease, text-decoration 0.2s ease;\n cursor: pointer;\n background: none;\n border: none;\n padding: 0;\n line-height: inherit;\n}\n\n.ui-link:focus-visible {\n outline: 2px solid #EA00A8;\n outline-offset: 2px;\n border-radius: 2px;\n}\n\n.ui-link-disabled {\n opacity: 0.5;\n cursor: not-allowed;\n pointer-events: none;\n}\n\n/* Sizes */\n.ui-link-sm {\n font-size: 0.75rem;\n}\n\n.ui-link-md {\n font-size: 0.875rem;\n}\n\n.ui-link-lg {\n font-size: 1rem;\n}\n\n/* Variants */\n.ui-link-primary {\n color: #EA00A8;\n background: none;\n border: none;\n padding: 0;\n}\n\n.ui-link-primary:hover {\n color: #B8006F;\n text-decoration: underline;\n text-underline-offset: 2px;\n}\n\n.ui-link-secondary {\n color: #6b7280;\n background: none;\n border: none;\n padding: 0;\n}\n\n.ui-link-secondary:hover {\n color: #1f2937;\n text-decoration: underline;\n text-underline-offset: 2px;\n}\n\n.ui-link-ghost {\n color: #6b7280;\n background: none;\n border: none;\n padding: 0;\n position: relative;\n}\n\n.ui-link-ghost:hover {\n color: #374151;\n}\n\n.ui-link-ghost::after {\n content: '';\n position: absolute;\n bottom: -2px;\n left: 0;\n width: 0;\n height: 1px;\n background-color: #374151;\n transition: width 0.3s ease;\n}\n\n.ui-link-ghost:hover::after {\n width: 100%;\n}\n\n.ui-link-underline {\n color: #EA00A8;\n text-decoration: underline;\n text-decoration-color: #EA00A8;\n text-underline-offset: 2px;\n background: none;\n border: none;\n padding: 0;\n}\n\n.ui-link-underline:hover {\n color: #B8006F;\n text-decoration-color: #B8006F;\n}\n\n/* Icon support */\n.ui-link svg {\n flex-shrink: 0;\n}\n\n/* Custom color support with relative colors */\n.ui-link-custom-color {\n color: var(--link-color);\n}\n\n.ui-link-custom-color:hover:not(.ui-link-disabled) {\n color: var(--link-hover-color);\n}\n\n.ui-link-custom-color.ui-link-underline {\n text-decoration-color: var(--link-color);\n}\n\n.ui-link-custom-color.ui-link-underline:hover:not(.ui-link-disabled) {\n text-decoration-color: var(--link-hover-color);\n}\n</style>\n","<template>\n <div class=\"tabs-container\">\n <div class=\"tabs-wrapper\">\n <!-- Tab List -->\n <div class=\"tabs-list\" role=\"tablist\">\n <button v-for=\"(tab, index) in tabs\" :key=\"tab.value\" ref=\"tabButtons\" \n class=\"tab-button\"\n :class=\"{ 'tab-button-active': modelValue === tab.value }\"\n :aria-selected=\"modelValue === tab.value\" \n :aria-controls=\"`tabpanel-${tab.value}`\" \n :id=\"`tab-${tab.value}`\"\n role=\"tab\" \n @click=\"handleTabClick(tab.value, index)\">\n {{ tab.label }}\n </button>\n\n <!-- Animated stretching underline -->\n <div class=\"tab-underline\" :style=\"underlineStyle\" />\n </div>\n </div>\n </div>\n</template>\n\n<script setup lang=\"ts\">\nimport { ref, computed, nextTick, onMounted, watch, toRefs } from 'vue'\n\ninterface Tab {\n label: string\n value: string\n}\n\ninterface Props {\n modelValue: string\n tabs: Tab[]\n}\n\ninterface Emits {\n (e: 'update:modelValue', value: string): void\n}\n\nconst props = defineProps<Props>()\nconst emit = defineEmits<Emits>()\n\nconst tabButtons = ref<HTMLElement[]>([])\nconst underlineStyle = ref({\n width: '0px',\n left: '0px',\n opacity: '0'\n})\n\nlet currentTabIndex = -1\nlet isAnimating = false\n\nconst handleTabClick = async (value: string, index: number) => {\n if (isAnimating) return\n\n emit('update:modelValue', value)\n await nextTick()\n animateUnderlineStretch(index)\n}\n\nconst animateUnderlineStretch = async (newIndex: number) => {\n if (!tabButtons.value[newIndex] || newIndex === currentTabIndex) return\n\n isAnimating = true\n const newTab = tabButtons.value[newIndex]\n const container = newTab.parentElement\n\n if (!container) return\n\n const newRect = newTab.getBoundingClientRect()\n const containerRect = container.getBoundingClientRect()\n const newLeft = newRect.left - containerRect.left\n const newWidth = newRect.width\n\n if (currentTabIndex === -1) {\n // Initial load - just appear at the new position\n underlineStyle.value = {\n width: `${newWidth}px`,\n left: `${newLeft}px`,\n opacity: '1'\n }\n currentTabIndex = newIndex\n isAnimating = false\n return\n }\n\n const currentTab = tabButtons.value[currentTabIndex]\n const currentRect = currentTab.getBoundingClientRect()\n const currentLeft = currentRect.left - containerRect.left\n const currentWidth = currentRect.width\n\n // Determine stretch direction and calculate stretch dimensions\n const isMovingRight = newIndex > currentTabIndex\n const stretchLeft = isMovingRight ? currentLeft : newLeft\n const stretchWidth = isMovingRight\n ? (newLeft + newWidth) - currentLeft\n : (currentLeft + currentWidth) - newLeft\n\n // Phase 1: Stretch to span both tabs\n underlineStyle.value = {\n width: `${stretchWidth}px`,\n left: `${stretchLeft}px`,\n opacity: '1'\n }\n\n // Phase 2: After stretch animation, contract to new position\n setTimeout(() => {\n underlineStyle.value = {\n width: `${newWidth}px`,\n left: `${newLeft}px`,\n opacity: '1'\n }\n currentTabIndex = newIndex\n setTimeout(() => {\n isAnimating = false\n }, 150) // Match the CSS transition duration\n }, 120) // Stretch duration\n}\n\n// Initialize underline position\nonMounted(async () => {\n await nextTick()\n const activeIndex = props.tabs.findIndex(tab => tab.value === props.modelValue)\n if (activeIndex !== -1) {\n animateUnderlineStretch(activeIndex)\n }\n})\n\n// Watch for external prop changes\nconst activeTabIndex = computed(() =>\n props.tabs.findIndex(tab => tab.value === props.modelValue)\n)\n\n// Update underline when active tab changes externally\nconst { modelValue } = toRefs(props)\nwatch(modelValue, async () => {\n await nextTick()\n const activeIndex = props.tabs.findIndex(tab => tab.value === props.modelValue)\n if (activeIndex !== -1) {\n animateUnderlineStretch(activeIndex)\n }\n})\n</script>\n\n<style scoped>\n.tabs-container {\n /* Container styling if needed */\n}\n\n.tabs-wrapper {\n position: relative;\n}\n\n.tabs-list {\n position: relative;\n display: flex;\n border-bottom: 1px solid #e5e7eb;\n}\n\n.tab-button {\n position: relative;\n flex: 1;\n padding: 1rem 1.5rem;\n font-weight: 500;\n font-size: 0.875rem;\n color: #6b7280;\n background: none;\n border: none;\n cursor: pointer;\n transition: color 0.15s ease;\n}\n\n.tab-button:hover {\n color: #EA00A8;\n}\n\n.tab-button:focus-visible {\n outline: none;\n color: #EA00A8;\n}\n\n.tab-button-active {\n color: #EA00A8;\n}\n\n.tab-underline {\n position: absolute;\n bottom: -3px;\n height: 5px;\n background-color: #EA00A8;\n border-radius: 9999px;\n transition: all 0.15s ease;\n}\n</style>\n","<template>\n <div class=\"loader-container\" :class=\"{ 'loader-centered': centered }\">\n <div class=\"loader-icon\">\n <!-- Simple SVG with fun animated path -->\n <svg :width=\"size\" :height=\"size\" viewBox=\"0 0 500 500\">\n <!-- Fun wavy path inspired by Strands -->\n <path\n :d=\"d\"\n fill=\"none\"\n :stroke=\"semiColor\"\n :stroke-width=\"weight\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n transform=\"translate(81, 13) scale(1.0)\"\n />\n \n <path\n :d=\"d\"\n fill=\"none\"\n :stroke=\"solidColor\"\n :stroke-width=\"weight\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n class=\"loader-animated-path\"\n transform=\"translate(81, 13) scale(1.0)\"\n />\n </svg>\n </div>\n \n <!-- Optional text -->\n <p v-if=\"text\" class=\"loader-text\" :class=\"{ [`loader-text-${variant}`]: variant !== 'auto' }\">{{ text }}</p>\n </div>\n</template>\n\n<script setup lang=\"ts\">\nimport { computed, ref } from 'vue'\n\nimport logo from '../../../assets/strands_icon_path.svg?raw'\n\nconst path = logo.replace(/<svg[^>]*>/, '').replace(/<\\/svg>/, '').trim()\nconst d = path.match(/d=\"([^\"]*)\"/)?.[1] || ''\n\ninterface Props {\n size?: number\n variant?: 'light' | 'dark' | 'auto'\n text?: string\n centered?: boolean\n weight?: number\n}\n\nconst props = withDefaults(defineProps<Props>(), {\n size: 80,\n variant: 'auto',\n centered: true,\n weight: 30,\n});\n\n// Computed colors for the loader animation\n\nconst semiColor = computed(() => \n props.variant === 'light' ? '#EA00A810'\n : props.variant === 'dark' ? '#ffffff10'\n : '#ffffff10'\n)\n\nconst solidColor = computed(() => \n props.variant === 'light' ? '#EA00A8'\n : props.variant === 'dark' ? '#ffffff'\n : '#ffffff'\n)\n</script>\n\n<style scoped>\n.loader-container {\n display: flex;\n flex-direction: column;\n align-items: center;\n gap: 1rem;\n}\n\n.loader-centered {\n justify-content: center;\n}\n\n.loader-icon {\n position: relative;\n}\n\n.loader-text {\n font-size: 0.875rem;\n font-weight: 500;\n color: #6b7280;\n}\n\n.loader-text-light {\n color: #6b7280;\n}\n\n.loader-text-dark {\n color: #d1d5db;\n}\n\n@keyframes draw-line {\n 0% {\n stroke-dasharray: 100 1000;\n stroke-dashoffset: 1000;\n }\n 100% {\n stroke-dasharray: 100 1000;\n stroke-dashoffset: -100;\n }\n}\n\n.loader-animated-path {\n animation: draw-line 0.8s linear infinite;\n}\n</style>","export default \"<svg width=\\\"302\\\" height=\\\"438\\\" viewBox=\\\"0 0 302 438\\\" fill=\\\"none\\\" xmlns=\\\"http://www.w3.org/2000/svg\\\">\\n<path d=\\\"M71.5001 96C71.5001 96 132 106 137 61.5C142 17 117.5 3.50005 94.5001 1.50003C71.5001 -0.499996 16.0001 8.5 2.00014 72.5C-6.5 130.5 71.5003 227.5 165 218C258.5 208.5 280.758 148.5 283.5 121C286.242 93.5 277.5 61.5 238.5 61.5C153 61.5 150.501 185 170.5 235C190.5 285 199 279 213 314C227.001 349 217.296 411.458 183 427C129.456 450.65 92 426 78.5 407.5C65 389 68.0003 357 94.5001 344.5C121 332 212.41 393.5 301.5 361\\\" stroke=\\\"black\\\"/>\\n</svg>\\n\"","<template>\n <button\n type=\"button\"\n :class=\"toggleClasses\"\n :aria-pressed=\"modelValue\"\n :aria-labelledby=\"id ? `${id}-label` : undefined\"\n @click=\"handleToggle\"\n >\n <span class=\"ui-toggle-thumb\" :class=\"thumbClasses\" />\n </button>\n</template>\n\n<script setup lang=\"ts\">\nimport { computed } from 'vue'\n\ninterface Props {\n modelValue?: boolean\n disabled?: boolean\n id?: string\n}\n\ninterface Emits {\n (e: 'update:modelValue', value: boolean): void\n}\n\nconst props = withDefaults(defineProps<Props>(), {\n modelValue: false,\n disabled: false\n})\n\nconst emit = defineEmits<Emits>()\n\nconst toggleClasses = computed(() => [\n 'ui-toggle',\n {\n 'ui-toggle--on': props.modelValue,\n 'ui-toggle--off': !props.modelValue,\n 'ui-toggle--disabled': props.disabled\n }\n])\n\nconst thumbClasses = computed(() => [\n {\n 'ui-toggle-thumb--on': props.modelValue,\n 'ui-toggle-thumb--off': !props.modelValue\n }\n])\n\nconst handleToggle = () => {\n if (props.disabled) return\n emit('update:modelValue', !props.modelValue)\n}\n</script>\n\n<style scoped>\n.ui-toggle {\n position: relative;\n display: inline-flex;\n align-items: center;\n width: 2.75rem;\n height: 1.5rem;\n border: 2px solid transparent;\n border-radius: 9999px;\n cursor: pointer;\n transition: all 0.2s ease-in-out;\n outline: none;\n background-color: transparent;\n padding: 0;\n}\n\n.ui-toggle:focus {\n box-shadow: 0 0 0 3px rgba(234, 0, 168, 0.2);\n}\n\n.ui-toggle--off {\n background-color: #d1d5db;\n}\n\n.ui-toggle--on {\n background-color: #ea00a8;\n}\n\n.ui-toggle--disabled {\n opacity: 0.5;\n cursor: not-allowed;\n}\n\n.ui-toggle-thumb {\n display: inline-block;\n width: 1.25rem;\n height: 1.25rem;\n background-color: white;\n border-radius: 50%;\n box-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.1), 0 1px 2px 0 rgba(0, 0, 0, 0.06);\n transition: transform 0.2s ease-in-out;\n}\n\n.ui-toggle-thumb--off {\n transform: translateX(0);\n}\n\n.ui-toggle-thumb--on {\n transform: translateX(1.25rem);\n}\n\n/* Dark mode support */\n@media (prefers-color-scheme: dark) {\n .ui-toggle--off {\n background-color: #4b5563;\n }\n \n .ui-toggle-thumb {\n background-color: #f9fafb;\n }\n}\n</style>","<template>\n <div class=\"accui-component-scope\">\n <div class=\"avatar-editor-simple\">\n <!-- Hidden file input (always available) -->\n <input\n ref=\"fileInput\"\n type=\"file\"\n accept=\"image/*\"\n class=\"hidden-input\"\n @change=\"handleFileSelect\"\n />\n \n <!-- File Upload Area -->\n <div v-if=\"!imageData\" \n class=\"upload-area\"\n @click=\"triggerFileUpload\" \n @drop=\"handleDrop\" \n @dragover.prevent \n @dragenter.prevent>\n <div class=\"upload-content\">\n <svg class=\"upload-icon\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"1.5\" \n d=\"M4 16l4.586-4.586a2 2 0 012.828 0L16 16m-2-2l1.586-1.586a2 2 0 012.828 0L20 14m-6-6h.01M6 20h12a2 2 0 002-2V6a2 2 0 00-2-2H6a2 2 0 00-2 2v12a2 2 0 002 2z\" />\n </svg>\n <h3 class=\"upload-title\">Upload your photo</h3>\n <p class=\"upload-subtitle\">Drag and drop or click to browse</p>\n <div class=\"upload-formats\">\n <span class=\"format-tag\">JPG</span>\n <span class=\"format-tag\">PNG</span>\n <span class=\"format-tag\">GIF</span>\n </div>\n </div>\n </div>\n\n <!-- Image Editor -->\n <div v-else class=\"editor-container\">\n <div class=\"editor-main\">\n <!-- Canvas with fixed circular crop -->\n <div class=\"canvas-container\">\n <canvas\n ref=\"canvas\"\n :width=\"canvasSize\"\n :height=\"canvasSize\"\n class=\"canvas\"\n @mousedown=\"startDrag\"\n @wheel=\"handleWheel\"\n />\n <!-- Fixed circular overlay -->\n <div class=\"crop-overlay\">\n <!-- Blurred backdrop overlay -->\n <div class=\"crop-backdrop\">\n <svg class=\"crop-svg\">\n <defs>\n <mask id=\"backdrop-mask\">\n <rect x=\"0\" y=\"0\" :width=\"canvasSize\" :height=\"canvasSize\" fill=\"white\" />\n <circle \n :cx=\"canvasSize / 2\" \n :cy=\"canvasSize / 2\" \n :r=\"cropRadius\" \n fill=\"black\" \n />\n </mask>\n </defs>\n <rect \n x=\"0\" \n y=\"0\" \n :width=\"canvasSize\" \n :height=\"canvasSize\" \n fill=\"black\" \n opacity=\"0.5\" \n mask=\"url(#backdrop-mask)\" \n />\n </svg>\n </div>\n <!-- Circle border -->\n <svg class=\"crop-svg\">\n <circle \n :cx=\"canvasSize / 2\" \n :cy=\"canvasSize / 2\" \n :r=\"cropRadius\" \n fill=\"none\" \n stroke=\"white\" \n stroke-width=\"2\"\n class=\"crop-circle\"\n />\n </svg>\n </div>\n </div>\n\n <!-- Simple Controls -->\n <div class=\"controls\">\n <!-- Zoom Slider -->\n <div class=\"zoom-control\">\n <button @click=\"zoom = Math.max(minZoom, zoom - 0.1); constrainImagePosition(); updateCanvas()\" \n class=\"zoom-button\">\n <svg class=\"zoom-icon\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M20 12H4\" />\n </svg>\n </button>\n <input\n type=\"range\"\n v-model.number=\"zoom\"\n :min=\"minZoom\"\n :max=\"maxZoom\"\n :step=\"0.01\"\n class=\"zoom-slider\"\n @input=\"constrainImagePosition(); updateCanvas()\"\n />\n <button @click=\"zoom = Math.min(maxZoom, zoom + 0.1); constrainImagePosition(); updateCanvas()\" \n class=\"zoom-button\">\n <svg class=\"zoom-icon\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M12 4v16m8-8H4\" />\n </svg>\n </button>\n </div>\n\n <!-- Action Buttons -->\n <div class=\"action-buttons\">\n <button @click=\"resetImage\" class=\"btn-secondary\">\n Reset\n </button>\n <button @click=\"changePhoto\" class=\"btn-secondary\">\n Change Photo\n </button>\n <button @click=\"cropAndUpload\" :disabled=\"uploading\" class=\"btn-primary\">\n {{ uploading ? 'Saving...' : 'Save Avatar' }}\n </button>\n </div>\n </div>\n </div>\n\n <!-- Preview -->\n <div class=\"preview-section\">\n <h3 class=\"preview-title\">Preview</h3>\n <div class=\"preview-container\">\n <canvas\n ref=\"previewCanvas\"\n :width=\"previewSize\"\n :height=\"previewSize\"\n class=\"preview-canvas\"\n />\n </div>\n <p class=\"preview-instructions\">\n Drag image to reposition<br>\n Scroll to zoom\n </p>\n </div>\n </div>\n </div>\n </div>\n</template>\n\n<script setup lang=\"ts\">\nimport { ref, reactive, onMounted, nextTick, watch } from 'vue'\n\ninterface Props {\n size?: number\n previewSize?: number\n maxFileSize?: number\n uploading?: boolean\n preselectedFile?: File | null\n}\n\ninterface Emits {\n (e: 'upload', file: File): void\n (e: 'error', error: string): void\n}\n\nconst props = withDefaults(defineProps<Props>(), {\n size: 300,\n previewSize: 100,\n maxFileSize: 5 * 1024 * 1024, // 5MB\n uploading: false\n})\n\nconst emit = defineEmits<Emits>()\n\n// Refs\nconst fileInput = ref<HTMLInputElement>()\nconst canvas = ref<HTMLCanvasElement>()\nconst previewCanvas = ref<HTMLCanvasElement>()\n\n// State\nconst imageData = ref<string>('')\nconst originalImage = ref<HTMLImageElement>()\nconst canvasSize = ref(props.size)\nconst previewSize = ref(props.previewSize)\nconst cropRadius = ref(props.size / 2.5) // Fixed circular crop area\n\n// Image position and zoom\nconst imagePos = reactive({ x: 0, y: 0 })\nconst zoom = ref(1)\nconst minZoom = ref(0.1)\nconst maxZoom = ref(3)\n\n// Drag state\nconst isDragging = ref(false)\nconst isResetting = ref(false)\nconst isWheelZooming = ref(false)\nconst dragStart = reactive({ x: 0, y: 0, imageX: 0, imageY: 0 })\n\nonMounted(() => {\n if (canvas.value) {\n const ctx = canvas.value.getContext('2d')\n if (ctx) {\n ctx.fillStyle = '#f9fafb'\n ctx.fillRect(0, 0, canvasSize.value, canvasSize.value)\n }\n }\n})\n\nconst triggerFileUpload = () => {\n fileInput.value?.click()\n}\n\nconst handleFileSelect = (event: Event) => {\n const target = event.target as HTMLInputElement\n const file = target.files?.[0]\n if (file) {\n processFile(file)\n }\n}\n\nconst handleDrop = (event: DragEvent) => {\n event.preventDefault()\n const file = event.dataTransfer?.files[0]\n if (file) {\n processFile(file)\n }\n}\n\nconst processFile = (file: File) => {\n // Validate file\n if (!file.type.startsWith('image/')) {\n emit('error', 'Please select an image file')\n return\n }\n\n if (file.size > props.maxFileSize) {\n emit('error', `File size must be less than ${Math.round(props.maxFileSize / 1024 / 1024)}MB`)\n return\n }\n\n // Read file\n const reader = new FileReader()\n reader.onload = (e) => {\n const result = e.target?.result as string\n loadImage(result)\n }\n reader.readAsDataURL(file)\n}\n\nconst loadImage = (dataUrl: string) => {\n imageData.value = dataUrl\n \n const img = new Image()\n img.onload = () => {\n originalImage.value = img\n \n // Disable watcher during initial load\n isResetting.value = true\n \n // Calculate initial zoom to ensure image completely fills the circular crop\n // Use the larger dimension to ensure the circle is completely filled\n const scale = Math.max(\n (cropRadius.value * 2) / img.width,\n (cropRadius.value * 2) / img.height\n )\n \n const initialZoom = scale // Start with exact scale to fill the circle\n minZoom.value = scale // Minimum zoom must fill the circle completely\n \n // Set max zoom to prevent going beyond original image size (1.0 = 100% of original)\n // But ensure we can at least fill the circle if the image is smaller than the crop area\n maxZoom.value = Math.max(1.0, scale)\n \n // Calculate and set position directly\n const scaledWidth = img.width * initialZoom\n const scaledHeight = img.height * initialZoom\n \n imagePos.x = (canvasSize.value - scaledWidth) / 2\n imagePos.y = (canvasSize.value - scaledHeight) / 2\n \n // Set the zoom\n zoom.value = initialZoom\n \n // Apply position constraints to ensure image covers the circle\n constrainImagePosition()\n \n // Re-enable watcher\n nextTick(() => {\n isResetting.value = false\n })\n \n // Update canvas\n nextTick(() => {\n updateCanvas()\n })\n }\n \n img.src = dataUrl\n}\n\nconst centerImage = () => {\n if (!originalImage.value) return\n \n const img = originalImage.value\n const scaledWidth = img.width * zoom.value\n const scaledHeight = img.height * zoom.value\n \n // Center the image to the canvas center\n imagePos.x = (canvasSize.value - scaledWidth) / 2\n imagePos.y = (canvasSize.value - scaledHeight) / 2\n \n // Apply position constraints to ensure image covers the circle\n constrainImagePosition()\n}\n\nconst updateCanvas = () => {\n if (!originalImage.value || !canvas.value) return\n \n const ctx = canvas.value.getContext('2d')\n if (!ctx) return\n \n // Clear canvas\n ctx.fillStyle = '#f9fafb'\n ctx.fillRect(0, 0, canvasSize.value, canvasSize.value)\n \n // Draw image\n const img = originalImage.value\n const scaledWidth = img.width * zoom.value\n const scaledHeight = img.height * zoom.value\n \n ctx.drawImage(img, imagePos.x, imagePos.y, scaledWidth, scaledHeight)\n \n // Update preview\n updatePreview()\n}\n\nconst updatePreview = () => {\n if (!originalImage.value || !previewCanvas.value || !canvas.value) return\n \n const previewCtx = previewCanvas.value.getContext('2d')\n if (!previewCtx) return\n \n // Clear preview\n previewCtx.fillStyle = '#ffffff'\n previewCtx.fillRect(0, 0, previewSize.value, previewSize.value)\n \n // Create circular clipping\n previewCtx.save()\n previewCtx.beginPath()\n previewCtx.arc(previewSize.value / 2, previewSize.value / 2, previewSize.value / 2, 0, Math.PI * 2)\n previewCtx.clip()\n \n // Calculate the crop area from the center of the canvas\n const cropX = canvasSize.value / 2 - cropRadius.value\n const cropY = canvasSize.value / 2 - cropRadius.value\n const cropSize = cropRadius.value * 2\n \n // Draw the cropped area to preview\n previewCtx.drawImage(\n canvas.value,\n cropX, cropY, cropSize, cropSize,\n 0, 0, previewSize.value, previewSize.value\n )\n \n previewCtx.restore()\n}\n\nconst startDrag = (event: MouseEvent) => {\n if (!originalImage.value) return\n \n isDragging.value = true\n dragStart.x = event.clientX\n dragStart.y = event.clientY\n dragStart.imageX = imagePos.x\n dragStart.imageY = imagePos.y\n \n document.addEventListener('mousemove', handleDrag)\n document.addEventListener('mouseup', stopDrag)\n}\n\nconst constrainImagePosition = () => {\n if (!originalImage.value) return\n \n const img = originalImage.value\n const scaledWidth = img.width * zoom.value\n const scaledHeight = img.height * zoom.value\n \n // Calculate the bounds to ensure the image always covers the circle\n const circleLeft = canvasSize.value / 2 - cropRadius.value\n const circleTop = canvasSize.value / 2 - cropRadius.value\n const circleRight = canvasSize.value / 2 + cropRadius.value\n const circleBottom = canvasSize.value / 2 + cropRadius.value\n \n // The image's right edge must be at least at the circle's right edge\n const maxX = circleRight - scaledWidth\n // The image's left edge must be at most at the circle's left edge\n const minX = circleLeft\n \n // The image's bottom edge must be at least at the circle's bottom edge\n const maxY = circleBottom - scaledHeight\n // The image's top edge must be at most at the circle's top edge\n const minY = circleTop\n \n // Apply constraints\n imagePos.x = Math.min(minX, Math.max(maxX, imagePos.x))\n imagePos.y = Math.min(minY, Math.max(maxY, imagePos.y))\n}\n\nconst handleDrag = (event: MouseEvent) => {\n if (!isDragging.value) return\n \n const deltaX = event.clientX - dragStart.x\n const deltaY = event.clientY - dragStart.y\n \n imagePos.x = dragStart.imageX + deltaX\n imagePos.y = dragStart.imageY + deltaY\n \n // Apply position constraints to keep image within bounds\n constrainImagePosition()\n \n updateCanvas()\n}\n\nconst stopDrag = () => {\n isDragging.value = false\n document.removeEventListener('mousemove', handleDrag)\n document.removeEventListener('mouseup', stopDrag)\n}\n\nconst handleWheel = (event: WheelEvent) => {\n event.preventDefault()\n \n const delta = event.deltaY > 0 ? -0.05 : 0.05\n const newZoom = Math.max(minZoom.value, Math.min(maxZoom.value, zoom.value + delta))\n \n if (newZoom !== zoom.value && originalImage.value) {\n // Set flag to prevent zoom watcher from interfering\n isWheelZooming.value = true\n \n // Always zoom from the center of the canvas (where the crop circle is centered)\n const img = originalImage.value\n const canvasCenter = canvasSize.value / 2\n \n // Calculate current dimensions\n const currentWidth = img.width * zoom.value\n const currentHeight = img.height * zoom.value\n \n // Calculate new dimensions\n const newWidth = img.width * newZoom\n const newHeight = img.height * newZoom\n \n // Calculate current position relative to canvas center\n const currentCenterOffsetX = (imagePos.x + currentWidth / 2) - canvasCenter\n const currentCenterOffsetY = (imagePos.y + currentHeight / 2) - canvasCenter\n \n // Scale the offset by the zoom ratio to maintain the same relative position\n const zoomRatio = newZoom / zoom.value\n const newCenterOffsetX = currentCenterOffsetX * zoomRatio\n const newCenterOffsetY = currentCenterOffsetY * zoomRatio\n \n // Calculate new position that keeps the same point under the canvas center\n imagePos.x = canvasCenter + newCenterOffsetX - newWidth / 2\n imagePos.y = canvasCenter + newCenterOffsetY - newHeight / 2\n \n zoom.value = newZoom\n \n // Apply position constraints after zoom\n constrainImagePosition()\n \n updateCanvas()\n \n // Clear flag after a short delay\n setTimeout(() => {\n isWheelZooming.value = false\n }, 16) // One frame delay\n }\n}\n\nconst resetImage = () => {\n if (!originalImage.value) return\n \n const img = originalImage.value\n \n // Disable watcher during reset\n isResetting.value = true\n \n // Reset to initial zoom that ensures the image fills the crop circle\n const scale = Math.max(\n (cropRadius.value * 2) / img.width,\n (cropRadius.value * 2) / img.height\n )\n \n const targetZoom = scale // Exact scale to fill the circle\n \n // Update zoom constraints\n minZoom.value = scale // Minimum zoom must fill the circle completely\n maxZoom.value = Math.max(1.0, scale) // Prevent going beyond original image size\n \n // Calculate and set position directly\n const scaledWidth = img.width * targetZoom\n const scaledHeight = img.height * targetZoom\n \n imagePos.x = (canvasSize.value - scaledWidth) / 2\n imagePos.y = (canvasSize.value - scaledHeight) / 2\n \n // Set the zoom\n zoom.value = targetZoom\n \n // Apply position constraints\n constrainImagePosition()\n \n // Re-enable watcher\n nextTick(() => {\n isResetting.value = false\n })\n \n updateCanvas()\n}\n\nconst cropAndUpload = async () => {\n if (!originalImage.value || !canvas.value) return\n \n // Create a new canvas for the cropped result\n const cropCanvas = document.createElement('canvas')\n cropCanvas.width = 256\n cropCanvas.height = 256\n const cropCtx = cropCanvas.getContext('2d')\n if (!cropCtx) return\n \n // White background\n cropCtx.fillStyle = '#ffffff'\n cropCtx.fillRect(0, 0, 256, 256)\n \n // Create circular clipping\n cropCtx.save()\n cropCtx.beginPath()\n cropCtx.arc(128, 128, 128, 0, Math.PI * 2)\n cropCtx.clip()\n \n // Calculate the crop area\n const cropX = canvasSize.value / 2 - cropRadius.value\n const cropY = canvasSize.value / 2 - cropRadius.value\n const cropSize = cropRadius.value * 2\n \n // Draw the cropped area\n cropCtx.drawImage(\n canvas.value,\n cropX, cropY, cropSize, cropSize,\n 0, 0, 256, 256\n )\n \n cropCtx.restore()\n \n // Convert to blob\n cropCanvas.toBlob((blob) => {\n if (blob) {\n const file = new File([blob], 'avatar.jpg', { type: 'image/jpeg' })\n emit('upload', file)\n }\n }, 'image/jpeg', 0.9)\n}\n\nconst changePhoto = () => {\n // Trigger file input to select a new photo\n triggerFileUpload()\n}\n\nconst clearImage = () => {\n imageData.value = ''\n originalImage.value = undefined\n \n // Reset all state to defaults\n zoom.value = 1\n minZoom.value = 0.1\n imagePos.x = 0\n imagePos.y = 0\n \n if (fileInput.value) {\n fileInput.value.value = ''\n }\n}\n\n// Watch zoom changes and maintain canvas center-based zoom\nwatch(zoom, (newZoom, oldZoom) => {\n if (isResetting.value || isWheelZooming.value) {\n // Skip during reset operations or wheel zooming\n return\n }\n \n if (newZoom !== oldZoom && originalImage.value && oldZoom > 0 && oldZoom !== 1) {\n // Only adjust position if this isn't the initial load (oldZoom !== 1)\n // This handles zoom changes from the slider - always zoom from canvas center\n const img = originalImage.value\n const canvasCenter = canvasSize.value / 2\n \n // Calculate current dimensions\n const oldWidth = img.width * oldZoom\n const oldHeight = img.height * oldZoom\n \n // Calculate new dimensions\n const newWidth = img.width * newZoom\n const newHeight = img.height * newZoom\n \n // Calculate current position relative to canvas center\n const currentCenterOffsetX = (imagePos.x + oldWidth / 2) - canvasCenter\n const currentCenterOffsetY = (imagePos.y + oldHeight / 2) - canvasCenter\n \n // Scale the offset by the zoom ratio to maintain the same relative position\n const zoomRatio = newZoom / oldZoom\n const newCenterOffsetX = currentCenterOffsetX * zoomRatio\n const newCenterOffsetY = currentCenterOffsetY * zoomRatio\n \n // Calculate new position that keeps the same point under the canvas center\n imagePos.x = canvasCenter + newCenterOffsetX - newWidth / 2\n imagePos.y = canvasCenter + newCenterOffsetY - newHeight / 2\n }\n \n updateCanvas()\n})\n\n// Watch for preselected file\nwatch(() => props.preselectedFile, (file) => {\n if (file) {\n processFile(file)\n }\n}, { immediate: true })\n</script>\n\n<style>\n.avatar-editor-simple {\n width: 100%;\n}\n\n/* Upload Area */\n.upload-area {\n border: 2px dashed #e5e7eb;\n border-radius: 12px;\n padding: 3rem;\n text-align: center;\n cursor: pointer;\n transition: all 0.2s;\n background: white;\n}\n\n.upload-area:hover {\n border-color: #ea00a8;\n background: #fef2f9;\n}\n\n.upload-content {\n display: flex;\n flex-direction: column;\n align-items: center;\n}\n\n.upload-icon {\n width: 3rem;\n height: 3rem;\n color: #9ca3af;\n margin-bottom: 1rem;\n}\n\n.upload-title {\n font-size: 1.125rem;\n font-weight: 600;\n color: #111827;\n margin-bottom: 0.25rem;\n}\n\n.upload-subtitle {\n font-size: 0.875rem;\n color: #6b7280;\n margin-bottom: 1rem;\n}\n\n.upload-formats {\n display: flex;\n gap: 0.5rem;\n justify-content: center;\n font-size: 0.75rem;\n color: #9ca3af;\n}\n\n.format-tag {\n padding: 0.25rem 0.5rem;\n background-color: #f3f4f6;\n border-radius: 0.25rem;\n}\n\n.hidden-input {\n display: none;\n}\n\n/* Editor Container */\n.editor-container {\n display: flex;\n gap: 2rem;\n}\n\n.editor-main {\n flex: 1;\n}\n\n/* Canvas Container */\n.canvas-container {\n position: relative;\n width: 300px;\n height: 300px;\n margin: 0 auto;\n border-radius: 12px;\n overflow: hidden;\n background: #f9fafb;\n box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1);\n}\n\n.canvas {\n display: block;\n cursor: move;\n}\n\n.crop-overlay {\n position: absolute;\n inset: 0;\n pointer-events: none;\n}\n\n.crop-backdrop {\n position: absolute;\n inset: 0;\n}\n\n.crop-svg {\n position: absolute;\n inset: 0;\n width: 100%;\n height: 100%;\n pointer-events: none;\n}\n\n.crop-circle {\n filter: drop-shadow(0 4px 3px rgba(0, 0, 0, 0.07)) drop-shadow(0 2px 2px rgba(0, 0, 0, 0.06));\n}\n\n.zoom-icon {\n width: 1rem;\n height: 1rem;\n}\n\n.preview-title {\n font-size: 0.875rem;\n font-weight: 500;\n color: #374151;\n margin-bottom: 0.75rem;\n}\n\n.preview-instructions {\n font-size: 0.75rem;\n color: #6b7280;\n margin-top: 0.75rem;\n text-align: center;\n}\n\n/* Controls */\n.controls {\n margin-top: 1.5rem;\n space-y: 1rem;\n}\n\n.zoom-control {\n display: flex;\n align-items: center;\n gap: 0.75rem;\n background: white;\n padding: 0.75rem;\n border-radius: 8px;\n border: 1px solid #e5e7eb;\n}\n\n.zoom-button {\n width: 32px;\n height: 32px;\n display: flex;\n align-items: center;\n justify-content: center;\n background: #f3f4f6;\n border: 1px solid #e5e7eb;\n border-radius: 6px;\n color: #4b5563;\n cursor: pointer;\n transition: all 0.15s;\n}\n\n.zoom-button:hover {\n background: #e5e7eb;\n color: #1f2937;\n}\n\n.zoom-slider {\n flex: 1;\n height: 6px;\n background: #e5e7eb;\n border-radius: 3px;\n outline: none;\n -webkit-appearance: none;\n}\n\n.zoom-slider::-webkit-slider-thumb {\n -webkit-appearance: none;\n width: 18px;\n height: 18px;\n background: #ea00a8;\n border: 2px solid white;\n border-radius: 50%;\n cursor: pointer;\n box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);\n}\n\n.zoom-slider::-moz-range-thumb {\n width: 18px;\n height: 18px;\n background: #ea00a8;\n border: 2px solid white;\n border-radius: 50%;\n cursor: pointer;\n box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);\n}\n\n/* Action Buttons */\n.action-buttons {\n display: flex;\n gap: 0.75rem;\n margin-top: 1rem;\n}\n\n.btn-primary,\n.btn-secondary {\n padding: 0.625rem 1.25rem;\n border-radius: 8px;\n font-size: 0.875rem;\n font-weight: 500;\n cursor: pointer;\n transition: all 0.15s;\n border: 1px solid transparent;\n}\n\n.btn-primary {\n background: #ea00a8;\n color: white;\n flex: 1;\n}\n\n.btn-primary:hover:not(:disabled) {\n background: #d10096;\n}\n\n.btn-primary:disabled {\n opacity: 0.5;\n cursor: not-allowed;\n}\n\n.btn-secondary {\n background: white;\n color: #4b5563;\n border-color: #e5e7eb;\n}\n\n.btn-secondary:hover {\n background: #f9fafb;\n color: #1f2937;\n}\n\n/* Preview Section */\n.preview-section {\n width: 150px;\n padding: 1rem;\n background: white;\n border: 1px solid #e5e7eb;\n border-radius: 12px;\n height: fit-content;\n}\n\n.preview-container {\n width: 100px;\n height: 100px;\n margin: 0 auto;\n border-radius: 50%;\n overflow: hidden;\n border: 2px solid #e5e7eb;\n background: white;\n}\n\n.preview-canvas {\n display: block;\n width: 100%;\n height: 100%;\n}\n</style>","/**\n * Sound effects utility functions using Web Audio API\n * These generate sounds programmatically without needing external audio files\n */\n\nexport class SoundEffects {\n private static audioContext: AudioContext | null = null;\n\n /**\n * Get or create a shared AudioContext\n */\n private static getAudioContext(): AudioContext | null {\n try {\n if (!this.audioContext) {\n this.audioContext = new (window.AudioContext || (window as any).webkitAudioContext)();\n }\n // Resume context if it's suspended (some browsers require user interaction)\n if (this.audioContext.state === 'suspended') {\n this.audioContext.resume();\n }\n return this.audioContext;\n } catch (error) {\n console.warn('Audio context not available:', error);\n return null;\n }\n }\n\n /**\n * Play a level up sound effect\n * A pleasant major chord with arpeggio and bell overtones\n */\n static playLevelUp(level?: number, userSettings?: any): void {\n const milestones = [10, 25, 50, 100, 150, 200];\n const isMilestone = level && milestones.includes(level);\n \n // Check user settings for audio preferences\n if (userSettings) {\n // For milestone levels, check milestone sounds setting\n if (isMilestone && userSettings.milestoneSounds === false) {\n return;\n }\n // For regular levels, check level up sounds setting\n if (!isMilestone && userSettings.levelUpSounds === false) {\n return;\n }\n }\n \n if (isMilestone) {\n this.playMilestoneLevelUp();\n } else {\n this.playRegularLevelUp();\n }\n }\n\n /**\n * Play regular level up sound for normal levels\n */\n private static playRegularLevelUp(): void {\n const audioContext = this.getAudioContext();\n if (!audioContext) return;\n\n const duration = 0.8;\n const now = audioContext.currentTime;\n \n // Create three oscillators for a pleasant C major chord\n const frequencies = [523.25, 659.25, 783.99]; // C5, E5, G5\n \n frequencies.forEach((freq, index) => {\n const oscillator = audioContext.createOscillator();\n const gainNode = audioContext.createGain();\n \n oscillator.connect(gainNode);\n gainNode.connect(audioContext.destination);\n \n // Use sine wave for a clean, pleasant sound\n oscillator.type = 'sine';\n oscillator.frequency.setValueAtTime(freq, now);\n \n // Add a slight pitch bend up for a magical effect\n oscillator.frequency.exponentialRampToValueAtTime(freq * 1.05, now + duration * 0.1);\n oscillator.frequency.exponentialRampToValueAtTime(freq * 1.02, now + duration);\n \n // Volume envelope with delay for each note (arpeggio effect)\n const delay = index * 0.05;\n gainNode.gain.setValueAtTime(0, now);\n gainNode.gain.linearRampToValueAtTime(0.15, now + delay + 0.02);\n gainNode.gain.exponentialRampToValueAtTime(0.01, now + delay + duration);\n \n oscillator.start(now + delay);\n oscillator.stop(now + delay + duration);\n });\n \n // Add a subtle bell/chime overtone\n const bellOscillator = audioContext.createOscillator();\n const bellGain = audioContext.createGain();\n \n bellOscillator.connect(bellGain);\n bellGain.connect(audioContext.destination);\n \n bellOscillator.type = 'triangle';\n bellOscillator.frequency.setValueAtTime(1046.5, now); // C6\n \n bellGain.gain.setValueAtTime(0, now);\n bellGain.gain.linearRampToValueAtTime(0.08, now + 0.01);\n bellGain.gain.exponentialRampToValueAtTime(0.001, now + 0.3);\n \n bellOscillator.start(now);\n bellOscillator.stop(now + 0.3);\n }\n\n /**\n * Play epic milestone level up sound for special levels (10, 25, 50, 100, 150, 200)\n * A longer, more elaborate celebration with multiple chord progressions\n */\n private static playMilestoneLevelUp(): void {\n const audioContext = this.getAudioContext();\n if (!audioContext) return;\n\n const now = audioContext.currentTime;\n \n // Extended duration for milestone celebration\n const totalDuration = 2.5;\n \n // First chord progression: C Major -> F Major -> G Major -> C Major\n const chordProgression = [\n { time: 0.0, frequencies: [523.25, 659.25, 783.99] }, // C Major (C5, E5, G5)\n { time: 0.4, frequencies: [587.33, 698.46, 880.00] }, // F Major (D5, F5, A5)\n { time: 0.8, frequencies: [622.25, 783.99, 987.77] }, // G Major (D#5, G5, B5)\n { time: 1.2, frequencies: [523.25, 659.25, 783.99] }, // C Major (C5, E5, G5)\n ];\n \n // Play chord progression\n chordProgression.forEach((chord, chordIndex) => {\n chord.frequencies.forEach((freq, noteIndex) => {\n const oscillator = audioContext.createOscillator();\n const gainNode = audioContext.createGain();\n \n oscillator.connect(gainNode);\n gainNode.connect(audioContext.destination);\n \n oscillator.type = 'sine';\n oscillator.frequency.setValueAtTime(freq, now + chord.time);\n \n // Add slight pitch bend for magic\n oscillator.frequency.exponentialRampToValueAtTime(freq * 1.03, now + chord.time + 0.05);\n oscillator.frequency.exponentialRampToValueAtTime(freq * 1.01, now + chord.time + 0.35);\n \n // Staggered note delays for arpeggio effect\n const noteDelay = noteIndex * 0.03;\n gainNode.gain.setValueAtTime(0, now + chord.time);\n gainNode.gain.linearRampToValueAtTime(0.12, now + chord.time + noteDelay + 0.02);\n gainNode.gain.exponentialRampToValueAtTime(0.02, now + chord.time + 0.35);\n gainNode.gain.exponentialRampToValueAtTime(0.001, now + chord.time + 0.4);\n \n oscillator.start(now + chord.time + noteDelay);\n oscillator.stop(now + chord.time + 0.45);\n });\n });\n \n // High-frequency sparkle effects throughout\n for (let i = 0; i < 8; i++) {\n const sparkleTime = now + 0.2 + (i * 0.15);\n const sparkleOsc = audioContext.createOscillator();\n const sparkleGain = audioContext.createGain();\n \n sparkleOsc.connect(sparkleGain);\n sparkleGain.connect(audioContext.destination);\n \n sparkleOsc.type = 'sine';\n const sparkleFreq = 1568 + (Math.random() * 800); // High frequencies for sparkle\n sparkleOsc.frequency.setValueAtTime(sparkleFreq, sparkleTime);\n sparkleOsc.frequency.exponentialRampToValueAtTime(sparkleFreq * 1.5, sparkleTime + 0.1);\n \n sparkleGain.gain.setValueAtTime(0, sparkleTime);\n sparkleGain.gain.linearRampToValueAtTime(0.06, sparkleTime + 0.01);\n sparkleGain.gain.exponentialRampToValueAtTime(0.001, sparkleTime + 0.12);\n \n sparkleOsc.start(sparkleTime);\n sparkleOsc.stop(sparkleTime + 0.15);\n }\n \n // Grand finale - triumphant high C chord\n const finaleTime = now + 1.6;\n const finaleFrequencies = [1046.5, 1318.5, 1567.98]; // C6, E6, G6\n \n finaleFrequencies.forEach((freq, index) => {\n const oscillator = audioContext.createOscillator();\n const gainNode = audioContext.createGain();\n \n oscillator.connect(gainNode);\n gainNode.connect(audioContext.destination);\n \n oscillator.type = 'triangle'; // Triangle wave for bell-like quality\n oscillator.frequency.setValueAtTime(freq, finaleTime);\n oscillator.frequency.exponentialRampToValueAtTime(freq * 1.02, finaleTime + 0.8);\n \n const delay = index * 0.02;\n gainNode.gain.setValueAtTime(0, finaleTime);\n gainNode.gain.linearRampToValueAtTime(0.15, finaleTime + delay + 0.03);\n gainNode.gain.exponentialRampToValueAtTime(0.001, finaleTime + 0.9);\n \n oscillator.start(finaleTime + delay);\n oscillator.stop(finaleTime + 0.95);\n });\n }\n\n /**\n * Play a success/completion sound\n * A short, bright confirmation tone\n */\n static playSuccess(): void {\n const audioContext = this.getAudioContext();\n if (!audioContext) return;\n\n const now = audioContext.currentTime;\n \n // Two quick ascending notes\n const frequencies = [659.25, 830.61]; // E5, G#5\n \n frequencies.forEach((freq, index) => {\n const oscillator = audioContext.createOscillator();\n const gainNode = audioContext.createGain();\n \n oscillator.connect(gainNode);\n gainNode.connect(audioContext.destination);\n \n oscillator.type = 'sine';\n oscillator.frequency.setValueAtTime(freq, now);\n \n const delay = index * 0.1;\n const duration = 0.15;\n \n gainNode.gain.setValueAtTime(0, now);\n gainNode.gain.linearRampToValueAtTime(0.2, now + delay + 0.01);\n gainNode.gain.exponentialRampToValueAtTime(0.01, now + delay + duration);\n \n oscillator.start(now + delay);\n oscillator.stop(now + delay + duration);\n });\n }\n\n /**\n * Play an error/failure sound\n * A low, descending tone\n */\n static playError(): void {\n const audioContext = this.getAudioContext();\n if (!audioContext) return;\n\n const now = audioContext.currentTime;\n const oscillator = audioContext.createOscillator();\n const gainNode = audioContext.createGain();\n \n oscillator.connect(gainNode);\n gainNode.connect(audioContext.destination);\n \n oscillator.type = 'sawtooth';\n oscillator.frequency.setValueAtTime(200, now);\n oscillator.frequency.exponentialRampToValueAtTime(100, now + 0.3);\n \n gainNode.gain.setValueAtTime(0.15, now);\n gainNode.gain.exponentialRampToValueAtTime(0.01, now + 0.3);\n \n oscillator.start(now);\n oscillator.stop(now + 0.3);\n }\n\n /**\n * Play a click/button press sound\n * A very short, soft click\n */\n static playClick(): void {\n const audioContext = this.getAudioContext();\n if (!audioContext) return;\n\n const now = audioContext.currentTime;\n const oscillator = audioContext.createOscillator();\n const gainNode = audioContext.createGain();\n \n oscillator.connect(gainNode);\n gainNode.connect(audioContext.destination);\n \n oscillator.type = 'sine';\n oscillator.frequency.setValueAtTime(1000, now);\n \n gainNode.gain.setValueAtTime(0.1, now);\n gainNode.gain.exponentialRampToValueAtTime(0.01, now + 0.03);\n \n oscillator.start(now);\n oscillator.stop(now + 0.03);\n }\n\n /**\n * Play a notification sound\n * A gentle two-tone chime\n */\n static playNotification(): void {\n const audioContext = this.getAudioContext();\n if (!audioContext) return;\n\n const now = audioContext.currentTime;\n const frequencies = [880, 1174.66]; // A5, D6\n \n frequencies.forEach((freq, index) => {\n const oscillator = audioContext.createOscillator();\n const gainNode = audioContext.createGain();\n \n oscillator.connect(gainNode);\n gainNode.connect(audioContext.destination);\n \n oscillator.type = 'sine';\n oscillator.frequency.setValueAtTime(freq, now);\n \n const delay = index * 0.15;\n gainNode.gain.setValueAtTime(0, now);\n gainNode.gain.linearRampToValueAtTime(0.12, now + delay + 0.02);\n gainNode.gain.exponentialRampToValueAtTime(0.01, now + delay + 0.4);\n \n oscillator.start(now + delay);\n oscillator.stop(now + delay + 0.4);\n });\n }\n\n /**\n * Play an XP gain sound\n * A quick, ascending glissando\n */\n static playXpGain(): void {\n const audioContext = this.getAudioContext();\n if (!audioContext) return;\n\n const now = audioContext.currentTime;\n const oscillator = audioContext.createOscillator();\n const gainNode = audioContext.createGain();\n \n oscillator.connect(gainNode);\n gainNode.connect(audioContext.destination);\n \n oscillator.type = 'sine';\n oscillator.frequency.setValueAtTime(440, now); // A4\n oscillator.frequency.exponentialRampToValueAtTime(880, now + 0.15); // A5\n \n gainNode.gain.setValueAtTime(0, now);\n gainNode.gain.linearRampToValueAtTime(0.15, now + 0.01);\n gainNode.gain.exponentialRampToValueAtTime(0.01, now + 0.2);\n \n oscillator.start(now);\n oscillator.stop(now + 0.2);\n }\n}\n\n// Export individual functions for convenience\nexport const playLevelUp = (level?: number, userSettings?: any) => SoundEffects.playLevelUp(level, userSettings);\nexport const playSuccess = () => SoundEffects.playSuccess();\nexport const playError = () => SoundEffects.playError();\nexport const playClick = () => SoundEffects.playClick();\nexport const playNotification = () => SoundEffects.playNotification();\nexport const playXpGain = () => SoundEffects.playXpGain();","<template>\n <div class=\"level-progress-container\">\n <svg :width=\"size\" :height=\"size\" :viewBox=\"`0 0 ${viewBox} ${viewBox}`\" style=\"position: relative;\">\n <!-- Level Up Overlay -->\n <g v-if=\"levelUpActive\">\n <circle\n :cx=\"center\"\n :cy=\"center\"\n :r=\"innerCircleRadius\"\n fill=\"#a800ff\"\n opacity=\"0.92\"\n />\n <text\n :x=\"center\"\n :y=\"center + 15\"\n text-anchor=\"middle\"\n font-size=\"38\"\n font-weight=\"bold\"\n fill=\"#fff\"\n style=\"font-family: 'Montserrat', sans-serif;\"\n >Level Up</text>\n </g>\n \n <!-- Background Arc (gray portion) -->\n <path\n v-if=\"animatedValue >= 0 && animatedValue < props.max\"\n :d=\"backgroundArcPath\"\n stroke=\"#ddd\"\n :stroke-width=\"thickness\"\n fill=\"none\"\n stroke-linecap=\"round\"\n />\n \n <!-- Label Arc (top, thicker) -->\n <path\n :d=\"staticArcPath\"\n :stroke=\"staticArcGradient\"\n :stroke-width=\"labelThickness\"\n fill=\"none\"\n stroke-linecap=\"round\"\n />\n \n <!-- Invisible arc for curved label text -->\n <path\n :id=\"'labelTextArc'\"\n :d=\"labelTextArcPath\"\n stroke=\"transparent\"\n fill=\"none\"\n transform=\"scale(-1, 1) translate(-400, 0)\"\n />\n \n <!-- Progress Arc (XP bar) -->\n <path\n v-if=\"animatedValue > 0 && animatedValue < props.max\"\n :d=\"progressArcPath\"\n :stroke=\"progressArcGradient\"\n :stroke-width=\"thickness\"\n fill=\"none\"\n stroke-linecap=\"round\"\n />\n \n <!-- Curved Label Text -->\n <text \n font-size=\"30\" \n font-weight=\"bold\" \n fill=\"var(--purple-100)\" \n style=\"font-family: 'Montserrat', sans-serif; letter-spacing: 8px;\"\n >\n <textPath\n xlink:href=\"#labelTextArc\"\n startOffset=\"50%\"\n text-anchor=\"middle\"\n alignment-baseline=\"hanging\"\n dominant-baseline=\"hanging\"\n text-length=\"100%\"\n >\n {{ levelLabel }}\n </textPath>\n </text>\n \n <!-- Gradient Definitions -->\n <defs>\n <linearGradient id=\"staticGradient\" x1=\"0\" y1=\"0\" x2=\"1\" y2=\"0\">\n <stop offset=\"0%\" stop-color=\"var(--strands-500)\" />\n <stop offset=\"100%\" stop-color=\"var(--strands-600)\" />\n </linearGradient>\n\n <linearGradient \n id=\"progressGradient\" \n gradientUnits=\"userSpaceOnUse\" \n :x1=\"progressGradientStart.x\" \n :y1=\"progressGradientStart.y\" \n :x2=\"progressGradientEnd.x\" \n :y2=\"progressGradientEnd.y\"\n >\n <stop offset=\"0%\" stop-color=\"var(--strands-600)\" />\n <stop offset=\"100%\" stop-color=\"var(--strands-400)\" />\n </linearGradient>\n </defs>\n </svg>\n </div>\n</template>\n\n<script setup lang=\"ts\">\nimport { computed, ref, watch } from 'vue';\nimport { playLevelUp } from '../utils/sounds';\n\n// ============================================================================\n// Props & Emits\n// ============================================================================\nconst props = defineProps<{\n value: number;\n max: number;\n level: number;\n levelLabel?: string;\n size?: number;\n thickness?: number;\n labelThickness?: number;\n staticArcAngle?: number;\n gapAngle?: number;\n userSettings?: any;\n}>();\n\nconst emit = defineEmits(['levelup']);\n\n// ============================================================================\n// Constants & Configuration\n// ============================================================================\nconst VIEW_BOX_SIZE = 400;\nconst ARC_PADDING = 18; // Extra space from edge\nconst INNER_GAP = 18; // Gap between progress ring and inner circle\nconst ANIMATION_DURATION = 600; // ms\n\n// Label arc configuration\nconst LABEL_SPACING = 8; // px, matches letter-spacing in template\nconst LABEL_FONT_SIZE = 30; // px, matches font-size in template\nconst LABEL_EXTRA_DEGREES = 12; // Extra spacing in degrees\nconst LABEL_CHAR_DEGREES = 8; // Degrees per character\n\n// ============================================================================\n// Component State\n// ============================================================================\nconst levelUpActive = ref(false);\nconst animatedValue = ref(props.value);\nconst animationDirection = ref<'forward' | 'backward'>('forward');\nlet animationFrame: number | null = null;\nlet prevValue = props.value;\nlet prevLevel = props.level;\n\n// ============================================================================\n// Computed Properties - Dimensions\n// ============================================================================\nconst viewBox = VIEW_BOX_SIZE;\nconst size = props.size ?? VIEW_BOX_SIZE;\nconst center = VIEW_BOX_SIZE / 2;\nconst thickness = computed(() => props.thickness ?? 24);\nconst labelThickness = computed(() => props.labelThickness ?? 46);\nconst gapAngle = computed(() => props.gapAngle ?? 16);\n\n// Radius calculations\nconst radius = computed(() => (VIEW_BOX_SIZE - thickness.value) / 2 - ARC_PADDING);\nconst labelRadius = computed(() => (VIEW_BOX_SIZE - labelThickness.value) / 1.9 - ARC_PADDING);\nconst textLabelRadius = computed(() => labelRadius.value + 10);\nconst innerCircleRadius = computed(() => radius.value - thickness.value / 2 - INNER_GAP);\n\n// ============================================================================\n// Computed Properties - Arc Angles\n// ============================================================================\nconst labelLength = computed(() => props.levelLabel?.length ?? 0);\nconst staticArcAngle = computed(() => {\n // Estimate arc angle needed for label\n return labelLength.value * LABEL_CHAR_DEGREES + LABEL_EXTRA_DEGREES;\n});\n\nconst labelStart = computed(() => -staticArcAngle.value / 2);\nconst labelEnd = computed(() => staticArcAngle.value / 2);\n\n// ============================================================================\n// Computed Properties - Arc Paths\n// ============================================================================\nconst staticArcPath = computed(() =>\n describeArc(center, center, labelRadius.value, labelStart.value, labelEnd.value)\n);\n\nconst labelTextArcPath = computed(() =>\n // Top arc: right to left, so text is right-side up at the top after rotation\n describeArc(center, center, textLabelRadius.value, -90, 90)\n);\n\nconst progressArcPath = computed(() => {\n const xpArcStart = labelEnd.value + gapAngle.value;\n const availableSweep = 360 - staticArcAngle.value - 3 * gapAngle.value;\n const progress = Math.max(0, Math.min(1, animatedValue.value / props.max));\n const xpArcSweep = availableSweep * progress;\n const xpArcEnd = xpArcStart + xpArcSweep;\n return describeArc(center, center, radius.value, xpArcStart, xpArcEnd);\n});\n\nconst backgroundArcPath = computed(() => {\n const xpArcStart = labelEnd.value + gapAngle.value;\n const availableSweep = 360 - staticArcAngle.value - 3 * gapAngle.value;\n const progress = Math.max(0, Math.min(1, animatedValue.value / props.max));\n const xpArcSweep = availableSweep * progress;\n const xpArcEnd = xpArcStart + xpArcSweep;\n const grayArcStart = progress === 0 ? xpArcStart : xpArcEnd + gapAngle.value;\n const grayArcEnd = labelStart.value - gapAngle.value + 360;\n return describeArc(center, center, radius.value, grayArcStart, grayArcEnd);\n});\n\n// ============================================================================\n// Computed Properties - Gradients\n// ============================================================================\nconst staticArcGradient = computed(() => 'url(#staticGradient)');\nconst progressArcGradient = computed(() => 'url(#progressGradient)');\n\nconst progressGradientStart = computed(() => {\n const xpArcStart = labelEnd.value + gapAngle.value;\n return polarToCartesian(center, center, radius.value, xpArcStart);\n});\n\nconst progressGradientEnd = computed(() => {\n const xpArcStart = labelEnd.value + gapAngle.value;\n const availableSweep = 360 - staticArcAngle.value - 3 * gapAngle.value;\n const progress = Math.max(0, Math.min(1, animatedValue.value / props.max));\n const xpArcSweep = availableSweep * progress;\n const xpArcEnd = xpArcStart + xpArcSweep;\n return polarToCartesian(center, center, radius.value, xpArcEnd);\n});\n\n// ============================================================================\n// Helper Functions\n// ============================================================================\nfunction polarToCartesian(cx: number, cy: number, r: number, angle: number) {\n const rad = (angle - 90) * Math.PI / 180.0;\n return {\n x: cx + r * Math.cos(rad),\n y: cy + r * Math.sin(rad),\n };\n}\n\nfunction describeArc(cx: number, cy: number, r: number, startAngle: number, endAngle: number) {\n const start = polarToCartesian(cx, cy, r, endAngle % 360);\n const end = polarToCartesian(cx, cy, r, startAngle % 360);\n const sweep = ((endAngle - startAngle + 360) % 360);\n const largeArcFlag = sweep <= 180 ? '0' : '1';\n return [\n 'M', start.x, start.y,\n 'A', r, r, 0, largeArcFlag, 0, end.x, end.y\n ].join(' ');\n}\n\nfunction easeInOut(t: number) {\n return t < 0.5 ? 2 * t * t : -1 + (4 - 2 * t) * t;\n}\n\n// ============================================================================\n// Animation Functions\n// ============================================================================\nfunction animateProgress(newValue: number, oldValue: number) {\n if (animationFrame) cancelAnimationFrame(animationFrame);\n \n const start = oldValue;\n const change = newValue - start;\n const startTime = performance.now();\n \n function step(now: number) {\n const elapsed = now - startTime;\n const t = Math.min(elapsed / ANIMATION_DURATION, 1);\n const eased = easeInOut(t);\n animatedValue.value = start + change * eased;\n \n if (t < 1) {\n animationFrame = requestAnimationFrame(step);\n } else {\n animatedValue.value = newValue;\n animationFrame = null;\n }\n }\n \n animationFrame = requestAnimationFrame(step);\n}\n\nfunction triggerLevelUp() {\n levelUpActive.value = true;\n playLevelUp(props.level, props.userSettings);\n emit('levelup');\n \n // Check if this is a milestone level for longer display\n const milestones = [10, 25, 50, 100, 150, 200];\n const isMilestone = milestones.includes(props.level);\n \n setTimeout(() => {\n levelUpActive.value = false;\n }, isMilestone ? 2000 : 1200);\n}\n\n// ============================================================================\n// Watchers\n// ============================================================================\nwatch(() => props.value, (newValue) => {\n animationDirection.value = newValue >= prevValue ? 'forward' : 'backward';\n animateProgress(newValue, prevValue);\n prevValue = newValue;\n});\n\nwatch(() => props.level, (newLevel) => {\n if (newLevel !== prevLevel && newLevel > prevLevel) {\n triggerLevelUp();\n }\n prevLevel = newLevel;\n});\n</script>\n\n<style scoped>\n.level-progress-container {\n display: flex;\n align-items: center;\n justify-content: center;\n padding: 12px;\n}\n</style>","<template>\n <div class=\"accui-component-scope\">\n\t<teleport to=\"body\">\n\t\t<div v-if=\"open\" class=\"modal-overlay\" @click=\"handleOverlayClick\">\n\t\t\t<div \n\t\t\t\tclass=\"modal-container\" \n\t\t\t\t:class=\"{ 'modal-container-fullscreen-mobile': fullscreenOnMobile }\"\n\t\t\t\t@click.stop\n\t\t\t>\n\t\t\t\t<div class=\"modal-card\">\n\t\t\t\t\t<div v-if=\"$slots['header']\" class=\"modal-header\">\n\t\t\t\t\t\t<slot name=\"header\" />\n\t\t\t\t\t</div>\n\t\t\t\t\t\n\t\t\t\t\t<div class=\"modal-content\">\n\t\t\t\t\t\t<slot />\n\t\t\t\t\t</div>\n\t\t\t\t\t\n\t\t\t\t\t<div v-if=\"$slots['footer']\" class=\"modal-footer\">\n\t\t\t\t\t\t<slot name=\"footer\" />\n\t\t\t\t\t</div>\n\t\t\t\t</div>\n\t\t\t</div>\n\t\t</div>\n\t</teleport>\n </div>\n</template>\n\n<script setup lang=\"ts\">\ninterface Props {\n\topen?: boolean\n\tcloseOnOverlayClick?: boolean\n\tfullscreenOnMobile?: boolean\n}\n\nconst props = withDefaults(defineProps<Props>(), {\n\topen: false,\n\tcloseOnOverlayClick: true,\n\tfullscreenOnMobile: true\n})\n\nconst emit = defineEmits<{\n\tclose: []\n}>()\n\nconst handleOverlayClick = () => {\n\tif (props.closeOnOverlayClick) {\n\t\temit('close')\n\t}\n}\n</script>\n\n<style scoped>\n.modal-overlay {\n\tposition: fixed;\n\ttop: 0;\n\tleft: 0;\n\tright: 0;\n\tbottom: 0;\n\tbackground: rgba(0, 0, 0, 0.8);\n\tdisplay: flex;\n\talign-items: center;\n\tjustify-content: center;\n\tpadding: 1rem;\n\tz-index: 9999999999;\n\tfont-family: var(--font-sans);\n\t-webkit-font-smoothing: antialiased;\n}\n\n.modal-container {\n\tbackground: white;\n\tborder-radius: 0.5rem;\n\tbox-shadow: 0 25px 50px -12px rgba(0, 0, 0, 0.25);\n\tpadding: 1.5rem;\n\tmax-width: calc(100vw - 2rem);\n\tmax-height: calc(100vh - 2rem);\n\toverflow-y: auto;\n\twidth: auto;\n}\n\n.modal-header {\n\tpadding-bottom: 1rem;\n\tborder-bottom: 1px solid #e5e7eb;\n\tmargin-bottom: 1.5rem;\n}\n\n.modal-footer {\n\tpadding-top: 1rem;\n\tborder-top: 1px solid #e5e7eb;\n\tmargin-top: 1.5rem;\n}\n\n/* Fullscreen on mobile */\n@media (max-width: 768px) {\n\t.modal-container-fullscreen-mobile {\n\t\twidth: 100vw;\n\t\theight: 100vh;\n\t\tmax-width: 100vw;\n\t\tmax-height: 100vh;\n\t\tborder-radius: 0;\n\t\tpadding: 1rem;\n\t}\n}\n\n/* Scrollbar styling */\n.modal-container::-webkit-scrollbar {\n\twidth: 6px;\n}\n\n.modal-container::-webkit-scrollbar-track {\n\tbackground: #f1f5f9;\n\tborder-radius: 3px;\n}\n\n.modal-container::-webkit-scrollbar-thumb {\n\tbackground: #cbd5e1;\n\tborder-radius: 3px;\n}\n\n.modal-container::-webkit-scrollbar-thumb:hover {\n\tbackground: #94a3b8;\n}\n</style>","<template>\n <div class=\"accui-component-scope\">\n <div v-if=\"shouldShowSecuredBy\"\n class=\"secured-footer\"\n :class=\"{ 'secured-footer-with-content': hasDefaultSlot, 'secured-footer-centered': !hasDefaultSlot }\">\n <slot name=\"default\" />\n\n <!-- Secured by logo - Right side when sign out present, center when alone -->\n <div v-if=\"shouldShowSecuredBy\" class=\"secured-logo\">\n <img :src=\"securedByLogo\" class=\"secured-logo-image\" />\n </div>\n </div>\n </div>\n</template>\n\n<script setup lang=\"ts\">\nimport { computed, useSlots } from 'vue'\nimport { useStrandsConfig, type StrandsAuthConfig } from '../composables/useStrandsConfig'\nimport { slotHasContent } from '../../utils/slots'\nimport securedByLogo from '@/assets/secured_by_strands_services.png'\n\ninterface Props {\n config?: StrandsAuthConfig\n}\n\nconst props = withDefaults(defineProps<Props>(), {})\n\n// Get configuration\nconst { config } = useStrandsConfig(props.config)\n\n// Hide \"Secured by\" logo when using Strands' own domain\nconst shouldShowSecuredBy = computed(() => {\n const baseUrl = config.value.baseUrl\n return baseUrl !== 'https://accounts.strands.gg'\n})\n\nconst slots = useSlots()\nconst hasDefaultSlot = computed(() => slotHasContent('default', slots))\n</script>\n\n<style scoped>\n.secured-footer {\n display: flex;\n align-items: center;\n gap: 0.5rem;\n padding-top: 1rem;\n border-top: 1px solid #e5e7eb;\n}\n\n.secured-footer-with-content {\n justify-content: space-between;\n}\n\n.secured-footer-centered {\n justify-content: center;\n}\n\n.secured-logo {\n flex-shrink: 0;\n}\n\n.secured-logo-image {\n height: 2rem;\n}\n</style>","export const slotHasContent = (slotName: string, slots: any) => {\n const slot = slots[slotName];\n if (!slot) return false;\n if (typeof slot === 'function') {\n const vnodes = slot();\n return Array.isArray(vnodes) && vnodes.length > 0;\n }\n return Array.isArray(slot) && slot.length > 0;\n};","export default \"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAABVgAAAHgCAYAAABQLAbaAAAEt2lUWHRYTUw6Y29tLmFkb2JlLnhtcAAAAAAAPD94cGFja2V0IGJlZ2luPSLvu78iIGlkPSJXNU0wTXBDZWhpSHpyZVN6TlRjemtjOWQiPz4KPHg6eG1wbWV0YSB4bWxuczp4PSJhZG9iZTpuczptZXRhLyIgeDp4bXB0az0iWE1QIENvcmUgNS41LjAiPgogPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4KICA8cmRmOkRlc2NyaXB0aW9uIHJkZjphYm91dD0iIgogICAgeG1sbnM6dGlmZj0iaHR0cDovL25zLmFkb2JlLmNvbS90aWZmLzEuMC8iCiAgICB4bWxuczpleGlmPSJodHRwOi8vbnMuYWRvYmUuY29tL2V4aWYvMS4wLyIKICAgIHhtbG5zOnBob3Rvc2hvcD0iaHR0cDovL25zLmFkb2JlLmNvbS9waG90b3Nob3AvMS4wLyIKICAgIHhtbG5zOnhtcD0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wLyIKICAgIHhtbG5zOnhtcE1NPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvbW0vIgogICAgeG1sbnM6c3RFdnQ9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZUV2ZW50IyIKICAgdGlmZjpJbWFnZUxlbmd0aD0iNDgwIgogICB0aWZmOkltYWdlV2lkdGg9IjEzNjgiCiAgIHRpZmY6UmVzb2x1dGlvblVuaXQ9IjIiCiAgIHRpZmY6WFJlc29sdXRpb249IjcyLzEiCiAgIHRpZmY6WVJlc29sdXRpb249IjcyLzEiCiAgIGV4aWY6UGl4ZWxYRGltZW5zaW9uPSIxMzY4IgogICBleGlmOlBpeGVsWURpbWVuc2lvbj0iNDgwIgogICBleGlmOkNvbG9yU3BhY2U9IjEiCiAgIHBob3Rvc2hvcDpDb2xvck1vZGU9IjMiCiAgIHBob3Rvc2hvcDpJQ0NQcm9maWxlPSJzUkdCIElFQzYxOTY2LTIuMSIKICAgeG1wOk1vZGlmeURhdGU9IjIw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rYdCFBEBYXQHawB8r7uGOCph1YlP9yoKH2PS1V0EEREREREREZlFW8B6BZN5xLgbTELOcR5rdATEp7prOIeru4A4qiAxjZh0rwYAxwMQERERERER0Xu0BawAUIWc0vn4nZIQ66UY7G7fDSSk0R2sYMDasnr36ozuOpqVhNzQXQMRERERERERmUdrwFpfbrv4/7N3P8lNJGvb/79Z5l/E+/ziyBEHA6MuVoBYAWIF2JPGGiFWgFmBzQqAFWBGkj2xWYHFClCvgOoRjdwd0om3z/NiZFX+BlUC4baxZEvKzKrrE8HpPnRj3w1SqerKO+90WcMlVQaYPR16tRCx6wJ+5gomcV1DaAaYN65rmEI/77oXEREREREREfmB04AV4CrXt4C+6zouoTrg6KXrIkogdl3Az1jSkF/DC9el2QBqjsuYhrpXRURERERERORUzgPWZdb6KYR84BVAQ4delduxRgRMrEczNpigFiUizDvXNYiIiIiIiIiIn4zrAka6tA4Iq6PtH1J4fpv1V67rKJpPNOMlzEfXdfzMCuvevJd816X1Aai6rmMK/RXWl10XISIiIiIiIiJ+ct7BOmKwoXexEsHLQ5o113UUzRXPxwMQ9oiLhco7vUMKV0HjAURERERERETkJ7wJWPMDZEI+8AoAi9nr0Yxd1yELlbguIASHNGsWu+W6jmkZ7FvXNYiIiIiIiIiIv7wJWKEQB14BVAaYA4Wss2OIKq5rOEfor9m569GMLeaN6zouIMkXf0RERERERERETuVVwLrMWj/CPHVdxwzECllnJyX1OmBN4T+ua/BZj73KAHOA/6MeThH+6BIRERERERERmS+vAlaAf/N4H2i7rmMG8pB1z+twMAQG4/XvYQQ91zX47JivbwgyXIVhMa5FIiIiIiIiIjJH3gWsAEPsU4qx7ToecKSQ9ZJSrNe/fxb7u+safHXIzkuLXXVdxwVt36GeuC5CRERERERERPzmZcB6h3qSQlG25lYVskoZHbKzabEbruu4qKHGA4iIiIiIiIjIBLwMWAFus/6K4mzPVch6Cb6PCLCYInRbz1Qerm65ruMS2upeFREREREREZFJeBuwQqFGBYBC1guzno8IiLBFeY3ORAHCVYy6V0VERERERERkQl4HrAUbFQAKWaXgihCuAu2b1NuuixARERERERGRMHgdsEI2KsBg9l3XMUPV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\"","import { ref, computed } from 'vue'\nimport type { \n MfaDevice, \n MfaDevicesResponse, \n TotpSetupResponse, \n BackupCodesResponse \n} from '../../types'\nimport { useStrandsConfig } from './useStrandsConfig'\nimport { useStrandsAuth } from './useStrandsAuth'\n\nconst mfaDevices = ref<MfaDevice[]>([])\nconst mfaEnabled = ref(false)\nconst loading = ref(false)\n\nexport function useStrandsMfa() {\n const { getUrl } = useStrandsConfig()\n const { currentSession } = useStrandsAuth()\n\n const hasMfaDevices = computed(() => mfaDevices.value.length > 0)\n // Filter out hardware keys and passkeys temporarily until cross-domain support is implemented\n const activeMfaDevices = computed(() => \n mfaDevices.value.filter(d => \n d.is_active && \n d.device_type !== 'hardware' && \n d.device_type !== 'passkey'\n )\n )\n\n // Helper function to make authenticated requests\n const makeAuthenticatedRequest = async (url: string, options: RequestInit = {}) => {\n if (!currentSession.value?.accessToken) {\n throw new Error('No access token available')\n }\n\n const response = await fetch(url, {\n ...options,\n headers: {\n 'Content-Type': 'application/json',\n 'Authorization': `Bearer ${currentSession.value.accessToken}`,\n ...options.headers,\n },\n })\n\n if (!response.ok) {\n const errorText = await response.text()\n let errorMessage = `Request failed: ${response.status} ${response.statusText}`\n \n try {\n const errorData = JSON.parse(errorText)\n errorMessage = errorData.message || errorMessage\n } catch {\n // If parsing fails, use the original error text\n if (errorText) {\n errorMessage = errorText\n }\n }\n \n throw new Error(errorMessage)\n }\n\n return response.json()\n }\n\n // Get all MFA devices for the user\n const fetchMfaDevices = async (): Promise<MfaDevicesResponse> => {\n loading.value = true\n try {\n const response = await makeAuthenticatedRequest(getUrl('mfaDevices'), {\n method: 'GET',\n })\n\n mfaDevices.value = response.devices || []\n mfaEnabled.value = response.mfa_enabled || false\n\n return response\n } finally {\n loading.value = false\n }\n }\n\n // Setup TOTP (authenticator app)\n const setupTotp = async (deviceName: string): Promise<TotpSetupResponse> => {\n loading.value = true\n try {\n const response = await makeAuthenticatedRequest(getUrl('mfaTotpSetup'), {\n method: 'POST',\n body: JSON.stringify({ device_name: deviceName }),\n })\n\n // Refresh devices list\n await fetchMfaDevices()\n\n return response\n } finally {\n loading.value = false\n }\n }\n\n // Verify TOTP setup\n const verifyTotpSetup = async (deviceId: string, totpCode: string): Promise<void> => {\n loading.value = true\n try {\n await makeAuthenticatedRequest(getUrl('mfaTotpVerify'), {\n method: 'POST',\n body: JSON.stringify({\n device_id: deviceId,\n totp_code: totpCode,\n }),\n })\n\n // Refresh devices list\n await fetchMfaDevices()\n } finally {\n loading.value = false\n }\n }\n\n // Setup email-based MFA\n const setupEmailMfa = async (deviceName: string): Promise<{ device_id: string; email: string }> => {\n loading.value = true\n try {\n const response = await makeAuthenticatedRequest(getUrl('mfaEmailSetup'), {\n method: 'POST',\n body: JSON.stringify({ device_name: deviceName }),\n })\n\n // Refresh devices list\n await fetchMfaDevices()\n\n return response\n } finally {\n loading.value = false\n }\n }\n\n // Send email verification code\n const sendEmailMfaCode = async (deviceId: string): Promise<void> => {\n loading.value = true\n try {\n await makeAuthenticatedRequest(getUrl('mfaEmailSend'), {\n method: 'POST',\n body: JSON.stringify({ device_id: deviceId }),\n })\n } finally {\n loading.value = false\n }\n }\n\n // Verify email MFA code\n const verifyEmailMfaCode = async (deviceId: string, code: string): Promise<boolean> => {\n loading.value = true\n try {\n const response = await makeAuthenticatedRequest(getUrl('mfaEmailVerify'), {\n method: 'POST',\n body: JSON.stringify({\n device_id: deviceId,\n code: code,\n }),\n })\n\n return response.verified || false\n } finally {\n loading.value = false\n }\n }\n\n // Disable an MFA device\n const disableMfaDevice = async (deviceId: string): Promise<void> => {\n loading.value = true\n try {\n await makeAuthenticatedRequest(getUrl('mfaDeviceDisable'), {\n method: 'POST',\n body: JSON.stringify({ device_id: deviceId }),\n })\n\n // Refresh devices list\n await fetchMfaDevices()\n } finally {\n loading.value = false\n }\n }\n\n // Regenerate backup codes for TOTP device\n const regenerateBackupCodes = async (deviceId: string): Promise<BackupCodesResponse> => {\n loading.value = true\n try {\n const response = await makeAuthenticatedRequest(getUrl('mfaBackupCodes'), {\n method: 'POST',\n body: JSON.stringify({ device_id: deviceId }),\n })\n\n return response\n } finally {\n loading.value = false\n }\n }\n\n // Helper function to get device type icon\n const getDeviceTypeIcon = (deviceType: string): string => {\n switch (deviceType) {\n case 'totp':\n return '📱' // Authenticator app\n case 'email':\n return '📧' // Email\n case 'hardware':\n return '🔑' // Hardware key\n case 'passkey':\n return '🔐' // Passkey\n default:\n return '🔒' // Generic security\n }\n }\n\n // Helper function to get device type name\n const getDeviceTypeName = (deviceType: string): string => {\n switch (deviceType) {\n case 'totp':\n return 'Authenticator App'\n case 'email':\n return 'Email Verification'\n case 'hardware':\n return 'Hardware Key'\n case 'passkey':\n return 'Passkey'\n default:\n return 'Unknown'\n }\n }\n\n // Helper function to format last used date\n const formatLastUsed = (lastUsedAt?: string | Date): string => {\n if (!lastUsedAt) return 'Never'\n \n const date = new Date(lastUsedAt)\n const now = new Date()\n const diffMs = now.getTime() - date.getTime()\n const diffDays = Math.floor(diffMs / (1000 * 60 * 60 * 24))\n \n if (diffDays === 0) return 'Today'\n if (diffDays === 1) return 'Yesterday'\n if (diffDays < 30) return `${diffDays} days ago`\n \n return date.toLocaleDateString()\n }\n\n return {\n // State\n mfaDevices: computed(() => mfaDevices.value),\n mfaEnabled: computed(() => mfaEnabled.value),\n loading: computed(() => loading.value),\n hasMfaDevices,\n activeMfaDevices,\n\n // Methods\n fetchMfaDevices,\n setupTotp,\n verifyTotpSetup,\n setupEmailMfa,\n sendEmailMfaCode,\n verifyEmailMfaCode,\n disableMfaDevice,\n regenerateBackupCodes,\n\n // Helper methods\n getDeviceTypeIcon,\n getDeviceTypeName,\n formatLastUsed,\n }\n}","<template>\n <div class=\"accui-component-scope\">\n <UiModal :open=\"show\" card-class=\"mfa-verification-modal\" class=\"mfa-verification-modal-wrapper\">\n <template #header>\n <div class=\"mfa-verification-header\">\n <h2 class=\"mfa-verification-title\">Two-Factor Authentication</h2>\n <p class=\"mfa-verification-subtitle\">Enter your verification code to continue</p>\n </div>\n </template>\n\n <div class=\"mfa-verification-content\">\n <!-- Loading State -->\n <div v-if=\"loading && !emailCodeSent\" class=\"mfa-verification-loading\">\n <StrandsUiLoader :size=\"24\" />\n <span class=\"mfa-verification-loading-text\">{{ isSendingMfaEmail || isVerifyingMfa ? authLoadingMessage :\n 'Loading...' }}</span>\n </div>\n\n <!-- Verification Form -->\n <div v-else class=\"mfa-verification-form\">\n <!-- Available MFA Methods -->\n <div v-if=\"availableMethods.length > 1\" class=\"mfa-methods-section\">\n <p class=\"mfa-methods-title\">Choose verification method:</p>\n <div class=\"mfa-methods-grid\">\n <button v-for=\"method in availableMethods\" :key=\"method.id\" @click=\"selectMethod(method)\" :class=\"[\n 'mfa-method-button',\n selectedMethod?.id === method.id ? 'mfa-method-button-selected' : 'mfa-method-button-default'\n ]\">\n <component :is=\"getDeviceIconComponent(method.device_type)\" :size=\"20\" class=\"mfa-method-icon\" />\n <div class=\"mfa-method-info\">\n <p class=\"mfa-method-name\">{{ method.device_name }}</p>\n <p class=\"mfa-method-type\">{{ getDeviceTypeName(method.device_type) }}</p>\n </div>\n <div v-if=\"selectedMethod?.id === method.id\" class=\"mfa-method-check\">\n <IconCheckCircle :size=\"20\" />\n </div>\n </button>\n </div>\n </div>\n\n <!-- Single Method Display -->\n <div v-else-if=\"selectedMethod\" class=\"mfa-single-method\">\n <div class=\"mfa-single-method-content\">\n <component :is=\"getDeviceIconComponent(selectedMethod.device_type)\" :size=\"24\" class=\"mfa-single-method-icon\" />\n <div>\n <h3 class=\"mfa-single-method-name\">{{ selectedMethod.device_name }}</h3>\n <p class=\"mfa-single-method-type\">{{ getDeviceTypeName(selectedMethod.device_type) }}</p>\n </div>\n </div>\n </div>\n\n <!-- Email MFA Code Request -->\n <div v-if=\"selectedMethod?.device_type === 'email' && !emailCodeSent\" class=\"mfa-email-request\">\n <p class=\"mfa-email-request-text\">Click below to receive your verification code</p>\n <StrandsUiButton variant=\"primary\" @click=\"sendEmailCode\" :disabled=\"loading\" :loading=\"loading\">\n Send Verification Code\n </StrandsUiButton>\n </div>\n\n <!-- Hardware Key & Passkey Authentication -->\n <div v-if=\"selectedMethod?.device_type === 'hardware' || selectedMethod?.device_type === 'passkey'\"\n class=\"mfa-hardware-section\">\n <div class=\"mfa-hardware-prompt\">\n <div class=\"mfa-hardware-prompt-content\">\n <div class=\"mfa-hardware-prompt-icon\">\n <component :is=\"selectedMethod.device_type === 'passkey' ? IconShield : IconKeyRound\" :size=\"24\" class=\"mfa-hardware-icon-svg\" />\n </div>\n <div class=\"mfa-hardware-prompt-text\">\n <h4 class=\"mfa-hardware-prompt-title\">{{ selectedMethod.device_type === 'passkey' ? 'Use your passkey'\n :\n 'Touch your hardware key' }}</h4>\n <p class=\"mfa-hardware-prompt-description\">{{ selectedMethod.device_type === 'passkey' ? 'Use biometrics, PIN, or device security to authenticate' : 'Insert and touch your hardware key to authenticate' }}</p>\n </div>\n </div>\n </div>\n <StrandsUiButton variant=\"primary\" @click=\"authenticateHardwareKey\" :disabled=\"loading\" :loading=\"loading\">\n {{ selectedMethod.device_type === 'passkey' ? 'Authenticate with Passkey' : 'Authenticate with Hardware Key' }}\n </StrandsUiButton>\n\n <!-- Backup Codes Option for Hardware Keys -->\n <div class=\"mfa-backup-option\">\n <StrandsUiButton\n variant=\"ghost\"\n size=\"sm\"\n @click=\"showBackupCodeInput = !showBackupCodeInput\"\n class=\"mfa-backup-toggle-button\">\n <IconKeyRound :size=\"16\" class=\"mfa-backup-toggle-icon\" />\n {{ showBackupCodeInput ? 'Hide backup code' : (selectedMethod.device_type === 'passkey' ? 'Can\\'t access your passkey? Use backup code' : 'Can\\'t access your key? Use backup code') }}\n </StrandsUiButton>\n </div>\n\n <!-- Backup Code Input for Hardware Keys -->\n <div v-if=\"showBackupCodeInput\" class=\"mfa-backup-input-section\">\n <div class=\"mfa-backup-warning\">\n <IconAlertTriangle :size=\"20\" class=\"mfa-backup-warning-icon\" />\n <div>\n <p class=\"mfa-backup-warning-title\">Backup Code Recovery</p>\n <p class=\"mfa-backup-warning-description\">\n Enter one of your backup codes. Each code can only be used once.\n </p>\n </div>\n </div>\n\n <StrandsUiInput v-model=\"backupCode\" label=\"Backup Code\" placeholder=\"abcd-1234\" :error=\"backupCodeError\"\n :disabled=\"loading\" @input=\"onBackupCodeInput\" @paste=\"onBackupCodePaste\" @keydown.enter=\"verifyBackupCode\" class=\"mfa-backup-input\" \n name=\"backup-code-1\" autocomplete=\"off\" inputmode=\"text\" \n data-lpignore=\"false\" data-form-type=\"other\" spellcheck=\"false\" />\n </div>\n </div>\n\n <!-- Code Input -->\n <form\n v-if=\"selectedMethod && selectedMethod.device_type !== 'hardware' && selectedMethod.device_type !== 'passkey' && (selectedMethod.device_type !== 'email' || emailCodeSent)\"\n class=\"mfa-code-section\" @submit.prevent=\"verify\"\n novalidate\n autocomplete=\"off\">\n <!-- Email confirmation -->\n <div v-if=\"selectedMethod.device_type === 'email' && emailCodeSent\"\n class=\"mfa-email-confirmation\">\n <div class=\"mfa-email-confirmation-content\">\n <IconCheckCircle :size=\"20\" class=\"mfa-email-confirmation-icon\" />\n <div>\n <p class=\"mfa-email-confirmation-title\">Code Sent!</p>\n <p class=\"mfa-email-confirmation-description\">Check your email for the verification code</p>\n </div>\n </div>\n </div>\n\n <!-- Code Input Field -->\n <StrandsUiInput v-model=\"verificationCode\" label=\"Verification Code\"\n :placeholder=\"selectedMethod.device_type === 'totp' ? '123456' : '123456'\" maxlength=\"6\"\n :error=\"verificationError\" :disabled=\"loading\" @input=\"onCodeInput\" @keydown.enter=\"verify\" @paste=\"onCodePaste\" autofocus\n name=\"totp\"\n id=\"totp-input\"\n autocomplete=\"one-time-code\"\n inputmode=\"numeric\" \n data-lpignore=\"false\" \n data-form-type=\"other\"\n data-bwignore=\"false\"\n data-1p-ignore=\"false\"\n data-testid=\"totp-input\"\n spellcheck=\"false\"\n aria-label=\"Enter your verification code\"\n aria-describedby=\"totp-description\"\n role=\"textbox\"\n tabindex=\"0\"\n pattern=\"[0-9]{6}\"\n minlength=\"6\"\n title=\"Enter 6-digit verification code\" />\n\n <!-- TOTP Help -->\n <div v-if=\"selectedMethod.device_type === 'totp'\" class=\"mfa-totp-help\" id=\"totp-description\">\n Open your authenticator app and enter the 6-digit code for \n <span class=\"mfa-device-name-text\">\"{{ selectedMethod.device_name }}\"</span>\n </div>\n\n <!-- Email Resend -->\n <div v-if=\"selectedMethod.device_type === 'email'\" class=\"mfa-email-resend\">\n <StrandsUiButton\n variant=\"ghost\"\n size=\"sm\"\n @click=\"sendEmailCode\"\n :disabled=\"loading || cooldownActive\"\n class=\"mfa-resend-button\">\n {{ cooldownActive ? `Resend in ${cooldownSeconds}s` : 'Resend Code' }}\n </StrandsUiButton>\n </div>\n\n <!-- Backup Codes Option -->\n <div class=\"mfa-backup-option\">\n <StrandsUiButton\n variant=\"ghost\"\n size=\"sm\"\n @click=\"showBackupCodeInput = !showBackupCodeInput\"\n class=\"mfa-backup-toggle-button\">\n <IconKeyRound :size=\"16\" class=\"mfa-backup-toggle-icon\" />\n {{ showBackupCodeInput ? 'Hide backup code' : 'Use backup code instead' }}\n </StrandsUiButton>\n </div>\n\n <!-- Backup Code Input -->\n <div v-if=\"showBackupCodeInput\" class=\"mfa-backup-input-section\">\n <div class=\"mfa-backup-warning\">\n <IconAlertTriangle :size=\"20\" class=\"mfa-backup-warning-icon\" />\n <div>\n <p class=\"mfa-backup-warning-title\">Backup Code Recovery</p>\n <p class=\"mfa-backup-warning-description\">\n Enter one of your backup codes. Each code can only be used once.\n </p>\n </div>\n </div>\n\n <StrandsUiInput v-model=\"backupCode\" label=\"Backup Code\" placeholder=\"abcd-1234\" :error=\"backupCodeError\"\n :disabled=\"loading\" @input=\"onBackupCodeInput\" @paste=\"onBackupCodePaste\" @keydown.enter=\"verifyBackupCode\" class=\"mfa-backup-input\" \n name=\"backup-code-2\" autocomplete=\"off\" inputmode=\"text\" \n data-lpignore=\"false\" data-form-type=\"other\" spellcheck=\"false\" />\n </div>\n </form>\n </div>\n </div>\n\n <template #footer>\n <div class=\"mfa-verification-footer\">\n <StrandsUiButton variant=\"secondary\" @click=\"closeModal\" :disabled=\"loading\">\n Cancel\n </StrandsUiButton>\n\n <StrandsUiButton\n v-if=\"(selectedMethod && selectedMethod.device_type !== 'hardware' && selectedMethod.device_type !== 'passkey' && (selectedMethod.device_type !== 'email' || emailCodeSent)) || ((selectedMethod?.device_type === 'hardware' || selectedMethod?.device_type === 'passkey') && showBackupCodeInput)\"\n variant=\"primary\" @click=\"showBackupCodeInput ? verifyBackupCode() : verify()\"\n :disabled=\"(!verificationCode.trim() && !backupCode.trim()) || loading\" :loading=\"loading\">\n {{ showBackupCodeInput ? 'Verify Backup Code' : 'Verify' }}\n </StrandsUiButton>\n </div>\n </template>\n </UiModal>\n </div>\n</template>\n\n<script setup lang=\"ts\">\nimport { ref, computed, watch, onBeforeUnmount, h } from 'vue'\nimport { StrandsUiButton, StrandsUiInput, StrandsUiLoader } from '../ui'\nimport UiModal from '../ui/UiModal.vue'\nimport { useStrandsMfa } from '../composables/useStrandsMfa'\nimport { useStrandsAuth } from '../composables/useStrandsAuth'\nimport type { MfaDevice } from '../../types'\n\n// Simple SVG icon components using render functions (no runtime compilation needed)\nconst IconSmartphone = {\n props: ['size'],\n render(this: any) {\n return h('svg', { \n width: this.size, \n height: this.size, \n fill: 'none', \n stroke: 'currentColor', \n viewBox: '0 0 24 24' \n }, [\n h('rect', { x: '5', y: '2', width: '14', height: '20', rx: '2', ry: '2' }),\n h('line', { x1: '12', y1: '18', x2: '12.01', y2: '18' })\n ])\n }\n}\n\nconst IconMail = {\n props: ['size'],\n render(this: any) {\n return h('svg', { \n width: this.size, \n height: this.size, \n fill: 'none', \n stroke: 'currentColor', \n viewBox: '0 0 24 24' \n }, [\n h('path', { d: 'm4 4 16 0 0 16 -16 0 z' }),\n h('path', { d: 'm22 6-10 7L2 6' })\n ])\n }\n}\n\nconst IconKeyRound = {\n props: ['size'],\n render(this: any) {\n return h('svg', { \n width: this.size, \n height: this.size, \n fill: 'none', \n stroke: 'currentColor', \n viewBox: '0 0 24 24' \n }, [\n h('circle', { cx: '7.5', cy: '15.5', r: '5.5' }),\n h('path', { d: 'm21 2-9.6 9.6' }),\n h('path', { d: 'm15.5 7.5 3 3L22 7l-3-3' })\n ])\n }\n}\n\nconst IconShield = {\n props: ['size'],\n render(this: any) {\n return h('svg', { \n width: this.size, \n height: this.size, \n fill: 'none', \n stroke: 'currentColor', \n viewBox: '0 0 24 24' \n }, [\n h('path', { d: 'M12 22s8-4 8-10V5l-8-3-8 3v7c0 6 8 10 8 10z' })\n ])\n }\n}\n\nconst IconCheckCircle = {\n props: ['size'],\n render(this: any) {\n return h('svg', { \n width: this.size, \n height: this.size, \n fill: 'none', \n stroke: 'currentColor', \n viewBox: '0 0 24 24' \n }, [\n h('path', { d: 'M22 11.08V12a10 10 0 1 1-5.93-9.14' }),\n h('polyline', { points: '22,4 12,14.01 9,11.01' })\n ])\n }\n}\n\nconst IconCheck = {\n props: ['size'],\n render(this: any) {\n return h('svg', { \n width: this.size, \n height: this.size, \n fill: 'none', \n stroke: 'currentColor', \n viewBox: '0 0 24 24' \n }, [\n h('polyline', { points: '20,6 9,17 4,12' })\n ])\n }\n}\n\nconst IconAlertTriangle = {\n props: ['size'],\n render(this: any) {\n return h('svg', { \n width: this.size, \n height: this.size, \n fill: 'none', \n stroke: 'currentColor', \n viewBox: '0 0 24 24' \n }, [\n h('path', { d: 'm21.73 18-8-14a2 2 0 0 0-3.48 0l-8 14A2 2 0 0 0 4 21h16a2 2 0 0 0 1.73-3Z' }),\n h('path', { d: 'M12 9v4' }),\n h('path', { d: 'm12 17 .01 0' })\n ])\n }\n}\n\ninterface Props {\n show: boolean\n availableMfaMethods?: MfaDevice[]\n sessionId?: string | null\n}\n\ninterface Emits {\n (e: 'close'): void\n (e: 'success'): void\n (e: 'error', error: string): void\n}\n\nconst props = defineProps<Props>()\nconst emit = defineEmits<Emits>()\n\nconst {\n loading: mfaLoading,\n getDeviceTypeIcon,\n getDeviceTypeName,\n} = useStrandsMfa()\n\nconst {\n verifyMfa,\n sendMfaEmailCode,\n getMfaWebAuthnChallenge,\n mfaSessionId: authMfaSessionId,\n loading: authLoading,\n loadingMessage: authLoadingMessage,\n isSendingMfaEmail,\n isVerifyingMfa,\n} = useStrandsAuth()\n\nconst loading = computed(() => mfaLoading.value || authLoading.value)\n\n// State\nconst selectedMethod = ref<MfaDevice | null>(null)\nconst verificationCode = ref('')\nconst verificationError = ref('')\nconst backupCode = ref('')\nconst backupCodeError = ref('')\nconst showBackupCodeInput = ref(false)\nconst emailCodeSent = ref(false)\nconst cooldownActive = ref(false)\nconst cooldownSeconds = ref(0)\n\nlet cooldownInterval: NodeJS.Timeout | null = null\n\n// Computed - filter out WebAuthn methods temporarily until cross-domain support is implemented\nconst availableMethods = computed(() => {\n const methods = props.availableMfaMethods || []\n // Temporarily disable hardware keys and passkeys until cross-domain WebAuthn is resolved\n return methods.filter(method =>\n method.device_type !== 'hardware' &&\n method.device_type !== 'passkey'\n )\n})\n\n// Auto-select if only one method available\nwatch(() => availableMethods.value, (methods) => {\n if (methods.length === 1) {\n selectedMethod.value = methods[0]\n } else if (methods.length === 0) {\n selectedMethod.value = null\n }\n}, { immediate: true })\n\n// Reset when modal opens/closes\nwatch(() => props.show, async (newShow) => {\n if (newShow) {\n // Reset state\n verificationCode.value = ''\n verificationError.value = ''\n backupCode.value = ''\n backupCodeError.value = ''\n showBackupCodeInput.value = false\n emailCodeSent.value = false\n cooldownActive.value = false\n cooldownSeconds.value = 0\n\n if (cooldownInterval) {\n clearInterval(cooldownInterval)\n cooldownInterval = null\n }\n\n // Loading state is already handled in useStrandsAuth when MFA is required\n\n // Auto-select method if only one available\n if (availableMethods.value.length === 1) {\n selectedMethod.value = availableMethods.value[0]\n\n // If the only method is email, automatically send the code\n if (selectedMethod.value.device_type === 'email') {\n // Small delay to ensure UI is ready\n setTimeout(async () => {\n try {\n await sendMfaEmailCode(selectedMethod.value!.id)\n emailCodeSent.value = true\n startCooldown()\n } catch (error) {\n emit('error', error instanceof Error ? error.message : 'Failed to send email code')\n // Even if auto-send fails, show the manual send button by not setting emailCodeSent to true\n }\n }, 100)\n }\n }\n } else {\n selectedMethod.value = null\n }\n})\n\nonBeforeUnmount(() => {\n if (cooldownInterval) {\n clearInterval(cooldownInterval)\n }\n})\n\nconst closeModal = () => {\n emit('close')\n}\n\nconst selectMethod = (method: MfaDevice) => {\n selectedMethod.value = method\n verificationCode.value = ''\n verificationError.value = ''\n emailCodeSent.value = false\n showBackupCodeInput.value = false\n}\n\nconst onCodeInput = (value: string) => {\n // Only allow digits for verification codes\n verificationCode.value = value.replace(/\\D/g, '').slice(0, 6)\n verificationError.value = ''\n}\n\nconst onCodePaste = (event: ClipboardEvent) => {\n event.preventDefault()\n const pastedData = event.clipboardData?.getData('text/plain') || ''\n // Extract only digits from pasted data and limit to 6 characters\n const cleanedData = pastedData.replace(/\\D/g, '').slice(0, 6)\n verificationCode.value = cleanedData\n verificationError.value = ''\n}\n\nconst onBackupCodeInput = (value: string) => {\n // Allow alphanumeric and hyphens for backup codes, normalize to lowercase\n // Remove any characters except letters, numbers, and hyphens\n let cleaned = value.replace(/[^a-zA-Z0-9-]/g, '').toLowerCase()\n\n // If the user is typing continuously without hyphens, auto-format with hyphens for xxxx-xxxx pattern\n if (!/[-]/.test(cleaned) && cleaned.length > 4) {\n // Format as xxxx-xxxx pattern\n const part1 = cleaned.substring(0, 4)\n const part2 = cleaned.substring(4, 8)\n cleaned = part2 ? `${part1}-${part2}` : part1\n }\n\n // Limit to xxxx-xxxx format (8 characters plus 1 hyphen = 9 total)\n if (cleaned.replace(/-/g, '').length <= 8) {\n backupCode.value = cleaned\n }\n\n backupCodeError.value = ''\n}\n\nconst onBackupCodePaste = (event: ClipboardEvent) => {\n event.preventDefault()\n const pastedData = event.clipboardData?.getData('text/plain') || ''\n // Process pasted backup code data with the same logic as typing\n let cleaned = pastedData.replace(/[^a-zA-Z0-9-]/g, '').toLowerCase()\n \n // If the pasted data doesn't have hyphens and is longer than 4 chars, auto-format\n if (!/[-]/.test(cleaned) && cleaned.length > 4) {\n const part1 = cleaned.substring(0, 4)\n const part2 = cleaned.substring(4, 8)\n cleaned = part2 ? `${part1}-${part2}` : part1\n }\n \n // Limit to xxxx-xxxx format (8 characters plus 1 hyphen = 9 total)\n if (cleaned.replace(/-/g, '').length <= 8) {\n backupCode.value = cleaned\n }\n backupCodeError.value = ''\n}\n\nconst sendEmailCode = async () => {\n if (!selectedMethod.value || selectedMethod.value.device_type !== 'email') return\n\n try {\n // Use the sign-in specific MFA email code method\n await sendMfaEmailCode(selectedMethod.value.id)\n emailCodeSent.value = true\n startCooldown()\n } catch (error) {\n emit('error', error instanceof Error ? error.message : 'Failed to send email code')\n }\n}\n\nconst startCooldown = () => {\n cooldownActive.value = true\n cooldownSeconds.value = 30\n\n cooldownInterval = setInterval(() => {\n cooldownSeconds.value -= 1\n if (cooldownSeconds.value <= 0) {\n cooldownActive.value = false\n if (cooldownInterval) {\n clearInterval(cooldownInterval)\n cooldownInterval = null\n }\n }\n }, 1000)\n}\n\nconst verify = async () => {\n if (!selectedMethod.value || !verificationCode.value) return\n\n verificationError.value = ''\n\n try {\n await verifyMfa(selectedMethod.value.id, verificationCode.value)\n emit('success')\n } catch (error) {\n verificationError.value = error instanceof Error ? error.message : 'Invalid verification code'\n }\n}\n\nconst verifyBackupCode = async () => {\n if (!backupCode.value) return\n\n backupCodeError.value = ''\n\n try {\n await verifyMfa('', backupCode.value, true) // deviceId not needed for backup codes\n emit('success')\n } catch (error) {\n backupCodeError.value = error instanceof Error ? error.message : 'Invalid backup code'\n }\n}\n\nconst getDeviceIconComponent = (deviceType: string) => {\n switch (deviceType) {\n case 'totp':\n return IconSmartphone\n case 'email':\n return IconMail\n case 'hardware':\n return IconKeyRound\n case 'passkey':\n return IconShield\n default:\n return IconShield\n }\n}\n\nconst authenticateHardwareKey = async () => {\n // Use sessionId from props or auth composable\n const sessionId = props.sessionId || authMfaSessionId.value\n\n if (!selectedMethod.value || (selectedMethod.value.device_type !== 'hardware' && selectedMethod.value.device_type !== 'passkey') || !sessionId) {\n emit('error', 'Missing requirements for hardware key authentication')\n return\n }\n\n try {\n // Check if WebAuthn is supported\n if (!window.navigator.credentials || !window.PublicKeyCredential) {\n throw new Error('Hardware keys are not supported in this browser')\n }\n\n // Get WebAuthn challenge from backend\n const challengeResponse = await getMfaWebAuthnChallenge(selectedMethod.value.id)\n\n // Extract the publicKey from the challenge response\n const challengeData = challengeResponse.challenge.publicKey || challengeResponse.challenge\n\n // Helper function to convert base64 to Uint8Array\n const base64ToUint8Array = (base64: string) => {\n if (!base64 || typeof base64 !== 'string') {\n return new Uint8Array(0)\n }\n const padding = '='.repeat((4 - base64.length % 4) % 4)\n const b64 = (base64 + padding).replace(/-/g, '+').replace(/_/g, '/')\n const rawData = window.atob(b64)\n const outputArray = new Uint8Array(rawData.length)\n for (let i = 0; i < rawData.length; ++i) {\n outputArray[i] = rawData.charCodeAt(i)\n }\n return outputArray\n }\n\n // Use the challenge from backend with device-optimized parameters\n const isPasskey = selectedMethod.value.device_type === 'passkey'\n\n // Convert challenge and other binary fields from base64 to Uint8Array\n const publicKeyCredentialRequestOptions: any = {\n ...challengeData,\n challenge: challengeData.challenge ? base64ToUint8Array(challengeData.challenge) : new Uint8Array(32),\n timeout: isPasskey ? 300000 : (challengeData.timeout || 60000),\n userVerification: (isPasskey ? 'required' : 'discouraged') as UserVerificationRequirement\n }\n\n // Convert allowCredentials if present\n if (challengeData.allowCredentials && Array.isArray(challengeData.allowCredentials)) {\n publicKeyCredentialRequestOptions.allowCredentials = challengeData.allowCredentials.map((cred: any) => ({\n ...cred,\n id: base64ToUint8Array(cred.id)\n }))\n }\n\n // Get WebAuthn credential from hardware key\n const credential = await navigator.credentials.get({\n publicKey: publicKeyCredentialRequestOptions\n }) as PublicKeyCredential\n\n if (!credential) {\n throw new Error(`${selectedMethod.value.device_type === 'passkey' ? 'Passkey' : 'Hardware key'} authentication was cancelled`)\n }\n\n // Try to get device information from the authenticator data\n const authenticatorData = new Uint8Array((credential.response as AuthenticatorAssertionResponse).authenticatorData)\n\n // Extract AAGUID (Authenticator Attestation Globally Unique Identifier) for device identification\n // AAGUID is at bytes 37-52 of authenticator data\n let deviceInfo = 'Security Key'\n if (authenticatorData.length >= 53) {\n const aaguid = Array.from(authenticatorData.slice(37, 53))\n const aaguidHex = aaguid.map(b => b.toString(16).padStart(2, '0')).join('')\n\n // Common AAGUID to device name mapping\n const knownAAGUIDs: Record<string, string> = {\n '00000000000000000000000000000000': 'Generic Security Key',\n 'ee882879721c491397753dfcce97072a': 'YubiKey 5 Series',\n 'f8a011f38c0a4d15800617111f9edc7d': 'YubiKey 5 Series',\n '2fc0579f811347eab116bb5a8db9202a': 'YubiKey 5 Series',\n 'c5ef55ffad9a4b9fb580adcb7c15e233': 'YubiKey 5 Series',\n '6d44ba9bf6ec2e49b9300200c9a3376d': 'Google Titan Security Key',\n 'de1e552d14e14b1f9390f6d61b56e4d1': 'Feitian Security Key',\n '12ded745aa4e4b4f84be2736d6b1b2a5': 'SoloKeys Solo',\n '8876631bd4a0427f57730ec71c9e0279': 'Nitrokey FIDO2'\n }\n\n deviceInfo = knownAAGUIDs[aaguidHex] || `Security Key (${aaguidHex.substring(0, 8)}...)`\n }\n\n // Format the credential for the backend\n const credentialData = {\n id: credential.id,\n rawId: Array.from(new Uint8Array(credential.rawId)),\n response: {\n clientDataJSON: Array.from(new Uint8Array(credential.response.clientDataJSON)),\n authenticatorData: Array.from(new Uint8Array((credential.response as AuthenticatorAssertionResponse).authenticatorData)),\n signature: Array.from(new Uint8Array((credential.response as AuthenticatorAssertionResponse).signature)),\n userHandle: (credential.response as AuthenticatorAssertionResponse).userHandle ?\n Array.from(new Uint8Array((credential.response as AuthenticatorAssertionResponse).userHandle!)) : null\n },\n type: credential.type,\n deviceInfo: deviceInfo // Include detected device info\n }\n\n // Send the credential data to the backend using the frontend device ID\n await verifyMfa(selectedMethod.value.id, JSON.stringify(credentialData))\n\n emit('success')\n\n } catch (error) {\n console.error('Hardware key authentication error:', error)\n emit('error', error instanceof Error ? error.message : 'Hardware key authentication failed')\n }\n}\n</script>\n\n<style scoped>\n/* Modal width control - Extreme override for MFA verification */\n.mfa-verification-modal-wrapper :deep(.modal-overlay) {\n align-items: center !important;\n justify-content: center !important;\n}\n\n.mfa-verification-modal-wrapper :deep(.modal-container) {\n width: 32rem !important;\n max-width: 32rem !important;\n min-width: 32rem !important;\n /* Critical: Force the modal to maintain fixed width */\n flex-shrink: 0 !important;\n flex-grow: 0 !important;\n flex-basis: auto !important;\n box-sizing: border-box !important;\n /* Override any auto width */\n width: 512px !important;\n}\n\n@media (max-width: 36rem) {\n .mfa-verification-modal-wrapper :deep(.modal-container) {\n width: calc(100vw - 2rem) !important;\n min-width: auto !important;\n max-width: calc(100vw - 2rem) !important;\n }\n}\n\n/* Force content to respect modal bounds */\n.mfa-verification-modal-wrapper :deep(.modal-content) {\n width: 100% !important;\n max-width: 100% !important;\n overflow: hidden !important;\n box-sizing: border-box !important;\n}\n\n/* Force all descendant elements to wrap and not overflow */\n.mfa-verification-modal-wrapper :deep(.modal-content *) {\n max-width: 100% !important;\n word-wrap: break-word !important;\n overflow-wrap: break-word !important;\n box-sizing: border-box !important;\n}</style>\n\n<!-- Additional global style to ensure it overrides everything -->\n<style>\n/* Global override for MFA verification modal width issue */\n.mfa-verification-modal-wrapper .modal-container {\n width: 32rem !important;\n max-width: 32rem !important;\n min-width: 32rem !important;\n flex-shrink: 0 !important;\n flex-grow: 0 !important;\n box-sizing: border-box !important;\n}\n\n@media (max-width: 36rem) {\n .mfa-verification-modal-wrapper .modal-container {\n width: calc(100vw - 2rem) !important;\n min-width: auto !important;\n max-width: calc(100vw - 2rem) !important;\n }\n}\n\n/* Force text wrapping globally for this modal */\n.mfa-verification-modal-wrapper .modal-content * {\n max-width: 100% !important;\n word-wrap: break-word !important;\n overflow-wrap: break-word !important;\n box-sizing: border-box !important;\n}\n\n/* Header */\n.mfa-verification-header {\n text-align: center;\n}\n\n.mfa-verification-title {\n font-size: 1.25rem;\n font-weight: 700;\n color: #111827;\n}\n\n.mfa-verification-subtitle {\n color: #4b5563;\n margin-top: 0.5rem;\n}\n\n/* Content */\n.mfa-verification-content {\n display: flex;\n flex-direction: column;\n gap: 1.5rem;\n max-width: 100%;\n overflow: hidden;\n}\n\n/* Loading */\n.mfa-verification-loading {\n display: flex;\n align-items: center;\n justify-content: center;\n padding: 2rem 0;\n}\n\n.mfa-verification-loading-text {\n margin-left: 0.75rem;\n color: #4b5563;\n}\n\n/* Form */\n.mfa-verification-form {\n display: flex;\n flex-direction: column;\n gap: 1rem;\n max-width: 100%;\n overflow: hidden;\n}\n\n/* Methods section */\n.mfa-methods-section {\n display: flex;\n flex-direction: column;\n gap: 0.75rem;\n}\n\n.mfa-methods-title {\n font-size: 0.875rem;\n font-weight: 500;\n color: #374151;\n}\n\n.mfa-methods-grid {\n display: grid;\n gap: 0.5rem;\n}\n\n/* Method buttons */\n.mfa-method-button {\n display: flex;\n align-items: center;\n gap: 0.75rem;\n padding: 0.75rem;\n border: 1px solid;\n border-radius: 0.5rem;\n transition: all 0.2s ease;\n cursor: pointer;\n background: none;\n text-align: left;\n width: 100%;\n}\n\n.mfa-method-button-default {\n border-color: #e5e7eb;\n background-color: transparent;\n}\n\n.mfa-method-button-default:hover {\n border-color: #d1d5db;\n background-color: #f9fafb;\n}\n\n.mfa-method-button-selected {\n border-color: var(--strands-primary, #EA00A8);\n background-color: rgba(234, 0, 168, 0.05);\n color: var(--strands-primary, #EA00A8);\n}\n\n.mfa-method-icon {\n color: var(--strands-primary, #EA00A8);\n}\n\n.mfa-method-info {\n text-align: left;\n flex: 1;\n}\n\n.mfa-method-name {\n font-weight: 500;\n margin: 0;\n}\n\n.mfa-method-type {\n font-size: 0.875rem;\n color: #6b7280;\n margin: 0;\n}\n\n.mfa-method-check {\n color: var(--strands-primary, #EA00A8);\n}\n\n/* Single method display */\n.mfa-single-method {\n background-color: #f9fafb;\n border-radius: 0.5rem;\n padding: 1rem;\n}\n\n.mfa-single-method-content {\n display: flex;\n align-items: center;\n gap: 0.75rem;\n}\n\n.mfa-single-method-icon {\n color: var(--strands-primary, #EA00A8);\n}\n\n.mfa-single-method-name {\n font-weight: 500;\n color: #111827;\n margin: 0;\n}\n\n.mfa-single-method-type {\n font-size: 0.875rem;\n color: #6b7280;\n margin: 0;\n}\n\n/* Email request */\n.mfa-email-request {\n text-align: center;\n}\n\n.mfa-email-request-text {\n font-size: 0.875rem;\n color: #4b5563;\n margin-bottom: 1rem;\n}\n\n/* Hardware section */\n.mfa-hardware-section {\n text-align: center;\n display: flex;\n flex-direction: column;\n gap: 1rem;\n}\n\n.mfa-hardware-prompt {\n background-color: #eff6ff;\n border: 1px solid #bfdbfe;\n border-radius: 0.5rem;\n padding: 1rem;\n}\n\n.mfa-hardware-prompt-content {\n display: flex;\n align-items: center;\n gap: 0.75rem;\n}\n\n.mfa-hardware-prompt-icon {\n width: 3rem;\n height: 3rem;\n background-color: #dbeafe;\n border-radius: 50%;\n display: flex;\n align-items: center;\n justify-content: center;\n}\n\n.mfa-hardware-icon-svg {\n width: 1.5rem;\n height: 1.5rem;\n color: #2563eb;\n}\n\n.mfa-hardware-prompt-text {\n text-align: left;\n}\n\n.mfa-hardware-prompt-title {\n font-weight: 500;\n color: #1e3a8a;\n margin: 0;\n}\n\n.mfa-hardware-prompt-description {\n font-size: 0.875rem;\n color: #1d4ed8;\n margin: 0;\n}\n\n/* Backup option */\n.mfa-backup-option {\n padding-top: 1rem;\n border-top: 1px solid #e5e7eb;\n display: flex;\n justify-content: center;\n}\n\n.mfa-backup-toggle-button {\n font-size: 0.875rem;\n color: #6b7280;\n justify-content: flex-start;\n gap: 0.5rem;\n}\n\n.mfa-backup-toggle-button:hover {\n color: #374151;\n background-color: #f9fafb;\n}\n\n.mfa-backup-toggle-icon {\n flex-shrink: 0;\n}\n\n/* Backup input section */\n.mfa-backup-input-section {\n display: flex;\n flex-direction: column;\n gap: 1rem;\n background-color: #fffbeb;\n border: 1px solid #fde68a;\n border-radius: 0.5rem;\n padding: 1rem;\n}\n\n.mfa-backup-warning {\n display: flex;\n align-items: flex-start;\n gap: 0.5rem;\n margin-bottom: 0.75rem;\n}\n\n.mfa-backup-warning-icon {\n width: 1.25rem;\n height: 1.25rem;\n color: #d97706;\n margin-top: 0.125rem;\n flex-shrink: 0;\n}\n\n.mfa-backup-warning-title {\n font-size: 0.875rem;\n font-weight: 500;\n color: #92400e;\n margin: 0;\n}\n\n.mfa-backup-warning-description {\n font-size: 0.875rem;\n color: #b45309;\n margin-top: 0.25rem;\n}\n\n.mfa-backup-input {\n font-family: ui-monospace, SFMono-Regular, 'SF Mono', Consolas, 'Liberation Mono', Menlo, monospace;\n}\n\n/* Code section */\n.mfa-code-section {\n display: flex;\n flex-direction: column;\n gap: 1rem;\n max-width: 100%;\n overflow: hidden;\n}\n\n/* Email confirmation */\n.mfa-email-confirmation {\n background-color: #f0fdf4;\n border: 1px solid #bbf7d0;\n border-radius: 0.5rem;\n padding: 1rem;\n}\n\n.mfa-email-confirmation-content {\n display: flex;\n align-items: flex-start;\n gap: 0.5rem;\n}\n\n.mfa-email-confirmation-icon {\n width: 1.25rem;\n height: 1.25rem;\n color: #059669;\n margin-top: 0.125rem;\n flex-shrink: 0;\n}\n\n.mfa-email-confirmation-title {\n font-size: 0.875rem;\n font-weight: 500;\n color: #166534;\n margin: 0;\n}\n\n.mfa-email-confirmation-description {\n font-size: 0.875rem;\n color: #15803d;\n margin-top: 0.25rem;\n}\n\n/* TOTP help - Force aggressive text wrapping */\n.mfa-totp-help {\n font-size: 0.875rem;\n color: #4b5563;\n line-height: 1.5;\n /* Force wrapping at all costs */\n word-wrap: break-word !important;\n overflow-wrap: anywhere !important;\n word-break: break-word !important;\n hyphens: auto !important;\n white-space: normal !important;\n /* Ensure no overflow */\n max-width: 100% !important;\n width: 100% !important;\n overflow: hidden !important;\n display: block !important;\n box-sizing: border-box !important;\n}\n\n.mfa-device-name-text {\n /* Break device names aggressively to prevent expansion */\n word-break: break-all !important;\n overflow-wrap: anywhere !important;\n word-wrap: break-word !important;\n display: inline !important;\n max-width: 100% !important;\n overflow: hidden !important;\n}\n\n/* Email resend */\n.mfa-email-resend {\n display: flex;\n justify-content: flex-end;\n font-size: 0.875rem;\n}\n\n.mfa-resend-button {\n color: var(--strands-primary, #EA00A8);\n font-size: 0.875rem;\n}\n\n.mfa-resend-button:hover:not(:disabled) {\n color: #B8006F;\n background-color: rgba(234, 0, 168, 0.05);\n}\n\n.mfa-resend-button:disabled {\n color: #9ca3af;\n cursor: not-allowed;\n}\n\n/* Footer */\n.mfa-verification-footer {\n display: flex;\n justify-content: space-between;\n}\n\n/* Backup input field */\n.mfa-backup-input {\n font-family: ui-monospace, SFMono-Regular, 'SF Mono', Consolas, 'Liberation Mono', Menlo, monospace;\n}\n</style>","import { ref, computed } from 'vue'\nimport { useStrandsConfig } from './useStrandsConfig'\n\nexport interface OAuthProvider {\n id: string\n name: string\n displayName?: string\n icon?: string\n iconUrl?: string\n auth_url: string\n scopes: string[]\n enabled: boolean\n metadata?: Record<string, string>\n}\n\nexport interface OAuthProvidersResponse {\n providers: OAuthProvider[]\n redirect_url: string\n}\n\nexport interface OAuthProviderDetailsResponse {\n success: boolean\n data: {\n provider: OAuthProvider\n authUrl: string\n state?: string\n }\n error?: {\n code: string\n message: string\n details?: any\n }\n}\n\nexport interface UseOAuthProvidersOptions {\n redirectUrl?: string\n scopes?: string[]\n}\n\nexport function useOAuthProviders(options: UseOAuthProvidersOptions = {}) {\n const { getUrl, config } = useStrandsConfig()\n \n const providers = ref<OAuthProvider[]>([])\n const loading = ref(false)\n const error = ref<string | null>(null)\n\n const enabledProviders = computed(() => \n providers.value.filter(provider => provider.enabled)\n )\n\n const fetchProviders = async () => {\n loading.value = true\n error.value = null\n\n try {\n let url = getUrl('oauthProviders')\n \n // Add redirect_url parameter if configured\n const redirectUrl = options.redirectUrl || config.value?.oauth2RedirectUrl\n if (redirectUrl) {\n const params = new URLSearchParams()\n \n // Convert relative URLs to absolute URLs\n let absoluteRedirectUrl = redirectUrl\n if (redirectUrl.startsWith('/')) {\n // Get the current origin\n const currentOrigin = window.location.origin\n absoluteRedirectUrl = `${currentOrigin}${redirectUrl}`\n }\n \n params.append('redirect_url', absoluteRedirectUrl)\n url = `${url}?${params.toString()}`\n }\n \n const response = await fetch(url, {\n method: 'GET',\n headers: {\n 'Content-Type': 'application/json',\n },\n })\n\n if (!response.ok) {\n const errorData = await response.json().catch(() => ({}))\n throw new Error(errorData.error?.message || `HTTP ${response.status}: ${response.statusText}`)\n }\n\n const result: OAuthProvidersResponse = await response.json()\n \n // The API returns { providers: [...], redirect_url: \"...\" }\n providers.value = result.providers || []\n } catch (err) {\n const errorMessage = err instanceof Error ? err.message : 'Failed to fetch OAuth providers'\n error.value = errorMessage\n } finally {\n loading.value = false\n }\n }\n\n const getProviderAuthUrl = async (\n providerId: string, \n customOptions?: Partial<UseOAuthProvidersOptions>\n ): Promise<string> => {\n const mergedOptions = { ...options, ...customOptions }\n \n // Build query parameters\n const params = new URLSearchParams()\n \n if (mergedOptions.redirectUrl) {\n // Convert relative URLs to absolute URLs\n let absoluteRedirectUrl = mergedOptions.redirectUrl\n if (mergedOptions.redirectUrl.startsWith('/')) {\n const currentOrigin = window.location.origin\n absoluteRedirectUrl = `${currentOrigin}${mergedOptions.redirectUrl}`\n }\n params.append('redirect_url', absoluteRedirectUrl)\n }\n \n if (mergedOptions.scopes && mergedOptions.scopes.length > 0) {\n params.append('scopes', mergedOptions.scopes.join(','))\n }\n\n const queryString = params.toString()\n const providerUrl = getUrl('oauthProvider').replace('{provider_id}', providerId)\n const fullUrl = queryString ? `${providerUrl}?${queryString}` : providerUrl\n\n try {\n const response = await fetch(fullUrl, {\n method: 'GET',\n headers: {\n 'Content-Type': 'application/json',\n },\n })\n\n if (!response.ok) {\n const errorData = await response.json().catch(() => ({}))\n throw new Error(errorData.error?.message || `HTTP ${response.status}: ${response.statusText}`)\n }\n\n const result: OAuthProviderDetailsResponse = await response.json()\n \n if (!result.success) {\n throw new Error(result.error?.message || 'Failed to get OAuth auth URL')\n }\n\n return result.data.authUrl\n } catch (err) {\n const errorMessage = err instanceof Error ? err.message : 'Failed to get OAuth auth URL'\n throw new Error(errorMessage)\n }\n }\n\n const redirectToProvider = async (\n providerId: string, \n customOptions?: Partial<UseOAuthProvidersOptions>\n ) => {\n try {\n // Find the provider and use its auth_url directly\n const provider = providers.value.find(p => p.id === providerId)\n if (!provider) {\n throw new Error(`OAuth provider '${providerId}' not found`)\n }\n \n if (!provider.auth_url) {\n throw new Error(`No auth URL configured for provider '${providerId}'`)\n }\n \n window.location.href = provider.auth_url\n } catch (err) {\n error.value = err instanceof Error ? err.message : 'Failed to redirect to OAuth provider'\n throw err\n }\n }\n\n const getProviderById = (providerId: string) => {\n return providers.value.find(provider => provider.id === providerId)\n }\n\n const getProviderIcon = (provider: OAuthProvider): string => {\n // Return custom icon URL if provided, otherwise use built-in icons\n if (provider.iconUrl) {\n return provider.iconUrl\n }\n\n // Built-in SVG icons for common providers\n switch (provider.id.toLowerCase()) {\n case 'google':\n return 'data:image/svg+xml;base64,PHN2ZyB2aWV3Qm94PSIwIDAgMjQgMjQiPjxwYXRoIGZpbGw9IiM0Mjg1RjQiIGQ9Ik0yMi41NiAxMi4yNWMwLS43OC0uMDctMS41My0uMi0yLjI1SDEydjQuMjZoNS45MmMtLjI2IDEuMzctMS4wNCAyLjUzLTIuMjEgMy4zMXYyLjc3aDMuNTdjMi4wOC0xLjkyIDMuMjgtNC43NCAzLjI4LTguMDl6Ii8+PHBhdGggZmlsbD0iIzM0QTg1MyIgZD0iTTEyIDIzYzIuOTcgMCA1LjQ2LS45OCA3LjI4LTIuNjZsLTMuNTctMi43N2MtLjk4LjY2LTIuMjMgMS4wNi0zLjcxIDEuMDYtMi44NiAwLTUuMjktMS45My02LjE2LTQuNTNIMi4xOHYyLjg0QzMuOTkgMjAuNTMgNy43IDIzIDEyIDIzeiIvPjxwYXRoIGZpbGw9IiNGQkJDMDUiIGQ9Ik01Ljg0IDE0LjA5Yy0uMjItLjY2LS4zNS0xLjM2LS4zNS0yLjA5cy4xMy0xLjQzLjM1LTIuMDlWNy4wN0gyLjE4QzEuNDMgOC41NSAxIDEwLjIyIDEgMTJzLjQzIDMuNDUgMS4xOCA0LjkzbDIuODUtMi4yMi44MS0uNjJ6Ii8+PHBhdGggZmlsbD0iI0VBNDMzNSIgZD0iTTEyIDUuMzhjMS42MiAwIDMuMDYuNTYgNC4yMSAxLjY0bDMuMTUtMy4xNUMxNy40NSAyLjA5IDE0Ljk3IDEgMTIgMSA3LjcgMSAzLjk5IDMuNDcgMi4xOCA3LjA3bDMuNjYgMi44NGMuODctMi42IDMuMy00LjUzIDYuMTYtNC41M3oiLz48L3N2Zz4='\n case 'github':\n return 'data:image/svg+xml;base64,PHN2ZyBmaWxsPSJjdXJyZW50Q29sb3IiIHZpZXdCb3g9IjAgMCAyNCAyNCI+PHBhdGggZD0iTTEyIDBoLTEyYy02LjYyNiAwLTEyIDUuMzczLTEyIDEyIDAgNS4zMDIgMy40MzggOS44IDguMjA3IDExLjM4Ny41OTkuMTExLjc5My0uMjYxLjc5My0uNTc3di0yLjIzNGMtMy4zMzguNzI2LTQuMDMzLTEuNDE2LTQuMDMzLTEuNDE2LS41NDYtMS4zODctMS4zMzMtMS43NTYtMS4zMzMtMS43NTYtMS4wODktLjc0NS4wODMtLjcyOS4wODMtLjcyOSAxLjIwNS4wODQgMS44MzkgMS4yMzcgMS44MzkgMS4yMzcgMS4wNyAxLjgzNCAyLjgwNyAxLjMwNCAzLjQ5Mi45OTcuMTA3LS43NzUuNDE4LTEuMzA1Ljc2Mi0xLjYwNC0yLjY2NS0uMzA1LTUuNDY3LTEuMzM0LTUuNDY3LTUuOTMxIDAtMS4zMTEuNDY5LTIuMzgxIDEuMjM2LTMuMjIxLS4xMjQtLjMwMy0uNTM1LTEuNTI0LjExNy0zLjE3NiAwIDAgMS4wMDgtLjMyMiAzLjMwMSAxLjIzLjk1Ny0uMjY2IDEuOTgzLS4zOTkgMy4wMDMtLjQwNCAxLjAyLjAwNSAyLjA0Ny4xMzggMy4wMDYuNDA0IDIuMjkxLTEuNTUyIDMuMjk3LTEuMjMgMy4yOTctMS4yMy42NTMgMS42NTMuMjQyIDIuODc0LjExOCAzLjE3Ni43Ny44NCAxLjIzNSAxLjkxMSAxLjIzNSAzLjIyMSAwIDQuNjA5LTIuODA3IDUuNjI0LTUuNDc5IDUuOTIxLjQzLjM3Mi44MjMgMS4xMDIuODIzIDIuMjIydjMuMjkzYzAgLjMxOS4xOTIuNjk0LjgwMS41NzYgNC43NjUtMS41ODkgOC4xOTktNi4wODYgOC4xOTktMTEuMzg2IDAtNi42MjctNS4zNzMtMTItMTItMTJ6Ii8+PC9zdmc+'\n case 'microsoft':\n case 'azure':\n return 'data:image/svg+xml;base64,PHN2ZyB2aWV3Qm94PSIwIDAgMjQgMjQiPjxyZWN0IGZpbGw9IiNmMjUwMjIiIHdpZHRoPSIxMSIgaGVpZ2h0PSIxMSIvPjxyZWN0IGZpbGw9IiM3ZmJhMDAiIHg9IjEzIiB3aWR0aD0iMTEiIGhlaWdodD0iMTEiLz48cmVjdCBmaWxsPSIjMDBhNGVmIiB5PSIxMyIgd2lkdGg9IjExIiBoZWlnaHQ9IjExIi8+PHJlY3QgZmlsbD0iI2ZmYjkwMCIgeD0iMTMiIHk9IjEzIiB3aWR0aD0iMTEiIGhlaWdodD0iMTEiLz48L3N2Zz4='\n case 'discord':\n return 'data:image/svg+xml;base64,PHN2ZyB2aWV3Qm94PSIwIDAgMjQgMjQiIGZpbGw9IiM1ODY1RjIiPjxwYXRoIGQ9Ik0yMC4zMTcgNC4zNjk2QTE5Ljc5MTMgMTkuNzkxMyAwIDAgMCAxOC4yMDU4IDMuMzY5NmMtLjk2NDIuMzU2NC0xLjk5NTguNjE1NC0zLjA1OC43NzNhMTQuNzI0NCAxNC43MjQ0IDAgMCAwLTYuMjk1NCAwIDEzLjU0OTQgMTMuNTQ5NCAwIDAgMC0zLjA1OC0uNzczIDEzLjY5MyAxMy42OTMgMCAwIDAtNS4wNjc2LTEuMjc5NCAyMC4xOTg0IDIwLjE5ODQgMCAwIDAtMi42NDk3IDkuMTE2MyAyMC4yODE4IDIwLjI4MTggMCAwIDAgMi4zNzU4IDIuNjNjMS4zMzIyLjEyNTggMi42NjUuMTcyMiA0LjA0NC4xNzIyaDEuMzE1NGMxLjM3OSAwIDIuNzExOC0uMDQ2NCA0LjA0NC0uMTcyMmEyMC4yODE4IDIwLjI4MTggMCAwIDAgMi4zNzU4LTIuNjMgMjAuMTk4NCAyMC4xOTg0IDAgMCAwIDIuNjQ5Ny05LjExNjNBMTkuNzkxMyAxOS43OTEzIDAgMCAwIDIwLjMxNyA0LjM2OTZ6TTE4LjE5IDEyQzE3LjY3IDE0LjQ5IDEzLjk5IDE2IDEyIDE2UzYuMzMgMTQuNDkgNS44MSAxMmMuNTItMi40OSA0LjE5LTQgNi4xOS00UzE3LjY3IDkuNTEgMTguMTkgMTJ6Ii8+PC9zdmc+'\n default:\n // Return a generic icon for unknown providers\n return 'data:image/svg+xml;base64,PHN2ZyB2aWV3Qm94PSIwIDAgMjQgMjQiIGZpbGw9ImN1cnJlbnRDb2xvciI+PGNpcmNsZSBjeD0iMTIiIGN5PSIxMiIgcj0iMTAiLz48dGV4dCB4PSIxMiIgeT0iMTciIHRleHQtYW5jaG9yPSJtaWRkbGUiIGZpbGw9IndoaXRlIiBmb250LXNpemU9IjEyIj57cHJvdmlkZXIuaWQuY2hhckF0KDApLnRvVXBwZXJDYXNlKCl9PC90ZXh0Pjwvc3ZnPg=='\n }\n }\n\n return {\n providers: computed(() => providers.value),\n enabledProviders,\n loading: computed(() => loading.value),\n error: computed(() => error.value),\n fetchProviders,\n getProviderAuthUrl,\n redirectToProvider,\n getProviderById,\n getProviderIcon\n }\n}\n","<template>\n <div class=\"accui-component-scope\">\n <div :class=\"props.inModal ? 'auth-container-modal auth-full-width auth-min-width' : 'auth-container auth-full-width auth-min-width auth-max-width auth-center auth-slide-up'\">\n <div :class=\"props.inModal ? 'auth-content-modal' : 'auth-content auth-card-modern'\">\n <!-- Header -->\n <div class=\"auth-header\">\n <Transition name=\"fade\" mode=\"out-in\">\n <h1 :key=\"currentMode\" class=\"auth-title\">\n {{ isPasswordReset ? 'Reset password' : isSignUp ? 'Create account' : 'Welcome back' }}\n </h1>\n </Transition>\n <Transition name=\"fade\" mode=\"out-in\">\n <p :key=\"currentMode\" class=\"auth-subtitle\">\n {{ isPasswordReset ? 'Enter your email address and we\\'ll send you a link' : isSignUp\n ?\n 'We\\'ll send you a magic link to get started' : 'Sign in to your account to continue' }}\n </p>\n </Transition>\n </div>\n\n <!-- Tab Switcher (only show for signin/signup) -->\n <Transition \n name=\"smooth-height\" \n @before-enter=\"onBeforeEnter\" \n @enter=\"onEnter\" \n @before-leave=\"onBeforeLeave\" \n @leave=\"onLeave\" \n @after-leave=\"onAfterLeave\"\n >\n <div v-if=\"!isPasswordReset\" class=\"auth-tabs-container\">\n <StrandsUiTabs v-model=\"currentMode\" :tabs=\"[\n { label: 'Sign In', value: 'signin' },\n { label: 'Sign Up', value: 'signup' }\n ]\" />\n </div>\n </Transition>\n\n <!-- OAuth Providers (not shown for password reset) -->\n <Transition \n name=\"smooth-height\" \n @before-enter=\"onBeforeEnter\" \n @enter=\"onEnter\" \n @before-leave=\"onBeforeLeave\" \n @leave=\"onLeave\" \n @after-leave=\"onAfterLeave\"\n >\n <div v-if=\"!isPasswordReset && displayProviders?.length\" class=\"auth-oauth-providers\">\n <StrandsUiButton \n v-for=\"provider in displayProviders\" \n :key=\"provider.id\" \n variant=\"outline\" \n full-width\n :disabled=\"oauthLoading\"\n @click=\"handleOAuthAuth(provider.id)\" \n class=\"auth-oauth-button\"\n >\n <div class=\"auth-oauth-icon-container\">\n <!-- Dynamic provider icons -->\n <div v-if=\"provider.icon || provider.iconUrl\" class=\"auth-oauth-icon\">\n <img :src=\"provider.icon || provider.iconUrl\" :alt=\"`${provider.displayName || provider.name} icon`\" class=\"auth-oauth-icon\" />\n </div>\n <!-- Built-in SVG icons for common providers -->\n <svg v-else-if=\"provider.id === 'google'\" viewBox=\"0 0 24 24\" class=\"auth-oauth-icon\">\n <path fill=\"#4285F4\"\n d=\"M22.56 12.25c0-.78-.07-1.53-.2-2.25H12v4.26h5.92c-.26 1.37-1.04 2.53-2.21 3.31v2.77h3.57c2.08-1.92 3.28-4.74 3.28-8.09z\" />\n <path fill=\"#34A853\"\n d=\"M12 23c2.97 0 5.46-.98 7.28-2.66l-3.57-2.77c-.98.66-2.23 1.06-3.71 1.06-2.86 0-5.29-1.93-6.16-4.53H2.18v2.84C3.99 20.53 7.7 23 12 23z\" />\n <path fill=\"#FBBC05\"\n d=\"M5.84 14.09c-.22-.66-.35-1.36-.35-2.09s.13-1.43.35-2.09V7.07H2.18C1.43 8.55 1 10.22 1 12s.43 3.45 1.18 4.93l2.85-2.22.81-.62z\" />\n <path fill=\"#EA4335\"\n d=\"M12 5.38c1.62 0 3.06.56 4.21 1.64l3.15-3.15C17.45 2.09 14.97 1 12 1 7.7 1 3.99 3.47 2.18 7.07l3.66 2.84c.87-2.6 3.3-4.53 6.16-4.53z\" />\n </svg>\n <svg v-else-if=\"provider.id === 'github'\" class=\"auth-oauth-icon auth-oauth-github\" viewBox=\"0 0 24 24\">\n <path\n d=\"M12 0c-6.626 0-12 5.373-12 12 0 5.302 3.438 9.8 8.207 11.387.599.111.793-.261.793-.577v-2.234c-3.338.726-4.033-1.416-4.033-1.416-.546-1.387-1.333-1.756-1.333-1.756-1.089-.745.083-.729.083-.729 1.205.084 1.839 1.237 1.839 1.237 1.07 1.834 2.807 1.304 3.492.997.107-.775.418-1.305.762-1.604-2.665-.305-5.467-1.334-5.467-5.931 0-1.311.469-2.381 1.236-3.221-.124-.303-.535-1.524.117-3.176 0 0 1.008-.322 3.301 1.23.957-.266 1.983-.399 3.003-.404 1.02.005 2.047.138 3.006.404 2.291-1.552 3.297-1.23 3.297-1.23.653 1.653.242 2.874.118 3.176.77.84 1.235 1.911 1.235 3.221 0 4.609-2.807 5.624-5.479 5.921.43.372.823 1.102.823 2.222v3.293c0 .319.192.694.801.576 4.765-1.589 8.199-6.086 8.199-11.386 0-6.627-5.373-12-12-12z\" />\n </svg>\n <!-- Generic icon for other providers -->\n <div v-else class=\"auth-oauth-generic-icon\">\n <span class=\"auth-oauth-generic-text\">{{ (provider.displayName || provider.name).charAt(0).toUpperCase() }}</span>\n </div>\n </div>\n <span class=\"auth-oauth-text\">\n Continue with {{ provider.displayName || provider.name.charAt(0).toUpperCase() + provider.name.slice(1) }}\n </span>\n </StrandsUiButton>\n </div>\n </Transition>\n\n <!-- Divider (not shown for password reset) -->\n <Transition \n name=\"smooth-height\" \n @before-enter=\"onBeforeEnter\" \n @enter=\"onEnter\" \n @before-leave=\"onBeforeLeave\" \n @leave=\"onLeave\" \n @after-leave=\"onAfterLeave\"\n >\n <div v-if=\"!isPasswordReset && displayProviders?.length\" class=\"auth-divider\">\n <span class=\"auth-divider-text\">Or {{ isSignUp ? 'create account' : 'sign in' }} with email</span>\n </div>\n </Transition>\n\n <!-- Auth Form -->\n <form @submit.prevent=\"handleAuth\" class=\"auth-form\">\n <div>\n <!-- Email -->\n <div :class=\"['email-field-spacing', (!isPasswordReset && !isSignUp) ? 'has-password' : 'no-password']\">\n <StrandsUiInput v-model=\"form.email\" type=\"email\" label=\"Email address\" placeholder=\"Enter your email\" required\n autocomplete=\"email\" :error=\"error && !form.email ? 'Email is required' : ''\" />\n </div>\n\n <!-- Password (Sign In Only) -->\n <Transition \n name=\"smooth-height\" \n @before-enter=\"onBeforeEnter\" \n @enter=\"onEnter\" \n @before-leave=\"onBeforeLeave\" \n @leave=\"onLeave\" \n @after-leave=\"onAfterLeave\"\n >\n <div v-if=\"!isPasswordReset && !isSignUp\" class=\"auth-password-field\">\n <div class=\"auth-password-header\">\n <span class=\"auth-password-label\">Password</span>\n <StrandsUiLink variant=\"primary\" size=\"sm\" @click=\"currentMode = 'reset-password'\">\n Forgot password?\n </StrandsUiLink>\n </div>\n\n <StrandsUiInput v-model=\"form.password\" type=\"password\"\n placeholder=\"Enter your password\" required\n autocomplete=\"current-password\"\n :error=\"error && !form.password ? 'Password is required' : ''\" />\n </div>\n </Transition>\n </div>\n\n <StrandsUiButton type=\"submit\" variant=\"primary\" full-width :disabled=\"buttonLoading || !isFormValid\" :loading=\"buttonLoading\"\n :loading-text=\"loadingMessage\">\n {{ isPasswordReset\n ? (isPasswordResetSubmitted\n ? 'Link sent!'\n : 'Send reset link')\n : isSignUp\n ? 'Send magic link'\n : 'Sign in'\n }}\n </StrandsUiButton>\n </form>\n\n <!-- Success Message for Password Reset -->\n <Transition name=\"expand\" mode=\"out-in\">\n <StrandsUiAlert v-if=\"isPasswordReset && isPasswordResetSubmitted\" key=\"reset-success\" variant=\"success\"\n :message=\"`Check your email - We've sent a password reset link to ${form.email}`\"\n class=\"auth-success-alert\" />\n </Transition>\n\n <!-- Back to Sign In (Password Reset Only) -->\n <Transition \n name=\"smooth-height\" \n @before-enter=\"onBeforeEnter\" \n @enter=\"onEnter\" \n @before-leave=\"onBeforeLeave\" \n @leave=\"onLeave\" \n @after-leave=\"onAfterLeave\"\n >\n <div v-if=\"isPasswordReset\" class=\"auth-back-link-container\">\n <StrandsUiLink @click=\"currentMode = 'signin'\" class=\"auth-back-link\">\n <svg class=\"auth-back-icon\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M15 19l-7-7 7-7\" />\n </svg>\n Back to sign in\n </StrandsUiLink>\n </div>\n </Transition>\n\n <!-- Error Alert -->\n <StrandsUiAlert v-if=\"error\" variant=\"error\" :message=\"error\" class=\"auth-error-alert\" dismissible\n @dismiss=\"error = ''\" />\n\n <!-- Secured by footer -->\n <StrandsSecuredFooter :config=\"props.config\">\n <!-- Need help -->\n <Transition name=\"support-fade\" v-if=\"getSupportEmail()\">\n <p class=\"auth-support-text\">\n Need help?\n <StrandsUiLink variant=\"primary\" :href=\"`mailto:${getSupportEmail()}`\">\n Contact Support\n </StrandsUiLink>\n </p>\n </Transition>\n </StrandsSecuredFooter>\n </div>\n </div>\n \n <!-- MFA Verification Modal -->\n <StrandsMfaVerification\n :show=\"showMfaVerification\"\n :available-mfa-methods=\"availableMfaMethods\"\n @success=\"handleMfaSuccess\"\n @close=\"handleMfaClose\"\n @error=\"handleMfaError\"\n />\n </div>\n</template>\n\n<script setup lang=\"ts\">\nimport { ref, reactive, computed, watch, onMounted } from 'vue'\nimport { StrandsUiCard, StrandsUiButton, StrandsUiInput, StrandsUiAlert, StrandsUiLink, StrandsUiTabs } from '../ui'\nimport StrandsSecuredFooter from './StrandsSecuredFooter.vue'\nimport StrandsMfaVerification from './StrandsMfaVerification.vue'\nimport { useStrandsConfig, type StrandsAuthConfig } from '../composables/useStrandsConfig'\nimport { useOAuthProviders } from '../composables/useOAuthProviders'\nimport { useStrandsAuth } from '../composables/useStrandsAuth'\nimport type { AuthResponse } from '../../types'\n\ninterface Props {\n mode?: 'signin' | 'signup' | 'reset-password'\n redirectUrl?: string\n inModal?: boolean\n // Fallback config if no global config is provided\n config?: StrandsAuthConfig\n}\n\ninterface Emits {\n (e: 'success', user: any): void\n (e: 'error', error: string): void\n (e: 'forgot-password'): void\n (e: 'password-reset-sent', email: string): void\n (e: 'mode-changed', mode: 'signin' | 'signup' | 'reset-password'): void\n}\n\nconst props = withDefaults(defineProps<Props>(), {\n mode: 'signin',\n inModal: false,\n})\n\nconst emit = defineEmits<Emits>()\n\n// Get configuration\nconst { getUrl, getSupportEmail } = useStrandsConfig(props.config)\n\n// Authentication state management\nconst { \n signIn, \n setAuthData, \n mfaRequired, \n availableMfaMethods,\n verifyMfa,\n sendMfaEmailCode,\n currentUser,\n loadingMessage\n} = useStrandsAuth()\n\n// OAuth providers management\nconst { \n enabledProviders, \n loading: oauthLoading, \n error: oauthError,\n fetchProviders,\n redirectToProvider,\n getProviderIcon\n} = useOAuthProviders({\n redirectUrl: props.redirectUrl,\n})\n\n// Fetch OAuth providers on component mount\nonMounted(() => {\n fetchProviders().catch(err => {\n console.warn('Failed to fetch OAuth providers:', err)\n })\n})\n\n// Computed property to determine which providers to show\nconst displayProviders = computed(() => {\n // Only show providers from API\n return enabledProviders.value\n})\n\n// Auth API functions\nconst authApi = {\n async signIn(email: string, password: string): Promise<AuthResponse> {\n const response = await fetch(getUrl('signIn'), {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify({ email, password }),\n })\n\n if (!response.ok) {\n if (response.status === 401) {\n throw new Error('Invalid email or password')\n } else if (response.status === 403) {\n throw new Error('Please verify your email address before signing in')\n } else {\n throw new Error(`Sign in failed: ${response.status} ${response.statusText}`)\n }\n }\n\n const result: AuthResponse = await response.json()\n return result\n },\n\n async signUp(email: string, password: string, firstName: string, lastName: string) {\n const response = await fetch(getUrl('signUp'), {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify({ email, password, firstName, lastName }),\n })\n\n if (!response.ok) {\n const errorData = await response.json().catch(() => ({}))\n throw new Error(errorData.error?.message || `HTTP ${response.status}: ${response.statusText}`)\n }\n\n const result = await response.json()\n \n return result.message\n },\n\n async requestPasswordReset(email: string) {\n // Integration point: This endpoint needs to be added to the accounts-api\n // For now, we'll show a placeholder message\n throw new Error('Password reset functionality is not yet implemented in the API. Please contact support.')\n \n /* When the endpoint is added, use this:\n const response = await fetch(getUrl('passwordReset'), {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify({ email }),\n })\n\n if (!response.ok) {\n const errorData = await response.json().catch(() => ({}))\n throw new Error(errorData.error?.message || `HTTP ${response.status}: ${response.statusText}`)\n }\n\n const result = await response.json()\n if (!result.success) {\n throw new Error(result.error?.message || 'Password reset request failed')\n }\n\n return result.data\n */\n }\n}\n\nconst currentMode = ref(props.mode)\nconst buttonLoading = ref(false)\nconst error = ref('')\nconst isPasswordResetSubmitted = ref(false)\nconst showMfaVerification = ref(false)\n\nconst form = reactive({\n firstName: '',\n lastName: '',\n email: '',\n password: '',\n confirmPassword: ''\n})\n\nconst isSignUp = computed(() => currentMode.value === 'signup')\nconst isPasswordReset = computed(() => currentMode.value === 'reset-password')\n\nconst isPasswordMatch = computed(() => {\n return form.password === form.confirmPassword\n})\n\nconst isFormValid = computed(() => {\n if (isPasswordReset.value) {\n return form.email.trim() && !isPasswordResetSubmitted.value\n }\n\n if (isSignUp.value) {\n return form.email.trim()\n }\n\n return form.email.trim() && form.password\n})\n\n// Password strength constants for better performance\nconst PASSWORD_STRENGTH_CONFIGS = {\n weak: {\n label: 'Weak',\n color: 'border-red-300',\n bgColor: 'bg-red-400',\n textColor: 'text-red-600',\n width: 33\n },\n medium: {\n label: 'Medium',\n color: 'border-yellow-300',\n bgColor: 'bg-yellow-400',\n textColor: 'text-yellow-600',\n width: 66\n },\n strong: {\n label: 'Strong',\n color: 'border-emerald-300',\n bgColor: 'bg-emerald-400',\n textColor: 'text-emerald-600',\n width: 100\n }\n} as const\n\nconst getPasswordStrength = (password: string) => {\n let score = 0\n\n if (password.length >= 8) score += 1\n if (password.length >= 12) score += 1\n if (/[a-z]/.test(password)) score += 1\n if (/[A-Z]/.test(password)) score += 1\n if (/[0-9]/.test(password)) score += 1\n if (/[^A-Za-z0-9]/.test(password)) score += 1\n\n const config = score <= 2 ? PASSWORD_STRENGTH_CONFIGS.weak \n : score <= 4 ? PASSWORD_STRENGTH_CONFIGS.medium \n : PASSWORD_STRENGTH_CONFIGS.strong\n\n return { score, ...config }\n}\n\n// Watch for MFA requirement\nwatch(mfaRequired, (required) => {\n if (required) {\n showMfaVerification.value = true\n }\n}, { immediate: true })\n\n// MFA handlers\nconst handleMfaSuccess = () => {\n showMfaVerification.value = false\n // The auth composable will have updated the user state\n emit('success', currentUser.value)\n}\n\nconst handleMfaClose = () => {\n showMfaVerification.value = false\n // Reset form or allow user to try again\n}\n\nconst handleMfaError = (errorMessage: string) => {\n error.value = errorMessage\n emit('error', errorMessage)\n}\n\nconst handleAuth = async () => {\n buttonLoading.value = true\n error.value = ''\n\n try {\n if (isPasswordReset.value) {\n // Handle password reset\n await authApi.requestPasswordReset(form.email)\n isPasswordResetSubmitted.value = true\n emit('password-reset-sent', form.email)\n } else if (isSignUp.value) {\n // Handle sign up\n const response = await authApi.signUp(\n form.email,\n form.password,\n form.firstName,\n form.lastName\n )\n emit('success', response.user)\n } else {\n // Handle sign in using MFA-enabled composable\n const response = await signIn({\n email: form.email,\n password: form.password\n })\n \n // If MFA is not required, emit success immediately\n if (!response.mfa_required) {\n emit('success', response.user)\n }\n // If MFA is required, the MFA modal will be shown automatically\n }\n } catch (err) {\n const errorMessage = err instanceof Error ? err.message : 'An unexpected error occurred'\n error.value = errorMessage\n emit('error', errorMessage)\n } finally {\n buttonLoading.value = false\n }\n}\n\nconst handleOAuthAuth = async (providerId: string) => {\n try {\n await redirectToProvider(providerId, {\n redirectUrl: props.redirectUrl,\n })\n } catch (err) {\n const errorMessage = err instanceof Error ? err.message : `Failed to ${isSignUp.value ? 'sign up' : 'sign in'} with ${providerId}`\n error.value = errorMessage\n emit('error', errorMessage)\n }\n}\n\n// Watch for prop changes\nwatch(() => props.mode, (newMode) => {\n currentMode.value = newMode\n})\n\n// Watch for mode changes to clear form\nwatch(currentMode, (newMode) => {\n error.value = ''\n isPasswordResetSubmitted.value = false\n // Clear form when switching modes\n form.firstName = ''\n form.lastName = ''\n form.email = ''\n form.password = ''\n form.confirmPassword = ''\n emit('mode-changed', newMode)\n})\n\n// Enhanced transition handlers with staggered timing for multiple elements\nlet transitionCounter = 0\n\nconst onBeforeEnter = (el: Element) => {\n const element = el as HTMLElement\n // Set initial state immediately without any margins or padding\n element.style.height = '0'\n element.style.opacity = '0'\n element.style.marginTop = '0'\n element.style.marginBottom = '0'\n element.style.paddingTop = '0'\n element.style.paddingBottom = '0'\n element.style.overflow = 'hidden'\n}\n\nconst onEnter = (el: Element, done: () => void) => {\n const element = el as HTMLElement\n \n // Add small stagger delay for multiple elements\n const currentIndex = transitionCounter++\n const staggerDelay = currentIndex * 50 // 50ms stagger\n \n setTimeout(() => {\n // Force a reflow to ensure the initial state is applied\n element.offsetHeight\n \n // Get the natural height by temporarily removing height constraint\n element.style.height = 'auto'\n const height = element.offsetHeight\n element.style.height = '0'\n \n // Force another reflow\n element.offsetHeight\n \n // Start the transition\n element.style.transition = 'height 350ms cubic-bezier(0.23, 1, 0.32, 1), opacity 350ms cubic-bezier(0.23, 1, 0.32, 1), margin 350ms cubic-bezier(0.23, 1, 0.32, 1), padding 350ms cubic-bezier(0.23, 1, 0.32, 1)'\n \n // Apply final state\n requestAnimationFrame(() => {\n element.style.height = height + 'px'\n element.style.opacity = '1'\n element.style.marginTop = ''\n element.style.marginBottom = ''\n element.style.paddingTop = ''\n element.style.paddingBottom = ''\n })\n \n // Clean up after transition\n setTimeout(() => {\n element.style.height = ''\n element.style.transition = ''\n element.style.overflow = ''\n done()\n }, 350)\n }, staggerDelay)\n}\n\nconst onBeforeLeave = (el: Element) => {\n const element = el as HTMLElement\n // Set the current height explicitly before starting transition\n const height = element.offsetHeight\n element.style.height = height + 'px'\n element.style.overflow = 'hidden'\n \n // Reset counter when elements start leaving\n transitionCounter = 0\n}\n\nconst onLeave = (el: Element, done: () => void) => {\n const element = el as HTMLElement\n \n // Add small stagger delay for leave transitions too\n const currentIndex = transitionCounter++\n const staggerDelay = currentIndex * 30 // 30ms stagger for leaving\n \n setTimeout(() => {\n // Force a reflow\n element.offsetHeight\n \n // Start the transition with slightly faster leave animation\n element.style.transition = 'height 300ms cubic-bezier(0.23, 1, 0.32, 1), opacity 300ms cubic-bezier(0.23, 1, 0.32, 1), margin 300ms cubic-bezier(0.23, 1, 0.32, 1), padding 300ms cubic-bezier(0.23, 1, 0.32, 1)'\n \n // Apply final state\n requestAnimationFrame(() => {\n element.style.height = '0'\n element.style.opacity = '0'\n element.style.marginTop = '0'\n element.style.marginBottom = '0'\n element.style.paddingTop = '0'\n element.style.paddingBottom = '0'\n })\n \n // Clean up after transition\n setTimeout(() => {\n element.style.height = ''\n element.style.opacity = ''\n element.style.margin = ''\n element.style.padding = ''\n element.style.transition = ''\n element.style.overflow = ''\n done()\n }, 300)\n }, staggerDelay)\n}\n\nconst onAfterLeave = (el: Element) => {\n const element = el as HTMLElement\n // Final cleanup - ensure all inline styles are removed\n element.style.height = ''\n element.style.opacity = ''\n element.style.margin = ''\n element.style.padding = ''\n element.style.transition = ''\n element.style.overflow = ''\n}\n</script>\n\n<style scoped>\n/* Simple fade transition - gentle and smooth */\n.fade-enter-active,\n.fade-leave-active {\n transition: opacity 350ms cubic-bezier(0.16, 1, 0.3, 1);\n}\n\n.fade-enter-from,\n.fade-leave-to {\n opacity: 0;\n}\n\n/* Smooth height transitions - handled entirely by JavaScript */\n.smooth-height-enter-active,\n.smooth-height-leave-active {\n /* JavaScript handles all transition logic */\n}\n\n/* Support block transition - gentle fade with subtle scale */\n.support-fade-enter-active,\n.support-fade-leave-active {\n transition: all 400ms cubic-bezier(0.16, 1, 0.3, 1);\n}\n\n.support-fade-enter-from {\n opacity: 0;\n transform: scale(0.97) translateY(8px);\n}\n\n.support-fade-leave-to {\n opacity: 0;\n transform: scale(0.99) translateY(-4px);\n}\n\n.support-fade-enter-to,\n.support-fade-leave-from {\n opacity: 1;\n transform: scale(1) translateY(0);\n}\n\n/* Expand transition - for alerts using modern height animation */\n.expand-enter-active,\n.expand-leave-active {\n overflow: hidden;\n}\n\n/* Modern browsers with interpolate-size support for expand */\n@supports (interpolate-size: allow-keywords) {\n .expand-enter-active,\n .expand-leave-active {\n interpolate-size: allow-keywords;\n }\n \n .expand-enter-active {\n transition: \n opacity 550ms cubic-bezier(0.16, 1, 0.3, 1),\n height 550ms cubic-bezier(0.16, 1, 0.3, 1),\n transform 550ms cubic-bezier(0.16, 1, 0.3, 1);\n }\n \n .expand-leave-active {\n transition: \n opacity 550ms cubic-bezier(0.16, 1, 0.3, 1),\n height 550ms cubic-bezier(0.16, 1, 0.3, 1),\n transform 550ms cubic-bezier(0.16, 1, 0.3, 1);\n }\n \n .expand-enter-from {\n opacity: 0;\n height: 0;\n transform: scale(0.99) translateY(-2px);\n }\n \n .expand-leave-to {\n opacity: 0;\n height: 0;\n transform: scale(0.997) translateY(1px);\n }\n \n .expand-enter-to,\n .expand-leave-from {\n opacity: 1;\n height: auto;\n transform: scale(1) translateY(0);\n }\n}\n\n/* Fallback for expand in older browsers */\n@supports not (interpolate-size: allow-keywords) {\n .expand-enter-active {\n transition: \n opacity 550ms cubic-bezier(0.16, 1, 0.3, 1),\n max-height 550ms cubic-bezier(0.16, 1, 0.3, 1),\n transform 550ms cubic-bezier(0.16, 1, 0.3, 1);\n }\n \n .expand-leave-active {\n transition: \n opacity 550ms cubic-bezier(0.16, 1, 0.3, 1),\n max-height 550ms cubic-bezier(0.16, 1, 0.3, 1),\n transform 550ms cubic-bezier(0.16, 1, 0.3, 1);\n }\n \n .expand-enter-from {\n opacity: 0;\n max-height: 0;\n transform: scale(0.99) translateY(-2px);\n }\n \n .expand-leave-to {\n opacity: 0;\n max-height: 0;\n transform: scale(0.997) translateY(1px);\n }\n \n .expand-enter-to,\n .expand-leave-from {\n opacity: 1;\n max-height: 150px;\n transform: scale(1) translateY(0);\n }\n}\n\n/* Loading pulse animation */\n@keyframes pulse {\n 0%, 100% {\n opacity: 1;\n }\n 50% {\n opacity: 0.5;\n }\n}\n\n.animate-pulse {\n animation: pulse 2s cubic-bezier(0.4, 0, 0.6, 1) infinite;\n}\n\n/* Slide up animation for main container - elegant entrance */\n@keyframes slide-up {\n from {\n opacity: 0;\n transform: translateY(24px) scale(0.96);\n filter: blur(2px);\n }\n to {\n opacity: 1;\n transform: translateY(0) scale(1);\n filter: blur(0px);\n }\n}\n\n.animate-slide-up {\n animation: slide-up 600ms cubic-bezier(0.25, 0.46, 0.45, 0.94);\n}\n\n/* Fade in animation for alerts - gentle appearance */\n@keyframes fade-in {\n from {\n opacity: 0;\n transform: scale(0.97) translateY(6px);\n }\n to {\n opacity: 1;\n transform: scale(1) translateY(0);\n }\n}\n\n.animate-fade-in {\n animation: fade-in 400ms cubic-bezier(0.25, 0.46, 0.45, 0.94);\n}\n\n/* Email field spacing animation */\n.email-field-spacing {\n transition: margin-bottom 500ms cubic-bezier(0.16, 1, 0.3, 1);\n}\n\n.email-field-spacing.has-password {\n margin-bottom: 1rem; /* mb-4 equivalent */\n}\n\n.email-field-spacing.no-password {\n margin-bottom: 0;\n}\n\n/* Password field transitions now handled by JavaScript smooth-height system */\n\n/* Auth Container Styles */\n.auth-full-width {\n width: 100%;\n}\n\n.auth-min-width {\n min-width: 420px;\n}\n\n.auth-max-width {\n max-width: 28rem;\n}\n\n.auth-center {\n margin-left: auto;\n margin-right: auto;\n}\n\n.auth-slide-up {\n animation: slide-up 600ms cubic-bezier(0.25, 0.46, 0.45, 0.94);\n}\n\n.auth-card-modern {\n background: white;\n border-radius: 0.5rem;\n padding: 2rem;\n box-shadow: 0 10px 25px -5px rgba(0, 0, 0, 0.1), 0 10px 10px -5px rgba(0, 0, 0, 0.04);\n}\n\n/* Header Styles */\n.auth-header {\n text-align: center;\n margin-bottom: 2rem;\n}\n\n.auth-title {\n font-size: 1.875rem;\n font-weight: 700;\n background: linear-gradient(135deg, #EA00A8 0%, #FF6B9D 100%);\n background-clip: text;\n -webkit-background-clip: text;\n -webkit-text-fill-color: transparent;\n margin-bottom: 0.5rem;\n}\n\n.auth-subtitle {\n color: #737373;\n}\n\n/* Tabs Container */\n.auth-tabs-container {\n margin-bottom: 2rem;\n}\n\n/* OAuth Provider Styles */\n.auth-oauth-providers {\n display: flex;\n flex-direction: column;\n gap: 0.75rem;\n margin-bottom: 1.5rem;\n}\n\n.auth-oauth-button {\n /* Button styles will be handled by the UiButton component */\n}\n\n.auth-oauth-icon-container {\n width: 1.25rem;\n height: 1.25rem;\n display: flex;\n align-items: center;\n justify-content: center;\n}\n\n.auth-oauth-icon {\n width: 1.25rem;\n height: 1.25rem;\n}\n\n.auth-oauth-github {\n fill: currentColor;\n}\n\n.auth-oauth-generic-icon {\n width: 1.25rem;\n height: 1.25rem;\n border-radius: 50%;\n background-color: #d4d4d8;\n display: flex;\n align-items: center;\n justify-content: center;\n}\n\n.auth-oauth-generic-text {\n font-size: 0.75rem;\n font-weight: 600;\n color: #525252;\n}\n\n.auth-oauth-text {\n font-weight: 500;\n}\n\n/* Divider Styles */\n.auth-divider {\n position: relative;\n margin: 1.5rem 0;\n text-align: center;\n}\n\n.auth-divider::before {\n content: '';\n position: absolute;\n top: 50%;\n left: 0;\n right: 0;\n height: 1px;\n background: #e5e5e5;\n}\n\n.auth-divider-text {\n background: white;\n padding: 0 1rem;\n color: #737373;\n font-size: 0.875rem;\n position: relative;\n z-index: 1;\n}\n\n/* Form Styles */\n.auth-form {\n display: flex;\n flex-direction: column;\n gap: 1.5rem;\n}\n\n.auth-password-field {\n margin-bottom: 1rem;\n}\n\n.auth-password-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n margin-bottom: 0.5rem;\n}\n\n.auth-password-label {\n font-size: 0.875rem;\n font-weight: 500;\n color: #374151;\n}\n\n/* Alert Styles */\n.auth-success-alert {\n margin-top: 1.5rem;\n animation: fade-in 400ms cubic-bezier(0.25, 0.46, 0.45, 0.94);\n}\n\n.auth-error-alert {\n margin-top: 1.5rem;\n animation: fade-in 400ms cubic-bezier(0.25, 0.46, 0.45, 0.94);\n}\n\n/* Back Link Styles */\n.auth-back-link-container {\n margin-top: 2rem;\n text-align: center;\n}\n\n.auth-back-link {\n display: inline-flex;\n align-items: center;\n gap: 0.5rem;\n}\n\n.auth-back-icon {\n width: 1rem;\n height: 1rem;\n}\n\n/* Support Text */\n.auth-support-text {\n color: #a3a3a3;\n font-size: 0.875rem;\n}\n\n/* Modal-specific styles - removes border, radius, background, and padding */\n.auth-container-modal {\n}\n\n.auth-content-modal {\n /* Remove card styling when in modal */\n background: transparent;\n border: none;\n border-radius: 0;\n padding: 0;\n box-shadow: none;\n}\n\n</style>","<template>\n <svg viewBox=\"0 0 24 24\" class=\"accui-w-5 accui-h-5\">\n <path fill=\"#4285F4\"\n d=\"M22.56 12.25c0-.78-.07-1.53-.2-2.25H12v4.26h5.92c-.26 1.37-1.04 2.53-2.21 3.31v2.77h3.57c2.08-1.92 3.28-4.74 3.28-8.09z\" />\n <path fill=\"#34A853\"\n d=\"M12 23c2.97 0 5.46-.98 7.28-2.66l-3.57-2.77c-.98.66-2.23 1.06-3.71 1.06-2.86 0-5.29-1.93-6.16-4.53H2.18v2.84C3.99 20.53 7.7 23 12 23z\" />\n <path fill=\"#FBBC05\"\n d=\"M5.84 14.09c-.22-.66-.35-1.36-.35-2.09s.13-1.43.35-2.09V7.07H2.18C1.43 8.55 1 10.22 1 12s.43 3.45 1.18 4.93l2.85-2.22.81-.62z\" />\n <path fill=\"#EA4335\"\n d=\"M12 5.38c1.62 0 3.06.56 4.21 1.64l3.15-3.15C17.45 2.09 14.97 1 12 1 7.7 1 3.99 3.47 2.18 7.07l3.66 2.84c.87-2.6 3.3-4.53 6.16-4.53z\" />\n </svg>\n</template>\n\n<script setup lang=\"ts\">\n// Optimized Google icon component\n</script>","<template>\n <svg class=\"accui-w-5 accui-h-5 accui-fill-current\" viewBox=\"0 0 24 24\">\n <path\n d=\"M12 0c-6.626 0-12 5.373-12 12 0 5.302 3.438 9.8 8.207 11.387.599.111.793-.261.793-.577v-2.234c-3.338.726-4.033-1.416-4.033-1.416-.546-1.387-1.333-1.756-1.333-1.756-1.089-.745.083-.729.083-.729 1.205.084 1.839 1.237 1.839 1.237 1.07 1.834 2.807 1.304 3.492.997.107-.775.418-1.305.762-1.604-2.665-.305-5.467-1.334-5.467-5.931 0-1.311.469-2.381 1.236-3.221-.124-.303-.535-1.524.117-3.176 0 0 1.008-.322 3.301 1.23.957-.266 1.983-.399 3.003-.404 1.02.005 2.047.138 3.006.404 2.291-1.552 3.297-1.23 3.297-1.23.653 1.653.242 2.874.118 3.176.77.84 1.235 1.911 1.235 3.221 0 4.609-2.807 5.624-5.479 5.921.43.372.823 1.102.823 2.222v3.293c0 .319.192.694.801.576 4.765-1.589 8.199-6.086 8.199-11.386 0-6.627-5.373-12-12-12z\" />\n </svg>\n</template>\n\n<script setup lang=\"ts\">\n// Optimized GitHub icon component\n</script>","<template>\n <div class=\"accui-component-scope\">\n <div class=\"accui-w-full accui-min-w-100 accui-max-w-md accui-mx-auto accui-animate-slide-up\">\n <StrandsUiCard variant=\"modern\">\n <!-- Header -->\n <div class=\"accui-text-center accui-mb-8\">\n <h1 class=\"accui-text-3xl accui-font-bold accui-text-gradient accui-mb-2\">Welcome back</h1>\n <p class=\"accui-text-neutral-600\">Sign in to your account to continue</p>\n </div>\n\n <!-- OAuth Providers with v-memo optimization -->\n <div v-if=\"enabledProviders?.length\" class=\"accui-space-y-3 accui-mb-6\">\n <StrandsUiButton \n v-for=\"provider in enabledProviders\" \n v-memo=\"[provider.id, provider.name, provider.displayName, oauthLoading]\"\n :key=\"provider.id\" \n variant=\"outline\" \n full-width\n :disabled=\"oauthLoading\"\n @click=\"handleOAuthSignIn(provider.id)\" \n class=\"btn-oauth accui-group\"\n >\n <div class=\"accui-w-5 accui-h-5 accui-flex accui-items-center accui-justify-center\">\n <!-- Dynamic provider icons -->\n <div v-if=\"provider.icon || provider.iconUrl\" class=\"accui-w-5 accui-h-5\">\n <img :src=\"provider.icon || provider.iconUrl\" :alt=\"`${provider.displayName || provider.name} icon`\" class=\"accui-w-5 accui-h-5\" />\n </div>\n <!-- Optimized built-in icons for common providers -->\n <IconGoogle v-else-if=\"provider.id === 'google'\" />\n <IconGithub v-else-if=\"provider.id === 'github'\" />\n <div v-else class=\"accui-w-5 accui-h-5 accui-rounded-full accui-bg-neutral-300 accui-flex accui-items-center accui-justify-center\">\n <span class=\"accui-text-xs accui-font-semibold accui-text-neutral-600\">{{ (provider.displayName || provider.name).charAt(0).toUpperCase() }}</span>\n </div>\n </div>\n <span class=\"accui-font-medium\">Continue with {{ provider.displayName || provider.name }}</span>\n </StrandsUiButton>\n </div>\n\n <!-- Divider -->\n <div v-if=\"enabledProviders?.length\" class=\"divider-with-text\">\n <span class=\"divider-text\">Or sign in with email</span>\n </div>\n\n <!-- Email/Password Form -->\n <form @submit.prevent=\"handleSignIn\" class=\"accui-gap-6 accui-flex accui-flex-col\">\n <div>\n <!-- Email -->\n <div class=\"email-field-spacing has-password\">\n <StrandsUiInput id=\"email\" v-model=\"form.email\" type=\"email\" label=\"Email address\"\n placeholder=\"Enter your email address\" autocomplete=\"email\" required\n :error=\"error ? 'Invalid email or password' : undefined\" />\n </div>\n\n <!-- Password -->\n <div class=\"accui-mb-4\">\n <span class=\"accui-text-sm accui-font-medium accui-text-neutral-700 accui-block accui-mb-2\">Password</span>\n <StrandsUiInput id=\"password\" v-model=\"form.password\" type=\"password\" placeholder=\"Enter your password\"\n autocomplete=\"current-password\" required :error=\"error ? 'Invalid email or password' : undefined\" />\n </div>\n </div>\n\n <StrandsUiButton type=\"submit\" variant=\"primary\" full-width :disabled=\"loading || !form.email || !form.password\"\n :loading=\"loading\" :loading-text=\"'Signing in...'\">\n Sign in\n </StrandsUiButton>\n </form>\n\n <!-- Forgot password link - moved outside form to control tab order -->\n <div class=\"accui-text-center accui-mt-4\">\n <StrandsUiLink @click=\"$emit('forgot-password')\" class=\"accui-text-sm\">\n Forgot password?\n </StrandsUiLink>\n </div>\n\n <!-- Error Alert -->\n <StrandsUiAlert v-if=\"error\" variant=\"error\" :message=\"error\" class=\"accui-mt-6 accui-animate-fade-in\" dismissible\n @dismiss=\"error = ''\" />\n\n <!-- Sign up link -->\n <div class=\"accui-mt-8 accui-text-center\">\n <p class=\"accui-text-sm accui-text-neutral-600\">\n Don't have an account?\n <StrandsUiLink @click=\"$emit('switch-to-signup')\">\n Sign up\n </StrandsUiLink>\n </p>\n </div>\n\n \n <!-- Secured by footer -->\n <StrandsSecuredFooter :config=\"props.config\">\n <!-- Need help -->\n <div v-if=\"getSupportEmail()\">\n <p class=\"accui-text-neutral-400 accui-text-sm\">\n Need help?\n <StrandsUiLink variant=\"primary\" :href=\"`mailto:${getSupportEmail()}`\">\n Contact Support\n </StrandsUiLink>\n </p>\n </div>\n </StrandsSecuredFooter>\n </StrandsUiCard>\n \n <!-- MFA Verification Modal -->\n <StrandsMfaVerification\n :show=\"showMfaVerification\"\n :available-mfa-methods=\"availableMfaMethods\"\n :session-id=\"mfaSessionId\"\n @success=\"handleMfaSuccess\"\n @close=\"handleMfaClose\"\n @error=\"handleMfaError\"\n />\n \n </div>\n </div>\n</template>\n\n<script setup lang=\"ts\">\nimport { ref, reactive, computed, onMounted, watch } from 'vue'\nimport { StrandsUiCard, StrandsUiButton, StrandsUiInput, StrandsUiAlert, StrandsUiLink } from '../ui'\nimport StrandsSecuredFooter from './StrandsSecuredFooter.vue'\nimport StrandsMfaVerification from './StrandsMfaVerification.vue'\nimport { IconGoogle, IconGithub } from './icons'\nimport { useStrandsConfig, type StrandsAuthConfig } from '../composables/useStrandsConfig'\nimport { useOAuthProviders } from '../composables/useOAuthProviders'\nimport { useStrandsAuth } from '../composables/useStrandsAuth'\nimport type { AuthResponse } from '../../types'\n\ninterface Props {\n redirectUrl?: string\n oauthScopes?: string[]\n config?: StrandsAuthConfig\n}\n\ninterface Emits {\n (e: 'success', user: any): void\n (e: 'error', error: string): void\n (e: 'forgot-password'): void\n (e: 'switch-to-signup'): void\n}\n\nconst props = withDefaults(defineProps<Props>(), {\n oauthScopes: () => []\n})\n\nconst emit = defineEmits<Emits>()\n\n// Get configuration\nconst { getUrl, getSupportEmail } = useStrandsConfig(props.config)\n\n// Authentication state management\nconst { \n signIn,\n mfaRequired,\n mfaSessionId,\n availableMfaMethods,\n loading: authLoading,\n currentUser,\n sendMfaEmailCode \n} = useStrandsAuth()\n\n// OAuth providers management\nconst { \n enabledProviders, \n loading: oauthLoading, \n error: oauthError,\n fetchProviders,\n redirectToProvider\n} = useOAuthProviders({\n redirectUrl: props.redirectUrl,\n scopes: props.oauthScopes\n})\n\n// Fetch OAuth providers on component mount\nonMounted(() => {\n fetchProviders().catch(err => {\n console.warn('Failed to fetch OAuth providers:', err)\n })\n})\n\nconst loading = computed(() => authLoading.value)\nconst error = ref('')\nconst showMfaVerification = ref(false)\n\n// Watch for MFA requirement\nwatch(mfaRequired, (required) => {\n if (required) {\n showMfaVerification.value = true\n }\n})\n\nconst form = reactive({\n email: '',\n password: ''\n})\n\nconst handleSignIn = async () => {\n error.value = ''\n \n try {\n const authData = await signIn({\n email: form.email,\n password: form.password,\n })\n \n // If MFA is not required, emit success immediately\n if (!authData.mfa_required) {\n emit('success', authData.user)\n }\n // If MFA is required, the watch on mfaRequired will show the MFA modal\n } catch (err) {\n const errorMessage = err instanceof Error ? err.message : 'Sign in failed'\n error.value = errorMessage\n emit('error', errorMessage)\n }\n}\n\nconst handleMfaSuccess = () => {\n showMfaVerification.value = false\n // The auth composable will have updated the user state\n emit('success', currentUser.value)\n}\n\nconst handleMfaClose = () => {\n showMfaVerification.value = false\n // Reset form or allow user to try again\n}\n\nconst handleMfaError = (errorMessage: string) => {\n error.value = errorMessage\n emit('error', errorMessage)\n}\n\nconst handleOAuthSignIn = async (providerId: string) => {\n try {\n await redirectToProvider(providerId, {\n redirectUrl: props.redirectUrl,\n scopes: props.oauthScopes\n })\n } catch (err) {\n const errorMessage = err instanceof Error ? err.message : `Failed to sign in with ${providerId}`\n error.value = errorMessage\n emit('error', errorMessage)\n }\n}\n</script>\n\n<style scoped>\n/* Email field spacing to match StrandsAuth */\n.email-field-spacing {\n transition: margin-bottom 500ms cubic-bezier(0.16, 1, 0.3, 1);\n}\n\n.email-field-spacing.has-password {\n margin-bottom: 1rem; /* mb-4 equivalent */\n}\n\n.email-field-spacing.no-password {\n margin-bottom: 0;\n}\n\n/* Override accui- prefixed Tailwind classes with CSS properties */\n.accui-w-full {\n width: 100%;\n}\n\n.accui-min-w-100 {\n min-width: 25rem;\n}\n\n.accui-max-w-md {\n max-width: 28rem;\n}\n\n.accui-mx-auto {\n margin-left: auto;\n margin-right: auto;\n}\n\n.accui-animate-slide-up {\n animation: slideUp 0.3s ease-out;\n}\n\n.accui-text-center {\n text-align: center;\n}\n\n.accui-mb-8 {\n margin-bottom: 2rem;\n}\n\n.accui-text-3xl {\n font-size: 1.875rem;\n}\n\n.accui-font-bold {\n font-weight: 700;\n}\n\n.accui-text-gradient {\n background: linear-gradient(to right, var(--strands-500, #EA00A8), var(--strands-600, #db2777));\n background-clip: text;\n -webkit-background-clip: text;\n color: transparent;\n}\n\n.accui-mb-2 {\n margin-bottom: 0.5rem;\n}\n\n.accui-text-neutral-600 {\n color: var(--neutral-600, #525252);\n}\n\n.accui-space-y-3 > * + * {\n margin-top: 0.75rem;\n}\n\n.accui-mb-6 {\n margin-bottom: 1.5rem;\n}\n\n.accui-w-5 {\n width: 1.25rem;\n}\n\n.accui-h-5 {\n height: 1.25rem;\n}\n\n.accui-flex {\n display: flex;\n}\n\n.accui-items-center {\n align-items: center;\n}\n\n.accui-justify-center {\n justify-content: center;\n}\n\n.accui-rounded-full {\n border-radius: 50%;\n}\n\n.accui-bg-neutral-300 {\n background-color: var(--neutral-300, #d4d4d4);\n}\n\n.accui-text-xs {\n font-size: 0.75rem;\n}\n\n.accui-font-semibold {\n font-weight: 600;\n}\n\n.accui-text-neutral-600 {\n color: var(--neutral-600, #525252);\n}\n\n.accui-font-medium {\n font-weight: 500;\n}\n\n.accui-gap-6 {\n gap: 1.5rem;\n}\n\n.accui-flex-col {\n flex-direction: column;\n}\n\n.accui-mb-4 {\n margin-bottom: 1rem;\n}\n\n.accui-text-sm {\n font-size: 0.875rem;\n}\n\n.accui-text-neutral-700 {\n color: var(--neutral-700, #404040);\n}\n\n.accui-block {\n display: block;\n}\n\n.accui-mt-4 {\n margin-top: 1rem;\n}\n\n.accui-mt-6 {\n margin-top: 1.5rem;\n}\n\n.accui-animate-fade-in {\n animation: fadeIn 0.2s ease-out;\n}\n\n.accui-mt-8 {\n margin-top: 2rem;\n}\n\n.accui-text-neutral-400 {\n color: var(--neutral-400, #a3a3a3);\n}\n\n.accui-fill-current {\n fill: currentColor;\n}\n\n@keyframes slideUp {\n from {\n opacity: 0;\n transform: translateY(20px);\n }\n to {\n opacity: 1;\n transform: translateY(0);\n }\n}\n\n@keyframes fadeIn {\n from {\n opacity: 0;\n }\n to {\n opacity: 1;\n }\n}\n</style>","<template>\n <div class=\"accui-component-scope\">\n <div class=\"signup-container\">\n <!-- Success State -->\n <StrandsUiCard v-if=\"signupSuccess\" variant=\"modern\">\n <div class=\"signup-success\">\n <div class=\"signup-success-icon\">📧</div>\n <h1 class=\"signup-success-title\">{{ successTitle }}</h1>\n <p class=\"signup-success-message\">{{ successMessage }}</p>\n <div v-if=\"successEmail\" class=\"signup-success-email\">\n <strong>{{ successEmail }}</strong>\n </div>\n <p class=\"signup-success-instructions\">\n Click the link in your email to complete your account setup. The link will expire in 24 hours.\n </p>\n <StrandsUiButton\n variant=\"outline\"\n full-width\n @click=\"resetToForm\"\n >\n Send Another Link\n </StrandsUiButton>\n </div>\n </StrandsUiCard>\n\n <!-- Signup Form -->\n <StrandsUiCard v-else variant=\"modern\">\n <!-- Header -->\n <div class=\"signup-header\">\n <h1 class=\"signup-title\">Create account</h1>\n <p class=\"signup-subtitle\">We'll send you a magic link to get started</p>\n </div>\n\n <!-- OAuth Providers -->\n <div v-if=\"enabledProviders?.length\" class=\"oauth-providers\">\n <StrandsUiButton \n v-for=\"provider in enabledProviders\" \n :key=\"provider.id\" \n variant=\"outline\" \n full-width\n :disabled=\"oauthLoading\"\n @click=\"handleOAuthSignUp(provider.id)\" \n class=\"btn-oauth group\"\n >\n <div class=\"oauth-icon-container\">\n <!-- Dynamic provider icons -->\n <div v-if=\"provider.icon || provider.iconUrl\" class=\"oauth-icon\">\n <img :src=\"provider.icon || provider.iconUrl\" :alt=\"`${provider.displayName || provider.name} icon`\" class=\"oauth-icon-image\" />\n </div>\n <!-- Built-in SVG icons for common providers -->\n <svg v-else-if=\"provider.id === 'google'\" viewBox=\"0 0 24 24\" class=\"oauth-icon\">\n <path fill=\"#4285F4\"\n d=\"M22.56 12.25c0-.78-.07-1.53-.2-2.25H12v4.26h5.92c-.26 1.37-1.04 2.53-2.21 3.31v2.77h3.57c2.08-1.92 3.28-4.74 3.28-8.09z\" />\n <path fill=\"#34A853\"\n d=\"M12 23c2.97 0 5.46-.98 7.28-2.66l-3.57-2.77c-.98.66-2.23 1.06-3.71 1.06-2.86 0-5.29-1.93-6.16-4.53H2.18v2.84C3.99 20.53 7.7 23 12 23z\" />\n <path fill=\"#FBBC05\"\n d=\"M5.84 14.09c-.22-.66-.35-1.36-.35-2.09s.13-1.43.35-2.09V7.07H2.18C1.43 8.55 1 10.22 1 12s.43 3.45 1.18 4.93l2.85-2.22.81-.62z\" />\n <path fill=\"#EA4335\"\n d=\"M12 5.38c1.62 0 3.06.56 4.21 1.64l3.15-3.15C17.45 2.09 14.97 1 12 1 7.7 1 3.99 3.47 2.18 7.07l3.66 2.84c.87-2.6 3.3-4.53 6.16-4.53z\" />\n </svg>\n <svg v-else-if=\"provider.id === 'github'\" class=\"oauth-icon oauth-icon-github\" viewBox=\"0 0 24 24\">\n <path\n d=\"M12 0c-6.626 0-12 5.373-12 12 0 5.302 3.438 9.8 8.207 11.387.599.111.793-.261.793-.577v-2.234c-3.338.726-4.033-1.416-4.033-1.416-.546-1.387-1.333-1.756-1.333-1.756-1.089-.745.083-.729.083-.729 1.205.084 1.839 1.237 1.839 1.237 1.07 1.834 2.807 1.304 3.492.997.107-.775.418-1.305.762-1.604-2.665-.305-5.467-1.334-5.467-5.931 0-1.311.469-2.381 1.236-3.221-.124-.303-.535-1.524.117-3.176 0 0 1.008-.322 3.301 1.23.957-.266 1.983-.399 3.003-.404 1.02.005 2.047.138 3.006.404 2.291-1.552 3.297-1.23 3.297-1.23.653 1.653.242 2.874.118 3.176.77.84 1.235 1.911 1.235 3.221 0 4.609-2.807 5.624-5.479 5.921.43.372.823 1.102.823 2.222v3.293c0 .319.192.694.801.576 4.765-1.589 8.199-6.086 8.199-11.386 0-6.627-5.373-12-12-12z\" />\n </svg>\n <div v-else class=\"oauth-icon-fallback\">\n <span class=\"oauth-icon-fallback-text\">{{ (provider.displayName || provider.name).charAt(0).toUpperCase() }}</span>\n </div>\n </div>\n <span class=\"oauth-button-text\">Continue with {{ provider.displayName || provider.name }}</span>\n </StrandsUiButton>\n </div>\n\n <!-- Divider -->\n <div v-if=\"enabledProviders?.length\" class=\"divider-with-text\">\n <span class=\"divider-text\">Or create account with email</span>\n </div>\n\n <!-- Sign Up Form -->\n <form @submit.prevent=\"handleSignUp\" class=\"signup-form\">\n <!-- Email -->\n <div>\n <StrandsUiInput\n id=\"email\"\n v-model=\"form.email\"\n type=\"email\"\n label=\"Email address\"\n placeholder=\"Enter your email address\"\n autocomplete=\"email\"\n required\n :error=\"error\"\n />\n </div>\n\n <StrandsUiButton\n type=\"submit\"\n variant=\"primary\"\n full-width\n :disabled=\"loading\"\n :loading=\"loading\"\n loading-text=\"Sending magic link...\"\n >\n Send magic link\n </StrandsUiButton>\n </form>\n\n <!-- Error Alert -->\n <div v-if=\"error\" class=\"signup-error\">\n <div class=\"signup-error-content\">\n <div class=\"signup-error-icon-container\">\n <svg class=\"signup-error-icon\" fill=\"currentColor\" viewBox=\"0 0 20 20\">\n <path fill-rule=\"evenodd\"\n d=\"M10 18a8 8 0 100-16 8 8 0 000 16zM8.28 7.22a.75.75 0 00-1.06 1.06L8.94 10l-1.72 1.72a.75.75 0 101.06 1.06L10 11.06l1.72 1.72a.75.75 0 101.06-1.06L11.06 10l1.72-1.72a.75.75 0 00-1.06-1.06L10 8.94 8.28 7.22z\"\n clip-rule=\"evenodd\" />\n </svg>\n <p class=\"signup-error-message\">{{ error }}</p>\n </div>\n </div>\n </div>\n\n <!-- Sign in link -->\n <div class=\"signup-signin-link\">\n <p class=\"signup-signin-text\">\n Already have an account?\n <button type=\"button\"\n class=\"signup-signin-button\"\n @click=\"$emit('switch-to-signin')\">\n Sign in\n </button>\n </p>\n </div>\n\n <!-- Secured by footer -->\n <StrandsSecuredFooter :config=\"props.config\">\n <!-- Need help -->\n <div v-if=\"getSupportEmail()\">\n <p class=\"signup-support-text\">\n Need help?\n <StrandsUiLink variant=\"primary\" :href=\"`mailto:${getSupportEmail()}`\">\n Contact Support\n </StrandsUiLink>\n </p>\n </div>\n </StrandsSecuredFooter>\n </StrandsUiCard>\n </div>\n </div>\n</template>\n\n<script setup lang=\"ts\">\nimport { ref, reactive, computed, onMounted } from 'vue'\nimport { StrandsUiCard, StrandsUiButton, StrandsUiInput, StrandsUiAlert, StrandsUiLink } from '../ui'\nimport StrandsSecuredFooter from './StrandsSecuredFooter.vue'\nimport { useStrandsConfig, type StrandsAuthConfig } from '../composables/useStrandsConfig'\nimport { useOAuthProviders } from '../composables/useOAuthProviders'\n\ninterface Props {\n redirectUrl?: string\n oauthScopes?: string[]\n config?: StrandsAuthConfig\n}\n\ninterface Emits {\n (e: 'success', user: any): void\n (e: 'error', error: string): void\n (e: 'switch-to-signin'): void\n}\n\nconst props = withDefaults(defineProps<Props>(), {\n oauthScopes: () => []\n})\n\nconst emit = defineEmits<Emits>()\n\n// Get configuration\nconst { getUrl, getSupportEmail } = useStrandsConfig(props.config)\n\n// OAuth providers management\nconst { \n enabledProviders, \n loading: oauthLoading, \n error: oauthError,\n fetchProviders,\n redirectToProvider\n} = useOAuthProviders({\n redirectUrl: props.redirectUrl,\n scopes: props.oauthScopes\n})\n\n// Fetch OAuth providers on component mount\nonMounted(() => {\n fetchProviders().catch(err => {\n console.warn('Failed to fetch OAuth providers:', err)\n })\n})\n\nconst loading = ref(false)\nconst error = ref('')\nconst signupSuccess = ref(false)\nconst successMessage = ref('')\nconst successTitle = ref('Magic Link Sent!')\nconst successEmail = ref('')\n\nconst form = reactive({\n email: ''\n})\n\nconst isFormValid = computed(() => {\n return form.email.trim() && form.email.includes('@')\n})\n\nconst handleSignUp = async () => {\n loading.value = true\n error.value = ''\n\n try {\n const signUpUrl = getUrl('signUp')\n console.log('Attempting sign up to URL:', signUpUrl)\n \n const response = await fetch(signUpUrl, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify({\n email: form.email\n }),\n })\n\n if (process.env['NODE_ENV'] === 'development') {\n console.log('Sign up response status:', response.status)\n }\n\n if (!response.ok) {\n let errorMessage = `Sign up failed (${response.status})`\n try {\n const errorData = await response.json()\n errorMessage = errorData.message || errorData.error || errorMessage\n } catch {\n const errorText = await response.text()\n errorMessage = errorText || errorMessage\n }\n throw new Error(errorMessage)\n }\n\n const result = await response.json()\n console.log('Magic link sign up success:', result)\n \n // Handle success state internally\n signupSuccess.value = true\n successEmail.value = form.email\n successMessage.value = result.message || 'Magic link sent! Check your email.'\n \n // Set appropriate title based on message content\n if (result.message) {\n if (result.message.includes('already have an account') || result.message.includes('Welcome back')) {\n successTitle.value = 'Welcome Back!'\n } else if (result.message.includes('Magic link sent') || result.message.includes('Check your email')) {\n successTitle.value = 'Magic Link Sent!'\n } else {\n successTitle.value = 'Success!'\n }\n }\n \n // Still emit for any parent that might need it\n emit('success', {\n email: form.email,\n message: result.message || 'Magic link sent! Check your email.'\n })\n } catch (err) {\n console.error('Sign up error:', err)\n \n let errorMessage = 'Unable to send magic link. Please try again.'\n \n if (err instanceof Error) {\n if (err.message.includes('fetch')) {\n errorMessage = 'Unable to connect to authentication service. Please check your internet connection and try again.'\n } else if (err.message.includes('CORS')) {\n const supportEmail = getSupportEmail()\n errorMessage = supportEmail \n ? `Authentication service configuration error. Please contact ${supportEmail}.`\n : 'Authentication service configuration error.'\n } else {\n errorMessage = err.message\n }\n }\n \n error.value = errorMessage\n emit('error', errorMessage)\n } finally {\n loading.value = false\n }\n}\n\nconst resetToForm = () => {\n signupSuccess.value = false\n successMessage.value = ''\n successTitle.value = 'Magic Link Sent!'\n successEmail.value = ''\n form.email = ''\n error.value = ''\n}\n\nconst handleOAuthSignUp = async (providerId: string) => {\n try {\n await redirectToProvider(providerId, {\n redirectUrl: props.redirectUrl,\n scopes: props.oauthScopes\n })\n } catch (err) {\n const errorMessage = err instanceof Error ? err.message : `Failed to sign up with ${providerId}`\n error.value = errorMessage\n emit('error', errorMessage)\n }\n}\n</script>\n\n<style scoped>\n.signup-container {\n width: 100%;\n min-width: 25rem;\n max-width: 28rem;\n margin: 0 auto;\n animation: slideUp 0.3s ease-out;\n}\n\n@keyframes slideUp {\n from {\n opacity: 0;\n transform: translateY(20px);\n }\n to {\n opacity: 1;\n transform: translateY(0);\n }\n}\n\n/* Success State */\n.signup-success {\n text-align: center;\n}\n\n.signup-success-icon {\n color: #10b981;\n font-size: 3.75rem;\n margin-bottom: 1rem;\n}\n\n.signup-success-title {\n font-size: 1.5rem;\n font-weight: 700;\n color: #111827;\n margin-bottom: 0.5rem;\n}\n\n.signup-success-message {\n color: #6b7280;\n margin-bottom: 1rem;\n}\n\n.signup-success-email {\n font-size: 0.875rem;\n color: #6b7280;\n margin-bottom: 1rem;\n}\n\n.signup-success-instructions {\n font-size: 0.875rem;\n color: #6b7280;\n margin-bottom: 1.5rem;\n}\n\n/* Header */\n.signup-header {\n text-align: center;\n margin-bottom: 2rem;\n}\n\n.signup-title {\n font-size: 1.875rem;\n font-weight: 700;\n background: linear-gradient(135deg, #EA00A8 0%, #FF6B9D 50%, #B8006F 100%);\n -webkit-background-clip: text;\n background-clip: text;\n -webkit-text-fill-color: transparent;\n margin-bottom: 0.5rem;\n}\n\n.signup-subtitle {\n color: #6b7280;\n}\n\n/* OAuth Providers */\n.oauth-providers {\n display: flex;\n flex-direction: column;\n gap: 0.75rem;\n margin-bottom: 1.5rem;\n}\n\n.oauth-icon-container {\n width: 1.25rem;\n height: 1.25rem;\n display: flex;\n align-items: center;\n justify-content: center;\n}\n\n.oauth-icon {\n width: 1.25rem;\n height: 1.25rem;\n}\n\n.oauth-icon-image {\n width: 1.25rem;\n height: 1.25rem;\n}\n\n.oauth-icon-github {\n fill: currentColor;\n}\n\n.oauth-icon-fallback {\n width: 1.25rem;\n height: 1.25rem;\n border-radius: 50%;\n background-color: #d1d5db;\n display: flex;\n align-items: center;\n justify-content: center;\n}\n\n.oauth-icon-fallback-text {\n font-size: 0.75rem;\n font-weight: 600;\n color: #6b7280;\n}\n\n.oauth-button-text {\n font-weight: 500;\n}\n\n/* Form */\n.signup-form {\n display: flex;\n flex-direction: column;\n gap: 1.5rem;\n}\n\n/* Error Alert */\n.signup-error {\n margin-top: 1.5rem;\n animation: fadeIn 0.3s ease-out;\n}\n\n@keyframes fadeIn {\n from {\n opacity: 0;\n }\n to {\n opacity: 1;\n }\n}\n\n.signup-error-content {\n background-color: #fef2f2;\n border: 1px solid #fecaca;\n border-radius: 0.5rem;\n padding: 1rem;\n}\n\n.signup-error-icon-container {\n display: flex;\n align-items: flex-start;\n gap: 0.75rem;\n}\n\n.signup-error-icon {\n width: 1rem;\n height: 1rem;\n margin-top: 0.125rem;\n flex-shrink: 0;\n color: #dc2626;\n}\n\n.signup-error-message {\n font-weight: 500;\n color: #dc2626;\n}\n\n/* Sign in link */\n.signup-signin-link {\n margin-top: 2rem;\n text-align: center;\n}\n\n.signup-signin-text {\n font-size: 0.875rem;\n color: #6b7280;\n}\n\n.signup-signin-button {\n font-weight: 600;\n color: #EA00A8;\n background: none;\n border: none;\n cursor: pointer;\n transition: color 0.2s ease;\n margin-left: 0.25rem;\n}\n\n.signup-signin-button:hover {\n color: #B8006F;\n}\n\n/* Support text */\n.signup-support-text {\n color: #9ca3af;\n font-size: 0.875rem;\n}\n\n/* Responsive */\n@media (max-width: 640px) {\n .signup-container {\n min-width: auto;\n max-width: none;\n width: 100%;\n }\n \n .signup-title {\n font-size: 1.5rem;\n }\n}\n</style>","<template>\n <div class=\"accui-component-scope\">\n <!-- Success State -->\n <div v-if=\"registrationComplete\" class=\"complete-signup-container\">\n <StrandsUiCard variant=\"modern\">\n <div class=\"complete-signup-success\">\n <div class=\"complete-signup-success-icon\">🎉</div>\n <h1 class=\"complete-signup-success-title\">Welcome to Strands!</h1>\n <p class=\"complete-signup-success-message\">\n Your account has been created successfully.\n </p>\n <p class=\"complete-signup-success-instructions\">\n You are now signed in and can access your dashboard.\n </p>\n <StrandsUiButton \n variant=\"primary\" \n full-width \n @click=\"redirectToReferrer\"\n >\n Go to Dashboard\n </StrandsUiButton>\n </div>\n <StrandsSecuredFooter />\n </StrandsUiCard>\n </div>\n\n <!-- Invalid Token State -->\n <div v-else-if=\"invalidToken\" class=\"complete-signup-container\">\n <StrandsUiCard variant=\"modern\">\n <div class=\"complete-signup-error\">\n <div class=\"complete-signup-error-icon\">❌</div>\n <h1 class=\"complete-signup-error-title\">Invalid Link</h1>\n <p class=\"complete-signup-error-message\">\n This registration link is invalid or has expired.\n </p>\n <p class=\"complete-signup-error-instructions\">\n Please request a new magic link to complete your registration.\n </p>\n <StrandsUiButton\n variant=\"primary\"\n full-width\n @click=\"$emit('request-new-link')\"\n >\n Request New Link\n </StrandsUiButton>\n </div>\n <StrandsSecuredFooter />\n </StrandsUiCard>\n </div>\n\n <!-- Registration Form -->\n <div v-else-if=\"token\" class=\"complete-signup-container\">\n <StrandsUiCard variant=\"modern\">\n <!-- Header -->\n <div class=\"complete-signup-header\">\n <h1 class=\"complete-signup-title\">Complete Your Registration</h1>\n <p class=\"complete-signup-subtitle\">Set up your account details to finish registration</p>\n <div v-if=\"email\" class=\"complete-signup-email-info\">\n <p class=\"complete-signup-email-text\">Creating account for: <span class=\"complete-signup-email-highlight\">{{ email }}</span></p>\n </div>\n </div>\n\n <!-- Registration Form -->\n <form @submit.prevent=\"handleCompleteSignUp\" class=\"complete-signup-form\">\n\n <!-- First Name -->\n <div>\n <StrandsUiInput\n id=\"firstName\"\n v-model=\"form.firstName\"\n type=\"text\"\n label=\"First Name (Optional)\"\n placeholder=\"Enter your first name\"\n autocomplete=\"given-name\"\n :error=\"fieldErrors.firstName\"\n />\n </div>\n\n <!-- Last Name -->\n <div>\n <StrandsUiInput\n id=\"lastName\"\n v-model=\"form.lastName\"\n type=\"text\"\n label=\"Last Name (Optional)\"\n placeholder=\"Enter your last name\"\n autocomplete=\"family-name\"\n :error=\"fieldErrors.lastName\"\n />\n </div>\n\n <!-- Password -->\n <div>\n <StrandsUiInput\n id=\"password\"\n v-model=\"form.password\"\n type=\"password\"\n label=\"Password\"\n placeholder=\"Create a strong password\"\n autocomplete=\"new-password\"\n required\n minlength=\"8\"\n :error=\"fieldErrors.password\"\n />\n <div class=\"complete-signup-password-hint\">\n Password must be at least 8 characters long\n </div>\n </div>\n\n <StrandsUiButton\n type=\"submit\"\n variant=\"primary\"\n full-width\n :disabled=\"loading || !isFormValid\"\n :loading=\"loading\"\n loading-text=\"Creating account...\"\n >\n Complete Registration\n </StrandsUiButton>\n </form>\n\n <!-- Error Alert -->\n <StrandsUiAlert \n v-if=\"error\" \n variant=\"error\" \n :message=\"error\" \n class=\"complete-signup-error-alert\" \n dismissible \n @dismiss=\"error = ''\"\n />\n \n <!-- Secured by footer -->\n <StrandsSecuredFooter :config=\"props.config\">\n <!-- Need help -->\n <div v-if=\"getSupportEmail()\" class=\"complete-signup-support\">\n <p class=\"complete-signup-support-text\">\n Need help?\n <StrandsUiLink variant=\"primary\" :href=\"`mailto:${getSupportEmail()}`\">\n Contact Support\n </StrandsUiLink>\n </p>\n </div>\n </StrandsSecuredFooter>\n </StrandsUiCard>\n\n </div>\n\n <!-- No Token State -->\n <div v-else class=\"complete-signup-container\">\n <StrandsUiCard variant=\"modern\">\n <div class=\"complete-signup-warning\">\n <div class=\"complete-signup-warning-icon\">⚠️</div>\n <h1 class=\"complete-signup-warning-title\">Missing Token</h1>\n <p class=\"complete-signup-warning-message\">\n No registration token was provided.\n </p>\n <p class=\"complete-signup-warning-instructions\">\n This page requires a valid registration token from the magic link in your email.\n </p>\n <StrandsUiButton\n variant=\"primary\"\n full-width\n @click=\"$emit('start-registration')\"\n >\n Start Registration\n </StrandsUiButton>\n </div>\n <StrandsSecuredFooter />\n </StrandsUiCard>\n </div>\n </div>\n</template>\n\n<script setup lang=\"ts\">\nimport { ref, reactive, computed, onMounted, watch } from 'vue'\nimport { StrandsUiCard, StrandsUiButton, StrandsUiInput, StrandsUiAlert, StrandsUiLink } from '../ui'\nimport StrandsSecuredFooter from './StrandsSecuredFooter.vue'\nimport { useStrandsConfig, type StrandsAuthConfig } from '../composables/useStrandsConfig'\nimport { useStrandsAuth } from '../composables/useStrandsAuth'\nimport type { AuthResponse } from '../../types'\n\ninterface Props {\n token?: string\n redirectUrl?: string\n config?: StrandsAuthConfig\n}\n\ninterface Emits {\n (e: 'success', result: any): void\n (e: 'error', error: string): void\n (e: 'invalid-token'): void\n (e: 'request-new-link'): void\n (e: 'start-registration'): void\n}\n\nconst props = defineProps<Props>()\n\nconst emit = defineEmits<Emits>()\n\n// Get configuration\nconst { getUrl, getSupportEmail } = useStrandsConfig(props.config)\n\n// Auth composable for token storage\nconst { setAuthData } = useStrandsAuth()\n\n// State management\nconst registrationComplete = ref(false)\nconst invalidToken = ref(false)\nconst loading = ref(false)\nconst error = ref('')\nconst email = ref('')\n\nconst form = reactive({\n firstName: '',\n lastName: '',\n password: ''\n})\n\nconst fieldErrors = reactive({\n firstName: '',\n lastName: '',\n password: ''\n})\n\n// Validate form\nconst isFormValid = computed(() => {\n const hasRequiredFields = form.password.trim()\n const passwordMinLength = form.password.length >= 8\n const hasValidToken = !!props.token\n \n return hasRequiredFields && passwordMinLength && hasValidToken\n})\n\n// Watch for password length\nwatch(\n () => form.password,\n (password) => {\n if (password && password.length < 8) {\n fieldErrors.password = 'Password must be at least 8 characters long'\n } else {\n fieldErrors.password = ''\n }\n }\n)\n\n\n// Redirect URL fallback\nconst redirectUrl = computed(() => props.redirectUrl || window.location.origin)\n\n// Extract email from JWT token for display\nonMounted(() => {\n if (props.token) {\n try {\n const parts = props.token.split('.')\n if (parts.length === 3) {\n const payload = JSON.parse(atob(parts[1]))\n if (payload.email) {\n email.value = payload.email\n }\n }\n } catch (err) {\n console.warn('Could not decode token for email display:', err)\n }\n }\n})\n\nconst redirectToReferrer = () => {\n if (redirectUrl.value) {\n console.log('Redirecting to referrer:', redirectUrl.value)\n window.location.href = redirectUrl.value\n }\n}\n\nconst handleCompleteSignUp = async () => {\n if (!props.token) {\n error.value = 'Registration token is required'\n return\n }\n\n // Clear all errors\n error.value = ''\n Object.keys(fieldErrors).forEach(key => {\n fieldErrors[key as keyof typeof fieldErrors] = ''\n })\n\n // Validate form\n if (!isFormValid.value) {\n error.value = 'Please fill in all required fields correctly'\n return\n }\n\n loading.value = true\n\n try {\n // Prepare headers with session context information\n const headers: Record<string, string> = {\n 'Content-Type': 'application/json',\n }\n \n // Note: User-Agent is set automatically by the browser and cannot be overridden for security reasons\n // The browser will send the correct User-Agent header automatically\n \n // Add Origin header for session tracking\n if (typeof window !== 'undefined' && window.location) {\n headers['Origin'] = window.location.origin\n }\n \n const response = await fetch(getUrl('completeRegistration'), {\n method: 'POST',\n headers,\n body: JSON.stringify({\n token: props.token,\n password: form.password,\n first_name: form.firstName || null,\n last_name: form.lastName || null\n }),\n })\n\n if (!response.ok) {\n const errorText = await response.text()\n throw new Error(`Failed to complete registration: ${errorText}`)\n }\n\n const result: AuthResponse = await response.json()\n console.log('Registration success:', result)\n \n // Store authentication data if tokens are present\n if (result.access_token && result.refresh_token && result.user) {\n setAuthData(result)\n console.log('Auth tokens stored successfully for user:', result.user.email)\n } else {\n console.warn('Registration response missing auth tokens or user data')\n }\n \n registrationComplete.value = true\n emit('success', result)\n \n // Redirect to referrer URL after successful registration\n setTimeout(() => {\n redirectToReferrer()\n }, 2000) // Give user 2 seconds to see the success message\n } catch (err) {\n if (err instanceof Error) {\n if (err.message.includes('CONFLICT') || err.message.includes('409')) {\n error.value = 'This account already exists. Please try signing in instead.'\n } else if (err.message.includes('BAD_REQUEST') || err.message.includes('400')) {\n error.value = 'Invalid or expired registration link. Please request a new one.'\n invalidToken.value = true\n emit('invalid-token')\n } else {\n error.value = err.message\n }\n } else {\n error.value = 'Failed to complete registration. Please try again.'\n }\n emit('error', error.value)\n } finally {\n loading.value = false\n }\n}\n</script>\n\n<style scoped>\n.complete-signup-container {\n width: 100%;\n min-width: 25rem;\n max-width: 28rem;\n margin: 0 auto;\n animation: slideUp 0.3s ease-out;\n}\n\n@keyframes slideUp {\n from {\n opacity: 0;\n transform: translateY(20px);\n }\n to {\n opacity: 1;\n transform: translateY(0);\n }\n}\n\n@keyframes fadeIn {\n from {\n opacity: 0;\n }\n to {\n opacity: 1;\n }\n}\n\n/* Success State */\n.complete-signup-success {\n text-align: center;\n}\n\n.complete-signup-success-icon {\n color: #10b981;\n font-size: 3.75rem;\n margin-bottom: 1rem;\n}\n\n.complete-signup-success-title {\n font-size: 1.875rem;\n font-weight: 700;\n background: linear-gradient(135deg, #EA00A8 0%, #FF6B9D 50%, #B8006F 100%);\n -webkit-background-clip: text;\n background-clip: text;\n -webkit-text-fill-color: transparent;\n margin-bottom: 0.5rem;\n}\n\n.complete-signup-success-message {\n color: #6b7280;\n margin-bottom: 1rem;\n}\n\n.complete-signup-success-instructions {\n font-size: 0.875rem;\n color: #6b7280;\n margin-bottom: 1.5rem;\n}\n\n/* Error State */\n.complete-signup-error {\n text-align: center;\n}\n\n.complete-signup-error-icon {\n color: #dc2626;\n font-size: 3.75rem;\n margin-bottom: 1rem;\n}\n\n.complete-signup-error-title {\n font-size: 1.875rem;\n font-weight: 700;\n background: linear-gradient(135deg, #EA00A8 0%, #FF6B9D 50%, #B8006F 100%);\n -webkit-background-clip: text;\n background-clip: text;\n -webkit-text-fill-color: transparent;\n margin-bottom: 0.5rem;\n}\n\n.complete-signup-error-message {\n color: #6b7280;\n margin-bottom: 1rem;\n}\n\n.complete-signup-error-instructions {\n font-size: 0.875rem;\n color: #6b7280;\n margin-bottom: 1.5rem;\n}\n\n/* Warning State */\n.complete-signup-warning {\n text-align: center;\n}\n\n.complete-signup-warning-icon {\n color: #f59e0b;\n font-size: 3.75rem;\n margin-bottom: 1rem;\n}\n\n.complete-signup-warning-title {\n font-size: 1.875rem;\n font-weight: 700;\n background: linear-gradient(135deg, #EA00A8 0%, #FF6B9D 50%, #B8006F 100%);\n -webkit-background-clip: text;\n background-clip: text;\n -webkit-text-fill-color: transparent;\n margin-bottom: 0.5rem;\n}\n\n.complete-signup-warning-message {\n color: #6b7280;\n margin-bottom: 1rem;\n}\n\n.complete-signup-warning-instructions {\n font-size: 0.875rem;\n color: #6b7280;\n margin-bottom: 1.5rem;\n}\n\n/* Header */\n.complete-signup-header {\n text-align: center;\n margin-bottom: 2rem;\n}\n\n.complete-signup-title {\n font-size: 1.875rem;\n font-weight: 700;\n background: linear-gradient(135deg, #EA00A8 0%, #FF6B9D 50%, #B8006F 100%);\n -webkit-background-clip: text;\n background-clip: text;\n -webkit-text-fill-color: transparent;\n margin-bottom: 0.5rem;\n}\n\n.complete-signup-subtitle {\n color: #6b7280;\n}\n\n.complete-signup-email-info {\n margin-top: 0.5rem;\n}\n\n.complete-signup-email-text {\n font-size: 0.875rem;\n color: #6b7280;\n}\n\n.complete-signup-email-highlight {\n font-weight: 500;\n color: #374151;\n}\n\n/* Form */\n.complete-signup-form {\n display: flex;\n flex-direction: column;\n gap: 1.5rem;\n}\n\n.complete-signup-password-hint {\n margin-top: 0.5rem;\n font-size: 0.75rem;\n color: #6b7280;\n}\n\n/* Error Alert */\n.complete-signup-error-alert {\n margin-top: 1.5rem;\n animation: fadeIn 0.3s ease-out;\n}\n\n/* Support */\n.complete-signup-support {\n margin-top: 1.5rem;\n text-align: center;\n}\n\n.complete-signup-support-text {\n color: #9ca3af;\n font-size: 0.875rem;\n}\n\n/* Responsive */\n@media (max-width: 640px) {\n .complete-signup-container {\n min-width: auto;\n max-width: none;\n width: 100%;\n }\n \n .complete-signup-title,\n .complete-signup-success-title,\n .complete-signup-error-title,\n .complete-signup-warning-title {\n font-size: 1.5rem;\n }\n \n .complete-signup-success-icon,\n .complete-signup-error-icon,\n .complete-signup-warning-icon {\n font-size: 3rem;\n }\n}\n</style>","<template>\n <div class=\"accui-component-scope\">\n <UiModal :open=\"show\" @close=\"closeModal\" card-class=\"modal-card\">\n <template #header>\n <div class=\"modal-header\">\n <h2 class=\"modal-title\">Setup Authenticator App</h2>\n <button @click=\"closeModal\" class=\"modal-close-button\">\n <svg class=\"modal-close-icon\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M6 18L18 6M6 6l12 12\" />\n </svg>\n </button>\n </div>\n </template>\n <!-- Step 1: Device Name -->\n <div v-if=\"step === 1\" class=\"step-container\">\n <div>\n <h3 class=\"step-title\">Name Your Device</h3>\n <p class=\"step-description\">\n Give this authenticator a memorable name (e.g., \"iPhone\", \"Work Phone\")\n </p>\n </div>\n\n <StrandsUiInput v-model=\"deviceName\" label=\"Device Name\" placeholder=\"My Authenticator\" :error=\"deviceNameError\"\n :disabled=\"loading\" />\n\n <div class=\"step-actions\">\n <StrandsUiButton variant=\"secondary\" @click=\"closeModal\" :disabled=\"loading\">\n Cancel\n </StrandsUiButton>\n <StrandsUiButton variant=\"primary\" @click=\"startSetup\" :disabled=\"!deviceName.trim() || loading\"\n :loading=\"loading\">\n Continue\n </StrandsUiButton>\n </div>\n </div>\n\n <!-- Step 2: QR Code and Setup -->\n <div v-if=\"step === 2\" class=\"step-container\">\n <div>\n <h3 class=\"step-title\">Scan QR Code</h3>\n <p class=\"step-description\">\n Scan this QR code with your authenticator app (Google Authenticator, Authy, etc.)\n </p>\n </div>\n\n <!-- QR Code -->\n <div class=\"qr-container\">\n <div v-if=\"qrCodeDataUrl\" class=\"qr-wrapper\">\n <img :src=\"qrCodeDataUrl\" alt=\"TOTP QR Code\" class=\"qr-image\" />\n </div>\n <div v-else class=\"qr-loading\">\n <StrandsUiLoader :size=\"24\" />\n </div>\n </div>\n\n <!-- Manual Entry -->\n <div class=\"manual-entry\">\n <p class=\"manual-label\">\n Can't scan? Enter this code manually:\n </p>\n <code class=\"manual-code\">\n {{ totpSetupData?.secret || '...' }}\n </code>\n </div>\n\n <!-- Backup Codes Preview -->\n <div v-if=\"totpSetupData?.backup_codes\" class=\"bg-yellow-50 border border-yellow-200 rounded-lg p-4\">\n <div class=\"flex items-start space-x-2\">\n <svg class=\"w-5 h-5 text-yellow-600 mt-0.5 flex-shrink-0\" fill=\"currentColor\" viewBox=\"0 0 20 20\">\n <path fill-rule=\"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 clip-rule=\"evenodd\" />\n </svg>\n <div>\n <p class=\"text-sm font-medium text-yellow-800\">Save Your Backup Codes</p>\n <p class=\"text-sm text-yellow-700 mt-1\">\n After setup, you'll receive backup codes. Store them safely - they're your only way to recover access if\n you\n lose your device.\n </p>\n </div>\n </div>\n </div>\n\n <div class=\"flex justify-end space-x-3 pt-4\">\n <StrandsUiButton variant=\"secondary\" @click=\"step = 1\" :disabled=\"loading\">\n Back\n </StrandsUiButton>\n <StrandsUiButton variant=\"primary\" @click=\"step = 3\" :disabled=\"loading\">\n I've Added It\n </StrandsUiButton>\n </div>\n </div>\n\n <!-- Step 3: Verification -->\n <div v-if=\"step === 3\" class=\"space-y-4\">\n <div>\n <h3 class=\"text-lg font-semibold text-gray-900 mb-2\">Verify Setup</h3>\n <p class=\"text-sm text-gray-600 mb-4\">\n Enter the 6-digit code from your authenticator app to complete setup\n </p>\n </div>\n\n <StrandsUiInput v-model=\"verificationCode\" label=\"Verification Code\" placeholder=\"123456\" maxlength=\"6\"\n :error=\"verificationError\" :disabled=\"loading\" @input=\"onVerificationCodeInput\" />\n\n <div class=\"totp-setup-step-actions\">\n <StrandsUiButton variant=\"secondary\" @click=\"step = 2\" :disabled=\"loading\">\n Back\n </StrandsUiButton>\n <StrandsUiButton variant=\"primary\" @click=\"verifySetup\" :disabled=\"verificationCode.length !== 6 || loading\"\n :loading=\"loading\">\n Verify & Enable\n </StrandsUiButton>\n </div>\n </div>\n\n <!-- Step 4: Success & Backup Codes -->\n <div v-if=\"step === 4\" class=\"totp-setup-step\">\n <div class=\"totp-setup-success\">\n <div class=\"totp-setup-success-icon\">\n <svg class=\"totp-setup-check-icon\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M5 13l4 4L19 7\" />\n </svg>\n </div>\n <h3 class=\"totp-setup-step-title\">TOTP Setup Complete!</h3>\n <p class=\"totp-setup-success-description\">\n Your authenticator app is now active for two-factor authentication.\n </p>\n </div>\n\n <!-- Backup Codes -->\n <div class=\"totp-setup-backup-codes\">\n <div class=\"totp-setup-backup-header\">\n <svg class=\"totp-setup-backup-warning-icon\" fill=\"currentColor\" viewBox=\"0 0 20 20\">\n <path fill-rule=\"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 clip-rule=\"evenodd\" />\n </svg>\n <div>\n <p class=\"totp-setup-backup-header-title\">Save These Backup Codes</p>\n <p class=\"totp-setup-backup-header-description\">\n Store these codes in a safe place. Each code can only be used once.\n </p>\n </div>\n </div>\n\n <div class=\"totp-setup-backup-grid-wrapper\">\n <div class=\"totp-setup-backup-grid\">\n <div v-for=\"(code, index) in totpSetupData?.backup_codes\" :key=\"index\" class=\"totp-setup-backup-code\">\n {{ code }}\n </div>\n </div>\n </div>\n\n <div class=\"totp-setup-backup-actions\">\n <StrandsUiButton variant=\"secondary\" size=\"sm\" @click=\"copyBackupCodes\">\n 📋 Copy Codes\n </StrandsUiButton>\n </div>\n </div>\n\n <div class=\"totp-setup-final-actions\">\n <StrandsUiButton variant=\"primary\" @click=\"finish\">\n Done\n </StrandsUiButton>\n </div>\n </div>\n </UiModal>\n </div>\n</template>\n\n<script setup lang=\"ts\">\nimport { ref, watch, nextTick } from 'vue'\n// QRCode library removed - using external QR service or manual display\nimport { StrandsUiButton, StrandsUiInput, StrandsUiLoader } from '../ui'\nimport UiModal from '../ui/UiModal.vue'\nimport { useStrandsMfa } from '../composables/useStrandsMfa'\nimport type { TotpSetupResponse } from '../../types'\n\ninterface Props {\n show: boolean\n}\n\ninterface Emits {\n (e: 'close'): void\n (e: 'success'): void\n}\n\nconst props = defineProps<Props>()\nconst emit = defineEmits<Emits>()\n\nconst { setupTotp, verifyTotpSetup, loading } = useStrandsMfa()\n\n// State\nconst step = ref(1)\nconst deviceName = ref('')\nconst deviceNameError = ref('')\nconst verificationCode = ref('')\nconst verificationError = ref('')\nconst totpSetupData = ref<TotpSetupResponse | null>(null)\nconst qrCodeDataUrl = ref('')\n\n// Reset when modal opens/closes\nwatch(() => props.show, (newShow) => {\n if (newShow) {\n // Reset state\n step.value = 1\n deviceName.value = ''\n deviceNameError.value = ''\n verificationCode.value = ''\n verificationError.value = ''\n totpSetupData.value = null\n qrCodeDataUrl.value = ''\n }\n})\n\n// Generate QR code using external service when TOTP setup data is available\nwatch(() => totpSetupData.value, async (newData) => {\n if (newData?.qr_code_url) {\n try {\n // Use a QR code generation service\n const qrUrl = `https://api.qrserver.com/v1/create-qr-code/?size=192x192&data=${encodeURIComponent(newData.qr_code_url)}&bgcolor=ffffff&color=000000`\n qrCodeDataUrl.value = qrUrl\n } catch (error) {\n console.error('Failed to generate QR code:', error)\n }\n }\n})\n\nconst closeModal = () => {\n emit('close')\n}\n\nconst startSetup = async () => {\n if (!deviceName.value.trim()) {\n deviceNameError.value = 'Device name is required'\n return\n }\n\n deviceNameError.value = ''\n\n try {\n const response = await setupTotp(deviceName.value.trim())\n totpSetupData.value = response\n step.value = 2\n } catch (error) {\n deviceNameError.value = error instanceof Error ? error.message : 'Failed to setup TOTP'\n }\n}\n\nconst onVerificationCodeInput = (value: string) => {\n // Only allow digits\n verificationCode.value = value.replace(/\\D/g, '').slice(0, 6)\n verificationError.value = ''\n}\n\nconst verifySetup = async () => {\n if (!totpSetupData.value || !verificationCode.value) {\n return\n }\n\n verificationError.value = ''\n\n try {\n await verifyTotpSetup(totpSetupData.value.device_id, verificationCode.value)\n step.value = 4\n } catch (error) {\n verificationError.value = error instanceof Error ? error.message : 'Invalid verification code'\n }\n}\n\nconst copyBackupCodes = async () => {\n if (!totpSetupData.value?.backup_codes) return\n\n try {\n const codesText = totpSetupData.value.backup_codes.join('\\n')\n await navigator.clipboard.writeText(codesText)\n // Could show a toast here\n console.log('Backup codes copied to clipboard')\n } catch (error) {\n console.error('Failed to copy backup codes:', error)\n }\n}\n\nconst finish = () => {\n emit('success')\n}\n</script>\n\n<style scoped>\n/* Modal container */\n.totp-setup-modal {\n max-width: 28rem;\n}\n\n/* Header */\n.totp-setup-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n}\n\n.totp-setup-title {\n font-size: 1.25rem;\n font-weight: 700;\n color: #111827;\n}\n\n.totp-setup-close-button {\n color: #9ca3af;\n transition: color 0.2s ease;\n background: none;\n border: none;\n cursor: pointer;\n padding: 0.25rem;\n}\n\n.totp-setup-close-button:hover {\n color: #4b5563;\n}\n\n.totp-setup-close-icon {\n width: 1.25rem;\n height: 1.25rem;\n}\n\n/* Steps */\n.totp-setup-step {\n display: flex;\n flex-direction: column;\n gap: 1rem;\n}\n\n.totp-setup-step-title {\n font-size: 1.125rem;\n font-weight: 600;\n color: #111827;\n margin-bottom: 0.5rem;\n}\n\n.totp-setup-step-description {\n font-size: 0.875rem;\n color: #6b7280;\n margin-bottom: 1rem;\n}\n\n.totp-setup-step-actions {\n display: flex;\n justify-content: flex-end;\n gap: 0.75rem;\n padding-top: 1rem;\n}\n\n/* QR Code */\n.totp-setup-qr-container {\n display: flex;\n justify-content: center;\n background-color: #f9fafb;\n padding: 1rem;\n border-radius: 0.5rem;\n}\n\n.totp-setup-qr-wrapper {\n background-color: white;\n padding: 1rem;\n border-radius: 0.5rem;\n box-shadow: 0 1px 2px 0 rgba(0, 0, 0, 0.05);\n}\n\n.totp-setup-qr-image {\n width: 12rem;\n height: 12rem;\n}\n\n.totp-setup-qr-loading {\n display: flex;\n align-items: center;\n justify-content: center;\n width: 12rem;\n height: 12rem;\n}\n\n/* Manual Entry */\n.totp-setup-manual-entry {\n background-color: #f9fafb;\n padding: 1rem;\n border-radius: 0.5rem;\n}\n\n.totp-setup-manual-label {\n font-size: 0.75rem;\n color: #6b7280;\n margin-bottom: 0.5rem;\n}\n\n.totp-setup-manual-code {\n font-size: 0.75rem;\n font-family: 'SF Mono', Monaco, Inconsolata, 'Roboto Mono', Consolas, 'Courier New', monospace;\n background-color: white;\n padding: 0.5rem;\n border-radius: 0.25rem;\n border: 1px solid #e5e7eb;\n word-break: break-all;\n color: #111827;\n display: block;\n}\n\n/* Backup Preview */\n.totp-setup-backup-preview {\n background-color: #fefce8;\n border: 1px solid #fde047;\n border-radius: 0.5rem;\n padding: 1rem;\n}\n\n.totp-setup-backup-warning {\n display: flex;\n align-items: flex-start;\n gap: 0.5rem;\n}\n\n.totp-setup-warning-icon {\n width: 1.25rem;\n height: 1.25rem;\n color: #d97706;\n margin-top: 0.125rem;\n flex-shrink: 0;\n}\n\n.totp-setup-backup-title {\n font-size: 0.875rem;\n font-weight: 500;\n color: #92400e;\n}\n\n.totp-setup-backup-description {\n font-size: 0.875rem;\n color: #a16207;\n margin-top: 0.25rem;\n}\n\n/* Success */\n.totp-setup-success {\n text-align: center;\n}\n\n.totp-setup-success-icon {\n width: 3rem;\n height: 3rem;\n background-color: #dcfce7;\n border-radius: 50%;\n display: flex;\n align-items: center;\n justify-content: center;\n margin: 0 auto 1rem;\n}\n\n.totp-setup-check-icon {\n width: 1.5rem;\n height: 1.5rem;\n color: #16a34a;\n}\n\n.totp-setup-success-description {\n font-size: 0.875rem;\n color: #6b7280;\n margin-bottom: 1.5rem;\n}\n\n/* Backup Codes */\n.totp-setup-backup-codes {\n background-color: #fef2f2;\n border: 1px solid #fecaca;\n border-radius: 0.5rem;\n padding: 1rem;\n}\n\n.totp-setup-backup-header {\n display: flex;\n align-items: flex-start;\n gap: 0.5rem;\n margin-bottom: 0.75rem;\n}\n\n.totp-setup-backup-warning-icon {\n width: 1.25rem;\n height: 1.25rem;\n color: #dc2626;\n margin-top: 0.125rem;\n flex-shrink: 0;\n}\n\n.totp-setup-backup-header-title {\n font-size: 0.875rem;\n font-weight: 500;\n color: #991b1b;\n}\n\n.totp-setup-backup-header-description {\n font-size: 0.875rem;\n color: #b91c1c;\n margin-top: 0.25rem;\n}\n\n.totp-setup-backup-grid-wrapper {\n background-color: white;\n border-radius: 0.25rem;\n border: 1px solid #e5e7eb;\n padding: 0.75rem;\n}\n\n.totp-setup-backup-grid {\n display: grid;\n grid-template-columns: repeat(2, 1fr);\n gap: 0.5rem;\n font-size: 0.875rem;\n font-family: 'SF Mono', Monaco, Inconsolata, 'Roboto Mono', Consolas, 'Courier New', monospace;\n color: #111827;\n}\n\n.totp-setup-backup-code {\n text-align: center;\n padding: 0.25rem 0;\n}\n\n.totp-setup-backup-actions {\n display: flex;\n justify-content: center;\n margin-top: 0.75rem;\n}\n\n.totp-setup-final-actions {\n display: flex;\n justify-content: flex-end;\n padding-top: 1rem;\n}\n\n/* Semantic CSS classes replacing Tailwind */\n.modal-card {\n max-width: 28rem;\n}\n\n.modal-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n}\n\n.modal-title {\n font-size: 1.25rem;\n font-weight: 700;\n color: #111827;\n}\n\n.modal-close-button {\n color: #9ca3af;\n transition: color 0.2s ease;\n background: none;\n border: none;\n cursor: pointer;\n padding: 0.25rem;\n}\n\n.modal-close-button:hover {\n color: #6b7280;\n}\n\n.modal-close-icon {\n width: 1.25rem;\n height: 1.25rem;\n}\n\n.step-container {\n display: flex;\n flex-direction: column;\n gap: 1rem;\n}\n\n.step-title {\n font-size: 1.125rem;\n font-weight: 600;\n color: #111827;\n margin-bottom: 0.5rem;\n}\n\n.step-description {\n font-size: 0.875rem;\n color: #6b7280;\n margin-bottom: 1rem;\n}\n\n.step-actions {\n display: flex;\n justify-content: flex-end;\n gap: 0.75rem;\n padding-top: 1rem;\n}\n\n.qr-container {\n display: flex;\n justify-content: center;\n background-color: #f9fafb;\n padding: 1rem;\n border-radius: 0.5rem;\n}\n\n.qr-wrapper {\n background-color: white;\n padding: 1rem;\n border-radius: 0.5rem;\n box-shadow: 0 1px 2px 0 rgba(0, 0, 0, 0.05);\n}\n\n.qr-image {\n width: 12rem;\n height: 12rem;\n}\n\n.qr-loading {\n display: flex;\n align-items: center;\n justify-content: center;\n width: 12rem;\n height: 12rem;\n}\n\n.manual-entry {\n background-color: #f9fafb;\n padding: 1rem;\n border-radius: 0.5rem;\n}\n\n.manual-label {\n font-size: 0.75rem;\n color: #6b7280;\n margin-bottom: 0.5rem;\n}\n\n.manual-code {\n font-size: 0.75rem;\n font-family: ui-monospace, SFMono-Regular, \"SF Mono\", Consolas, \"Liberation Mono\", Menlo, monospace;\n background-color: white;\n padding: 0.5rem;\n border-radius: 0.25rem;\n border: 1px solid #e5e7eb;\n word-break: break-all;\n color: #111827;\n display: block;\n}\n\n.backup-preview {\n background-color: #fefce8;\n border: 1px solid #fde047;\n border-radius: 0.5rem;\n padding: 1rem;\n}\n\n.backup-warning {\n display: flex;\n align-items: flex-start;\n gap: 0.5rem;\n}\n\n.warning-icon {\n width: 1.25rem;\n height: 1.25rem;\n color: #d97706;\n margin-top: 0.125rem;\n flex-shrink: 0;\n}\n\n.backup-title {\n font-size: 0.875rem;\n font-weight: 500;\n color: #92400e;\n}\n\n.backup-description {\n font-size: 0.875rem;\n color: #a16207;\n margin-top: 0.25rem;\n}\n\n.success-container {\n text-align: center;\n}\n\n.success-icon {\n width: 3rem;\n height: 3rem;\n background-color: #dcfce7;\n border-radius: 50%;\n display: flex;\n align-items: center;\n justify-content: center;\n margin: 0 auto 1rem;\n}\n\n.success-check-icon {\n width: 1.5rem;\n height: 1.5rem;\n color: #16a34a;\n}\n\n.success-description {\n font-size: 0.875rem;\n color: #6b7280;\n margin-bottom: 1.5rem;\n}\n\n.backup-codes-container {\n background-color: #fef2f2;\n border: 1px solid #fecaca;\n border-radius: 0.5rem;\n padding: 1rem;\n}\n\n.backup-codes-header {\n display: flex;\n align-items: flex-start;\n gap: 0.5rem;\n margin-bottom: 0.75rem;\n}\n\n.backup-codes-warning-icon {\n width: 1.25rem;\n height: 1.25rem;\n color: #dc2626;\n margin-top: 0.125rem;\n flex-shrink: 0;\n}\n\n.backup-codes-title {\n font-size: 0.875rem;\n font-weight: 500;\n color: #991b1b;\n}\n\n.backup-codes-description {\n font-size: 0.875rem;\n color: #b91c1c;\n margin-top: 0.25rem;\n}\n\n.backup-codes-grid-wrapper {\n background-color: white;\n border-radius: 0.25rem;\n border: 1px solid #e5e7eb;\n padding: 0.75rem;\n}\n\n.backup-codes-grid {\n display: grid;\n grid-template-columns: repeat(2, 1fr);\n gap: 0.5rem;\n font-size: 0.875rem;\n font-family: ui-monospace, SFMono-Regular, \"SF Mono\", Consolas, \"Liberation Mono\", Menlo, monospace;\n color: #111827;\n}\n\n.backup-code {\n text-align: center;\n padding: 0.25rem 0;\n}\n\n.backup-actions {\n display: flex;\n justify-content: center;\n margin-top: 0.75rem;\n}\n\n.final-actions {\n display: flex;\n justify-content: flex-end;\n padding-top: 1rem;\n}\n</style>\n","<template>\n <div class=\"accui-component-scope\">\n <UiModal :open=\"show\" @close=\"closeModal\" card-class=\"email-mfa-setup-modal\">\n <template #header>\n <div class=\"email-mfa-setup-header\">\n <h2 class=\"email-mfa-setup-title\">Setup Email 2FA</h2>\n <button @click=\"closeModal\" class=\"email-mfa-setup-close-button\">\n <svg class=\"email-mfa-setup-close-icon\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M6 18L18 6M6 6l12 12\" />\n </svg>\n </button>\n </div>\n </template>\n <!-- Step 1: Device Name -->\n <div v-if=\"step === 1\" class=\"email-mfa-setup-step\">\n <div>\n <h3 class=\"email-mfa-setup-step-title\">Name Your Email 2FA</h3>\n <p class=\"email-mfa-setup-step-description\">\n Give this email 2FA method a memorable name (e.g., \"Personal Email\", \"Work Email\")\n </p>\n </div>\n\n <StrandsUiInput v-model=\"deviceName\" label=\"Device Name\" placeholder=\"Personal Email\" :error=\"deviceNameError\"\n :disabled=\"loading\" />\n\n <div class=\"email-mfa-setup-info\">\n <div class=\"email-mfa-setup-info-content\">\n <svg class=\"email-mfa-setup-info-icon\" fill=\"currentColor\" viewBox=\"0 0 20 20\">\n <path fill-rule=\"evenodd\"\n d=\"M18 10a8 8 0 11-16 0 8 8 0 0116 0zm-7-4a1 1 0 11-2 0 1 1 0 012 0zM9 9a1 1 0 000 2v3a1 1 0 001 1h1a1 1 0 100-2v-3a1 1 0 00-1-1H9z\"\n clip-rule=\"evenodd\" />\n </svg>\n <div>\n <p class=\"email-mfa-setup-info-title\">Email 2FA</p>\n <p class=\"email-mfa-setup-info-description\">\n Verification codes will be sent to your registered email address when logging in.\n </p>\n </div>\n </div>\n </div>\n\n <div class=\"email-mfa-setup-step-actions\">\n <StrandsUiButton variant=\"secondary\" @click=\"closeModal\" :disabled=\"loading\">\n Cancel\n </StrandsUiButton>\n <StrandsUiButton variant=\"primary\" @click=\"startSetup\" :disabled=\"!deviceName.trim() || loading\"\n :loading=\"loading\">\n Setup Email 2FA\n </StrandsUiButton>\n </div>\n </div>\n\n <!-- Step 2: Test Verification -->\n <div v-if=\"step === 2\" class=\"email-mfa-setup-step\">\n <div>\n <h3 class=\"email-mfa-setup-step-title\">Test Email 2FA</h3>\n <p class=\"email-mfa-setup-step-description\">\n We've sent a test verification code to your email. Enter it below to complete setup.\n </p>\n </div>\n\n <div class=\"email-mfa-setup-success-notification\">\n <div class=\"email-mfa-setup-success-content\">\n <svg class=\"email-mfa-setup-success-icon\" fill=\"currentColor\" viewBox=\"0 0 20 20\">\n <path fill-rule=\"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 clip-rule=\"evenodd\" />\n </svg>\n <div>\n <p class=\"email-mfa-setup-success-title\">Code Sent!</p>\n <p class=\"email-mfa-setup-success-description\">\n Check your email inbox for the verification code.\n </p>\n </div>\n </div>\n </div>\n\n <StrandsUiInput v-model=\"verificationCode\" label=\"Verification Code\" placeholder=\"123456\" maxlength=\"6\"\n :error=\"verificationError\" :disabled=\"loading\" @input=\"onVerificationCodeInput\" />\n\n <div class=\"email-mfa-setup-resend-section\">\n <StrandsUiButton variant=\"secondary\" size=\"sm\" @click=\"resendCode\" :disabled=\"loading || cooldownActive\">\n {{ cooldownActive ? `Resend in ${cooldownSeconds}s` : 'Resend Code' }}\n </StrandsUiButton>\n </div>\n\n <div class=\"email-mfa-setup-step-actions\">\n <StrandsUiButton variant=\"secondary\" @click=\"step = 1\" :disabled=\"loading\">\n Back\n </StrandsUiButton>\n <StrandsUiButton variant=\"primary\" @click=\"verifySetup\" :disabled=\"verificationCode.length !== 6 || loading\"\n :loading=\"loading\">\n Verify & Enable\n </StrandsUiButton>\n </div>\n </div>\n\n <!-- Step 3: Success -->\n <div v-if=\"step === 3\" class=\"email-mfa-setup-step\">\n <div class=\"email-mfa-setup-completion\">\n <div class=\"email-mfa-setup-completion-icon\">\n <svg class=\"email-mfa-setup-check-icon\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M5 13l4 4L19 7\" />\n </svg>\n </div>\n <h3 class=\"email-mfa-setup-step-title\">Email 2FA Setup Complete!</h3>\n <p class=\"email-mfa-setup-completion-description\">\n Email verification is now active for your account. You'll receive codes at your registered email address.\n </p>\n </div>\n\n <div class=\"email-mfa-setup-info\">\n <div class=\"email-mfa-setup-info-content\">\n <svg class=\"email-mfa-setup-info-icon\" fill=\"currentColor\" viewBox=\"0 0 20 20\">\n <path fill-rule=\"evenodd\"\n d=\"M18 10a8 8 0 11-16 0 8 8 0 0116 0zm-7-4a1 1 0 11-2 0 1 1 0 012 0zM9 9a1 1 0 000 2v3a1 1 0 001 1h1a1 1 0 100-2v-3a1 1 0 00-1-1H9z\"\n clip-rule=\"evenodd\" />\n </svg>\n <div>\n <p class=\"email-mfa-setup-info-title\">How it works</p>\n <p class=\"email-mfa-setup-info-description\">\n When logging in, you'll receive a 6-digit code at your email address. Enter this code to complete\n authentication.\n </p>\n </div>\n </div>\n </div>\n\n <div class=\"email-mfa-setup-final-actions\">\n <StrandsUiButton variant=\"primary\" @click=\"finish\">\n Done\n </StrandsUiButton>\n </div>\n </div>\n </UiModal>\n </div>\n</template>\n\n<script setup lang=\"ts\">\nimport { ref, watch, onBeforeUnmount } from 'vue'\nimport { StrandsUiButton, StrandsUiInput } from '../ui'\nimport UiModal from '../ui/UiModal.vue'\nimport { useStrandsMfa } from '../composables/useStrandsMfa'\n\ninterface Props {\n show: boolean\n}\n\ninterface Emits {\n (e: 'close'): void\n (e: 'success'): void\n}\n\nconst props = defineProps<Props>()\nconst emit = defineEmits<Emits>()\n\nconst { setupEmailMfa, sendEmailMfaCode, verifyEmailMfaCode, loading } = useStrandsMfa()\n\n// State\nconst step = ref(1)\nconst deviceName = ref('')\nconst deviceNameError = ref('')\nconst verificationCode = ref('')\nconst verificationError = ref('')\nconst emailMfaDeviceId = ref<string | null>(null)\nconst cooldownActive = ref(false)\nconst cooldownSeconds = ref(0)\n\nlet cooldownInterval: NodeJS.Timeout | null = null\n\n// Reset when modal opens/closes\nwatch(() => props.show, (newShow) => {\n if (newShow) {\n // Reset state\n step.value = 1\n deviceName.value = ''\n deviceNameError.value = ''\n verificationCode.value = ''\n verificationError.value = ''\n emailMfaDeviceId.value = null\n cooldownActive.value = false\n cooldownSeconds.value = 0\n if (cooldownInterval) {\n clearInterval(cooldownInterval)\n cooldownInterval = null\n }\n }\n})\n\nonBeforeUnmount(() => {\n if (cooldownInterval) {\n clearInterval(cooldownInterval)\n }\n})\n\nconst closeModal = () => {\n emit('close')\n}\n\nconst startSetup = async () => {\n if (!deviceName.value.trim()) {\n deviceNameError.value = 'Device name is required'\n return\n }\n\n deviceNameError.value = ''\n\n try {\n const response = await setupEmailMfa(deviceName.value.trim())\n emailMfaDeviceId.value = response.device_id\n\n // Now send the first verification code\n await sendEmailMfaCode(response.device_id)\n\n step.value = 2\n startCooldown()\n } catch (error) {\n deviceNameError.value = error instanceof Error ? error.message : 'Failed to setup email MFA'\n }\n}\n\nconst onVerificationCodeInput = (value: string) => {\n // Only allow digits\n verificationCode.value = value.replace(/\\D/g, '').slice(0, 6)\n verificationError.value = ''\n}\n\nconst verifySetup = async () => {\n if (!emailMfaDeviceId.value || !verificationCode.value) {\n return\n }\n\n verificationError.value = ''\n\n try {\n const verified = await verifyEmailMfaCode(emailMfaDeviceId.value, verificationCode.value)\n if (verified) {\n step.value = 3\n } else {\n verificationError.value = 'Invalid verification code'\n }\n } catch (error) {\n verificationError.value = error instanceof Error ? error.message : 'Invalid verification code'\n }\n}\n\nconst resendCode = async () => {\n if (!emailMfaDeviceId.value || cooldownActive.value) {\n return\n }\n\n try {\n await sendEmailMfaCode(emailMfaDeviceId.value)\n startCooldown()\n } catch (error) {\n console.error('Failed to resend code:', error)\n }\n}\n\nconst startCooldown = () => {\n cooldownActive.value = true\n cooldownSeconds.value = 30\n\n cooldownInterval = setInterval(() => {\n cooldownSeconds.value -= 1\n if (cooldownSeconds.value <= 0) {\n cooldownActive.value = false\n if (cooldownInterval) {\n clearInterval(cooldownInterval)\n cooldownInterval = null\n }\n }\n }, 1000)\n}\n\nconst finish = () => {\n emit('success')\n}\n</script>\n\n<style scoped>\n/* Modal container */\n.email-mfa-setup-modal {\n max-width: 28rem;\n}\n\n/* Header */\n.email-mfa-setup-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n}\n\n.email-mfa-setup-title {\n font-size: 1.25rem;\n font-weight: 700;\n color: #111827;\n}\n\n.email-mfa-setup-close-button {\n color: #9ca3af;\n transition: color 0.2s ease;\n background: none;\n border: none;\n cursor: pointer;\n padding: 0.25rem;\n}\n\n.email-mfa-setup-close-button:hover {\n color: #4b5563;\n}\n\n.email-mfa-setup-close-icon {\n width: 1.25rem;\n height: 1.25rem;\n}\n\n/* Steps */\n.email-mfa-setup-step {\n display: flex;\n flex-direction: column;\n gap: 1rem;\n}\n\n.email-mfa-setup-step-title {\n font-size: 1.125rem;\n font-weight: 600;\n color: #111827;\n margin-bottom: 0.5rem;\n}\n\n.email-mfa-setup-step-description {\n font-size: 0.875rem;\n color: #4b5563;\n margin-bottom: 1rem;\n}\n\n.email-mfa-setup-step-actions {\n display: flex;\n justify-content: flex-end;\n gap: 0.75rem;\n padding-top: 1rem;\n}\n\n/* Info box */\n.email-mfa-setup-info {\n background-color: #eff6ff;\n border: 1px solid #bfdbfe;\n border-radius: 0.5rem;\n padding: 1rem;\n}\n\n.email-mfa-setup-info-content {\n display: flex;\n align-items: flex-start;\n gap: 0.5rem;\n}\n\n.email-mfa-setup-info-icon {\n width: 1.25rem;\n height: 1.25rem;\n color: #2563eb;\n margin-top: 0.125rem;\n flex-shrink: 0;\n}\n\n.email-mfa-setup-info-title {\n font-size: 0.875rem;\n font-weight: 500;\n color: #1e3a8a;\n margin: 0;\n}\n\n.email-mfa-setup-info-description {\n font-size: 0.875rem;\n color: #1d4ed8;\n margin-top: 0.25rem;\n}\n\n/* Success notification */\n.email-mfa-setup-success-notification {\n background-color: #f0fdf4;\n border: 1px solid #bbf7d0;\n border-radius: 0.5rem;\n padding: 1rem;\n}\n\n.email-mfa-setup-success-content {\n display: flex;\n align-items: flex-start;\n gap: 0.5rem;\n}\n\n.email-mfa-setup-success-icon {\n width: 1.25rem;\n height: 1.25rem;\n color: #059669;\n margin-top: 0.125rem;\n flex-shrink: 0;\n}\n\n.email-mfa-setup-success-title {\n font-size: 0.875rem;\n font-weight: 500;\n color: #166534;\n margin: 0;\n}\n\n.email-mfa-setup-success-description {\n font-size: 0.875rem;\n color: #15803d;\n margin-top: 0.25rem;\n}\n\n/* Resend section */\n.email-mfa-setup-resend-section {\n display: flex;\n justify-content: space-between;\n}\n\n/* Completion */\n.email-mfa-setup-completion {\n text-align: center;\n}\n\n.email-mfa-setup-completion-icon {\n width: 3rem;\n height: 3rem;\n background-color: #dcfce7;\n border-radius: 50%;\n display: flex;\n align-items: center;\n justify-content: center;\n margin: 0 auto 1rem;\n}\n\n.email-mfa-setup-check-icon {\n width: 1.5rem;\n height: 1.5rem;\n color: #16a34a;\n}\n\n.email-mfa-setup-completion-description {\n font-size: 0.875rem;\n color: #4b5563;\n margin-bottom: 1.5rem;\n}\n\n/* Final actions */\n.email-mfa-setup-final-actions {\n display: flex;\n justify-content: flex-end;\n padding-top: 1rem;\n}\n</style>\n","<template>\n <div class=\"accui-component-scope\">\n <UiModal :open=\"show\" @close=\"closeModal\" card-class=\"hardware-key-setup-modal\">\n <template #header>\n <div class=\"hardware-key-setup-header\">\n <h2 class=\"hardware-key-setup-title\">Setup Hardware Key</h2>\n <button @click=\"closeModal\" class=\"hardware-key-setup-close\">\n <svg class=\"hardware-key-setup-close-icon\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M6 18L18 6M6 6l12 12\" />\n </svg>\n </button>\n </div>\n </template>\n\n <!-- Step 1: Device Name -->\n <div v-if=\"step === 1\" class=\"hardware-key-setup-step\">\n <div>\n <h3 class=\"hardware-key-setup-step-title\">Name Your Hardware Key</h3>\n <p class=\"hardware-key-setup-step-description\">\n Give your hardware key a memorable name (e.g., \"YubiKey 5\", \"Work Security Key\")\n </p>\n </div>\n\n <StrandsUiInput v-model=\"deviceName\" label=\"Device Name\" placeholder=\"My Hardware Key\" :error=\"deviceNameError\"\n :disabled=\"loading\" />\n\n <div class=\"hardware-key-setup-actions\">\n <StrandsUiButton variant=\"secondary\" @click=\"closeModal\" :disabled=\"loading\">\n Cancel\n </StrandsUiButton>\n <StrandsUiButton variant=\"primary\" @click=\"startSetup\" :disabled=\"!deviceName.trim() || loading\"\n :loading=\"loading\">\n Continue\n </StrandsUiButton>\n </div>\n </div>\n\n <!-- Step 2: Hardware Key Registration -->\n <div v-if=\"step === 2\" class=\"hardware-key-setup-step\">\n <div>\n <h3 class=\"hardware-key-setup-step-title\">Register Hardware Key</h3>\n <p class=\"hardware-key-setup-step-description\">\n Insert your hardware key and follow your browser's prompts to complete registration.\n </p>\n </div>\n\n <!-- Hardware Key Illustration -->\n <div class=\"hardware-key-setup-illustration\">\n <div class=\"hardware-key-setup-illustration-content\">\n <div class=\"hardware-key-setup-icon-container\">\n <svg class=\"hardware-key-setup-icon\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\"\n d=\"M15 7a2 2 0 012 2m0 0a2 2 0 012 2v6a2 2 0 01-2 2H9a2 2 0 01-2-2V9a2 2 0 012-2m0 0V7a2 2 0 012-2m0 0V5a2 2 0 012-2h6a2 2 0 012 2v2M7 7h3m0 0v8m0-8h8m-8 8h8\" />\n </svg>\n </div>\n <p class=\"hardware-key-setup-status\">Hardware Key Ready</p>\n <p class=\"hardware-key-setup-substatus\">Click \"Register Key\" when ready</p>\n </div>\n </div>\n\n <!-- Instructions -->\n <div class=\"hardware-key-setup-instructions\">\n <div class=\"hardware-key-setup-instructions-header\">\n <svg class=\"hardware-key-setup-info-icon\" fill=\"currentColor\" viewBox=\"0 0 20 20\">\n <path fill-rule=\"evenodd\"\n d=\"M18 10a8 8 0 11-16 0 8 8 0 0116 0zm-7-4a1 1 0 11-2 0 1 1 0 012 0zM9 9a1 1 0 000 2v3a1 1 0 001 1h1a1 1 0 100-2v-3a1 1 0 00-1-1H9z\"\n clip-rule=\"evenodd\" />\n </svg>\n <div>\n <p class=\"hardware-key-setup-instructions-title\">Setup Instructions</p>\n <ul class=\"hardware-key-setup-instructions-list\">\n <template v-if=\"props.deviceType === 'passkey'\">\n <li>• Your browser will prompt you to create a passkey</li>\n <li>• Use Touch ID, Face ID, Windows Hello, or PIN</li>\n <li>• Follow the prompts to complete setup</li>\n </template>\n <template v-else>\n <li>• Insert your hardware key into a USB port</li>\n <li>• Your browser will prompt you to interact with the key</li>\n <li>• Touch the key's button or sensor when prompted</li>\n </template>\n </ul>\n </div>\n </div>\n </div>\n\n <div class=\"hardware-key-setup-actions\">\n <StrandsUiButton variant=\"secondary\" @click=\"step = 1\" :disabled=\"loading\">\n Back\n </StrandsUiButton>\n <StrandsUiButton variant=\"primary\" @click=\"handleRegisterHardwareKey\" :disabled=\"loading\" :loading=\"loading\">\n Register Key\n </StrandsUiButton>\n </div>\n </div>\n\n <!-- Step 3: Registration In Progress -->\n <div v-if=\"step === 3\" class=\"hardware-key-setup-step\">\n <div class=\"hardware-key-setup-progress\">\n <div class=\"hardware-key-setup-progress-icon\">\n <StrandsUiLoader :size=\"24\" class=\"hardware-key-setup-loader\" />\n </div>\n <h3 class=\"hardware-key-setup-step-title\">Registering Hardware Key</h3>\n <p class=\"hardware-key-setup-progress-message\">\n {{ registrationMessage }}\n </p>\n </div>\n\n <!-- Dynamic Progress Indicator -->\n <div class=\"hardware-key-setup-progress-indicator\">\n <div class=\"hardware-key-setup-progress-content\">\n <div class=\"hardware-key-setup-progress-check\">\n <div class=\"hardware-key-setup-check-icon\">\n <svg class=\"hardware-key-setup-check\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M5 13l4 4L19 7\" />\n </svg>\n </div>\n </div>\n <p class=\"hardware-key-setup-progress-text\">Touch your hardware key to complete registration</p>\n </div>\n </div>\n </div>\n\n <!-- Step 4: Success & Backup Codes -->\n <div v-if=\"step === 4\" class=\"hardware-key-setup-step\">\n <div class=\"hardware-key-setup-success\">\n <div class=\"hardware-key-setup-success-icon\">\n <svg class=\"hardware-key-setup-success-check\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M5 13l4 4L19 7\" />\n </svg>\n </div>\n <h3 class=\"hardware-key-setup-step-title\">Hardware Key Setup Complete!</h3>\n <p class=\"hardware-key-setup-success-message\">\n Your hardware key is now active for two-factor authentication.\n </p>\n </div>\n\n <!-- Backup Codes -->\n <div class=\"hardware-key-setup-backup-codes\">\n <div class=\"hardware-key-setup-backup-codes-header\">\n <svg class=\"hardware-key-setup-warning-icon\" fill=\"currentColor\" viewBox=\"0 0 20 20\">\n <path fill-rule=\"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 clip-rule=\"evenodd\" />\n </svg>\n <div>\n <p class=\"hardware-key-setup-backup-codes-title\">Save These Backup Codes</p>\n <p class=\"hardware-key-setup-backup-codes-description\">\n Store these codes in a safe place. Each code can only be used once if you lose your hardware key.\n </p>\n </div>\n </div>\n\n <div class=\"hardware-key-setup-codes-container\">\n <div class=\"hardware-key-setup-codes-grid\">\n <div v-for=\"(code, index) in backupCodes\" :key=\"index\" class=\"hardware-key-setup-code\">\n {{ code }}\n </div>\n </div>\n </div>\n\n <div class=\"hardware-key-setup-copy-action\">\n <StrandsUiButton variant=\"secondary\" size=\"sm\" @click=\"copyBackupCodes\">\n 📋 Copy Codes\n </StrandsUiButton>\n </div>\n </div>\n\n <div class=\"hardware-key-setup-final-action\">\n <StrandsUiButton variant=\"primary\" @click=\"finish\">\n Done\n </StrandsUiButton>\n </div>\n </div>\n\n <!-- Step 5: Error State -->\n <div v-if=\"step === 5\" class=\"hardware-key-setup-step\">\n <div class=\"hardware-key-setup-error\">\n <div class=\"hardware-key-setup-error-icon\">\n <svg class=\"hardware-key-setup-error-x\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M6 18L18 6M6 6l12 12\" />\n </svg>\n </div>\n <h3 class=\"hardware-key-setup-step-title\">Registration Failed</h3>\n <p class=\"hardware-key-setup-error-message\">\n {{ errorMessage }}\n </p>\n </div>\n\n <div class=\"hardware-key-setup-actions\">\n <StrandsUiButton variant=\"secondary\" @click=\"step = 1\">\n Start Over\n </StrandsUiButton>\n <StrandsUiButton variant=\"primary\" @click=\"closeModal\">\n Close\n </StrandsUiButton>\n </div>\n </div>\n </UiModal>\n </div>\n</template>\n\n<script setup lang=\"ts\">\nimport { ref, watch, computed, withDefaults } from 'vue'\nimport { useStrandsAuth } from '../composables/useStrandsAuth'\nimport { StrandsUiButton, StrandsUiInput, StrandsUiLoader } from '../ui'\nimport UiModal from '../ui/UiModal.vue'\nimport { useStrandsMfa } from '../composables/useStrandsMfa'\n\ninterface Props {\n show: boolean\n deviceType?: 'passkey' | 'hardware'\n}\n\ninterface Emits {\n (e: 'close'): void\n (e: 'success'): void\n}\n\nconst props = withDefaults(defineProps<Props>(), {\n deviceType: 'hardware'\n})\nconst emit = defineEmits<Emits>()\n\nconst { loading: mfaLoading } = useStrandsMfa()\nconst { registerHardwareKey, completeHardwareKeyRegistration, currentSession } = useStrandsAuth()\n\n// Internal loading state for this component\nconst internalLoading = ref(false)\nconst loading = computed(() => mfaLoading.value || internalLoading.value)\n\n// State\nconst step = ref(1)\nconst deviceName = ref('')\nconst deviceNameError = ref('')\nconst registrationMessage = ref('Please touch your hardware key when prompted')\nconst errorMessage = ref('')\nconst backupCodes = ref<string[]>([])\n\n// Reset when modal opens/closes\nwatch(() => props.show, (newShow) => {\n if (newShow) {\n // Reset state\n step.value = 1\n deviceName.value = ''\n deviceNameError.value = ''\n registrationMessage.value = 'Please touch your hardware key when prompted'\n errorMessage.value = ''\n backupCodes.value = []\n }\n})\n\nconst closeModal = () => {\n emit('close')\n}\n\n// Get optimal authenticator selection based on device type\nconst getOptimalAuthenticatorSelection = (deviceType: 'hardware' | 'passkey') => {\n if (deviceType === 'passkey') {\n return {\n authenticatorAttachment: undefined, // Allow both platform and cross-platform for passkeys\n requireResidentKey: true, // Passkeys are resident credentials\n residentKey: 'required',\n userVerification: 'required' // Passkeys should always verify user\n }\n } else {\n // Hardware keys (YubiKey, etc.)\n return {\n authenticatorAttachment: 'cross-platform', // Prefer external authenticators like YubiKey\n requireResidentKey: false,\n residentKey: 'discouraged',\n userVerification: 'discouraged' // YubiKeys work better with discouraged\n }\n }\n}\n\n// Helper function to create a device-optimized WebAuthn challenge\nconst createOptimizedWebAuthnChallenge = (challenge: any, deviceType: 'hardware' | 'passkey') => {\n // Safe buffer conversion that creates new clean objects\n const safeBufferConvert = (data: any): Uint8Array => {\n try {\n if (!data) {\n return new Uint8Array(32) // Default 32-byte random challenge\n }\n\n // If it's already a Uint8Array, create a new clean copy\n if (data instanceof Uint8Array) {\n return new Uint8Array(data)\n }\n\n // If it has a buffer property, extract it safely\n if (data && typeof data === 'object' && data.buffer) {\n return new Uint8Array(data.buffer)\n }\n\n // If it's an array of numbers\n if (Array.isArray(data)) {\n return new Uint8Array(data)\n }\n\n // If it's a string, try base64 decode\n if (typeof data === 'string') {\n const binary = atob(data)\n const bytes = new Uint8Array(binary.length)\n for (let i = 0; i < binary.length; i++) {\n bytes[i] = binary.charCodeAt(i)\n }\n return bytes\n }\n\n // Fallback: create random bytes\n console.warn('Unknown data format, using random bytes:', data)\n return crypto.getRandomValues(new Uint8Array(32))\n\n } catch (error) {\n console.error('Buffer conversion failed:', error)\n return crypto.getRandomValues(new Uint8Array(32))\n }\n }\n\n try {\n // Create a completely new clean object to avoid extension conflicts\n const cleanChallenge: any = {\n rp: challenge.rp || { name: 'Strands Accounts' },\n user: {\n id: safeBufferConvert(challenge.user?.id),\n name: challenge.user?.name || 'user',\n displayName: challenge.user?.displayName || challenge.user?.name || 'User'\n },\n challenge: safeBufferConvert(challenge.challenge),\n pubKeyCredParams: challenge.pubKeyCredParams || [\n { type: 'public-key', alg: -7 }, // ES256 (ECDSA w/ SHA-256)\n { type: 'public-key', alg: -35 }, // ES384 (ECDSA w/ SHA-384) \n { type: 'public-key', alg: -36 }, // ES512 (ECDSA w/ SHA-512)\n { type: 'public-key', alg: -257 }, // RS256 (RSASSA-PKCS1-v1_5 w/ SHA-256)\n { type: 'public-key', alg: -258 }, // RS384 (RSASSA-PKCS1-v1_5 w/ SHA-384)\n { type: 'public-key', alg: -259 }, // RS512 (RSASSA-PKCS1-v1_5 w/ SHA-512)\n { type: 'public-key', alg: -37 }, // PS256 (RSASSA-PSS w/ SHA-256)\n { type: 'public-key', alg: -38 }, // PS384 (RSASSA-PSS w/ SHA-384)\n { type: 'public-key', alg: -39 }, // PS512 (RSASSA-PSS w/ SHA-512)\n { type: 'public-key', alg: -8 } // EdDSA (Ed25519)\n ],\n timeout: challenge.timeout || (deviceType === 'passkey' ? 300000 : 120000), // Longer timeout for passkeys\n authenticatorSelection: challenge.authenticatorSelection || getOptimalAuthenticatorSelection(deviceType),\n attestation: challenge.attestation || (deviceType === 'passkey' ? 'none' : 'direct') // Different attestation preferences\n }\n\n // Only add excludeCredentials if it exists and has valid data\n if (challenge.excludeCredentials && Array.isArray(challenge.excludeCredentials) && challenge.excludeCredentials.length > 0) {\n cleanChallenge.excludeCredentials = challenge.excludeCredentials.map((cred: any) => ({\n type: 'public-key' as PublicKeyCredentialType,\n id: safeBufferConvert(cred.id)\n }))\n }\n\n return cleanChallenge as PublicKeyCredentialCreationOptions\n } catch (error) {\n console.error('Failed to create clean challenge:', error)\n throw new Error('Unable to process WebAuthn challenge data')\n }\n}\n\nconst startSetup = async () => {\n if (!deviceName.value.trim()) {\n deviceNameError.value = 'Device name is required'\n return\n }\n\n deviceNameError.value = ''\n step.value = 2\n}\n\nconst handleRegisterHardwareKey = async () => {\n internalLoading.value = true\n step.value = 3\n registrationMessage.value = `Starting ${props.deviceType === 'passkey' ? 'passkey' : 'hardware key'} registration...`\n\n try {\n // Check if WebAuthn is supported\n if (!window.navigator.credentials || !window.PublicKeyCredential) {\n throw new Error('WebAuthn is not supported in this browser')\n }\n\n // Check for platform authenticator support (better YubiKey detection)\n try {\n const available = await PublicKeyCredential.isUserVerifyingPlatformAuthenticatorAvailable?.()\n console.log('Platform authenticator available:', available)\n\n // Also check if conditional mediation is supported (indicates modern WebAuthn support)\n if (PublicKeyCredential.isConditionalMediationAvailable) {\n const conditionalMediationAvailable = await PublicKeyCredential.isConditionalMediationAvailable()\n console.log('Conditional mediation available:', conditionalMediationAvailable)\n }\n } catch (checkError) {\n console.warn('Could not check authenticator availability:', checkError)\n // Continue anyway as this is not critical\n }\n\n // Use composable for API call\n if (!currentSession.value?.accessToken) {\n throw new Error('Not authenticated. Please sign in again.')\n }\n\n const { device_id, challenge } = await registerHardwareKey(deviceName.value.trim(), currentSession.value.accessToken)\n\n console.log('WebAuthn challenge received:', JSON.stringify(challenge, null, 2))\n console.log('Device ID:', device_id)\n\n // Validate challenge structure\n if (!challenge || typeof challenge !== 'object') {\n throw new Error('Invalid challenge received from server')\n }\n\n // Log the raw challenge properties to debug the extension issue\n console.log('Challenge properties:', Object.keys(challenge))\n console.log('Challenge.challenge type:', typeof challenge.challenge, challenge.challenge)\n console.log('Challenge.user type:', typeof challenge.user, challenge.user)\n if (challenge.user) {\n console.log('Challenge.user.id type:', typeof challenge.user.id, challenge.user.id)\n }\n\n // Try to create a device-specific challenge optimized for the device type\n const processedChallenge = createOptimizedWebAuthnChallenge(challenge, props.deviceType)\n console.log('Processed challenge for WebAuthn:', processedChallenge)\n\n registrationMessage.value = 'Please touch your hardware key now...'\n\n // Create WebAuthn credential\n const credential = await navigator.credentials.create({\n publicKey: processedChallenge\n }) as PublicKeyCredential\n\n if (!credential) {\n throw new Error('Hardware key registration was cancelled')\n }\n\n console.log('WebAuthn credential created:', credential)\n registrationMessage.value = 'Completing registration...'\n\n // Complete registration via API using composable\n const response = credential.response as AuthenticatorAttestationResponse\n\n try {\n // Validate credential components before processing\n console.log('Credential structure:', {\n id: credential.id,\n rawId: credential.rawId,\n response: response,\n type: credential.type\n })\n\n if (!credential.rawId) {\n throw new Error('Missing rawId in credential')\n }\n if (!response.clientDataJSON) {\n throw new Error('Missing clientDataJSON in credential response')\n }\n if (!response.attestationObject) {\n throw new Error('Missing attestationObject in credential response')\n }\n\n // Safe ArrayBuffer to Array conversion\n const rawIdArray = credential.rawId instanceof ArrayBuffer ?\n Array.from(new Uint8Array(credential.rawId)) :\n Array.from(credential.rawId)\n\n const clientDataArray = response.clientDataJSON instanceof ArrayBuffer ?\n Array.from(new Uint8Array(response.clientDataJSON)) :\n Array.from(response.clientDataJSON)\n\n const attestationArray = response.attestationObject instanceof ArrayBuffer ?\n Array.from(new Uint8Array(response.attestationObject)) :\n Array.from(response.attestationObject)\n\n const credentialPayload = {\n id: credential.id,\n rawId: rawIdArray,\n response: {\n clientDataJSON: clientDataArray,\n attestationObject: attestationArray\n },\n type: credential.type\n }\n\n console.log('Sending credential payload:', credentialPayload)\n const result = await completeHardwareKeyRegistration(device_id, credentialPayload, currentSession.value.accessToken)\n console.log('Registration completed successfully:', result)\n backupCodes.value = result.backup_codes || []\n step.value = 4\n } catch (credError) {\n console.error('Error processing WebAuthn credential:', credError)\n throw new Error(`Failed to process hardware key data: ${credError instanceof Error ? credError.message : String(credError)}`)\n }\n\n } catch (error) {\n console.error('Hardware key registration error:', error)\n\n // Provide user-friendly error messages for common YubiKey issues\n let userErrorMessage = 'Hardware key registration failed'\n\n if (error instanceof Error) {\n const errorMsg = error.message.toLowerCase()\n\n if (errorMsg.includes('not supported') || errorMsg.includes('webauthn')) {\n userErrorMessage = 'WebAuthn is not supported in this browser. Please use Chrome, Firefox, Safari, or Edge.'\n } else if (errorMsg.includes('cancelled') || errorMsg.includes('aborted')) {\n userErrorMessage = 'Hardware key registration was cancelled. Please try again and touch your key when prompted.'\n } else if (errorMsg.includes('timeout')) {\n userErrorMessage = 'Hardware key registration timed out. Please ensure your key is connected and try again.'\n } else if (errorMsg.includes('not allowed') || errorMsg.includes('invalid state')) {\n userErrorMessage = 'This hardware key may already be registered or cannot be used. Try a different key or contact support.'\n } else if (errorMsg.includes(\"can't be used\") || errorMsg.includes('newer or different')) {\n userErrorMessage = 'Your hardware key is not compatible. Please ensure you have a FIDO2/WebAuthn compatible key like YubiKey 5 Series, and that it\\'s properly connected.'\n } else if (errorMsg.includes('user verification') || errorMsg.includes('pin')) {\n userErrorMessage = 'Hardware key verification failed. If your key has a PIN, please enter it when prompted.'\n } else {\n userErrorMessage = error.message\n }\n }\n\n errorMessage.value = userErrorMessage\n step.value = 5\n } finally {\n internalLoading.value = false\n }\n}\n\nconst copyBackupCodes = async () => {\n if (!backupCodes.value.length) return\n\n try {\n const codesText = backupCodes.value.join('\\n')\n await navigator.clipboard.writeText(codesText)\n // Could show a toast here\n console.log('Backup codes copied to clipboard')\n } catch (error) {\n console.error('Failed to copy backup codes:', error)\n }\n}\n\nconst finish = () => {\n emit('success')\n}\n</script>\n\n<style scoped>\n/* Modal container */\n.hardware-key-setup-modal {\n max-width: 28rem;\n}\n\n/* Header */\n.hardware-key-setup-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n}\n\n.hardware-key-setup-title {\n font-size: 1.25rem;\n font-weight: 700;\n color: #111827;\n}\n\n.hardware-key-setup-close {\n color: #9ca3af;\n transition: color 0.2s ease;\n background: none;\n border: none;\n cursor: pointer;\n padding: 0.25rem;\n border-radius: 0.25rem;\n}\n\n.hardware-key-setup-close:hover {\n color: #4b5563;\n}\n\n.hardware-key-setup-close-icon {\n width: 1.25rem;\n height: 1.25rem;\n}\n\n/* Step container */\n.hardware-key-setup-step {\n display: flex;\n flex-direction: column;\n gap: 1rem;\n}\n\n.hardware-key-setup-step-title {\n font-size: 1.125rem;\n font-weight: 600;\n color: #111827;\n margin-bottom: 0.5rem;\n}\n\n.hardware-key-setup-step-description {\n font-size: 0.875rem;\n color: #6b7280;\n margin-bottom: 1rem;\n}\n\n/* Actions */\n.hardware-key-setup-actions {\n display: flex;\n justify-content: flex-end;\n gap: 0.75rem;\n padding-top: 1rem;\n}\n\n.hardware-key-setup-final-action {\n display: flex;\n justify-content: flex-end;\n padding-top: 1rem;\n}\n\n/* Illustration */\n.hardware-key-setup-illustration {\n display: flex;\n justify-content: center;\n background-color: #f9fafb;\n padding: 1.5rem;\n border-radius: 0.5rem;\n}\n\n.hardware-key-setup-illustration-content {\n text-align: center;\n}\n\n.hardware-key-setup-icon-container {\n width: 4rem;\n height: 4rem;\n background-color: #dbeafe;\n border-radius: 0.5rem;\n display: flex;\n align-items: center;\n justify-content: center;\n margin: 0 auto 1rem auto;\n}\n\n.hardware-key-setup-icon {\n width: 2rem;\n height: 2rem;\n color: #2563eb;\n}\n\n.hardware-key-setup-status {\n font-size: 0.875rem;\n font-weight: 500;\n color: #111827;\n}\n\n.hardware-key-setup-substatus {\n font-size: 0.75rem;\n color: #6b7280;\n margin-top: 0.25rem;\n}\n\n/* Instructions */\n.hardware-key-setup-instructions {\n background-color: #eff6ff;\n border: 1px solid #bfdbfe;\n border-radius: 0.5rem;\n padding: 1rem;\n}\n\n.hardware-key-setup-instructions-header {\n display: flex;\n align-items: flex-start;\n gap: 0.5rem;\n}\n\n.hardware-key-setup-info-icon {\n width: 1.25rem;\n height: 1.25rem;\n color: #2563eb;\n margin-top: 0.125rem;\n flex-shrink: 0;\n}\n\n.hardware-key-setup-instructions-title {\n font-size: 0.875rem;\n font-weight: 500;\n color: #1e40af;\n}\n\n.hardware-key-setup-instructions-list {\n font-size: 0.875rem;\n color: #1d4ed8;\n margin-top: 0.25rem;\n display: flex;\n flex-direction: column;\n gap: 0.25rem;\n}\n\n/* Progress states */\n.hardware-key-setup-progress {\n text-align: center;\n}\n\n.hardware-key-setup-progress-icon {\n width: 3rem;\n height: 3rem;\n background-color: #dbeafe;\n border-radius: 50%;\n display: flex;\n align-items: center;\n justify-content: center;\n margin: 0 auto 1rem auto;\n}\n\n.hardware-key-setup-loader {\n color: #2563eb;\n}\n\n.hardware-key-setup-progress-message {\n font-size: 0.875rem;\n color: #6b7280;\n margin-bottom: 1.5rem;\n}\n\n.hardware-key-setup-progress-indicator {\n background-color: #f9fafb;\n padding: 1rem;\n border-radius: 0.5rem;\n}\n\n.hardware-key-setup-progress-content {\n display: flex;\n align-items: center;\n gap: 0.75rem;\n}\n\n.hardware-key-setup-progress-check {\n flex-shrink: 0;\n}\n\n.hardware-key-setup-check-icon {\n width: 1.5rem;\n height: 1.5rem;\n background-color: #2563eb;\n border-radius: 50%;\n display: flex;\n align-items: center;\n justify-content: center;\n}\n\n.hardware-key-setup-check {\n width: 1rem;\n height: 1rem;\n color: white;\n}\n\n.hardware-key-setup-progress-text {\n font-size: 0.875rem;\n color: #374151;\n}\n\n/* Success state */\n.hardware-key-setup-success {\n text-align: center;\n}\n\n.hardware-key-setup-success-icon {\n width: 3rem;\n height: 3rem;\n background-color: #dcfce7;\n border-radius: 50%;\n display: flex;\n align-items: center;\n justify-content: center;\n margin: 0 auto 1rem auto;\n}\n\n.hardware-key-setup-success-check {\n width: 1.5rem;\n height: 1.5rem;\n color: #16a34a;\n}\n\n.hardware-key-setup-success-message {\n font-size: 0.875rem;\n color: #6b7280;\n margin-bottom: 1.5rem;\n}\n\n/* Backup codes */\n.hardware-key-setup-backup-codes {\n background-color: #fef2f2;\n border: 1px solid #fecaca;\n border-radius: 0.5rem;\n padding: 1rem;\n}\n\n.hardware-key-setup-backup-codes-header {\n display: flex;\n align-items: flex-start;\n gap: 0.5rem;\n margin-bottom: 0.75rem;\n}\n\n.hardware-key-setup-warning-icon {\n width: 1.25rem;\n height: 1.25rem;\n color: #dc2626;\n margin-top: 0.125rem;\n flex-shrink: 0;\n}\n\n.hardware-key-setup-backup-codes-title {\n font-size: 0.875rem;\n font-weight: 500;\n color: #991b1b;\n}\n\n.hardware-key-setup-backup-codes-description {\n font-size: 0.875rem;\n color: #b91c1c;\n margin-top: 0.25rem;\n}\n\n.hardware-key-setup-codes-container {\n background-color: white;\n border-radius: 0.25rem;\n border: 1px solid #d1d5db;\n padding: 0.75rem;\n}\n\n.hardware-key-setup-codes-grid {\n display: grid;\n grid-template-columns: repeat(2, 1fr);\n gap: 0.5rem;\n font-size: 0.875rem;\n font-family: ui-monospace, SFMono-Regular, \"SF Mono\", Consolas, \"Liberation Mono\", Menlo, monospace;\n color: #111827;\n}\n\n.hardware-key-setup-code {\n text-align: center;\n padding: 0.25rem 0;\n}\n\n.hardware-key-setup-copy-action {\n display: flex;\n justify-content: center;\n margin-top: 0.75rem;\n}\n\n/* Error state */\n.hardware-key-setup-error {\n text-align: center;\n}\n\n.hardware-key-setup-error-icon {\n width: 3rem;\n height: 3rem;\n background-color: #fee2e2;\n border-radius: 50%;\n display: flex;\n align-items: center;\n justify-content: center;\n margin: 0 auto 1rem auto;\n}\n\n.hardware-key-setup-error-x {\n width: 1.5rem;\n height: 1.5rem;\n color: #dc2626;\n}\n\n.hardware-key-setup-error-message {\n font-size: 0.875rem;\n color: #6b7280;\n margin-bottom: 1.5rem;\n}\n</style>","<template>\n <div class=\"accui-component-scope\">\n <UiModal :open=\"show\" @close=\"closeModal\" card-class=\"backup-codes-modal\">\n <template #header>\n <div class=\"backup-codes-header\">\n <h2 class=\"backup-codes-title\">Backup Codes</h2>\n <button @click=\"closeModal\" class=\"backup-codes-close-button\">\n <svg class=\"backup-codes-close-icon\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M6 18L18 6M6 6l12 12\" />\n </svg>\n </button>\n </div>\n </template>\n <div v-if=\"loading\" class=\"backup-codes-loading\">\n <StrandsUiLoader :size=\"24\" />\n <span class=\"backup-codes-loading-text\">Loading backup codes...</span>\n </div>\n\n <div v-else class=\"backup-codes-content\">\n <!-- Device Info -->\n <div v-if=\"device\" class=\"backup-codes-device-info\">\n <div class=\"backup-codes-device-content\">\n <span class=\"backup-codes-device-icon\">📱</span>\n <div>\n <h3 class=\"backup-codes-device-name\">{{ device.device_name }}</h3>\n <p class=\"backup-codes-device-type\">{{ getDeviceTypeName(device.device_type) }}</p>\n </div>\n </div>\n </div>\n\n <!-- Warning -->\n <div class=\"backup-codes-warning\">\n <div class=\"backup-codes-warning-content\">\n <svg class=\"backup-codes-warning-icon\" fill=\"currentColor\" viewBox=\"0 0 20 20\">\n <path fill-rule=\"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 clip-rule=\"evenodd\" />\n </svg>\n <div>\n <p class=\"backup-codes-warning-title\">Important Security Information</p>\n <ul class=\"backup-codes-warning-list\">\n <li>• Each backup code can only be used once</li>\n <li>• Store these codes in a safe place</li>\n <li>• Use backup codes if you lose access to your authenticator</li>\n <li>• Regenerating codes will invalidate all previous codes</li>\n </ul>\n </div>\n </div>\n </div>\n\n <!-- Backup Codes -->\n <div v-if=\"backupCodes.length > 0\">\n <h3 class=\"backup-codes-section-title\">Your Backup Codes</h3>\n <div class=\"backup-codes-grid-wrapper\">\n <div class=\"backup-codes-grid\">\n <div v-for=\"(code, index) in backupCodes\" :key=\"index\" class=\"backup-codes-code-item\">\n {{ code }}\n </div>\n </div>\n </div>\n\n <div class=\"backup-codes-actions\">\n <StrandsUiButton variant=\"secondary\" size=\"sm\" @click=\"copyBackupCodes\">\n 📋 Copy All Codes\n </StrandsUiButton>\n <StrandsUiButton variant=\"secondary\" size=\"sm\" @click=\"downloadBackupCodes\">\n 💾 Download\n </StrandsUiButton>\n </div>\n </div>\n\n <!-- Actions -->\n <div class=\"backup-codes-main-actions\">\n <div class=\"backup-codes-main-actions-content\">\n <StrandsUiButton variant=\"secondary\" @click=\"regenerateCodes\" :disabled=\"loading\" :loading=\"loading\">\n 🔄 Regenerate Codes\n </StrandsUiButton>\n <StrandsUiButton variant=\"primary\" @click=\"closeModal\">\n Done\n </StrandsUiButton>\n </div>\n </div>\n\n <!-- Regeneration Warning -->\n <div v-if=\"showRegenerateWarning\" class=\"backup-codes-regenerate-warning\">\n <div class=\"backup-codes-regenerate-content\">\n <svg class=\"backup-codes-regenerate-icon\" fill=\"currentColor\" viewBox=\"0 0 20 20\">\n <path fill-rule=\"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 clip-rule=\"evenodd\" />\n </svg>\n <div>\n <p class=\"backup-codes-regenerate-title\">Regenerate Backup Codes?</p>\n <p class=\"backup-codes-regenerate-description\">\n This will invalidate all current backup codes. Make sure to save the new ones.\n </p>\n <div class=\"backup-codes-regenerate-actions\">\n <StrandsUiButton variant=\"primary\" size=\"sm\" @click=\"confirmRegenerate\" :disabled=\"loading\"\n :loading=\"loading\">\n Yes, Regenerate\n </StrandsUiButton>\n <StrandsUiButton variant=\"secondary\" size=\"sm\" @click=\"showRegenerateWarning = false\">\n Cancel\n </StrandsUiButton>\n </div>\n </div>\n </div>\n </div>\n </div>\n </UiModal>\n </div>\n</template>\n\n<script setup lang=\"ts\">\nimport { ref, watch, onMounted } from 'vue'\nimport { StrandsUiButton, StrandsUiLoader } from '../ui'\nimport UiModal from '../ui/UiModal.vue'\nimport { useStrandsMfa } from '../composables/useStrandsMfa'\nimport type { MfaDevice } from '../../types'\n\ninterface Props {\n show: boolean\n device?: MfaDevice | null\n}\n\ninterface Emits {\n (e: 'close'): void\n}\n\nconst props = defineProps<Props>()\nconst emit = defineEmits<Emits>()\n\nconst { regenerateBackupCodes, loading, getDeviceTypeName } = useStrandsMfa()\n\n// State\nconst backupCodes = ref<string[]>([])\nconst showRegenerateWarning = ref(false)\n\n// Load backup codes when modal opens\nwatch(() => props.show, async (newShow) => {\n if (newShow && props.device) {\n showRegenerateWarning.value = false\n // For now, we'll use the device's backup codes if available\n // In a real implementation, you might fetch fresh codes or show cached ones\n backupCodes.value = []\n }\n})\n\nonMounted(async () => {\n if (props.show && props.device) {\n // Initialize with empty codes - user needs to regenerate to see them\n backupCodes.value = []\n }\n})\n\nconst closeModal = () => {\n emit('close')\n}\n\nconst regenerateCodes = () => {\n showRegenerateWarning.value = true\n}\n\nconst confirmRegenerate = async () => {\n if (!props.device) return\n\n try {\n const response = await regenerateBackupCodes(props.device.id)\n backupCodes.value = response.backup_codes\n showRegenerateWarning.value = false\n } catch (error) {\n console.error('Failed to regenerate backup codes:', error)\n // Show error message\n }\n}\n\nconst copyBackupCodes = async () => {\n if (backupCodes.value.length === 0) return\n\n try {\n const codesText = backupCodes.value.join('\\n')\n await navigator.clipboard.writeText(codesText)\n // Could show a toast here\n console.log('Backup codes copied to clipboard')\n } catch (error) {\n console.error('Failed to copy backup codes:', error)\n }\n}\n\nconst downloadBackupCodes = () => {\n if (backupCodes.value.length === 0) return\n\n const deviceName = props.device?.device_name || 'device'\n const timestamp = new Date().toISOString().split('T')[0]\n const filename = `strands-backup-codes-${deviceName}-${timestamp}.txt`\n\n const content = [\n 'Strands Account Backup Codes',\n '============================',\n '',\n `Device: ${props.device?.device_name}`,\n `Generated: ${new Date().toLocaleString()}`,\n '',\n 'IMPORTANT:',\n '- Each code can only be used once',\n '- Store these codes in a safe place',\n '- Use these if you lose access to your authenticator',\n '',\n 'Backup Codes:',\n ...backupCodes.value.map((code, index) => `${index + 1}. ${code}`),\n '',\n '============================',\n ].join('\\n')\n\n const blob = new Blob([content], { type: 'text/plain' })\n const url = URL.createObjectURL(blob)\n const link = document.createElement('a')\n link.href = url\n link.download = filename\n document.body.appendChild(link)\n link.click()\n document.body.removeChild(link)\n URL.revokeObjectURL(url)\n}\n</script>\n\n<style scoped>\n/* Modal container */\n.backup-codes-modal {\n max-width: 28rem;\n}\n\n/* Header */\n.backup-codes-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n}\n\n.backup-codes-title {\n font-size: 1.25rem;\n font-weight: 700;\n color: #111827;\n}\n\n.backup-codes-close-button {\n color: #9ca3af;\n transition: color 0.2s ease;\n background: none;\n border: none;\n cursor: pointer;\n padding: 0.25rem;\n}\n\n.backup-codes-close-button:hover {\n color: #4b5563;\n}\n\n.backup-codes-close-icon {\n width: 1.25rem;\n height: 1.25rem;\n}\n\n/* Loading */\n.backup-codes-loading {\n display: flex;\n align-items: center;\n justify-content: center;\n padding: 2rem 0;\n}\n\n.backup-codes-loading-text {\n margin-left: 0.75rem;\n color: #4b5563;\n}\n\n/* Content */\n.backup-codes-content {\n display: flex;\n flex-direction: column;\n gap: 1.5rem;\n}\n\n/* Device info */\n.backup-codes-device-info {\n background-color: #f9fafb;\n border-radius: 0.5rem;\n padding: 1rem;\n}\n\n.backup-codes-device-content {\n display: flex;\n align-items: center;\n gap: 0.75rem;\n}\n\n.backup-codes-device-icon {\n font-size: 1.5rem;\n}\n\n.backup-codes-device-name {\n font-weight: 500;\n color: #111827;\n margin: 0;\n}\n\n.backup-codes-device-type {\n font-size: 0.875rem;\n color: #6b7280;\n margin: 0;\n}\n\n/* Warning */\n.backup-codes-warning {\n background-color: #fef2f2;\n border: 1px solid #fecaca;\n border-radius: 0.5rem;\n padding: 1rem;\n}\n\n.backup-codes-warning-content {\n display: flex;\n align-items: flex-start;\n gap: 0.5rem;\n}\n\n.backup-codes-warning-icon {\n width: 1.25rem;\n height: 1.25rem;\n color: #dc2626;\n margin-top: 0.125rem;\n flex-shrink: 0;\n}\n\n.backup-codes-warning-title {\n font-size: 0.875rem;\n font-weight: 500;\n color: #991b1b;\n margin: 0;\n}\n\n.backup-codes-warning-list {\n font-size: 0.875rem;\n color: #b91c1c;\n margin-top: 0.25rem;\n display: flex;\n flex-direction: column;\n gap: 0.25rem;\n list-style: none;\n padding: 0;\n}\n\n/* Section title */\n.backup-codes-section-title {\n font-size: 1.125rem;\n font-weight: 600;\n color: #111827;\n margin-bottom: 0.75rem;\n}\n\n/* Codes grid */\n.backup-codes-grid-wrapper {\n background-color: white;\n border: 1px solid #e5e7eb;\n border-radius: 0.5rem;\n padding: 1rem;\n}\n\n.backup-codes-grid {\n display: grid;\n grid-template-columns: repeat(2, 1fr);\n gap: 0.5rem;\n font-size: 0.875rem;\n font-family: 'SF Mono', Monaco, Inconsolata, 'Roboto Mono', Consolas, 'Courier New', monospace;\n}\n\n.backup-codes-code-item {\n text-align: center;\n padding: 0.5rem 0;\n background-color: #f9fafb;\n border-radius: 0.25rem;\n}\n\n/* Actions */\n.backup-codes-actions {\n display: flex;\n justify-content: center;\n margin-top: 1rem;\n gap: 0.75rem;\n}\n\n.backup-codes-main-actions {\n padding-top: 1rem;\n border-top: 1px solid #e5e7eb;\n}\n\n.backup-codes-main-actions-content {\n display: flex;\n justify-content: space-between;\n}\n\n/* Regenerate warning */\n.backup-codes-regenerate-warning {\n background-color: #fefce8;\n border: 1px solid #fde047;\n border-radius: 0.5rem;\n padding: 1rem;\n}\n\n.backup-codes-regenerate-content {\n display: flex;\n align-items: flex-start;\n gap: 0.5rem;\n}\n\n.backup-codes-regenerate-icon {\n width: 1.25rem;\n height: 1.25rem;\n color: #d97706;\n margin-top: 0.125rem;\n flex-shrink: 0;\n}\n\n.backup-codes-regenerate-title {\n font-size: 0.875rem;\n font-weight: 500;\n color: #92400e;\n margin: 0;\n}\n\n.backup-codes-regenerate-description {\n font-size: 0.875rem;\n color: #a16207;\n margin-top: 0.25rem;\n}\n\n.backup-codes-regenerate-actions {\n display: flex;\n gap: 0.5rem;\n margin-top: 0.75rem;\n}\n</style>\n","<template>\n <div class=\"accui-component-scope\">\n <UiModal :open=\"show\" card-class=\"confirm-modal\">\n <template #header>\n <h2 class=\"confirm-modal-title\">{{ title }}</h2>\n </template>\n \n <p class=\"confirm-modal-message\">{{ message }}</p>\n\n <div class=\"confirm-modal-actions\">\n <StrandsUiButton\n variant=\"secondary\"\n @click=\"handleCancel\"\n :disabled=\"loading\"\n >\n {{ cancelText }}\n </StrandsUiButton>\n <StrandsUiButton\n :variant=\"variant\"\n @click=\"handleConfirm\"\n :disabled=\"loading\"\n :loading=\"loading\"\n >\n {{ confirmText }}\n </StrandsUiButton>\n </div>\n </UiModal>\n </div>\n</template>\n\n<script setup lang=\"ts\">\nimport { ref } from 'vue'\nimport { StrandsUiButton } from '../ui'\nimport UiModal from '../ui/UiModal.vue'\n\ntype ButtonVariant = 'primary' | 'secondary' | 'ghost' | 'outline'\n\ninterface Props {\n show: boolean\n title: string\n message: string\n confirmText?: string\n cancelText?: string\n variant?: ButtonVariant\n}\n\ninterface Emits {\n (e: 'confirm'): void\n (e: 'cancel'): void\n}\n\nconst props = withDefaults(defineProps<Props>(), {\n confirmText: 'Confirm',\n cancelText: 'Cancel',\n variant: 'primary'\n})\n\nconst emit = defineEmits<Emits>()\n\nconst loading = ref(false)\n\nconst handleConfirm = () => {\n loading.value = true\n emit('confirm')\n // Note: Parent component should handle resetting loading state\n // by either closing the modal or setting loading to false\n}\n\nconst handleCancel = () => {\n emit('cancel')\n}\n</script>\n\n<style scoped>\n.confirm-modal {\n max-width: 24rem;\n}\n\n.confirm-modal-title {\n font-size: 1.125rem;\n font-weight: 700;\n color: #111827;\n}\n\n.confirm-modal-message {\n font-size: 0.875rem;\n color: #6b7280;\n margin-bottom: 1.5rem;\n}\n\n.confirm-modal-actions {\n display: flex;\n justify-content: flex-end;\n gap: 0.75rem;\n}\n</style>\n","<template>\n <div class=\"accui-component-scope\">\n <UiModal :open=\"showModal\" @close=\"closeModal\" card-class=\"mfa-modal-card\">\n <template #header>\n <div class=\"mfa-modal-header\">\n <h2 class=\"mfa-modal-title\">Two-Factor Authentication</h2>\n <button @click=\"closeModal\" class=\"mfa-modal-close\">\n <svg class=\"mfa-modal-close-icon\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M6 18L18 6M6 6l12 12\" />\n </svg>\n </button>\n </div>\n </template>\n <!-- Loading State -->\n <div v-if=\"mfaLoading\" class=\"mfa-loading\">\n <StrandsUiLoader :size=\"32\" />\n <span class=\"mfa-loading-text\">Loading MFA settings...</span>\n </div>\n\n <!-- Tab Navigation -->\n <div v-else class=\"mfa-content\">\n <!-- MFA Status Overview -->\n <div class=\"mfa-status-overview\">\n <div class=\"mfa-status-content\">\n <div>\n <h3 class=\"mfa-status-title\">Two-Factor Authentication</h3>\n <p class=\"mfa-status-subtitle\">\n {{ mfaEnabled ? 'Enabled' : 'Add extra security to your account' }}\n </p>\n </div>\n <div class=\"mfa-status-badges\">\n <span v-if=\"mfaEnabled\" class=\"mfa-status-badge mfa-status-badge-enabled\">\n <Shield :size=\"12\" class=\"mfa-badge-icon\" />\n Enabled\n </span>\n <span v-else class=\"mfa-status-badge mfa-status-badge-disabled\">\n Not Enabled\n </span>\n </div>\n </div>\n </div>\n\n <!-- Tab Navigation -->\n <div class=\"mfa-tabs-container\">\n <nav class=\"mfa-tabs-nav\" aria-label=\"Tabs\">\n <button @click=\"activeTab = 'add'\" :class=\"[\n 'mfa-tab-button',\n activeTab === 'add' ? 'mfa-tab-button-active' : 'mfa-tab-button-inactive'\n ]\">\n Add New Device\n </button>\n <button v-if=\"activeMfaDevices.length > 0\" @click=\"activeTab = 'manage'\" :class=\"[\n 'mfa-tab-button',\n activeTab === 'manage' ? 'mfa-tab-button-active' : 'mfa-tab-button-inactive'\n ]\">\n Active Devices ({{ activeMfaDevices.length }})\n </button>\n </nav>\n </div>\n\n <!-- Tab Content: Add New Device -->\n <div v-if=\"activeTab === 'add'\" class=\"mfa-add-devices\">\n <div>\n <h3 class=\"mfa-section-title\">Choose Your Authentication Method</h3>\n <div class=\"mfa-device-options\">\n <!-- TOTP Setup -->\n <div class=\"mfa-device-option\" @click=\"startTotpSetup\">\n <div class=\"mfa-device-layout\">\n <div class=\"mfa-device-icon-container mfa-device-icon-totp\">\n <Smartphone :size=\"24\" class=\"mfa-device-icon\" />\n </div>\n <div class=\"mfa-device-content\">\n <div class=\"mfa-device-info\">\n <h4 class=\"mfa-device-title\">Authenticator App</h4>\n <p class=\"mfa-device-description\">\n Use Google Authenticator, Authy, or any TOTP-compatible app to generate secure codes\n </p>\n </div>\n </div>\n <div class=\"mfa-device-action\">\n <StrandsUiButton variant=\"primary\" size=\"md\" @click.stop=\"startTotpSetup\" :disabled=\"mfaLoading\">\n Setup\n </StrandsUiButton>\n </div>\n </div>\n </div>\n\n <!-- Email MFA Setup -->\n <div class=\"mfa-device-option\" @click=\"startEmailMfaSetup\">\n <div class=\"mfa-device-layout\">\n <div class=\"mfa-device-icon-container mfa-device-icon-email\">\n <Mail :size=\"24\" class=\"mfa-device-icon\" />\n </div>\n <div class=\"mfa-device-content\">\n <div class=\"mfa-device-info\">\n <h4 class=\"mfa-device-title\">Email Verification</h4>\n <p class=\"mfa-device-description\">\n Receive verification codes directly in your email inbox for easy access\n </p>\n </div>\n </div>\n <div class=\"mfa-device-action\">\n <StrandsUiButton variant=\"primary\" size=\"md\" @click.stop=\"startEmailMfaSetup\"\n :disabled=\"mfaLoading\">\n Setup\n </StrandsUiButton>\n </div>\n </div>\n </div>\n\n <!-- Hardware Key Setup - Temporarily Disabled -->\n <!-- \n <div class=\"group p-6 bg-white border border-gray-200 rounded-xl hover:border-gray-300 hover:shadow-md transition-all duration-200 cursor-pointer\" @click=\"startHardwareKeySetup\">\n <div class=\"flex items-center justify-between\">\n <div class=\"flex-shrink-0 w-14 h-14 bg-[var(--strands-primary)] bg-opacity-10 rounded-xl flex items-center justify-center group-hover:bg-[var(--strands-primary)] group-hover:bg-opacity-15 transition-colors\">\n <KeyRound :size=\"24\" class=\"text-[var(--strands-primary)]\" />\n </div>\n <div class=\"flex items-start space-x-4\">\n <div class=\"min-w-0 flex-1\">\n <h4 class=\"font-semibold text-gray-900 text-lg\">Hardware Security Key</h4>\n <p class=\"text-xs text-gray-500 mt-2\">\n Use YubiKey, FIDO2, or other physical security keys for ultimate protection\n </p>\n </div>\n </div>\n <div class=\"flex flex-col space-y-2 ml-4\">\n <StrandsUiButton\n variant=\"primary\"\n size=\"md\"\n @click.stop=\"startHardwareKeySetup\"\n :disabled=\"mfaLoading\"\n >\n Setup\n </StrandsUiButton>\n </div>\n </div>\n </div>\n\n <-- Passkey Setup - Temporarily Disabled -->\n <!-- \n <div class=\"group p-6 bg-white border border-gray-200 rounded-xl hover:border-gray-300 hover:shadow-md transition-all duration-200 cursor-pointer\" @click=\"startPasskeySetup\">\n <div class=\"flex items-center justify-between\">\n <div class=\"flex-shrink-0 w-14 h-14 bg-[var(--strands-primary)] bg-opacity-10 rounded-xl flex items-center justify-center group-hover:bg-[var(--strands-primary)] group-hover:bg-opacity-15 transition-colors\">\n <Shield :size=\"24\" class=\"text-[var(--strands-primary)]\" />\n </div>\n <div class=\"flex items-start space-x-4\">\n <div class=\"min-w-0 flex-1\">\n <h4 class=\"font-semibold text-gray-900 text-lg\">Passkey</h4>\n <p class=\"text-xs text-gray-500 mt-2\">\n Use your device's built-in biometrics, PIN, or cross-device passkeys\n </p>\n </div>\n </div>\n <div class=\"flex flex-col space-y-2 ml-4\">\n <StrandsUiButton\n variant=\"primary\"\n size=\"md\"\n @click.stop=\"startPasskeySetup\"\n :disabled=\"mfaLoading\"\n >\n Setup\n </StrandsUiButton>\n </div>\n </div>\n </div>\n -->\n </div>\n </div>\n </div>\n\n <!-- Tab Content: Active Devices -->\n <div v-else-if=\"activeTab === 'manage' && activeMfaDevices.length > 0\" class=\"mfa-manage-devices\">\n <div>\n <h3 class=\"mfa-section-title\">Manage Your Active Devices</h3>\n <div class=\"mfa-devices-list\">\n <div v-for=\"device in activeMfaDevices\" :key=\"device.id\" class=\"mfa-device-card\">\n <div class=\"mfa-device-card-content\">\n <div class=\"mfa-device-card-info\">\n <div class=\"mfa-device-card-icon-container\" :class=\"getDeviceIconBackground(device.device_type)\">\n <component :is=\"getDeviceIconComponent(device.device_type)\" :size=\"24\"\n class=\"mfa-device-card-icon\" />\n </div>\n <div class=\"mfa-device-card-details\">\n <h4 class=\"mfa-device-card-name\">{{ device.device_name }}</h4>\n <p class=\"mfa-device-card-type\">\n {{ getDeviceTypeName(device.device_type) }}\n </p>\n <p class=\"mfa-device-card-last-used\">\n Last used {{ formatLastUsed(device.last_used_at) }}\n </p>\n </div>\n </div>\n <div class=\"mfa-device-card-actions\">\n <!-- Backup codes button for TOTP, Hardware Key, and Passkey devices -->\n <StrandsUiButton\n v-if=\"device.device_type === 'totp' || device.device_type === 'hardware' || device.device_type === 'passkey'\"\n variant=\"secondary\" size=\"sm\" @click=\"showBackupCodes(device)\" :disabled=\"mfaLoading\">\n <KeyRound :size=\"14\" class=\"mfa-button-icon\" />\n Backup Codes\n </StrandsUiButton>\n\n <!-- Test email MFA -->\n <StrandsUiButton v-if=\"device.device_type === 'email'\" variant=\"secondary\" size=\"sm\"\n @click=\"testEmailMfa(device)\" :disabled=\"mfaLoading\">\n <Mail :size=\"14\" class=\"mfa-button-icon\" />\n Send Test Code\n </StrandsUiButton>\n\n <!-- Remove device -->\n <StrandsUiButton variant=\"secondary\" size=\"sm\" @click=\"confirmDisableDevice(device)\"\n :disabled=\"mfaLoading\" class=\"mfa-remove-button\">\n <Trash2 :size=\"14\" class=\"mfa-button-icon\" />\n Remove\n </StrandsUiButton>\n </div>\n </div>\n </div>\n </div>\n </div>\n </div>\n </div>\n\n <!-- TOTP Setup Modal -->\n <StrandsTotpSetupModal v-if=\"showTotpSetup\" :show=\"showTotpSetup\" @close=\"showTotpSetup = false\"\n @success=\"handleTotpSetupSuccess\" />\n\n <!-- Email MFA Setup Modal -->\n <StrandsEmailMfaSetupModal v-if=\"showEmailMfaSetup\" :show=\"showEmailMfaSetup\" @close=\"showEmailMfaSetup = false\"\n @success=\"handleEmailMfaSetupSuccess\" />\n\n <!-- Hardware Key Setup Modal -->\n <StrandsHardwareKeySetupModal v-if=\"showHardwareKeySetup\" :show=\"showHardwareKeySetup\" :device-type=\"'hardware'\"\n @close=\"showHardwareKeySetup = false\" @success=\"handleHardwareKeySetupSuccess\" />\n\n <!-- Passkey Setup Modal -->\n <StrandsHardwareKeySetupModal v-if=\"showPasskeySetup\" :show=\"showPasskeySetup\" :device-type=\"'passkey'\"\n @close=\"showPasskeySetup = false\" @success=\"handlePasskeySetupSuccess\" />\n\n <!-- Backup Codes Modal -->\n <StrandsBackupCodesModal v-if=\"showBackupCodesModal\" :show=\"showBackupCodesModal\" :device=\"selectedDevice\"\n @close=\"showBackupCodesModal = false\" />\n\n </UiModal>\n\n <!-- Confirm Disable Modal -->\n <StrandsConfirmModal v-if=\"showConfirmDisable\" :show=\"showConfirmDisable\" title=\"Remove MFA Device\"\n :message=\"`Are you sure you want to remove '${selectedDevice?.device_name}'? This action cannot be undone.`\"\n confirm-text=\"Remove Device\" cancel-text=\"Keep Device\" variant=\"secondary\" @confirm=\"handleDisableDevice\"\n @cancel=\"showConfirmDisable = false\" />\n </div>\n</template>\n\n<script setup lang=\"ts\">\nimport { ref, computed, onMounted, watch, h } from 'vue'\nimport { StrandsUiButton, StrandsUiLoader } from '../ui'\n\n// Inline SVG icon components using render functions (no runtime compilation needed)\nconst Smartphone = {\n props: { size: { type: [String, Number], default: 24 } },\n render(this: any) {\n return h('svg', { \n width: this.size, \n height: this.size, \n fill: 'none', \n stroke: 'currentColor', \n viewBox: '0 0 24 24' \n }, [\n h('rect', { x: '5', y: '2', width: '14', height: '20', rx: '2', ry: '2' }),\n h('line', { x1: '12', y1: '18', x2: '12.01', y2: '18' })\n ])\n }\n}\n\nconst Mail = {\n props: { size: { type: [String, Number], default: 24 } },\n render(this: any) {\n return h('svg', { \n width: this.size, \n height: this.size, \n fill: 'none', \n stroke: 'currentColor', \n viewBox: '0 0 24 24' \n }, [\n h('path', { d: 'm4 4 16 0c1.1 0 2 .9 2 2l0 12c0 1.1-.9 2-2 2l-16 0c-1.1 0-2-.9-2-2l0-12c0-1.1.9-2 2-2z' }),\n h('polyline', { points: '22,6 12,13 2,6' })\n ])\n }\n}\n\nconst KeyRound = {\n props: { size: { type: [String, Number], default: 24 } },\n render(this: any) {\n return h('svg', { \n width: this.size, \n height: this.size, \n fill: 'none', \n stroke: 'currentColor', \n viewBox: '0 0 24 24' \n }, [\n h('path', { d: 'M2.586 17.414A2 2 0 0 0 2 18.828V21a1 1 0 0 0 1 1h3a1 1 0 0 0 1-1v-1a1 1 0 0 1 1-1h1a1 1 0 0 0 1-1v-1a1 1 0 0 1 1-1h.172a2 2 0 0 0 1.414-.586l.814-.814a6.5 6.5 0 1 0-4-4z' }),\n h('circle', { cx: '16.5', cy: '7.5', r: '.5', fill: 'currentColor' })\n ])\n }\n}\n\nconst Shield = {\n props: { size: { type: [String, Number], default: 24 } },\n render(this: any) {\n return h('svg', { \n width: this.size, \n height: this.size, \n fill: 'none', \n stroke: 'currentColor', \n viewBox: '0 0 24 24' \n }, [\n h('path', { d: 'M20 13c0 5-3.5 7.5-7.66 8.95a1 1 0 0 1-.67-.01C7.5 20.5 4 18 4 13V6a1 1 0 0 1 1-1c2 0 4.5-1.2 6.24-2.72a1.17 1.17 0 0 1 1.52 0C14.51 3.81 17 5 19 5a1 1 0 0 1 1 1z' })\n ])\n }\n}\n\nconst Trash2 = {\n props: { size: { type: [String, Number], default: 24 } },\n render(this: any) {\n return h('svg', { \n width: this.size, \n height: this.size, \n fill: 'none', \n stroke: 'currentColor', \n viewBox: '0 0 24 24' \n }, [\n h('path', { d: 'm3 6 18 0' }),\n h('path', { d: 'm19 6-1 14c0 1-1 2-2 2l-8 0c-1 0-2-1-2-2l-1-14' }),\n h('path', { d: 'm8 6V4c0-1 1-2 2-2h4c1 0 2 1 2 2v2' }),\n h('line', { x1: '10', x2: '10', y1: '11', y2: '17' }),\n h('line', { x1: '14', x2: '14', y1: '11', y2: '17' })\n ])\n }\n}\nimport UiModal from '../ui/UiModal.vue'\nimport StrandsTotpSetupModal from './StrandsTotpSetupModal.vue'\nimport StrandsEmailMfaSetupModal from './StrandsEmailMfaSetupModal.vue'\nimport StrandsHardwareKeySetupModal from './StrandsHardwareKeySetupModal.vue'\nimport StrandsBackupCodesModal from './StrandsBackupCodesModal.vue'\nimport StrandsConfirmModal from './StrandsConfirmModal.vue'\nimport { useStrandsMfa } from '../composables/useStrandsMfa'\nimport type { MfaDevice } from '../../types'\n\ninterface Props {\n show: boolean\n}\n\ninterface Emits {\n (e: 'close'): void\n (e: 'mfa-updated'): void\n}\n\nconst props = defineProps<Props>()\nconst emit = defineEmits<Emits>()\n\n// MFA composable\nconst {\n mfaDevices,\n mfaEnabled,\n loading: mfaLoading,\n activeMfaDevices,\n fetchMfaDevices,\n disableMfaDevice,\n sendEmailMfaCode,\n getDeviceTypeIcon,\n getDeviceTypeName,\n formatLastUsed,\n} = useStrandsMfa()\n\n// Modal states\nconst showModal = computed(() => props.show)\nconst activeTab = ref<'add' | 'manage'>('add')\nconst showTotpSetup = ref(false)\nconst showEmailMfaSetup = ref(false)\nconst showHardwareKeySetup = ref(false)\nconst showPasskeySetup = ref(false)\nconst showBackupCodesModal = ref(false)\nconst showConfirmDisable = ref(false)\nconst selectedDevice = ref<MfaDevice | null>(null)\n\n// Load MFA devices when modal opens\nwatch(() => props.show, async (newShow) => {\n if (newShow) {\n await fetchMfaDevices()\n }\n})\n\nonMounted(async () => {\n if (props.show) {\n await fetchMfaDevices()\n }\n})\n\nconst closeModal = () => {\n emit('close')\n}\n\nconst startTotpSetup = () => {\n showTotpSetup.value = true\n}\n\nconst startEmailMfaSetup = () => {\n showEmailMfaSetup.value = true\n}\n\nconst startHardwareKeySetup = () => {\n showHardwareKeySetup.value = true\n}\n\nconst startPasskeySetup = () => {\n showPasskeySetup.value = true\n}\n\nconst showBackupCodes = (device: MfaDevice) => {\n selectedDevice.value = device\n showBackupCodesModal.value = true\n}\n\nconst testEmailMfa = async (device: MfaDevice) => {\n try {\n await sendEmailMfaCode(device.id)\n // Show success message or toast\n console.log('Test code sent to email')\n } catch (error) {\n console.error('Failed to send test code:', error)\n // Show error message\n }\n}\n\nconst confirmDisableDevice = (device: MfaDevice) => {\n selectedDevice.value = device\n showConfirmDisable.value = true\n}\n\nconst handleDisableDevice = async () => {\n if (selectedDevice.value) {\n try {\n await disableMfaDevice(selectedDevice.value.id)\n showConfirmDisable.value = false\n selectedDevice.value = null\n emit('mfa-updated')\n } catch (error) {\n console.error('Failed to disable MFA device:', error)\n // Show error message\n }\n }\n}\n\nconst handleTotpSetupSuccess = async () => {\n showTotpSetup.value = false\n await fetchMfaDevices()\n activeTab.value = 'manage' // Switch to manage tab after setup\n emit('mfa-updated')\n}\n\nconst handleEmailMfaSetupSuccess = async () => {\n showEmailMfaSetup.value = false\n await fetchMfaDevices()\n activeTab.value = 'manage' // Switch to manage tab after setup\n emit('mfa-updated')\n}\n\nconst handleHardwareKeySetupSuccess = async () => {\n showHardwareKeySetup.value = false\n await fetchMfaDevices()\n activeTab.value = 'manage' // Switch to manage tab after setup\n emit('mfa-updated')\n}\n\nconst handlePasskeySetupSuccess = async () => {\n showPasskeySetup.value = false\n await fetchMfaDevices()\n activeTab.value = 'manage' // Switch to manage tab after setup\n emit('mfa-updated')\n}\n\nconst getDeviceIconBackground = (deviceType: string) => {\n switch (deviceType) {\n case 'totp':\n return 'mfa-device-bg-blue'\n case 'email':\n return 'mfa-device-bg-green'\n case 'hardware':\n return 'mfa-device-bg-purple'\n case 'passkey':\n return 'mfa-device-bg-indigo'\n default:\n return 'mfa-device-bg-gray'\n }\n}\n\nconst getDeviceIconComponent = (deviceType: string) => {\n switch (deviceType) {\n case 'totp':\n return Smartphone\n case 'email':\n return Mail\n case 'hardware':\n return KeyRound\n case 'passkey':\n return Shield\n default:\n return Shield\n }\n}\n</script>\n\n<style scoped>\n/* Modal styles */\n.mfa-modal-card {\n max-width: 56rem;\n}\n\n.mfa-modal-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n}\n\n.mfa-modal-title {\n font-size: 1.5rem;\n font-weight: 700;\n color: #111827;\n}\n\n.mfa-modal-close {\n color: #9ca3af;\n background: none;\n border: none;\n cursor: pointer;\n transition: color 0.2s ease;\n}\n\n.mfa-modal-close:hover {\n color: #4b5563;\n}\n\n.mfa-modal-close-icon {\n width: 1.5rem;\n height: 1.5rem;\n}\n\n/* Loading state */\n.mfa-loading {\n display: flex;\n align-items: center;\n justify-content: center;\n padding: 3rem 0;\n}\n\n.mfa-loading-text {\n margin-left: 0.75rem;\n color: #4b5563;\n}\n\n/* Main content */\n.mfa-content {\n display: flex;\n flex-direction: column;\n gap: 1.5rem;\n}\n\n/* Status overview */\n.mfa-status-overview {\n background-color: #f9fafb;\n border-radius: 0.75rem;\n padding: 1rem;\n}\n\n.mfa-status-content {\n display: flex;\n align-items: center;\n justify-content: space-between;\n}\n\n.mfa-status-title {\n font-weight: 600;\n color: #111827;\n}\n\n.mfa-status-subtitle {\n font-size: 0.875rem;\n color: #4b5563;\n}\n\n.mfa-status-badges {\n display: flex;\n align-items: center;\n}\n\n.mfa-status-badge {\n display: inline-flex;\n align-items: center;\n padding: 0.125rem 0.625rem;\n border-radius: 9999px;\n font-size: 0.75rem;\n font-weight: 500;\n}\n\n.mfa-status-badge-enabled {\n background-color: #dcfce7;\n color: #166534;\n}\n\n.mfa-status-badge-disabled {\n background-color: #f3f4f6;\n color: #4b5563;\n}\n\n.mfa-badge-icon {\n margin-right: 0.25rem;\n}\n\n/* Tab navigation */\n.mfa-tabs-container {\n border-bottom: 1px solid #e5e7eb;\n}\n\n.mfa-tabs-nav {\n margin-bottom: -1px;\n display: flex;\n gap: 2rem;\n}\n\n.mfa-tab-button {\n white-space: nowrap;\n padding: 0.5rem 0.25rem;\n border-bottom: 2px solid transparent;\n font-weight: 500;\n font-size: 0.875rem;\n background: none;\n border-top: none;\n border-left: none;\n border-right: none;\n cursor: pointer;\n transition: all 0.2s ease;\n}\n\n.mfa-tab-button-active {\n border-bottom-color: var(--strands-primary, #EA00A8);\n color: var(--strands-primary, #EA00A8);\n}\n\n.mfa-tab-button-inactive {\n border-bottom-color: transparent;\n color: #6b7280;\n}\n\n.mfa-tab-button-inactive:hover {\n color: #374151;\n border-bottom-color: #d1d5db;\n}\n\n/* Section titles */\n.mfa-section-title {\n font-size: 1.25rem;\n font-weight: 600;\n color: #111827;\n margin-bottom: 1.5rem;\n}\n\n/* Add devices section */\n.mfa-add-devices {\n display: flex;\n flex-direction: column;\n gap: 1.5rem;\n}\n\n.mfa-device-options {\n display: flex;\n flex-direction: column;\n gap: 1rem;\n}\n\n.mfa-device-option {\n padding: 1.5rem;\n background-color: #ffffff;\n border: 1px solid #e5e7eb;\n border-radius: 0.75rem;\n cursor: pointer;\n transition: all 0.2s ease;\n group: hover;\n}\n\n.mfa-device-option:hover {\n border-color: #d1d5db;\n box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1);\n}\n\n.mfa-device-layout {\n display: flex;\n align-items: center;\n justify-content: space-between;\n}\n\n.mfa-device-icon-container {\n flex-shrink: 0;\n width: 3.5rem;\n height: 3.5rem;\n border-radius: 0.75rem;\n display: flex;\n align-items: center;\n justify-content: center;\n transition: background-color 0.2s ease;\n}\n\n.mfa-device-icon-totp {\n background-color: rgba(59, 130, 246, 0.1);\n}\n\n.mfa-device-option:hover .mfa-device-icon-totp {\n background-color: rgba(59, 130, 246, 0.15);\n}\n\n.mfa-device-icon-email {\n background-color: rgba(16, 185, 129, 0.1);\n}\n\n.mfa-device-option:hover .mfa-device-icon-email {\n background-color: rgba(16, 185, 129, 0.15);\n}\n\n.mfa-device-icon {\n color: var(--strands-primary, #EA00A8);\n}\n\n.mfa-device-content {\n display: flex;\n align-items: flex-start;\n gap: 1rem;\n margin-left: 1rem;\n margin-right: 1rem;\n}\n\n.mfa-device-info {\n min-width: 0;\n flex: 1;\n}\n\n.mfa-device-title {\n font-weight: 600;\n color: #111827;\n font-size: 1.125rem;\n}\n\n.mfa-device-description {\n font-size: 0.75rem;\n color: #6b7280;\n margin-top: 0.5rem;\n}\n\n.mfa-device-action {\n display: flex;\n flex-direction: column;\n gap: 0.5rem;\n margin-left: 1rem;\n}\n\n/* Manage devices section */\n.mfa-manage-devices {\n display: flex;\n flex-direction: column;\n gap: 1.5rem;\n}\n\n.mfa-devices-list {\n max-height: 24rem;\n overflow-y: auto;\n display: flex;\n flex-direction: column;\n gap: 1rem;\n padding-right: 0.5rem;\n}\n\n.mfa-device-card {\n padding: 1.5rem;\n background-color: #ffffff;\n border: 1px solid #e5e7eb;\n border-radius: 0.75rem;\n transition: all 0.2s ease;\n}\n\n.mfa-device-card:hover {\n border-color: #d1d5db;\n box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1);\n}\n\n.mfa-device-card-content {\n display: flex;\n align-items: flex-start;\n justify-content: space-between;\n}\n\n.mfa-device-card-info {\n display: flex;\n align-items: flex-start;\n gap: 1rem;\n}\n\n.mfa-device-card-icon-container {\n flex-shrink: 0;\n width: 3.5rem;\n height: 3.5rem;\n border-radius: 0.75rem;\n display: flex;\n align-items: center;\n justify-content: center;\n}\n\n.mfa-device-card-icon {\n color: #4b5563;\n}\n\n.mfa-device-card-details {\n min-width: 0;\n flex: 1;\n}\n\n.mfa-device-card-name {\n font-weight: 600;\n color: #111827;\n font-size: 1.125rem;\n}\n\n.mfa-device-card-type {\n font-size: 0.875rem;\n color: #4b5563;\n margin-top: 0.25rem;\n}\n\n.mfa-device-card-last-used {\n font-size: 0.75rem;\n color: #6b7280;\n margin-top: 0.5rem;\n}\n\n.mfa-device-card-actions {\n display: flex;\n flex-direction: column;\n gap: 0.5rem;\n margin-left: 1rem;\n}\n\n.mfa-button-icon {\n margin-right: 0.5rem;\n}\n\n.mfa-remove-button {\n color: #dc2626;\n border-color: #fecaca;\n}\n\n.mfa-remove-button:hover {\n background-color: #fef2f2;\n color: #b91c1c;\n}\n\n/* Device type background colors */\n.mfa-device-bg-blue {\n background-color: #eff6ff;\n}\n\n.mfa-device-card:hover .mfa-device-bg-blue {\n background-color: #dbeafe;\n}\n\n.mfa-device-bg-green {\n background-color: #f0fdf4;\n}\n\n.mfa-device-card:hover .mfa-device-bg-green {\n background-color: #dcfce7;\n}\n\n.mfa-device-bg-purple {\n background-color: #faf5ff;\n}\n\n.mfa-device-card:hover .mfa-device-bg-purple {\n background-color: #f3e8ff;\n}\n\n.mfa-device-bg-indigo {\n background-color: #eef2ff;\n}\n\n.mfa-device-card:hover .mfa-device-bg-indigo {\n background-color: #e0e7ff;\n}\n\n.mfa-device-bg-gray {\n background-color: #f9fafb;\n}\n\n.mfa-device-card:hover .mfa-device-bg-gray {\n background-color: #f3f4f6;\n}\n\n/* Responsive design */\n@media (max-width: 768px) {\n .mfa-device-layout {\n flex-direction: column;\n align-items: flex-start;\n gap: 1rem;\n }\n\n .mfa-device-content {\n margin-left: 0;\n margin-right: 0;\n width: 100%;\n }\n\n .mfa-device-action {\n margin-left: 0;\n width: 100%;\n }\n\n .mfa-device-card-content {\n flex-direction: column;\n gap: 1rem;\n }\n\n .mfa-device-card-actions {\n margin-left: 0;\n width: 100%;\n }\n}\n\n</style>\n","<template>\n <div class=\"accui-component-scope\">\n <UiModal :open=\"true\" @close=\"$emit('close')\" card-class=\"max-w-lg\">\n <template #header>\n <div class=\"settings-header\">\n <h2 class=\"settings-title\">Settings</h2>\n <button \n class=\"settings-close-button\"\n @click=\"$emit('close')\"\n type=\"button\"\n >\n <svg class=\"settings-close-icon\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M6 18L18 6M6 6l12 12\" />\n </svg>\n </button>\n </div>\n </template>\n\n <!-- Audio Preferences Section -->\n <div class=\"settings-content\">\n <div class=\"settings-section\">\n <h3 class=\"settings-section-title\">Audio Preferences</h3>\n \n <!-- Level Up Sounds Toggle -->\n <div class=\"settings-option\">\n <div class=\"settings-option-content\">\n <div class=\"settings-option-info\">\n <label for=\"level-up-sounds\" class=\"settings-option-label\">\n Level Up Sounds\n </label>\n <p class=\"settings-option-description\">\n Play sound effects when you level up\n </p>\n </div>\n <UiToggle\n id=\"level-up-sounds\"\n v-model=\"localSettings.levelUpSounds\"\n @update:model-value=\"updateSetting('levelUpSounds', $event)\"\n />\n </div>\n </div>\n\n <!-- Milestone Level Up Sounds Toggle -->\n <div class=\"settings-option\">\n <div class=\"settings-option-content\">\n <div class=\"settings-option-info\">\n <label for=\"milestone-sounds\" class=\"settings-option-label\">\n Milestone Level Sounds\n </label>\n <p class=\"settings-option-description\">\n Play special celebration sounds for milestone levels (10, 25, 50, 100, 150, 200)\n </p>\n </div>\n <UiToggle\n id=\"milestone-sounds\"\n v-model=\"localSettings.milestoneSounds\"\n @update:model-value=\"updateSetting('milestoneSounds', $event)\"\n />\n </div>\n </div>\n </div>\n </div>\n\n <template #footer>\n <div class=\"settings-footer\">\n <UiButton \n variant=\"secondary\" \n @click=\"$emit('close')\"\n >\n Close\n </UiButton>\n <UiButton \n variant=\"primary\" \n @click=\"saveSettings\"\n :loading=\"saving\"\n >\n {{ saving ? 'Saving...' : 'Save Settings' }}\n </UiButton>\n </div>\n </template>\n </UiModal>\n </div>\n</template>\n\n<script setup lang=\"ts\">\nimport { ref, reactive, watch } from 'vue'\nimport { useStrandsAuth } from '../composables/useStrandsAuth'\nimport UiButton from '../ui/UiButton.vue'\nimport UiToggle from '../ui/UiToggle.vue'\nimport UiModal from '../ui/UiModal.vue'\n\ninterface AudioSettings {\n levelUpSounds: boolean\n milestoneSounds: boolean\n}\n\ninterface Props {\n open?: boolean\n}\n\ninterface Emits {\n (e: 'close'): void\n (e: 'settings-updated', settings: AudioSettings): void\n}\n\nconst props = withDefaults(defineProps<Props>(), {\n open: false\n})\n\nconst emit = defineEmits<Emits>()\n\nconst { currentUser, updateUserSettings } = useStrandsAuth()\nconst saving = ref(false)\n\n// Initialize local settings from user settings or defaults\nconst localSettings = reactive<AudioSettings>({\n levelUpSounds: currentUser.value?.settings?.levelUpSounds ?? true,\n milestoneSounds: currentUser.value?.settings?.milestoneSounds ?? true\n})\n\n// Watch for changes in user settings\nwatch(() => currentUser.value?.settings, (newSettings) => {\n if (newSettings) {\n localSettings.levelUpSounds = newSettings.levelUpSounds ?? true\n localSettings.milestoneSounds = newSettings.milestoneSounds ?? true\n }\n}, { deep: true })\n\nconst handleOverlayClick = () => {\n emit('close')\n}\n\nconst updateSetting = (key: keyof AudioSettings, value: boolean) => {\n localSettings[key] = value\n}\n\nconst saveSettings = async () => {\n if (saving.value) return\n \n saving.value = true\n \n try {\n // Update settings on server\n await updateUserSettings({\n ...currentUser.value?.settings,\n ...localSettings\n })\n \n // Emit updated settings to parent\n emit('settings-updated', { ...localSettings })\n \n // Close modal\n emit('close')\n } catch (error) {\n console.error('Failed to save settings:', error)\n // TODO: Show error message to user\n } finally {\n saving.value = false\n }\n}\n</script>\n\n<style scoped>\n.settings-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n}\n\n.settings-title {\n font-size: 1.25rem;\n font-weight: 700;\n color: #111827;\n}\n\n.settings-close-button {\n color: #9ca3af;\n background: none;\n border: none;\n padding: 0;\n cursor: pointer;\n transition: color 0.2s ease;\n}\n\n.settings-close-button:hover {\n color: #6b7280;\n}\n\n.settings-close-icon {\n width: 1.5rem;\n height: 1.5rem;\n}\n\n.settings-content {\n display: flex;\n flex-direction: column;\n gap: 1.5rem;\n}\n\n.settings-section {\n /* Section container */\n}\n\n.settings-section-title {\n font-size: 1.125rem;\n font-weight: 600;\n color: #111827;\n margin-bottom: 1rem;\n}\n\n.settings-option {\n background-color: #f9fafb;\n border: 1px solid #e5e7eb;\n border-radius: 0.5rem;\n padding: 1rem;\n margin-bottom: 1rem;\n}\n\n.settings-option:last-child {\n margin-bottom: 0;\n}\n\n.settings-option-content {\n display: flex;\n align-items: center;\n justify-content: space-between;\n}\n\n.settings-option-info {\n flex: 1;\n}\n\n.settings-option-label {\n display: block;\n font-size: 0.875rem;\n font-weight: 500;\n color: #111827;\n margin-bottom: 0.25rem;\n}\n\n.settings-option-description {\n font-size: 0.75rem;\n color: #6b7280;\n}\n\n.settings-footer {\n display: flex;\n justify-content: flex-end;\n gap: 0.75rem;\n}\n\n/* Override Tailwind classes with CSS properties */\n.max-w-lg {\n max-width: 32rem;\n}\n</style>\n\n","<template>\n <StrandsUiModal \n :open=\"visible\" \n @close=\"handleClose\"\n >\n <template #header>\n <div class=\"modal-header-content\">\n <h2 class=\"modal-title\">Active Sessions</h2>\n <p class=\"modal-subtitle\">Manage your {{ sessions.length }} active device{{ sessions.length !== 1 ? 's' : '' }}</p>\n </div>\n </template>\n \n <div class=\"strands-sessions-modal\">\n <!-- Loading State -->\n <div v-if=\"loading\" class=\"sessions-loading\">\n <StrandsUiLoader :size=\"40\" />\n <p class=\"loading-text\">Loading sessions...</p>\n </div>\n\n <!-- Empty State -->\n <div v-else-if=\"sessions.length === 0\" class=\"sessions-empty\">\n <div class=\"empty-icon\">\n <svg width=\"48\" height=\"48\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.5\">\n <rect x=\"2\" y=\"4\" width=\"20\" height=\"16\" rx=\"2\" />\n <line x1=\"8\" y1=\"10\" x2=\"16\" y2=\"10\" />\n <line x1=\"8\" y1=\"14\" x2=\"12\" y2=\"14\" />\n </svg>\n </div>\n <h3 class=\"empty-title\">No Active Sessions</h3>\n <p class=\"empty-description\">You don't have any active sessions at the moment.</p>\n </div>\n\n <!-- Sessions List -->\n <div v-else class=\"sessions-container\">\n <!-- Session Statistics -->\n <div v-if=\"stats\" class=\"session-stats\">\n <div class=\"stat-card\">\n <span class=\"stat-label\">Total Sessions</span>\n <span class=\"stat-value\">{{ stats.total_sessions }}</span>\n </div>\n <div class=\"stat-card\">\n <span class=\"stat-label\">Active Devices</span>\n <span class=\"stat-value\">{{ stats.active_sessions }}</span>\n </div>\n <div v-if=\"stats.unique_locations && stats.unique_locations.length > 0\" class=\"stat-card\">\n <span class=\"stat-label\">Locations</span>\n <span class=\"stat-value\">{{ stats.unique_locations.length }}</span>\n </div>\n </div>\n\n <!-- Sessions List -->\n <div class=\"sessions-list\">\n <div\n v-for=\"session in sessions\"\n :key=\"session.id\"\n class=\"session-card\"\n :class=\"{ 'current-session': session.is_current }\"\n >\n <!-- Session Header -->\n <div class=\"session-header\">\n <div class=\"session-device\">\n <div class=\"device-icon\">\n <component \n :is=\"getDeviceIcon(session.device_type)\" \n :size=\"20\"\n />\n </div>\n <div class=\"device-info\">\n <h4 class=\"device-name\">\n {{ session.device_name || 'Unknown Device' }}\n <span v-if=\"session.is_current\" class=\"current-badge\">Current</span>\n </h4>\n <p class=\"device-type\">{{ session.device_type || 'Unknown type' }}</p>\n </div>\n </div>\n \n <StrandsUiButton\n v-if=\"session.is_current\"\n variant=\"outline\"\n size=\"sm\"\n @click=\"handleRevokeCurrentSession(session.id)\"\n :disabled=\"revokingSession === session.id\"\n class=\"current-session-button\"\n >\n <StrandsUiLoader v-if=\"revokingSession === session.id\" :size=\"16\" />\n <span v-else>Sign Out</span>\n </StrandsUiButton>\n \n <StrandsUiButton\n v-else\n variant=\"outline\"\n size=\"sm\"\n @click=\"handleRevokeSession(session.id)\"\n :disabled=\"revokingSession === session.id\"\n >\n <StrandsUiLoader v-if=\"revokingSession === session.id\" :size=\"16\" />\n <span v-else>End Session</span>\n </StrandsUiButton>\n </div>\n\n <!-- Session Details -->\n <div class=\"session-details\">\n <div class=\"detail-row\">\n <span class=\"detail-icon\">\n <MapPin :size=\"14\" />\n </span>\n <span class=\"detail-text\">\n <template v-if=\"session.city && session.country\">\n {{ session.city }}, {{ session.country }}\n </template>\n <template v-else-if=\"session.country\">\n {{ session.country }}\n </template>\n <template v-else>\n Location unknown\n </template>\n </span>\n </div>\n\n <div v-if=\"session.ip_address\" class=\"detail-row\">\n <span class=\"detail-icon\">\n <Globe :size=\"14\" />\n </span>\n <span class=\"detail-text\">{{ session.ip_address }}</span>\n </div>\n\n <div class=\"detail-row\">\n <span class=\"detail-icon\">\n <Clock :size=\"14\" />\n </span>\n <span class=\"detail-text\">\n Last active {{ formatTimeAgo(session.last_activity_at || session.created_at) }}\n </span>\n </div>\n\n <div class=\"detail-row\">\n <span class=\"detail-icon\">\n <Calendar :size=\"14\" />\n </span>\n <span class=\"detail-text\">\n Started {{ formatDate(session.created_at) }}\n </span>\n </div>\n </div>\n </div>\n </div>\n\n <!-- Bulk Actions -->\n <div v-if=\"sessions.length > 1\" class=\"bulk-actions\">\n <StrandsUiButton\n variant=\"outline\"\n @click=\"handleRevokeAllOther\"\n :disabled=\"revokingAll\"\n >\n <StrandsUiLoader v-if=\"revokingAll\" :size=\"16\" />\n <span v-else>End All Other Sessions</span>\n </StrandsUiButton>\n <p class=\"bulk-actions-hint\">\n This will sign you out on all other devices\n </p>\n </div>\n </div>\n </div>\n </StrandsUiModal>\n</template>\n\n<script setup lang=\"ts\">\nimport { ref, watch } from 'vue'\nimport { StrandsUiModal, StrandsUiButton, StrandsUiLoader } from '../ui'\nimport { useStrandsAuth } from '../composables/useStrandsAuth'\nimport type { SessionInfo, SessionStats } from '../../types'\n\n// Inline SVG icon components using render functions (no runtime compilation needed)\nimport { h } from 'vue'\n\nconst Monitor = {\n props: ['size'],\n render(this: any) {\n return h('svg', { \n width: this.size, \n height: this.size, \n fill: 'none', \n stroke: 'currentColor', \n viewBox: '0 0 24 24' \n }, [\n h('rect', { x: '2', y: '7', width: '20', height: '10', rx: '2', ry: '2' }),\n h('line', { x1: '8', y1: '21', x2: '16', y2: '21' }),\n h('line', { x1: '12', y1: '17', x2: '12', y2: '21' })\n ])\n }\n}\n\nconst Smartphone = {\n props: ['size'],\n render(this: any) {\n return h('svg', { \n width: this.size, \n height: this.size, \n fill: 'none', \n stroke: 'currentColor', \n viewBox: '0 0 24 24' \n }, [\n h('rect', { x: '5', y: '2', width: '14', height: '20', rx: '2', ry: '2' }),\n h('line', { x1: '12', y1: '18', x2: '12.01', y2: '18' })\n ])\n }\n}\n\nconst Tablet = {\n props: ['size'],\n render(this: any) {\n return h('svg', { \n width: this.size, \n height: this.size, \n fill: 'none', \n stroke: 'currentColor', \n viewBox: '0 0 24 24' \n }, [\n h('rect', { x: '4', y: '2', width: '16', height: '20', rx: '2', ry: '2' }),\n h('line', { x1: '12', y1: '18', x2: '12.01', y2: '18' })\n ])\n }\n}\n\nconst MapPin = {\n props: ['size'],\n render(this: any) {\n return h('svg', { \n width: this.size, \n height: this.size, \n fill: 'none', \n stroke: 'currentColor', \n viewBox: '0 0 24 24' \n }, [\n h('path', { d: 'M21 10c0 7-9 13-9 13s-9-6-9-13a9 9 0 0118 0z' }),\n h('circle', { cx: '12', cy: '10', r: '3' })\n ])\n }\n}\n\nconst Globe = {\n props: ['size'],\n render(this: any) {\n return h('svg', { \n width: this.size, \n height: this.size, \n fill: 'none', \n stroke: 'currentColor', \n viewBox: '0 0 24 24' \n }, [\n h('circle', { cx: '12', cy: '12', r: '10' }),\n h('line', { x1: '2', y1: '12', x2: '22', y2: '12' }),\n h('path', { d: 'M12 2a15.3 15.3 0 014 10 15.3 15.3 0 01-4 10 15.3 15.3 0 01-4-10 15.3 15.3 0 014-10z' })\n ])\n }\n}\n\nconst Clock = {\n props: ['size'],\n render(this: any) {\n return h('svg', { \n width: this.size, \n height: this.size, \n fill: 'none', \n stroke: 'currentColor', \n viewBox: '0 0 24 24' \n }, [\n h('circle', { cx: '12', cy: '12', r: '10' }),\n h('polyline', { points: '12 6 12 12 16 14' })\n ])\n }\n}\n\nconst Calendar = {\n props: ['size'],\n render(this: any) {\n return h('svg', { \n width: this.size, \n height: this.size, \n fill: 'none', \n stroke: 'currentColor', \n viewBox: '0 0 24 24' \n }, [\n h('rect', { x: '3', y: '4', width: '18', height: '18', rx: '2', ry: '2' }),\n h('line', { x1: '16', y1: '2', x2: '16', y2: '6' }),\n h('line', { x1: '8', y1: '2', x2: '8', y2: '6' }),\n h('line', { x1: '3', y1: '10', x2: '21', y2: '10' })\n ])\n }\n}\n\ninterface Props {\n modelValue: boolean\n}\n\ninterface Emits {\n (e: 'update:modelValue', value: boolean): void\n (e: 'sessionsUpdated'): void\n (e: 'currentSessionRevoked'): void\n}\n\nconst props = defineProps<Props>()\nconst emit = defineEmits<Emits>()\n\n// Auth composable\nconst { getUserSessions, getSessionStats, revokeSession, revokeAllOtherSessions, signOut } = useStrandsAuth()\n\n// State\nconst visible = ref(props.modelValue)\nconst loading = ref(false)\nconst sessions = ref<SessionInfo[]>([])\nconst stats = ref<SessionStats | null>(null)\nconst revokingSession = ref<string | null>(null)\nconst revokingAll = ref(false)\nconst error = ref<string | null>(null)\n\n// Watch for prop changes\nwatch(() => props.modelValue, (newVal) => {\n visible.value = newVal\n if (newVal) {\n loadSessions()\n }\n})\n\n// Load sessions and stats\nconst loadSessions = async () => {\n loading.value = true\n error.value = null\n \n try {\n const [sessionsData, statsData] = await Promise.all([\n getUserSessions(),\n getSessionStats()\n ])\n \n sessions.value = sessionsData || []\n stats.value = statsData || null\n } catch (err) {\n console.error('Failed to load sessions:', err)\n error.value = 'Failed to load sessions. Please try again.'\n sessions.value = []\n } finally {\n loading.value = false\n }\n}\n\n// Handle closing the modal\nconst handleClose = () => {\n visible.value = false\n emit('update:modelValue', false)\n}\n\n// Revoke a single session\nconst handleRevokeSession = async (sessionId: string) => {\n if (!confirm('Are you sure you want to end this session? The device will be signed out.')) {\n return\n }\n \n revokingSession.value = sessionId\n \n try {\n await revokeSession(sessionId)\n await loadSessions() // Reload the list\n emit('sessionsUpdated')\n } catch (err) {\n console.error('Failed to revoke session:', err)\n alert('Failed to end session. Please try again.')\n } finally {\n revokingSession.value = null\n }\n}\n\n// Revoke all other sessions\nconst handleRevokeAllOther = async () => {\n if (!confirm('Are you sure you want to end all other sessions? You will be signed out on all other devices.')) {\n return\n }\n \n revokingAll.value = true\n \n try {\n await revokeAllOtherSessions()\n await loadSessions() // Reload the list\n emit('sessionsUpdated')\n } catch (err) {\n console.error('Failed to revoke sessions:', err)\n alert('Failed to end sessions. Please try again.')\n } finally {\n revokingAll.value = false\n }\n}\n\n// Revoke current session (signs user out)\nconst handleRevokeCurrentSession = async (sessionId: string) => {\n if (!confirm('Are you sure you want to sign out? You will need to sign in again to access your account.')) {\n return\n }\n \n revokingSession.value = sessionId\n \n try {\n // First revoke the session\n await revokeSession(sessionId)\n \n // Then sign out the user (clears local state and tokens)\n await signOut()\n \n // Close the modal\n visible.value = false\n emit('update:modelValue', false)\n emit('sessionsUpdated')\n \n // Optionally emit a special event for current session revocation\n emit('currentSessionRevoked')\n } catch (err) {\n console.error('Failed to revoke current session:', err)\n alert('Failed to sign out. Please try again.')\n } finally {\n revokingSession.value = null\n }\n}\n\n// Get device icon based on type\nconst getDeviceIcon = (deviceType?: string) => {\n switch(deviceType?.toLowerCase()) {\n case 'mobile':\n return Smartphone\n case 'tablet':\n return Tablet\n default:\n return Monitor\n }\n}\n\n// Format time ago\nconst formatTimeAgo = (date: string | Date) => {\n if (!date) return 'Unknown'\n \n const now = new Date()\n const then = new Date(date)\n const seconds = Math.floor((now.getTime() - then.getTime()) / 1000)\n \n if (seconds < 60) return 'just now'\n if (seconds < 3600) return `${Math.floor(seconds / 60)} minutes ago`\n if (seconds < 86400) return `${Math.floor(seconds / 3600)} hours ago`\n if (seconds < 604800) return `${Math.floor(seconds / 86400)} days ago`\n return then.toLocaleDateString()\n}\n\n// Format date\nconst formatDate = (date: string | Date) => {\n if (!date) return 'Unknown'\n return new Date(date).toLocaleDateString('en-US', {\n month: 'short',\n day: 'numeric',\n year: 'numeric',\n hour: '2-digit',\n minute: '2-digit'\n })\n}\n\n// Load sessions on mount if visible\nif (visible.value) {\n loadSessions()\n}\n</script>\n\n<style scoped>\n/* Modal Header */\n.modal-header-content {\n text-align: center;\n}\n\n.modal-title {\n font-size: 1.25rem;\n font-weight: 600;\n color: #111827;\n margin: 0 0 0.5rem 0;\n}\n\n.modal-subtitle {\n font-size: 0.875rem;\n color: #6b7280;\n margin: 0;\n}\n\n.strands-sessions-modal {\n max-width: 42rem;\n min-width: 32rem;\n}\n\n/* Loading State */\n.sessions-loading {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n padding: 3rem;\n gap: 1rem;\n}\n\n.loading-text {\n color: #6b7280;\n font-size: 0.875rem;\n}\n\n/* Empty State */\n.sessions-empty {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n padding: 3rem;\n text-align: center;\n}\n\n.empty-icon {\n color: #d1d5db;\n margin-bottom: 1rem;\n}\n\n.empty-title {\n font-size: 1.125rem;\n font-weight: 600;\n color: #111827;\n margin-bottom: 0.5rem;\n}\n\n.empty-description {\n color: #6b7280;\n font-size: 0.875rem;\n}\n\n/* Session Statistics */\n.session-stats {\n display: grid;\n grid-template-columns: repeat(auto-fit, minmax(120px, 1fr));\n gap: 1rem;\n margin-bottom: 1.5rem;\n padding: 1rem;\n background-color: #f9fafb;\n border-radius: 0.5rem;\n}\n\n.stat-card {\n display: flex;\n flex-direction: column;\n gap: 0.25rem;\n}\n\n.stat-label {\n font-size: 0.75rem;\n color: #6b7280;\n text-transform: uppercase;\n letter-spacing: 0.05em;\n}\n\n.stat-value {\n font-size: 1.5rem;\n font-weight: 600;\n color: #111827;\n}\n\n/* Sessions List */\n.sessions-list {\n display: flex;\n flex-direction: column;\n gap: 1rem;\n}\n\n.session-card {\n padding: 1rem;\n border: 1px solid #e5e7eb;\n border-radius: 0.5rem;\n background: white;\n transition: all 0.15s ease;\n}\n\n.session-card:hover {\n border-color: #d1d5db;\n box-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.1);\n}\n\n.session-card.current-session {\n border-color: #a7f3d0;\n background-color: #f0fdf9;\n}\n\n/* Session Header */\n.session-header {\n display: flex;\n justify-content: space-between;\n align-items: flex-start;\n margin-bottom: 0.75rem;\n}\n\n.session-device {\n display: flex;\n gap: 0.75rem;\n align-items: flex-start;\n flex: 1;\n}\n\n.device-icon {\n padding: 0.5rem;\n background-color: #f3f4f6;\n border-radius: 0.375rem;\n color: #6b7280;\n}\n\n.current-session .device-icon {\n background-color: #dcfce7;\n color: #16a34a;\n}\n\n.device-info {\n flex: 1;\n}\n\n.device-name {\n font-size: 0.875rem;\n font-weight: 600;\n color: #111827;\n display: flex;\n align-items: center;\n gap: 0.5rem;\n}\n\n.current-badge {\n display: inline-flex;\n align-items: center;\n padding: 0.125rem 0.5rem;\n background-color: #dcfce7;\n color: #15803d;\n font-size: 0.75rem;\n font-weight: 500;\n border-radius: 9999px;\n border: 1px solid #bbf7d0;\n}\n\n.device-type {\n font-size: 0.75rem;\n color: #6b7280;\n margin-top: 0.125rem;\n text-transform: capitalize;\n}\n\n/* Session Details */\n.session-details {\n display: flex;\n flex-direction: column;\n gap: 0.5rem;\n padding-left: 3rem;\n}\n\n.detail-row {\n display: flex;\n align-items: center;\n gap: 0.5rem;\n font-size: 0.8125rem;\n color: #6b7280;\n}\n\n.detail-icon {\n display: flex;\n align-items: center;\n color: #9ca3af;\n}\n\n.detail-text {\n flex: 1;\n}\n\n/* Bulk Actions */\n.bulk-actions {\n margin-top: 1.5rem;\n padding-top: 1.5rem;\n border-top: 1px solid #e5e7eb;\n display: flex;\n flex-direction: column;\n align-items: center;\n gap: 0.5rem;\n}\n\n.bulk-actions-hint {\n font-size: 0.75rem;\n color: #6b7280;\n text-align: center;\n}\n\n/* Responsive */\n@media (max-width: 640px) {\n .strands-sessions-modal {\n min-width: unset;\n width: 100%;\n }\n \n .session-stats {\n grid-template-columns: 1fr 1fr;\n }\n \n .session-details {\n padding-left: 0;\n margin-top: 0.75rem;\n padding-top: 0.75rem;\n border-top: 1px solid #f3f4f6;\n }\n}\n\n/* Current Session Button Styling */\n.current-session-button {\n border-color: #dc2626 !important;\n color: #dc2626 !important;\n}\n\n.current-session-button:hover {\n background-color: #dc2626 !important;\n color: white !important;\n}\n</style>","<template>\n <div class=\"accui-component-scope\">\n <div :class=\"inModal ? 'profile-container-modal profile-container-width' : 'profile-container profile-container-width profile-max-width profile-centered profile-animated'\">\n <div :class=\"inModal ? 'profile-content-modal profile-content-layout' : 'profile-content profile-card-modern profile-content-layout'\">\n <!-- Header -->\n <div class=\"profile-header\">\n <h1 class=\"profile-title\">Profile Settings</h1>\n <p class=\"profile-subtitle\">Manage your account information and preferences</p>\n </div>\n\n <!-- Profile Image Section -->\n <div class=\"profile-image-section\">\n <div class=\"profile-image-container\">\n <!-- Progress Ring Container -->\n <div class=\"profile-image-wrapper\">\n <!-- Progress Ring SVG -->\n <StrandsUiLevelProgress\n :size=\"140\" \n :value=\"currentUser?.xp || 0\" \n :max=\"currentUser?.next_level_xp || 1\" \n :level=\"currentUser?.level || 0\" \n :level-label=\"`LEVEL ${currentUser?.level || 0}`\"\n :user-settings=\"currentUser?.settings\"\n class=\"profile-progress-ring\" \n />\n\n <!-- Avatar -->\n <div \n v-if=\"currentUser?.avatar\"\n class=\"profile-avatar profile-avatar-with-image\"\n >\n <img \n :src=\"currentUser.avatar\" \n :alt=\"`${currentUser.firstName} ${currentUser.lastName}`\"\n class=\"profile-avatar-image\"\n />\n </div>\n <div \n v-else\n class=\"profile-avatar profile-avatar-initials\"\n >\n {{ getInitials(currentUser?.firstName, currentUser?.lastName) }}\n </div>\n \n <!-- Upload Overlay -->\n <button\n class=\"profile-upload-overlay\"\n @click=\"triggerAvatarUpload\"\n :disabled=\"uploading\"\n >\n <StrandsUiLoader v-if=\"uploading\" :size=\"24\" variant=\"dark\" />\n <svg v-else class=\"profile-upload-icon\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M3 9a2 2 0 012-2h.93a2 2 0 001.664-.89l.812-1.22A2 2 0 0110.07 4h3.86a2 2 0 011.664.89l.812 1.22A2 2 0 0018.07 7H19a2 2 0 012 2v9a2 2 0 01-2 2H5a2 2 0 01-2-2V9z\" />\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M15 13a3 3 0 11-6 0 3 3 0 616 0z\" />\n </svg>\n </button>\n </div>\n </div>\n \n <!-- Hidden file input for avatar selection -->\n <input\n ref=\"avatarFileInput\"\n type=\"file\"\n accept=\"image/*\"\n class=\"profile-file-input\"\n @change=\"handleAvatarFileSelect\"\n />\n </div>\n\n <!-- Profile Form -->\n <form @submit.prevent=\"handleUpdateProfile\" class=\"profile-form\">\n <div class=\"profile-form-grid\">\n <!-- Personal Information -->\n <div class=\"profile-section\">\n <h3 class=\"profile-section-title\">Personal Information</h3>\n \n <StrandsUiInput\n id=\"firstName\"\n v-model=\"form.firstName\"\n type=\"text\"\n label=\"First name\"\n placeholder=\"Enter your first name\"\n autocomplete=\"given-name\"\n :disabled=\"loading || fetchingProfile\"\n :error=\"errors.firstName\"\n />\n\n <StrandsUiInput\n id=\"lastName\"\n v-model=\"form.lastName\"\n type=\"text\"\n label=\"Last name\"\n placeholder=\"Enter your last name\"\n autocomplete=\"family-name\"\n :disabled=\"loading || fetchingProfile\"\n :error=\"errors.lastName\"\n />\n\n <!-- Email Change Section -->\n <div class=\"profile-setting-card\">\n <div class=\"profile-setting-header\">\n <div>\n <h4 class=\"profile-setting-title\">Email Address</h4>\n <p class=\"profile-setting-subtitle\">{{ currentUser?.email }}</p>\n </div>\n <StrandsUiButton\n variant=\"secondary\"\n size=\"sm\"\n @click=\"showEmailChange = !showEmailChange\"\n >\n {{ showEmailChange ? 'Cancel' : 'Change' }}\n </StrandsUiButton>\n </div>\n\n <Transition name=\"expand\">\n <div v-if=\"showEmailChange\" class=\"profile-change-form\">\n <StrandsUiInput\n v-model=\"emailChangeForm.newEmail\"\n type=\"email\"\n placeholder=\"New email address\"\n autocomplete=\"email\"\n :error=\"emailChangeForm.errors.newEmail\"\n />\n <StrandsUiInput\n v-model=\"emailChangeForm.password\"\n type=\"password\"\n placeholder=\"Current password\"\n autocomplete=\"current-password\"\n :error=\"emailChangeForm.errors.password\"\n />\n <StrandsUiButton\n variant=\"primary\"\n size=\"sm\"\n @click=\"handleEmailChange\"\n :disabled=\"!isEmailChangeFormValid || emailChangeLoading\"\n >\n {{ emailChangeLoading ? 'Updating...' : 'Update Email' }}\n </StrandsUiButton>\n </div>\n </Transition>\n </div>\n\n <!-- Username Change Section -->\n <div class=\"profile-field-section\">\n <div class=\"profile-field-header\">\n <div>\n <h4 class=\"profile-field-title\">Username</h4>\n <p class=\"profile-field-subtitle\">\n {{ currentUser?.username || 'No username set' }}\n </p>\n </div>\n <StrandsUiButton\n variant=\"secondary\"\n size=\"sm\"\n :disabled=\"!usernameChangeData.canChange || usernameChangeLoading\"\n @click=\"handleToggleUsernameChange\"\n >\n {{\n usernameChangeData.cooldownEnd\n ? `Wait ${usernameChangeData.daysRemaining} day${usernameChangeData.daysRemaining === 1 ? '' : 's'} to change`\n : showUsernameChange\n ? 'Cancel'\n : (currentUser?.username\n ? 'Change'\n : 'Set Username')\n }}\n </StrandsUiButton>\n </div>\n\n <Transition name=\"expand\">\n <div v-if=\"showUsernameChange\" class=\"profile-change-form\">\n <StrandsUiInput\n v-model=\"usernameForm.username\"\n type=\"text\"\n placeholder=\"Enter username (3-30 characters)\"\n autocomplete=\"username\"\n :error=\"usernameForm.errors.username\"\n />\n <div v-if=\"usernameAvailability.message\" class=\"profile-availability-message\" :class=\"usernameAvailability.available ? 'success' : 'error'\">\n {{ usernameAvailability.message }}\n </div>\n <StrandsUiButton\n variant=\"primary\"\n size=\"sm\"\n @click=\"handleUsernameChange\"\n :disabled=\"!isUsernameChangeFormValid || usernameChangeLoading\"\n >\n {{ usernameChangeLoading ? 'Updating...' : 'Update Username' }}\n </StrandsUiButton>\n </div>\n </Transition>\n </div>\n </div>\n\n <!-- Security Settings -->\n <div class=\"profile-password-section\">\n <h3 class=\"profile-section-title\">Security Settings</h3>\n \n <!-- Password Change -->\n <div class=\"profile-field-section\">\n <div class=\"profile-field-header\">\n <div>\n <h4 class=\"profile-field-title\">Password</h4>\n <p class=\"profile-field-subtitle\">Last updated {{ passwordLastUpdated }}</p>\n </div>\n <StrandsUiButton\n variant=\"secondary\"\n size=\"sm\"\n @click=\"showPasswordChange = !showPasswordChange\"\n >\n {{ showPasswordChange ? 'Cancel' : 'Change' }}\n </StrandsUiButton>\n </div>\n\n <Transition name=\"expand\">\n <div v-if=\"showPasswordChange\" class=\"profile-change-form\">\n <StrandsUiInput\n v-model=\"passwordForm.current\"\n type=\"password\"\n placeholder=\"Current password\"\n autocomplete=\"current-password\"\n />\n <StrandsUiInput\n v-model=\"passwordForm.new\"\n type=\"password\"\n placeholder=\"New password\"\n autocomplete=\"new-password\"\n />\n <StrandsUiInput\n v-model=\"passwordForm.confirm\"\n type=\"password\"\n placeholder=\"Confirm new password\"\n autocomplete=\"new-password\"\n />\n <StrandsUiButton\n variant=\"primary\"\n size=\"sm\"\n @click=\"handlePasswordChange\"\n :disabled=\"!isPasswordFormValid\"\n >\n Update Password\n </StrandsUiButton>\n </div>\n </Transition>\n </div>\n\n <!-- Two-Factor Authentication -->\n <div class=\"profile-field-section\">\n <div class=\"profile-field-header profile-field-header-vertical\">\n <div class=\"profile-mfa-content\">\n <div>\n <h4 class=\"profile-field-title\">Two-Factor Authentication</h4>\n <p class=\"profile-field-subtitle\">\n {{ currentUser?.mfaEnabled ? 'Enabled' : 'Add extra security to your account' }}\n </p>\n </div>\n \n <!-- Device Type Chips -->\n <div v-if=\"mfaDeviceChips.length > 0\" class=\"profile-mfa-chips\">\n <div\n v-for=\"chip in mfaDeviceChips\"\n :key=\"chip.type\"\n :class=\"[\n 'mfa-device-chip',\n chip.color\n ]\"\n >\n <component :is=\"chip.icon\" :size=\"12\" />\n <span>{{ chip.count }}</span>\n <span>{{ chip.label }}</span>\n </div>\n </div>\n </div>\n <StrandsUiButton\n :variant=\"currentUser?.mfaEnabled ? 'secondary' : 'primary'\"\n size=\"sm\"\n @click=\"showMfaModal = true\"\n class=\"profile-toggle-container\"\n >\n {{ currentUser?.mfaEnabled ? 'Manage' : 'Setup' }}\n </StrandsUiButton>\n </div>\n </div>\n\n <!-- Active Sessions -->\n <div class=\"profile-field-section\">\n <div class=\"profile-field-header\">\n <div>\n <h4 class=\"profile-field-title\">Active Sessions</h4>\n <p class=\"profile-field-subtitle\">\n <span v-if=\"loadingSessions\">Loading sessions...</span>\n <span v-else>{{ activeSessions.length }} active device{{ activeSessions.length !== 1 ? 's' : '' }}</span>\n </p>\n </div>\n <div class=\"profile-field-actions\">\n <StrandsUiButton\n variant=\"secondary\"\n size=\"sm\"\n @click=\"showSessionsModal = true\"\n :disabled=\"loadingSessions\"\n >\n Manage\n </StrandsUiButton>\n </div>\n </div>\n </div>\n </div>\n </div>\n\n <!-- Action Buttons - Only show when changes are made -->\n <div v-if=\"hasChanges\" class=\"profile-actions-section\">\n <StrandsUiButton\n type=\"submit\"\n variant=\"primary\"\n :disabled=\"loading\"\n :loading=\"loading\"\n >\n {{ loading ? 'Saving changes...' : 'Save changes' }}\n </StrandsUiButton>\n\n <StrandsUiButton\n variant=\"secondary\"\n @click=\"handleCancel\"\n :disabled=\"loading\"\n >\n Cancel\n </StrandsUiButton>\n </div>\n </form>\n\n <!-- Success/Error Messages -->\n <div v-if=\"successMessage\" class=\"animate-fade-in\">\n <div class=\"alert-success\">\n <div class=\"profile-help-item\">\n <svg class=\"profile-help-icon\" fill=\"currentColor\" viewBox=\"0 0 20 20\">\n <path fill-rule=\"evenodd\" d=\"M10 18a8 8 0 100-16 8 8 0 000 16zm3.857-9.809a.75.75 0 00-1.214-.882l-3.236 4.53L7.53 10.173a.75.75 0 00-1.06 1.061l2.5 2.5a.75.75 0 001.137-.089l4-5.5z\" clip-rule=\"evenodd\" />\n </svg>\n <p class=\"profile-alert-message\">{{ successMessage }}</p>\n </div>\n </div>\n </div>\n\n <div v-if=\"errorMessage\" class=\"animate-fade-in\">\n <div class=\"alert-error\">\n <div class=\"profile-help-item\">\n <svg class=\"profile-help-icon\" fill=\"currentColor\" viewBox=\"0 0 20 20\">\n <path fill-rule=\"evenodd\" d=\"M10 18a8 8 0 100-16 8 8 0 000 16zM8.28 7.22a.75.75 0 00-1.06 1.06L8.94 10l-1.72 1.72a.75.75 0 101.06 1.06L10 11.06l1.72 1.72a.75.75 0 101.06-1.06L11.06 10l1.72-1.72a.75.75 0 00-1.06-1.06L10 8.94 8.28 7.22z\" clip-rule=\"evenodd\" />\n </svg>\n <p class=\"profile-alert-message\">{{ errorMessage }}</p>\n </div>\n </div>\n </div>\n\n \n <!-- Secured by footer -->\n <StrandsSecuredFooter :config=\"props.config\">\n <div class=\"profile-footer-actions\">\n <!-- Sign Out button -->\n <StrandsUiButton\n color=\"red\"\n @click=\"handleSignOut\"\n :disabled=\"signingOut\"\nclass=\"profile-sign-out-button\"\n >\n {{ signingOut ? 'Signing out...' : 'Sign Out' }}\n </StrandsUiButton>\n\n <!-- Settings button -->\n <StrandsUiButton\n variant=\"secondary\"\n @click=\"showSettingsModal = true\"\nclass=\"profile-sign-out-button\"\n >\n <svg class=\"profile-action-icon\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M10.325 4.317c.426-1.756 2.924-1.756 3.35 0a1.724 1.724 0 002.573 1.066c1.543-.94 3.31.826 2.37 2.37a1.724 1.724 0 001.065 2.572c1.756.426 1.756 2.924 0 3.35a1.724 1.724 0 00-1.066 2.573c.94 1.543-.826 3.31-2.37 2.37a1.724 1.724 0 00-2.572 1.065c-.426 1.756-2.924 1.756-3.35 0a1.724 1.724 0 00-2.573-1.066c-1.543.94-3.31-.826-2.37-2.37a1.724 1.724 0 00-1.065-2.572c-1.756-.426-1.756-2.924 0-3.35a1.724 1.724 0 001.066-2.573c-.94-1.543.826-3.31 2.37-2.37.996.608 2.296.07 2.572-1.065z\" />\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M15 12a3 3 0 11-6 0 3 3 0 016 0z\" />\n </svg>\n </StrandsUiButton>\n </div>\n\n <!-- Need help -->\n <div v-if=\"getSupportEmail()\">\n <p class=\"profile-footer-text\">\n Need help?\n <StrandsUiLink variant=\"primary\" :href=\"`mailto:${getSupportEmail()}`\">\n Contact Support\n </StrandsUiLink>\n </p>\n </div>\n </StrandsSecuredFooter>\n </div>\n\n <!-- MFA Management Modal -->\n <StrandsMfaModal\n :show=\"showMfaModal\"\n @close=\"showMfaModal = false\"\n @mfa-updated=\"handleMfaUpdated\"\n />\n\n <!-- Settings Modal -->\n <StrandsSettingsModal\n v-if=\"showSettingsModal\"\n @close=\"showSettingsModal = false\"\n @settings-updated=\"handleSettingsUpdated\"\n />\n\n <!-- Sessions Management Modal -->\n <StrandsSessionsModal \n v-model=\"showSessionsModal\" \n @sessions-updated=\"handleSessionsUpdated\"\n />\n\n <!-- Avatar Editor Modal -->\n <div v-if=\"showAvatarEditor\" class=\"profile-avatar-modal-overlay\">\n <div class=\"profile-avatar-modal\">\n <div class=\"profile-avatar-modal-content\">\n <div class=\"profile-avatar-modal-header\">\n <h2 class=\"profile-modal-title\">Edit Avatar</h2>\n <button\n @click=\"handleAvatarEditorClose\"\n class=\"profile-avatar-modal-close\"\n >\n <svg class=\"profile-avatar-modal-close-icon\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M6 18L18 6M6 6l12 12\" />\n </svg>\n </button>\n </div>\n \n <StrandsUiAvatarEditor\n :uploading=\"uploading\"\n :preselected-file=\"selectedImageFile\"\n @upload=\"handleAvatarUpload\"\n @error=\"handleAvatarError\"\n />\n </div>\n </div>\n </div>\n </div>\n </div>\n</template>\n\n<script setup lang=\"ts\">\nimport { ref, reactive, computed, onMounted, watch, h } from 'vue'\nimport { StrandsUiButton, StrandsUiInput, StrandsUiLink, StrandsUiLoader, StrandsUiLevelProgress, StrandsUiModal, StrandsUiAvatarEditor } from '../ui'\nimport StrandsSecuredFooter from './StrandsSecuredFooter.vue'\nimport StrandsMfaModal from './StrandsMfaModal.vue'\nimport StrandsSettingsModal from './StrandsSettingsModal.vue'\nimport StrandsSessionsModal from './StrandsSessionsModal.vue'\nimport { useStrandsConfig, type StrandsAuthConfig } from '../composables/useStrandsConfig'\nimport { useStrandsAuth } from '../composables/useStrandsAuth'\nimport { useStrandsMfa } from '../composables/useStrandsMfa'\n\n// Inline SVG icon components using render functions (no runtime compilation needed)\nconst Smartphone = {\n props: ['size'],\n render(this: any) {\n return h('svg', { \n width: this.size, \n height: this.size, \n fill: 'none', \n stroke: 'currentColor', \n viewBox: '0 0 24 24' \n }, [\n h('rect', { x: '5', y: '2', width: '14', height: '20', rx: '2', ry: '2' }),\n h('line', { x1: '12', y1: '18', x2: '12.01', y2: '18' })\n ])\n }\n}\n\nconst Mail = {\n props: ['size'],\n render(this: any) {\n return h('svg', { \n width: this.size, \n height: this.size, \n fill: 'none', \n stroke: 'currentColor', \n viewBox: '0 0 24 24' \n }, [\n h('path', { d: 'm4 4 16 0c1.1 0 2 .9 2 2l0 12c0 1.1-.9 2-2 2l-16 0c-1.1 0-2-.9-2-2l0-12c0-1.1.9-2 2-2z' }),\n h('polyline', { points: '22,6 12,13 2,6' })\n ])\n }\n}\n\nconst KeyRound = {\n props: ['size'],\n render(this: any) {\n return h('svg', { \n width: this.size, \n height: this.size, \n fill: 'none', \n stroke: 'currentColor', \n viewBox: '0 0 24 24' \n }, [\n h('path', { d: 'M2.586 17.414A2 2 0 0 0 2 18.828V21a1 1 0 0 0 1 1h3a1 1 0 0 0 1-1v-1a1 1 0 0 1 1-1h1a1 1 0 0 0 1-1v-1a1 1 0 0 1 1-1h.172a2 2 0 0 0 1.414-.586l.814-.814a6.5 6.5 0 1 0-4-4z' }),\n h('circle', { cx: '16.5', cy: '7.5', r: '.5', fill: 'currentColor' })\n ])\n }\n}\nimport type { User, SessionInfo } from '../../types'\n\ninterface Props {\n user?: User\n config?: StrandsAuthConfig\n autoFetch?: boolean // Whether to automatically fetch user profile on mount\n inModal?: boolean // Whether the component is being displayed inside a modal\n}\n\ninterface Emits {\n (e: 'profile-updated', user: User): void\n (e: 'error', error: string): void\n (e: 'manage-sessions'): void\n (e: 'mfa-toggle', enabled: boolean): void\n}\n\nconst props = withDefaults(defineProps<Props>(), {\n autoFetch: true,\n inModal: false\n})\nconst emit = defineEmits<Emits>()\n\n// Get configuration and authentication \nconst { getSupportEmail, getUrl } = useStrandsConfig(props.config)\nconst { fetchProfile, updateProfile, changeEmail, changeUsername, getUsernameCooldown, checkUsernameAvailability, getUserSessions, currentUser: authUser, currentSession, isAuthenticated, refreshToken, signOut } = useStrandsAuth()\nconst { activeMfaDevices, fetchMfaDevices } = useStrandsMfa()\n\n// Internal user state\nconst internalUser = ref<User | null>(null)\nconst fetchingProfile = ref(false)\n\n// Use authenticated user from composable, fallback to prop, then internal state\nconst currentUser = computed(() => {\n const user = authUser.value || props.user || internalUser.value\n console.log('Current user computed:', {\n hasAuthUser: !!authUser.value,\n hasPropUser: !!props.user,\n hasInternalUser: !!internalUser.value,\n selectedUser: user,\n avatar: user?.avatar\n })\n return user\n})\n\nconst loading = ref(false)\nconst uploading = ref(false)\nconst signingOut = ref(false)\nconst showPasswordChange = ref(false)\nconst showEmailChange = ref(false)\nconst emailChangeLoading = ref(false)\nconst showUsernameChange = ref(false)\nconst usernameChangeLoading = ref(false)\nconst showMfaModal = ref(false)\nconst showSettingsModal = ref(false)\nconst showAvatarEditor = ref(false)\nconst selectedImageFile = ref<File | null>(null)\nconst successMessage = ref('')\nconst errorMessage = ref('')\nconst activeSessions = ref<SessionInfo[]>([])\nconst loadingSessions = ref(false)\nconst showSessionsModal = ref(false)\n\n// Username change state\nconst usernameChangeData = reactive({\n canChange: true,\n cooldownEnd: null as Date | null,\n daysRemaining: 0\n})\n\nconst usernameAvailability = reactive({\n available: false,\n message: '',\n checking: false\n})\n\n// Temporary total XP state for testing (accumulates infinitely)\n\n// Refs\nconst avatarFileInput = ref<HTMLInputElement>()\n\nconst form = reactive({\n firstName: '',\n lastName: '',\n email: ''\n})\n\nconst emailChangeForm = reactive({\n newEmail: '',\n password: '',\n errors: {\n newEmail: '',\n password: ''\n }\n})\n\nconst passwordForm = reactive({\n current: '',\n new: '',\n confirm: ''\n})\n\nconst usernameForm = reactive({\n username: '',\n errors: {\n username: ''\n }\n})\n\nconst errors = reactive({\n firstName: '',\n lastName: '',\n email: ''\n})\n\nconst hasChanges = computed(() => {\n const user = currentUser.value\n if (!user) return false\n return (\n form.firstName !== (user.firstName || '') ||\n form.lastName !== (user.lastName || '')\n )\n})\n\nconst isPasswordFormValid = computed(() => {\n return (\n passwordForm.current &&\n passwordForm.new &&\n passwordForm.confirm &&\n passwordForm.new === passwordForm.confirm &&\n passwordForm.new.length >= 8\n )\n})\n\nconst isEmailChangeFormValid = computed(() => {\n return (\n emailChangeForm.newEmail &&\n emailChangeForm.password &&\n emailChangeForm.newEmail !== currentUser.value?.email &&\n emailChangeForm.newEmail.includes('@')\n )\n})\n\nconst isUsernameChangeFormValid = computed(() => {\n const usernameRegex = /^[a-zA-Z0-9_-]{3,30}$/\n return (\n usernameForm.username &&\n usernameRegex.test(usernameForm.username) &&\n usernameForm.username !== currentUser.value?.username &&\n !usernameAvailability.checking\n )\n})\n\nconst passwordLastUpdated = computed(() => {\n const user = currentUser.value\n if (!user) return 'Never'\n \n // Use passwordUpdatedAt if available, otherwise fall back to createdAt\n const updateDate = user.passwordUpdatedAt || user.createdAt\n if (!updateDate) return 'Never'\n \n const date = new Date(updateDate)\n const now = new Date()\n const diffMs = now.getTime() - date.getTime()\n const diffDays = Math.floor(diffMs / (1000 * 60 * 60 * 24))\n \n if (diffDays === 0) return 'Today'\n if (diffDays === 1) return 'Yesterday'\n if (diffDays < 30) return `${diffDays} days ago`\n if (diffDays < 365) {\n const months = Math.floor(diffDays / 30)\n return months === 1 ? '1 month ago' : `${months} months ago`\n }\n const years = Math.floor(diffDays / 365)\n return years === 1 ? '1 year ago' : `${years} years ago`\n})\n\nconst deviceTypeCounts = computed(() => {\n const devices = activeMfaDevices.value || []\n const counts = {\n totp: 0,\n email: 0,\n hardware: 0,\n passkey: 0\n }\n \n devices.forEach(device => {\n if (device.device_type in counts) {\n counts[device.device_type as keyof typeof counts]++\n }\n })\n \n return counts\n})\n\nconst mfaDeviceChips = computed(() => {\n const chips = []\n const counts = deviceTypeCounts.value\n \n if (counts.totp > 0) {\n chips.push({\n type: 'totp',\n count: counts.totp,\n label: counts.totp === 1 ? 'Auth app' : 'Auth apps',\n icon: Smartphone,\n color: 'chip-blue'\n })\n }\n \n if (counts.email > 0) {\n chips.push({\n type: 'email',\n count: counts.email,\n label: 'Email',\n icon: Mail,\n color: 'chip-green'\n })\n }\n \n if (counts.hardware > 0 || counts.passkey > 0) {\n const totalHardware = counts.hardware + counts.passkey\n chips.push({\n type: 'hardware',\n count: totalHardware,\n label: totalHardware === 1 ? 'Key' : 'Keys',\n icon: KeyRound,\n color: 'chip-purple'\n })\n }\n \n return chips\n})\n\n// Calculate XP required for a specific level using the provided formula\nconst getXpForLevel = (level: number): number => {\n if (level <= 1) return 0\n \n let totalXp = 0\n for (let i = 1; i < level; i++) {\n // Formula: xp = 4 * i + Math.pow(1.5, i / 4) + xp\n // This accumulates XP required for each level\n totalXp += 4 * i + Math.pow(1.5, i / 4)\n }\n return Math.floor(totalXp)\n}\n\n// Calculate level from total XP\nconst getLevelFromXp = (totalXp: number): number => {\n let level = 1\n let cumulativeXp = 0\n \n // Keep incrementing level while totalXp is greater than required\n while (true) {\n const xpForNextLevel = getXpForLevel(level + 1)\n if (totalXp < xpForNextLevel) {\n break\n }\n level++\n // Safety check to prevent infinite loops\n if (level > 1000) break\n }\n \n return level\n}\n\n// Leveling system computed properties\nconst userLevel = computed(() => {\n return getLevelFromXp(currentUser.value?.xp || 0)\n})\n\nconst currentExp = computed(() => {\n const level = userLevel.value\n const xpForCurrentLevel = getXpForLevel(level)\n // Current XP within the level (progress toward next level)\n return (currentUser.value?.xp || 0) - xpForCurrentLevel\n})\n\nconst expToNextLevel = computed(() => {\n const level = userLevel.value\n const xpForCurrentLevel = getXpForLevel(level)\n const xpForNextLevel = getXpForLevel(level + 1)\n // XP needed to complete this level\n return xpForNextLevel - xpForCurrentLevel\n})\n\nconst progressPercentage = computed(() => {\n return Math.round((currentExp.value / expToNextLevel.value) * 100)\n})\n\nconst totalCircumference = computed(() => {\n const radius = 54\n return 2 * Math.PI * radius\n})\n\nconst progressLength = computed(() => {\n const progress = progressPercentage.value / 100\n return progress * totalCircumference.value\n})\n\nconst progressGapLength = computed(() => {\n // Create visible gap between progress and remaining background\n const smallGap = (totalCircumference.value * 5) / 360 // 5 degree gap\n const remaining = totalCircumference.value - progressLength.value - smallGap\n return remaining\n})\n\nconst getInitials = (firstName?: string, lastName?: string) => {\n if (!firstName && !lastName) return 'U'\n return `${firstName?.[0] || ''}${lastName?.[0] || ''}`.toUpperCase()\n}\n\n// Format time ago utility function\nconst formatTimeAgo = (dateString?: string | Date) => {\n if (!dateString) return 'Unknown'\n \n const date = new Date(dateString)\n const now = new Date()\n const diffMs = now.getTime() - date.getTime()\n const diffMinutes = Math.floor(diffMs / (1000 * 60))\n const diffHours = Math.floor(diffMs / (1000 * 60 * 60))\n const diffDays = Math.floor(diffMs / (1000 * 60 * 60 * 24))\n \n if (diffMinutes < 1) return 'Just now'\n if (diffMinutes < 60) return `${diffMinutes}m ago`\n if (diffHours < 24) return `${diffHours}h ago`\n if (diffDays < 7) return `${diffDays}d ago`\n if (diffDays < 30) return `${Math.floor(diffDays / 7)}w ago`\n if (diffDays < 365) return `${Math.floor(diffDays / 30)}mo ago`\n return `${Math.floor(diffDays / 365)}y ago`\n}\n\n// Fetch user profile from API\nconst fetchUserProfile = async () => {\n if (!props.autoFetch || props.user || !isAuthenticated.value) return // Skip if disabled, user prop provided, or not authenticated\n \n fetchingProfile.value = true\n try {\n await fetchProfile()\n // Also fetch MFA devices when profile is loaded\n if (isAuthenticated.value) {\n await fetchMfaDevices()\n }\n // The fetchProfile from composable will update authUser, so currentUser computed will reflect the change\n } catch (err) {\n const errorMsg = err instanceof Error ? err.message : 'Failed to load profile'\n errorMessage.value = errorMsg\n emit('error', errorMsg)\n } finally {\n fetchingProfile.value = false\n }\n}\n\n// Load user sessions\nconst loadUserSessions = async () => {\n console.log('loadUserSessions called, isAuthenticated:', isAuthenticated.value)\n if (!isAuthenticated.value) {\n console.log('Not authenticated, skipping session load')\n return\n }\n \n loadingSessions.value = true\n try {\n console.log('Calling getUserSessions...')\n const sessions = await getUserSessions()\n console.log('Sessions loaded:', sessions)\n activeSessions.value = sessions || []\n } catch (err) {\n console.error('Failed to load sessions:', err)\n // Don't show error to user for sessions as it's not critical\n } finally {\n loadingSessions.value = false\n }\n}\n\n// Initialize form with user data\nwatch(() => currentUser.value, (user) => {\n if (user) {\n form.firstName = user.firstName || ''\n form.lastName = user.lastName || ''\n form.email = user.email // Keep for display but not for editing\n }\n}, { immediate: true })\n\n// Watch for authentication state changes and load sessions\nwatch(() => isAuthenticated.value, (authenticated, wasAuthenticated) => {\n console.log('Authentication state changed from', wasAuthenticated, 'to', authenticated)\n if (authenticated && !wasAuthenticated) {\n // User just signed in, load sessions after a small delay to ensure tokens are set\n console.log('User just signed in, loading sessions...')\n setTimeout(() => {\n loadUserSessions()\n }, 500)\n } else if (!authenticated) {\n console.log('User signed out, clearing sessions')\n activeSessions.value = []\n }\n}, { immediate: false })\n\n// Also watch for session changes (when tokens are refreshed)\nwatch(() => currentSession.value, (session) => {\n console.log('Session changed:', session)\n if (session && isAuthenticated.value) {\n setTimeout(() => {\n loadUserSessions()\n }, 100)\n }\n})\n\n// Fetch profile and sessions on mount if needed\nonMounted(() => {\n console.log('StrandsUserProfile mounted')\n fetchUserProfile()\n loadUserSessions()\n})\n\nconst clearMessages = () => {\n successMessage.value = ''\n errorMessage.value = ''\n Object.keys(errors).forEach(key => {\n errors[key as keyof typeof errors] = ''\n })\n}\n\nconst handleUpdateProfile = async () => {\n clearMessages()\n loading.value = true\n\n try {\n const updatedUser = await updateProfile({\n firstName: form.firstName,\n lastName: form.lastName,\n })\n \n if (updatedUser) {\n successMessage.value = 'Profile updated successfully'\n emit('profile-updated', updatedUser)\n }\n } catch (err) {\n const error = err instanceof Error ? err.message : 'Failed to update profile'\n errorMessage.value = error\n emit('error', error)\n } finally {\n loading.value = false\n }\n}\n\nconst handlePasswordChange = async () => {\n if (!isPasswordFormValid.value) return\n\n clearMessages()\n loading.value = true\n\n try {\n // Integration point: Replace with actual password change call\n // Example: await authSDK.changePassword(passwordForm.current, passwordForm.new)\n \n // Simulate API call for demo\n await new Promise(resolve => setTimeout(resolve, 1000))\n \n successMessage.value = 'Password updated successfully'\n showPasswordChange.value = false\n passwordForm.current = ''\n passwordForm.new = ''\n passwordForm.confirm = ''\n } catch (err) {\n errorMessage.value = 'Failed to update password'\n } finally {\n loading.value = false\n }\n}\n\nconst handleEmailChange = async () => {\n if (!isEmailChangeFormValid.value) return\n\n // Clear previous errors\n emailChangeForm.errors.newEmail = ''\n emailChangeForm.errors.password = ''\n clearMessages()\n emailChangeLoading.value = true\n\n try {\n const result = await changeEmail(emailChangeForm.newEmail, emailChangeForm.password)\n \n successMessage.value = result.message || 'Email updated successfully. Please verify your new email address.'\n showEmailChange.value = false\n emailChangeForm.newEmail = ''\n emailChangeForm.password = ''\n \n // Emit profile updated event\n if (currentUser.value) {\n emit('profile-updated', currentUser.value)\n }\n } catch (err) {\n const error = err instanceof Error ? err.message : 'Failed to update email'\n \n // Try to parse specific field errors\n if (error.includes('password')) {\n emailChangeForm.errors.password = 'Invalid password'\n } else if (error.includes('email')) {\n emailChangeForm.errors.newEmail = error\n } else {\n errorMessage.value = error\n }\n \n emit('error', error)\n } finally {\n emailChangeLoading.value = false\n }\n}\n\nconst handleToggleUsernameChange = async () => {\n if (!showUsernameChange.value) {\n // When opening, check cooldown status\n usernameChangeLoading.value = true\n try {\n const cooldownData = await getUsernameCooldown()\n usernameChangeData.canChange = cooldownData.can_change\n usernameChangeData.cooldownEnd = cooldownData.cooldown_end ? new Date(cooldownData.cooldown_end) : null\n usernameChangeData.daysRemaining = cooldownData.days_remaining || 0\n \n if (usernameChangeData.canChange) {\n showUsernameChange.value = true\n usernameForm.username = currentUser.value?.username || ''\n } else {\n errorMessage.value = `You can change your username again in ${usernameChangeData.daysRemaining} days`\n }\n } catch (err) {\n errorMessage.value = 'Failed to check username cooldown'\n showUsernameChange.value = true // Allow opening anyway\n } finally {\n usernameChangeLoading.value = false\n }\n } else {\n // When closing, reset form\n showUsernameChange.value = false\n usernameForm.username = ''\n usernameForm.errors.username = ''\n usernameAvailability.available = false\n usernameAvailability.message = ''\n }\n}\n\nconst handleUsernameChange = async () => {\n if (!isUsernameChangeFormValid.value) {\n // First check if username is valid format\n const usernameRegex = /^[a-zA-Z0-9_-]{3,30}$/\n if (!usernameRegex.test(usernameForm.username)) {\n usernameForm.errors.username = 'Username must be 3-30 characters and contain only letters, numbers, hyphens, and underscores'\n return\n }\n \n // Check availability before attempting to update\n usernameAvailability.checking = true\n usernameAvailability.message = 'Checking availability...'\n \n try {\n const result = await checkUsernameAvailability(usernameForm.username)\n usernameAvailability.available = result.available\n usernameAvailability.message = result.message\n \n if (!result.available) {\n usernameForm.errors.username = 'Username is not available'\n return\n }\n } catch (err) {\n usernameForm.errors.username = 'Failed to check username availability'\n return\n } finally {\n usernameAvailability.checking = false\n }\n }\n\n clearMessages()\n usernameChangeLoading.value = true\n\n try {\n const result = await changeUsername(usernameForm.username)\n \n successMessage.value = result.message || 'Username updated successfully'\n showUsernameChange.value = false\n usernameForm.username = ''\n usernameForm.errors.username = ''\n usernameAvailability.available = false\n usernameAvailability.message = ''\n \n // Emit profile updated event\n if (currentUser.value) {\n emit('profile-updated', currentUser.value)\n }\n } catch (err) {\n const error = err instanceof Error ? err.message : 'Failed to update username'\n \n if (error.includes('taken')) {\n usernameForm.errors.username = 'Username is already taken'\n } else if (error.includes('cooldown') || error.includes('30 days')) {\n errorMessage.value = error\n showUsernameChange.value = false\n } else {\n usernameForm.errors.username = error\n }\n \n emit('error', error)\n } finally {\n usernameChangeLoading.value = false\n }\n}\n\nconst triggerAvatarUpload = () => {\n if (uploading.value) return\n avatarFileInput.value?.click()\n}\n\nconst handleAvatarFileSelect = (event: Event) => {\n const target = event.target as HTMLInputElement\n const file = target.files?.[0]\n if (file) {\n // Validate file\n if (!file.type.startsWith('image/')) {\n errorMessage.value = 'Please select an image file'\n return\n }\n \n if (file.size > 5 * 1024 * 1024) { // 5MB limit\n errorMessage.value = 'File size must be less than 5MB'\n return\n }\n \n // Store the selected file and open editor\n selectedImageFile.value = file\n showAvatarEditor.value = true\n }\n \n // Reset the input\n if (target) {\n target.value = ''\n }\n}\n\nconst handleAvatarUpload = async (file: File) => {\n await uploadAvatar(file)\n showAvatarEditor.value = false\n selectedImageFile.value = null\n}\n\nconst handleAvatarError = (error: string) => {\n errorMessage.value = error\n}\n\nconst handleAvatarEditorClose = () => {\n showAvatarEditor.value = false\n selectedImageFile.value = null\n}\n\nconst uploadAvatar = async (file: File) => {\n uploading.value = true\n clearMessages()\n \n try {\n // Check if we have an access token\n if (!currentSession.value?.accessToken) {\n throw new Error('No access token available. Please sign in again.')\n }\n \n // Create form data\n const formData = new FormData()\n formData.append('avatar', file)\n \n // Upload to API endpoint\n const response = await fetch(getUrl('avatar'), {\n method: 'POST',\n body: formData,\n headers: {\n 'Authorization': `Bearer ${currentSession.value.accessToken}`\n }\n })\n \n if (!response.ok) {\n // Handle authentication errors\n if (response.status === 401) {\n // Try to refresh token and retry once\n try {\n console.log('Access token expired, attempting to refresh...')\n const refreshed = await refreshToken()\n if (refreshed && currentSession.value?.accessToken) {\n console.log('Token refreshed successfully, retrying avatar upload...')\n // Retry the upload with new token\n const retryResponse = await fetch(getUrl('avatar'), {\n method: 'POST',\n body: formData,\n headers: {\n 'Authorization': `Bearer ${currentSession.value.accessToken}`\n }\n })\n \n if (!retryResponse.ok) {\n const errorData = await retryResponse.json().catch(() => ({}))\n throw new Error(errorData.message || `Upload failed: ${retryResponse.status} ${retryResponse.statusText}`)\n }\n \n // Use the retry response for processing\n const retryResult = await retryResponse.json()\n console.log('Avatar upload retry success:', retryResult)\n \n // Update user avatar in the current user state\n if (authUser.value) {\n console.log('Updating authUser avatar from:', authUser.value.avatar, 'to:', retryResult.avatar_url)\n authUser.value.avatar = retryResult.avatar_url\n \n // Also update localStorage\n if (typeof window !== 'undefined') {\n localStorage.setItem('strands_auth_user', JSON.stringify(authUser.value))\n }\n }\n \n // Also update internal user state if present\n if (internalUser.value) {\n internalUser.value.avatar = retryResult.avatar_url\n }\n \n // Refresh user profile from API to ensure we have the latest data\n try {\n await fetchProfile()\n console.log('Profile refreshed after avatar upload retry')\n } catch (refreshError) {\n console.warn('Failed to refresh profile after avatar upload retry:', refreshError)\n }\n \n successMessage.value = 'Avatar updated successfully'\n \n // Emit with current user data\n if (currentUser.value) {\n emit('profile-updated', currentUser.value)\n }\n return\n } else {\n throw new Error('Authentication expired. Please sign in again.')\n }\n } catch (refreshError) {\n throw new Error('Authentication expired. Please sign in again.')\n }\n } else {\n const errorData = await response.json().catch(() => ({}))\n throw new Error(errorData.message || `Upload failed: ${response.status} ${response.statusText}`)\n }\n }\n \n const result = await response.json()\n console.log('Avatar upload success:', result)\n \n // Update user avatar in the current user state\n if (authUser.value) {\n console.log('Updating authUser avatar from:', authUser.value.avatar, 'to:', result.avatar_url)\n authUser.value.avatar = result.avatar_url\n \n // Also update localStorage\n if (typeof window !== 'undefined') {\n localStorage.setItem('strands_auth_user', JSON.stringify(authUser.value))\n }\n }\n \n // Also update internal user state if present\n if (internalUser.value) {\n internalUser.value.avatar = result.avatar_url\n }\n \n // Refresh user profile from API to ensure we have the latest data\n try {\n await fetchProfile()\n console.log('Profile refreshed after avatar upload')\n } catch (refreshError) {\n console.warn('Failed to refresh profile after avatar upload:', refreshError)\n }\n \n successMessage.value = 'Avatar updated successfully'\n \n // Emit with current user data\n if (currentUser.value) {\n emit('profile-updated', currentUser.value)\n }\n \n } catch (err) {\n const error = err instanceof Error ? err.message : 'Failed to upload avatar'\n errorMessage.value = error\n emit('error', error)\n } finally {\n uploading.value = false\n }\n}\n\nconst handleMfaUpdated = async () => {\n // Refresh the user profile and MFA devices to get updated status\n try {\n await fetchProfile()\n await fetchMfaDevices()\n successMessage.value = 'MFA settings updated successfully'\n emit('mfa-toggle', currentUser.value?.mfaEnabled || false)\n } catch (err) {\n console.error('Failed to refresh profile after MFA update:', err)\n }\n}\n\nconst handleSettingsUpdated = (settings: any) => {\n successMessage.value = 'Settings updated successfully'\n // Settings are automatically updated in the auth composable\n // The modal already handles the API call and state updates\n}\n\nconst handleSessionsUpdated = () => {\n // Refresh session count when sessions are updated\n loadUserSessions()\n}\n\nconst handleCancel = () => {\n const user = currentUser.value\n if (user) {\n form.firstName = user.firstName || ''\n form.lastName = user.lastName || ''\n form.email = user.email\n }\n clearMessages()\n showPasswordChange.value = false\n showEmailChange.value = false\n passwordForm.current = ''\n passwordForm.new = ''\n passwordForm.confirm = ''\n emailChangeForm.newEmail = ''\n emailChangeForm.password = ''\n emailChangeForm.errors.newEmail = ''\n emailChangeForm.errors.password = ''\n}\n\nconst handleSignOut = async () => {\n signingOut.value = true\n clearMessages()\n \n try {\n await signOut()\n // The signOut function from useStrandsAuth will handle navigation and token clearing\n successMessage.value = 'Signed out successfully'\n } catch (err) {\n const error = err instanceof Error ? err.message : 'Failed to sign out'\n errorMessage.value = error\n emit('error', error)\n signingOut.value = false\n }\n}\n\n\n// Initialize username cooldown data when component mounts\nonMounted(async () => {\n if (currentUser.value && isAuthenticated.value) {\n try {\n const cooldownData = await getUsernameCooldown()\n usernameChangeData.canChange = cooldownData.can_change\n usernameChangeData.cooldownEnd = cooldownData.cooldown_end ? new Date(cooldownData.cooldown_end) : null\n usernameChangeData.daysRemaining = cooldownData.days_remaining || 0\n } catch (err) {\n console.error('Failed to fetch username cooldown:', err)\n }\n }\n})\n\n</script>\n\n<style scoped>\n/* Container Styles */\n.profile-container-width {\n width: 100%;\n}\n\n.profile-max-width {\n max-width: 56rem;\n}\n\n.profile-centered {\n margin: 0 auto;\n}\n\n.profile-animated {\n animation: slideUp 0.3s ease-out;\n}\n\n@keyframes slideUp {\n from {\n opacity: 0;\n transform: translateY(20px);\n }\n to {\n opacity: 1;\n transform: translateY(0);\n }\n}\n\n.profile-content-layout {\n display: flex;\n flex-direction: column;\n gap: 1.5rem;\n}\n\n.profile-card-modern {\n background: #ffffff;\n border: 1px solid #e5e7eb;\n border-radius: 1rem;\n padding: 2rem;\n box-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.1);\n}\n\n/* Modal-specific styles */\n.profile-container-modal {\n /* Remove any container-specific styles when in modal */\n}\n\n.profile-content-modal {\n /* Remove card styling when in modal */\n background: transparent;\n border: none;\n border-radius: 0;\n padding: 0;\n box-shadow: none;\n}\n\n/* Header */\n.profile-header {\n text-align: center;\n display: flex;\n flex-direction: column;\n gap: 0.5rem;\n}\n\n.profile-title {\n font-size: 1.5rem;\n font-weight: 700;\n color: #EA00A8;\n}\n\n.profile-subtitle {\n color: #4b5563;\n font-size: 0.875rem;\n}\n\n/* Profile Image Section */\n.profile-image-section {\n display: flex;\n flex-direction: column;\n align-items: center;\n}\n\n.profile-image-container {\n position: relative;\n}\n\n.profile-image-wrapper {\n position: relative;\n display: inline-block;\n}\n\n.profile-image-wrapper:hover .profile-upload-overlay {\n opacity: 1;\n}\n\n.profile-progress-ring {\n position: absolute;\n z-index: 10;\n top: 50%;\n left: 50%;\n transform: translate(-50%, -50%);\n pointer-events: none;\n}\n\n.profile-avatar {\n width: 6rem;\n height: 6rem;\n border-radius: 50%;\n position: relative;\n}\n\n.profile-avatar-with-image {\n box-shadow: 0 20px 25px -5px rgba(0, 0, 0, 0.1);\n overflow: hidden;\n}\n\n.profile-avatar-image {\n width: 100%;\n height: 100%;\n object-fit: cover;\n}\n\n.profile-avatar-initials {\n background-color: #EA00A8;\n display: flex;\n align-items: center;\n justify-content: center;\n color: white;\n font-size: 1.5rem;\n font-weight: 700;\n box-shadow: 0 20px 25px -5px rgba(0, 0, 0, 0.1);\n z-index: 10;\n}\n\n.profile-upload-overlay {\n position: absolute;\n inset: 0;\n border-radius: 50%;\n background: rgba(0, 0, 0, 0.4);\n display: flex;\n align-items: center;\n justify-content: center;\n opacity: 0;\n transition: opacity 0.2s ease;\n z-index: 20;\n border: none;\n cursor: pointer;\n}\n\n.profile-upload-overlay:disabled {\n cursor: not-allowed;\n}\n\n.profile-upload-icon {\n width: 1.5rem;\n height: 1.5rem;\n color: white;\n}\n\n.profile-file-input {\n display: none;\n}\n\n/* Profile Form */\n.profile-form {\n display: flex;\n flex-direction: column;\n gap: 1rem;\n}\n\n.profile-form-grid {\n display: grid;\n grid-template-columns: 1fr;\n gap: 1rem;\n}\n\n@media (min-width: 768px) {\n .profile-form {\n gap: 1.5rem;\n }\n \n .profile-form-grid {\n grid-template-columns: 1fr 1fr;\n gap: 1.5rem;\n }\n \n .profile-title {\n font-size: 1.875rem;\n }\n \n .profile-subtitle {\n font-size: 1rem;\n }\n}\n\n/* Section Styles */\n.profile-section {\n display: flex;\n flex-direction: column;\n gap: 0.75rem;\n}\n\n@media (min-width: 768px) {\n .profile-section {\n gap: 1rem;\n }\n}\n\n.profile-section-title {\n font-size: 1.125rem;\n font-weight: 600;\n color: #111827;\n}\n\n/* Setting Cards */\n.profile-setting-card {\n display: flex;\n flex-direction: column;\n gap: 1rem;\n padding: 1rem;\n background-color: #f9fafb;\n border-radius: 0.75rem;\n}\n\n.profile-setting-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: 0.5rem;\n}\n\n.profile-setting-title {\n font-weight: 500;\n color: #111827;\n}\n\n.profile-setting-subtitle {\n font-size: 0.875rem;\n color: #4b5563;\n}\n\n/* Transitions */\n.expand-enter-active {\n transition: all 0.4s cubic-bezier(0.4, 0, 0.2, 1);\n overflow: hidden;\n}\n\n.expand-leave-active {\n transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);\n overflow: hidden;\n}\n\n.expand-enter-from {\n max-height: 0;\n opacity: 0;\n transform: translateY(-10px);\n}\n\n.expand-leave-to {\n max-height: 0;\n opacity: 0;\n transform: translateY(-10px);\n}\n\n.expand-enter-to,\n.expand-leave-from {\n max-height: 300px;\n opacity: 1;\n transform: translateY(0);\n}\n\n/* MFA Device Chip */\n.mfa-device-chip {\n display: inline-flex;\n align-items: center;\n gap: 0.375rem;\n padding: 0.25rem 0.625rem;\n border-radius: 0.5rem;\n font-size: 0.75rem;\n font-weight: 500;\n border: 1px solid;\n transition: color 0.15s ease, background-color 0.15s ease, border-color 0.15s ease;\n}\n\n/* MFA Chip Color Variants */\n.mfa-device-chip.chip-blue {\n background-color: #eff6ff;\n color: #1d4ed8;\n border-color: #bfdbfe;\n}\n\n.mfa-device-chip.chip-green {\n background-color: #f0fdf4;\n color: #15803d;\n border-color: #bbf7d0;\n}\n\n.mfa-device-chip.chip-purple {\n background-color: #faf5ff;\n color: #7c3aed;\n border-color: #e9d5ff;\n}\n\n\n/* New semantic classes for Tailwind conversion */\n.profile-change-form {\n display: flex;\n flex-direction: column;\n gap: 0.75rem;\n overflow: hidden;\n}\n\n.profile-field-section {\n display: flex;\n flex-direction: column;\n gap: 1rem;\n padding: 1rem;\n background-color: #f9fafb;\n border-radius: 0.75rem;\n}\n\n.profile-field-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: 0.5rem;\n}\n\n.profile-field-header-vertical {\n align-items: flex-start;\n gap: 1rem;\n}\n\n.profile-password-section {\n display: flex;\n flex-direction: column;\n gap: 0.75rem;\n}\n\n@media (min-width: 768px) {\n .profile-password-section {\n gap: 1rem;\n }\n}\n\n.profile-mfa-content {\n flex: 1;\n display: flex;\n flex-direction: column;\n gap: 0.75rem;\n}\n\n.profile-mfa-chips {\n display: flex;\n flex-wrap: wrap;\n gap: 0.5rem;\n}\n\n.profile-actions-section {\n display: flex;\n flex-direction: column;\n gap: 0.75rem;\n padding-top: 1.5rem;\n border-top: 1px solid #e5e7eb;\n animation: slideUp 0.3s ease-out;\n}\n\n@media (min-width: 640px) {\n .profile-actions-section {\n flex-direction: row;\n }\n}\n\n.profile-help-item {\n display: flex;\n align-items: flex-start;\n gap: 0.75rem;\n}\n\n.profile-help-icon {\n width: 1rem;\n height: 1rem;\n flex-shrink: 0;\n}\n\n.profile-footer-actions {\n display: flex;\n gap: 1rem;\n align-items: stretch;\n}\n\n.profile-action-icon {\n width: 1rem;\n height: 1rem;\n}\n\n.profile-footer-text {\n color: #9ca3af;\n font-size: 0.875rem;\n}\n\n/* Avatar Editor Modal */\n.profile-avatar-modal-overlay {\n position: fixed;\n inset: 0;\n background-color: rgba(0, 0, 0, 0.5);\n display: flex;\n align-items: center;\n justify-content: center;\n z-index: 50;\n padding: 1rem;\n}\n\n.profile-avatar-modal {\n background-color: #ffffff;\n border-radius: 0.75rem;\n box-shadow: 0 25px 50px -12px rgba(0, 0, 0, 0.25);\n max-width: 56rem;\n width: 100%;\n max-height: 90vh;\n overflow-y: auto;\n}\n\n.profile-avatar-modal-content {\n padding: 1.5rem;\n display: flex;\n flex-direction: column;\n gap: 1.5rem;\n}\n\n.profile-avatar-modal-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n}\n\n.profile-avatar-modal-close {\n color: #9ca3af;\n transition: color 0.2s ease;\n background: none;\n border: none;\n cursor: pointer;\n padding: 0.25rem;\n border-radius: 0.25rem;\n}\n\n.profile-avatar-modal-close:hover {\n color: #4b5563;\n}\n\n.profile-avatar-modal-close-icon {\n width: 1.5rem;\n height: 1.5rem;\n}\n\n/* Profile field styles */\n.profile-field-title {\n font-weight: 500;\n color: #111827;\n}\n\n.profile-field-subtitle {\n font-size: 0.875rem;\n color: #6b7280;\n}\n\n.profile-availability-message {\n font-size: 0.75rem;\n}\n\n.profile-availability-message.success {\n color: #16a34a;\n}\n\n.profile-availability-message.error {\n color: #dc2626;\n}\n\n.profile-toggle-container {\n flex-shrink: 0;\n}\n\n.profile-alert-message {\n font-weight: 500;\n}\n\n.profile-modal-title {\n font-size: 1.25rem;\n font-weight: 700;\n color: #111827;\n}\n\n/* Sign out button styles */\n.profile-sign-out-button {\n width: 100%;\n}\n\n@media (min-width: 640px) {\n .profile-sign-out-button {\n width: auto;\n }\n}\n\n/* Sessions Modal Styles */\n.sessions-modal {\n min-width: 32rem;\n max-width: 48rem;\n}\n\n.session-current-badge {\n background-color: #dcfdf7;\n color: #065f46;\n font-size: 0.75rem;\n font-weight: 500;\n padding: 0.125rem 0.5rem;\n border-radius: 9999px;\n border: 1px solid #a7f3d0;\n}\n\n.modal-header {\n margin-bottom: 1.5rem;\n}\n\n.modal-title {\n font-size: 1.5rem;\n font-weight: 700;\n color: #111827;\n margin-bottom: 0.5rem;\n}\n\n.modal-subtitle {\n color: #6b7280;\n}\n\n.sessions-content {\n display: flex;\n flex-direction: column;\n gap: 1.5rem;\n}\n\n.session-stats {\n display: flex;\n gap: 1rem;\n padding: 1rem;\n background-color: #f9fafb;\n border-radius: 0.5rem;\n}\n\n.stat-item {\n display: flex;\n flex-direction: column;\n align-items: center;\n gap: 0.25rem;\n}\n\n.stat-label {\n font-size: 0.875rem;\n color: #6b7280;\n}\n\n.stat-value {\n font-size: 1.5rem;\n font-weight: 700;\n color: #111827;\n}\n\n.sessions-list {\n display: flex;\n flex-direction: column;\n gap: 1rem;\n}\n\n.sessions-loading {\n display: flex;\n align-items: center;\n gap: 0.5rem;\n padding: 2rem;\n justify-content: center;\n color: #6b7280;\n}\n\n.sessions-empty {\n text-align: center;\n padding: 2rem;\n color: #6b7280;\n}\n\n.session-card {\n border: 1px solid #e5e7eb;\n border-radius: 0.5rem;\n padding: 1rem;\n background-color: #ffffff;\n}\n\n.session-card-header {\n display: flex;\n justify-content: space-between;\n align-items: flex-start;\n margin-bottom: 0.75rem;\n}\n\n.session-device-info {\n flex: 1;\n}\n\n.session-device-name {\n font-size: 1.125rem;\n font-weight: 600;\n color: #111827;\n margin-bottom: 0.25rem;\n}\n\n.session-card-details {\n display: flex;\n flex-direction: column;\n gap: 0.5rem;\n}\n\n.session-detail-row {\n display: flex;\n gap: 0.5rem;\n}\n\n.detail-label {\n font-weight: 500;\n color: #6b7280;\n min-width: 6rem;\n}\n\n.detail-value {\n color: #111827;\n}\n\n.session-actions {\n display: flex;\n justify-content: center;\n padding-top: 1rem;\n border-top: 1px solid #e5e7eb;\n}\n\n@media (max-width: 640px) {\n .sessions-modal {\n min-width: auto;\n width: 100%;\n margin: 1rem;\n }\n \n .session-stats {\n flex-direction: column;\n gap: 0.5rem;\n }\n \n .session-card-header {\n flex-direction: column;\n gap: 0.75rem;\n }\n \n .detail-label {\n min-width: 5rem;\n }\n}\n</style>\n\n","<template>\n <div class=\"accui-component-scope\">\n <div class=\"accui-w-full accui-min-w-100 accui-max-w-md accui-mx-auto accui-animate-slide-up\">\n <StrandsUiCard variant=\"modern\">\n <!-- Header -->\n <div class=\"accui-text-center accui-mb-8\">\n <h1 class=\"accui-text-3xl accui-font-bold accui-text-gradient accui-mb-2\">Reset password</h1>\n <p class=\"accui-text-neutral-600\">Enter your email address and we'll send you a link to reset your password</p>\n </div>\n\n <!-- Reset Form -->\n <form @submit.prevent=\"handlePasswordReset\" class=\"accui-space-y-6\">\n <StrandsUiInput id=\"email\" v-model=\"form.email\" type=\"email\" label=\"Email address\"\n placeholder=\"Enter your email address\" autocomplete=\"email\" required :disabled=\"loading || isSubmitted\"\n :error=\"error ? 'Email address not found' : undefined\" />\n\n <StrandsUiButton type=\"submit\" variant=\"primary\" full-width :disabled=\"loading || !form.email.trim() || isSubmitted\"\n :loading=\"loading\" :loading-text=\"'Sending link...'\">\n {{ isSubmitted ? 'Link sent!' : 'Send reset link' }}\n </StrandsUiButton>\n </form>\n\n <!-- Success Message -->\n <StrandsUiAlert v-if=\"isSubmitted\" variant=\"success\"\n :message=\"`Check your email - We've sent a password reset link to ${form.email}`\"\n class=\"accui-mt-6 accui-animate-fade-in\" />\n\n <!-- Error Message -->\n <StrandsUiAlert v-if=\"error\" variant=\"error\" :message=\"error\" class=\"accui-mt-6 accui-animate-fade-in\" dismissible\n @dismiss=\"error = ''\" />\n\n <!-- Back to Sign In -->\n <div class=\"accui-mt-8 accui-text-center\">\n <StrandsUiLink @click=\"$emit('back-to-signin')\" class=\"accui-inline-flex accui-items-center accui-gap-2\">\n <svg class=\"accui-w-4 accui-h-4\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M15 19l-7-7 7-7\" />\n </svg>\n Back to sign in\n </StrandsUiLink>\n </div>\n\n <!-- Secured by footer -->\n <StrandsSecuredFooter :config=\"props.config\">\n <!-- Need help -->\n <div v-if=\"getSupportEmail()\" class=\"accui-mt-6 accui-text-center\">\n <p class=\"accui-text-neutral-400 accui-text-sm\">\n Need help?\n <StrandsUiLink variant=\"primary\" :href=\"`mailto:${getSupportEmail()}`\">\n Contact Support\n </StrandsUiLink>\n </p>\n </div>\n </StrandsSecuredFooter>\n </StrandsUiCard>\n </div>\n </div>\n</template>\n\n<script setup lang=\"ts\">\nimport { ref, reactive } from 'vue'\nimport { StrandsUiCard, StrandsUiButton, StrandsUiInput, StrandsUiAlert, StrandsUiLink } from '../ui'\nimport StrandsSecuredFooter from './StrandsSecuredFooter.vue'\nimport { useStrandsConfig, type StrandsAuthConfig } from '../composables/useStrandsConfig'\n\ninterface Props {\n config?: StrandsAuthConfig\n}\n\ninterface Emits {\n (e: 'success', email: string): void\n (e: 'error', error: string): void\n (e: 'back-to-signin'): void\n}\n\nconst props = withDefaults(defineProps<Props>(), {})\nconst emit = defineEmits<Emits>()\n\n// Get configuration\nconst { getSupportEmail } = useStrandsConfig(props.config)\n\nconst loading = ref(false)\nconst error = ref('')\nconst isSubmitted = ref(false)\n\nconst form = reactive({\n email: ''\n})\n\nconst handlePasswordReset = async () => {\n loading.value = true\n error.value = ''\n\n try {\n // Integration point: Replace with actual password reset API call\n console.log('Password reset request:', { email: form.email })\n\n // Simulate API call\n await new Promise(resolve => setTimeout(resolve, 1000))\n\n isSubmitted.value = true\n emit('success', form.email)\n } catch (err) {\n error.value = 'Failed to send password reset email. Please try again.'\n emit('error', error.value)\n } finally {\n loading.value = false\n }\n}\n</script>\n\n<style scoped>\n/* Override accui- prefixed Tailwind classes with CSS properties */\n.accui-w-full {\n width: 100%;\n}\n\n.accui-min-w-100 {\n min-width: 25rem;\n}\n\n.accui-max-w-md {\n max-width: 28rem;\n}\n\n.accui-mx-auto {\n margin-left: auto;\n margin-right: auto;\n}\n\n.accui-animate-slide-up {\n animation: slideUp 0.3s ease-out;\n}\n\n.accui-text-center {\n text-align: center;\n}\n\n.accui-mb-8 {\n margin-bottom: 2rem;\n}\n\n.accui-text-3xl {\n font-size: 1.875rem;\n}\n\n.accui-font-bold {\n font-weight: 700;\n}\n\n.accui-text-gradient {\n background: linear-gradient(to right, var(--strands-500, #EA00A8), var(--strands-600, #db2777));\n background-clip: text;\n -webkit-background-clip: text;\n color: transparent;\n}\n\n.accui-mb-2 {\n margin-bottom: 0.5rem;\n}\n\n.accui-text-neutral-600 {\n color: var(--neutral-600, #525252);\n}\n\n.accui-space-y-6 > * + * {\n margin-top: 1.5rem;\n}\n\n.accui-mt-6 {\n margin-top: 1.5rem;\n}\n\n.accui-animate-fade-in {\n animation: fadeIn 0.2s ease-out;\n}\n\n.accui-mt-8 {\n margin-top: 2rem;\n}\n\n.accui-inline-flex {\n display: inline-flex;\n}\n\n.accui-items-center {\n align-items: center;\n}\n\n.accui-gap-2 {\n gap: 0.5rem;\n}\n\n.accui-w-4 {\n width: 1rem;\n}\n\n.accui-h-4 {\n height: 1rem;\n}\n\n.accui-text-neutral-400 {\n color: var(--neutral-400, #a3a3a3);\n}\n\n.accui-text-sm {\n font-size: 0.875rem;\n}\n\n@keyframes slideUp {\n from {\n opacity: 0;\n transform: translateY(20px);\n }\n to {\n opacity: 1;\n transform: translateY(0);\n }\n}\n\n@keyframes fadeIn {\n from {\n opacity: 0;\n }\n to {\n opacity: 1;\n }\n}\n</style>","<template>\n <div v-if=\"signedInOrInverted\" class=\"animate-fade-in\">\n <slot :user=\"user\" :signOut=\"signOut\" :invert=\"invert\" />\n </div>\n <div v-else-if=\"signedOutOrInverted\" class=\"animate-fade-in\">\n <slot name=\"fallback\" :signIn=\"signIn\">\n <!-- Default fallback content -->\n <div class=\"signed-in-fallback\">\n <div class=\"signed-in-icon-container\">\n <svg class=\"signed-in-icon\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" 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 </svg>\n </div>\n <h3 class=\"signed-in-title\">Sign in required</h3>\n <p class=\"signed-in-subtitle\">You need to be signed in to access this content.</p>\n <button\n @click=\"signIn\"\n class=\"signed-in-button\"\n >\n Sign in\n </button>\n </div>\n </slot>\n </div>\n <div v-else-if=\"showLoading\" class=\"animate-fade-in\">\n <slot name=\"loading\">\n <StrandsUiLoader\n :size=\"64\" \n text=\"Checking authentication...\" \n variant=\"auto\" \n :show-particles=\"true\" \n />\n </slot>\n </div>\n</template>\n\n<script setup lang=\"ts\">\nimport { ref, computed, onMounted } from 'vue'\nimport { useStrandsAuth } from '../composables/useStrandsAuth'\nimport { StrandsUiLoader } from '../ui'\n\ninterface Props {\n showFallback?: boolean\n invert?: boolean\n}\n\ninterface Emits {\n (e: 'sign-in-required'): void\n}\n\nconst props = withDefaults(defineProps<Props>(), {\n showFallback: true,\n invert: false\n})\n\nconst invert = props.invert ?? false\n\nconst signedInOrInverted = computed(() => ((isAuthenticated.value && !invert) || (!isAuthenticated.value && invert)) && !showLoading.value)\nconst signedOutOrInverted = computed(() => ((isAuthenticated.value && invert) || (!isAuthenticated.value && !invert)) && props.showFallback && !showLoading.value)\n\nconst emit = defineEmits<Emits>()\n\n// Local loading state to ensure loading shows on first render\nconst isComponentReady = ref(false)\n\nconst { isAuthenticated, isInitializing, isSigningIn, user, signOut } = useStrandsAuth()\n\n// Show loading until both auth is initialized AND component is ready\n// Don't show loading during sign-in attempts - let StrandsAuth handle its own loading\nconst showLoading = computed(() => (isInitializing.value && !isSigningIn.value) || !isComponentReady.value)\n\nonMounted(() => {\n // Add a small delay to ensure we show loading state\n setTimeout(() => {\n isComponentReady.value = true\n }, 100)\n})\n\nconst signIn = () => {\n emit('sign-in-required')\n}\n</script>\n\n<style scoped>\n.signed-in-fallback {\n text-align: center;\n padding: 2rem 0;\n}\n\n.signed-in-icon-container {\n width: 4rem;\n height: 4rem;\n margin: 0 auto 1rem;\n background-color: #f5f5f5;\n border-radius: 50%;\n display: flex;\n align-items: center;\n justify-content: center;\n}\n\n.signed-in-icon {\n width: 2rem;\n height: 2rem;\n color: #a3a3a3;\n}\n\n.signed-in-title {\n font-size: 1.125rem;\n font-weight: 600;\n color: #171717;\n margin-bottom: 0.5rem;\n}\n\n.signed-in-subtitle {\n color: #525252;\n margin-bottom: 1rem;\n}\n\n.signed-in-button {\n background-color: #EA00A8;\n color: white;\n width: auto;\n padding: 0.5rem 1.5rem;\n border: none;\n border-radius: 0.5rem;\n cursor: pointer;\n font-weight: 600;\n transition: background-color 0.2s ease;\n}\n\n.signed-in-button:hover {\n background-color: #B8006F;\n}\n</style>","<template>\n <div v-if=\"!isAuthenticated && !isLoading\" class=\"animate-fade-in\">\n <slot :signIn=\"signIn\" :signUp=\"signUp\" />\n </div>\n <div v-else-if=\"showFallback && isAuthenticated && !isLoading\" class=\"animate-fade-in\">\n <slot name=\"fallback\" :user=\"user\" :signOut=\"signOut\">\n <!-- Default fallback content for signed in users -->\n <div class=\"signed-out-fallback\">\n <div class=\"signed-out-icon-container\">\n <svg class=\"signed-out-icon\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" 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 </svg>\n </div>\n <h3 class=\"signed-out-title\">Already signed in</h3>\n <p class=\"signed-out-subtitle\">You're currently signed in as {{ user?.email }}.</p>\n <button\n @click=\"signOut\"\n class=\"signed-out-button\"\n >\n Sign out\n </button>\n </div>\n </slot>\n </div>\n <div v-else-if=\"isLoading\" class=\"animate-fade-in\">\n <slot name=\"loading\">\n <StrandsUiLoader \n :size=\"64\"\n text=\"Checking authentication...\"\n variant=\"auto\"\n :show-particles=\"true\"\n />\n </slot>\n </div>\n</template>\n\n<script setup lang=\"ts\">\nimport { useStrandsAuth } from '../composables/useStrandsAuth'\nimport { StrandsUiLoader } from '../ui'\n\ninterface Props {\n showFallback?: boolean\n}\n\ninterface Emits {\n (e: 'sign-in-clicked'): void\n (e: 'sign-up-clicked'): void\n}\n\nconst props = withDefaults(defineProps<Props>(), {\n showFallback: true\n})\n\nconst emit = defineEmits<Emits>()\n\nconst { isAuthenticated, isLoading, user, signOut } = useStrandsAuth()\n\nconst signIn = () => {\n emit('sign-in-clicked')\n}\n\nconst signUp = () => {\n emit('sign-up-clicked')\n}\n</script>\n\n<style scoped>\n.signed-out-fallback {\n text-align: center;\n padding: 2rem 0;\n}\n\n.signed-out-icon-container {\n width: 4rem;\n height: 4rem;\n margin: 0 auto 1rem;\n background-color: #fce7f3;\n border-radius: 50%;\n display: flex;\n align-items: center;\n justify-content: center;\n}\n\n.signed-out-icon {\n width: 2rem;\n height: 2rem;\n color: #db2777;\n}\n\n.signed-out-title {\n font-size: 1.125rem;\n font-weight: 600;\n color: #171717;\n margin-bottom: 0.5rem;\n}\n\n.signed-out-subtitle {\n color: #525252;\n margin-bottom: 1rem;\n}\n\n.signed-out-button {\n background-color: #f3f4f6;\n color: #374151;\n width: auto;\n padding: 0.5rem 1.5rem;\n border: 1px solid #d1d5db;\n border-radius: 0.5rem;\n cursor: pointer;\n font-weight: 600;\n transition: all 0.2s ease;\n}\n\n.signed-out-button:hover {\n background-color: #e5e7eb;\n border-color: #9ca3af;\n}\n</style>","<template>\n <div class=\"accui-component-scope\">\n <svg \n viewBox=\"0 0 22571 9413\" \n xmlns=\"http://www.w3.org/2000/svg\" \n :class=\"class\"\n role=\"img\"\n aria-label=\"Strands Services Logo\"\n >\n <g>\n <text \n x=\"3798.06\" \n y=\"7203.65\" \n style=\"font-family:'CourierNewPS-BoldMT', 'Courier New', monospace;font-weight:700;font-size:5295.12px;fill:currentColor;\"\n >\n trands\n </text>\n </g>\n <g>\n <path \n d=\"M2370.75,8047.43c-172.831,0 -349.758,-28.381 -520.19,-86.274c-362.325,-122.988 -626.515,-354.842 -724.651,-635.835c-94.464,-270.121 -70.883,-674.383 204.038,-923.606c318.411,-288.759 731.429,-170.714 1168.59,-45.891c186.811,53.375 395.367,112.962 625.668,152.923c-0.424,-11.579 -0.988,-21.181 -1.412,-28.806c-14.12,-228.042 -92.911,-347.217 -223.524,-544.618c-83.592,-126.376 -178.48,-269.696 -272.097,-466.956c-74.978,-158.006 -138.096,-327.308 -188.082,-502.822c-408.216,-4.095 -801.606,-101.666 -1135.83,-290.313c-874.468,-493.079 -1531.48,-1711.66 -1068.34,-2543.62c195.283,-350.747 599.829,-639.082 1030.5,-734.394c321.095,-71.166 618.185,-23.298 836.343,134.707c228.183,165.207 391.131,461.309 425.16,772.66c29.371,267.862 -42.784,514.825 -203.049,695.423c-247.669,279.016 -675.371,371.786 -1089.66,236.232l175.515,-536.852c194.295,63.541 396.497,32.9 491.809,-74.414c68.059,-76.673 72.436,-183.14 64.105,-259.107c-18.356,-167.889 -111.973,-316.576 -195,-376.728c-85.569,-61.988 -221.547,-76.532 -382.8,-40.666c-271.533,60.152 -542.641,248.375 -659.133,457.778c-126.942,228.042 -103.784,560.433 63.541,912.027c171.137,359.643 465.968,682.997 788.616,865.007c216.181,121.999 473.593,192.882 744.843,211.097c-19.91,-172.69 -27.111,-345.522 -20.475,-513.977c23.864,-608.865 225.642,-1098.41 567.917,-1378.28c338.604,-276.898 921.487,-426.997 1334.79,-159.7c453.119,293.136 534.452,990.394 350.041,1468.36c-164.077,425.444 -583.307,786.075 -1150.24,989.406c-130.048,46.738 -262.355,83.451 -395.226,110.28c35.583,109.432 77.379,215.192 125.105,315.446c76.673,161.253 156.17,281.558 233.126,397.767c150.521,227.619 292.854,442.67 316.152,821.517c1.694,28.522 3.248,65.659 3.53,109.431c88.534,-1.694 179.61,-7.766 273.086,-19.344c234.819,-28.947 692.521,-185.215 954.251,-408.635l202.34,499.143c-286.222,212.469 -804.15,435.189 -1087.4,470.066c-144.592,17.791 -283.817,24.851 -417.395,24.004c-75.684,261.648 -223.665,536.852 -507.34,722.674c-206.438,135.272 -466.251,204.885 -736.795,204.885l-0.424,0Zm-542.076,-1260.51c-52.669,-0 -93.617,9.743 -119.316,33.182c-79.073,71.731 -79.78,234.114 -50.127,318.977c38.69,110.702 185.116,223.523 373.057,287.347c271.956,92.346 572.576,70.319 765.882,-56.34c114.374,-74.837 189.353,-185.258 238.209,-303.303c-263.484,-45.185 -495.48,-111.409 -693.022,-167.89c-205.873,-58.881 -391.978,-111.973 -514.683,-111.973Zm1872.91,-4019.61c-153.346,0 -336.768,62.27 -471.193,172.126c-212.227,173.538 -343.828,524.708 -361.055,963.283c-5.93,149.393 1.271,302.88 20.192,455.802c110.421,-21.463 219.994,-51.257 327.167,-89.805c406.239,-145.721 710.531,-392.966 814.032,-661.11c98.842,-256.141 62.835,-666.052 -130.047,-790.875c-51.963,-33.606 -121.717,-49.421 -199.096,-49.421Z\" \n style=\"fill:currentColor;fill-rule:nonzero;\" \n />\n </g>\n </svg>\n </div>\n</template>\n\n<script setup lang=\"ts\">\ninterface Props {\n class?: string\n}\n\nwithDefaults(defineProps<Props>(), {\n class: ''\n})\n</script>","<template>\n <slot />\n</template>\n\n<script setup lang=\"ts\">\nimport { onMounted } from 'vue'\nimport { provideStrandsConfig, type StrandsAuthConfig } from '../composables/useStrandsConfig'\n\ninterface Props {\n config: StrandsAuthConfig\n}\n\nconst props = defineProps<Props>()\n\n// Provide the configuration to all child components\nonMounted(() => {\n provideStrandsConfig(props.config)\n})\n\n// Also provide immediately for SSR compatibility\nprovideStrandsConfig(props.config)\n</script>\n","<template>\n <svg :class=\"iconClass\" :fill=\"fill\" :stroke=\"stroke\" :viewBox=\"viewBox\" :aria-hidden=\"ariaHidden\">\n <component :is=\"iconComponent\" />\n </svg>\n</template>\n\n<script setup lang=\"ts\">\nimport { computed, h as createElement } from 'vue'\n\ninterface Props {\n name: string\n class?: string\n size?: 'xs' | 'sm' | 'md' | 'lg' | 'xl'\n fill?: string\n stroke?: string\n ariaHidden?: boolean\n}\n\nconst props = withDefaults(defineProps<Props>(), {\n class: '',\n size: 'md',\n fill: 'none',\n stroke: 'currentColor',\n ariaHidden: true\n})\n\nconst sizeClasses = {\n xs: 'w-3 h-3',\n sm: 'w-4 h-4',\n md: 'w-5 h-5',\n lg: 'w-6 h-6',\n xl: 'w-8 h-8'\n}\n\nconst iconClass = computed(() => `${sizeClasses[props.size]} ${props.class}`)\nconst viewBox = computed(() => '0 0 24 24')\n\nconst icons = {\n 'eye': () => createElement('g', [\n createElement('path', { \n 'stroke-linecap': 'round', \n 'stroke-linejoin': 'round', \n 'stroke-width': '2', \n d: 'M15 12a3 3 0 11-6 0 3 3 0 016 0z' \n }),\n createElement('path', { \n 'stroke-linecap': 'round', \n 'stroke-linejoin': 'round', \n 'stroke-width': '2',\n d: 'M2.458 12C3.732 7.943 7.523 5 12 5c4.478 0 8.268 2.943 9.542 7-1.274 4.057-5.064 7-9.542 7-4.477 0-8.268-2.943-9.542-7z' \n })\n ]),\n 'eye-slash': () => createElement('g', [\n createElement('path', { \n 'stroke-linecap': 'round', \n 'stroke-linejoin': 'round', \n 'stroke-width': '2',\n d: 'M13.875 18.825A10.05 10.05 0 0112 19c-4.478 0-8.268-2.943-9.543-7a9.97 9.97 0 011.563-3.029m5.858.908a3 3 0 114.243 4.243M9.878 9.878l4.242 4.242M9.878 9.878L3 3m6.878 6.878L21 21' \n })\n ]),\n 'camera': () => createElement('path', { \n 'stroke-linecap': 'round', \n 'stroke-linejoin': 'round', \n 'stroke-width': '2', \n d: 'M3 9a2 2 0 012-2h.93a2 2 0 001.664-.89l.812-1.22A2 2 0 0710.07 4h3.86a2 2 0 011.664.89l.812 1.22A2 2 0 0018.07 7H19a2 2 0 012 2v9a2 2 0 01-2 2H5a2 2 0 01-2-2V9z' \n }),\n 'chevron-left': () => createElement('path', { \n 'stroke-linecap': 'round', \n 'stroke-linejoin': 'round', \n 'stroke-width': '2', \n d: 'M15 19l-7-7 7-7' \n }),\n 'loading': () => createElement('g', [\n createElement('circle', { \n class: 'opacity-25', \n cx: '12', \n cy: '12', \n r: '10', \n stroke: 'currentColor', \n 'stroke-width': '4' \n }),\n createElement('path', { \n class: 'opacity-75', \n fill: 'currentColor', \n d: 'm4 12a8 8 0 0 1 8-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 0 1 4 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z' \n })\n ]),\n 'check-circle': () => createElement('path', { \n 'fill-rule': 'evenodd', \n d: 'M10 18a8 8 0 100-16 8 8 0 000 16zm3.857-9.809a.75.75 0 00-1.214-.882l-3.236 4.53L7.53 10.173a.75.75 0 00-1.06 1.061l2.5 2.5a.75.75 0 001.137-.089l4-5.5z', \n 'clip-rule': 'evenodd' \n }),\n 'x-circle': () => createElement('path', { \n 'fill-rule': 'evenodd', \n d: 'M10 18a8 8 0 100-16 8 8 0 000 16zM8.28 7.22a.75.75 0 00-1.06 1.06L8.94 10l-1.72 1.72a.75.75 0 101.06 1.06L10 11.06l1.72 1.72a.75.75 0 101.06-1.06L11.06 10l1.72-1.72a.75.75 0 00-1.06-1.06L10 8.94 8.28 7.22z', \n 'clip-rule': 'evenodd' \n }),\n 'lock': () => createElement('path', { \n 'stroke-linecap': 'round', \n 'stroke-linejoin': 'round', \n 'stroke-width': '2', \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 'user': () => createElement('path', { \n 'stroke-linecap': 'round', \n 'stroke-linejoin': 'round', \n 'stroke-width': '2', \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 'google': () => createElement('g', { fill: 'currentColor' }, [\n createElement('path', { \n fill: '#4285F4', \n d: 'M22.56 12.25c0-.78-.07-1.53-.2-2.25H12v4.26h5.92c-.26 1.37-1.04 2.53-2.21 3.31v2.77h3.57c2.08-1.92 3.28-4.74 3.28-8.09z' \n }),\n createElement('path', { \n fill: '#34A853', \n d: 'M12 23c2.97 0 5.46-.98 7.28-2.66l-3.57-2.77c-.98.66-2.23 1.06-3.71 1.06-2.86 0-5.29-1.93-6.16-4.53H2.18v2.84C3.99 20.53 7.7 23 12 23z' \n }),\n createElement('path', { \n fill: '#FBBC05', \n d: 'M5.84 14.09c-.22-.66-.35-1.36-.35-2.09s.13-1.43.35-2.09V7.07H2.18C1.43 8.55 1 10.22 1 12s.43 3.45 1.18 4.93l2.85-2.22.81-.62z' \n }),\n createElement('path', { \n fill: '#EA4335', \n d: 'M12 5.38c1.62 0 3.06.56 4.21 1.64l3.15-3.15C17.45 2.09 14.97 1 12 1 7.7 1 3.99 3.47 2.18 7.07l3.66 2.84c.87-2.6 3.3-4.53 6.16-4.53z' \n })\n ]),\n 'github': () => createElement('path', { \n 'fill-rule': 'evenodd', \n d: 'M12 2C6.477 2 2 6.484 2 12.017c0 4.425 2.865 8.18 6.839 9.504.5.092.682-.217.682-.483 0-.237-.008-.868-.013-1.703-2.782.605-3.369-1.343-3.369-1.343-.454-1.158-1.11-1.466-1.11-1.466-.908-.62.069-.608.069-.608 1.003.07 1.531 1.032 1.531 1.032.892 1.53 2.341 1.088 2.91.832.092-.647.35-1.088.636-1.338-2.22-.253-4.555-1.113-4.555-4.951 0-1.093.39-1.988 1.029-2.688-.103-.253-.446-1.272.098-2.65 0 0 .84-.27 2.75 1.026A9.564 9.564 0 0112 6.844c.85.004 1.705.115 2.504.337 1.909-1.296 2.747-1.027 2.747-1.027.546 1.379.202 2.398.1 2.651.64.7 1.028 1.595 1.028 2.688 0 3.848-2.339 4.695-4.566 4.943.359.309.678.92.678 1.855 0 1.338-.012 2.419-.012 2.747 0 .268.18.58.688.482A10.019 10.019 0 0022 12.017C22 6.484 17.522 2 12 2z', \n 'clip-rule': 'evenodd' \n })\n}\n\nconst iconComponent = computed(() => {\n const icon = icons[props.name as keyof typeof icons]\n return icon ? icon() : createElement('path', { d: '' })\n})\n</script>\n","<template>\n <div class=\"accui-component-scope\" ref=\"containerRef\">\n <SignedIn :invert=\"!!props.user\">\n <!-- Signed In State - User Button Trigger -->\n <button @click=\"toggleDropdown\" @keydown.enter=\"toggleDropdown\" @keydown.space.prevent=\"toggleDropdown\"\n @keydown.escape=\"closeDropdown\" @keydown.arrow-down.prevent=\"openDropdown\"\n class=\"user-button\"\n aria-haspopup=\"true\" :aria-expanded=\"showDropdown\" aria-label=\"User menu\">\n <div class=\"user-button-content\">\n <!-- User Info -->\n <div v-if=\"!hideUser\" class=\"user-info\">\n <div class=\"user-name\">\n {{ displayName }}\n </div>\n </div>\n\n <!-- Avatar with Level Progress Ring -->\n <div class=\"avatar-container\">\n <div class=\"avatar-wrapper\">\n <!-- Avatar Image -->\n <img v-if=\"user?.avatar\" :src=\"user.avatar\" :alt=\"`${user.firstName || user.email}'s avatar`\"\n class=\"avatar-image\" />\n\n <!-- Default Avatar -->\n <div v-else class=\"avatar-default\">\n <svg class=\"avatar-icon\" fill=\"currentColor\" viewBox=\"0 0 20 20\">\n <path fill-rule=\"evenodd\" d=\"M10 9a3 3 0 100-6 3 3 0 000 6zm-7 9a7 7 0 1114 0H3z\"\n clip-rule=\"evenodd\" />\n </svg>\n </div>\n </div>\n </div>\n\n <!-- Dropdown Arrow -->\n <svg class=\"dropdown-arrow\" :class=\"{ 'dropdown-arrow-open': showDropdown }\" fill=\"none\" stroke=\"currentColor\"\n viewBox=\"0 0 24 24\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M19 9l-7 7-7-7\" />\n </svg>\n </div>\n\n <!-- Dropdown Menu -->\n <Transition name=\"dropdown\">\n <div v-if=\"showDropdown\"\n :class=\"[\n 'dropdown-menu',\n `dropdown-menu-align-${props.menuAlign}`,\n `dropdown-menu-vertical-${props.menuVerticalAlign}`\n ]\"\n role=\"menu\" aria-orientation=\"vertical\" @keydown.escape=\"closeDropdown\"\n @keydown.arrow-up.prevent=\"focusPrevious\" @keydown.arrow-down.prevent=\"focusNext\"\n @keydown.home.prevent=\"focusFirst\" @keydown.end.prevent=\"focusLast\">\n <div class=\"dropdown-content\">\n <!-- User Info Header -->\n <div class=\"dropdown-header\">\n <div v-if=\"user\" class=\"dropdown-avatar-container\">\n <StrandsUiLevelProgress :size=\"80\" :value=\"user.xp\" :max=\"user.next_level_xp\" :level=\"user.level\"\n :level-label=\"`LEVEL ${user.level}`\" :user-settings=\"user.settings\"\n class=\"level-progress-overlay\" />\n <img v-if=\"user?.avatar\" :src=\"user.avatar\" :alt=\"`${user.firstName || user.email}'s avatar`\"\n class=\"dropdown-avatar-image\" />\n <div v-else class=\"dropdown-avatar-default\">\n <svg class=\"dropdown-avatar-icon\" fill=\"currentColor\" viewBox=\"0 0 20 20\">\n <path fill-rule=\"evenodd\" d=\"M10 9a3 3 0 100-6 3 3 0 000 6zm-7 9a7 7 0 1114 0H3z\"\n clip-rule=\"evenodd\" />\n </svg>\n </div>\n </div>\n <div class=\"dropdown-user-details\">\n <div class=\"dropdown-user-name\">{{ displayName }}</div>\n <div class=\"dropdown-user-email\">{{ user?.email }}</div>\n </div>\n </div>\n\n <div class=\"dropdown-divider\"></div>\n\n <!-- Menu Items -->\n <div class=\"dropdown-menu-items\">\n <button ref=\"profileButtonRef\" @click=\"openProfile\"\n class=\"dropdown-menu-item\"\n role=\"menuitem\" tabindex=\"-1\">\n <svg class=\"dropdown-menu-icon\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\"\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 </svg>\n Profile\n </button>\n\n <button @click=\"handleSignOut\"\n class=\"dropdown-menu-item dropdown-menu-item-danger\"\n role=\"menuitem\" tabindex=\"-1\">\n <svg class=\"dropdown-menu-icon dropdown-menu-icon-danger\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\"\n d=\"M17 16l4-4m0 0l-4-4m4 4H7m6 4v1a3 3 0 01-3 3H6a3 3 0 01-3-3V7a3 3 0 013-3h4a3 3 0 013 3v1\" />\n </svg>\n Sign Out\n </button>\n </div>\n </div>\n </div>\n </Transition>\n </button>\n\n <!-- Profile Modal -->\n <StrandsUiModal :open=\"showProfileModal\" @close=\"closeProfile\" :fullscreen-on-mobile=\"false\">\n <template #header>\n <div class=\"modal-header\">\n <h2 class=\"modal-title\">User Profile</h2>\n <button @click=\"closeProfile\"\n class=\"modal-close-button\"\n aria-label=\"Close profile\">\n <svg class=\"modal-close-icon\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M6 18L18 6M6 6l12 12\" />\n </svg>\n </button>\n </div>\n </template>\n\n <StrandsUserProfile :user=\"user\" @profile-updated=\"handleProfileUpdated\" @error=\"handleProfileError\" in-modal />\n </StrandsUiModal>\n\n <!-- Fallback Slot - Sign In Button (shown when not authenticated) -->\n <template #fallback>\n <button @click=\"openSignIn\"\n class=\"sign-in-button\"\n aria-label=\"Sign in\">\n <svg class=\"sign-in-icon\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\"\n d=\"M11 16l-4-4m0 0l4-4m-4 4h14m-5 4v1a3 3 0 01-3 3H6a3 3 0 01-3-3V7a3 3 0 013-3h7a3 3 0 013 3v1\" />\n </svg>\n <span>Sign In</span>\n </button>\n\n <!-- Sign In Modal -->\n <StrandsUiModal :open=\"showSignInModal\" @close=\"closeSignIn\" :fullscreen-on-mobile=\"false\">\n <template #header>\n <div class=\"modal-header\">\n <h2 class=\"modal-title\">Sign In</h2>\n <button @click=\"closeSignIn\"\n class=\"modal-close-button\"\n aria-label=\"Close sign in\">\n <svg class=\"modal-close-icon\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M6 18L18 6M6 6l12 12\" />\n </svg>\n </button>\n </div>\n </template>\n\n <StrandsAuth @signed-in=\"handleSignedIn\" @error=\"handleSignInError\" :redirect-url=\"redirectUrl\" in-modal />\n </StrandsUiModal>\n </template>\n </SignedIn>\n </div>\n</template>\n\n<script setup lang=\"ts\">\nimport { ref, computed, nextTick, onMounted, onUnmounted } from 'vue'\nimport { useStrandsAuth } from '../composables/useStrandsAuth'\nimport { StrandsUiLevelProgress, StrandsUiModal } from '../ui'\nimport { StrandsAuth, StrandsUserProfile, SignedIn } from '.'\nimport { User } from '../../types'\n\ninterface Props {\n hideUser?: boolean\n variant?: 'minimal' | 'compact' | 'full'\n redirectUrl?: string\n user?: User,\n menuAlign?: 'left' | 'right' | 'center'\n menuVerticalAlign?: 'bottom' | 'top'\n}\n\nconst props = withDefaults(defineProps<Props>(), {\n hideUser: false,\n variant: 'minimal',\n redirectUrl: '/',\n user: undefined,\n menuAlign: 'right',\n menuVerticalAlign: 'bottom'\n})\n\nconst emit = defineEmits<{\n 'profile-updated': []\n 'signed-out': []\n 'signed-in': []\n}>()\n\n// Auth composable\nconst { currentUser, signOut } = useStrandsAuth()\n\n// Component state\nconst showDropdown = ref(false)\nconst showProfileModal = ref(false)\nconst showSignInModal = ref(false)\nconst containerRef = ref<HTMLElement>()\nconst profileButtonRef = ref<HTMLButtonElement>()\n\nconst user = computed(() => props.user || currentUser.value)\n\n// User display logic\nconst displayName = computed(() => {\n if (!user.value) return 'User'\n\n if (user.value.username) {\n return user.value.username\n }\n\n if (user.value.firstName && user.value.lastName) {\n return `${user.value.firstName} ${user.value.lastName}`\n }\n\n if (user.value.firstName) {\n return user.value.firstName\n }\n\n return user.value.email || 'User'\n})\n\n// Dropdown management\nconst toggleDropdown = () => {\n showDropdown.value = !showDropdown.value\n\n if (showDropdown.value) {\n nextTick(() => {\n profileButtonRef.value?.focus()\n })\n }\n}\n\nconst openDropdown = () => {\n showDropdown.value = true\n nextTick(() => {\n profileButtonRef.value?.focus()\n })\n}\n\nconst closeDropdown = () => {\n showDropdown.value = false\n}\n\n// Keyboard navigation for dropdown\nconst focusNext = () => {\n // Simple implementation - can be enhanced\n}\n\nconst focusPrevious = () => {\n // Simple implementation - can be enhanced\n}\n\nconst focusFirst = () => {\n profileButtonRef.value?.focus()\n}\n\nconst focusLast = () => {\n // Focus the last item (sign out button)\n}\n\n// Profile modal management\nconst openProfile = () => {\n showProfileModal.value = true\n closeDropdown()\n}\n\nconst closeProfile = () => {\n showProfileModal.value = false\n}\n\nconst handleProfileUpdated = () => {\n emit('profile-updated')\n}\n\nconst handleProfileError = (error: string) => {\n console.error('Profile error:', error)\n}\n\n// Sign in modal management\nconst openSignIn = () => {\n showSignInModal.value = true\n}\n\nconst closeSignIn = () => {\n showSignInModal.value = false\n}\n\nconst handleSignedIn = () => {\n closeSignIn()\n emit('signed-in')\n}\n\nconst handleSignInError = (error: string) => {\n console.error('Sign in error:', error)\n}\n\n// Sign out handler\nconst handleSignOut = async () => {\n try {\n await signOut()\n closeDropdown()\n emit('signed-out')\n } catch (error) {\n console.error('Sign out error:', error)\n }\n}\n\n// Click outside to close dropdown\nconst handleClickOutside = (event: Event) => {\n if (containerRef.value && !containerRef.value.contains(event.target as Node)) {\n closeDropdown()\n }\n}\n\nonMounted(() => {\n document.addEventListener('click', handleClickOutside)\n})\n\nonUnmounted(() => {\n document.removeEventListener('click', handleClickOutside)\n})\n</script>\n\n<style scoped>\n/* User Button */\n.user-button {\n position: relative;\n display: flex;\n align-items: center;\n padding: 0.5rem 0.75rem;\n border-radius: 9999px;\n background-color: #f3f4f6;\n color: #111827;\n font-size: 0.875rem;\n font-weight: 500;\n border: none;\n cursor: pointer;\n transition: all 0.15s;\n}\n\n.user-button:hover {\n background-color: #d1d5db;\n}\n\n.user-button:focus {\n outline: none;\n box-shadow: 0 0 0 2px #EA00A8;\n}\n\n.user-button-content {\n display: flex;\n align-items: center;\n gap: 0.75rem;\n}\n\n.user-info {\n display: flex;\n flex-direction: column;\n align-items: flex-start;\n}\n\n.user-name {\n font-size: 0.875rem;\n font-weight: 500;\n color: #111827;\n}\n\n.avatar-container {\n position: relative;\n flex-shrink: 0;\n}\n\n.avatar-wrapper {\n position: relative;\n width: 2rem;\n height: 2rem;\n}\n\n.avatar-image {\n width: 2rem;\n height: 2rem;\n border-radius: 50%;\n object-fit: cover;\n}\n\n.avatar-default {\n width: 2rem;\n height: 2rem;\n border-radius: 50%;\n background-color: #e5e7eb;\n display: flex;\n align-items: center;\n justify-content: center;\n}\n\n.avatar-icon {\n width: 1.25rem;\n height: 1.25rem;\n color: #6b7280;\n}\n\n.dropdown-arrow {\n width: 1rem;\n height: 1rem;\n color: #9ca3af;\n transition: transform 0.15s;\n}\n\n.dropdown-arrow-open {\n transform: rotate(180deg);\n}\n\n/* Dropdown Menu */\n.dropdown-menu {\n position: absolute;\n width: 18rem;\n background: white;\n border-radius: 0.5rem;\n box-shadow: 0 10px 15px -3px rgb(0 0 0 / 0.1), 0 4px 6px -2px rgb(0 0 0 / 0.05);\n border: 1px solid #e5e7eb;\n z-index: 50;\n}\n\n/* Horizontal alignment */\n.dropdown-menu-align-left {\n left: 0;\n}\n\n.dropdown-menu-align-right {\n right: 0;\n}\n\n.dropdown-menu-align-center {\n left: 50%;\n transform: translateX(-50%);\n}\n\n/* Vertical alignment */\n.dropdown-menu-vertical-bottom {\n top: 100%;\n margin-top: 0.5rem;\n}\n\n.dropdown-menu-vertical-top {\n bottom: 100%;\n margin-bottom: 0.5rem;\n}\n\n/* Center horizontal alignment needs special handling for transforms */\n.dropdown-menu-align-center.dropdown-menu-vertical-bottom {\n transform: translateX(-50%);\n}\n\n.dropdown-menu-align-center.dropdown-menu-vertical-top {\n transform: translateX(-50%);\n}\n\n.dropdown-content {\n padding: 0.5rem;\n}\n\n.dropdown-header {\n display: flex;\n align-items: center;\n gap: 1rem;\n padding: 0.75rem;\n border-radius: 0.5rem;\n background-color: #f9fafb;\n}\n\n.dropdown-avatar-container {\n position: relative;\n}\n\n.level-progress-overlay {\n position: absolute;\n z-index: 10;\n top: 50%;\n left: 50%;\n transform: translate(-50%, -50%);\n pointer-events: none;\n}\n\n.dropdown-avatar-image {\n width: 3.5rem;\n height: 3.5rem;\n border-radius: 50%;\n object-fit: cover;\n}\n\n.dropdown-avatar-default {\n width: 3.5rem;\n height: 3.5rem;\n border-radius: 50%;\n background-color: #e5e7eb;\n display: flex;\n align-items: center;\n justify-content: center;\n}\n\n.dropdown-avatar-icon {\n width: 1.25rem;\n height: 1.25rem;\n color: #6b7280;\n}\n\n.dropdown-user-details {\n flex: 1;\n min-width: 0;\n text-align: left;\n}\n\n.dropdown-user-name {\n font-size: 0.875rem;\n font-weight: 500;\n color: #111827;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n.dropdown-user-email {\n font-size: 0.875rem;\n color: #6b7280;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n.dropdown-divider {\n height: 1px;\n background-color: #e5e7eb;\n margin: 0.5rem 0;\n}\n\n.dropdown-menu-items {\n display: flex;\n flex-direction: column;\n gap: 0.25rem;\n}\n\n.dropdown-menu-item {\n width: 100%;\n display: flex;\n align-items: center;\n gap: 0.75rem;\n padding: 0.5rem 0.75rem;\n font-size: 0.875rem;\n color: #374151;\n border-radius: 0.5rem;\n border: none;\n background: none;\n cursor: pointer;\n transition: all 0.15s;\n text-align: left;\n}\n\n.dropdown-menu-item:hover,\n.dropdown-menu-item:focus {\n background-color: #f3f4f6;\n outline: none;\n}\n\n.dropdown-menu-item-danger {\n color: #dc2626;\n}\n\n.dropdown-menu-item-danger:hover,\n.dropdown-menu-item-danger:focus {\n background-color: #fef2f2;\n}\n\n.dropdown-menu-icon {\n width: 1rem;\n height: 1rem;\n color: #9ca3af;\n}\n\n.dropdown-menu-icon-danger {\n color: #ef4444;\n}\n\n/* Sign In Button */\n.sign-in-button {\n position: relative;\n display: flex;\n align-items: center;\n gap: 0.5rem;\n padding: 0.5rem 1rem;\n border-radius: 9999px;\n background-color: #EA00A8;\n color: white;\n font-size: 0.875rem;\n font-weight: 500;\n border: none;\n cursor: pointer;\n transition: all 0.15s;\n}\n\n.sign-in-button:hover {\n background-color: #B8006F;\n}\n\n.sign-in-button:focus {\n outline: none;\n box-shadow: 0 0 0 2px #EA00A8, 0 0 0 4px white;\n}\n\n.sign-in-icon {\n width: 1rem;\n height: 1rem;\n}\n\n/* Modal Styles */\n.modal-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n}\n\n.modal-title {\n font-size: 1.25rem;\n font-weight: 600;\n color: #111827;\n}\n\n.modal-close-button {\n padding: 0.25rem;\n border-radius: 0.5rem;\n color: #9ca3af;\n background: none;\n border: none;\n cursor: pointer;\n transition: all 0.2s;\n}\n\n.modal-close-button:hover {\n color: #6b7280;\n background-color: #f3f4f6;\n}\n\n.modal-close-icon {\n width: 1.25rem;\n height: 1.25rem;\n}\n\n/* Transitions */\n.dropdown-enter-active,\n.dropdown-leave-active {\n transition: all 0.15s ease;\n}\n\n.dropdown-enter-from,\n.dropdown-leave-to {\n opacity: 0;\n}\n\n.dropdown-enter-to,\n.dropdown-leave-from {\n opacity: 1;\n}\n\n/* Transform-based transitions for different alignments */\n.dropdown-menu-align-left.dropdown-enter-from,\n.dropdown-menu-align-left.dropdown-leave-to {\n transform: scale(0.95) translateY(4px);\n}\n\n.dropdown-menu-align-left.dropdown-enter-to,\n.dropdown-menu-align-left.dropdown-leave-from {\n transform: scale(1) translateY(0);\n}\n\n.dropdown-menu-align-right.dropdown-enter-from,\n.dropdown-menu-align-right.dropdown-leave-to {\n transform: scale(0.95) translateY(4px);\n}\n\n.dropdown-menu-align-right.dropdown-enter-to,\n.dropdown-menu-align-right.dropdown-leave-from {\n transform: scale(1) translateY(0);\n}\n\n.dropdown-menu-align-center.dropdown-enter-from,\n.dropdown-menu-align-center.dropdown-leave-to {\n transform: translateX(-50%) scale(0.95) translateY(4px);\n}\n\n.dropdown-menu-align-center.dropdown-enter-to,\n.dropdown-menu-align-center.dropdown-leave-from {\n transform: translateX(-50%) scale(1) translateY(0);\n}\n\n/* Responsive adjustments */\n@media (max-width: 640px) {\n .dropdown-menu {\n width: 16rem;\n }\n \n .user-info {\n display: none;\n }\n}\n</style>","<template>\n <div \n ref=\"scrollContainer\" \n :style=\"{ height: containerHeight + 'px', overflowY: 'auto' }\"\n @scroll=\"handleScroll\"\n class=\"accui-virtual-list\"\n >\n <div :style=\"{ height: totalHeight + 'px', position: 'relative' }\">\n <div \n v-for=\"item in visibleItems\" \n :key=\"getItemKey(item.data)\"\n :style=\"{\n position: 'absolute',\n top: item.top + 'px',\n left: 0,\n right: 0,\n height: itemHeight + 'px'\n }\"\n >\n <slot :item=\"item.data\" :index=\"item.index\">\n <!-- Default fallback -->\n <div class=\"accui-p-2 accui-border-b\">\n {{ JSON.stringify(item.data) }}\n </div>\n </slot>\n </div>\n </div>\n </div>\n</template>\n\n<script setup lang=\"ts\">\nimport { ref, computed, onMounted, onUnmounted, nextTick } from 'vue'\n\ninterface Props {\n items: any[]\n itemHeight: number\n containerHeight: number\n itemKey?: string | ((item: any) => string | number)\n overscan?: number\n}\n\nconst props = withDefaults(defineProps<Props>(), {\n itemKey: 'id',\n overscan: 5\n})\n\nconst scrollContainer = ref<HTMLElement>()\nconst scrollTop = ref(0)\n\n// Calculate visible range\nconst visibleRange = computed(() => {\n const start = Math.floor(scrollTop.value / props.itemHeight)\n const end = Math.min(\n start + Math.ceil(props.containerHeight / props.itemHeight),\n props.items.length - 1\n )\n \n return {\n start: Math.max(0, start - props.overscan),\n end: Math.min(props.items.length - 1, end + props.overscan)\n }\n})\n\n// Get visible items with positioning\nconst visibleItems = computed(() => {\n const { start, end } = visibleRange.value\n const items = []\n \n for (let i = start; i <= end; i++) {\n items.push({\n index: i,\n data: props.items[i],\n top: i * props.itemHeight\n })\n }\n \n return items\n})\n\n// Total height of all items\nconst totalHeight = computed(() => props.items.length * props.itemHeight)\n\n// Get item key function\nconst getItemKey = (item: any): string | number => {\n if (typeof props.itemKey === 'function') {\n return props.itemKey(item)\n }\n return item[props.itemKey] || item.id || Math.random()\n}\n\n// Handle scroll events with throttling\nlet scrollTimer: NodeJS.Timeout | null = null\nconst handleScroll = (event: Event) => {\n if (scrollTimer) {\n clearTimeout(scrollTimer)\n }\n \n scrollTimer = setTimeout(() => {\n const target = event.target as HTMLElement\n scrollTop.value = target.scrollTop\n }, 16) // ~60fps\n}\n\n// Cleanup\nonUnmounted(() => {\n if (scrollTimer) {\n clearTimeout(scrollTimer)\n }\n})\n\n// Scroll to item function\nconst scrollToItem = (index: number, align: 'start' | 'center' | 'end' = 'start') => {\n if (!scrollContainer.value) return\n \n let scrollTo = index * props.itemHeight\n \n if (align === 'center') {\n scrollTo -= props.containerHeight / 2 - props.itemHeight / 2\n } else if (align === 'end') {\n scrollTo -= props.containerHeight - props.itemHeight\n }\n \n scrollContainer.value.scrollTop = Math.max(0, scrollTo)\n}\n\n// Expose methods\ndefineExpose({\n scrollToItem\n})\n</script>\n\n<style scoped>\n.accui-virtual-list {\n /* Improve scrolling performance */\n will-change: scroll-position;\n -webkit-overflow-scrolling: touch;\n}\n\n.accui-virtual-list::-webkit-scrollbar {\n width: 8px;\n}\n\n.accui-virtual-list::-webkit-scrollbar-track {\n background: rgba(0, 0, 0, 0.1);\n border-radius: 4px;\n}\n\n.accui-virtual-list::-webkit-scrollbar-thumb {\n background: rgba(0, 0, 0, 0.3);\n border-radius: 4px;\n}\n\n.accui-virtual-list::-webkit-scrollbar-thumb:hover {\n background: rgba(0, 0, 0, 0.5);\n}\n</style>","<template>\n <div class=\"accui-component-scope\">\n <UiModal :open=\"show\" @close=\"closeModal\" card-class=\"mfa-setup-modal\">\n <template #header>\n <div class=\"mfa-setup-header\">\n <div>\n <h2 class=\"mfa-setup-title\">Two-Factor Authentication</h2>\n <p class=\"mfa-setup-subtitle\">Add extra security to your account</p>\n </div>\n <div class=\"mfa-setup-status-container\">\n <span class=\"mfa-setup-status-badge\"\n :class=\"mfaEnabled || activeMfaDevices.length > 0 ? 'mfa-setup-status-enabled' : 'mfa-setup-status-disabled'\">\n {{ mfaEnabled || activeMfaDevices.length > 0 ? 'Enabled' : 'Not Enabled' }}\n </span>\n </div>\n </div>\n </template>\n\n <div class=\"mfa-setup-content\">\n <!-- Loading State -->\n <div v-if=\"loading\" class=\"mfa-setup-loading\">\n <StrandsUiLoader :size=\"32\" />\n <span class=\"mfa-setup-loading-text\">Loading MFA settings...</span>\n </div>\n\n <!-- MFA Options -->\n <div v-else class=\"mfa-setup-sections\">\n <!-- Current MFA Status -->\n <div v-if=\"mfaEnabled || activeMfaDevices.length > 0\" class=\"mfa-setup-status-alert\">\n <div class=\"mfa-setup-status-content\">\n <div class=\"mfa-setup-status-icon\">\n <Shield :size=\"20\" class=\"mfa-setup-shield-icon\" />\n </div>\n <div>\n <span class=\"mfa-setup-status-title\">2FA is currently enabled on your account</span>\n <p class=\"mfa-setup-status-description\">Your account has additional security protection</p>\n </div>\n </div>\n </div>\n\n <!-- Setup Options -->\n <div>\n <h3 class=\"mfa-setup-methods-title\">Choose Your Authentication Method</h3>\n <div class=\"mfa-setup-methods-grid\">\n <!-- TOTP Setup -->\n <div class=\"mfa-setup-method-card\" @click=\"startTotpSetup\">\n <div class=\"mfa-setup-method-content\">\n <div class=\"mfa-setup-method-icon mfa-setup-totp-icon\">\n <Smartphone :size=\"28\" class=\"mfa-setup-icon-svg\" />\n </div>\n <div class=\"mfa-setup-method-info\">\n <h4 class=\"mfa-setup-method-title\">Authenticator App</h4>\n <p class=\"mfa-setup-method-description\">Use Google Authenticator, Authy, or any TOTP-compatible app\n to\n generate secure codes</p>\n </div>\n <StrandsUiButton variant=\"primary\" size=\"md\" @click.stop=\"startTotpSetup\" :disabled=\"loading\"\n class=\"mfa-setup-method-button\">\n Setup Authenticator\n </StrandsUiButton>\n </div>\n </div>\n\n <!-- Email MFA Setup -->\n <div class=\"mfa-setup-method-card\" @click=\"startEmailMfaSetup\">\n <div class=\"mfa-setup-method-content\">\n <div class=\"mfa-setup-method-icon mfa-setup-email-icon\">\n <Mail :size=\"28\" class=\"mfa-setup-icon-svg\" />\n </div>\n <div class=\"mfa-setup-method-info\">\n <h4 class=\"mfa-setup-method-title\">Email Verification</h4>\n <p class=\"mfa-setup-method-description\">Receive verification codes directly in your email inbox for\n easy\n access</p>\n </div>\n <StrandsUiButton variant=\"primary\" size=\"md\" @click.stop=\"startEmailMfaSetup\" :disabled=\"loading\"\n class=\"mfa-setup-method-button\">\n Setup Email 2FA\n </StrandsUiButton>\n </div>\n </div>\n </div>\n </div>\n\n <!-- Manage Existing -->\n <div v-if=\"activeMfaDevices.length > 0\" class=\"mfa-setup-manage-section\">\n <div class=\"mfa-setup-manage-header\">\n <div>\n <h3 class=\"mfa-setup-manage-title\">Manage Existing Methods</h3>\n <p class=\"mfa-setup-manage-description\">{{ activeMfaDevices.length }} device(s) currently active</p>\n </div>\n <StrandsUiButton variant=\"secondary\" size=\"md\" @click=\"openMfaModal\" :disabled=\"loading\">\n <Settings :size=\"16\" class=\"mfa-setup-manage-icon\" />\n Manage Devices\n </StrandsUiButton>\n </div>\n </div>\n </div>\n </div>\n\n <template #footer>\n <div class=\"mfa-setup-footer\">\n <StrandsUiButton variant=\"secondary\" @click=\"closeModal\" :disabled=\"loading\">\n Cancel\n </StrandsUiButton>\n </div>\n </template>\n </UiModal>\n\n <!-- TOTP Setup Modal -->\n <StrandsTotpSetupModal v-if=\"showTotpSetup\" :show=\"showTotpSetup\" @close=\"showTotpSetup = false\"\n @success=\"handleSetupSuccess\" />\n\n <!-- Email MFA Setup Modal -->\n <StrandsEmailMfaSetupModal v-if=\"showEmailMfaSetup\" :show=\"showEmailMfaSetup\" @close=\"showEmailMfaSetup = false\"\n @success=\"handleSetupSuccess\" />\n\n <!-- Hardware Key Setup Modal -->\n <StrandsHardwareKeySetupModal v-if=\"showHardwareKeySetup\" :show=\"showHardwareKeySetup\"\n @close=\"showHardwareKeySetup = false\" @success=\"handleSetupSuccess\" />\n\n <!-- Full MFA Management Modal -->\n <StrandsMfaModal v-if=\"showMfaModal\" :show=\"showMfaModal\" @close=\"showMfaModal = false\"\n @mfa-updated=\"handleMfaUpdated\" />\n </div>\n</template>\n\n<script setup lang=\"ts\">\nimport { ref, watch, onMounted, h } from 'vue'\nimport { StrandsUiButton, StrandsUiLoader } from '../ui'\nimport UiModal from '../ui/UiModal.vue'\nimport StrandsTotpSetupModal from './StrandsTotpSetupModal.vue'\nimport StrandsEmailMfaSetupModal from './StrandsEmailMfaSetupModal.vue'\nimport StrandsHardwareKeySetupModal from './StrandsHardwareKeySetupModal.vue'\nimport StrandsMfaModal from './StrandsMfaModal.vue'\nimport { useStrandsMfa } from '../composables/useStrandsMfa'\n\n// Inline SVG icon components using render functions (no runtime compilation needed)\nconst Smartphone = {\n props: {\n size: {\n type: [String, Number],\n default: 24\n }\n },\n render(this: any) {\n return h('svg', { \n width: this.size, \n height: this.size, \n fill: 'none', \n stroke: 'currentColor', \n viewBox: '0 0 24 24' \n }, [\n h('rect', { x: '5', y: '2', width: '14', height: '20', rx: '2', ry: '2' }),\n h('line', { x1: '12', y1: '18', x2: '12.01', y2: '18' })\n ])\n }\n}\n\nconst Mail = {\n props: {\n size: {\n type: [String, Number],\n default: 24\n }\n },\n render(this: any) {\n return h('svg', { \n width: this.size, \n height: this.size, \n fill: 'none', \n stroke: 'currentColor', \n viewBox: '0 0 24 24' \n }, [\n h('path', { d: 'm4 4 16 0c1.1 0 2 .9 2 2l0 12c0 1.1-.9 2-2 2l-16 0c-1.1 0-2-.9-2-2l0-12c0-1.1.9-2 2-2z' }),\n h('polyline', { points: '22,6 12,13 2,6' })\n ])\n }\n}\n\nconst KeyRound = {\n props: {\n size: {\n type: [String, Number],\n default: 24\n }\n },\n render(this: any) {\n return h('svg', { \n width: this.size, \n height: this.size, \n fill: 'none', \n stroke: 'currentColor', \n viewBox: '0 0 24 24' \n }, [\n h('path', { d: 'M2.586 17.414A2 2 0 0 0 2 18.828V21a1 1 0 0 0 1 1h3a1 1 0 0 0 1-1v-1a1 1 0 0 1 1-1h1a1 1 0 0 0 1-1v-1a1 1 0 0 1 1-1h.172a2 2 0 0 0 1.414-.586l.814-.814a6.5 6.5 0 1 0-4-4z' }),\n h('circle', { cx: '16.5', cy: '7.5', r: '.5', fill: 'currentColor' })\n ])\n }\n}\n\nconst Shield = {\n props: {\n size: {\n type: [String, Number],\n default: 24\n }\n },\n render(this: any) {\n return h('svg', { \n width: this.size, \n height: this.size, \n fill: 'none', \n stroke: 'currentColor', \n viewBox: '0 0 24 24' \n }, [\n h('path', { d: 'M20 13c0 5-3.5 7.5-7.66 8.95a1 1 0 0 1-.67-.01C7.5 20.5 4 18 4 13V6a1 1 0 0 1 1-1c2 0 4.5-1.2 6.24-2.72a1.17 1.17 0 0 1 1.52 0C14.51 3.81 17 5 19 5a1 1 0 0 1 1 1z' })\n ])\n }\n}\n\nconst Settings = {\n props: {\n size: {\n type: [String, Number],\n default: 24\n }\n },\n render(this: any) {\n return h('svg', { \n width: this.size, \n height: this.size, \n fill: 'none', \n stroke: 'currentColor', \n viewBox: '0 0 24 24' \n }, [\n h('path', { d: 'M12.22 2h-.44a2 2 0 0 0-2 2v.18a2 2 0 0 1-1 1.73l-.43.25a2 2 0 0 1-2 0l-.15-.08a2 2 0 0 0-2.73.73l-.22.38a2 2 0 0 0 .73 2.73l.15.1a2 2 0 0 1 1 1.72v.51a2 2 0 0 1-1 1.74l-.15.09a2 2 0 0 0-.73 2.73l.22.38a2 2 0 0 0 2.73.73l.15-.08a2 2 0 0 1 2 0l.43.25a2 2 0 0 1 1 1.73V20a2 2 0 0 0 2 2h.44a2 2 0 0 0 2-2v-.18a2 2 0 0 1 1-1.73l.43-.25a2 2 0 0 1 2 0l.15.08a2 2 0 0 0 2.73-.73l.22-.39a2 2 0 0 0-.73-2.73l-.15-.08a2 2 0 0 1-1-1.74v-.5a2 2 0 0 1 1-1.74l.15-.09a2 2 0 0 0 .73-2.73l-.22-.38a2 2 0 0 0-2.73-.73l-.15.08a2 2 0 0 1-2 0l-.43-.25a2 2 0 0 1-1-1.73V4a2 2 0 0 0-2-2z' }),\n h('circle', { cx: '12', cy: '12', r: '3' })\n ])\n }\n}\n\ninterface Props {\n show?: boolean\n}\n\ninterface Emits {\n (e: 'success'): void\n (e: 'error', error: string): void\n (e: 'close'): void\n}\n\nconst props = withDefaults(defineProps<Props>(), {\n show: false\n})\n\nconst emit = defineEmits<Emits>()\n\nconst {\n mfaDevices,\n mfaEnabled,\n loading,\n activeMfaDevices,\n fetchMfaDevices,\n} = useStrandsMfa()\n\n// Modal states\nconst showTotpSetup = ref(false)\nconst showEmailMfaSetup = ref(false)\nconst showHardwareKeySetup = ref(false)\nconst showMfaModal = ref(false)\n\n// Load MFA devices when modal opens\nwatch(() => props.show, async (newShow) => {\n if (newShow) {\n await fetchMfaDevices()\n }\n})\n\nonMounted(async () => {\n if (props.show) {\n await fetchMfaDevices()\n }\n})\n\nconst closeModal = () => {\n emit('close')\n}\n\nconst startTotpSetup = () => {\n showTotpSetup.value = true\n}\n\nconst startEmailMfaSetup = () => {\n showEmailMfaSetup.value = true\n}\n\nconst startHardwareKeySetup = () => {\n showHardwareKeySetup.value = true\n}\n\nconst openMfaModal = () => {\n showMfaModal.value = true\n}\n\nconst handleSetupSuccess = async () => {\n showTotpSetup.value = false\n showEmailMfaSetup.value = false\n showHardwareKeySetup.value = false\n await fetchMfaDevices()\n emit('success')\n}\n\nconst handleMfaUpdated = async () => {\n await fetchMfaDevices()\n}\n</script>\n\n<style scoped>\n/* Header */\n.mfa-setup-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n}\n\n.mfa-setup-title {\n font-size: 1.5rem;\n font-weight: 700;\n color: #111827;\n}\n\n.mfa-setup-subtitle {\n color: #6b7280;\n margin-top: 0.25rem;\n}\n\n.mfa-setup-status-container {\n text-align: right;\n}\n\n.mfa-setup-status-badge {\n display: inline-flex;\n align-items: center;\n padding: 0.25rem 0.75rem;\n border-radius: 9999px;\n font-size: 0.875rem;\n font-weight: 500;\n}\n\n.mfa-setup-status-enabled {\n background-color: #dcfce7;\n color: #166534;\n}\n\n.mfa-setup-status-disabled {\n background-color: #f3f4f6;\n color: #374151;\n}\n\n/* Content */\n.mfa-setup-content {\n display: flex;\n flex-direction: column;\n gap: 2rem;\n}\n\n.mfa-setup-loading {\n display: flex;\n align-items: center;\n justify-content: center;\n padding: 4rem 0;\n}\n\n.mfa-setup-loading-text {\n margin-left: 0.75rem;\n color: #6b7280;\n}\n\n.mfa-setup-sections {\n display: flex;\n flex-direction: column;\n gap: 2rem;\n}\n\n/* Status alert */\n.mfa-setup-status-alert {\n background-color: #f0fdf4;\n border: 1px solid #bbf7d0;\n border-radius: 0.75rem;\n padding: 1.5rem;\n}\n\n.mfa-setup-status-content {\n display: flex;\n align-items: center;\n gap: 0.75rem;\n}\n\n.mfa-setup-status-icon {\n width: 2.5rem;\n height: 2.5rem;\n background-color: #dcfce7;\n border-radius: 50%;\n display: flex;\n align-items: center;\n justify-content: center;\n}\n\n.mfa-setup-shield-icon {\n color: #16a34a;\n}\n\n.mfa-setup-status-title {\n color: #166534;\n font-weight: 500;\n font-size: 1.125rem;\n}\n\n.mfa-setup-status-description {\n color: #15803d;\n font-size: 0.875rem;\n margin-top: 0.25rem;\n}\n\n/* Methods section */\n.mfa-setup-methods-title {\n font-size: 1.25rem;\n font-weight: 600;\n color: #111827;\n margin-bottom: 1.5rem;\n}\n\n.mfa-setup-methods-grid {\n display: grid;\n grid-template-columns: repeat(1, 1fr);\n gap: 1.5rem;\n}\n\n/* Method cards */\n.mfa-setup-method-card {\n padding: 2rem;\n border: 1px solid #e5e7eb;\n border-radius: 0.75rem;\n cursor: pointer;\n transition: all 0.2s ease;\n}\n\n.mfa-setup-method-card:hover {\n box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -2px rgba(0, 0, 0, 0.05);\n border-color: #EA00A8;\n}\n\n.mfa-setup-method-disabled {\n border-color: #d1d5db;\n background-color: #f9fafb;\n opacity: 0.6;\n cursor: not-allowed;\n}\n\n.mfa-setup-method-disabled:hover {\n box-shadow: none;\n border-color: #d1d5db;\n}\n\n.mfa-setup-method-content {\n display: flex !important;\n flex-direction: column !important;\n align-items: center !important;\n justify-content: flex-start !important;\n text-align: center;\n gap: 1rem;\n}\n\n.mfa-setup-method-icon {\n width: 4rem;\n height: 4rem;\n border-radius: 0.75rem;\n display: flex;\n align-items: center;\n justify-content: center;\n transition: all 0.2s ease;\n}\n\n.mfa-setup-totp-icon {\n background-color: rgba(234, 0, 168, 0.15);\n}\n\n.mfa-setup-method-card:hover .mfa-setup-totp-icon {\n background-color: rgba(234, 0, 168, 0.25);\n}\n\n.mfa-setup-email-icon {\n background-color: rgba(234, 0, 168, 0.15);\n}\n\n.mfa-setup-method-card:hover .mfa-setup-email-icon {\n background-color: rgba(234, 0, 168, 0.25);\n}\n\n.mfa-setup-hardware-icon {\n background-color: #e5e7eb;\n}\n\n.mfa-setup-icon-svg {\n color: #EA00A8;\n}\n\n.mfa-setup-icon-disabled {\n color: #9ca3af;\n}\n\n.mfa-setup-method-info {\n display: flex;\n flex-direction: column;\n gap: 0.5rem;\n}\n\n.mfa-setup-method-title {\n font-weight: 600;\n color: #111827;\n font-size: 1.125rem;\n margin: 0;\n}\n\n.mfa-setup-method-title-disabled {\n color: #6b7280;\n}\n\n.mfa-setup-method-description {\n max-width: 300px;\n text-wrap: balance;\n font-size: 0.875rem;\n color: #6b7280;\n line-height: 1.625;\n margin: 0;\n}\n\n.mfa-setup-method-description-disabled {\n color: #9ca3af;\n}\n\n.mfa-setup-method-button {\n width: 100%;\n margin-top: 1rem;\n}\n\n/* Manage section */\n.mfa-setup-manage-section {\n border-top: 1px solid #e5e7eb;\n padding-top: 2rem;\n}\n\n.mfa-setup-manage-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n}\n\n.mfa-setup-manage-title {\n font-size: 1.125rem;\n font-weight: 600;\n color: #111827;\n}\n\n.mfa-setup-manage-description {\n color: #6b7280;\n font-size: 0.875rem;\n margin-top: 0.25rem;\n}\n\n.mfa-setup-manage-icon {\n margin-right: 0.5rem;\n}\n\n/* Footer */\n.mfa-setup-footer {\n display: flex;\n justify-content: flex-end;\n gap: 0.75rem;\n}\n</style>","import type { App } from 'vue'\n\n// Import all UI components\nimport StrandsUiAlert from '../ui/UiAlert.vue'\nimport StrandsUiButton from '../ui/UiButton.vue'\nimport StrandsUiCard from '../ui/UiCard.vue'\nimport StrandsUiInput from '../ui/UiInput.vue'\nimport StrandsUiLink from '../ui/UiLink.vue'\nimport StrandsUiTabs from '../ui/UiTabs.vue'\nimport StrandsUiLoader from '../ui/UiLoader.vue'\n\n// Placeholder function for compatibility\nfunction injectSquircleStyles() {\n // No-op - squircle functionality removed\n}\n\n// Global components map\nconst components = {\n StrandsUiAlert,\n StrandsUiButton,\n StrandsUiCard,\n StrandsUiInput,\n StrandsUiLink,\n StrandsUiTabs,\n StrandsUiLoader,\n}\n\nexport interface StrandsUIOptions {\n prefix?: string\n}\n\nexport default {\n install(app: App, options: StrandsUIOptions = {}) {\n const { prefix = '' } = options\n\n // Inject squircle CSS styles globally\n injectSquircleStyles()\n\n // Register all components globally\n Object.entries(components).forEach(([name, component]) => {\n const componentName = prefix ? `${prefix}${name}` : name\n app.component(componentName, component)\n })\n }\n}\n\n// Export individual components for tree-shaking\nexport {\n StrandsUiAlert,\n StrandsUiButton,\n StrandsUiCard,\n StrandsUiInput,\n StrandsUiLink,\n StrandsUiTabs,\n StrandsUiLoader,\n}\n\n// Export utility functions\nexport { injectSquircleStyles }\n\n// Export types\nexport type {\n ButtonVariant,\n ButtonSize,\n InputType,\n CardVariant,\n LinkVariant,\n AlertVariant,\n} from '../ui/index'","import { useStrandsAuth } from './useStrandsAuth'\nimport { useStrandsConfig } from './useStrandsConfig'\nimport type { AuthenticatedFetchOptions } from '../../types'\n\n/**\n * Enhanced fetch composable that automatically includes auth headers\n * and handles token refresh for API requests (Vue version)\n */\nexport function useAuthenticatedFetch() {\n const { config } = useStrandsConfig()\n const { currentSession, refreshToken, getAuthHeaders } = useStrandsAuth()\n\n const authenticatedFetch = async (\n url: string | URL,\n options: AuthenticatedFetchOptions = {}\n ): Promise<Response> => {\n const {\n autoRefresh = true,\n requireAuth = true,\n baseURL,\n ...fetchOptions\n } = options\n\n // Check if user is authenticated when required\n if (requireAuth && !currentSession.value?.accessToken) {\n throw new Error('User is not authenticated')\n }\n\n // Construct full URL using baseURL from options or config\n let fullUrl: string | URL = url\n const resolvedBaseURL = baseURL || config.value.baseUrl\n \n if (resolvedBaseURL && typeof url === 'string' && !url.startsWith('http')) {\n fullUrl = new URL(url, resolvedBaseURL).toString()\n }\n\n // Prepare headers\n const headers = new Headers(fetchOptions.headers)\n \n // Add auth headers if available\n if (currentSession.value?.accessToken) {\n try {\n const authHeaders = getAuthHeaders()\n Object.entries(authHeaders).forEach(([key, value]) => {\n headers.set(key, value)\n })\n } catch (error) {\n console.warn('[Strands Auth] Failed to get auth headers:', error)\n if (requireAuth) {\n throw error\n }\n }\n }\n\n // Make the request\n const enhancedOptions: RequestInit = {\n ...fetchOptions,\n headers\n }\n\n let response = await fetch(fullUrl, enhancedOptions)\n\n // Handle 401 with auto-refresh\n if (response.status === 401 && autoRefresh && currentSession.value?.refreshToken) {\n console.log('[Strands Auth] Request failed with 401, attempting token refresh...')\n \n try {\n // Attempt to refresh token\n const refreshed = await refreshToken()\n \n if (refreshed && currentSession.value?.accessToken) {\n // Update headers with new token\n const newAuthHeaders = getAuthHeaders()\n Object.entries(newAuthHeaders).forEach(([key, value]) => {\n headers.set(key, value)\n })\n\n // Retry the request with new token\n console.log('[Strands Auth] Retrying request with refreshed token')\n response = await fetch(fullUrl, { ...enhancedOptions, headers })\n }\n } catch (refreshError) {\n console.error('[Strands Auth] Token refresh failed:', refreshError)\n // Return the original 401 response\n }\n }\n\n return response\n }\n\n /**\n * Convenience method for making authenticated GET requests\n */\n const get = (url: string | URL, options?: AuthenticatedFetchOptions) => {\n return authenticatedFetch(url, { ...options, method: 'GET' })\n }\n\n /**\n * Convenience method for making authenticated POST requests\n */\n const post = (url: string | URL, body?: any, options?: AuthenticatedFetchOptions) => {\n const headers = new Headers(options?.headers)\n \n // Auto-set content type for JSON requests\n if (body && typeof body === 'object' && !headers.has('Content-Type')) {\n headers.set('Content-Type', 'application/json')\n }\n\n return authenticatedFetch(url, {\n ...options,\n method: 'POST',\n headers,\n body: typeof body === 'object' ? JSON.stringify(body) : body\n })\n }\n\n /**\n * Convenience method for making authenticated PUT requests\n */\n const put = (url: string | URL, body?: any, options?: AuthenticatedFetchOptions) => {\n const headers = new Headers(options?.headers)\n \n if (body && typeof body === 'object' && !headers.has('Content-Type')) {\n headers.set('Content-Type', 'application/json')\n }\n\n return authenticatedFetch(url, {\n ...options,\n method: 'PUT',\n headers,\n body: typeof body === 'object' ? JSON.stringify(body) : body\n })\n }\n\n /**\n * Convenience method for making authenticated DELETE requests\n */\n const del = (url: string | URL, options?: AuthenticatedFetchOptions) => {\n return authenticatedFetch(url, { ...options, method: 'DELETE' })\n }\n\n /**\n * Convenience method for making authenticated PATCH requests\n */\n const patch = (url: string | URL, body?: any, options?: AuthenticatedFetchOptions) => {\n const headers = new Headers(options?.headers)\n \n if (body && typeof body === 'object' && !headers.has('Content-Type')) {\n headers.set('Content-Type', 'application/json')\n }\n\n return authenticatedFetch(url, {\n ...options,\n method: 'PATCH',\n headers,\n body: typeof body === 'object' ? JSON.stringify(body) : body\n })\n }\n\n return {\n authenticatedFetch,\n get,\n post,\n put,\n delete: del,\n patch\n }\n}\n\n// Export convenience functions for non-composable usage\nexport const $authFetch = {\n get: async (url: string | URL, options?: AuthenticatedFetchOptions) => {\n const { get } = useAuthenticatedFetch()\n return get(url, options)\n },\n post: async (url: string | URL, body?: any, options?: AuthenticatedFetchOptions) => {\n const { post } = useAuthenticatedFetch()\n return post(url, body, options)\n },\n put: async (url: string | URL, body?: any, options?: AuthenticatedFetchOptions) => {\n const { put } = useAuthenticatedFetch()\n return put(url, body, options)\n },\n delete: async (url: string | URL, options?: AuthenticatedFetchOptions) => {\n const { delete: del } = useAuthenticatedFetch()\n return del(url, options)\n },\n patch: async (url: string | URL, body?: any, options?: AuthenticatedFetchOptions) => {\n const { patch } = useAuthenticatedFetch()\n return patch(url, body, options)\n }\n}","// Email validation\nexport const isValidEmail = (email: string): boolean => {\n const emailRegex = /^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$/\n return emailRegex.test(email)\n}\n\n// Password strength validation\nexport const validatePassword = (password: string): {\n isValid: boolean\n strength: 'weak' | 'medium' | 'strong'\n errors: string[]\n} => {\n const errors: string[] = []\n let score = 0\n\n if (password.length < 8) {\n errors.push('Password must be at least 8 characters long')\n } else {\n score += 1\n }\n\n if (!/[A-Z]/.test(password)) {\n errors.push('Password must contain at least one uppercase letter')\n } else {\n score += 1\n }\n\n if (!/[a-z]/.test(password)) {\n errors.push('Password must contain at least one lowercase letter')\n } else {\n score += 1\n }\n\n if (!/\\d/.test(password)) {\n errors.push('Password must contain at least one number')\n } else {\n score += 1\n }\n\n if (!/[!@#$%^&*(),.?\":{}|<>]/.test(password)) {\n errors.push('Password must contain at least one special character')\n } else {\n score += 1\n }\n\n const isValid = errors.length === 0\n let strength: 'weak' | 'medium' | 'strong' = 'weak'\n\n if (score >= 4) {\n strength = 'strong'\n } else if (score >= 3) {\n strength = 'medium'\n }\n\n return { isValid, strength, errors }\n}\n\n// Name validation\nexport const isValidName = (name: string): boolean => {\n return name.trim().length >= 2\n}\n\n\n// Generic required field validation\nexport const isRequired = (value: string): boolean => {\n return value.trim().length > 0\n}\n\n// Password confirmation validation\nexport const passwordsMatch = (password: string, confirmation: string): boolean => {\n return password === confirmation\n}\n\n// Generate user initials\nexport const getInitials = (firstName?: string, lastName?: string): string => {\n const first = firstName?.charAt(0).toUpperCase() || ''\n const last = lastName?.charAt(0).toUpperCase() || ''\n return first + last || 'U'\n}\n\n// Format date for display\nexport const formatDate = (date: string | Date): string => {\n const d = typeof date === 'string' ? new Date(date) : date\n return d.toLocaleDateString('en-US', {\n year: 'numeric',\n month: 'long',\n day: 'numeric'\n })\n}\n\n// Debounce utility for input validation\nexport const debounce = <T extends (...args: any[]) => any>(\n func: T,\n wait: number\n): ((...args: Parameters<T>) => void) => {\n let timeout: NodeJS.Timeout\n return (...args: Parameters<T>) => {\n clearTimeout(timeout)\n timeout = setTimeout(() => func(...args), wait)\n }\n}\n","/**\n * Lazy loading configuration for heavy components\n */\nimport { defineAsyncComponent } from 'vue'\n\n// Loading component for better UX during component load\nconst LoadingComponent = {\n template: `\n <div class=\"accui-flex accui-items-center accui-justify-center accui-p-4\">\n <div class=\"accui-animate-spin accui-rounded-full accui-h-6 accui-w-6 accui-border-b-2 accui-border-primary-500\"></div>\n </div>\n `\n}\n\n// Error component for failed loads\nconst ErrorComponent = {\n template: `\n <div class=\"accui-flex accui-items-center accui-justify-center accui-p-4 accui-text-red-600\">\n <span class=\"accui-text-sm\">Failed to load component</span>\n </div>\n `\n}\n\n// Lazy loading components have been removed due to static import conflicts\n// All components that were previously lazy-loaded are now directly exported \n// from components/index.ts to avoid TypeScript TS4023 declaration errors\n\n// This file now only contains utility functions for potential future lazy loading\n\n// Pre-load function for components that will likely be used\nexport const preloadComponent = (componentLoader: () => Promise<any>) => {\n // Preload when idle or after user interaction\n if ('requestIdleCallback' in window) {\n requestIdleCallback(() => {\n componentLoader()\n })\n } else {\n // Fallback for browsers without requestIdleCallback\n setTimeout(() => {\n componentLoader()\n }, 100)\n }\n}\n\n// Preload critical components that might be needed soon \nexport const preloadCriticalComponents = () => {\n // All components are now statically imported, so preloading is not needed\n // This function is kept for backwards compatibility\n}"],"names":["props","__props","alertClasses","computed","success","error","warning","info","variant","titleClasses","messageClasses","iconPath","_openBlock","_createElementBlock","_hoisted_1","_createElementVNode","class","value","role","_hoisted_2","_hoisted_3","_hoisted_4","d","_hoisted_6","title","_renderSlot","_ctx","message","dismissible","_hoisted_7","type","onClick","$emit","fill","viewBox","colorMap","red","blue","green","yellow","purple","pink","gray","indigo","orange","teal","cyan","emerald","lime","amber","rose","slate","zinc","neutral","stone","strands","primary","sRGBtoY","r","g","b","y","Math","pow","calcAPCA","txtY","bgY","sapc","getEffectiveRgb","colorProp","baseColorName","includes","split","baseRgb","hex","result","exec","parseInt","hexToRgb","effectiveRgb","shade","isNaN","mixPercent","round","opacity","opacityRatio","whiteRgb","getContrastTextColor","fontWeight","fontSize","bgRgb","blackY","whiteY","blackContrast","abs","whiteContrast","threshold","getAPCAThreshold","getColorValue","color","colorName","baseColor","shadeNum","clampedPercent","min","max","opacityPercent","getLightColor","buttonClasses","size","fullWidth","filter","Boolean","join","buttonStyles","getFontCharacteristics","primaryColor","hoverColor","lightColor","contrastColor","hoverContrastColor","hoverColorForContrast","getHoverContrastColor","lightColorForContrast","lightContrastColor","baseStyles","backgroundColor","boxShadow","border","borderColor","borderWidth","borderStyle","disabled","loading","style","_cache","$event","cx","cy","stroke","loadingText","$slots","padding","shadow","emit","__emit","slots","useSlots","showPassword","ref","inputId","random","toString","substr","computedType","inputClasses","errorClasses","iconPadding","passwordPadding","sm","md","lg","handleInput","event","target","togglePasswordVisibility","label","for","required","_hoisted_5","id","modelValue","placeholder","autocomplete","name","inputmode","maxlength","onInput","onBlur","onFocus","onKeydown","_hoisted_8","_hoisted_9","_hoisted_10","_toDisplayString","helpText","_hoisted_11","tag","to","href","linkProps","baseProps","external","linkStyles","textDecorationColor","handleClick","_createBlock","_resolveDynamicComponent","_mergeProps","tabButtons","underlineStyle","width","left","currentTabIndex","isAnimating","animateUnderlineStretch","async","newIndex","newTab","container","parentElement","newRect","getBoundingClientRect","containerRect","newLeft","newWidth","currentRect","currentLeft","currentWidth","isMovingRight","stretchLeft","stretchWidth","setTimeout","onMounted","nextTick","activeIndex","tabs","findIndex","tab","toRefs","watch","_Fragment","_renderList","index","key","_unref","handleTabClick","path","replace","trim","match","semiColor","solidColor","_normalizeClass","centered","height","weight","transform","text","toggleClasses","thumbClasses","handleToggle","fileInput","canvas","previewCanvas","imageData","originalImage","canvasSize","previewSize","cropRadius","imagePos","reactive","x","zoom","minZoom","maxZoom","isDragging","isResetting","isWheelZooming","dragStart","imageX","imageY","ctx","getContext","fillStyle","fillRect","triggerFileUpload","click","handleFileSelect","file","files","processFile","handleDrop","preventDefault","dataTransfer","startsWith","maxFileSize","reader","FileReader","onload","e","loadImage","readAsDataURL","dataUrl","img","Image","scale","initialZoom","scaledWidth","scaledHeight","constrainImagePosition","updateCanvas","src","drawImage","updatePreview","previewCtx","save","beginPath","arc","PI","clip","cropX","cropY","cropSize","restore","startDrag","clientX","clientY","document","addEventListener","handleDrag","stopDrag","circleLeft","circleTop","maxX","minX","maxY","minY","deltaX","deltaY","removeEventListener","handleWheel","delta","newZoom","canvasCenter","currentHeight","newHeight","currentCenterOffsetX","currentCenterOffsetY","zoomRatio","newCenterOffsetX","newCenterOffsetY","resetImage","targetZoom","cropAndUpload","cropCanvas","createElement","cropCtx","toBlob","blob","File","changePhoto","oldZoom","oldWidth","oldHeight","preselectedFile","immediate","accept","onChange","onMousedown","onWheel","mask","_hoisted_14","_hoisted_16","_hoisted_17","step","number","_hoisted_19","uploading","_hoisted_20","_hoisted_21","_hoisted_22","onDrop","onDragover","onDragenter","SoundEffects","static","getAudioContext","this","audioContext","window","AudioContext","webkitAudioContext","state","resume","playLevelUp","level","userSettings","isMilestone","milestoneSounds","levelUpSounds","playMilestoneLevelUp","playRegularLevelUp","duration","now","currentTime","forEach","freq","oscillator","createOscillator","gainNode","createGain","connect","destination","frequency","setValueAtTime","exponentialRampToValueAtTime","delay","gain","linearRampToValueAtTime","start","stop","bellOscillator","bellGain","time","frequencies","chord","chordIndex","noteIndex","noteDelay","i","sparkleTime","sparkleOsc","sparkleGain","sparkleFreq","finaleTime","playSuccess","playError","playClick","playNotification","playXpGain","VIEW_BOX_SIZE","levelUpActive","animatedValue","animationDirection","animationFrame","prevValue","prevLevel","center","thickness","labelThickness","gapAngle","radius","labelRadius","textLabelRadius","innerCircleRadius","labelLength","levelLabel","length","staticArcAngle","labelStart","labelEnd","staticArcPath","describeArc","labelTextArcPath","progressArcPath","xpArcStart","xpArcEnd","backgroundArcPath","availableSweep","progress","grayArcStart","grayArcEnd","staticArcGradient","progressArcGradient","progressGradientStart","polarToCartesian","progressGradientEnd","angle","rad","cos","sin","startAngle","endAngle","end","largeArcFlag","triggerLevelUp","newValue","oldValue","change","startTime","performance","requestAnimationFrame","elapsed","t","eased","easeInOut","animateProgress","newLevel","position","x1","y1","x2","y2","offset","gradientUnits","handleOverlayClick","closeOnOverlayClick","_Teleport","open","fullscreenOnMobile","config","useStrandsConfig","shouldShowSecuredBy","baseUrl","hasDefaultSlot","slotName","slot","vnodes","Array","isArray","slotHasContent","mfaDevices","mfaEnabled","useStrandsMfa","getUrl","currentSession","useStrandsAuth","hasMfaDevices","activeMfaDevices","is_active","device_type","makeAuthenticatedRequest","url","options","accessToken","Error","response","fetch","headers","Authorization","ok","errorText","errorMessage","status","statusText","JSON","parse","json","fetchMfaDevices","method","devices","mfa_enabled","setupTotp","deviceName","body","stringify","device_name","verifyTotpSetup","deviceId","totpCode","device_id","totp_code","setupEmailMfa","sendEmailMfaCode","verifyEmailMfaCode","code","verified","disableMfaDevice","regenerateBackupCodes","getDeviceTypeIcon","deviceType","getDeviceTypeName","formatLastUsed","lastUsedAt","date","Date","diffMs","getTime","diffDays","floor","toLocaleDateString","IconSmartphone","render","h","rx","ry","IconMail","IconKeyRound","IconShield","IconCheckCircle","points","IconAlertTriangle","mfaLoading","verifyMfa","sendMfaEmailCode","getMfaWebAuthnChallenge","mfaSessionId","authMfaSessionId","authLoading","loadingMessage","authLoadingMessage","isSendingMfaEmail","isVerifyingMfa","selectedMethod","verificationCode","verificationError","backupCode","backupCodeError","showBackupCodeInput","emailCodeSent","cooldownActive","cooldownSeconds","cooldownInterval","availableMethods","availableMfaMethods","methods","show","newShow","clearInterval","startCooldown","onBeforeUnmount","closeModal","onCodeInput","slice","onCodePaste","cleanedData","clipboardData","getData","onBackupCodeInput","cleaned","toLowerCase","test","part1","substring","part2","onBackupCodePaste","sendEmailCode","setInterval","verify","verifyBackupCode","getDeviceIconComponent","authenticateHardwareKey","sessionId","navigator","credentials","PublicKeyCredential","challengeResponse","challengeData","challenge","publicKey","base64ToUint8Array","base64","Uint8Array","b64","repeat","rawData","atob","outputArray","charCodeAt","isPasskey","publicKeyCredentialRequestOptions","timeout","userVerification","allowCredentials","map","cred","credential","get","authenticatorData","deviceInfo","aaguidHex","from","padStart","ee882879721c491397753dfcce97072a","f8a011f38c0a4d15800617111f9edc7d","c5ef55ffad9a4b9fb580adcb7c15e233","de1e552d14e14b1f9390f6d61b56e4d1","credentialData","rawId","clientDataJSON","signature","userHandle","_createVNode","UiModal","header","footer","_hoisted_36","StrandsUiButton","StrandsUiLoader","selectMethod","_hoisted_12","_hoisted_13","_hoisted_15","_hoisted_18","_hoisted_23","_hoisted_24","_createTextVNode","_hoisted_25","_hoisted_26","_hoisted_27","StrandsUiInput","onPaste","spellcheck","onSubmit","novalidate","_hoisted_28","_hoisted_29","autofocus","tabindex","pattern","minlength","_hoisted_30","_hoisted_31","_hoisted_32","_hoisted_33","_hoisted_34","_hoisted_35","useOAuthProviders","providers","enabledProviders","provider","enabled","fetchProviders","redirectUrl","oauth2RedirectUrl","params","URLSearchParams","absoluteRedirectUrl","location","origin","append","errorData","catch","err","getProviderAuthUrl","providerId","customOptions","mergedOptions","scopes","queryString","providerUrl","fullUrl","data","authUrl","redirectToProvider","find","p","auth_url","getProviderById","getProviderIcon","iconUrl","getSupportEmail","signIn","setAuthData","mfaRequired","currentUser","oauthLoading","oauthError","displayProviders","authApi","email","password","signUp","firstName","lastName","requestPasswordReset","currentMode","mode","buttonLoading","isPasswordResetSubmitted","showMfaVerification","form","confirmPassword","isSignUp","isPasswordReset","isFormValid","handleMfaSuccess","handleMfaClose","handleMfaError","handleAuth","user","mfa_required","newMode","transitionCounter","onBeforeEnter","el","element","marginTop","marginBottom","paddingTop","paddingBottom","overflow","onEnter","done","currentIndex","offsetHeight","transition","onBeforeLeave","onLeave","margin","onAfterLeave","inModal","_Transition","StrandsUiTabs","handleOAuthAuth","icon","alt","displayName","charAt","toUpperCase","StrandsUiLink","StrandsUiAlert","onDismiss","StrandsSecuredFooter","StrandsMfaVerification","onSuccess","onClose","onError","oauthScopes","handleSignIn","authData","StrandsUiCard","__","___","_cached","_isMemoSame","_memo","handleOAuthSignIn","IconGoogle","IconGithub","signupSuccess","successMessage","successTitle","successEmail","handleSignUp","signUpUrl","process","env","supportEmail","resetToForm","handleOAuthSignUp","registrationComplete","invalidToken","fieldErrors","hasRequiredFields","passwordMinLength","hasValidToken","token","parts","payload","redirectToReferrer","handleCompleteSignUp","Object","keys","first_name","last_name","access_token","refresh_token","deviceNameError","totpSetupData","qrCodeDataUrl","newData","qr_code_url","qrUrl","encodeURIComponent","startSetup","onVerificationCodeInput","verifySetup","copyBackupCodes","backup_codes","codesText","clipboard","writeText","finish","secret","emailMfaDeviceId","resendCode","registerHardwareKey","completeHardwareKeyRegistration","internalLoading","registrationMessage","backupCodes","getOptimalAuthenticatorSelection","authenticatorAttachment","requireResidentKey","residentKey","handleRegisterHardwareKey","isUserVerifyingPlatformAuthenticatorAvailable","isConditionalMediationAvailable","checkError","processedChallenge","safeBufferConvert","buffer","binary","bytes","crypto","getRandomValues","cleanChallenge","rp","pubKeyCredParams","alg","authenticatorSelection","attestation","excludeCredentials","createOptimizedWebAuthnChallenge","create","attestationObject","rawIdArray","ArrayBuffer","clientDataArray","attestationArray","credentialPayload","credError","String","userErrorMessage","errorMsg","showRegenerateWarning","device","regenerateCodes","confirmRegenerate","downloadBackupCodes","filename","toISOString","content","toLocaleString","Blob","URL","createObjectURL","link","download","appendChild","removeChild","revokeObjectURL","handleConfirm","handleCancel","cancelText","confirmText","Smartphone","Number","default","Mail","KeyRound","Shield","Trash2","showModal","activeTab","showTotpSetup","showEmailMfaSetup","showHardwareKeySetup","showPasskeySetup","showBackupCodesModal","showConfirmDisable","selectedDevice","startTotpSetup","startEmailMfaSetup","handleDisableDevice","handleTotpSetupSuccess","handleEmailMfaSetupSuccess","handleHardwareKeySetupSuccess","handlePasskeySetupSuccess","getDeviceIconBackground","last_used_at","showBackupCodes","testEmailMfa","confirmDisableDevice","StrandsTotpSetupModal","StrandsEmailMfaSetupModal","StrandsHardwareKeySetupModal","StrandsBackupCodesModal","StrandsConfirmModal","onConfirm","onCancel","updateUserSettings","saving","localSettings","settings","newSettings","deep","updateSetting","saveSettings","UiButton","UiToggle","Monitor","Tablet","MapPin","Globe","Clock","Calendar","getUserSessions","getSessionStats","revokeSession","revokeAllOtherSessions","signOut","visible","sessions","stats","revokingSession","revokingAll","newVal","loadSessions","sessionsData","statsData","Promise","all","handleClose","handleRevokeAllOther","confirm","alert","getDeviceIcon","formatTimeAgo","then","seconds","StrandsUiModal","total_sessions","active_sessions","unique_locations","session","is_current","handleRevokeCurrentSession","handleRevokeSession","city","country","ip_address","last_activity_at","created_at","month","day","year","hour","minute","_hoisted_37","fetchProfile","updateProfile","changeEmail","changeUsername","getUsernameCooldown","checkUsernameAvailability","authUser","isAuthenticated","refreshToken","internalUser","fetchingProfile","signingOut","showPasswordChange","showEmailChange","emailChangeLoading","showUsernameChange","usernameChangeLoading","showMfaModal","showSettingsModal","showAvatarEditor","selectedImageFile","activeSessions","loadingSessions","showSessionsModal","usernameChangeData","canChange","cooldownEnd","daysRemaining","usernameAvailability","available","checking","avatarFileInput","emailChangeForm","newEmail","errors","passwordForm","current","new","usernameForm","username","hasChanges","isPasswordFormValid","isEmailChangeFormValid","isUsernameChangeFormValid","passwordLastUpdated","updateDate","passwordUpdatedAt","createdAt","months","years","deviceTypeCounts","counts","totp","hardware","passkey","mfaDeviceChips","chips","push","count","totalHardware","getXpForLevel","totalXp","userLevel","getLevelFromXp","xp","currentExp","xpForCurrentLevel","expToNextLevel","progressPercentage","totalCircumference","progressLength","smallGap","loadUserSessions","authenticated","wasAuthenticated","autoFetch","fetchUserProfile","clearMessages","handleUpdateProfile","updatedUser","handlePasswordChange","resolve","handleEmailChange","handleToggleUsernameChange","cooldownData","can_change","cooldown_end","days_remaining","handleUsernameChange","triggerAvatarUpload","handleAvatarFileSelect","handleAvatarUpload","uploadAvatar","handleAvatarError","handleAvatarEditorClose","formData","FormData","retryResponse","retryResult","avatar","avatar_url","localStorage","setItem","refreshError","handleMfaUpdated","handleSettingsUpdated","handleSessionsUpdated","handleSignOut","StrandsUiLevelProgress","next_level_xp","chip","_hoisted_38","_hoisted_39","_hoisted_40","_hoisted_41","_hoisted_42","_hoisted_43","_hoisted_44","_hoisted_45","_hoisted_46","_hoisted_47","StrandsMfaModal","onMfaUpdated","StrandsSettingsModal","onSettingsUpdated","StrandsSessionsModal","onSessionsUpdated","_hoisted_48","_hoisted_49","_hoisted_50","StrandsUiAvatarEditor","onUpload","isSubmitted","handlePasswordReset","invert","signedInOrInverted","showLoading","signedOutOrInverted","showFallback","isComponentReady","isInitializing","isSigningIn","isLoading","args","xmlns","provideStrandsConfig","sizeClasses","xs","xl","iconClass","icons","eye","camera","lock","google","github","iconComponent","ariaHidden","showDropdown","showProfileModal","showSignInModal","containerRef","profileButtonRef","toggleDropdown","focus","openDropdown","closeDropdown","focusNext","focusPrevious","focusFirst","focusLast","openProfile","closeProfile","handleProfileUpdated","handleProfileError","openSignIn","closeSignIn","handleSignedIn","handleSignInError","handleClickOutside","contains","onUnmounted","SignedIn","fallback","StrandsAuth","onSignedIn","hideUser","menuAlign","menuVerticalAlign","StrandsUserProfile","onProfileUpdated","scrollContainer","scrollTop","visibleRange","itemHeight","ceil","containerHeight","items","overscan","visibleItems","top","totalHeight","getItemKey","item","itemKey","scrollTimer","handleScroll","clearTimeout","__expose","scrollToItem","align","scrollTo","overflowY","onScroll","_normalizeStyle","Settings","openMfaModal","handleSetupSuccess","components","StrandsUIPlugin","install","app","prefix","entries","component","componentName","useAuthenticatedFetch","getAuthHeaders","authenticatedFetch","autoRefresh","requireAuth","baseURL","fetchOptions","resolvedBaseURL","Headers","authHeaders","set","enhancedOptions","newAuthHeaders","post","has","put","delete","patch","$authFetch","del","func","wait","confirmation","score","strength","isValid"],"mappings":"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"}