1/** 2 * Georgia Residents promo card visibility / link rewriter. 3 * 4 * Two locations carry a "Login to Verify" CTA tied to the Georgia Residents 5 * Summer 2026 promo: the home page's Immersive Hero promo slider, and a card 6 * on the Special Offers page. This script reads the JS-readable resident 7 * cookie (STYXKEY_GAQ_GARES, set by the Tessitura-GAI plugin â see 8 * TessAPI::setGAResidentCookie() and the three triggers in TessAPI.php + 9 * RestAPI.php + session.js) and adjusts those cards accordingly: 10 * 11 * - Cookie absent (guest / pre-cookie session) â leave UI untouched. 12 * - Cookie === '1' (logged-in GA resident) â rewrite the CTA href to 13 * /tickets and change the 14 * visible text to "Buy Tickets". 15 * - Cookie === '0' (logged-in non-resident) â remove the entire slide / 16 * card from the DOM. If the 17 * removal leaves the immersive 18 * hero promo slider with 0 19 * slides, remove the whole 20 * drawer; with 1 slide, hide 21 * the prev/next controls. 22 * 23 * Detection is text-based: any <a> whose normalized text is "login to verify" 24 * AND whose nearest ancestor matches the page-scoped block selector set is 25 * treated as a resident promo CTA. The containment gate is what prevents an 26 * unrelated "Login to Verify" link elsewhere on a page from being hijacked. 27 * 28 * This script is enqueued as a standalone footer file with no $(document).ready 29 * wrapper, so the IIFE runs synchronously at parse time after the DOM is 30 * parsed but before new_home_scripts.js (which initializes the immersive hero 31 * slider) executes. functions.php enforces that load order by adding this 32 * script to new_home_scripts' dependency array. 33 */ 34(function() { 35 'use strict'; 36 37 var match = document.cookie.match(/(?:^|;\s*)STYXKEY_GAQ_GARES=(\d)/); 38 var residentState = match ? match[1] : null; 39 if (residentState === null) { return; } // guest / pre-cookie â bail out 40 41 // Page-scoped block selectors. The home-page slide selector is global 42 // (only present on pages that render the Immersive Hero). The Special 43 // Offers card selector is intentionally scoped to /special-offers so a 44 // future page that happens to reuse .options-grid__element doesn't pick 45 // up resident-promo behavior unintentionally. 46 var path = window.location.pathname.replace(/\/+$/, ''); 47 var blockSelectors = ['.immersive-hero__promo-slide']; 48 if (path === '/special-offers') { 49 blockSelectors.push('.options-grid__element'); 50 } 51 var BLOCK_SELECTORS = blockSelectors.join(','); 52 53 function findResidentCTAs() { 54 var ctas = []; 55 var anchors = document.querySelectorAll('a'); 56 for (var i = 0; i < anchors.length; i++) { 57 var a = anchors[i]; 58 if ((a.textContent || '').trim().toLowerCase() === 'login to verify') { 59 ctas.push(a); 60 } 61 } 62 return ctas; 63 } 64 65 // Returns true if cta should be handled even outside a BLOCK_SELECTORS 66 // container â currently: any <a class="button"> with the resident-promo text. 67 function isStandaloneResidentCTA(cta) { 68 return cta.classList.contains('button'); 69 } 70 71 function rewriteCtaText(cta, newText) { 72 // Most CTAs in this codebase wrap their visible label in a 73 // <span class="button__text">. Prefer that when present so the 74 // adjacent .link__arrow / svg children are preserved untouched. 75 var btnText = cta.querySelector('.button__text'); 76 if (btnText) { 77 btnText.textContent = newText; 78 return; 79 } 80 // Fallback: replace the first non-empty text node in the link's 81 // direct children. This preserves element children like inline SVGs. 82 for (var i = 0; i < cta.childNodes.length; i++) { 83 var n = cta.childNodes[i]; 84 if (n.nodeType === 3 /* TEXT_NODE */ && n.nodeValue.trim()) { 85 n.nodeValue = newText; 86 return; 87 } 88 } 89 // Last resort â nothing matched. Overwrite the link content entirely. 90 cta.textContent = newText; 91 } 92 93 var removalsHappened = false;
94 95 findResidentCTAs().forEach(function(cta) { 96 var card = cta.closest(BLOCK_SELECTORS); 97 if (!card && !isStandaloneResidentCTA(cta)) { return; } 98 99 if (residentState === '1') { 100 cta.href = '/tickets'; 101 rewriteCtaText(cta, 'Buy Tickets'); 102 } else if (residentState === '0') { 103 // For standalone button CTAs with no containing card, remove the 104 // button itself rather than a parent block. 105 var target = card || cta; 106 target.parentNode && target.parentNode.removeChild(target); 107 removalsHappened = true; 108 } 109 }); 110 111 // Immersive Hero promo drawer cleanup. Mirrors the masthead pattern in 112 // assets/js/new-home/masthead.js (~lines 27-39): after the targeted 113 // children are removed, recount and either kill the whole drawer (0 114 // slides) or just hide the prev/next nav (1 slide). Only runs when we 115 // actually removed something, so the resident-state-'1' path and the 116 // no-op guest path don't touch the drawer. 117 if (removalsHappened) { 118 var drawers = document.querySelectorAll('.immersive-hero__promo'); 119 for (var d = 0; d < drawers.length; d++) { 120 var drawer = drawers[d]; 121 var remaining = drawer.querySelectorAll('.immersive-hero__promo-slide').length; 122 if (remaining === 0) { 123 drawer.parentNode && drawer.parentNode.removeChild(drawer); 124 } else if (remaining === 1) { 125 var bottom = drawer.querySelector('.immersive-hero__promo-bottom'); 126 if (bottom) { 127 bottom.classList.add('immersive-hero__promo-bottom--hidden'); 128 } 129 } 130 } 131 } 132})();
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.