1<!doctype html> 2<html lang="en-us"> 3<head> 4 <title>Dot Gov | Alameda County</title> 5 <meta charset="utf-8"> 6 <meta http-equiv="X-UA-Compatible" content="IE=edge"> 7 <meta name="viewport" content="width=device-width, initial-scale=1"> 8 <!-- The above 3 meta tags *must* come first in the head; any other head content must come *after* these tags --> 9 <meta name="Description" content="Page with information about connecting with Alameda County."> 10 <meta name="Keywords" content="Alameda County, government, social media, open government, citizen engagement, Facebook, Twitter, Flickr, YouTube, GovDelivery, email subscription, e-Subscription, e-Subscribe, connect, stay connected, get connected, "> 11 <meta name="Location" content="Alameda County, Bay Area, California, United States"> 12 13 <!-- Google Tag Manager -->
14<script>
vendor: 331 bytes, lines 14-18
14(function(w,d,s,l,i){w[l]=w[l]||[];w[l].push({'gtm.start': 15new Date().getTime(),event:'gtm.js'});var f=d.getElementsByTagName(s)[0], 16j=d.createElement(s),dl=l!='dataLayer'?'&l='+l:'';j.async=true;j.src= 17'https://www.googletagmanager.com/gtm.js?id='+i+dl;f.parentNode.insertBefore(j,f); 18})(window,document,'script','dataLayer','
18GTM-MW6VWCK
vendor: 3 bytes, line 18
18');
18</script>
18 19<!-- End Google Tag Manager --> 20 21<!-- Bootstrap core CSS --> 22<link href="/acgov-css/bootstrap.min.css" rel="stylesheet"> 23 24<!-- IE10 viewport hack for Surface/desktop Windows 8 bug --> 25<link href="/acgov-css/ie10-viewport-bug-workaround.css" rel="stylesheet"> 26 27<!-- Custom styles for this template --> 28<link href="/acgov-css/custom.css" rel="stylesheet"> 29 30<!-- Google Material Icons Font --> 31<link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet"> 32 33<!-- Background Image Load --> 34<!-- When changing the wallpaper image, keep in mind that it may effect the readability of content since the 35content div is partially transparent. Adjust the transparency on line 164 of the custom.css file -->
36<script> 37//window.onload = function() { 38//if (window.screen.width > 767) { 39// document.body.style.backgroundImage = "url('/img/wallpaper-merritt-adj2.jpg')"; 40//} 41//} 42 43function submitsearch() { 44 document.getElementById("search-form").submit(); 45} 46function goback() { 47 window.history.back(); 48} 49</script>
49 50
51<script> /* NEW TEMP SEARCH BOX */ 52 (function() { 53 var cx = '002986915478428468373:0muhvevs3v0'; 54 var gcse = document.createElement('script'); 55 gcse.type = 'text/javascript'; 56 gcse.async = true; 57 gcse.src = 'https://cse.google.com/cse.js?cx=' + cx; 58 var s = document.getElementsByTagName('script')[0]; 59 s.parentNode.insertBefore(gcse, s); 60 })(); 61</script>
61 62 63 64<style> /* NEW TEMP SEARCH BOX */ 65td.gsc-search-button { padding-right: 5px; } 66td.gsib_a { 67 padding:10px; 68} 69.gsc-search-button-v2 { 70 padding: 11px 25px !important; 71 margin: 15px; 72 border-radius: 3px !important; 73} 74.gsc-search-button-v2 svg { 75 width:18px; 76 height:18px; 77} 78/*Media Querry*/ 79@media (max-width:767px){ 80td.gsc-input { width:20%;} 81} 82</style> 83 84 <style> 85 .social-icon { 86 max-width: 75px; 87 margin: 10px; 88 } 89 .info-msg {display: none;} 90 91 </style> 92</head> 93 94<body> 95 <!-- skip to content --> 96<header> 97 <a href="#content" class="skip-link">Skip to Content</a> 98 99 <!-- Above-the-fold branding --> 100 <div id="acgov-branding" class="container branding"> 101 <div class="row container"> 102 <div id="acgov-logo" class="col-sm-6 col-xs-12 logo"> 103 <a href="/index.htm"> 104 <img id="acgovlogo" class="img-responsive acgov-logo" src="/img/acgov-branding2024.png" alt="Alameda County CA acgov Home" /> 105 </a> 106 </div> 107 <div id="acgov-tagline" class="col-sm-6 col-xs-12 tagline"> 108 <!-- Accessible Translate trigger (top) --> 109 <a id="translate-trigger-top" href="#" role="button" data-toggle="modal" data-target="#modal-trans" aria-haspopup="dialog" aria-controls="modal-trans" aria-expanded="false"> 110 <span class="material-icons md-24 trans-icon"></span> Translate 111 </a> 112 </div> 113 </div> 114 </div> 115 116 <!-- Sticky / scrolled branding --> 117 <div id="acgov-branding-scroll" class="container branding" style="display:none;"> 118 <div class="row container"> 119 <div id="logo-scroll" class="col-sm-2 col-xs-12 logo"> 120 <a href="/index.htm"> 121 <img class="img-responsive acgov-logo" src="/img/acgov-branding2024.png" alt="ACGOV Logo" /> 122 </a> 123 </div> 124 <div id="spacer" class="col-sm-5 col-xs-12 spacer"></div> 125 <div id="tagline-scroll" class="col-sm-5 col-xs-12 tagline-scroll"> 126 <!-- Accessible Translate trigger (sticky) --> 127 <a id="translate-trigger-scroll" href="#" role="button" data-toggle="modal" data-target="#modal-trans" aria-haspopup="dialog" aria-controls="modal-trans" aria-expanded="false"> 128 <span class="material-icons md-24 trans-icon"></span> Translate 129 </a> 130 </div> 131 </div> 132 </div> 133</header> 134
135<script> 136 // ===== Sticky header behavior (original, now with null-safety) ===== 137 window.onscroll = changePos; 138 function changePos() { 139 var branding = document.getElementById("acgov-branding"); 140 var brandingscroll = document.getElementById("acgov-branding-scroll"); 141 var tagline = document.getElementById("acgov-tagline"); 142 var logo = document.getElementById("acgovlogo"); 143 144 if (document.documentElement.clientWidth >= 768) { 145 if (window.pageYOffset > 57) { 146 if (branding) branding.style.display = "none"; 147 if (brandingscroll) brandingscroll.style.display = "block"; 148 } else { 149 if (branding) branding.style.display = "block"; 150 if (brandingscroll) brandingscroll.style.display = "none"; 151 } 152 } else { 153 if (window.pageYOffset > 57) { 154 if (tagline) tagline.style.display = "none"; 155 if (logo) logo.style.maxWidth = "200px"; 156 } else { 157 if (tagline) tagline.style.display = "block"; 158 if (logo) logo.style.maxWidth = "100%"; 159 } 160 } 161 } 162 163 // ===== Accessibility: aria-expanded sync + focus trap for #modal-trans ===== 164 document.addEventListener("DOMContentLoaded", function () { 165 var modal = document.getElementById("modal-trans"); 166 if (!modal) return; // modal needs to exist 167 168 // Collect both triggers, if present 169 var triggers = [ 170 document.getElementById("translate-trigger-top"), 171 document.getElementById("translate-trigger-scroll") 172 ].filter(Boolean); 173 174 // Remember which trigger opened the modal (for focus restore + aria state) 175 var lastTrigger = null; 176 177 // When a trigger is clicked, record it as the opener 178 triggers.forEach(function (t) { 179 t.addEventListener("click", function () { lastTrigger = t; }, { capture: true }); 180 }); 181 182 // Helper: set aria-expanded on all triggers (defaults to "false") 183 function setExpandedForTriggers(value) { 184 triggers.forEach(function (t) { 185 t.setAttribute("aria-expanded", value ? "true" : "false"); 186 }); 187 } 188 189 // Bootstrap modal events 190 modal.addEventListener("shown.bs.modal", function (evt) { 191 // Prefer the event's relatedTarget (Bootstrap sets it), else use lastTrigger 192 var opener = evt && evt.relatedTarget ? evt.relatedTarget : lastTrigger; 193 // First set all to false, then true on the opener (for accuracy) 194 setExpandedForTriggers(false); 195 if (opener && opener.setAttribute) opener.setAttribute("aria-expanded", "true"); 196 197 // Move focus to the first meaningful element inside the modal 198 var focusables = getFocusableElements(modal); 199 if (focusables.length) { 200 var preferred = modal.querySelector('[data-primary], .btn-primary, [data-dismiss="modal"], .close'); 201 (preferred && typeof preferred.focus === "function" ? preferred : focusables[0]).focus(); 202 } 203 204 // Start focus trap 205 modal.addEventListener("keydown", trapTabKey); 206 }); 207 208 modal.addEventListener("hidden.bs.modal", function () { 209 // Reset aria-expanded for all triggers 210 setExpandedForTriggers(false); 211 212 // Stop focus trap 213 modal.removeEventListener("keydown", trapTabKey); 214 215 // Restore focus to the opener, if available 216 if (lastTrigger && typeof lastTrigger.focus === "function") { 217 lastTrigger.focus(); 218 } 219 lastTrigger = null; 220 }); 221 222 // ===== Focus trap helpers ===== 223 function getFocusableElements(container) { 224 var selector = [ 225 'a[href]:not([tabindex="-1"])', 226 'area[href]:not([tabindex="-1"])', 227 'input:not([type="hidden"]):not([disabled]):not([tabindex="-1"])', 228 'select:not([disabled]):not([tabindex="-1"])', 229 'textarea:not([disabled]):not([tabindex="-1"])', 230 'button:not([disabled]):not([tabindex="-1"])', 231 'iframe:not([tabindex="-1"])', 232 'audio[controls]:not([tabindex="-1"])', 233 'video[controls]:not([tabindex="-1"])', 234 '[contenteditable]:not([tabindex="-1"])', 235 '[tabindex]:not([tabindex="-1"])' 236 ].join(','); 237 238 return Array.prototype.slice.call(container.querySelectorAll(selector)) 239 .filter(function (el) { 240 return el.offsetWidth > 0 || el.offsetHeight > 0 || el.getClientRects().length > 0; 241 }); 242 } 243 244 function trapTabKey(e) { 245 if (e.key !== "Tab") return; 246 247 var focusables = getFocusableElements(modal); 248 if (!focusables.length) return; 249 250 var first = focusables[0]; 251 var last = focusables[focusables.length - 1]; 252 var active = document.activeElement; 253 254 if (e.shiftKey) { 255 if (active === first || !modal.contains(active)) { 256 last.focus(); 257 e.preventDefault(); 258 } 259 } else { 260 if (active === last || !modal.contains(active)) { 261 first.focus(); 262 e.preventDefault(); 263 } 264 } 265 } 266 }); 267</script>
267 268 <div role="search" class="container searchbox"> 269<!--<div class="container urgent"> 270 <div class="row"> 271 <p><i class="material-icons md-48 md-vertical-middle"></i> This is a sample urgent notification box. Please click here for more information: <a href="as">Urgent Link</a></p> 272 </div> 273</div>--> 274 <!-- <div class="container info-msg"> 275 <div class="row"> 276 <p><span class="material-icons md-48 md-vertical-middle">warning</span><strong>Upcoming Website Outages</strong><br> Due to upcoming maintenance, you may encounter errors when accessing County websites this Sunday, August 10th.<br>We apologize for any inconvenience.</p> 277 </div> 278 </div> --> 279<div class="container info-msg"> 280 <div class="row"> 281 <p><span class="material-icons md-48 md-vertical-middle">info</span> Alameda County is gradually transitioning our websites to a new .GOV domain name: "alamedacountyca.gov".</br><a href="/government/dotgov.htm">Learn more</a><span class="material-icons md-32 md-vertical-middle">arrow_forward</span></p> 282 </div> 283 </div> 284 285 <div class="row search"> 286 <form id="search-form" style="margin: auto; width: 90%;" method="get" action="https://acsearch.acgov.org/s/search.html?" target="_parent" type="external"> 287 <div class="input-group"> 288 <label for="funnelbackinput" class="sr-only">Search</label> 289 290 <input id="funnelbackinput" type="search" name="query" class="form-control search-input" placeholder="What can we help you find today?" aria-label="Search"> 291 <span class="input-group-addon"> 292 <button type="submit" class="btn search-button" name="btnG" value="Search" aria-label="Submit search">Search</button> 293 </span> 294 </div> 295 <input type="hidden" name="collection" value="acgov" /> 296 <input type="hidden" name="profile" value="acgov"> 297 <input type="hidden" name="form" value="acgov" /> 298 </form> 299 </div> 300</div> 301<!-- skip to content jumplink destination <div> starts here--> 302<div role="main" id="content"> 303 <!-- ending </div> is located at begining of footer --> 304 <!-- Google Translate the Pages ---------------------------------> 305<div class="modal fade" id="modal-trans" tabindex="-1" role="dialog" aria-modal="true" aria-labelledby="modal-title" aria-describedby="modal-desc"> 306 <div class="modal-dialog" role="document"> 307 <div class="modal-content"> 308 <div class="modal-header"> 309 310 <!-- Close button: accessible label + visual "Ã" --> 311 <button type="button" class="close" data-dismiss="modal" aria-label="Close dialog"> 312 <span aria-hidden="true">×</span> 313 <span class="sr-only">Close</span> 314 </button> 315 316 <!-- Modal title with id referenced by aria-labelledby --> 317 <h3 class="modal-title" id="modal-title">Translate this Page</h3> 318 </div> 319 320 <!-- Body gets an id referenced by aria-describedby --> 321 <div class="modal-body deptinfo" id="modal-desc"> 322 <h4>Disclaimer</h4> 323 <p>Translation of pages on ACGOV.org is performed by Google Translate, a third-party service which Alameda County has no control over. The service provides automated computer translations that are only an approximation of the websitesâ original content.</p> 324 <p>Alameda County does not warrant the accuracy, reliability, or timeliness of any information translated by Google Translate. These translations should not be considered exact renderings of the original ACGOV.org site. Some portions of the site will not be translated at all, which includes but is not limited to buttons, graphics, photos, and video content.</p> 325 326 <!-- Keep the widget container as its own block (avoid nesting <div> inside <p>) --> 327 <div class="mt-3" id="google_translate_element"></div> 328 </div> 329 330 <!-- Optional footer with an explicit close action for keyboard users --> 331 <div class="modal-footer"> 332 <button type="button" class="btn btn-primary" data-dismiss="modal" data-primary>Close</button> 333 </div> 334 </div> 335 </div> 336</div> 337
338<script> 339(function () { 340 var attempts = 0; 341 var maximumAttempts = 60; 342 343 function attachTranslationTracking() { 344 var dropdown = document.querySelector(".goog-te-combo"); 345 346 if (!dropdown) { 347 attempts++; 348 349 if (attempts < maximumAttempts) { 350 window.setTimeout(attachTranslationTracking, 500); 351 } else { 352 console.warn("Translation tracking: Google Translate dropdown was not found."); 353 } 354 355 return; 356 } 357 358 if (dropdown.getAttribute("data-siteimprove-tracking") === "true") { 359 return; 360 } 361 362 dropdown.setAttribute("data-siteimprove-tracking", "true"); 363 364 dropdown.addEventListener("change", function () { 365 var selectedOption = this.options[this.selectedIndex]; 366 367 if (!this.value || !selectedOption) { 368 return; 369 } 370 371 var languageName = selectedOption.text.trim(); 372 373 console.log( 374 "Siteimprove translation event:", 375 this.value, 376 languageName 377 ); 378 379 window._sz = window._sz || []; 380 window._sz.push([ 381 "event", 382 "Translation", 383 "Language selected", 384 languageName 385 ]); 386 }); 387 388 console.log("Translation tracking attached."); 389 } 390 391 attachTranslationTracking(); 392})(); 393</script>
393 394 <div class="container content"> 395 <div class="row row-title"> 396 <h1 class="pagetitle">.GOV Transition</h1> 397 <a href="#" data-toggle="modal" data-target="#modal-trans"><span class="material-icons md-48 trans-icon"></span></a> 398 </div> 399 <div class="row regular"> 400 <div class="col-xs-12 col-sm-8 main-column"> 401 <p>Alameda County is committed to providing secure and reliable information on our websites. We want you to trust that our websites are the "official" websites of Alameda County. This is the primary reason why we are transitioning our websites to .GOV domain names.</p> <p>Our websites will gradually transition from "acgov.org" to "alamedacountyca.gov". In the meantime, you will see "official" Alameda County websites with both domain names.</p> 402 <h2>What is .GOV?</h2> 403 <p>The .GOV domain name indicates that a website is owned by an official US government organization. The DotGov program examines each request for a .gov domain name to ensure it is from a genuine US-based government or public sector organization.</p> 404 <h2>Why .GOV?</h2> 405 <h3>Trust</h3> 406 <p>You are more likely to trust the information on a .GOV website because it has been vetted and approved by a government agency. This is especially important in regard to election results.</p> 407 <h3>Authority</h3> 408 <p>A .GOV website is considered an authoritative source of information, which can increase the website's visibility and ranking in search engines.</p> 409 <h3>Identification</h3> 410 <p>Using a .GOV domain shows we are official.</p> 411 <h3>Credibility</h3> 412 <p>All branches of the United States federal government use a .GOV domain. Information such as Census statistics, Congressional hearings, and Supreme Court rulings would be included in sites with this domain.</p> 413 <h3>Legally Required</h3> 414 <p>California State Assembly Bill No. 1637 requires all local government agencies to use a .GOV domain name no later than January 1, 2029.</p> 415 <h2>When is this happening?</h2> 416 <p>The transition of all our websites to .GOV domain names will be a long process. We have already launched our first .GOV website with more to come. The transition will also include our employees' official email addresses.</p> 417 </div> 418 <div class="col-xs-12 col-sm-4 side-column bordered"> 419 <div id="related"> 420 <h2><span class="material-icons md-36 md-vertical-middle"></span> Related Links</h2> 421 <ul> 422 <li><a href="https://get.gov/" class="external-link">Official .GOV Registry</a></li> 423 424 </ul> 425 </div> 426 </div> 427 </div> 428 <!-- Modal Window --> 429 <div class="modal fade" id="modal-govd" tabindex="-1" role="dialog" aria-label="Email subscription sign-up"> 430 <div class="modal-dialog" role="document"> 431 <div class="modal-content"> 432 <div class="modal-header"> 433 <button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">×</span></button> 434 <h3 class="modal-title"><span class="material-icons md-36 md-vertical-middle"></span> Get Email Updates</h3> 435 </div> 436 <div class="modal-body deptinfo"> 437 <form id="GD-snippet-form" action="https://public.govdelivery.com/accounts/CAALAME/subscribers/qualify" accept-charset="UTF-8" method="post"><input name="utf8" type="hidden" value="â" /><input type="hidden" name="authenticity_token" value="Og1izipZAapbmVioBvav08Yp6RF2enmpMVaUvFUWIgWjE8h632WdH4pZz4jP0NJoSB6RtqPGddhUnED3QpqZSQ==" /> 438 <input type="hidden" name="topic_id" id="topic_id" value="CAALAME" /> 439 <fieldset> 440 <div> 441 Join our email subscription lists and get notified by email when updates happen. To sign up for updates or to access your subscriber preferences, please enter your contact information below. 442 </div> 443 <ol class="form"> 444 <li class="email_fields" style="display: block"> 445 <label for="email">Email Address</label> 446 <input type="text" name="email" id="email" class="long" /> 447 </li> 448 </ol> 449 <div class="button_panel"> 450 <input type="submit" name="commit" value="Subscribe" class="form_button" /> 451 </div> 452 </fieldset> 453 </form> 454 </div> 455 </div> 456 </div> 457 </div> 458 </div> 459 <!-- ending of role="main" here--> 460</div> 461 462<!-- footer starts here --> 463<footer class="container-fluid footer"> 464 <div class="row text-center"> 465 <p> 466 <a class="cu" href="/government/contactus.htm">Contact Us</a> | 467 <a class="acc" href="/government/accessibility.htm">Accessibility</a> | 468 <a class="la" href="/acspeaks/">Language Access</a> | 469 <a class="em" href="/emergencysite/">
469Emergencies</a> | 470 <a class="ld" href="/government/legal.htm">Legal/Disclaimers</a> | 471 <a class="ps" href="/government/legal.htm">Privacy Statement</a> | 472 <a class="gu" href="/government/guidelines.htm">Website Guidelines</a> | 473 <a class="sb" href="/government/sb272.htm">SB 272 </a> | 474 <a class="sm" href="/sitemap.htm">Site Map</a> 475 <br /> 476 <a href="https://www.facebook.com/AlamedaCounty" class="external-link"><img class="social-icon" src="/img/facebook200x200.png" alt="facbook icon" /></a> 477 <a href="https://twitter.com/AlamedaCounty" class="external-link"><img class="social-icon" src="/img/twitter200x200.png" alt="Twitter icon" /></a> 478 <a href="https://www.youtube.com/user/AlamedaCountyCA" class="external-link"><img class="social-icon" src="/img/youtube200x200.png" alt="YouTube icon" /></a> 479 <a href="https://www.flickr.com/photos/alamedacounty" class="external-link"><img class="social-icon" src="/img/flickr200x200.png" alt="Flickr icon" /></a> 480 <a href="/government/connected/rss.htm"><img class="social-icon" src="/img/rss200x200.png" alt="RSS icon" /></a> 481 <a href="https://public.govdelivery.com/accounts/CAALAME/subscriber/new" class="external-link"><img class="social-icon" src="/img/govdelivery200x200.png" alt="GovDelivery icon" /></a> 482 <br /> 483 <a href="http://www.adobe.com/go/getreader" class="external-link"> 484 <img alt="Get Adobe Reader" style="padding: 10px;" src="/img/get-reader.png" /></a> 485 <br /> 486 <span class="material-icons md-18" style="vertical-align:bottom"></span> 2025 Alameda County 487 </p> 488 </div> 489</footer> 490 491<!-- Bootstrap core JavaScript 492================================================== --> 493<!-- Placed at the end of the document so the pages load faster --> 494
495<script type="text/javascript"> 496function googleTranslateElementInit() { 497 new google.translate.TranslateElement({pageLanguage: 'en', includedLanguages: 'af,am,ar,de,es,fa,fr,gu,hi,id,ja,km,ko,pt,ru,so,sw,tl,ur,vi,yo,zh-CN,zh-TW'}, 'google_translate_element'); 498} 499</script>
499<script type="text/javascript" src="//translate.google.com/translate_a/element.js?cb=googleTranslateElementInit"></script>
499 500 501
502<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.3/jquery.min.js"></script>
502
503<script>window.jQuery || document.write('
503<script src="/acgov-js/jquery.min.js"><\/script>')</script>
503
504<script src="/acgov-js/bootstrap.min.js"></script>
504 505<!-- IE10 viewport hack for Surface/desktop Windows 8 bug -->
506<script src="/acgov-js/ie10-viewport-bug-workaround.js"></script>
506 507<!-- Google Analytics code -->
508<script>
vendor: 340 bytes, lines 508-514
508 509 (function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){ 510 (i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o), 511 m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m) 512 })(window,document,'script','//www.google-analytics.com/analytics.js','ga'); 513 514 ga('create', '
514UA-48660008-1
vendor: 44 bytes, lines 514-515
514', 'acgov.org'); 515 ga('send', 'pageview');
516</script>
516 517 518 519 520<!-- External Links--> 521<!-- External Link Popup - HTML structure --> 522<div id="external-popup" class="popup-overlay" role="dialog" aria-labelledby="popup-title" aria-hidden="true"> 523 <div class="popup-content"> 524 <button id="close-external-popup" class="popup-close" aria-label="Close">X</button> 525 <p><img src="/img/external-site-icon.svg" width="50px" alt="External Link" class="popup-icon"></p> 526 <h2 id="popup-title">External Link</h2> 527 <p>You are about to leave an official Alameda County website. 528 Alameda County bears no responsibility for the accuracy, legality, accessibility, or content of the external site or for that of subsequent links. 529 Contact the external site for answers to questions regarding its content.</p> 530 <div class="popup-button-container"> 531 <button id="cancel-external" class="popup-button btn btn-default btn-lg">Cancel</button> 532 <button id="continue-external" class="popup-button btn btn-success btn-lg">Continue</button> 533 </div> 534 </div> 535</div> 536 537<!-- External Link Popup JavaScript -->
538<script> 539 document.addEventListener("DOMContentLoaded", function () { 540 const modal = document.getElementById("external-popup"); 541 const closeButton = document.getElementById("close-external-popup"); 542 const cancelButton = document.getElementById("cancel-external"); 543 const continueButton = document.getElementById("continue-external"); 544 545 // CHANGED: store the actual trigger element (the link), not document.activeElement 546 let lastTriggerEl = null; 547 548 let popupShownInSession = sessionStorage.getItem('externalPopupShown') === 'true'; 549 550 // (Optional but recommended) Make sure dialog semantics are present 551 if (!modal.hasAttribute('role')) modal.setAttribute('role', 'dialog'); 552 if (!modal.hasAttribute('aria-modal')) modal.setAttribute('aria-modal', 'true'); 553 554 function getFocusableInModal() { 555 const nodeList = modal.querySelectorAll( 556 "button, [href], input, select, textarea, [tabindex]:not([tabindex='-1'])" 557 ); 558 return Array.from(nodeList).filter(el => !el.hasAttribute('disabled') && el.offsetParent !== null); 559 } 560 561 // CHANGED: accept the trigger element; derive URL from it 562 function openModal(triggerEl) { 563 lastTriggerEl = triggerEl; // <-- save the invoker reliably 564 const externalURL = triggerEl?.href; 565 566 modal.style.display = "block"; 567 modal.setAttribute("aria-hidden", "false"); 568 569 // Move focus inside the dialog (prefer the close button; fallback to first focusable or modal) 570 const focusables = getFocusableInModal(); 571 (closeButton || focusables[0] || modal).focus(); 572 573 continueButton.onclick = () => { 574 sessionStorage.setItem('externalPopupShown', 'true'); 575 popupShownInSession = true; 576 if (externalURL) window.location.href = externalURL; 577 }; 578 cancelButton.onclick = closeModal; 579 closeButton.onclick = closeModal; 580 581 document.addEventListener("keydown", trapTabKey); 582 document.addEventListener("keydown", closeOnEscape); 583 584 // If you want "once per session" behavior on open, keep this: 585 sessionStorage.setItem('externalPopupShown', 'true'); 586 popupShownInSession = true; 587 } 588 589 function closeModal() { 590 modal.style.display = "none"; 591 modal.setAttribute("aria-hidden", "true"); 592 593 document.removeEventListener("keydown", trapTabKey); 594 document.removeEventListener("keydown", closeOnEscape); 595 596 // CHANGED: restore focus to the invoker on the next frame for VO/Safari reliability 597 if (lastTriggerEl && lastTriggerEl.isConnected) { 598 requestAnimationFrame(() => { 599 try { 600 lastTriggerEl.focus({ preventScroll: false }); 601 } catch (_) { 602 // Silent fallback 603 lastTriggerEl.focus(); 604 } 605 }); 606 } 607 } 608 609 function trapTabKey(e) { 610 if (e.key !== "Tab") return; 611 612 const focusableElements = getFocusableInModal(); 613 if (!focusableElements.length) return; 614 615 const firstElement = focusableElements[0]; 616 const lastElement = focusableElements[focusableElements.length - 1]; 617 618 if (e.shiftKey && document.activeElement === firstElement) { 619 lastElement.focus(); 620 e.preventDefault(); 621 } else if (!e.shiftKey && document.activeElement === lastElement) { 622 firstElement.focus(); 623 e.preventDefault(); 624 } 625 } 626 627 function closeOnEscape(e) { 628 if (e.key === "Escape") { 629 e.preventDefault(); 630 closeModal(); 631 } 632 } 633 634 function setupExternalLinks() { 635 document.querySelectorAll('a.external-link').forEach(link => { 636 if (link.children.length === 1 && link.querySelector("button, img, span.material-icons, i.material-icons")) { 637 link.classList.add("hide-icon"); 638 } 639 640 // CHANGED: pass the actual link as the trigger 641 link.addEventListener('click', function (e) { 642 e.preventDefault(); 643 openModal(link); // was openModal(link.href) 644 }); 645 646 // CHANGED: nested clickable children also pass the link as trigger 647 link.querySelectorAll("button, img").forEach(element => { 648 element.addEventListener("click", function (e) { 649 e.preventDefault(); 650 openModal(link); // was openModal(link.href) 651 }); 652 }); 653 654 // ARIA hint that this opens a dialog 655 if (!link.hasAttribute("aria-haspopup")) { 656 link.setAttribute("aria-haspopup", "dialog"); 657 } 658 }); 659 } 660 661 modal.style.display = "none"; 662 modal.setAttribute("aria-hidden", "true"); 663 664 setupExternalLinks(); 665 666 window.addEventListener('pageshow', (event) => { 667 if (event.persisted && popupShownInSession) { 668 modal.style.display = "none"; 669 modal.setAttribute("aria-hidden", "true"); 670 } 671 }); 672 673 window.addEventListener('beforeunload', () => { 674 sessionStorage.removeItem('externalPopupShown'); 675 }); 676 }); 677</script>
677 678 679<!-- Automatically sets aria label for phone, email, directions icons -->
680<script> 681 const iconGlyphMap = { 682 '\uE0CD': 'Phone', 683 '\uE0BE': 'Email', 684 '\uE52E': 'Get directions' 685 }; 686 687 document.querySelectorAll('.material-icons').forEach(icon => { 688 const glyph = icon.textContent.trim(); 689 if (iconGlyphMap[glyph]) { 690 icon.setAttribute('aria-label', iconGlyphMap[glyph]); 691 icon.setAttribute('role', 'img'); 692 } 693 }); 694</script>
694 695</body> 696 697 698 699<!-- Siteimprove Analytics Code -->
700<script async src="https://siteimproveanalytics.com/js/siteanalyze_10984.js"></script>
700 701 702 703 704</body> 705</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.