()
| 930 | this.turnstileBubble?.destroy(); |
| 931 | this.turnstileBubble = null; |
| 932 | this.turnstileInitPromise = null; |
| 933 | } |
| 934 | |
| 935 | renderWelcomeStep() { |
| 936 | this.ensureValidAccessMode(); |
| 937 | const hasError = !!this.redeemError; |
| 938 | const isPreviewMode = this.isPreviewMode(); |
| 939 | const controlsDisabled = this.isRedeeming; |
| 940 | const inputPlaceholder = isPreviewMode ? 'Email address' : 'Invite code'; |
| 941 | const inputMaxLength = isPreviewMode ? 254 : 24; |
| 942 | const inputValue = this.getCurrentAccessValue(); |
| 943 | const showPreviewHint = isPreviewMode && !hasError; |
| 944 | const feedbackHtml = hasError |
| 945 | ? (this.redeemError === FREE_ACCESS_UNAVAILABLE_HINT |
| 946 | ? FREE_ACCESS_UNAVAILABLE_HINT_HTML |
| 947 | : this.escapeHtml(this.redeemError)) |
| 948 | : (showPreviewHint ? FREE_ACCESS_EMAIL_HINT_HTML : ''); |
| 949 | const feedbackClass = hasError ? 'text-red-500' : 'text-muted-foreground'; |
| 950 | |
| 951 | return ` |
| 952 | <div id="welcome-theme-toggle" class="theme-toggle-container" role="radiogroup" aria-label="Theme selection" data-theme="${themeManager.getPreference()}" style="position:fixed;top:12px;right:12px;z-index:9999"> |
| 953 | <div class="theme-toggle-indicator"></div> |
| 954 | <button type="button" class="theme-toggle-btn" data-theme-option="light" aria-checked="${themeManager.getPreference() === 'light'}" title="Light"> |
| 955 | <svg class="w-[18px] h-[18px]" fill="none" stroke="currentColor" viewBox="0 0 24 24" stroke-width="1.5"> |
| 956 | <path stroke-linecap="round" stroke-linejoin="round" d="M12 3v1.5m0 15V21m9-9h-1.5M4.5 12H3m15.364-6.364-1.06 1.06M6.697 17.303l-1.06 1.06m0-12.728 1.06 1.06m9.607 9.607 1.06 1.06M12 8.25a3.75 3.75 0 1 1 0 7.5 3.75 3.75 0 0 1 0-7.5z"></path> |
| 957 | </svg> |
| 958 | </button> |
| 959 | <button type="button" class="theme-toggle-btn" data-theme-option="dark" aria-checked="${themeManager.getPreference() === 'dark'}" title="Dark"> |
| 960 | <svg class="w-[18px] h-[18px]" fill="none" stroke="currentColor" viewBox="0 0 24 24" stroke-width="1.5"> |
| 961 | <path stroke-linecap="round" stroke-linejoin="round" d="M21 12.79A9 9 0 0 1 11.21 3 7.5 7.5 0 1 0 21 12.79z"></path> |
| 962 | </svg> |
| 963 | </button> |
| 964 | <button type="button" class="theme-toggle-btn" data-theme-option="system" aria-checked="${themeManager.getPreference() === 'system'}" title="System"> |
| 965 | <svg class="w-[18px] h-[18px]" fill="none" stroke="currentColor" viewBox="0 0 24 24" stroke-width="1.5"> |
| 966 | <path stroke-linecap="round" stroke-linejoin="round" d="M9 17v2h6v-2m2 0h.75A2.25 2.25 0 0 0 20 14.75V7.25A2.25 2.25 0 0 0 17.75 5H6.25A2.25 2.25 0 0 0 4 7.25v7.5A2.25 2.25 0 0 0 6.25 17H7.5"></path> |
| 967 | </svg> |
| 968 | </button> |
| 969 | </div> |
| 970 | <div role="dialog" aria-modal="true" class="${MODAL_CLASSES}" style="padding:28px 28px 20px"> |
| 971 | <style> |
| 972 | /* Entrance animation matching app's subtle motion language */ |
| 973 | @keyframes welcomeModalIn { |
| 974 | from { opacity: 0; transform: scale(calc(var(--welcome-modal-scale, 1) * 0.97)) translateY(6px); } |
| 975 | to { opacity: 1; transform: scale(var(--welcome-modal-scale, 1)) translateY(0); } |
| 976 | } |
| 977 | .welcome-modal-enter { |
| 978 | animation: welcomeModalIn 0.2s ease-out; |
| 979 | } |
| 980 | .welcome-modal-glass { |
| 981 | background: hsl(var(--color-background) / 0.72); |
| 982 | backdrop-filter: blur(20px) saturate(1.2); |
| 983 | -webkit-backdrop-filter: blur(20px) saturate(1.2); |
| 984 | } |
| 985 | #welcome-panel { |
| 986 | background: rgba(0,0,0,0.35) !important; |
| 987 | backdrop-filter: blur(4px) !important; |
| 988 | -webkit-backdrop-filter: blur(4px) !important; |
| 989 | } |
no test coverage detected