1<!DOCTYPE html> 2<html lang="en"> 3 4<head> 5 <meta charset="UTF-8"> 6 <meta name="viewport" content="width=device-width, initial-scale=1.0"> 7 <title>Login - DocAccess - Revolutionary Document Accessibility</title> 8
8<script src="/static/homepage.js"></script>
8 9 <link rel="stylesheet" href="/static/style.css"> 10 <link rel="preconnect" href="https://fonts.googleapis.com"> 11 <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin> 12 <link 13 href="https://fonts.googleapis.com/css2?family=Lato:ital,wght@0,100;0,300;0,400;0,700;0,800;0,900;1,100;1,300;1,400;1,700;1,800;1,900&family=Roboto:ital,wght@0,100..900;1,100..900&display=swap" 14 rel="stylesheet"> 15 <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0/css/all.min.css"> 16 <style> 17 .password-toggle { 18 background: none; 19 border: none; 20 cursor: pointer; 21 padding: 4px 10px; 22 color: #666; 23 right: 0; 24 top: 0; 25 bottom: 0; 26 } 27 28 .password-toggle:hover { 29 color: #333; 30 } 31 32 .password-toggle:focus { 33 outline: 2px solid #007bff; 34 outline-offset: 2px; 35 border-radius: 4px; 36 } 37 38 .alert-danger { 39 color: #721c24; 40 background-color: #f8d7da; 41 border: 1px solid #f5c6cb; 42 padding: 12px; 43 margin-bottom: 16px; 44 border-radius: 4px; 45 } 46 47 .form-group { 48 margin-bottom: 1rem; 49 } 50 51 .form-control { 52 width: 100%; 53 padding: 8px 12px; 54 border: 1px solid #ced4da; 55 border-radius: 4px; 56 } 57 58 .form-control:focus { 59 outline: 2px solid #007bff; 60 outline-offset: 2px; 61 border-color: #007bff; 62 } 63 64 .btn-gradient:focus { 65 outline: 2px solid #007bff; 66 outline-offset: 2px; 67 } 68 69 .btn-link { 70 display: inline-block; 71 margin-left: 1rem; 72 color: #007bff; 73 text-decoration: none; 74 } 75 76 .btn-link:hover { 77 text-decoration: underline; 78 } 79 80 .btn-link:focus { 81 outline: 2px solid #007bff; 82 outline-offset: 2px; 83 border-radius: 4px; 84 } 85 86 .sr-only { 87 position: absolute; 88 width: 1px; 89 height: 1px; 90 padding: 0; 91 margin: -1px; 92 overflow: hidden; 93 clip: rect(0, 0, 0, 0); 94 white-space: nowrap; 95 border: 0; 96 } 97 98 /* SSO Login Buttons */ 99 .sso-login-section { 100 margin-top: 30px; 101 padding: 20px 0; 102 border-top: 1px solid #ccc; 103 } 104 105 .sso-login-buttons { 106 display: flex; 107 flex-direction: column; 108 gap: 12px; 109 margin-top: 15px; 110 } 111 112 .sso-login-button { 113 display: flex; 114 align-items: center; 115 justify-content: center; 116 padding: 5px 20px; 117 border: 1px solid #ddd; 118 border-radius: 4px; 119 text-decoration: none; 120 font-weight: 500; 121 transition: all 0.2s ease; 122 width: 100%; 123 font-size: 16px; 124 } 125 126 .sso-login-button:hover { 127 text-decoration: none; 128 transform: translateY(-1px); 129 box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1); 130 } 131 132 .sso-login-button.google { 133 background-color: #fff; 134 color: #333; 135 border-color: #dadce0; 136 } 137 138 .sso-login-button.google:hover { 139 background-color: #f8f9fa; 140 color: #333; 141 } 142 143 .sso-login-button.microsoft { 144 background-color: #0078d4; 145 color: white; 146 border-color: #0078d4; 147 } 148 149 .sso-login-button.microsoft:hover { 150 background-color: #106ebe; 151 color: white; 152 } 153 154 .sso-login-button.sso { 155 background-color: #178758; 156 color: #fff; 157 border-color: #178758; 158 } 159 160 .sso-login-button.sso:hover { 161 background-color: #136f48; 162 color: #fff; 163 } 164 165 .sso-icon { 166 margin-right: 10px; 167 width: 18px; 168 height: 18px; 169 } 170 171 /* "Works with your identity provider" trust strip below the SSO 172 buttons. Icons for the providers we natively support (Google, 173 Microsoft, Okta) plus name chips for common SAML/OIDC IdPs that 174 route through the same generic flow. */ 175 .sso-supported { 176 margin-top: 18px; 177 text-align: center; 178 } 179 180 .sso-supported-label { 181 font-size: 12px; 182 color: #6b7280; 183 margin: 0 0 10px; 184 text-transform: uppercase; 185 letter-spacing: 0.04em; 186 } 187 188 .sso-supported-logos { 189 display: flex; 190 flex-wrap: wrap; 191 justify-content: center; 192 gap: 8px; 193 } 194 195 .sso-chip { 196 display: inline-flex; 197 align-items: center; 198 gap: 6px; 199 padding: 4px 10px; 200 border: 1px solid #e5e7eb; 201 border-radius: 9999px; 202 font-size: 12px; 203 font-weight: 500; 204 color: #374151; 205 background: #fff; 206 white-space: nowrap; 207 } 208 209 .sso-chip svg { 210 width: 14px; 211 height: 14px; 212 flex-shrink: 0; 213 } 214 215 .sso-supported-more { 216 font-size: 12px; 217 color: #9ca3af; 218 margin: 10px 0 0; 219 } 220 221 .alert-info { 222 color: #004085; 223 background-color: #cce5ff; 224 border: 1px solid #b8daff; 225 padding: 12px; 226 margin-bottom: 16px; 227 border-radius: 4px; 228 } 229 </style> 230
230<script src="/static/common.js"></script>
vendor: 1 bytes, line 230
230
231<script> 232 (function () { 233 // Check for affiliate parameter in URL 234 const urlParams = new URLSearchParams(window.location.search); 235 const affiliateId = urlParams.get('affiliate'); 236 237 if (affiliateId) { 238 // Store affiliate ID in cookie for 30 days 239 const maxAge = 30 * 24 * 60 * 60; // 30 days in seconds 240 241 // Build cookie string using max-age instead of expires 242 let cookieString = `docaccess_affiliate=${affiliateId}; max-age=${maxAge}; path=/`; 243 244 // Only set domain if we're on the production domain 245 const hostname = window.location.hostname; 246 if (hostname.includes('docaccess.com')) { 247 // For subdomain compatibility, use the root domain with a dot prefix 248 if (hostname === 'docaccess.com' || hostname === 'www.docaccess.com') { 249 cookieString += `; domain=.docaccess.com`; 250 } else { 251 // For other subdomains, use the specific hostname 252 cookieString += `; domain=${hostname}`; 253 } 254 } 255 // For localhost or IP addresses, don't set domain at all 256 257 // Add Secure flag if on HTTPS 258 if (window.location.protocol === 'https:') { 259 cookieString += '; Secure'; 260 } 261 262 // Always use SameSite=Lax for better compatibility 263 cookieString += '; SameSite=Lax'; 264 265 // Set the cookie 266 document.cookie = cookieString; 267 268 console.log('Affiliate ID stored:', affiliateId); 269 console.log('Cookie string:', cookieString); 270 console.log('Current domain:', hostname); 271 console.log('Protocol:', window.location.protocol); 272 273 // Verify cookie was set 274 setTimeout(() => { 275 const storedValue = window.getAffiliateCookie(); 276 if (storedValue) { 277 console.log('Cookie verified - affiliate ID:', storedValue); 278 } else { 279 console.warn('Cookie was not stored successfully'); 280 } 281 }, 100); 282 } 283 284 // Helper function to read cookie (for other scripts to use) 285 window.getAffiliateCookie = function () { 286 // First try to get from cookie 287 const cookies = document.cookie.split(';'); 288 for (let cookie of cookies) { 289 const [name, value] = cookie.trim().split('='); 290 if (name === 'docaccess_affiliate') { 291 return value; 292 } 293 } 294 295 // Fallback to localStorage for development environments 296 if (typeof (Storage) !== "undefined") { 297 const localStorageValue = localStorage.getItem('docaccess_affiliate'); 298 if (localStorageValue) { 299 console.log('Using affiliate ID from localStorage:', localStorageValue); 300 return localStorageValue; 301 } 302 } 303 304 return null; 305 }; 306 307 // Also store in localStorage as a fallback (useful for development) 308 if (affiliateId && typeof (Storage) !== "undefined") { 309 localStorage.setItem('docaccess_affiliate', affiliateId); 310 console.log('Also stored affiliate ID in localStorage for fallback'); 311 } 312 })(); 313</script>
vendor: 1 bytes, line 313
313
314<script> 315 // UTM Parameter Tracking (always loaded â independent from affiliate capture) 316 (function () { 317 // Check for UTM parameters in URL 318 const urlParams = new URLSearchParams(window.location.search); 319 const utmParams = {}; 320 321 // List of UTM parameters to capture 322 const utmKeys = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_content', 'utm_term']; 323 324 // Also capture custom tracking parameters 325 const customKeys = ['gclid', 'fbclid', 'ref']; 326 327 // Capture all UTM parameters 328 let hasUTM = false; 329 utmKeys.forEach(key => { 330 const value = urlParams.get(key); 331 if (value) { 332 utmParams[key] = value; 333 hasUTM = true; 334 } 335 }); 336 337 // Capture custom parameters 338 customKeys.forEach(key => { 339 const value = urlParams.get(key); 340 if (value) { 341 utmParams[key] = value; 342 } 343 }); 344 345 // If we have UTM parameters, store them 346 if (hasUTM || Object.keys(utmParams).length > 0) { 347 // Store in sessionStorage for immediate use 348 try { 349 sessionStorage.setItem('utm_params', JSON.stringify(utmParams)); 350 console.log('UTM parameters captured in sessionStorage:', utmParams); 351 } catch (e) { 352 console.error('Error storing UTM parameters in sessionStorage:', e); 353 } 354 355 // Store in localStorage for persistence across sessions 356 try { 357 // Get existing stored UTMs to merge (first-touch attribution) 358 const existingUTMs = localStorage.getItem('docaccess_utm_params'); 359 const existingData = existingUTMs ? JSON.parse(existingUTMs) : {}; 360 361 // Store with timestamp using ISO string format 362 const currentISOString = new Date().toISOString(); 363 const utmData = { 364 ...utmParams, 365 timestamp: currentISOString, 366 first_touch: existingData.first_touch || utmParam
366s, 367 first_touch_time: existingData.first_touch_time || currentISOString 368 }; 369 370 localStorage.setItem('docaccess_utm_params', JSON.stringify(utmData)); 371 console.log('UTM parameters stored in localStorage:', utmData); 372 } catch (e) { 373 console.error('Error storing UTM parameters in localStorage:', e); 374 } 375 376 // Store in cookie for server-side access (30 days) 377 const maxAge = 30 * 24 * 60 * 60; // 30 days in seconds 378 379 let cookieString = `docaccess_utm=${encodeURIComponent(JSON.stringify(utmParams))}; max-age=${maxAge}; path=/`; 380 381 // Root-domain cookie only on the production host â a preview or 382 // sandbox subdomain must not write attribution cookies that prod reads 383 const hostname = window.location.hostname; 384 if (hostname === 'docaccess.com' || hostname === 'www.docaccess.com') { 385 cookieString += `; domain=.docaccess.com`; 386 } 387 388 // Add security flags 389 if (window.location.protocol === 'https:') { 390 cookieString += '; Secure'; 391 } 392 cookieString += '; SameSite=Lax'; 393 394 document.cookie = cookieString; 395 console.log('UTM parameters stored in cookie'); 396 } 397 398 // Helper function to get stored UTM parameters 399 window.getStoredUTMParams = function () { 400 // Try sessionStorage first (current session) 401 try { 402 const sessionUTMs = sessionStorage.getItem('utm_params'); 403 if (sessionUTMs) { 404 return JSON.parse(sessionUTMs); 405 } 406 } catch (e) { } 407 408 // Try localStorage (persistent) 409 try { 410 const localUTMs = localStorage.getItem('docaccess_utm_params'); 411 if (localUTMs) { 412 const data = JSON.parse(localUTMs); 413 // Return just the UTM params, not the metadata 414 const { timestamp, first_touch, first_touch_time, ...utms } = data; 415 return utms; 416 } 417 } catch (e) { } 418 419 // Try cookie 420 const cookies = document.cookie.split(';'); 421 for (let cookie of cookies) { 422 const [name, value] = cookie.trim().split('='); 423 if (name === 'docaccess_utm') { 424 try { 425 return JSON.parse(decodeURIComponent(value)); 426 } catch (e) { } 427 } 428 } 429 430 return {}; 431 }; 432 433 // Helper to get first-touch attribution data 434 window.getFirstTouchUTMs = function () { 435 try { 436 const localUTMs = localStorage.getItem('docaccess_utm_params'); 437 if (localUTMs) { 438 const data = JSON.parse(localUTMs); 439 return { 440 utms: data.first_touch || {}, 441 timestamp: data.first_touch_time || null 442 }; 443 } 444 } catch (e) { } 445 return { utms: {}, timestamp: null }; 446 }; 447 })(); 448</script>
448 449</head> 450 451<body class="da" id="da"> 452 <a href="#main-content" class="sr-only sr-only-focusable">Skip to main content</a> 453 <header class="flex items-center justify-between py-4 px-8 "> 454 <div class="logo-container flex items-center"> 455 <a href="/"><img src="/static/doc-access-streamline.svg" alt="DocAccess Logo, powered by CivicPlus" class="h-10"><span class="beta-badge" style="display: none;">Beta</span></a> 456 </div> 457 <nav id="main-nav" class="hidden md:flex items-center font-medium docaccess-nav"> 458 <ul class="flex items-center space-x-7 list-none m-0 p-0"> 459 <li><a href="/">Home</a></li> 460 <li><a href="/blog">Blog</a></li> 461 <li><a href="/support">Support</a></li> 462 <li><a href="/pricing">Pricing</a></li> 463 <li><a href="/contact">Contact</a></li> 464 <li><a href="/app/" class="btn-action" aria-label="Sign in">Log In</a></li> 465 <li><a href="/start" class="btn-gradient">Get Your Free Accessibility Report</a></li> 466 </ul> 467 </nav> 468 <button id="mobile-menu-btn" class="hamburger md:hidden focus:outline-none z-20 relative w-8 h-8" aria-label="Mobile Menu"> 469 <span></span> 470 <span></span> 471 <span></span> 472 </button> 473 </header> 474 <main id="main-content" class="w-full" role="main"> 475 <section class="login-page start-hero py-16" aria-labelledby="page-title"> 476 <div class="max-w-screen-lg mx-auto px-6hero-content"> 477 <h1 id="page-title" class="text-3xl md:text-5xl font-bold mb-4 text-center"> 478 Login </h1> 479 <div class="text-lg md:text-xl mb-16 text-center card"> 480 481 <form method="post" action="/app/login" id='login-form' aria-labelledby="login-title"> 482 <h2 id="login-title" class="sr-only">Login Form</h2> 483 <div class="form-group"> 484 <label for="email">Email</label> 485 <input type="email" class="form-control" id="email" name="email" required 486 aria-required="true" autocomplete="email"> 487 </div> 488 489 <div class="form-group"> 490 <label for="password">Password</label> 491 <div class="relative"> 492 <input type="password" class="form-control pr-10" id="password" name="password" required 493 aria-required="true" autocomplete="current-password" 494 aria-describedby="login-password-toggle-desc"> 495 <button type="button" 496 class="password-toggle absolute right-3 top-1/2 transform -translate-y-1/2" 497 id="toggle_password" aria-label="Show password" aria-pressed="false" 498 aria-controls="password"> 499 <i class="fas fa-eye" aria-hidden="true"></i> 500 </button> 501 <span id="login-password-toggle-desc" class="sr-only">Toggle password visibility</span> 502 </div> 503 </div> 504 505 <button type="submit" class="btn-gradient form-submit-button">Login</button> 506 <a href="/app/forgot-password" class="btn-link">Forgot Password?</a> 507 </form> 508 509 510 <div class="sso-login-section "> 511 <div class="sso-login-buttons"> 512 <a href="https://accounts.google.com/o/oauth2/v2/auth?client_id=489961069422-5b8t3kektuloc3frco66bcgvnle9n1v2.apps.googleusercontent.com&redirect_uri=https%3A%2F%2Fdocaccess.com%2Fapp%2Flogin&response_type=code&scope=openid+email+profile&state=5bfecd6de33e754d32cbfc2fe26278cffe9c5cbeac693c71a785564c5c39b7e4&nonce=bd43697a9c21
512d838a0e17d2fa0f5aa6e" class="sso-login-button google"> 513 <svg class="sso-icon" viewBox="0 0 24 24"> 514 <path fill="#4285f4" 515 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" /> 516 <path fill="#34a853" 517 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" /> 518 <path fill="#fbbc05" 519 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" /> 520 <path fill="#ea4335" 521 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" /> 522 </svg> 523 Sign in with Google Workspace 524 </a> 525 <a href="https://login.microsoftonline.com/common/oauth2/v2.0/authorize?client_id=894e292a-793e-4446-bdb9-8c2d5bf00349&redirect_uri=https%3A%2F%2Fdocaccess.com%2Fapp%2Flogin&response_type=code&scope=openid+profile+email+User.Read&state=74374971aca3d2b58246d74e79a08c49b35f7187f51568420c4542a676b9b012&nonce=8423b15c8f4768452f4e8ee36d681bb1" 526 class="sso-login-button microsoft"> 527 <svg class="sso-icon" viewBox="0 0 24 24" fill="currentColor"> 528 <path 529 d="M11.4 24H0V12.6h11.4V24zM24 24H12.6V12.6H24V24zM11.4 11.4H0V0h11.4v11.4zM24 11.4H12.6V0H24v11.4z" /> 530 </svg> 531 Sign in with Microsoft 532 </a> 533 <a href="?sso=true" class="sso-login-button sso"> 534 <svg class="sso-icon" viewBox="0 0 24 24" fill="currentColor" aria-hidden="true"> 535 <path d="M12 2 4 6v6c0 5 3.5 9.4 8 10 4.5-.6 8-5 8-10V6l-8-4z"/> 536 </svg> 537 Sign in with Single Sign-On 538 </a> 539 </div> 540 <div class="sso-supported" role="note" aria-label="Supported single sign-on providers"> 541 <p class="sso-supported-label">Works with your organization's identity provider</p> 542 <div class="sso-supported-logos"> 543 <span class="sso-chip"> 544 <svg viewBox="0 0 24 24" aria-hidden="true"> 545 <path fill="#4285f4" 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" /> 546 <path fill="#34a853" 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" /> 547 <path fill="#fbbc05" 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" /> 548 <path fill="#ea4335" 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" /> 549 </svg>
549Google Workspace</span> 550 <span class="sso-chip"> 551 <svg viewBox="0 0 24 24" aria-hidden="true"> 552 <defs> 553 <linearGradient id="entraChipGrad" x1="2" y1="3" x2="20" y2="21" gradientUnits="userSpaceOnUse"> 554 <stop offset="0" stop-color="#32d4f5"/> 555 <stop offset=".5" stop-color="#198ab3"/> 556 <stop offset="1" stop-color="#114a8b"/> 557 </linearGradient> 558 </defs> 559 <path fill="url(#entraChipGrad)" d="M12 2.5 3 19.5l1.9 1 7.1-13 4.2 7.7-3.9 2.1 1 1.9 6.6-3.6L12 2.5z"/> 560 </svg>Microsoft Entra ID</span> 561 <span class="sso-chip">Okta</span> 562 <span class="sso-chip">OneLogin</span> 563 <span class="sso-chip">Ping Identity</span> 564 <span class="sso-chip">Auth0</span> 565 </div> 566 <p class="sso-supported-more">â¦and any other SAML or OIDC identity provider</p> 567 </div> 568 </div> 569 570 </div> 571 </div> 572 </section> 573 </main> 574 <footer class="docaccess-footer text-white w-full"> 575 <div class="max-w-7xl mx-auto px-8 py-10 flex flex-col md:flex-row justify-between items-start md:items-center"> 576 <!-- Logo and tagline --> 577 <div class="mb-8 md:mb-0"> 578 <img src="/static/doc-access-streamline-reversed.svg" alt="DocAccess, powered by CivicPlus" class="h-12 mb-4"> 579 <p class="text-sm"> 580 Your Same Documents - Transcribed, Searchable, Translated, & Assisted. <span aria-hidden="true">ðÂÂÂ</span> 581 </p> 582 </div> 583 584 <!-- Navigation --> 585 <nav class="grid grid-cols-2 gap-x-12 gap-y-2 h-full"> 586 <ul class="list-none m-0 p-0 flex flex-col justify-between h-full"> 587 <li><a href="/app/login" class="block hover:underline" aria-label="Sign in">Log In</a></li> 588 <li><a href="/support" class="block hover:underline">Support</a></li> 589 <li><a href="/pricing" class="block hover:underline">Pricing</a></li> 590 </ul> 591 <ul class="list-none m-0 p-0 flex flex-col justify-between h-full"> 592 <li><a href="/start" class="inline-block btn-gradient text-center mt-2">Get Your Free Accessibility Report</a></li> 593 </ul> 594 </nav> 595 </div> 596 597 <!-- Bottom Footer --> 598 <div class="lower-footer text-sm py-4"> 599 <div class="mx-auto px-8 flex flex-col md:flex-row justify-between items-center"> 600 <p><a href="https://www.civicplus.com" target="_blank">é CivicPlus LLC</a> 601 <span id="current-year"></span> 602
602<script> 603 document.getElementById('current-year').textContent = new Date().getFullYear(); 604 </script>
604 605 </p> 606 <a href="/terms-of-use">Terms of Use</a> 607 <a href="/privacy-policy">Privacy Policy</a> 608 <a href="/terms-of-service">Customer Terms of Service</a> 609 <a href="/accessibility-statement">Accessibility Statement</a> 610 </div> 611 </div> 612 </footer> 613
613<script> 614 document.addEventListener('DOMContentLoaded', function () { 615 function setupPasswordToggle(toggleId, inputId) { 616 const toggleButton = document.getElementById(toggleId); 617 const passwordInput = document.getElementById(inputId); 618 619 if (toggleButton && passwordInput) { 620 toggleButton.addEventListener('click', function () { 621 const type = passwordInput.type === 'password' ? 'text' : 'password'; 622 passwordInput.type = type; 623 624 // Update ARIA attributes 625 const isPressed = type === 'text'; 626 this.setAttribute('aria-pressed', isPressed); 627 this.setAttribute('aria-label', isPressed ? 'Hide password' : 'Show password'); 628 629 // Update icon 630 const icon = this.querySelector('i'); 631 icon.classList.toggle('fa-eye'); 632 icon.classList.toggle('fa-eye-slash'); 633 }); 634 635 // Add keyboard support 636 toggleButton.addEventListener('keydown', function (e) { 637 if (e.key === 'Enter' || e.key === ' ') { 638 e.preventDefault(); 639 this.click(); 640 } 641 }); 642 } 643 } 644 645 // Setup toggles for both forms 646 setupPasswordToggle('toggle_password', 'password'); 647 setupPasswordToggle('toggle_confirm_password', 'confirm_password'); 648 649 // Auto-focus SSO section if owner account error is shown 650 }); 651 </script>
651 652</body> 653 654</html>
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.