1// GOOGLE SHEETS CONFIG 2var SHEETS = { 3 banner: 'https://docs.google.com/spreadsheets/d/e/2PACX-1vQi4aHMdzZZtSyXUUwjUhFT8zgLMOFP9d3TnnjO56ToerUSz6hjxu448TvrtxQ2KkX3Y4UM3itcXIbr/pub?gid=322705111&single=true&output=csv', 4 events: 'https://docs.google.com/spreadsheets/d/e/2PACX-1vQi4aHMdzZZtSyXUUwjUhFT8zgLMOFP9d3TnnjO56ToerUSz6hjxu448TvrtxQ2KkX3Y4UM3itcXIbr/pub?gid=486574204&single=true&output=csv', 5 announcements: 'https://docs.google.com/spreadsheets/d/e/2PACX-1vQi4aHMdzZZtSyXUUwjUhFT8zgLMOFP9d3TnnjO56ToerUSz6hjxu448TvrtxQ2KkX3Y4UM3itcXIbr/pub?gid=1065844255&single=true&output=csv', 6 slideshow: 'https://docs.google.com/spreadsheets/d/e/2PACX-1vQi4aHMdzZZtSyXUUwjUhFT8zgLMOFP9d3TnnjO56ToerUSz6hjxu448TvrtxQ2KkX3Y4UM3itcXIbr/pub?gid=770268520&single=true&output=csv', 7 resources: 'https://docs.google.com/spreadsheets/d/e/2PACX-1vQi4aHMdzZZtSyXUUwjUhFT8zgLMOFP9d3TnnjO56ToerUSz6hjxu448TvrtxQ2KkX3Y4UM3itcXIbr/pub?gid=328470026&single=true&output=csv', 8 donations: 'https://docs.google.com/spreadsheets/d/e/2PACX-1vQi4aHMdzZZtSyXUUwjUhFT8zgLMOFP9d3TnnjO56ToerUSz6hjxu448TvrtxQ2KkX3Y4UM3itcXIbr/pub?gid=361270418&single=true&output=csv' 9}; 10 11 12var IC_ARR = 'â'; 13var IC_CAL = 'ð '; 14var IC_PIN = 'ð'; 15 16// Simple CSV parser (handles quoted fields) 17function parseCSV(text) { 18 var lines = text.trim().replace(/\r\n/g, '\n').replace(/\r/g, '\n').split('\n'); 19 if (lines.length < 2) return []; 20 var headers = lines[0].split(',').map(function (h) { 21 return h.trim().replace(/"/g, ''); 22 }); 23 return lines.slice(1).map(function (line) { 24 var values = [], cur = '', inQ = false; 25 for (var i = 0; i < line.length; i++) { 26 var ch = line[i]; 27 if (ch === '"') { 28 inQ = !inQ; 29 } else if (ch === ',' && !inQ) { 30 values.push(cur.trim()); 31 cur = ''; 32 } else { 33 cur += ch; 34 } 35 } 36 values.push(cur.trim()); 37 var obj = {}; 38 headers.forEach(function (h, i) { 39 obj[h] = (values[i] || '').replace(/"/g, '').trim(); 40 }); 41 return obj; 42 }); 43} 44 45function fetchSheet(url, callback) { 46 fetch(url) 47 .then(function (r) { return r.text(); }) 48 .then(function (text) { callback(parseCSV(text)); }) 49 .catch(function (err) { 50 console.error('Failed to load sheet:', err); 51 callback([]); 52 }); 53} 54 55// SITE BANNER â dismissible alert from Google Sheet (active, message, link_text, link_url, urgency) 56// urgency: "urgent" or "yes" = red; otherwise = yellow (normal) 57function loadBanner() { 58 var container = document.getElementById('siteBanner'); 59 if (!container) return; 60 61 var dismissed = sessionStorage.getItem('siteBannerDismissed'); 62 if (dismissed) return; 63 64 fetchSheet(SHEETS.banner, function (rows) { 65 var row = (rows || []).find(function (r) { return r.active === 'yes'; }); 66 if (!row || !row.message) return; 67 68 var msg = (row.message || '').trim(); 69 var linkText = (row.link_text || '').trim(); 70 var linkUrl = (row.link_url || '').trim(); 71 var linkHtml = linkText && linkUrl 72 ? ' <a href="' + linkUrl + '" target="_blank" rel="noopener" class="underline hover:no-underline font-medium text-inherit">' + linkText + '</a>' 73 : ''; 74 75 var urgency = (row.urgency || '').toLowerCase().trim(); 76 var isUrgent = urgency === 'urgent' || urgency === 'yes'; 77 78 var bgClass = isUrgent ? 'bg-red-500/50' : 'bg-gold/40'; 79 var dotClass = isUrgent ? 'bg-red-400' : 'bg-gold'; 80 var btnClass = isUrgent ? 'text-red-200 hover:text-white' : 'text-gold hover:text-white'; 81 82 container.className = bgClass + ' text-white/95 px-4 py-3 flex items-center gap-3 text-sm md:text-base'; 83 container.innerHTML = 84 '<span class="w-2 h-2 rounded-full ' + dotClass + ' flex-shrink-0"></span>' + 85 '<span class="flex-grow">' + msg + linkHtml + '</span>' + 86 '<button type="button" id="bannerClose" aria-label="Dismiss" class="' + btnClass + ' transition-colors flex-shrink-0 p-1">' + 87 '<i class="fas fa-times"></i>' + 88 '</button>'; 89 container.classList.remove('hidden'); 90 91 var btn = document.getElementById('bannerClose'); 92 if (btn) { 93 btn.addEventListener('click', function () { 94 container.classList.add('hidden'); 95 sessionStorage.setItem('siteBannerDismissed', '1'); 96 }); 97 } 98 }); 99} 100 101// OFFICIAL ANNOUNCEMENTS â homepage preview 102function loadAnnouncementsPreview() { 103 var container = document.getElementById('announcementPreview'); 104 var section = document.getElementById('section-announcements-home'); 105 if (!container) return; 106 107 fetchSheet(SHEETS.announcements, function (rows) { 108 var published = (rows || []) 109 .filter(function (r) { return r.published === 'yes'; }) 110 .sort(function (a, b) { return new Date(b.date) - new Date(a.date); }); 111 112 if (!published.length) { 113 if (section) { 114 section.classList.add('hidden'); 115 section.setAttribute('aria-hidden', 'true'); 116 } 117 return; 118 } 119 120 if (section) { 121 section.classList.remove('hidden'); 122 section.setAttribute('aria-hidden', 'false'); 123 } 124 125 var html = ''; 126 published.forEach(function (r, index) { 127 var linkHtml = ''; 128 if (r.link_text && r.link_url) { 129 linkHtml = 130 '<a href="' + r.link_url + '" target="_blank" rel="noopener" class="inline-flex items-center gap-1 text-gold hover:text-gold/90 text-sm font-medium mt
130-4">' + 131 r.link_text + ' ' + IC_ARR + 132 '</a>'; 133 } 134 135 html += 136 '<article class="' + (index > 0 ? 'mt-6 pt-6 border-t border-gold/40 ' : '') + 'block">' + 137 '<p class="text-gold font-bold text-sm mb-2">' + (r.date || '') + '</p>' + 138 '<h3 class="text-white font-bold text-lg md:text-xl mb-4">' + (r.title || '') + '</h3>' + 139 '<p class="text-white/90 text-sm md:text-base leading-relaxed">' + (r.body || '') + '</p>' + 140 linkHtml + 141 '</article>'; 142 }); 143 144 container.innerHTML = html; 145 }); 146} 147 148// Format date for archive display (e.g. "14 JAN 2025") 149function formatDateArchive(dateStr) { 150 if (!dateStr) return ''; 151 var d = new Date(dateStr); 152 if (isNaN(d.getTime())) return dateStr; 153 var months = ['JAN', 'FEB', 'MAR', 'APR', 'MAY', 'JUN', 'JUL', 'AUG', 'SEP', 'OCT', 'NOV', 'DEC']; 154 return d.getDate() + ' ' + months[d.getMonth()] + ' ' + d.getFullYear(); 155} 156 157// OFFICIAL ANNOUNCEMENTS ARCHIVE â Recent + Past sections 158function loadAnnouncementsArchive() { 159 var recentEl = document.getElementById('announcementsRecent'); 160 var pastEl = document.getElementById('announcementsPast'); 161 if (!recentEl && !pastEl) return; 162 163 fetchSheet(SHEETS.announcements, function (rows) { 164 var published = (rows || []) 165 .filter(function (r) { return r.published === 'yes'; }) 166 .sort(function (a, b) { return new Date(b.date) - new Date(a.date); }); 167 168 var recent = published.slice(0, 2); 169 var past = published.slice(2); 170 171 function cardHtml(r) { 172 var linkHtml = (r.link_text && r.link_url) 173 ? '<a href="' + r.link_url + '" target="_blank" rel="noopener" class="inline-flex items-center gap-1 text-gold hover:text-gold/90 text-sm font-medium mt-3">' + r.link_text + ' ' + IC_ARR + '</a>' 174 : ''; 175 return '<article class="rounded-2xl bg-navy border border-gold/40 p-6 flex flex-col md:flex-row md:items-start gap-4">' + 176 '<p class="text-gold font-bold text-sm whitespace-nowrap flex-shrink-0">' + formatDateArchive(r.date) + '</p>' + 177 '<div class="flex-grow min-w-0">' + 178 '<h3 class="text-white font-bold text-lg md:text-xl mb-2">' + (r.title || '') + '</h3>' + 179 '<p class="text-white/85 text-sm md:text-base leading-relaxed">' + (r.body || '') + '</p>' + 180 linkHtml + 181 '</div>' + 182 '</article>'; 183 } 184 185 if (recentEl) { 186 recentEl.innerHTML = recent.length ? recent.map(cardHtml).join('') : '<p class="text-white/60 text-sm">No recent announcements.</p>'; 187 } 188 if (pastEl) { 189 pastEl.innerHTML = past.length ? past.map(cardHtml).join('') : '<p class="text-white/60 text-sm">No past announcements.</p>'; 190 } 191 }); 192} 193 194// UPCOMING EVENTS â featured + grid 195function loadEvents() { 196 var featuredEl = document.getElementById('featuredEvent'); 197 var gridEl = document.getElementById('eventsGrid'); 198 if (!featuredEl && !gridEl) return; 199 200 fetchSheet(SHEETS.events, function (rows) { 201 if (!rows || !rows.length) return; 202 203 var featured = null; 204 var others = []; 205 206 rows.forEach(function (r) { 207 if (r.published && r.published !== 'yes') return; 208 if (!r.title) return; 209 if (r.featured === 'yes' && !featured) { 210 featured = r; 211 } else { 212 others.push(r); 213 } 214 }); 215 216 // Featured card 217 if (featuredEl) { 218 if (!featured) { 219 featuredEl.innerHTML = 220 '<div class="rounded-2xl bg-navy-dark border border-white/10 p-6 text-white/70 text-sm">No featured event at the moment.</div>'; 221 } else { 222 var fImg = featured.image_url 223 ? '<div class="h-48 w-full overflow-hidden rounded-t-2xl"><img src="' + featured.image_url + '" alt="' + featured.title + '" class="w-full h-full object-cover transition-transform duration-300 group-hover:scale-105"></div>' 224 : ''; 225 var fDate = featured.date || ''; 226 var fTime = featured.time || ''; 227 var fLoc = featured.location || ''; 228 var fContent = fImg + 229 '<div class="px-6 py-5 md:px-8 md:py-6">' + 230 '<p class="text-white/70 text-xs uppercase tracking-[0.2em] mb-1">Featured</p>' + 231 '<h3 class="text-white font-bold text-2xl md:text-3xl mb-3">' + featured.title + '</h3>' + 232 '<div class="flex flex-wrap items-center gap-3 text-sm text-white/80 mb-3">' + 233 (fDate || fTime ? '<span>' + IC_CAL + ' ' + fDate + (fTime ? ' · ' + fTime : '') + '</span>' : '') + 234 (fLoc ? '<span>' + IC_PIN + ' ' + fLoc + '</span>' : '') + 235 '</div>' + 236 '<p class="text-white/80 text-sm md:text-base leading-relaxed">' + (featured.description || '') + '</p>' + 237 (featured.rsvp_link ? '<span class="inline-flex items-center justify-center px-6 py-2 mt-4 rounded-lg bg-gold text-navy font-semibold text-sm group-hover:bg-gold-dark transition">RSVP ' + IC_ARR + '</span>' : '') + 238 '</div>'; 239 var fClasses = 'group rounded-2xl bg-navy-dark gold-glow-border transition-all duration-300 ease-out hover:-translate-y-1 block'; 240 featuredEl.innerHTML = featured.rsvp_link 241 ? '<a href="' + featured.rsvp_link + '" target="_blank" rel="noopener" class="' + fClasses + '">' + fContent + '</a>' 242 : '<article class="' + fClasses + '">' + fContent + '</article>'; 243 } 244 } 245 246 // Grid cards (homepage: 3 events; events page: all + filter) 247 if (gridEl) { 248 if (!others.length) { 249 gridEl.innerHTML = 250 '<div class="col-span-full rounded-2xl bg-navy-dark border border-white/10 p-6 text-white/70 text-sm">No upcoming events to show right now.</div>'; 251 } else { 252 var isEventsPage = /events\.html/.test(window.location.pathname) || window.location.href.indexOf('events.html') !== -1; 253 var gridEvents = isEventsPage ? others : others.slice(0, 3); 254 255 // Build filter UI on events page 256 var filterEl = document.getElementById('eventsFilter'); 257 if (isEventsPage && filterEl) { 258 var categories = [];
259 others.forEach(function (ev) { 260 var cat = (ev.category || '').trim(); 261 if (cat && categories.indexOf(cat) === -1) categories.push(cat); 262 }); 263 categories.sort(); 264 var filterHtml = '<div class="flex flex-wrap items-center gap-2 mb-6">' + 265 '<span class="text-white/70 text-sm mr-2">Filter:</span>' + 266 '<button type="button" class="events-filter-btn px-4 py-2 rounded-lg text-sm font-medium transition-all duration-200 bg-gold text-navy" data-category="">All</button>'; 267 categories.forEach(function (cat) { 268 filterHtml += '<button type="button" class="events-filter-btn px-4 py-2 rounded-lg text-sm font-medium transition-all duration-200 bg-white/10 text-white/90 hover:bg-gold/30 hover:text-white border border-white/20" data-category="' + cat.replace(/"/g, '"') + '" data-audience="">' + cat + '</button>'; 269 }); 270 filterHtml += '<span class="text-white/40 text-sm mx-1">|</span>' + 271 '<button type="button" class="events-filter-btn px-4 py-2 rounded-lg text-sm font-medium transition-all duration-200 bg-white/10 text-white/90 hover:bg-gold/30 hover:text-white border border-white/20" data-category="" data-audience="women">Women</button>' + 272 '<button type="button" class="events-filter-btn px-4 py-2 rounded-lg text-sm font-medium transition-all duration-200 bg-white/10 text-white/90 hover:bg-gold/30 hover:text-white border border-white/20" data-category="" data-audience="men">Men</button>' + 273 '</div>'; 274 filterEl.innerHTML = filterHtml; 275 } 276 277 function renderEventCard(ev) { 278 var eImg = ev.image_url 279 ? '<div class="h-40 w-full overflow-hidden rounded-t-2xl"><img src="' + ev.image_url + '" alt="' + (ev.title || '') + '" class="w-full h-full object-cover transition-transform duration-300 group-hover:scale-105"></div>' 280 : '<div class="h-40 w-full overflow-hidden rounded-t-2xl bg-navy-dark flex items-center justify-center"><i class="fas fa-calendar-alt text-white/30 text-4xl"></i></div>'; 281 var eBtn = '<span class="inline-flex items-center gap-1 text-gold font-semibold text-sm mt-4 group-hover:text-gold/90 transition-colors">Learn more ' + IC_ARR + '</span>'; 282 var eDate = ev.date || ''; 283 var eTime = ev.time || ''; 284 var eLoc = ev.location || ''; 285 var cardClasses = 'group rounded-2xl bg-navy-dark gold-glow-border flex flex-col justify-between transition-all duration-300 ease-out hover:-translate-y-1 block'; 286 var cardContent = eImg + 287 '<div class="p-6 flex flex-col flex-grow">' + 288 '<div class="flex-grow">' + 289 '<p class="text-white/70 text-xs uppercase tracking-[0.2em] mb-1">' + 290 (ev.category || '') + 291 (ev.audience ? ' · ' + ev.audience : '') + 292 '</p>' + 293 '<h3 class="text-white font-bold text-lg md:text-xl mb-3">' + ev.title + '</h3>' + 294 '<div class="text-gold text-sm mb-2">' + 295 (eDate || eTime ? IC_CAL + ' ' + eDate + (eTime ? ' · ' + eTime : '') : '') + 296 '</div>' + 297 (eLoc ? '<div class="text-gold text-sm mb-2">' + IC_PIN + ' ' + eLoc + '</div>' : '') + 298 '<p class="text-white/80 text-sm leading-relaxed">' + (ev.description || '') + '</p>' + 299 '</div>' + 300 eBtn + 301 '</div>'; 302 if (ev.rsvp_link) { 303 return '<a href="' + ev.rsvp_link + '" target="_blank" rel="noopener" class="' + cardClasses + '">' + cardContent + '</a>'; 304 } 305 return '<article class="' + cardClasses + '">' + cardContent + '</article>'; 306 } 307 308 function renderGrid(eventsToShow) { 309 var html = ''; 310 eventsToShow.forEach(function (ev) { 311 html += renderEventCard(ev); 312 }); 313 gridEl.innerHTML = html || '<div class="col-span-full rounded-2xl bg-navy-dark border border-white/10 p-6 text-white/70 text-sm">No events in this category.</div>'; 314 } 315 316 renderGrid(gridEvents); 317
318 // Wire filter buttons 319 if (isEventsPage && filterEl) { 320 filterEl.querySelectorAll('.events-filter-btn').forEach(function (btn) { 321 btn.addEventListener('click', function () { 322 var cat = this.getAttribute('data-category') || ''; 323 var aud = (this.getAttribute('data-audience') || '').toLowerCase(); 324 filterEl.querySelectorAll('.events-filter-btn').forEach(function (b) { 325 var bCat = b.getAttribute('data-category') || ''; 326 var bAud = (b.getAttribute('data-audience') || '').toLowerCase(); 327 var isActive = bCat === cat && bAud === aud; 328 b.className = 'events-filter-btn px-4 py-2 rounded-lg text-sm font-medium transition-all duration-200 ' + 329 (isActive ? 'bg-gold text-navy' : 'bg-white/10 text-white/90 hover:bg-gold/30 hover:text-white border border-white/20'); 330 }); 331 var filtered = others.filter(function (ev) { 332 var matchCat = !cat || (ev.category || '').trim() === cat; 333 var audStr = (ev.audience || '').toLowerCase(); 334 var matchAud = !aud || 335 (aud === 'women' && (audStr.indexOf('women') !== -1 || audStr.indexOf('sisters') !== -1)) || 336 (aud === 'men' && (audStr.indexOf('brothers') !== -1 || (audStr.indexOf('men') !== -1 && audStr.indexOf('women') === -1))); 337 return matchCat && matchAud; 338 }); 339 renderGrid(filtered); 340 }); 341 }); 342 } 343 } 344 } 345 }); 346} 347 348// FEATURED ITEMS SLIDESHOW 349function loadSlideshow() { 350 var track = document.getElementById('slideshowTrack'); 351 var dots = document.getElementById('slideshowDots'); 352 var section = document.getElementById('section-featured-home'); 353 if (!track || !dots) return; 354 355 fetchSheet(SHEETS.slideshow, function (rows) { 356 var slides = (rows || []) 357 .filter(function (r) { return r.active === 'yes'; }) 358 .sort(function (a, b) { 359 return (parseInt(a.order, 10) || 0) - (parseInt(b.order, 10) || 0); 360 }); 361 362 if (!slides.length) { 363 if (section) { 364 section.classList.add('hidden'); 365 section.setAttribute('aria-hidden', 'true'); 366 } 367 track.innerHTML = ''; 368 dots.innerHTML = ''; 369 return; 370 } 371 372 if (section) { 373 section.classList.remove('hidden'); 374 section.setAttribute('aria-hidden', 'false'); 375 } 376 377 // Build slides 378 var html = ''; 379 slides.forEach(function (s) { 380 var url = s.image_url || ''; 381 html += 382 '<div class="w-full h-full flex-shrink-0">' + 383 '<img src="' + url + '" alt="featured item" class="w-full h-full object-cover" />' + 384 '</div>'; 385 }); 386 track.innerHTML = html; 387 388 // Build dots (slightly larger for visibility) 389 var dotsHtml = ''; 390 slides.forEach(function (_, i) { 391 dotsHtml += 392 '<button type="button" class="w-3 h-3 md:w-3.5 md:h-3.5 rounded-full ' + 393 (i === 0 ? 'bg-gold' : 'bg-white/50') + 394 '" data-index="' + i + '"></button>'; 395 }); 396 dots.innerHTML = dotsHtml; 397 398 var current = 0; 399 function goTo(index) { 400 current = index; 401 track.style.transform = 'translateX(-' + (current * 100) + '%)'; 402 var dotEls = dots.querySelectorAll('button'); 403 dotEls.forEach(function (d, i) { 404 d.classList.toggle('bg-gold', i === current); 405 d.classList.toggle('bg-white/50', i !== current); 406 }); 407 } 408 409 // Wire dot clicks 410 dots.querySelectorAll('button').forEach(function (btn) { 411 btn.addEventListener('click', function () { 412 var idx = parseInt(this.getAttribute('data-index'), 10) || 0; 413 goTo(idx); 414 }); 415 }); 416 417 // Auto-advance 418 setInterval(function () { 419 if (!slides.length) return; 420 goTo((current + 1) % slides.length); 421 }, 4000); 422 }); 423} 424 425// RESOURCES PAGE â cards from Google Sheet (id, active, title, description, tag, link [, link_text]) 426function loadResources() { 427 var container = document.getElementById('resourcesList'); 428 if (!container) return; 429 430 fetchSheet(SHEETS.resources, function (rows) { 431 var active = (rows || []).filter(function (r) { 432 return r.active === 'yes' && (r.title || r.link); 433 }); 434 435 if (!active.length) { 436 container.innerHTML = 437 '<div class="rounded-2xl bg-navy-dark border border-white/10 p-8 text-white/70 text-sm">No resources to show right now.</div>'; 438 return; 439 } 440 441 var html = ''; 442 active.forEach(function (r) {
443 var tags = (r.tag || '').split(/\s*[â\-]\s*/).filter(Boolean); 444 var tagsHtml = tags.length 445 ? tags.map(function (t) { 446 return '<span class="inline-block px-2.5 py-0.5 rounded text-xs font-medium bg-white/15 text-white/90">' + (t.trim()) + '</span>'; 447 }).join(' ') 448 : ''; 449 var ctaText = (r.link_text || '').trim() || 'Go to resource'; 450 var linkHtml = r.link 451 ? '<a href="' + r.link + '" target="_blank" rel="noopener" class="inline-flex items-center gap-1 text-gold font-semibold text-sm mt-4 hover:text-gold/90 transition-colors">' + ctaText + ' ' + IC_ARR + '</a>' 452 : ''; 453 454 html += 455 '<article class="rounded-2xl bg-navy border border-gold/40 p-6 flex flex-col">' + 456 '<div class="flex flex-wrap gap-2 mb-3">' + tagsHtml + '</div>' + 457 '<h3 class="text-white font-bold text-xl md:text-2xl mb-3">' + (r.title || '') + '</h3>' + 458 '<p class="text-white/70 text-sm md:text-base leading-relaxed flex-grow">' + (r.description || '') + '</p>' + 459 linkHtml + 460 '</article>'; 461 }); 462 container.innerHTML = html; 463 }); 464} 465 466// DONATE PAGE â causes/campaigns from Google Sheet (id, active, order, title, link) 467function loadCampaigns() { 468 var container = document.getElementById('campaignsList'); 469 if (!container) return; 470 471 fetchSheet(SHEETS.donations, function (rows) { 472 var active = (rows || []) 473 .filter(function (r) { return r.active === 'yes' && (r.title || r.link); }) 474 .sort(function (a, b) { 475 return (parseInt(a.order, 10) || 0) - (parseInt(b.order, 10) || 0); 476 }); 477 478 if (!active.length) { 479 container.innerHTML = 480 '<div class="rounded-2xl bg-navy-dark border border-white/10 p-6 text-white/70 text-sm">No campaigns to show right now.</div>'; 481 return; 482 } 483 484 var html = ''; 485 active.forEach(function (c) { 486 var link = (c.link || '').trim(); 487 var isLink = link && link.indexOf('http') === 0; 488 var cardContent = 489 '<span class="text-white font-bold text-lg md:text-xl flex-grow">' + (c.title || '') + '</span>' + 490 (isLink ? '<i class="fas fa-arrow-right text-gold text-sm flex-shrink-0"></i>' : ''); 491 var wrapper = isLink 492 ? '<a href="' + link + '" target="_blank" rel="noopener" class="rounded-2xl bg-navy border border-gold/40 p-6 flex items-center gap-4 hover:border-gold/60 transition-colors">' + cardContent + '</a>' 493 : '<div class="rounded-2xl bg-navy border border-gold/40 p-6 flex items-center gap-4">' + cardContent + '</div>'; 494 html += wrapper; 495 }); 496 container.innerHTML = html; 497 }); 498} 499 500// Init for homepage + resources + donate pages 501document.addEventListener('DOMContentLoaded', function () { 502 loadBanner(); 503 loadAnnouncementsPreview(); 504 loadAnnouncementsArchive(); 505 loadEvents(); 506 loadSlideshow(); 507 loadResources(); 508 loadCampaigns(); 509}); 510
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.