1// Master Collective â progressive enhancement only. The full experience and all meaningful content remain available in static HTML. 2(() => { 3 const header = document.querySelector('[data-header]'); 4 const menuToggle = document.querySelector('[data-menu-toggle]'); 5 const primaryNav = document.querySelector('#primary-navigation'); 6 7 const updateHeader = () => { 8 if (!header) return; 9 header.classList.toggle('is-scrolled', window.scrollY > 16); 10 }; 11 12 updateHeader(); 13 window.addEventListener('scroll', updateHeader, { passive: true }); 14 15 if (menuToggle && primaryNav) { 16 const mobileBreakpoint = window.matchMedia('(max-width: 820px)'); 17 const firstMenuLink = primaryNav.querySelector('.nav-links a'); 18 19 const setMenuState = (open) => { 20 const active = Boolean(open && mobileBreakpoint.matches); 21 document.body.classList.toggle('menu-open', active); 22 menuToggle.setAttribute('aria-expanded', String(active)); 23 primaryNav.setAttribute('aria-hidden', String(!active && mobileBreakpoint.matches)); 24 25 if ('inert' in primaryNav) primaryNav.inert = !active && mobileBreakpoint.matches; 26 if (active) window.requestAnimationFrame(() => firstMenuLink?.focus()); 27 }; 28 29 const closeMenu = () => setMenuState(false); 30 const syncMenuState = () => { 31 if (mobileBreakpoint.matches) closeMenu(); 32 else { 33 document.body.classList.remove('menu-open'); 34 menuToggle.setAttribute('aria-expanded', 'false'); 35 primaryNav.setAttribute('aria-hidden', 'false'); 36 if ('inert' in primaryNav) primaryNav.inert = false; 37 } 38 }; 39 40 syncMenuState(); 41 mobileBreakpoint.addEventListener('change', syncMenuState); 42 menuToggle.addEventListener('click', () => setMenuState(!document.body.classList.contains('menu-open'))); 43 primaryNav.querySelectorAll('a').forEach((item) => item.addEventListener('click', closeMenu)); 44 window.addEventListener('keydown', (event) => { 45 if (event.key === 'Escape') closeMenu(); 46 }); 47 } 48 49 const considerationForm = document.querySelector('[data-club-consideration-form]'); 50 if (considerationForm) { 51 considerationForm.addEventListener('submit', async (event) => { 52 event.preventDefault(); 53 if (!considerationForm.reportValidity()) return; 54 55 const endpointReady = considerationForm.dataset.endpointReady === 'true'; 56 const endpoint = considerationForm.dataset.endpoint || ''; 57 const status = considerationForm.querySelector('.club-form-status'); 58 const button = considerationForm.querySelector('button[type="submit"]'); 59 if (!endpointReady || !endpoint) { 60 if (status) status.textContent = considerationForm.dataset.errorLabel || 'Secure submission is not yet available.'; 61 return; 62 } 63 64 if (button) { 65 button.disabled = true; 66 button.dataset.label = button.textContent; 67 button.textContent = considerationForm.dataset.processingLabel || 'Submittingâ¦'; 68 } 69 70 try { 71 const body = new URLSearchParams(new FormData(considerationForm)); 72 await fetch(endpoint, { 73 method: 'POST', 74 mode: 'no-cors', 75 headers: { 'Content-Type': 'application/x-www-form-urlencoded;charset=UTF-8' }, 76 body, 77 keepalive: true, 78 }); 79 window.location.assign(considerationForm.dataset.thankYouPath || '/club-consideration-received/'); 80 } catch (error) { 81 if (status) status.textContent = considerationForm.dataset.errorLabel || 'Secure submission could not be completed.'; 82 if (button) { 83 button.disabled = false; 84 button.textContent = button.dataset.label || button.textContent; 85 } 86 } 87 }); 88 } 89 90 const spotlightForm = document.querySelector('[data-spotlight-form]'); 91 if (spotlightForm) { 92 spotlightForm.addEventListener('submit', (event) => { 93 event.preventDefault(); 94 if (!spotlightForm.reportValidity()) return; 95 96 const thanks = document.querySelector('[data-spotlight-thanks]'); 97 spotlightForm.hidden = true; 98 if (thanks) { 99 thanks.hidden = false;
100 thanks.focus(); 101 } 102 }); 103 } 104 105 const universityForm = document.querySelector('[data-university-form]'); 106 if (universityForm) { 107 universityForm.addEventListener('submit', (event) => { 108 event.preventDefault(); 109 if (!universityForm.reportValidity()) return; 110 111 const thanks = document.querySelector('[data-university-thanks]'); 112 universityForm.hidden = true; 113 if (thanks) { 114 thanks.hidden = false; 115 thanks.focus(); 116 } 117 }); 118 } 119 120 const partnerForm = document.querySelector('[data-partner-form]'); 121 if (partnerForm) { 122 partnerForm.addEventListener('submit', (event) => { 123 event.preventDefault(); 124 if (!partnerForm.reportValidity()) return; 125 126 const thanks = document.querySelector('[data-partner-thanks]'); 127 partnerForm.hidden = true; 128 if (thanks) { 129 thanks.hidden = false; 130 thanks.focus(); 131 } 132 }); 133 } 134 135 const mAndAForm = document.querySelector('[data-m-and-a-form]'); 136 if (mAndAForm) { 137 mAndAForm.addEventListener('submit', (event) => { 138 event.preventDefault(); 139 if (!mAndAForm.reportValidity()) return; 140 window.location.assign(mAndAForm.dataset.thankYouPath || '/m-and-a-application-received/'); 141 }); 142 } 143 144 const postFundingForm = document.querySelector('[data-post-funding-form]'); 145 if (postFundingForm) { 146 postFundingForm.addEventListener('submit', (event) => { 147 event.preventDefault(); 148 if (!postFundingForm.reportValidity()) return; 149 150 const thanks = document.querySelector('[data-post-funding-thanks]'); 151 postFundingForm.hidden = true; 152 if (thanks) { 153 thanks.hidden = false; 154 thanks.focus(); 155 } 156 }); 157 } 158 159 const insightsFilter = document.querySelector('[data-insights-filter]'); 160 if (insightsFilter) { 161 const search = insightsFilter.querySelector('[data-insights-search]'); 162 const topicButtons = [...insightsFilter.querySelectorAll('[data-insights-topic]')]; 163 const cards = [...document.querySelectorAll('[data-insights-card]')]; 164 const emptyState = document.querySelector('[data-insights-empty]'); 165 let activeTopic = ''; 166 const normalize = (value) => String(value || '').trim().toLocaleLowerCase(); 167 168 const applyFilters = () => { 169 const query = normalize(search?.value); 170 let visibleCount = 0; 171 cards.forEach((card) => { 172 const matchesQuery = !query || normalize(card.dataset.search).includes(query); 173 const topics = String(card.dataset.topic || '').split('|').map(normalize).filter(Boolean); 174 const matchesTopic = !activeTopic || topics.includes(activeTopic); 175 const visible = matchesQuery && matchesTopic; 176 card.hidden = !visible; 177 card.classList.toggle('is-filtered-out', !visible); 178 card.setAttribute('aria-hidden', String(!visible)); 179 if (visible) visibleCount += 1; 180 }); 181 if (emptyState) emptyState.hidden = visibleCount !== 0; 182 }; 183 184 search?.addEventListener('input', applyFilters); 185 search?.addEventListener('search', applyFilters); 186 topicButtons.forEach((button) => button.addEventListener('click', () => { 187 activeTopic = normalize(button.dataset.insightsTopic); 188 topicButtons.forEach((item) => { 189 const active = item === button; 190 item.classList.toggle('is-active', active); 191 item.setAttribute('aria-pressed', String(active)); 192 }); 193 applyFilters(); 194 })); 195 insightsFilter.dataset.ready = 'true'; 196 applyFilters(); 197 } 198})();
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.