1<!DOCTYPE html> 2<html lang="en"> 3<head> 4<style> 5 .gam-sport-banner-ad iframe, 6 .gam-sport-banner-ad-2 iframe 7 { 8 width: 100%; 9 height: auto; 10 } 11 12 .prog-mobile-banners #gam-banner-ad, 13 .prog-mobile-banners #gam-banner-ad-2 14 { 15 min-height: 100px; 16 display: flex; 17 align-items: center; 18 justify-content: center; 19 } 20 21 /* Desktop presenting sponsor: cap at native 300x75. */ 22 .gam-presenting-sponsor-2, 23 .gam_ps { 24 max-width: 300px; 25 max-height: 75px; 26 margin: 0 auto; 27 overflow: hidden; 28 } 29 30 .gam-presenting-sponsor-2 iframe, 31 .gam_ps iframe { 32 width: 100%; 33 height: 100%; 34 } 35 36 /* Layout 19 desktop presenting sponsor. 37 The slot is defined as a fixed 300x75 (defineSlot below), so give the iframe its 38 full 300x75 viewport and paint it at 2/3 (200x50) with a transform â same pattern 39 as the mobile slot. The old width:200px!important squeezed the iframe VIEWPORT to 40 200 while the creative document inside stayed 300 wide, clipping the right third 41 of every creative ("Piedmont" -> "Piedm"). The container rules reserve the flex 42 slot so the priority nav measures correctly before the ad loads; GAM tracking is 43 unaffected (the creative loads at native size, it just paints smaller). */ 44 .presenting-sponsor-desktop-19 { 45 width: 212px; 46 min-width: 212px; 47 overflow: hidden; 48 } 49 .presenting-sponsor-desktop-19 .gam-presenting-sponsor-2 { 50 width: 200px; 51 height: 50px; 52 max-width: 200px; 53 max-height: 50px; 54 overflow: hidden; 55 position: relative; 56 } 57 .presenting-sponsor-desktop-19 .gam-presenting-sponsor-2 iframe { 58 width: 300px !important; 59 /* beat the generic img/iframe max-width:100% (would cap the viewport at the 60 200px container and clip the creative's right third) */ 61 max-width: none !important; 62 height: 75px !important; 63 transform: scale(0.6667); 64 transform-origin: top left; 65 border: 0; 66 } 67 68 /* AB-6152: Bootstrap-3 header menus (Style 4/8/9/15/17) render the desktop 69 sponsor inside .presenting-sponsor-mobile-menu, whose template LESS floats 70 #gam-presenting-sponsor-2 off-screen (margin:0 -200px auto; width:250px) â so 71 it's hidden until you scroll and can run off the side / drop below the nav. 72 This GAM <style> loads BEFORE template main.css, so a class rule can't beat the 73 LESS on source order; we beat it on SPECIFICITY by including the slot id 74 (.class #id = 1,1,0 > the LESS .a .b .c = 0,3,0). Pin the slot to the same 75 200x50 right-aligned, clipped box template 19 uses so it stays in the viewport, 76 in both the rest and .fixedbar states. Scoped to .presenting-sponsor-mobile-menu, 77 so template 19 (.presenting-sponsor-desktop-19) is untouched. */ 78 /* DIV wrapper = Style 15 family (the wrap is a div after the menu ul). 79 Absolute + translateY instead of float:right â the float top-aligned the 80 50px slot in the ~76px menu bar, so it rode visibly higher than the nav 81 links ("doesn't line up"). The nearest positioned ancestor is the header 82 .container (position:relative), which spans the bar's full height, so 83 top:50% centers the sponsor on the same line as the links in both the 84 resting and .fixedbar states. */ 85 div.presenting-sponsor-mobile-menu #gam-presenting-sponsor-2 { 86 position: absolute; 87 right: 15px; 88 top: 50%; 89 transform: translateY(-50%); 90 float: none; 91 width: 200px; 92 max-width: 200px; 93 height: 50px; 94 max-height: 50px; 95 margin: 0; 96 overflow: hidden; 97 } 98 /* AB-6152 follow-up (template 5 / Style 15 family): the absolute rule above only 99 holds if an ancestor of the slot is positioned, so right:15px/top:50% anchor to 100 the header .container. Template 5's main.less sets `.custom-nav .navbar 101 { position: inherit }`, which makes the navbar STATIC and removes BS3's default 102 position:relative â so in the resting (unscrolled) state NO ancestor is 103 positioned and the slot anchors to the viewport, dropping the sponsor on top of 104 the nav links. (Scrolled, the position:fixed .fixedbar became the containing 105 block and it looked fine â hence the intermittent behavior.) Re-establish the 106 containing block AB-6152 assumes, for both states. Scoped to .custom-nav so only 107 the Style 15 header family is affected; a no-op for the li-variant (Style 8/9), 108 whose slot is position:relative (in-flow), not absolute. */ 109 .custom-nav #nav-container { 110 position: relative; 111 } 112 /* AB-6152 follow-up #2 (Style-15 family, all-dropdown navs): when the greedy collapser 113 in topmenu2.js runs out of movable items â every remaining item is a .dropdown, which 114 it won't nest into MORE â but the nav still reaches the presenting sponsor, it tags the 115 header .nav-compact (then .nav-compact-2 if one tier isn't enough). That tightens the 116 nav just enough to clear the ad. Applied ONLY in that jammed case and cleared on resize, 117 so sparse navs keep their full padding and text size (and the larger-text preference). 118 Tier 1 trims horizontal padding only â text size is untouched; tier 2 is the last resort 119 and only then nudges letter-spacing. Loaded before template main.css, so we win on 120 specificity (id + 2 classes) + !important, same as the rules above. */ 121 .custom-nav.nav-compact #nav-links > li > a { 122 padding-left: 9px !important; 123 padding-right: 9px !important; 124 } 125 .custom-nav.nav-compact.nav-compact-2 #nav-links > li > a { 126 padding-left: 5px !important; 127 padding-right: 5px !important; 128 letter-spacing: -0.2px; 129 } 130 /* LI wrapper = Style 8/9 (the sponsor is an inline li in the greedy #nav-links). 131 Keep it in flow â the nav JS reserves its width; absolute would collapse the li. */ 132 li.presenting-sponsor-mobile-menu #gam-presenting-sponsor-2 { 133 float: right; 134 width: 200px; 135 max-width: 200px; 136 height: 50px; 137 max-height: 50px; 138 margin: 0; 139 overflow: hidden; 140 position: relative; 141 } 142 .presenting-sponsor-mobile-menu #gam-presenting-sponsor-2 iframe { 143 /* Full 300x75 viewport scaled to 200x50 â a 200px viewport clips the right 144 third of the 300-wide creative document (same bug as the t19 rule above). */ 145 width: 300px !important; 146 max-width: none !important; 147 height: 75px !important; 148 transform: scale(0.6667); 149 transform-origin: top left; 150 border: 0; 151 } 152 153 /* Mobile presenting sponsor: GAM serves a 300x75 creative, so visually 154 scale the whole iframe down to fit the header next to the logo + nav 155 + hamburger. The iframe still loads at native 300x75 so impressions, 156 click tracking, and viewability reporting fire correctly â it just 157 paints smaller. (Pattern ported from the State Association sites.) */ 158 #gam-presenting-sponsor-mobile { 159 width: 200px; 160 height: 50px; 161 overflow: hidden; 162 position: relative; 163 margin: 0; 164 } 165 #gam-presenting-sponsor-mobile iframe { 166 width: 300px !important; 167 max-width: none !important; 168 height: 75px !important; 169 transform: scale(0.6667); 170 transform-origin: top left; 171 border: 0; 172 } 173 @media (max-width: 380px) { 174 #gam-presenting-sponsor-mobile { 175 width: 160px; 176 height: 40px; 177 } 178 #gam-presenting-sponsor-mobile iframe { 179 transform: scale(0.5333); 180 } 181 } 182 183 /* Template 19 mobile: the sponsor has its own full-width row below the nav, 184 so don't clamp it to the inline box the other templates use. 185 Class+id specificity beats the bare #id rules above, including the 380px breakpoint. */ 186 .presenting-sponsor-mobile-19 #gam-presenting-sponsor-mobile { 187 width: auto; 188 max-width: 100%; 189 height: 64px; 190 } 191 192 /* ===== PRESENTING SPONSOR FOLLOWS EACH TEMPLATE'S NATIVE NAV ===== 193 No universal breakpoint. The desktop slot (.gam-presenting-sponsor-2) shows while 194 the header is in desktop mode and the mobile slot (#gam-presenting-sponsor-mobile) 195 shows once it collapses â exactly the Bootstrap visibility classes each header 196 already carries (BS3: hidden-sm hidden-xs / hidden-md hidden-lg; BS4/5: d-none 197 d-md-block / d-block d-md-none). The JS below fills whichever slot the CSS shows, 198 so per-template breakpoints are honored automatically. For the greedy "MORE" nav 199 (Style 8/9/15) the desktop sponsor is an inline <li>; nudgeGreedyNav() re-runs 200 AdjustNav() after the GAM creative paints so the nav reserves the ad's real width 201 and pushes overflow links into MORE instead of wrapping the sponsor below the nav. 202 (An earlier "force mobile sponsor at <=992 everywhere" rule lived here; it was
203 reverted because it misplaced the mobile slot on desktop-nav templates.) */ 204 205</style> 206 207 208 209
209<script async src="https://securepubads.g.doubleclick.net/tag/js/gpt.js"></script>
209 210
210<script> 211 window.googletag = window.googletag || { cmd: [] }; 212 213 function isMobile() { 214 return window.innerWidth <= 768; 215 } 216 217 // The greedy "MORE" nav (topmenu.js, Header Style 8/9/15) lays out BEFORE the GAM 218 // presenting-sponsor iframe paints, so it never reserves the ad's width and the 219 // sponsor wraps to a line below the nav. Re-running AdjustNav() once the creative is 220 // sized makes the nav recount the sponsor <li> and tuck overflow links into MORE, 221 // keeping the sponsor inline. No-op on templates without the greedy nav (AdjustNav 222 // is undefined there), so it's safe to call unconditionally. 223 function nudgeGreedyNav() { 224 if (typeof AdjustNav === 'function') { 225 try { AdjustNav(); } catch (e) { /* greedy nav not present on this template */ } 226 } 227 } 228 229 googletag.cmd.push(function () { 230 var isMobileDevice = isMobile(); 231 var REFRESH_KEY = 'refresh'; 232 var REFRESH_VALUE = 'true'; 233 234 // NEW: programmatic flag + refresh timing 235 var useProgrammaticAds = false; 236 // 30s is Google's minimum refresh interval for any slot AdX can fill do not lower 237 var REFRESH_MS = 30000; 238 239 // NEW: add a body class only when programmatic + mobile (for stable layout) 240 if (useProgrammaticAds && isMobileDevice) { 241 document.body.classList.add('prog-mobile-banners'); 242 } 243 244 // ------- PRESENTING SPONSOR------- 245 // Define BOTH slots unconditionally. Defining a slot does NOT request an ad 246 // (only display()/refresh() does), and the responsive-fill block below 247 // displays exactly ONE at a time â so this adds no load-time impressions. 248 // The old isMobileDevice (innerWidth<=768) branch defined only one slot for 249 // the page's life; combined with CSS that switches the sponsor container at 250 // 992px, that stranded 769-991px on a visible-but-empty slot (the tablet dead 251 // zone). We now align the fill to the 992 CSS boundary (see below). 252 var sponsorSlotsById = {}; 253 sponsorSlotsById['gam-presenting-sponsor-mobile'] = googletag.defineSlot('/22870419559/headerwebmobile', [[300, 75]], 'gam-presenting-sponsor-mobile') 254 .setTargeting(REFRESH_KEY, REFRESH_VALUE) 255 .addService(googletag.pubads()); 256 sponsorSlotsById['gam-presenting-sponsor-2'] = googletag.defineSlot('/22870419559/headerwebdesktop', [[300, 75]], 'gam-presenting-sponsor-2') 257 .setTargeting(REFRESH_KEY, REFRESH_VALUE) 258 .addService(googletag.pubads()); 259 260 // Build base arrays of allowed sizes 261 var desktopTabletProgrammatic = [[640, 100], [728, 90]]; 262 var mobileProgrammatic = [[320, 50]]; // << mobile = 320x50 ONLY 263 var desktopTabletDefault = [[640, 100]]; 264 var mobileDefault = [[640, 100]]; 265 266 var allProgrammaticSizes = [[640, 100], [728, 90], [320, 50]]; 267 var allDefaultSizes = [[640, 100]]; 268 269 var bannerMapping = googletag.sizeMapping() 270 .addSize([1024, 0], useProgrammaticAds ? desktopTabletProgrammatic : desktopTabletDefault) // desktop 271 .addSize([768, 0], useProgrammaticAds ? desktopTabletProgrammatic : desktopTabletDefault) // tablet 272 .addSize([0, 0], useProgrammaticAds ? mobileProgrammatic : mobileDefault) // phones 273 .build(); 274 275 googletag.defineSlot( 276 '/22870419559/bannerweb', 277 useProgrammaticAds ? allProgrammaticSizes : allDefaultSizes, 278 'gam-banner-ad' 279 ) 280 .defineSizeMapping(bannerMapping) 281 .setTargeting(REFRESH_KEY, REFRESH_VALUE) 282 .addService(googletag.pubads()); 283 284 googletag.defineSlot( 285 '/22870419559/bannerweb', 286 useProgrammaticAds ? allProgrammaticSizes : allDefaultSizes, 287 'gam-banner-ad-2' 288 ) 289 .defineSizeMapping(bannerMapping) 290 .setTargeting(REFRESH_KEY, REFRESH_VALUE) 291 .addService(googletag.pubads()); 292 293 googletag.defineSlot('/22870419559/agent', [[300, 75]], 'gam-agent-ad') 294 .setTargeting(REFRESH_KEY, REFRESH_VALUE) 295 .addService(googletag.pubads()); 296 297 googletag.pubads().setTargeting('siteid', '958'); 298 googletag.pubads().setTargeting('isschoolpay', '0'); 299 300 googletag.pubads().addEventListener('impressionViewable', function (event) { 301 var slot = event.slot; 302 if (slot.getTargeting(REFRESH_KEY).indexOf(REFRESH_VALUE) > -1) { 303 setTimeout(function () { 304 googletag.pubads().refresh([slot]); 305 }, REFRESH_MS); 306 } 307 }); 308 309 googletag.enableServices(); 310 311 // ------- PRESENTING SPONSOR: responsive fill (AB-6152 follow-up) ------- 312 // The desktop/mobile split is owned entirely by each header's NATIVE Bootstrap 313 // visibility classes (no universal @media here anymore). We fill whichever slot 314 // the CSS currently shows, and re-fill on resize so a breakpoint cross is never 315 // stranded on an empty slot. Only ONE slot is displayed at a time, so load-time 316 // impression volume is unchanged â the filled slot is always the VISIBLE (and 317 // viewable) one. For the greedy "MORE" nav the desktop sponsor is an inline <li>; 318 // nudgeGreedyNav() (called after the creative paints) re-runs AdjustNav so the nav 319 // reserves the ad's width and keeps it inline instead of wrapping it below. 320 (function () { 321 var sponsorDisplayed = { 'gam-presenting-sponsor-2': false, 'gam-presenting-sponsor-mobile': false }; 322 // Is the element actually rendered (not display:none on it or any ancestor)? 323 function isShown(el) { return !!(el && (el.offsetParent !== null || el.getClientRects().length)); } 324 // Fill whichever slot the CSS currently shows. The desktop/mobile split is owned 325 // entirely by the header CSS (the @media block above sets <=992 -> mobile on the 326 // standard menus; layout 19 keeps its reserved desktop slot, etc.), so the JS just 327 // follows it â no width is hard-coded here, and template-specific breakpoints 328 // (e.g. 19's reserved slot) are honored automatically. Fall back to a 993 width 329 // split only if neither container has been laid out yet. 330 function activeSponsorId() { 331 var d = document.getElementById('gam-presenting-sponsor-2'); 332 var m = document.getElementById('gam-presenting-sponsor-mobile'); 333 if (isShown(d)) return 'gam-presenting-sponsor-2'; 334 if (isShown(m)) return 'gam-presenting-sponsor-mobile'; 335 if (!d && !m) return null; 336 return window.innerWidth >= 993 ? 'gam-presenting-sponsor-2' : 'gam-presenting-sponsor-mobile'; 337 } 338 function fillActiveSponsor() { 339 var id = activeSponsorId(); 340 if (!id || !document.getElementById(id)) return; // this template doesn't render that slot 341 var slot = sponsorSlotsById[id]; 342 if (!slot) return; 343 if (!sponsorDisplayed[id]) { 344 googletag.display(id); 345 sponsorDisplayed[id] = true; 346 } else { 347 googletag.pubads().refresh([slot]); // already shown once -> re-serve on return 348 } 349 } 350 function whenReady(fn) { 351 if (document.readyState === 'loading') document.addEventListener('DOMContentLoaded', fn); 352 else fn(); 353 } 354 whenReady(fillActiveSponsor); 355 // Re-fill the now-visible slot after a resize crosses any template's CSS breakpoint. 356 var resizeTimer; 357 window.addEventListener('resize', function () { 358 clearTimeout(resizeTimer); 359 resizeTimer = setTimeout(fillActiveSponsor, 200);
360 }); 361 })(); 362 363 // Add event listeners for responsive image handling 364 document.addEventListener('DOMContentLoaded', function () { 365 handleResponsiveImages(); 366 367 // Add debounced resize handler 368 var resizeTimeout = null; 369 window.addEventListener('resize', function () { 370 if (resizeTimeout) { 371 clearTimeout(resizeTimeout); 372 } 373 374 resizeTimeout = setTimeout(function () { 375 handleResponsiveImages(); 376 }, 250); 377 }); 378 }); 379 380 // Add slotRenderEnded event to handle styling right after ads render 381 googletag.pubads().addEventListener('slotRenderEnded', function (event) { 382 // Give a small delay to ensure content is available 383 setTimeout(function () { 384 var id = event.slot.getSlotElementId(); 385 var container = document.getElementById(id); 386 if (container) { 387 var iframes = container.querySelectorAll('iframe[id^="google_ads_iframe"]'); 388 iframes.forEach(applyResponsiveStyles); 389 } 390 if (id === 'gam-presenting-sponsor-2') { 391 // Belt-and-suspenders for the greedy nav: re-run after the creative has 392 // settled, covering the cross-origin safe-frame path where 393 // fitPresentingSponsor (and thus its inline nudge) can't measure the ad. 394 setTimeout(nudgeGreedyNav, 250); 395 } 396 }, 50); 397 }); 398 399 // Function to handle responsive images 400 function handleResponsiveImages() { 401 ['gam-banner-ad', 'gam-banner-ad-2', 'gam-sport-banner-ad', 'gam-sport-banner-ad-2', 'gam-presenting-sponsor-2', 'gam-presenting-sponsor-mobile'].forEach(adId => { 402 var adContainer = document.querySelector(`#${adId}`); 403 if (adContainer) { 404 observeIframeInsertion(adContainer); 405 var iframes = adContainer.querySelectorAll('iframe[id^="google_ads_iframe"]'); 406 iframes.forEach(applyResponsiveStyles); 407 } 408 }); 409 } 410 411 // Function to observe iframe insertion - from original code 412 function observeIframeInsertion(container) { 413 var observer = new MutationObserver(function (mutations) { 414 mutations.forEach(function (mutation) { 415 if (mutation.addedNodes) { 416 mutation.addedNodes.forEach(function (node) { 417 if (node.tagName === 'IFRAME' && node.id.startsWith('google_ads_iframe')) { 418 applyResponsiveStyles(node); 419 observeIframeChanges(node); 420 } 421 }); 422 } 423 }); 424 }); 425 426 observer.observe(container, { 427 childList: true, 428 subtree: true 429 }); 430 } 431 432 function applyResponsiveStyles(iframe) { 433 if (!iframe) return; 434 435 // Presenting sponsor (desktop AND mobile, ALL templates): one proportional 436 // fit â scale the creative to its reserved nav slot, no crop. (Previously this 437 // was template-19-only; every other template clipped via the default box.) 438 if (iframe.closest('.gam-presenting-sponsor-2') || iframe.closest('#gam-presenting-sponsor-mobile')) { 439 fitPresentingSponsor(iframe); 440 return; 441 } 442 443 // Banner / sport-banner ads â unchanged. 444 if ( 445 iframe.closest('.gam-banner-ad') || 446 iframe.closest('.gam-banner-ad-2') || 447 iframe.closest('.gam-sport-banner-ad') || 448 iframe.closest('.gam-sport-banner-ad-2') 449 ) { 450 var isTemplate19 = !!document.querySelector('.sticky-header-19'); 451 var isTemplate19Banner = isTemplate19 && iframe.closest('.gam-banner-ad'); 452 453 if (isMobile() && !isTemplate19Banner) { 454 iframe.style.width = '100%'; 455 iframe.style.height = 'auto'; 456 try { 457 var iframeDoc = iframe.contentDocument || iframe.contentWindow.document; 458 // Template 19's top banner sits at the very top of the sticky 459 // header with nothing overlapping it; the 20% push-down other 460 // templates use just renders as dead white space above the ad. 461 iframeDoc.querySelectorAll('img').forEach(function (img) { 462 img.style.maxWidth = '100%'; 463 img.style.height = 'auto'; 464 img.style.marginTop = iframe.closest('.gam-banner-ad') ? '20%' : '0'; 465 }); 466 } catch (e) { 467 console.error('Could not access iframe content:', e); 468 } 469 } 470 471 // Template 19's top banner ad: pin the iframe to the creative's true 472 // rendered height on EVERY device, not just mobile (AB-6411 â the 473 // sticky ad row is a fixed 122px box on desktop; see main.less/ 474 // CSSStyle19). Set inline with !important so it wins regardless of 475 // CSS state â GAM ad sizing lives here in JS, not in template CSS, 476 // which is easy to defeat via selector specificity drift (this exact 477 // element had multiple overlapping height:auto rules quietly taking 478 // turns winning). 479 if (isTemplate19Banner) { 480 try { 481 var iframeDoc19 = iframe.contentDocument || iframe.contentWindow.document; 482 if (iframeDoc19.documentElement) { iframeDoc19.documentElement.style.margin = '0'; iframeDoc19.documentElement.style.padding = '0'; } 483 if (iframeDoc19.body) { iframeDoc19.body.style.margin = '0'; iframeDoc19.body.style.padding = '0'; } 484 var bannerImg = iframeDoc19.querySelector('img'); 485 var fitBannerHeight = function () {
486 if (!bannerImg.naturalWidth) return; 487 var w = iframe.getBoundingClientRect().width; 488 var h = Math.round(w * bannerImg.naturalHeight / bannerImg.naturalWidth); 489 if (h > 0) iframe.style.setProperty('height', h + 'px', 'important'); 490 }; 491 if (bannerImg) { 492 bannerImg.style.maxWidth = '100%'; 493 bannerImg.style.height = 'auto'; 494 bannerImg.style.display = 'block'; 495 bannerImg.style.marginTop = '0'; 496 if (bannerImg.complete && bannerImg.naturalWidth) { fitBannerHeight(); } 497 else { bannerImg.addEventListener('load', fitBannerHeight); } 498 } 499 } catch (e) { 500 console.error('Could not access iframe content:', e); 501 } 502 } 503 } 504 } 505 506 // Scale the presenting sponsor to fit its reserved nav slot from the creative's 507 // TRUE dimensions, preserving aspect ratio (never crop). Generalized from the old 508 // template-19-only version so EVERY template gets the same treatment. Per the 509 // business-rules GAM section, sizing lives here in JS â CSS can't reach the creative 510 // inside the friendly iframe. The iframe still loads the native creative so GAM 511 // impression/click/viewability tracking fires correctly; we only change how it paints. 512 function fitPresentingSponsor(iframe) { 513 var container = iframe.closest('.gam-presenting-sponsor-2, #gam-presenting-sponsor-mobile'); 514 if (!container) return; 515 var isMobileSlot = container.id === 'gam-presenting-sponsor-mobile'; 516 517 // Target box = the slot each template reserves in its nav. Read it from the 518 // rendered container; fall back / sanity-cap so an unbounded (e.g. max-width:none) 519 // or not-yet-sized container can't blow the ad out across the nav. 520 var boxW = container.clientWidth; 521 var boxH = container.clientHeight; 522 if (!boxW || boxW < 40 || boxW > 400) boxW = isMobileSlot ? Math.max(200, window.innerWidth - 24) : 240; 523 if (!boxH || boxH < 20 || boxH > 120) boxH = isMobileSlot ? 64 : 72; 524 525 function apply(nativeW, nativeH) { 526 if (!nativeW || !nativeH) return; 527 // Fit WITHIN the box on both dimensions, preserving aspect ratio â no crop. 528 var scale = Math.min(boxW / nativeW, boxH / nativeH); 529 iframe.style.setProperty('width', nativeW + 'px', 'important'); 530 iframe.style.setProperty('height', nativeH + 'px', 'important'); 531 iframe.style.setProperty('transform', 'scale(' + scale + ')', 'important'); 532 iframe.style.transformOrigin = 'top left'; 533 // display:block so the iframe ignores inherited line-height (e.g. 85px on 534 // template 14's .upper-side) and its own vertical-align:bottom, which push an 535 // inline iframe DOWN inside the slot and let overflow:hidden clip the bottom. 536 iframe.style.setProperty('display', 'block', 'important'); 537 // Collapse the container to the painted size so there's no gap or overflow. 538 container.style.width = Math.round(nativeW * scale) + 'px'; 539 container.style.height = Math.round(nativeH * scale) + 'px'; 540 container.style.overflow = 'hidden'; 541 // Desktop sponsor sits inline in the greedy nav â now that it has a real 542 // width, let the nav reserve it (pushes overflow links into MORE). 543 if (!isMobileSlot) nudgeGreedyNav(); 544 } 545 546 try { 547 var doc = iframe.contentDocument || iframe.contentWindow.document; 548 var img = doc && doc.querySelector('img'); 549 if (img) { 550 // GAM's friendly iframe ships an 8px <body> margin that nudges the creative 551 // down/right (then overflow:hidden crops it). Zero margins + block-level the 552 // image to kill the inline baseline gap, then measure true dimensions. 553 if (doc.documentElement) { doc.documentElement.style.margin = '0'; doc.documentElement.style.padding = '0'; } 554 if (doc.body) { doc.body.style.margin = '0'; doc.body.style.padding = '0'; } 555 img.style.display = 'block'; 556 img.style.maxWidth = 'none'; 557 img.style.width = 'auto'; 558 img.style.height = 'auto';
559 if (img.complete && img.naturalWidth) { 560 apply(img.naturalWidth, img.naturalHeight); 561 } else { 562 img.addEventListener('load', function () { 563 apply(img.naturalWidth, img.naturalHeight); 564 }); 565 } 566 } 567 } catch (e) { 568 // Cross-origin (safe-frame) creative â can't measure it; leave the CSS default. 569 console.error('Could not size presenting sponsor:', e); 570 } 571 } 572 573 function observeIframeChanges(iframe) { 574 iframe.addEventListener('load', function () { 575 applyResponsiveStyles(iframe); 576 }); 577 578 var observer = new MutationObserver(function (mutations) { 579 mutations.forEach(function (mutation) { 580 if (mutation.type === 'childList' || (mutation.type === 'attributes' && mutation.attributeName === 'src')) { 581 applyResponsiveStyles(iframe); 582 } 583 }); 584 }); 585 586 observer.observe(iframe, { 587 childList: true, 588 subtree: true, 589 attributes: true, 590 attributeFilter: ['src'] 591 }); 592 } 593 }); 594 </script>
594 595 596 <!-- End GPT Tag --> 597 <!-- Google tag (gtag.js) -->
vendor: 73 bytes, lines 597-598
597 598 <script async src="https://www.googletagmanager.com/gtag/js?id=
598G-KWN6WNQ89R
vendor: 21 bytes, lines 598-599
598"></script> 599
599<script> 600
vendor: 171 bytes, lines 600-604
600window.dataLayer = window.dataLayer || []; 601 function gtag() { dataLayer.push(arguments); } 602 gtag('js', new Date()); 603 604 gtag('config', '
604G-KWN6WNQ89R
vendor: 13 bytes, lines 604-605
604'); 605
605</script>
605 606 607 608 <meta charset="utf-8" /> 609 <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=2.0, user-scalable=yes" /> 610 <title>St. Martin High School Yellow jackets Athletics Calendar | St. Martin High School (Ocean Springs, MS)</title> 611 <meta name="description" content="Stay up-to-date with the St. Martin Yellow jackets athletics calendar. View upcoming sports events, game dates, and important school activities." /> 612 <meta name="keywords" content="st. martin high school, yellow jackets, athletics calendar, school sports calendar, st. martin high school yellow jackets calendar, high school sports events, st. martin high school sports schedule" /> 613 <meta property="og:image" content="https://5starassets.blob.core.windows.net/athleticsites/958/91/images/9f55438e-5510-4fa8-adc9-5828b9add3d6.png"> 614 <link rel="canonical" href="https://www.stmartinathletics.com/calendar" /> 615<meta name="robots" content="index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1" /> 616
616<script type="application/ld+json">{"@context":"https://schema.org","@type":"SportsOrganization","name":"St. Martin High School","url":"https://www.stmartinathletics.com","logo":"https://5starassets.blob.core.windows.net/athleticsites/958/91/images/9f55438e-5510-4fa8-adc9-5828b9add3d6.png","description":"Stay up-to-date with the St. Martin Yellow jackets athletics calendar. View upcoming sports events, game dates, and important school activities.","alternateName":"St. Martin High School Yellow jackets","address":{"@type":"PostalAddress","addressLocality":"Ocean Springs","addressRegion":"MS"}}</script>
616 617
617<script type="application/ld+json">{"@context":"https://schema.org","@type":"WebSite","name":"St. Martin High School","url":"https://www.stmartinathletics.com","potentialAction":{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https://www.stmartinathletics.com/search?keyword={search_term_string}"},"query-input":"required name=search_term_string"}}</script>
617 618 619 620 621
621<script src="https://unpkg.com/focus-visible/dist/focus-visible.min.js"></script>
621 622 <!-- latest CDN compiled and minified CSS for lity (simple lightbox) --> 623 <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/lity/2.3.1/lity.min.css" integrity="sha256-0SZxASYAglrmIuTx+ZYHE3hzTnCZWB7XLu+iA8AG0Z0=" crossorigin="anonymous" /> 624 <!-- latest CDN compiled and minified CSS for bootstrap 3 --> 625 <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous"> 626 <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap-theme.min.css" integrity="sha384-rHyoN1iRsVXV4nD0JutlnGaslCJuC7uwjduW9SVrLvRYooPp2bWYgmgJQIXwl/Sp" crossorigin="anonymous"> 627 <!-- latest CDN compiled and minified CSS for slick slider --> 628 <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/slick-carousel/1.9.0/slick.min.css" integrity="sha256-UK1EiopXIL+KVhfbFa8xrmAWPeBjMVdvYMYkTAEv/HI=" crossorigin="anonymous" /> 629 <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/slick-carousel/1.9.0/slick-theme.min.css" integrity="sha256-4hqlsNP9KM6+2eA8VUT0kk4RsMRTeS7QGHIM+MZ5sLY=" crossorigin="anonymous" /> 630 <!-- latest CDN compiled and minified CSS for font awesome --> 631 <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.css" integrity="sha256-NuCn4IvuZXdBaFKJOAcsU2Q3ZpwbdFisd5dux4jkQ5w=" crossorigin="anonymous" /> 632 <!-- locally stored compiled and minified CSS for yamm --> 633 <link rel="stylesheet" href="/lib/yamm3/yamm/yamm.min.css" /> 634 <link rel="stylesheet" href="/lib/datatables/media/css/dataTables.bootstrap.min.css" /> 635 <link rel="stylesheet" href="/less/templates/1/main.min.css?v=2.3" /> 636 <link rel="icon" type="image/png" href="https://5starassets.blob.core.windows.net/athleticsites/958/91/images/9f55438e-5510-4fa8-adc9-5828b9add3d6.png"> 637 <link href="/lib/sweetalert/dist/sweetalert.css" rel="stylesheet" /> 638 <link rel="stylesheet" href="/less/Components/AIAgent.min.css" /> 639 640 641 642 <style> 643 h1{color: #01058a;} 644 body{background: url(https://5starassets.blob.core.windows.net/athleticsites/958/91/images/2aa8152d-18d3-4100-aaed-93abfda2bedf.jpg);} 645 .cd-main-content{background-image:url(https://5starassets.blob.core.windows.net/athleticsites/958/91/images/);} 646 @media (max-width: 500px){ 647 #calendar-link{background-color: #01058a;} 648 } 649 #calendar-link > span{color:#01058a;} 650 .header-topper:before{background:#01058a;} 651 .header-topper .row:before {background:#01058a;} 652 .bg-primary{background-color: #01058a;} 653 .bg-secondary{background-color: #f4d214;} 654 .bg-gradient-primary-dark{background-image: linear-gradient(180deg,#000,#01058a);} 655 .text-primary{color: #01058a !important;} 656 .text-secondary{color: #f4d214 !important;} 657 .text-primary-font{color: #ffffff;} 658 .right-angle-primary{border-color: rgba(255,255,255,0) #01058a transparent #01058a;} 659 .left-angle-secondary{border-color: #fff #f4d214 transparent transparent;} 660 .border-all-thin-primary{border: solid 1px #01058a;} 661 .border-all-xl-primary{border: 20px solid #01058a;} 662 .border-all-sm-secondary{border: 2px solid #f4d214;} 663 .border-right-xl-primary{border-right: 20px solid #01058a;} 664 .border-right-xl-secondary{border-right: 20px solid #f4d214;} 665 .border-top-sm-secondary{border-top: 2px solid #f4d214 !important;} 666 .border-bottom-sm-secondary{border-bottom: 2px solid #f4d214 !important;}
667 .pins span:before,.pins span:after{border-top: 4px solid #01058a; border-bottom: 4px solid #f4d214;} 668 .angle-primary-secondary{border-color: #01058a #f4d214 #01058a #f4d214;} 669 .team-menu .navbar-nav>li.active {background-color: #f4d214; color: #01058a;} 670 .team-menu .navbar-nav>li.active:after {border-top-color: #f4d214;} 671 .team-menu-container{background-image:url(https://5starassets.blob.core.windows.net/athleticsites/958/91/images/dc5b8a2e-30f8-4d5b-971d-d53135bebe32.png);} 672 .news-header-container{background-image:url(https://5starassets.blob.core.windows.net/athleticsites/958/91/images/dc5b8a2e-30f8-4d5b-971d-d53135bebe32.png);} 673 .arrow_box {border-bottom: 4px solid #f4d214;} 674 .arrow_box:before {border-top-color: #f4d214;} 675 .ticker-19-badge-today, .ticker-19-badge-upcoming, .ticker-19-badge-final { background-color: #01058a; } 676 .ticker-19-calendar-link { background-color: #01058a; color: #fff !important; min-width: 80px !important; padding: 0 20px !important; border: none !important; border-right: 3px solid rgba(255,255,255,0.3) !important; font-size: 1rem !important; font-weight: 700 !important; text-transform: uppercase !important; letter-spacing: 1px !important; gap: 4px !important; } 677 .ticker-19-calendar-link:hover { filter: brightness(1.15); } 678 .ticker-19-calendar-link i { font-size: 1.3rem !important; } 679 .ticker-19-calendar-link span { color: #fff !important; font-size: 0.7rem !important; font-weight: 700 !important; letter-spacing: 1px !important; } 680 </style> 681 682 683 684 <link href="/lib/fullcalendar/dist/fullcalendar.css" rel="stylesheet" /> 685 <style> 686 .composite-calendar-view { padding: 20px 0 24px; } 687 688 /* ===== CARD ===== */ 689 .cal-card { 690 background: #fff; 691 border: 1px solid #e5e7eb; 692 border-radius: 10px; 693 box-shadow: 0 2px 8px rgba(0,0,0,0.06); 694 margin-bottom: 24px; 695 overflow: hidden; 696 } 697 698 /* ===== HEADER ===== */ 699 .cal-header { 700 display: flex; 701 align-items: center; 702 justify-content: space-between; 703 flex-wrap: wrap; 704 gap: 12px; 705 padding: 18px 24px; 706 border-bottom: 1px solid #e5e7eb; 707 background: #fafafa; 708 } 709 .cal-title { 710 font-size: 1.6rem; 711 font-weight: 800; 712 text-transform: uppercase; 713 letter-spacing: 1.5px; 714 color: #1a1a1a; 715 margin: 0; 716 white-space: nowrap; 717 } 718 .cal-header-controls { 719 display: flex; 720 align-items: center; 721 gap: 8px; 722 flex-wrap: wrap; 723 } 724 .cal-select { 725 font-size: 1.2rem; 726 font-weight: 600; 727 height: 44px; 728 padding: 8px 14px; 729 border-radius: 6px; 730 border: 1px solid #d1d5db; 731 color: #1a1a1a; 732 background: #fff; 733 cursor: pointer; 734 min-width: 160px; 735 } 736 .cal-select:focus { border-color: #888; outline: none; } 737 .cal-select option { color: #1a1a1a; font-size: 1.2rem; } 738 739 /* ===== CALENDAR AREA ===== */ 740 #calendar { padding: 20px 24px 24px; } 741 742 /* ===== FULLCALENDAR OVERRIDES ===== */ 743 .fc-toolbar { 744 margin-bottom: 16px !important; 745 display: flex !important; 746 align-items: center !important; 747 justify-content: space-between !important; 748 flex-wrap: wrap; 749 gap: 8px; 750 } 751 .fc-toolbar .fc-left { order: 1; display: flex; align-items: center; gap: 4px; } 752 .fc-toolbar .fc-center { order: 2; } 753 .fc-toolbar .fc-right { order: 3; display: flex; align-items: center; gap: 0; } 754 .fc-toolbar .fc-center h2 { 755 font-size: 1.8rem; 756 font-weight: 800; 757 text-transform: uppercase; 758 letter-spacing: 1px; 759 color: #1a1a1a; 760 margin: 0; 761 } 762 .fc-button { 763 font-size: 1.1rem !important; 764 font-weight: 700 !important; 765 text-transform: uppercase; 766 letter-spacing: 0.3px; 767 padding: 7px 14px !important; 768 border: 1px solid #d1d5db !important; 769 background: #fff !important; 770 color: #1a1a1a !important; 771 box-shadow: none !important; 772 line-height: 1.2 !important; 773 height: auto !important; 774 margin: 0 !important; 775 } 776 .fc-button:first-child { border-radius: 6px 0 0 6px !important; } 777 .fc-button:last-child { border-radius: 0 6px 6px 0 !important; } 778 .fc-button:only-child { border-radius: 6px !important; } 779 .fc-button + .fc-button { margin-left: -1px !important; } 780 .fc-button:hover { background: #f5f5f5 !important; } 781 .fc-button.fc-state-active, .fc-state-active { 782 background: #1a1a1a !important; 783 color: #fff !important; 784 border-color: #1a1a1a !important; 785 z-index: 1; 786 } 787 .fc-prev-button, .fc-next-button { padding: 7px 10px !important; } 788 .fc-today-button { border-radius: 6px !important; margin-left: 6px !important; } 789 790 /* Day headers */ 791 .fc-day-header { 792 font-size: 1.1rem; 793 font-weight: 800; 794 text-transform: uppercase; 795 letter-spacing: 1px; 796 color: #1a1a1a; 797 padding: 12px 0 !important; 798 border-color: #e5e7eb !important; 799 } 800 .fc-day-number { font-size: 1.3rem; font-weight: 700; color: #1a1a1a; padding: 8px 10px !important; } 801 .fc-unthemed td.fc-today { background: rgba(0,0,0,0.02) !important; } 802 .fc-unthemed th, .fc-unthemed td { border-color: #f0f0f0 !important; } 803 804 /* Events in grid */ 805 .fc-title { white-space: normal !important; } 806 .fc-day-grid-event { 807 border: none !important; 808 border-radius: 3px !important; 809 padding: 3px 6px !important; 810 font-size: 1rem !important; 811 font-weight: 600 !important; 812 margin-bottom: 2px !important; 813 line-height: 1.3; 814 background: #f3f4f6 !important; 815 color: #1a1a1a !important; 816 border-left: 3px solid #aaa !important; 817 } 818 .fc-day-grid-event:hover { background: #e8e9eb !important; } 819 .fc-more { font-size: 0.9rem; font-weight: 700; color: #888; } 820 821 /* List view */ 822 .fc-list-heading td { 823 font-size: 1.25rem !important; 824 font-weight: 800 !important; 825 text-transform: uppercase; 826 letter-spacing: 0.5px; 827 background: #f9fafb !important; 828 color: #000 !important; 829 padding: 14px 16px !important; 830 } 831 .fc-list-item td { 832 font-size: 1.2rem !important; 833 font-weight: 600 !important; 834 padding: 12px 16px !important; 835 border-color: #f0f0f0 !important; 836 color: #000 !important; 837 } 838 .fc-list-item-title a { color: #000 !important; font-weight: 600 !important; } 839 .fc-list-item-time, 840 .fc-list-item-marker { 841 font-size: 1.4rem !important; 842 font-weight: 700 !important; 843 color: #000 !important; 844 } 845 .fc-list-item:hover td { background: #fafafa !important; } 846 847 /* Import messages */ 848 .import-message { 849 margin: 0 24px 16px; 850 padding: 12px 16px; 851 border-radius: 6px; 852 border: 1px solid #bce8f1; 853 background: #d9edf7; 854 color: #31708f; 855 } 856 .import-message .close { float: right; font-size: 18px; font-weight: bold; opacity: .3; cursor: pointer; } 857 .import-message .close:hover { opacity: .6; } 858 .ics-url-box { 859 margin: 8px 0; padding: 8px; background: #f9f9f9; 860 border: 1px solid #ddd; border-radius: 4px; 861 font-family: monospace; font-size: 0.85rem; word-break: break-all; cursor: pointer; 862 } 863 .ics-url-box:hover { background: #f0f0f0; } 864 865 /* ===== MOBILE ===== */ 866 @media (max-width: 768px) { 867 .cal-header { flex-direction: column; align-items: stretch; padding: 14px 16px; } 868 .cal-title { font-size: 1.1rem; }
869 .cal-header-controls { flex-direction: column; } 870 .cal-select { width: 100%; min-width: 100%; } 871 #calendar { padding: 12px; } 872 .fc-toolbar { flex-direction: column !important; gap: 8px !important; } 873 .fc-toolbar .fc-left, .fc-toolbar .fc-right, .fc-toolbar .fc-center { justify-content: center; width: 100%; } 874 .fc-toolbar .fc-center h2 { font-size: 1.1rem; text-align: center; } 875 } 876 877 /* Subscribe-to-Schedule trigger + modal (parallel to SA template-4 modal). */ 878 .sch-cal-sub-btn { 879 display: inline-flex; 880 align-items: center; 881 gap: 8px; 882 padding: 8px 16px; 883 background: #c8102e; 884 color: #fff; 885 border: none; 886 border-radius: 6px; 887 font-weight: 700; 888 font-size: 1.15rem; 889 letter-spacing: 0.04em; 890 text-transform: uppercase; 891 cursor: pointer; 892 transition: background 0.18s ease, transform 0.12s ease; 893 } 894 .sch-cal-sub-btn i { color: #fff; font-size: 1rem; } 895 .sch-cal-sub-btn:hover, 896 .sch-cal-sub-btn:focus { background: #a40e26; color: #fff; transform: translateY(-1px); outline: none; } 897 898 body.sch-cal-sub-locked { overflow: hidden; } 899 .sch-cal-sub-overlay { 900 position: fixed; 901 inset: 0; 902 /* Above the school site's fixed/sticky nav (which sits at z-index 903 1030-1050 depending on layout). 9999 keeps the modal above any 904 sticky toolbar / chat widget without going into max-int territory. */ 905 z-index: 9999; 906 background: rgba(0, 0, 0, 0.55); 907 backdrop-filter: blur(2px); 908 -webkit-backdrop-filter: blur(2px); 909 display: flex; 910 align-items: center; 911 justify-content: center; 912 padding: 20px; 913 } 914 .sch-cal-sub-overlay[hidden] { display: none; } 915 .sch-cal-sub-modal { 916 position: relative; 917 background: #fff; 918 color: #0a0a0a; 919 border-radius: 8px; 920 width: 100%; 921 max-width: 660px; 922 max-height: calc(100vh - 40px); 923 overflow-y: auto; 924 box-shadow: 0 24px 60px rgba(0, 0, 0, 0.35); 925 padding: 32px 32px 24px; 926 animation: schCalSubIn 0.18s ease;
927 border-top: 4px solid #c8102e; 928 } 929 @keyframes schCalSubIn { 930 from { transform: translateY(12px); opacity: 0; } 931 to { transform: translateY(0); opacity: 1; } 932 } 933 .sch-cal-sub-header { 934 display: flex; align-items: center; gap: 14px; 935 padding-bottom: 14px; 936 margin-bottom: 18px; 937 position: relative; 938 } 939 .sch-cal-sub-header::after { 940 content: ''; 941 position: absolute; 942 left: 0; bottom: 0; 943 width: 64px; height: 3px; 944 background: #c8102e; 945 } 946 .sch-cal-sub-logo { 947 width: 44px; height: 44px; flex-shrink: 0; 948 background: #c8102e; 949 color: #fff; 950 display: inline-flex; align-items: center; justify-content: center; 951 transform: rotate(-3deg); 952 } 953 .sch-cal-sub-logo i { color: #fff; font-size: 1.15rem; transform: rotate(3deg); } 954 .sch-cal-sub-title { 955 margin: 0; flex: 1; 956 font-weight: 800; 957 font-size: 1.9rem; 958 color: #0a0a0a; 959 letter-spacing: 0.02em; 960 text-transform: uppercase; 961 line-height: 1.05; 962 } 963 .sch-cal-sub-close { 964 background: transparent; border: 0; 965 width: 36px; height: 36px; 966 border-radius: 50%; 967 cursor: pointer; 968 color: #4a4a4a; 969 display: inline-flex; align-items: center; justify-content: center; 970 transition: background 0.15s ease; 971 } 972 .sch-cal-sub-close i { font-size: 1rem; color: inherit; } 973 .sch-cal-sub-close:hover { background: #f3f3f3; color: #0a0a0a; } 974 975 .sch-cal-sub-lede { margin: 0 0 18px; color: #444; font-size: 1.1rem; line-height: 1.5; } 976 977 /* "You are subscribing to X" â the one line that tells a parent whether 978 they are getting one team or the whole school. */ 979 .sch-cal-sub-scope { 980 margin: 0 0 16px; 981 padding: 12px 16px; 982 background: #f3f5f7; 983 border-left: 4px solid #c8102e; 984 color: #111; 985 font-size: 1.15rem; 986 line-height: 1.45; 987 } 988 .sch-cal-sub-scope-label { 989 display: block; 990 margin-bottom: 2px; 991 font-size: 0.82rem; 992 font-weight: 700; 993 letter-spacing: 0.09em; 994 text-transform: uppercase; 995 color: #4a4a4a; 996 } 997 .sch-cal-sub-scope strong { font-weight: 800; } 998 .sch-cal-sub-scope-hint { 999 display: block; 1000 margin-top: 4px; 1001 font-size: 0.98rem; 1002 color: #3d3d3d; 1003 } 1004 1005 .sch-cal-sub-grid { 1006 display: grid; 1007 grid-template-columns: repeat(3, 1fr); 1008 gap: 10px; 1009 margin-bottom: 18px; 1010 } 1011 .sch-cal-sub-tile { 1012 display: flex; flex-direction: column; 1013 align-items: center; justify-content: center; 1014 gap: 10px; 1015 min-height: 104px; 1016 background: #fafaf7; 1017 border: 2px solid #ececec; 1018 border-radius: 4px; 1019 padding: 16px 10px; 1020 text-align: center; 1021 color: #0a0a0a; 1022 text-decoration: none; 1023 font-size: 1rem; 1024 font-weight: 700; 1025 letter-spacing: 0.06em; 1026 text-transform: uppercase; 1027 transition: border-color 0.18s ease, background 0.18s ease, transform 0.12s ease; 1028 cursor: pointer; 1029 } 1030 .sch-cal-sub-tile i { 1031 font-size: 1.8rem; 1032 color: #0a0a0a; 1033 background: #fff; 1034 width: 44px; height: 44px; 1035 line-height: 44px; 1036 display: inline-flex; align-items: center; justify-content: center; 1037 border: 1px solid #ececec; 1038 } 1039 .sch-cal-sub-tile:hover, 1040 .sch-cal-sub-tile:focus, 1041 .sch-cal-sub-tile.is-active { 1042 border-color: #c8102e; 1043 background: #fff; 1044 color: #0a0a0a; 1045 text-decoration: none; 1046 outline: none; 1047 transform: translateY(-2px); 1048 } 1049 .sch-cal-sub-tile.is-active i { border-color: #c8102e; } 1050 .sch-cal-sub-tile[data-sch-subscribe-provider="google"] i { color: #4285F4; } 1051 .sch-cal-sub-tile[data-sch-subscribe-provider="apple"] i { color: #0a0a0a; } 1052 .sch-cal-sub-tile[data-sch-subscribe-provider="outlook365"] i, 1053 .sch-cal-sub-tile[data-sch-subscribe-provider="outlook"] i { color: #0078D4; } 1054 .sch-cal-sub-tile[data-sch-subscribe-provider="yahoo"] i { color: #6001D2; } 1055 .sch-cal-sub-tile[data-sch-subscribe-provider="android"] i { color: #3DDC84; } 1056 .sch-cal-sub-tile[data-sch-subscribe-provider="rss"] i { color: #F26522; } 1057 .sch-cal-sub-tile[data-sch-subscribe-provider="excel"] i { color: #207245; } 1058 1059 .sch-cal-sub-url-row { 1060 display: flex; align-items: center; gap: 8px; 1061 background: #f7f7f7; 1062 border: 1px solid #e3e3e3; 1063 border-radius: 8px; 1064 padding: 8px 10px; 1065 margin-bottom: 18px; 1066 } 1067 .sch-cal-sub-url-row label { 1068 font-size: 0.8rem; letter-spacing: 0.1em; 1069 text-transform: uppercase; color: #666; 1070 flex-shrink: 0; margin: 0; 1071 } 1072 .sch-cal-sub-url-row input { 1073 flex: 1; min-width: 0; 1074 border: 0; background: transparent; 1075 font-size: 1rem; color: #222; 1076 padding: 4px 2px; 1077 } 1078 .sch-cal-sub-url-row input:focus { outline: none; } 1079 .sch-cal-sub-copy { 1080 background: #fff; 1081 border: 1px solid #d9d9d9; 1082 border-radius: 6px; 1083 padding: 6px 12px; 1084 font-size: 0.9rem; letter-spacing: 0.06em; 1085 text-transform: uppercase; 1086 cursor: pointer; 1087 color: #0a0a0a; 1088 transition: background 0.15s ease; 1089 } 1090 .sch-cal-sub-copy:hover { background: #f3f3f3; } 1091 .sch-cal-sub-footer { 1092 border-top: 1px solid #ececec; 1093 padding-top: 18px;
1094 display: flex; 1095 align-items: center; 1096 justify-content: flex-start; 1097 } 1098 .sch-cal-sub-primary { 1099 display: inline-flex; align-items: center; gap: 10px; 1100 background: #c8102e; color: #fff; 1101 border: 0; padding: 14px 30px; 1102 border-radius: 0; 1103 font-weight: 700; 1104 font-size: 1.15rem; 1105 letter-spacing: 0.12em; 1106 text-transform: uppercase; 1107 cursor: pointer; 1108 box-shadow: 6px 6px 0 #0a0a0a; 1109 transition: transform 0.15s ease, box-shadow 0.15s ease; 1110 } 1111 .sch-cal-sub-primary:hover, 1112 .sch-cal-sub-primary:focus { 1113 transform: translate(-2px, -2px); 1114 box-shadow: 8px 8px 0 #0a0a0a; 1115 color: #fff; 1116 outline: none; 1117 } 1118 1119 @media (max-width: 600px) { 1120 .sch-cal-sub-modal { padding: 22px 18px 18px; } 1121 .sch-cal-sub-grid { grid-template-columns: repeat(2, 1fr); } 1122 .sch-cal-sub-title { font-size: 1.45rem; } 1123 .sch-cal-sub-btn { width: 100%; justify-content: center; } 1124 } 1125 /* Keyboard focus visibility (WCAG 2.4.7) */ 1126 .cal-select:focus-visible, 1127 .sch-cal-sub-btn:focus-visible, 1128 .sch-cal-sub-url-row input:focus-visible, 1129 .sch-cal-sub-tile:focus-visible, 1130 .sch-cal-sub-primary:focus-visible, 1131 #calendar a:focus-visible { 1132 outline: 2px solid #005fcc; 1133 outline-offset: 2px; 1134 } 1135 </style> 1136 1137 1138</head> 1139<body viewport="fixed"> 1140 <a href="#main-content" class="skip-link">Skip to main content</a> 1141 1142 <div class="ticker-19-section" aria-label="Game Schedule"> 1143 <div class="ticker-19-bar"> 1144 <!-- Composite calendar link â LEFT side like OU --> 1145 <a href="/calendar" class="ticker-19-calendar-link" aria-label="View full schedule"> 1146 <i class="fa fa-calendar" aria-hidden="true"></i> 1147 <span>Composite</span> 1148 </a> 1149 1150 <!-- Tabs --> 1151 <div class="ticker-19-tabs" role="tablist"> 1152 <button class="ticker-19-tab active" id="ticker19-ev-btn" role="tab" aria-controls="ticker19-events" aria-selected="true" tabindex="0">Events</button> 1153 <button class="ticker-19-tab" id="ticker19-res-btn" role="tab" aria-controls="ticker19-results" aria-selected="false" tabindex="0">Results</button> 1154 </div> 1155 1156 <!-- Events Panel --> 1157 <div class="ticker-19-panel active" id="ticker19-events" role="tabpanel" aria-labelledby="ticker19-ev-btn"> 1158 <div class="ticker-19-scroll-container"> 1159 <button class="ticker-19-arrow ticker-19-arrow-left" aria-label="Previous games"><i class="fa fa-chevron-left" aria-hidden="true"></i></button> 1160 <div class="ticker-19-track events-slider-19"> 1161 <div class="ticker-19-card" tabindex="0" role="button" aria-expanded="false" aria-label="Football vs Gulfport â Oct. 9"> 1162 <div class="ticker-19-card-top"> 1163 <span class="ticker-19-date"><span class="ticker-19-badge ticker-19-badge-today" style="background-color:#01058a;">Oct. 9</span> · TBA</span> 1164 </div> 1165 <div class="ticker-19-sport">Football - Varsity</div> 1166 <div class="ticker-19-opponent"> 1167 <img src="https://5starassets.blob.core.windows.net/mascots/generics/1.png" class="ticker-19-opp-logo" alt="Gulfport" loading="lazy" /> 1168 <span class="ticker-19-opp-name">vs Gulfport</span> 1169 </div> 1170 </div> 1171 <div class="ticker-19-card" tabindex="0" role="button" aria-expanded="false" aria-label="Football at D'iberville â Oct. 16"> 1172 <div class="ticker-19-card-top">
1173 <span class="ticker-19-date"><span class="ticker-19-badge ticker-19-badge-today" style="background-color:#01058a;">Oct. 16</span> · TBA</span> 1174 </div> 1175 <div class="ticker-19-sport">Football - Varsity</div> 1176 <div class="ticker-19-opponent"> 1177 <img src="https://5starassets.blob.core.windows.net/mascots/generics/1.png" class="ticker-19-opp-logo" alt="D'iberville" loading="lazy" /> 1178 <span class="ticker-19-opp-name">at D'iberville</span> 1179 </div> 1180 </div> 1181 <div class="ticker-19-card" tabindex="0" role="button" aria-expanded="false" aria-label="Football vs Harrison Central â Oct. 23"> 1182 <div class="ticker-19-card-top"> 1183 <span class="ticker-19-date"><span class="ticker-19-badge ticker-19-badge-today" style="background-color:#01058a;">Oct. 23</span> · TBA</span> 1184 </div> 1185 <div class="ticker-19-sport">Football - Varsity</div> 1186 <div class="ticker-19-opponent"> 1187 <img src="https://5starassets.blob.core.windows.net/mascots/generics/1.png" class="ticker-19-opp-logo" alt="Harrison Central" loading="lazy" /> 1188 <span class="ticker-19-opp-name">vs Harrison Central</span> 1189 </div> 1190 </div> 1191 <div class="ticker-19-card" tabindex="0" role="button" aria-expanded="false" aria-label="Soccer vs Resurrection Catholic â Oct. 26"> 1192 <div class="ticker-19-card-top"> 1193 <span class="ticker-19-date"><span class="ticker-19-badge ticker-19-badge-today" style="background-color:#01058a;">Oct. 26</span> · 5:30 PM</span> 1194 </div> 1195 <div class="ticker-19-sport">Girls Soccer - Varsity</div> 1196 <div class="ticker-19-opponent"> 1197 <img src="https://5starassets.blob.core.windows.net/mascots/generics/4.png" class="ticker-19-opp-logo" alt="Resurrection Catholic" loading="lazy" /> 1198 <span class="ticker-19-opp-name">vs Resurrection Catholic</span> 1199 </div> 1200 </div> 1201 <div class="ticker-19-card" tabindex="0" role="button" aria-expanded="false" aria-label="Soccer vs Resurrection Catholic â Oct. 26"> 1202 <div class="ticker-19-card-top"> 1203 <span class="ticker-19-date"><span class="ticker-19-badge ticker-19-badge-today" style="background-color:#01058a;">Oct. 26</span> · 7:00 PM</span> 1204 </div> 1205 <div class="ticker-19-sport">Girls Soccer - Varsity</div> 1206 <div class="ticker-19-opponent"> 1207 <img src="https://5starassets.blob.core.windows.net/mascots/generics/4.png" class="ticker-19-opp-logo" alt="Resurrection Catholic" loading="lazy" /> 1208 <span class="ticker-19-opp-name">vs Resurrection Catholic</span> 1209 </div> 1210 </div> 1211 <div class="ticker-19-card" tabindex="0" role="button" aria-expanded="false" aria-label="Soccer vs Sumrall â Oct. 29"> 1212 <div class="ticker-19-card-top"> 1213 <span class="ticker-19-date"><span class="ticker-19-badge ticker-19-badge-today" style="background-color:#01058a;">Oct. 29</span> · 5:30 PM</span> 1214 </div> 1215 <div class="ticker-19-sport">Girls Soccer - Varsity</div> 1216 <div class="ticker-19-opponent"> 1217 <img src="https://5starassets.blob.core.windows.net/mascots/generics/4.png" class="ticker-19-opp-logo" alt="Sumrall" loading="lazy" />
1218 <span class="ticker-19-opp-name">vs Sumrall</span> 1219 </div> 1220 </div> 1221 <div class="ticker-19-card" tabindex="0" role="button" aria-expanded="false" aria-label="Soccer vs Sumrall â Oct. 29"> 1222 <div class="ticker-19-card-top"> 1223 <span class="ticker-19-date"><span class="ticker-19-badge ticker-19-badge-today" style="background-color:#01058a;">Oct. 29</span> · 7:00 PM</span> 1224 </div> 1225 <div class="ticker-19-sport">Girls Soccer - Varsity</div> 1226 <div class="ticker-19-opponent"> 1227 <img src="https://5starassets.blob.core.windows.net/mascots/generics/4.png" class="ticker-19-opp-logo" alt="Sumrall" loading="lazy" /> 1228 <span class="ticker-19-opp-name">vs Sumrall</span> 1229 </div> 1230 </div> 1231 <div class="ticker-19-card" tabindex="0" role="button" aria-expanded="false" aria-label="Basketball at Pass Christian â Oct. 31"> 1232 <div class="ticker-19-card-top"> 1233 <span class="ticker-19-date"><span class="ticker-19-badge ticker-19-badge-today" style="background-color:#01058a;">Oct. 31</span> · 12:05 PM</span> 1234 </div> 1235 <div class="ticker-19-sport">Girls Basketball - Varsity</div> 1236 <div class="ticker-19-opponent"> 1237 <img src="https://5starassets.blob.core.windows.net/mascots/generics/2.png" class="ticker-19-opp-logo" alt="Pass Christian" loading="lazy" /> 1238 <span class="ticker-19-opp-name">at Pass Christian</span> 1239 </div> 1240 </div> 1241 <div class="ticker-19-card" tabindex="0" role="button" aria-expanded="false" aria-label="Basketball at Long Beach â Oct. 31"> 1242 <div class="ticker-19-card-top"> 1243 <span class="ticker-19-date"><span class="ticker-19-badge ticker-19-badge-today" style="background-color:#01058a;">Oct. 31</span> · 1:45 PM</span> 1244 </div> 1245 <div class="ticker-19-sport">Girls Basketball - Varsity</div> 1246 <div class="ticker-19-opponent"> 1247 <img src="https://5starassets.blob.core.windows.net/mascots/generics/2.png" class="ticker-19-opp-logo" alt="Long Beach" loading="lazy" /> 1248 <span class="ticker-19-opp-name">at Long Beach</span> 1249 </div> 1250 </div> 1251 <div class="ticker-19-card" tabindex="0" role="button" aria-expanded="false" aria-label="Basketball vs Ocean Springs â Nov. 2"> 1252 <div class="ticker-19-card-top"> 1253 <span class="ticker-19-date"><span class="ticker-19-badge ticker-19-badge-today" style="background-color:#01058a;">Nov. 2</span> · 6:30 PM</span> 1254 </div> 1255 <div class="ticker-19-sport">Boys Basketball - Freshman</div> 1256 <div class="ticker-19-opponent"> 1257 <img src="https://5starassets.blob.core.windows.net/mascots/generics/2.png" class="ticker-19-opp-logo" alt="Ocean Springs" loading="lazy" /> 1258 <span class="ticker-19-opp-name">vs Ocean Springs</span> 1259 </div> 1260 </div> 1261 </div> 1262 <button class="ticker-19-arrow ticker-19-arrow-right" aria-label="Next games"><i class="fa fa-chevron-right" aria-hidden="true"></i></button> 1263 </div> 1264 </div> 1265 1266 <!-- Results Panel --> 1267 <div class="ticker-19-panel" id="ticker19-results" role="tabpanel" aria-labelledby="ticker19-res-btn" hidden> 1268 <div class="ticker-19-scroll-container"> 1269 <button class="ticker-19-arrow ticker-19-arrow-left" aria-label="Previous results"><i class="fa fa-chevron-left" aria-hidden="true"></i></button> 1270 <div class="ticker-19-track results-slider-19"> 1271 <div class="ticker-19-empty">No recent results</div> 1272 </div> 1273 <button class="ticker-19-arrow ticker-19-arrow-right" aria-label="Next results"><i class="fa fa-chevron-right" aria-hidden="true"></i></button> 1274 </div> 1275 </div> 1276 </div> 1277 </div> 1278
1278<script> 1279 (function loadTicker() { 1280 if (typeof jQuery !== 'undefined') { 1281 var s = document.createElement('script'); 1282 s.src = '/js/UpcomingEventsStyle19.js'; 1283 document.body.appendChild(s); 1284 } else { 1285 setTimeout(loadTicker, 50); 1286 } 1287 })(); 1288 </script>
1288 1289 1290<!-- Mobile: collapsible mini schedule (future events only) --> 1291 <div class="mobile-mini-sched" id="mobileMinSched" aria-label="Upcoming events" hidden> 1292 <div class="mms-filter"> 1293 <select id="mmsSportFilter" class="mms-sport-select" aria-label="Filter by sport"> 1294 <option value="">All Sports</option> 1295 <option value="Baseball">Baseball</option> 1296 <option value="Basketball">Basketball</option> 1297 <option value="Football">Football</option> 1298 <option value="Soccer">Soccer</option> 1299 <option value="Softball">Softball</option> 1300 <option value="Volleyball">Volleyball</option> 1301 </select> 1302 </div> 1303 <div class="mms-events" id="mmsEvents" aria-live="polite"> 1304 <div class="mms-event" data-sport="Football"> 1305 <div class="mms-date"> 1306 <span class="mms-month">OCT</span> 1307 <span class="mms-day">9</span> 1308 </div> 1309 <div class="mms-info"> 1310 <span class="mms-sport">Football - Varsity</span> 1311 <span class="mms-matchup"> 1312 <img src="https://5starassets.blob.core.windows.net/mascots/generics/1.png" class="mms-logo" alt="" loading="lazy" /> 1313 vs Gulfport 1314 </span> 1315 </div> 1316 <div class="mms-right"> 1317 <span class="mms-time">TBA</span> 1318 </div> 1319 </div> 1320 <div class="mms-event" data-sport="Football"> 1321 <div class="mms-date"> 1322 <span class="mms-month">OCT</span> 1323 <span class="mms-day">16</span> 1324 </div> 1325 <div class="mms-info"> 1326 <span class="mms-sport">Football - Varsity</span> 1327 <span class="mms-matchup"> 1328 <img src="https://5starassets.blob.core.windows.net/mascots/generics/1.png" class="mms-logo" alt="" loading="lazy" /> 1329 at D'iberville 1330 </span> 1331 </div> 1332 <div class="mms-right"> 1333 <span class="mms-time">TBA</span> 1334 </div> 1335 </div> 1336 <div class="mms-event" data-sport="Football"> 1337 <div class="mms-date"> 1338 <span class="mms-month">OCT</span> 1339 <span class="mms-day">23</span> 1340 </div> 1341 <div class="mms-info"> 1342 <span class="mms-sport">Football - Varsity</span> 1343 <span class="mms-matchup"> 1344 <img src="https://5starassets.blob.core.windows.net/mascots/generics/1.png" class="mms-logo" alt="" loading="lazy" /> 1345 vs Harrison Central 1346 </span> 1347 </div> 1348 <div class="mms-right"> 1349 <span class="mms-time">TBA</span> 1350 </div> 1351 </div> 1352 <div class="mms-event" data-sport="Soccer"> 1353 <div class="mms-date"> 1354 <span class="mms-month">OCT</span> 1355 <span class="mms-day">26</span> 1356 </div> 1357 <div class="mms-info"> 1358 <span class="mms-sport">Girls Soccer - Varsity</span> 1359 <span class="mms-matchup"> 1360 <img src="https://5starassets.blob.core.windows.net/mascots/generics/4.png" class="mms-logo" alt="" loading="lazy" /> 1361 vs Resurrection Catholic 1362 </span> 1363 </div> 1364 <div class="mms-right">
1365 <span class="mms-time">5:30 PM</span> 1366 </div> 1367 </div> 1368 <div class="mms-event" data-sport="Soccer"> 1369 <div class="mms-date"> 1370 <span class="mms-month">OCT</span> 1371 <span class="mms-day">26</span> 1372 </div> 1373 <div class="mms-info"> 1374 <span class="mms-sport">Girls Soccer - Varsity</span> 1375 <span class="mms-matchup"> 1376 <img src="https://5starassets.blob.core.windows.net/mascots/generics/4.png" class="mms-logo" alt="" loading="lazy" /> 1377 vs Resurrection Catholic 1378 </span> 1379 </div> 1380 <div class="mms-right"> 1381 <span class="mms-time">7:00 PM</span> 1382 </div> 1383 </div> 1384 <div class="mms-event" data-sport="Soccer"> 1385 <div class="mms-date"> 1386 <span class="mms-month">OCT</span> 1387 <span class="mms-day">29</span> 1388 </div> 1389 <div class="mms-info"> 1390 <span class="mms-sport">Girls Soccer - Varsity</span> 1391 <span class="mms-matchup"> 1392 <img src="https://5starassets.blob.core.windows.net/mascots/generics/4.png" class="mms-logo" alt="" loading="lazy" /> 1393 vs Sumrall 1394 </span> 1395 </div> 1396 <div class="mms-right"> 1397 <span class="mms-time">5:30 PM</span> 1398 </div> 1399 </div> 1400 <div class="mms-event" data-sport="Soccer"> 1401 <div class="mms-date"> 1402 <span class="mms-month">OCT</span> 1403 <span class="mms-day">29</span> 1404 </div> 1405 <div class="mms-info"> 1406 <span class="mms-sport">Girls Soccer - Varsity</span> 1407 <span class="mms-matchup"> 1408 <img src="https://5starassets.blob.core.windows.net/mascots/generics/4.png" class="mms-logo" alt="" loading="lazy" /> 1409 vs Sumrall 1410 </span> 1411 </div> 1412 <div class="mms-right"> 1413 <span class="mms-time">7:00 PM</span> 1414 </div> 1415 </div> 1416 <div class="mms-event" data-sport="Basketball"> 1417 <div class="mms-date"> 1418 <span class="mms-month">OCT</span> 1419 <span class="mms-day">31</span> 1420 </div> 1421 <div class="mms-info"> 1422 <span class="mms-sport">Girls Basketball - Varsity</span> 1423 <span class="mms-matchup"> 1424 <img src="https://5starassets.blob.core.windows.net/mascots/generics/2.png" class="mms-logo" alt="" loading="lazy" /> 1425 at Pass Christian 1426 </span> 1427 </div> 1428 <div class="mms-right"> 1429 <span class="mms-time">12:05 PM</span> 1430 </div> 1431 </div> 1432 <div class="mms-event" data-sport="Basketball"> 1433 <div class="mms-date"> 1434 <span class="mms-month">OCT</span> 1435 <span class="mms-day">31</span> 1436 </div> 1437 <div class="mms-info"> 1438 <span class="mms-sport">Girls Basketball - Varsity</span> 1439 <span class="mms-matchup"> 1440 <img src="https://5starassets.blob.core.windows.net/mascots/generics/2.png" class="mms-logo" alt="" loading="lazy" /> 1441 at Long Beach 1442 </span> 1443 </div> 1444 <div class="mms-right">
1445 <span class="mms-time">1:45 PM</span> 1446 </div> 1447 </div> 1448 <div class="mms-event" data-sport="Basketball"> 1449 <div class="mms-date"> 1450 <span class="mms-month">NOV</span> 1451 <span class="mms-day">2</span> 1452 </div> 1453 <div class="mms-info"> 1454 <span class="mms-sport">Boys Basketball - Freshman</span> 1455 <span class="mms-matchup"> 1456 <img src="https://5starassets.blob.core.windows.net/mascots/generics/2.png" class="mms-logo" alt="" loading="lazy" /> 1457 vs Ocean Springs 1458 </span> 1459 </div> 1460 <div class="mms-right"> 1461 <span class="mms-time">6:30 PM</span> 1462 </div> 1463 </div> 1464 </div> 1465 <a href="/calendar" class="mms-full-link"><i class="fa fa-calendar" aria-hidden="true"></i> Full Schedule</a> 1466 </div> 1467 1468<style> 1469 /* Game footnote (Homecoming, Senior Night, ...) under the matchup */ 1470 .ticker-19-footnote { 1471 font-size: 0.7rem; 1472 font-style: italic; 1473 font-weight: 600; 1474 color: #444; 1475 text-align: center; 1476 white-space: nowrap; 1477 overflow: hidden; 1478 text-overflow: ellipsis; 1479 max-width: 190px; 1480 margin: 1px auto 0; 1481 } 1482 1483 /* Auto-scroll card text that overflows its max-width (JS flags with .t19-marq) */ 1484 .ticker-19-sport.t19-marq, .ticker-19-opp-name.t19-marq { text-overflow: clip; } 1485 .t19-marq .t19-marq-inner { 1486 display: inline-block; 1487 white-space: nowrap; 1488 animation: t19-marq-slide var(--t19-marq-dur, 6s) ease-in-out infinite alternate; 1489 } 1490 .ticker-19-card:hover .t19-marq .t19-marq-inner, 1491 .ticker-19-card:focus-within .t19-marq .t19-marq-inner { animation-play-state: paused; } 1492 @keyframes t19-marq-slide { 1493 0%, 20% { transform: translateX(0); } 1494 80%, 100% { transform: translateX(var(--t19-marq-shift, 0px)); } 1495 } 1496 @media (prefers-reduced-motion: reduce) { 1497 .ticker-19-sport.t19-marq, .ticker-19-opp-name.t19-marq { text-overflow: ellipsis; } 1498 .t19-marq .t19-marq-inner { animation: none; } 1499 } 1500 1501 .mobile-cal-bar { display: none; } 1502 .mobile-mini-sched { display: none; } 1503 @media (max-width: 991px) { 1504 .ticker-19-section { display: none !important; } 1505 1506 /* Calendar bar: toggle + full schedule link */ 1507 .mobile-cal-bar { 1508 display: flex !important; 1509 align-items: center; 1510 justify-content: center; 1511 padding: 0; 1512 margin: 0; 1513 } 1514 .mcb-toggle { 1515 flex: 1; 1516 display: flex; 1517 align-items: center; 1518 justify-content: center; 1519 gap: 8px; 1520 color: #fff; 1521 background: transparent; 1522 border: none; 1523 font-size: 1.1rem; 1524 font-weight: 700; 1525 text-transform: uppercase; 1526 letter-spacing: 0.4px; 1527 padding: 8px 14px; 1528 cursor: pointer; 1529 } 1530 .mcb-caret { 1531 transition: transform 0.2s; 1532 font-size: 0.95rem; 1533 } 1534 .mcb-toggle[aria-expanded="true"] .mcb-caret { 1535 transform: rotate(180deg); 1536 } 1537 .mcb-full { 1538 display: flex; 1539 align-items: center; 1540 justify-content: center; 1541 padding: 8px 16px; 1542 color: rgba(255,255,255,0.9); 1543 text-decoration: none; 1544 border-left: 1px solid rgba(255,255,255,0.15); 1545 font-size: 1.05rem; 1546 } 1547 .mcb-full:hover { color: #fff; text-decoration: none; } 1548 1549 /* Mini schedule (collapsed by default) */ 1550 .mobile-mini-sched { 1551 background: #fff; 1552 border-bottom: 1px solid #e5e7eb; 1553 overflow: hidden; 1554 max-height: 0; 1555 transition: max-height 0.3s ease; 1556 } 1557 .mobile-mini-sched.mms-open { 1558 display: block; 1559 max-height: 1200px; 1560 } 1561 .mms-event { 1562 display: flex; 1563 align-items: center; 1564 gap: 14px; 1565 padding: 14px 16px;
1566 border-bottom: 1px solid #f0f0f0; 1567 } 1568 .mms-event:last-child { border-bottom: none; } 1569 .mms-date { 1570 display: flex; 1571 flex-direction: column; 1572 align-items: center; 1573 min-width: 56px; 1574 flex-shrink: 0; 1575 } 1576 .mms-month { 1577 font-size: 1rem; 1578 font-weight: 700; 1579 text-transform: uppercase; 1580 color: #444; 1581 line-height: 1; 1582 } 1583 .mms-day { 1584 font-size: 1.85rem; 1585 font-weight: 800; 1586 color: #000; 1587 line-height: 1.2; 1588 } 1589 .mms-info { 1590 flex: 1; 1591 min-width: 0; 1592 } 1593 .mms-sport { 1594 display: block; 1595 font-size: 1.05rem; 1596 font-weight: 700; 1597 text-transform: uppercase; 1598 color: #444; 1599 letter-spacing: 0.3px; 1600 } 1601 .mms-matchup { 1602 display: flex; 1603 align-items: center; 1604 gap: 8px; 1605 font-size: 1.2rem; 1606 font-weight: 700; 1607 color: #000; 1608 white-space: nowrap; 1609 overflow: hidden; 1610 text-overflow: ellipsis; 1611 } 1612 .mms-logo { 1613 width: 32px; 1614 height: 32px; 1615 object-fit: contain; 1616 border-radius: 50%; 1617 flex-shrink: 0; 1618 } 1619 .mms-right { 1620 flex-shrink: 0; 1621 text-align: right; 1622 } 1623 .mms-time { 1624 font-size: 1.15rem; 1625 font-weight: 600; 1626 color: #000; 1627 } 1628 .mms-filter { 1629 padding: 12px 16px; 1630 border-bottom: 1px solid #e5e7eb; 1631 } 1632 .mms-sport-select { 1633 width: 100%; 1634 padding: 12px 14px; 1635 font-size: 1.2rem; 1636 font-weight: 600; 1637 border: 1px solid #d1d5db; 1638 border-radius: 4px; 1639 background: #fff; 1640 color: #000; 1641 -webkit-appearance: menulist; 1642 } 1643 .mms-sport-select option { 1644 color: #000; 1645 background: #fff; 1646 font-size: 1.2rem; 1647 } 1648 .mms-full-link { 1649 display: flex; 1650 align-items: center; 1651 justify-content: center; 1652 gap: 10px; 1653 padding: 16px; 1654 font-size: 1.2rem; 1655 font-weight: 700; 1656 text-transform: uppercase; 1657 letter-spacing: 0.5px; 1658 color: #000; 1659 text-decoration: none; 1660 border-top: 1px solid #e5e7eb; 1661 } 1662 .mms-full-link:hover { color: #1a1a1a; text-decoration: none; } 1663 } 1664</style>
1665<script> 1666document.addEventListener('DOMContentLoaded', function () { 1667 var btn = document.getElementById('mcbToggle'); 1668 var sched = document.getElementById('mobileMinSched'); 1669 var calBar = document.querySelector('.mobile-cal-bar'); 1670 if (!btn || !sched || !calBar) return; 1671 1672 // Move the schedule right after the calendar bar so it expands downward 1673 calBar.parentNode.insertBefore(sched, calBar.nextSibling); 1674 1675 // Toggle expand/collapse 1676 btn.addEventListener('click', function () { 1677 var open = sched.classList.toggle('mms-open'); 1678 sched.hidden = !open; 1679 btn.setAttribute('aria-expanded', open ? 'true' : 'false'); 1680 }); 1681 1682 // Sport filter: fetch filtered events from server 1683 var filter = document.getElementById('mmsSportFilter'); 1684 var eventsContainer = document.getElementById('mmsEvents'); 1685 if (filter && eventsContainer) { 1686 filter.addEventListener('change', function () { 1687 var sport = this.value; 1688 eventsContainer.style.opacity = '0.5'; 1689 fetch('/api/mobile-events?sport=' + encodeURIComponent(sport)) 1690 .then(function (r) { return r.json(); }) 1691 .then(function (events) { 1692 var html = ''; 1693 events.forEach(function (g) { 1694 html += '<div class="mms-event" data-sport="' + (g.sport || '') + '">' 1695 + '<div class="mms-date"><span class="mms-month">' + g.month + '</span><span class="mms-day">' + g.day + '</span></div>' 1696 + '<div class="mms-info"><span class="mms-sport">' + g.sportLabel + '</span>' 1697 + '<span class="mms-matchup">' 1698 + (g.opponentLogo ? '<img src="' + g.opponentLogo + '" class="mms-logo" alt="" loading="lazy" />' : '') 1699 + g.matchup + '</span></div>' 1700 + '<div class="mms-right"><span class="mms-time">' + g.time + '</span></div></div>'; 1701 }); 1702 eventsContainer.innerHTML = html || '<div style="padding:18px;text-align:center;color:#555;font-size:1rem;font-weight:500;">No upcoming events</div>'; 1703 eventsContainer.style.opacity = '1'; 1704 }) 1705 .catch(function () { eventsContainer.style.opacity = '1'; }); 1706 }); 1707 } 1708}); 1709</script>
1709 1710 1711 1712 <input type="hidden" value="958" id="schoolId" /> 1713 <input type="hidden" value="false" id="customAppSchool" /> 1714 <input type="hidden" value="8/31/2023 12:00:00 AM" id="adServingDateBegins" /> 1715 <header> 1716 1717 1718 1719 <div class="row"> 1720 <div class="col-md-12 no-print"> 1721 1722 </div> 1723 </div> 1724 1725 <div class="header-topper"> 1726 <div class="row"> 1727 <h1 class="site-title text-primary no-print"><small style="color: black;"> <i>THE OFFICIAL SITE OF </i></small><br /><i>St. Martin High School Athletics</i></h1> 1728 </div> 1729 </div> 1730 <div class="row"> 1731 <div class="col-md-12"> 1732 <div class="main-menu-container bg-primary" id="fixedscroll"> 1733 <div class="fixed-menu-container"> 1734 <div class="header-social-media"> 1735 <div class="feed-wrapper"> 1736 <a href="https://www.facebook.com/StMartinHighSchoolActivities/" target="_blank" rel="noopener" aria-label="Visit our Facebook page"> 1737 <i class="fa fa-facebook text-primary-font" aria-hidden="true"></i> 1738 <span class="sr-only">Facebook</span> 1739 </a> 1740 <a href="https://twitter.com/stmartinsports" target="_blank" rel="noopener" aria-label="Visit our X page"> 1741 <i class="fa fa-twitter text-primary-font" aria-hidden="true"></i> 1742 <span class="sr-only">X</span> 1743 </a> 1744</div> 1745 1746 </div> 1747 <div id="center"> 1748 <div class="header-gfx border-right-xl-secondary no-print"> 1749 <a href="/"><img src="https://5starassets.blob.core.windows.net/athleticsites/958/91/images/de26b5b7-cdcc-4648-a984-f85a7312c181.png" aria-label="St. Martin" alt="St. Martin Logo" /><span class="mk-blank">-</span></a> 1750 </div> 1751 <div class="primary-line border-right-xl-primary"></div> 1752 </div> 1753 <div class=""> 1754 1755 <nav class="custom-nav" role="navigation" aria-label="Main Navigation" data-sponsor-model="true"> 1756 <div class="navbar yamm navbar-static-top"> 1757 <div class="container" id="nav-container"> 1758 <div class="navbar-header"> 1759 <button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#navbar" aria-expanded="false" aria-controls="navbar"> 1760 <span class="sr-only">Toggle navigation</span> 1761 <span class="icon-bar bg-secondary"></span> 1762 <span class="icon-bar bg-secondary"></span> 1763 <span class="icon-bar bg-secondary"></span> 1764 </button> 1765 <a class="navbar-brand" href="/" aria-label="Return to St. Martin Home Page"> 1766 <img src="https://5starassets.blob.core.windows.net/athleticsites/958/91/images/fa90332f-b0c3-47a7-a8f8-cf50bd689d14.png" class="img-responsive tag" aria-label="St. Martin Logo" alt="St. Martin Logo" /> 1767 </a> 1768 <div class="presenting-sponsor hidden-md hidden-lg"> 1769 <div class="adzone adzone-0 presenting-sponsor"> 1770 <div class="ad-placement"> 1771 <div id='gam-presenting-sponsor-mobile' class="gam_ps"></div> 1772 </div> 1773 1774 </div> 1775 </div> 1776 </div> 1777 <div id="navbar" class="navbar-collapse collapse" aria-expanded="false"> 1778 <ul class="nav navbar-nav" id="nav-links" role="menubar"> 1779 1780 <li class="dropdown yamm-fw" role="presentation"> 1781 <a href="#" data-toggle="dropdown" class="dropdown-toggle text-primary-font" role="menuitem" aria-haspopup="true" aria-expanded="false" tabindex="0">SPORTS</a> 1782 <ul id="dropdown1" class="dropdown-menu two-columns" role="menu"> 1783 <li role="menuitem"> 1784 <div class="sport-link-nfo"> 1785 <div class="row"> 1786 <div class="col-xs-12 col-sm-6"> 1787 <div class="link"> 1788 <a class="text-primary" href="/sport/baseball/boys/" role="menuitem" tabindex="0" aria-label="Baseball go to Main Team Page">BASEBALL</a> 1789 </div> 1790 </div> 1791 <div class="hidden-xs col-sm-6"> 1792 <div class="nfo"> 1793 <a class="text-primary" href="/sport/baseball/boys/?tab=schedule" role="menuitem" aria-label="Baseball - Schedules" tabindex="0">Schedules</a><span> /</span> 1794 <a class="text-primary" href="/sport/baseball/boys/?tab=roster" role="menuitem" aria-label="Baseball - Rosters" tabindex="0">Rosters</a><span> /</span> 1795 <a class="text-primary" href="/sport/baseball/boys/?tab=news" role="menuitem" aria-label="Baseball - News" tabindex="0">News</a> 1796 </div> 1797 </div> 1798 </div> 1799 </div> 1800 </li> 1801 <li role="menuitem"> 1802 <div class="sport-link-nfo"> 1803 <div class="row"> 1804 <div class="col-xs-12 col-sm-6"> 1805 <div class="link"> 1806 <a class="text-primary" href="/sport/basketball/boys/" role="menuitem" tabindex="0" aria-label="Basketball(Boys) go to Main Team Page">BASKETBALL(BOYS)</a> 1807 </div> 1808 </div> 1809 <div class="hidden-xs col-sm-6"> 1810 <div class="nfo"> 1811 <a class="text-primary" href="/sport/basketball/boys/?tab=schedule" role="menuitem" aria-label="Basketball(Boys) - Schedules" tabindex="0">Schedules</a><span> /</span> 1812 <a class="text-primary" href="/sport/basketball/boys/?tab=roster" role="menuitem" aria-label="Basketball(Boys) - Rosters" tabindex="0">Rosters</a><span> /</span> 1813 <a class="text-primary" href="/sport/basketball/boys/?tab=news" role="menuitem" aria-label="Basketball(Boys) - News" tabindex="0">News</a> 1814 </div> 1815 </div> 1816 </div> 1817 </div> 1818 </li> 1819 <li role="menuitem"> 1820 <div class="sport-link-nfo"> 1821 <div class="row"> 1822 <div class="col-xs-12 col-sm-6"> 1823 <div class="link"> 1824 <a class="text-primary" href="/sport/basketball/girls/" role="menuitem" tabindex="0" aria-label="Basketball(Girls) go to Main Team Page">BASKETBALL(GIRLS)</a> 1825 </div> 1826 </div> 1827 <div class="hidden-xs col-sm-6"> 1828 <div class="nfo"> 1829 <a class="text-primary" href="/sport/basketball/girls/?tab=schedule" role="menuitem" aria-label="Basketball(Girls) - Schedules" tabindex="0">Schedules</a><span> /</span> 1830 <a class="text-primary" href="/sport/basketball/girls/?tab=roster" role="menuitem" aria-label="Basketball(Girls) - Rosters" tabindex="0">Rosters</a><span> /</span> 1831 <a class="text-primary" href="/sport/basketball/girls/?tab=news" role="menuitem" aria-label="Basketball(Girls) - News" tabindex="0">News</a> 1832 </div> 1833 </div> 1834 </div> 1835 </div> 1836 </li> 1837 <li role="menuitem"> 1838 <div class="sport-link-nfo"> 1839 <div class="row"> 1840 <div class="col-xs-12 col-sm-6"> 1841 <div class="link"> 1842 <a class="text-primary" href="/sport/football/boys/" role="menuitem" tabindex="0" aria-label="Football go to Main Team Page">FOOTBALL</a> 1843 </div> 1844 </div> 1845 <div class="hidden-xs col-sm-6"> 1846 <div class="nfo"> 1847 <a class="text-primary" href="/sport/football/boys/?tab=schedule" role="menuitem" aria-label="Football - Schedules" tabindex="0">Schedules</a><span> /</span> 1848 <a class="text-primary" href="/sport/football/boys/?tab=roster" role="menuitem" aria-label="Football - Rosters" tabindex="0">Rosters</a><span> /</span> 1849 <a class="text-primary" href="/sport/football/boys/?tab=news" role="menuitem" aria-label="Football - News" tabindex="0">News</a> 1850 </div> 1851 </div> 1852 </div> 1853 </div> 1854 </li> 1855 <li role="menuitem"> 1856 <div class="sport-link-nfo"> 1857 <div class="row"> 1858 <div class="col-xs-12 col-sm-6"> 1859 <div class="link"> 1860 <a class="text-primary" href="/sport/soccer/boys/" role="menuitem" tabindex="0" aria-label="Soccer(Boys) go to Main Team Page">SOCCER(BOYS)</a> 1861 </div> 1862 </div> 1863 <div class="hidden-xs col-sm-6"> 1864 <div class="nfo"> 1865 <a class="text-primary" href="/sport/soccer/boys/?tab=schedule" role="menuitem" aria-label="Soccer(Boys) - Schedules" tabindex="0">Schedules</a><span> /</span> 1866 <a class="text-primary" href="/sport/soccer/boys/?tab=roster" role="menuitem" aria-label="Soccer(Boys) - Rosters" tabindex="0">Rosters</a><span> /</span> 1867 <a class="text-primary" href="/sport/soccer/boys/?tab=news" role="menuitem" aria-label="Soccer(Boys) - News" tabindex="0">News</a> 1868 </div> 1869 </div> 1870 </div> 1871 </div> 1872 </li> 1873 <li role="menuitem"> 1874 <div class="sport-link-nfo"> 1875 <div class="row"> 1876 <div class="col-xs-12 col-sm-6"> 1877 <div class="link"> 1878 <a class="text-primary" href="/sport/soccer/girls/" role="menuitem" tabindex="0" aria-label="Soccer(Girls) go to Main Team Page">SOCCER(GIRLS)</a> 1879 </div> 1880 </div> 1881 <div class="hidden-xs col-sm-6"> 1882 <div class="nfo"> 1883 <a class="text-primary" href="/sport/soccer/girls/?tab=schedule" role="menuitem" aria-label="Soccer(Girls) - Schedules" tabindex="0">Schedules</a><span> /</span> 1884 <a class="text-primary" href="/sport/soccer/girls/?tab=roster" role="menuitem" aria-label="Soccer(Girls) - Rosters" tabindex="0">Rosters</a><span> /</span> 1885 <a class="text-primary" href="/sport/soccer/girls/?tab=news" role="menuitem" aria-label="Soccer(Girls) - News" tabindex="0">News</a> 1886 </div> 1887 </div> 1888 </div> 1889 </div> 1890 </li> 1891 <li role="menuitem"> 1892 <div class="sport-link-nfo"> 1893 <div class="row"> 1894 <div class="col-xs-12 col-sm-6"> 1895 <div class="link"> 1896 <a class="text-primary" href="/sport/softball/girls/" role="menuitem" tabindex="0" aria-label="Softball(Girls) go to Main Team Page">SOFTBALL(GIRLS)</a> 1897 </div> 1898 </div> 1899 <div class="hidden-xs col-sm-6"> 1900 <div class="nfo"> 1901 <a class="text-primary" href="/sport/softball/girls/?tab=schedule" role="menuitem" aria-label="Softball(Girls) - Schedules"
1901 tabindex="0">Schedules</a><span> /</span> 1902 <a class="text-primary" href="/sport/softball/girls/?tab=roster" role="menuitem" aria-label="Softball(Girls) - Rosters" tabindex="0">Rosters</a><span> /</span> 1903 <a class="text-primary" href="/sport/softball/girls/?tab=news" role="menuitem" aria-label="Softball(Girls) - News" tabindex="0">News</a> 1904 </div> 1905 </div> 1906 </div> 1907 </div> 1908 </li> 1909 <li role="menuitem"> 1910 <div class="sport-link-nfo"> 1911 <div class="row"> 1912 <div class="col-xs-12 col-sm-6"> 1913 <div class="link"> 1914 <a class="text-primary" href="/sport/volleyball/girls/" role="menuitem" tabindex="0" aria-label="Volleyball go to Main Team Page">VOLLEYBALL</a> 1915 </div> 1916 </div> 1917 <div class="hidden-xs col-sm-6"> 1918 <div class="nfo"> 1919 <a class="text-primary" href="/sport/volleyball/girls/?tab=schedule" role="menuitem" aria-label="Volleyball - Schedules" tabindex="0">Schedules</a><span> /</span> 1920 <a class="text-primary" href="/sport/volleyball/girls/?tab=roster" role="menuitem" aria-label="Volleyball - Rosters" tabindex="0">Rosters</a><span> /</span> 1921 <a class="text-primary" href="/sport/volleyball/girls/?tab=news" role="menuitem" aria-label="Volleyball - News" tabindex="0">News</a> 1922 </div> 1923 </div> 1924 </div> 1925 </div> 1926 </li> 1927 </ul> 1928 </li> 1929 <li role="presentation"> 1930 <a class="slanted-btn text-primary-font" href="#" role="menuitem" tabindex="0"><span>INSIDE ATHLETICS</span></a> 1931 </li> 1932 <li role="presentation"> 1933 <a class="slanted-btn text-primary-font" href="/photos" role="menuitem" tabindex="0"><span>PHOTOS</span></a> 1934 </li> 1935 <li role="presentation"> 1936 <a class="slanted-btn text-primary-font" href="/news" role="menuitem" tabindex="0"><span>NEWS</span></a> 1937 </li> 1938 <li id="more" class="hidden" role="presentation"> 1939 <a class="dropdown-toggle text-primary-font" data-toggle="dropdown" aria-haspopup="true" href="#" role="menuitem" aria-expanded="false" tabindex="0"> 1940 More <span class="caret"></span> 1941 </a> 1942 <ul class="dropdown-menu dropdown-menu-right" role="menu"></ul> 1943 </li> 1944 </ul> 1945 1946 <div class="presenting-sponsor-mobile-menu hidden-sm hidden-xs"> 1947 <div class="adzone adzone-0 presenting-sponsor"> 1948 <div class="ad-placement"> 1949 <div id='gam-presenting-sponsor-2' class="gam-presenting-sponsor-2"></div> 1950 </div> 1951 1952 </div> 1953 </div> 1954 </div> 1955 </div> 1956 </div> 1957 <div class="mobile-cal-bar bg-primary"><button type="button" class="mcb-toggle" id="mcbToggle" aria-expanded="false"><i class="fa fa-calendar"></i> Calendar <i class="fa fa-caret-down mcb-caret"></i></button><a href="/calendar" class="mcb-full"><i class="fa fa-arrow-right"></i></a></div> 1958</nav> 1959 1960<!--Centerville--> 1961 1962 1963 </div> 1964 <div class="clearfix"></div> 1965 </div> 1966 </div> 1967 </div> 1968 </div> 1969 1970 </header> 1971 <div class="banner-ad-container-sticky-footer"> 1972 <div class="banner-ad"> 1973 <div class="banner"> 1974 <div class="row"> 1975 <div class="col-md-12 col-sm-12"> 1976 <div class="ad-placement"> 1977 <div id='gam-banner-ad' class="gam-banner-ad"> 1978
1978<script> 1979 googletag.cmd.push(function () { googletag.display('gam-banner-ad'); }); 1980 </script>
1980 1981 </div> 1982 </div> 1983 </div> 1984 </div> 1985</div> 1986 1987 </div> 1988 </div> 1989 <div class="cd-main-content"> 1990 <div class="row"> 1991 <div class="col-md-3"> 1992 <div class="vertical-menu"> 1993 1994 1995<nav class="cd-side-nav" role="navigation"> 1996 <div class="row"> 1997 <div class="feeder-container"> 1998 </div> 1999</div> 2000 2001 <ul> 2002 <li class="cd-label text-secondary border-top-sm-secondary border-bottom-sm-secondary"> 2003 2004 ATHLETICS 2005 2006 </li> 2007 <li class="has-children bg-primary schedules"> 2008 <a href="#" aria-label="SCHEDULES link" aria-expanded="false" aria-haspopup="true">schedules</a> 2009 <ul class="large-submenu bg-primary"> 2010 <li> 2011 <div class="row"> 2012 <div class="col-md-6"> 2013 <div> 2014 <span class="sidebar-subnav-header" aria-label="boys"> 2015 <strong>boys</strong> 2016 </span> 2017 </div> 2018 <div><a href="/sport/baseball/boys" aria-label="Baseball">baseball</a></div> 2019 <div><a href="/sport/basketball/boys" aria-label="Basketball">basketball</a></div> 2020 <div><a href="/sport/football/boys" aria-label="Football">football</a></div> 2021 <div><a href="/sport/soccer/boys" aria-label="Soccer">soccer</a></div> 2022 </div> 2023 <div class="col-md-6"> 2024 <div> 2025 <span class="sidebar-subnav-header" aria-label="girls"> 2026 <strong>girls</strong> 2027 </span> 2028 </div> 2029 <div><a href="/sport/basketball/girls" aria-label="Basketball">basketball</a></div> 2030 <div><a href="/sport/soccer/girls" aria-label="Soccer">soccer</a></div> 2031 <div><a href="/sport/softball/girls" aria-label="Softball">softball</a></div> 2032 <div><a href="/sport/volleyball/girls" aria-label="Volleyball">volleyball</a></div> 2033 </div> 2034 </div> 2035 </li> 2036 </ul> 2037 </li> 2038 <li class="bg-primary"> 2039 <a href="/news" aria-label="NEWS">news</a> 2040 </li> 2041 <li class="has-children bg-primary rosters"> 2042 <a href="#" aria-label="ROSTERS link" aria-expanded="false" aria-haspopup="true">rosters</a> 2043 <ul class="large-submenu bg-primary"> 2044 <li> 2045 <div class="row"> 2046 <div class="col-md-6"> 2047 <div> 2048 <span class="sidebar-subnav-header" aria-label="boys"> 2049 <strong>boys</strong> 2050 </span> 2051 </div> 2052 <div><a href="/sport/baseball/boys?tab=roster" aria-label="Baseball">baseball</a></div> 2053 <div><a href="/sport/basketball/boys?tab=roster" aria-label="Basketball">basketball</a></div> 2054 <div><a href="/sport/football/boys?tab=roster" aria-label="Football">football</a></div> 2055 <div><a href="/sport/soccer/boys?tab=roster" aria-label="Soccer">soccer</a></div> 2056 </div> 2057 <div class="col-md-6"> 2058 <div>
2059 <span class="sidebar-subnav-header" aria-label="girls"> 2060 <strong>girls</strong> 2061 </span> 2062 </div> 2063 <div><a href="/sport/basketball/girls?tab=roster" aria-label="Basketball">basketball</a></div> 2064 <div><a href="/sport/soccer/girls?tab=roster" aria-label="Soccer">soccer</a></div> 2065 <div><a href="/sport/softball/girls?tab=roster" aria-label="Softball">softball</a></div> 2066 <div><a href="/sport/volleyball/girls?tab=roster" aria-label="Volleyball">volleyball</a></div> 2067 </div> 2068 </div> 2069 </li> 2070 </ul> 2071 </li> 2072 <li class="has-children bg-primary coaches-and-staff"> 2073 <a href="#" aria-label="COACHES AND STAFF link" aria-expanded="false" aria-haspopup="true">coaches and staff</a> 2074 <ul class="large-submenu bg-primary"> 2075 <li> 2076 <div class="row"> 2077 <div class="col-md-6"> 2078 <div> 2079 <span class="sidebar-subnav-header" aria-label="boys"> 2080 <strong>boys</strong> 2081 </span> 2082 </div> 2083 <div><a href="/sport/baseball/boys?tab=staff" aria-label="Baseball">baseball</a></div> 2084 <div><a href="/sport/basketball/boys?tab=staff" aria-label="Basketball">basketball</a></div> 2085 <div><a href="/sport/football/boys?tab=staff" aria-label="Football">football</a></div> 2086 <div><a href="/sport/soccer/boys?tab=staff" aria-label="Soccer">soccer</a></div> 2087 </div> 2088 <div class="col-md-6"> 2089 <div> 2090 <span class="sidebar-subnav-header" aria-label="girls"> 2091 <strong>girls</strong> 2092 </span> 2093 </div> 2094 <div><a href="/sport/basketball/girls?tab=staff" aria-label="Basketball">basketball</a></div> 2095 <div><a href="/sport/soccer/girls?tab=staff" aria-label="Soccer">soccer</a></div> 2096 <div><a href="/sport/softball/girls?tab=staff" aria-label="Softball">softball</a></div> 2097 <div><a href="/sport/volleyball/girls?tab=staff" aria-label="Volleyball">volleyball</a></div> 2098 </div> 2099 </div> 2100 </li> 2101 </ul> 2102 </li> 2103 <li class="cd-label text-secondary border-top-sm-secondary border-bottom-sm-secondary"> 2104 2105 RESOURCES 2106 2107 </li> 2108 <li class="bg-primary"> 2109 <a href="/links" aria-label="LINKS">links</a> 2110 </li> 2111 <li class="bg-primary"> 2112 <a href="/documents" aria-label="FORMS">forms</a> 2113 </li> 2114 </ul> 2115</nav> 2116 2117 </div> 2118 </div> 2119 <div class="col-md-9"> 2120 <div class="content-wrapper" id="main-content" role="main"> 2121 2122<div class="composite-calendar-view"> 2123 <div class="container"> 2124 <div class="cal-card"> 2125 <div class="cal-header"> 2126 <h1 class="cal-title">Composite Schedule</h1>
2127 <div class="cal-header-controls"> 2128 <select class="cal-select" id="sportFilter" aria-label="Filter by sport"> 2129 <option value="">All Sports</option> 2130 <option value="Baseball">Baseball</option> 2131 <option value="Basketball">Basketball</option> 2132 <option value="Football">Football</option> 2133 <option value="Soccer">Soccer</option> 2134 <option value="Softball">Softball</option> 2135 <option value="Volleyball">Volleyball</option> 2136 </select> 2137 <select class="cal-select" id="schoolTeams" aria-label="Filter by team"> 2138 <option value="0">All Teams</option> 2139 <option value="9608" data-sport="Soccer">Boys Varsity Soccer</option> 2140 <option value="9611" data-sport="Basketball">Boys Varsity Basketball</option> 2141 <option value="9614" data-sport="Baseball">Boys Varsity Baseball</option> 2142 <option value="9615" data-sport="Football">Boys Varsity Football</option> 2143 <option value="9898" data-sport="Soccer">Boys JV Soccer</option> 2144 <option value="9899" data-sport="Basketball">Boys JV Basketball</option> 2145 <option value="66070" data-sport="Basketball">Boys Freshman Basketball</option> 2146 <option value="9610" data-sport="Soccer">Girls Varsity Soccer</option> 2147 <option value="9613" data-sport="Volleyball">Girls Varsity Volleyball</option> 2148 <option value="9616" data-sport="Basketball">Girls Varsity Basketball</option> 2149 <option value="9895" data-sport="Softball">Girls JV Softball</option> 2150 <option value="9896" data-sport="Soccer">Girls JV Soccer</option> 2151 </select> 2152 <button type="button" class="sch-cal-sub-btn" data-sch-subscribe-open 2153 aria-haspopup="dialog" aria-controls="sch-cal-sub-modal"> 2154 <i class="fa fa-calendar-plus-o" aria-hidden="true"></i> 2155 <span>Subscribe to Calendar</span> 2156 </button> 2157 </div> 2158 </div> 2159 <div id="importMessages" role="status"></div> 2160 <div id="calendar"></div> 2161 </div> 2162 </div> 2163</div> 2164 2165<div class="sch-cal-sub-overlay" data-sch-subscribe-overlay 2166 data-school-id="958" 2167 data-school-name="St. Martin High School" 2168 data-api-base="https://mmboltapi.azurewebsites.net/api/v2/events" hidden> 2169 <div class="sch-cal-sub-modal" role="dialog" aria-modal="true" 2170 aria-labelledby="sch-cal-sub-title" aria-describedby="sch-cal-sub-scope" 2171 id="sch-cal-sub-modal"> 2172 <header class="sch-cal-sub-header"> 2173 <div class="sch-cal-sub-logo" aria-hidden="true"> 2174 <i class="fa fa-calendar-plus-o"></i> 2175 </div> 2176 <h2 id="sch-cal-sub-title" class="sch-cal-sub-title">Subscribe to the Calendar</h2> 2177 <button type="button" class="sch-cal-sub-close" 2178 data-sch-subscribe-close aria-label="Close subscribe dialog"> 2179 <i class="fa fa-times" aria-hidden="true"></i> 2180 </button> 2181 </header> 2182 2183 <p id="sch-cal-sub-scope" class="sch-cal-sub-scope"> 2184 <span class="sch-cal-sub-scope-label">You are subscribing to</span> 2185 <strong data-sch-subscribe-scope-target>the full calendar, every sport and every team</strong> 2186 <span class="sch-cal-sub-scope-hint" data-sch-subscribe-scope-hint></span> 2187 </p> 2188 2189 <p class="sch-cal-sub-lede">Pick the calendar app you use and your schedule stays in 2190 sync automatically as games are added or changed. The Excel and Download .ics 2191 options give you a one-time copy that won’t update on its own.</p> 2192 2193 <div class="sch-cal-sub-grid" role="list"> 2194 <a href="https://calendar.google.com/calendar/r?cid=webcal%3A%2F%2Fmmboltapi.azurewebsites.net%2Fapi%2Fv2%2Fevents%2Fcalendar%2F958%2F0%2Fcalendar.ics" data-sch-subscribe-provider="google" 2195 data-ics-url="https://mmboltapi.azurewebsites.net/api/v2/events/calendar/958/0/calendar.ics" 2196 target="_blank" rel="noopener" class="sch-cal-sub-tile" role="listitem"> 2197 <i class="fa fa-google" aria-hidden="true"></i>
2198 <span>Google</span> 2199 </a> 2200 <a href="webcal://mmboltapi.azurewebsites.net/api/v2/events/calendar/958/0/calendar.ics" data-sch-subscribe-provider="apple" 2201 class="sch-cal-sub-tile" role="listitem"> 2202 <i class="fa fa-apple" aria-hidden="true"></i> 2203 <span>Apple</span> 2204 </a> 2205 <a href="https://outlook.office.com/calendar/0/addfromweb?url=https%3A%2F%2Fmmboltapi.azurewebsites.net%2Fapi%2Fv2%2Fevents%2Fcalendar%2F958%2F0%2Fcalendar.ics&name=St.%20Martin%20High%20School%20Schedule" data-sch-subscribe-provider="outlook365" 2206 target="_blank" rel="noopener" class="sch-cal-sub-tile" role="listitem"> 2207 <i class="fa fa-windows" aria-hidden="true"></i> 2208 <span>Microsoft 365</span> 2209 </a> 2210 <a href="https://outlook.live.com/calendar/0/addfromweb?url=https%3A%2F%2Fmmboltapi.azurewebsites.net%2Fapi%2Fv2%2Fevents%2Fcalendar%2F958%2F0%2Fcalendar.ics&name=St.%20Martin%20High%20School%20Schedule" data-sch-subscribe-provider="outlook" 2211 target="_blank" rel="noopener" class="sch-cal-sub-tile" role="listitem"> 2212 <i class="fa fa-envelope" aria-hidden="true"></i> 2213 <span>Outlook.com</span> 2214 </a> 2215 <a href="https://calendar.google.com/calendar/r?cid=webcal%3A%2F%2Fmmboltapi.azurewebsites.net%2Fapi%2Fv2%2Fevents%2Fcalendar%2F958%2F0%2Fcalendar.ics" data-sch-subscribe-provider="android" 2216 data-ics-url="https://mmboltapi.azurewebsites.net/api/v2/events/calendar/958/0/calendar.ics" 2217 target="_blank" rel="noopener" class="sch-cal-sub-tile" role="listitem"> 2218 <i class="fa fa-android" aria-hidden="true"></i> 2219 <span>Android</span> 2220 </a> 2221 <a href="/Calendar/Schedule.csv" data-sch-subscribe-provider="excel" 2222 class="sch-cal-sub-tile" role="listitem"> 2223 <i class="fa fa-file-excel-o" aria-hidden="true"></i> 2224 <span>Excel</span> 2225 </a> 2226 <a href="https://mmboltapi.azurewebsites.net/api/v2/events/downloadcalendar/958/0" data-sch-subscribe-provider="other" 2227 class="sch-cal-sub-tile" role="listitem"> 2228 <i class="fa fa-download" aria-hidden="true"></i> 2229 <span>Download .ics</span> 2230 </a> 2231 </div> 2232 2233 <div class="sch-cal-sub-url-row"> 2234 <label for="sch-cal-sub-url">Feed URL</label> 2235 <input id="sch-cal-sub-url" type="text" readonly value="https://mmboltapi.azurewebsites.net/api/v2/events/calendar/958/0/calendar.ics" /> 2236 <button type="button" class="sch-cal-sub-copy" data-sch-subscribe-copy> 2237 <i class="fa fa-copy" aria-hidden="true"></i> Copy 2238 </button> 2239 </div> 2240 2241 <footer class="sch-cal-sub-footer"> 2242 <button type="button" class="sch-cal-sub-primary" 2243 data-sch-subscribe-primary>Subscribe Now</button> 2244 </footer> 2245 </div> 2246</div> 2247 2248 2249 2250 </div> 2251 </div> 2252 </div> 2253 2254 <footer> 2255 2256 2257 2258 2259 <div class="footer bg-primary"> 2260 <div class="footer-contain"> 2261 <div id="footer-gradient" class="angle-primary-secondary bg-primary"></div> 2262 <div id="footer-gradient-bottom" class="bg-primary"> 2263 <div class="row"> 2264 <div class="col-md-12"> 2265 <div id="address"> 2266 <p> 2267 ATHLETIC OFFICE - (228) 872-0256<br /> 2268 10700 YELLOW JACKET BLVD.<br /> 2269 Ocean Springs, MS 39564<br /> 2270 </p> 2271 <br /> 2272 <p>Thank you to all of our <a style="color: #fff; text-decoration: underline; padding: 3px;" href="/sponsor/SponsorsPage">Sponsors!</a></p> 2273 </div> 2274 </div> 2275 </div> 2276 <!-- app promotion --> 2277 <div class="footer-items"> 2278 <div class="row"> 2279 <div class="col-md-12"> 2280 <div id="app-downloads"> 2281 <div id="badges"> 2282 <div class="row"> 2283 <div class="col-sm-12"> 2284 <a href="https://itunes.apple.com/us/app/niaaa/id963291250?mt=8" target="_blank"><img class="img-responsive download" src="/images/dl-apple.png" aria-label="Apple App Store Badge" alt="Apple App Store Badge" /></a> 2285 <img class="img-responsive app-icon" src="/images/niaaa-icon.png" aria-label="Mascot Media App Icon Logo" alt="Mascot Media App Icon Logo" /> 2286 2287 <a href="https://play.google.com/store/apps/details?id=com.sidelineaccess.niaaa&hl=en" target="_blank"><img class="img-responsive download" src="/images/dl-google.png" aria-label="Google Play Store Badge" alt="Google Play Store Badge" /></a> 2288 </div> 2289 </div> 2290 </div> 2291 </div> 2292 </div> 2293 </div> 2294 </div> 2295 </div> 2296 </div> 2297 <div class="feeder-schools-footer bg-primary"> 2298 </div> 2299</div> 2300 <div class="footer bg-primary"> 2301 <div class="widget padded-box"> 2302 <div class="footer-items"> 2303 <div class="row"> 2304 <div class="col-md-12"> 2305 2306 </div> 2307 </div> 2308 </div> 2309 </div> 2310</div> 2311 2312 </footer> 2313 </div> 2314 <div class="privacy-terms"> 2315 <a href="http://www.mascotmedia.net/privacy-policy/" target="_blank" rel="noopener noreferrer">PRIVACY POLICY</a> <span class="sr-only">(opens in a new tab)</span> | 2316 2317
2318 <span>© 2026 MASCOT MEDIA, LLC</span> 2319 </div> 2320 <div class="ad-space"> 2321 </div> 2322 2323
2323<script src="/lib/jquery/dist/jquery.min.js"></script>
2323 2324
2324<script src="/js/lity.js"></script>
2324 2325
2325<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js" integrity="sha384-Tc5IQib027qvyjSMfHjOMaLkfuWVxZxUPnCJA7l2mCWNIpG9mGCD8wGNIcPD7Txa" crossorigin="anonymous"></script>
2325 2326
2326<script type="text/javascript" src="/js/scrollfixed.min.js"></script>
2326 2327
2327<script src="/js/topmenu2.min.js?v=1.1"></script>
2327 2328
2328<script src="/js/sidenav.min.js"></script>
2328 2329
2329<script src="/js/latestheadlines.min.js"></script>
2329 2330
2330<script src="/lib/datatables/media/js/jquery.dataTables.min.js"></script>
2330 2331
2331<script src="/lib/datatables/media/js/dataTables.bootstrap.min.js"></script>
2331 2332
2332<script src="/lib/datatables-responsive/js/dataTables.responsive.min.js"></script>
2332 2333
2333<script src="/lib/jquery.menu-aim/jquery.menu-aim.min.js"></script>
2333 2334
2334<script src="https://cdn.jsdelivr.net/jquery.slick/1.3.15/slick.min.js"></script>
2334 2335
2335<script src="/js/StagingButtons.min.js"></script>
2335 2336
2336<script src="/lib/sweetalert/dist/sweetalert.min.js"></script>
2336 2337
2337<script src="/lib/slick-carousel/slick/slick.min.js"></script>
2337 2338
2338<script src="/js/PlatinumSponsorStyle2.min.js"></script>
2338 2339
2339<script src="/js/CommitmentsStyle1.min.js"></script>
2339 2340 2341 2342 2343 2344
2344<script src="/lib/moment/moment.js"></script>
2344 2345
2345<script src="/lib/fullcalendar/dist/fullcalendar.js"></script>
2345 2346 2347
2347<script type="text/javascript"> 2348 $(document).ready(function () { 2349 setTimeout(function () { 2350 $('#calendar').fullCalendar({ 2351 eventRender: function (event, element) { 2352 // Keyboard + SR access for month-grid events (WCAG 2.1.1) 2353 element.attr('tabindex', '0'); 2354 element.attr('aria-label', (event.title || '') + (event.start ? ', ' + event.start.format('MMMM D') : '')); 2355 element.on('keydown', function (e) { 2356 if (e.key === 'Enter' || e.keyCode === 13) { $(this).trigger('click'); } 2357 }); 2358 }, 2359 header: { 2360 left: 'prev,next today', 2361 center: 'title', 2362 right: 'month,listMonth' 2363 }, 2364 events: { 2365 url: '/CalendarEvents/', 2366 type: 'GET', 2367 data: { 2368 schoolTeamId: '0' 2369 }, 2370 color: '#e6e7e8', 2371 textColor: 'black' 2372 }, 2373 contentHeight: "auto", 2374 themeSystem: 'bootstrap3', 2375 eventLimit: 4, 2376 windowResize: function (view) { 2377 if ($(window).width() < 991) { 2378 $('#calendar').fullCalendar('changeView', 'listMonth'); 2379 } 2380 } 2381 }); 2382 }, 500); 2383 2384 // Enhanced import handler with Google Calendar smart fallback 2385 $(document).on('change', '#importCal', function () { 2386 var selectedOption = $(this).find('option:selected'); 2387 var importUrl = $(this).val(); 2388 2389 if (importUrl == "") { 2390 return false; 2391 } 2392 2393 if (selectedOption.attr('id') === 'googleCalImport') { 2394 handleGoogleCalendarImport(selectedOption); 2395 } else { 2396 window.open(importUrl, '_blank'); 2397 } 2398 2399 $(this).val(''); 2400 }); 2401 2402 // Picking a sport narrows the Team dropdown to that sport's teams 2403 // instead of wiping the selection: "Soccer" then leaves Boys 2404 // Varsity, Girls JV and so on to choose from. 2405 $(document).on('change', '#sportFilter', function () { 2406 var sport = $(this).val(); 2407 applyCalendarFilters(sport, filterTeamsBySport(sport)); 2408 }); 2409 2410 $(document).on('change', '#schoolTeams', function () { 2411 applyCalendarFilters($('#sportFilter').val(), $(this).val()); 2412 }); 2413 2414 // Initialize calendar links 2415 ConfigureCalendarLinks(958, '0'); 2416 }); 2417 2418 function handleGoogleCalendarImport(optionElement) { 2419 var importUrl = optionElement.val(); 2420 var icsUrl = optionElement.data('ics-url'); 2421 2422 // Show the fallback panel immediately so it is waiting on this tab 2423 // when the user comes back from Google Calendar (whether the import 2424 // succeeded or showed "Unable to add calendar"). 2425 showImportFallback(icsUrl); 2426 2427 // Try the one-click cid import. 2428 window.open(importUrl, '_blank'); 2429 } 2430 2431 function showImportFallback(icsUrl) { 2432 if ($('.import-fallback').length) { return; } 2433 var safeUrl = String(icsUrl).replace(/'/g, "\\'"); 2434 var html = '<div class="import-message import-fallback alert alert-warning">' + 2435 '<button type="button" class="close" onclick="$(this).parent().remove();">×</button>' + 2436 '<strong>Calendar did not import?</strong> ' + 2437 '<button class="btn btn-sm btn-primary" onclick="copyUrlAndOpenSettings(\'' + safeUrl + '\')">Open Google Calendar</button> ' + 2438 'to add it manually (URL will be copied to your clipboard).' + 2439 '</div>'; 2440 $('#importMessages').prepend(html); 2441 } 2442 2443 function showImportMessage(message, type) { 2444 var alertClass = type === 'error' ? 'alert-danger' : 'alert-info'; 2445 var messageHtml = '<div class="import-message alert ' + alertClass + '">' + 2446 '<button type="button" class="close" onclick="$(this).parent().remove();">×</button>' + 2447 message + 2448 '</div>'; 2449 2450 $('.import-message').remove(); // Remove existing messages 2451 $('#importMessages').prepend(messageHtml); 2452 } 2453 2454 function copyUrlAndOpenSettings(icsUrl) { 2455 var openSettings = function () { 2456 window.open('https://calendar.google.com/calendar/u/0/r/settings/addbyurl', '_blank'); 2457 }; 2458 if (navigator.clipboard && navigator.clipboard.writeText) { 2459 navigator.clipboard.writeText(icsUrl).then(openSettings, openSettings); 2460 } else { 2461 openSettings();
2462 } 2463 } 2464 2465 function showManualInstructions(icsUrl) { 2466 var instructionsHtml = '<div class="import-message alert alert-info">' + 2467 '<button type="button" class="close" onclick="$(this).parent().remove();">×</button>' + 2468 '<strong>Manual Import Instructions:</strong><br>' + 2469 '1. <button class="btn btn-sm btn-success" onclick="copyUrlToClipboard(\'' + icsUrl + '\', this)">Copy Calendar URL</button><br><br>' + 2470 '2. <a href="https://calendar.google.com/calendar/u/0/r/settings/addbyurl" target="_blank" class="btn btn-sm btn-primary">Open Google Calendar Settings</a><br><br>' + 2471 '3. Paste the URL in the "URL of calendar" field<br>' + 2472 '4. Click "Add calendar"' + 2473 '</div>'; 2474 2475 $('.import-message').remove(); 2476 $('#importMessages').prepend(instructionsHtml); 2477 } 2478 2479 function copyUrlToClipboard(url, buttonElement) { 2480 if (navigator.clipboard) { 2481 navigator.clipboard.writeText(url).then(function () { 2482 $(buttonElement).text('Copied!').removeClass('btn-success').addClass('btn-secondary'); 2483 setTimeout(function () { 2484 $(buttonElement).text('Copy Calendar URL').removeClass('btn-secondary').addClass('btn-success'); 2485 }, 2000); 2486 }).catch(function () { 2487 // Fallback: show the URL for manual copying 2488 showUrlForManualCopy(url, buttonElement); 2489 }); 2490 } else { 2491 // Fallback: show the URL for manual copying 2492 showUrlForManualCopy(url, buttonElement); 2493 } 2494 } 2495 2496 function showUrlForManualCopy(url, buttonElement) { 2497 var urlBox = '<div class="ics-url-box" onclick="selectText(this)" style="margin-top: 10px;">' + url + '</div>'; 2498 $(buttonElement).after(urlBox); 2499 $(buttonElement).text('Click URL below to copy').removeClass('btn-success').addClass('btn-warning'); 2500 } 2501 2502 function selectText(element) { 2503 var range = document.createRange(); 2504 range.selectNodeContents(element); 2505 var selection = window.getSelection(); 2506 selection.removeAllRanges(); 2507 selection.addRange(range); 2508 2509 try { 2510 document.execCommand('copy'); 2511 $(element).css('background-color', '#d4edda').after('<span style="color: green; font-size: 12px;"> Copied!</span>'); 2512 setTimeout(function () { 2513 $(element).css('background-color', '#f9f9f9').next('span').remove(); 2514 }, 2000); 2515 } catch (err) { 2516 console.log('Copy failed:', err); 2517 } 2518 } 2519 2520 function guid() { 2521 function s4() { 2522 return Math.floor((1 + Math.random()) * 0x10000) 2523 .toString(16) 2524 .substring(1); 2525 } 2526 return s4() + s4() + '-' + s4() + '-' + s4() + '-' + 2527 s4() + '-' + s4() + s4() + s4(); 2528 } 2529 2530 var schoolTeamOptions = null; 2531 2532 // Snapshot of every team option, taken before the first narrowing so a 2533 // later sport change rebuilds from the full list rather than from 2534 // whatever survived the previous one. 2535 function teamOptionSnapshot() { 2536 if (!schoolTeamOptions) { 2537 schoolTeamOptions = $('#schoolTeams option').map(function () { 2538 return { value: this.value, text: this.text, sport: this.getAttribute('data-sport') || '' }; 2539 }).get(); 2540 } 2541 return schoolTeamOptions; 2542 } 2543 2544 // Rebuilds the Team dropdown for the selected sport and returns the team 2545 // id that survived: the previous pick if it belongs to this sport, 2546 // otherwise All Teams. 2547 function filterTeamsBySport(sport) { 2548 var select = document.getElementById('schoolTeams'); 2549 if (!select) { return '0'; } 2550 2551 var previous = select.value; 2552 var wanted = (sport || '').toLowerCase(); 2553 var options = teamOptionSnapshot().filter(function (o) { 2554 return o.value === '0' || !wanted || o.sport.toLowerCase() === wanted; 2555 }); 2556 2557 select.innerHTML = ''; 2558 options.forEach(function (o) { 2559 var option = document.createElement('option'); 2560 option.value = o.value; 2561 option.text = o.text; // .text, not innerHTML: school-entered data 2562 if (o.sport) { option.setAttribute('data-sport', o.sport); } 2563 select.appendChild(option); 2564 }); 2565 2566 select.value = options.some(function (o) { return o.value === previous; }) ? previous : '0'; 2567 return select.value; 2568 } 2569 2570 // Single path for both dropdowns, so the month grid and the subscribe 2571 // links can never disagree about what is being shown. 2572 function applyCalendarFilters(sport, schoolTeamId) { 2573 var teamId = String(schoolTeamId || '0'); 2574 var source = { 2575 url: '/CalendarEvents/', type: 'GET', 2576 data: { schoolTeamId: teamId }, 2577 color: '#e6e7e8', textColor: 'black' 2578 }; 2579 // A team belongs to exactly one sport, so the sport filter only has
2580 // work to do while the feed is still school-wide. 2581 if (sport && teamId === '0') { 2582 source.success = function (events) { 2583 return events.filter(function (e) { 2584 return e.title && e.title.toLowerCase().indexOf(sport.toLowerCase()) > -1; 2585 }); 2586 }; 2587 } 2588 2589 $('#calendar').fullCalendar('removeEventSources'); 2590 $('#calendar').fullCalendar('addEventSource', source); 2591 ConfigureCalendarLinks(958, teamId); 2592 } 2593 2594 // Points every tile in the subscribe modal at the currently selected 2595 // team. The feed URL carries the team id (0 = the school's whole 2596 // calendar), so choosing "Boys Varsity Soccer" produces a Boys Varsity 2597 // Soccer subscription rather than every game the school plays. 2598 // 2599 // Deliberately no cache-buster on the .ics URL: Google keys a 2600 // subscription off the exact URL, so a per-load guid would let one 2601 // parent stack up a duplicate calendar on every visit. 2602 function ConfigureCalendarLinks(schoolId, schoolTeamId) { 2603 var overlay = document.querySelector('[data-sch-subscribe-overlay]'); 2604 if (!overlay) { return; } 2605 2606 var teamId = String(schoolTeamId || '0'); 2607 var apiBase = overlay.getAttribute('data-api-base'); 2608 var schoolName = overlay.getAttribute('data-school-name') || 'School'; 2609 var teamLabel = teamId !== '0' 2610 ? $('#schoolTeams option:selected').text().replace(/\s+/g, ' ').trim() 2611 : ''; 2612 2613 var icsHttps = apiBase + '/calendar/' + schoolId + '/' + teamId + '/calendar.ics'; 2614 var icsWebcal = icsHttps.replace(/^https:/i, 'webcal:'); 2615 var encodedIcs = encodeURIComponent(icsHttps); 2616 var googleUrl = 'https://calendar.google.com/calendar/r?cid=' + encodeURIComponent(icsWebcal); 2617 var calName = encodeURIComponent(teamLabel ? schoolName + ' ' + teamLabel : schoolName + ' Schedule'); 2618 2619 setSubscribeTile(overlay, 'google', googleUrl, icsHttps); 2620 setSubscribeTile(overlay, 'android', googleUrl, icsHttps); 2621 setSubscribeTile(overlay, 'apple', icsWebcal); 2622 setSubscribeTile(overlay, 'outlook365', 'https://outlook.office.com/calendar/0/addfromweb?url=' + encodedIcs + '&name=' + calName); 2623 setSubscribeTile(overlay, 'outlook', 'https://outlook.live.com/calendar/0/addfromweb?url=' + encodedIcs + '&name=' + calName); 2624 setSubscribeTile(overlay, 'excel', '/Calendar/Schedule.csv?schoolTeamId=' + encodeURIComponent(teamId)); 2625 setSubscribeTile(overlay, 'other', apiBase + '/downloadcalendar/' + schoolId + '/' + teamId); 2626 2627 var urlInput = overlay.querySelector('#sch-cal-sub-url'); 2628 if (urlInput) { urlInput.value = icsHttps; } 2629 2630 // textContent, not innerHTML: the team label is school-entered data. 2631 var scopeTarget = overlay.querySelector('[data-sch-subscribe-scope-target]'); 2632 var scopeHint = overlay.querySelector('[data-sch-subscribe-scope-hint]'); 2633 if (scopeTarget) { 2634 scopeTarget.textContent = teamLabel || 'the full calendar, every sport and every team'; 2635 } 2636 if (scopeHint) { 2637 if (teamLabel) { 2638 scopeHint.textContent = 'Only this team. Set the Team dropdown back to All Teams for the whole calendar.'; 2639 } else if ($('#sportFilter').val()) { 2640 scopeHint.textContent = 'A sport on its own cannot be subscribed to. Pick a team in the Team dropdown to get just that team.'; 2641 } else { 2642 scopeHint.textContent = 'Pick a team in the Team dropdown first to subscribe to one team instead.'; 2643 } 2644 } 2645 } 2646 2647 function setSubscribeTile(overlay, provider, href, icsUrl) { 2648 var tile = overlay.querySelector('[data-sch-subscribe-provider="' + provider + '"]'); 2649 if (!tile) { return; } 2650 tile.setAttribute('href', href); 2651 if (icsUrl) { tile.setAttribute('data-ics-url', icsUrl); } 2652 } 2653 2654 // --- Subscribe-to-Schedule modal ----------------------------- 2655 (function () {
2656 var overlay = document.querySelector('[data-sch-subscribe-overlay]'); 2657 var openBtn = document.querySelector('[data-sch-subscribe-open]'); 2658 if (!overlay || !openBtn) return; 2659 var closeBtn = overlay.querySelector('[data-sch-subscribe-close]'); 2660 var urlInput = overlay.querySelector('#sch-cal-sub-url'); 2661 var copyBtn = overlay.querySelector('[data-sch-subscribe-copy]'); 2662 var primary = overlay.querySelector('[data-sch-subscribe-primary]'); 2663 var tiles = overlay.querySelectorAll('[data-sch-subscribe-provider]'); 2664 var selected = tiles.length ? tiles[0] : null; 2665 2666 function setSelected(tile) { 2667 selected = tile; 2668 tiles.forEach(function (t) { 2669 t.classList.toggle('is-active', t === tile); 2670 }); 2671 } 2672 function openModal() { 2673 // Rebuild from the live dropdown rather than trusting the last 2674 // change event: browsers restore <select> state on a soft 2675 // reload without firing change, which would otherwise leave the 2676 // tiles pointing at whatever team was picked before the reload. 2677 var teamSelect = document.getElementById('schoolTeams'); 2678 ConfigureCalendarLinks(overlay.getAttribute('data-school-id'), teamSelect ? teamSelect.value : '0'); 2679 overlay.hidden = false; 2680 document.body.classList.add('sch-cal-sub-locked'); 2681 if (selected) setSelected(selected); 2682 setTimeout(function () { primary && primary.focus(); }, 30); 2683 } 2684 function closeModal() { 2685 overlay.hidden = true; 2686 document.body.classList.remove('sch-cal-sub-locked'); 2687 openBtn.focus(); 2688 } 2689 2690 openBtn.addEventListener('click', openModal); 2691 closeBtn && closeBtn.addEventListener('click', closeModal); 2692 overlay.addEventListener('click', function (e) { 2693 if (e.target === overlay) closeModal(); 2694 }); 2695 document.addEventListener('keydown', function (e) { 2696 if (!overlay.hidden && e.key === 'Escape') closeModal(); 2697 }); 2698 2699 tiles.forEach(function (tile) { 2700 tile.addEventListener('click', function (e) { 2701 setSelected(tile); 2702 var href = tile.getAttribute('href'); 2703 if (!href || href === '#') { 2704 e.preventDefault(); 2705 return; 2706 } 2707 // Google and Android both route through Google's add-by-URL 2708 // flow, so show the fallback banner for either before opening. 2709 var provider = tile.getAttribute('data-sch-subscribe-provider'); 2710 if (provider === 'google' || provider === 'android') { 2711 var icsUrl = tile.getAttribute('data-ics-url'); 2712 if (icsUrl && typeof showImportFallback === 'function') { 2713 showImportFallback(icsUrl); 2714 } 2715 } 2716 }); 2717 }); 2718 2719 primary && primary.addEventListener('click', function () { 2720 if (selected) selected.click(); 2721 }); 2722 2723 copyBtn && copyBtn.addEventListener('click', function () { 2724 urlInput.select(); 2725 try { document.execCommand('copy'); } catch (_) { } 2726 if (navigator.clipboard) { 2727 navigator.clipboard.writeText(urlInput.value).catch(function () { });
2728 } 2729 var orig = copyBtn.innerHTML; 2730 copyBtn.innerHTML = '<i class="fa fa-check" aria-hidden="true"></i> Copied'; 2731 setTimeout(function () { copyBtn.innerHTML = orig; }, 1600); 2732 }); 2733 })(); 2734 </script>
2734 2735 2736 2737 2738 2739 2740 2741
2741<script type="text/javascript"> 2742 $.extend(true, $.fn.dataTable.defaults, { 2743 language: { 2744 "processing": "<i class='fa fa-refresh fa-spin fa-2x'></i><br />Loading..." 2745 } 2746 }); 2747 2748 $('.dropdown-button').dropdown({ 2749 inDuration: 300, 2750 outDuration: 225, 2751 //alignment: "center", 2752 hover: false, // Activate on hover 2753 }); 2754 </script>
2754 2755
2755<script type='text/javascript'> 2756 var url = ''; 2757 var regex = /([\d]{10,})/g; 2758 var meta = document.createElement('meta'); 2759 meta.setAttribute('name', 'apple-itunes-app'); 2760 meta.setAttribute('content', 'app-id=' + url.match(regex)); 2761 document.getElementsByTagName('head')[0].appendChild(meta); 2762 </script>
2762 2763 2764 <!-- Quantcast Tag --> 2765
2765<script type="text/javascript"> 2766 window._qevents = window._qevents || []; 2767 (function () { 2768 var elem = document.createElement('script'); 2769 elem.src = (document.location.protocol == "https:" ? "https://secure" : "http://edge") + ".quantserve.com/quant.js"; 2770 elem.async = true; 2771 elem.type = "text/javascript"; 2772 var scpt = document.getElementsByTagName('script')[0]; 2773 scpt.parentNode.insertBefore(elem, scpt); 2774 })(); 2775 window._qevents.push({ 2776 qacct: "p-L8Vz-DsnmdfCj", 2777 uid: "__INSERT_EMAIL_HERE__" 2778 }); 2779 </script>
2779 2780 <noscript> 2781 <div style="display:none;"> 2782 <img src="//pixel.quantserve.com/pixel/p-L8Vz-DsnmdfCj.gif" border="0" height="1" width="1" alt="Quantcast" /> 2783 </div> 2784 </noscript> 2785 <!-- End Quantcast tag --> 2786</body> 2787</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.