1<!DOCTYPE html> 2<html lang="en" class="h-full"> 3 4<head> 5 <meta charset="utf-8"> 6 <meta name="viewport" content="width=device-width, initial-scale=1"> 7 <meta name="csrf-token" content="3xb9r3YBUSfm6nHsaFEbe6oegveNR1tmzpnMPFpt"> 8 9 10 <meta name="vapid-public-key" content="BMghJlhP9QKI8NOk4_-uHuO0dJ0nNCgVBgzNRfTdtnGzBZQmaJydBs1CoLfe_dD153YiepLnoNO8G5P7IvMRF7g"> 11 12 <link rel="icon" type="image/png" href="/images/logo/running-calendar-logo.png"> 13 14 15 <link rel="manifest" href="/manifest.webmanifest"> 16 <link rel="apple-touch-icon" sizes="180x180" href="/icons/apple-touch-icon.png"> 17 <meta name="apple-mobile-web-app-capable" content="yes"> 18 <meta name="mobile-web-app-capable" content="yes"> 19 20 <meta name="apple-mobile-web-app-status-bar-style" content="default"> 21 <meta name="apple-mobile-web-app-title" content="RunningCalendar"> 22 23 24 <meta name="theme-color" content="#ffffff" media="(prefers-color-scheme: light)"> 25 <meta name="theme-color" content="#0f172a" media="(prefers-color-scheme: dark)"> 26 27 28 <meta name="copyright" content="© 2026 RunningCalendar"> 29 <link rel="license" href="https://runningcalendar.co.za/terms"> 30 31 <title>Contact â RunningCalendar</title><meta name="description" content="Get in touch with RunningCalendar. Report a race correction, submit a new event, or ask a general question. We reply within one working day."><link rel="canonical" href="https://runningcalendar.co.za/contact"><meta property="og:site_name" content="RunningCalendar"> 32 33 34 35 36
36<script type="application/ld+json"> 37 {"@context":"https:\/\/schema.org","@type":"ContactPage","name":"Contact RunningCalendar","url":"https:\/\/runningcalendar.co.za\/contact"} 38 </script>
38 39 40 <link rel="preconnect" href="https://fonts.bunny.net" crossorigin> 41 <link rel="dns-prefetch" href="https://fonts.bunny.net"> 42 <link href="https://fonts.bunny.net/css?family=inter:400,500,600,700,800|jetbrains-mono:400,500,600&display=swap" rel="stylesheet"> 43 44 45 46 47 48 49
49<script> 50 window.dataLayer = window.dataLayer || []; 51 window.gtag = window.gtag || function () { window.dataLayer.push(arguments); }; 52 gtag('consent', 'default', { 53 ad_storage: 'denied', 54 ad_user_data: 'denied', 55 ad_personalization: 'denied', 56 analytics_storage: 'denied', 57 wait_for_update: 500, 58 }); 59 60 gtag('set', 'ads_data_redaction', true); 61</script>
61 62 63 64
64<script async src="https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?client=ca-pub-8912238222537097" crossorigin="anonymous"></script>
vendor: 72 bytes, lines 64-69
64 65 66 67 68 69 <script async src="https://www.googletagmanager.com/gtag/js?id=
69G-1SD3620RF7
vendor: 21 bytes, lines 69-71
69"></script> 70 71
71<script> 72 window.dataLayer = window.dataLayer || []; 73 window.gtag = window.gtag || function () { window.dataLayer.push(arguments); }; 74 window.rcGaContext = JSON.parse('{\u0022content_group\u0022:\u0022other\u0022}'); 75 (function () { 76 var context = {}; 77 JSON.parse('[\u0022event_slug\u0022,\u0022event_year\u0022,\u0022event_province\u0022,\u0022event_country\u0022,\u0022event_month\u0022,\u0022event_verified\u0022]').forEach(function (key) { context[key] = undefined; }); 78 gtag('set', Object.assign(context, window.rcGaContext)); 79 })(); 80 </script>
80 81
81<script> 82 window.dataLayer = window.dataLayer || []; 83 window.gtag = window.gtag || function () { window.dataLayer.push(arguments); }; 84 gtag('js', new Date()); 85 gtag('config', 'G-1SD3620RF7'); 86 </script>
86 87 88 89 <link rel="preload" as="style" href="https://runningcalendar.co.za/build/assets/klaro-init-D9kWC4xL.css" /><link rel="preload" as="style" href="https://runningcalendar.co.za/build/assets/app-UCWSNQpH.css" /><link rel="modulepreload" as="script" href="https://runningcalendar.co.za/build/assets/klaro-init-BzzS2RY0.js" /><link rel="modulepreload" as="script" href="https://runningcalendar.co.za/build/assets/rolldown-runtime-CbXtAM7H.js" /><link rel="modulepreload" as="script" href="https://runningcalendar.co.za/build/assets/app-DilpS2M4.js" /><link rel="stylesheet" href="https://runningcalendar.co.za/build/assets/klaro-init-D9kWC4xL.css" data-navigate-track="reload" /><link rel="stylesheet" href="https://runningcalendar.co.za/build/assets/app-UCWSNQpH.css" data-navigate-track="reload" />
89<script type="module" src="https://runningcalendar.co.za/build/assets/klaro-init-BzzS2RY0.js" data-navigate-track="reload"></script>
89<script type="module" src="https://runningcalendar.co.za/build/assets/app-DilpS2M4.js" data-navigate-track="reload"></script>
89 90 <style> 91 :root.dark { 92 color-scheme: dark; 93 } 94</style>
95<script> 96 window.Flux = { 97 applyAppearance (appearance) { 98 let applyDark = () => document.documentElement.classList.add('dark') 99 let applyLight = () => document.documentElement.classList.remove('dark') 100 101 if (appearance === 'system') { 102 let media = window.matchMedia('(prefers-color-scheme: dark)') 103 104 window.localStorage.removeItem('flux.appearance') 105 106 media.matches ? applyDark() : applyLight() 107 } else if (appearance === 'dark') { 108 window.localStorage.setItem('flux.appearance', 'dark') 109 110 applyDark() 111 } else if (appearance === 'light') { 112 window.localStorage.setItem('flux.appearance', 'light') 113 114 applyLight() 115 } 116 } 117 } 118 119 window.Flux.applyAppearance(window.localStorage.getItem('flux.appearance') || 'system') 120</script>
120 121<!-- Livewire Styles --><style >[wire\:loading][wire\:loading], [wire\:loading\.delay][wire\:loading\.delay], [wire\:loading\.inline-block][wire\:loading\.inline-block], [wire\:loading\.inline][wire\:loading\.inline], [wire\:loading\.block][wire\:loading\.block], [wire\:loading\.flex][wire\:loading\.flex], [wire\:loading\.table][wire\:loading\.table], [wire\:loading\.grid][wire\:loading\.grid], [wire\:loading\.inline-flex][wire\:loading\.inline-flex] {display: none;}[wire\:loading\.delay\.none][wire\:loading\.delay\.none], [wire\:loading\.delay\.shortest][wire\:loading\.delay\.shortest], [wire\:loading\.delay\.shorter][wire\:loading\.delay\.shorter], [wire\:loading\.delay\.short][wire\:loading\.delay\.short], [wire\:loading\.delay\.default][wire\:loading\.delay\.default], [wire\:loading\.delay\.long][wire\:loading\.delay\.long], [wire\:loading\.delay\.longer][wire\:loading\.delay\.longer], [wire\:loading\.delay\.longest][wire\:loading\.delay\.longest] {display: none;}[wire\:offline][wire\:offline] {display: none;}[wire\:dirty]:not(textarea):not(input):not(select) {display: none;}:root {--livewire-progress-bar-color: #2299dd;}[x-cloak="x-cloak"],[x-cloak=""] {display: none !important;}[wire\:cloak="wire:cloak"],[wire\:cloak=""] {display: none !important;}dialog#livewire-error::backdrop {background-color: rgba(0, 0, 0, .6);}</style> 122</head> 123 124<body class="flex min-h-full flex-col bg-bg font-sans antialiased text-ink"> 125 126 <a 127 href="#main-content" 128 class="sr-only focus:not-sr-only focus:fixed focus:top-4 focus:left-4 focus:z-[200] focus:rounded-lg focus:bg-surface focus:px-4 focus:py-2 focus:text-sm focus:font-semibold focus:text-ink focus:shadow-lg focus:ring-2 focus:ring-ink" 129> 130 Skip to content 131</a> 132 133 134<div 135 x-data="{ drawerOpen: false, tab: (['menu','browse','account'].includes(localStorage.getItem('rc_nav_tab')) ? localStorage.getItem('rc_nav_tab') : 'menu'), isDesktop: false }" 136 class="contents" 137 x-init=" 138 // Persist the active drawer tab so reopening keeps the last selection. 139 $watch('tab', v => localStorage.setItem('rc_nav_tab', v)); 140 // Reactive desktop flag â the mobile sheet must NOT render on desktop. 141 // Gating on a matchMedia flag (not Tailwind lg:hidden) avoids the 142 // x-show inline-display leak: a resize-while-open would otherwise keep 143 // the full-screen scrim mounted on desktop and eat clicks (CLAUDE.md §10). 144 const mq = window.matchMedia('(min-width: 1024px)'); 145 isDesktop = mq.matches; 146 mq.addEventListener('change', (e) => { isDesktop = e.matches; if (e.matches) drawerOpen = false; }); 147 window.addEventListener('keydown', (e) => { 148 if ((e.metaKey || e.ctrlKey) && e.key === 'k') { 149 e.preventDefault(); 150 $dispatch('open-search-modal'); 151 } 152 }); 153 " 154> 155 156 <header role="banner" class="sticky top-0 z-20 bg-surface border-b border-rule-soft"> 157 158 159 160 161 <div 162 class="hidden lg:flex items-center gap-4 px-6 py-3 mx-auto max-w-screen-xl relative" 163 x-data="{ calOpen: false }" 164 @keydown.escape.window="calOpen = false" 165 @click.outside="calOpen = false" 166 > 167 168 169 <a href="https://runningcalendar.co.za" class="flex shrink-0 items-center gap-2.5 text-ink" aria-label="RunningCalendar home"> 170 <img 171 src="https://runningcalendar.co.za/images/logo/running-calendar-logo.png" 172 alt="RunningCalendar" 173 width="32" 174 height="32" 175 class="h-8 w-8 object-contain" 176 > 177 <span class="font-semibold tracking-tight">RunningCalendar</span> 178 </a> 179 180 181 <nav class="flex shrink-0 items-center gap-1" aria-label="Primary navigation"> 182 183 <div class="flex items-stretch"> 184 <a 185 href="https://runningcalendar.co.za/calendar" 186 class="whitespace-nowrap rounded-l-lg px-3 py-2 text-sm font-medium transition 187 text-ink-2 hover:bg-soft hover:text-ink" 188 > 189 Calendar 190 </a> 191 <button 192 type="button" 193 @click="calOpen = !calOpen" 194 :aria-expanded="calOpen" 195 aria-label="Calendar browse shortcuts" 196 class="inline-flex items-center cursor-pointer rounded-r-lg pl-0.5 pr-2 text-sm font-medium transition 197 text-ink-2 hover:bg-soft hover:text-ink" 198 > 199 <svg 200 width="13" 201 height="13"
202 viewBox="0 0 24 24" 203 fill="none" 204 stroke="currentColor" 205 stroke-width="1.8" 206 stroke-linecap="round" 207 stroke-linejoin="round" 208 class="flex-shrink-0 transition-transform duration-150" :class="{ 'rotate-180': calOpen }" 209 ><polyline points="6 9 12 15 18 9"/></svg> 210 </button> 211 </div> 212 <a 213 href="https://runningcalendar.co.za/near-me" 214 @click="calOpen = false" 215 class="whitespace-nowrap rounded-lg px-3 py-2 text-sm font-medium transition 216 text-ink-2 hover:bg-soft hover:text-ink" 217 > 218 Near Me 219 </a> 220 <a 221 href="https://runningcalendar.co.za/results" 222 @click="calOpen = false" 223 class="whitespace-nowrap rounded-lg px-3 py-2 text-sm font-medium transition 224 text-ink-2 hover:bg-soft hover:text-ink" 225 > 226 Results 227 </a> 228 <a 229 href="https://runningcalendar.co.za/advertise" 230 @click="calOpen = false" 231 class="whitespace-nowrap rounded-lg px-3 py-2 text-sm font-medium transition 232 text-ink-2 hover:bg-soft hover:text-ink" 233 > 234 Advertise 235 </a> 236 </nav> 237 238 239 <button 240 type="button" 241 @click="$dispatch('open-search-modal')" 242 class="flex items-center gap-2 px-3 bg-soft border border-transparent rounded-lg h-10 cursor-pointer transition hover:bg-surface hover:border-rule text-muted" 243 style="min-width:170px;flex:1 1 auto" 244 aria-label="Search races, towns" 245 > 246 <svg 247 width="18" 248 height="18"
249 viewBox="0 0 24 24" 250 fill="none" 251 stroke="currentColor" 252 stroke-width="1.8" 253 stroke-linecap="round" 254 stroke-linejoin="round" 255 class="flex-shrink-0 shrink-0" 256 ><circle cx="11" cy="11" r="7"/><path d="m20 20-3.5-3.5"/></svg> 257 258 <span class="flex-1 truncate text-sm text-left">Search races<span class="hidden xl:inline">, towns</span>â¦</span> 259 260 <kbd 261 x-text="navigator.platform?.toUpperCase().includes('MAC') ? 'âK' : 'Ctrl K'" 262 class="hidden xl:inline-block font-mono text-[11px] px-1.5 py-0.5 bg-surface border border-rule rounded text-ink-2 font-semibold shadow-[0_1px_0_var(--rule)]" 263 >âK</kbd> 264 </button> 265 266 267 <div class="flex shrink-0 items-center gap-1"> 268 269 270 <a 271 href="https://runningcalendar.co.za/ad-free" 272 title="Remove ads for R29/month" 273 class="hidden 2xl:inline-flex items-center gap-1.5 py-1.5 pr-3 pl-2.5 rounded-full border border-amber-300 text-amber-800 text-xs font-semibold whitespace-nowrap transition hover:brightness-95" 274 style="background:linear-gradient(180deg,#FFFBEB 0%,#FEF3C7 100%)" 275 > 276 <span class="w-1.5 h-1.5 bg-amber-400 rounded-full" style="box-shadow:0 0 0 3px rgba(245,158,11,.18)"></span> 277 Ad-free <b class="font-bold">R29</b> 278 </a> 279 280 281 <div class="w-px h-[22px] bg-rule mx-0.5"></div> 282 283 284 <ui-dropdown position="bottom end" x-data="" data-flux-dropdown> 285 <button 286 type="button" 287 aria-label="Theme" 288 title="Theme" 289 class="inline-flex items-center justify-center w-10 h-10 rounded-lg text-ink-2 border border-transparent transition hover:bg-soft hover:border-rule cursor-pointer" 290 > 291 <svg 292 width="20" 293 height="20"
294 viewBox="0 0 24 24" 295 fill="none" 296 stroke="currentColor" 297 stroke-width="1.8" 298 stroke-linecap="round" 299 stroke-linejoin="round" 300 class="flex-shrink-0" x-show="!$flux.dark" 301 ><circle cx="12" cy="12" r="4"/><path d="M12 2v2"/><path d="M12 20v2"/><path d="m4.93 4.93 1.41 1.41"/><path d="m17.66 17.66 1.41 1.41"/><path d="M2 12h2"/><path d="M20 12h2"/><path d="m6.34 17.66-1.41 1.41"/><path d="m19.07 4.93-1.41 1.41"/></svg> 302 <svg 303 width="20" 304 height="20" 305 viewBox="0 0 24 24" 306 fill="none" 307 stroke="currentColor" 308 stroke-width="1.8" 309 stroke-linecap="round" 310 stroke-linejoin="round" 311 class="flex-shrink-0" x-show="$flux.dark" x-cloak="x-cloak" 312 ><path d="M12 3a6 6 0 0 0 9 9 9 9 0 1 1-9-9Z"/></svg> 313 </button> 314 <ui-menu 315 class="[:where(&)]:min-w-48 p-[.3125rem] rounded-lg shadow-xs border border-zinc-200 dark:border-zinc-600 bg-white dark:bg-zinc-700 focus:outline-hidden" 316 popover="manual" 317 data-flux-menu 318> 319 <button type="button" class="flex items-center px-2 py-1.5 w-full focus:outline-hidden select-none rounded-md text-start text-sm font-medium [&[disabled]]:opacity-50 text-zinc-800 data-active:bg-zinc-50 dark:text-white dark:data-active:bg-zinc-600 **:data-flux-menu-item-icon:text-zinc-400 dark:**:data-flux-menu-item-icon:text-white/60 [&[data-active]_[data-flux-menu-item-icon]]:text-current" data-flux-menu-item="data-flux-menu-item" data-flux-menu-item-has-icon="data-flux-menu-item-has-icon" x-on:click="$flux.appearance = 'light'"> 320 <svg class="shrink-0 [:where(&)]:size-5 me-2" data-flux-menu-item-icon="data-flux-menu-item-icon" data-flux-icon xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor" aria-hidden="true" data-slot="icon"> 321 <path d="M10 2a.75.75 0 0 1 .75.75v1.5a.75.75 0 0 1-1.5 0v-1.5A.75.75 0 0 1 10 2ZM10 15a.75.75 0 0 1 .75.75v1.5a.75.75 0 0 1-1.5 0v-1.5A.75.75 0 0 1 10 15ZM10 7a3 3 0 1 0 0 6 3 3 0 0 0 0-6ZM15.657 5.404a.75.75 0 1 0-1.06-1.06l-1.061 1.06a.75.75 0 0 0 1.06 1.06l1.06-1.06ZM6.464 14.596a.75.75 0 1 0-1.06-1.06l-1.06 1.06a.75.75 0 0 0 1.06 1.06l1.06-1.06ZM18 10a.75.75 0 0 1-.75.75h-1.5a.75.75 0 0 1 0-1.5h1.5A.75.75 0 0 1 18 10ZM5 10a.75.75 0 0 1-.75.75h-1.5a.75.75 0 0 1 0-1.5h1.5A.75.75 0 0 1 5 10ZM14.596 15.657a.75.75 0 0 0 1.06-1.06l-1.06-1.061a.75.75 0 1 0-1.06 1.06l1.06 1.06ZM5.404 6.464a.75.75 0 0 0 1.06-1.06l-1.06-1.06a.75.75 0 1 0-1.061 1.06l1.06 1.06Z"/> 322</svg> 323 324 325 Light 326 </button> 327 <button type="button" class="flex items-center px-2 py-1.5 w-full focus:outline-hidden select-none rounded-md text-start text-sm font-medium [&[disabled]]:opacity-50 text-zinc-800 data-active:bg-zinc-50 dark:text-white dark:data-active:bg-zinc-600 **:data-flux-menu-item-icon:text-zinc-400 dark:**:data-flux-menu-item-icon:text-white/60 [&[data-active]_[data-flux-menu-item-icon]]:text-current" data-flux-menu-item="data-flux-menu-item" data-flux-menu-item-has-icon="data-flux-menu-item-has-icon" x-on:click="$flux.appearance = 'system'"> 328 <svg class="shrink-0 [:where(&)]:size-5 me-2" data-flux-menu-item-icon="data-flux-menu-item-icon" data-flux-icon xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor" aria-hidden="true" data-slot="icon"> 329 <path fill-rule="evenodd" d="M2 4.25A2.25 2.25 0 0 1 4.25 2h11.5A2.25 2.25 0 0 1 18 4.25v8.5A2.25 2.25 0 0 1 15.75 15h-3.105a3.501 3.501 0 0 0 1.1 1.677A.75.75 0 0 1 13.26 18H6.74a.75.75 0 0 1-.484-1.323A3.501 3.501 0 0 0 7.355 15H4.25A2.25 2.25 0 0 1 2 12.75v-8.5Zm1.5 0a.75.75 0 0 1 .75-.75h11.5a.75.75 0 0 1 .75.75v7.5a.75.75 0 0 1-.75.75H4.25a.75.75 0 0 1-.75-.75v-7.5Z" clip-rule="evenodd"/> 330</svg> 331 332 333 System 334 </button> 335 <button type="button" class="flex items-center px-2 py-1.5 w-full focus:outline-hidden select-none rounded-md text-start text-sm font-medium [&[disabled]]:opacity-50 text-zinc-800 data-active:bg-zinc-50 dark:text-white dark:data-active:bg-zinc-600 **:data-flux-menu-item-icon:text-zinc-400 dark:**:data-flux-menu-item-icon:text-white/60 [&[data-active]_[data-flux-menu-item-icon]]:text-current" data-flux-menu-item="data-flux-menu-item" data-flux-menu-item-has-icon="data-flux-menu-item-has-icon" x-on:click="$flux.appearance = 'dark'"> 336 <svg class="shrink-0 [:where(&)]:size-5 me-2" data-flux-menu-item-icon="data-flux-menu-item-icon" data-flux-icon xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor" aria-hidden="true" data-slot="icon"> 337 <path fill-rule="evenodd" d="M7.455 2.004a.75.75 0 0 1 .26.77 7 7 0 0 0 9.958 7.967.75.75 0 0 1 1.067.853A8.5 8.5 0 1 1 6.647 1.921a.75.75 0 0 1 .808.083Z" clip-rule="evenodd"/> 338</svg> 339 340 341 Dark 342 </button> 343</ui-menu> 344</ui-dropdown> 345 346
347 <div wire:snapshot="{"data":{"iconOnly":true},"memo":{"id":"H90TFiqQ1IKuhXqUof0i","name":"locale-selector","path":"contact","method":"GET","release":"a-a-a","children":[],"scripts":[],"assets":[],"errors":[],"locale":"en"},"checksum":"9bec9bac240fe6a2a8096c82514f6916d9486c1441c8c0af491741fc04a73601"}" wire:effects="{"partials":[]}" wire:id="H90TFiqQ1IKuhXqUof0i" 348 x-data="geoSelector(JSON.parse('{\u0022tree\u0022:{\u0022resetLabel\u0022:\u0022All of Southern Africa\u0022,\u0022total\u0022:500,\u0022countries\u0022:[{\u0022code\u0022:\u0022ZA\u0022,\u0022name\u0022:\u0022South Africa\u0022,\u0022count\u0022:492,\u0022provinces\u0022:[{\u0022slug\u0022:\u0022western-cape\u0022,\u0022code\u0022:\u0022WC\u0022,\u0022name\u0022:\u0022Western Cape\u0022,\u0022count\u0022:125,\u0022cities\u0022:[{\u0022name\u0022:\u0022Cape Town\u0022,\u0022slug\u0022:\u0022cape-town\u0022,\u0022count\u0022:84},{\u0022name\u0022:\u0022George\u0022,\u0022slug\u0022:\u0022george\u0022,\u0022count\u0022:41}]},{\u0022slug\u0022:\u0022gauteng\u0022,\u0022code\u0022:\u0022GP\u0022,\u0022name\u0022:\u0022Gauteng\u0022,\u0022count\u0022:99,\u0022cities\u0022:[{\u0022name\u0022:\u0022Johannesburg\u0022,\u0022slug\u0022:\u0022johannesburg\u0022,\u0022count\u0022:78},{\u0022name\u0022:\u0022Pretoria\u0022,\u0022slug\u0022:\u0022pretoria\u0022,\u0022count\u0022:52}]},{\u0022slug\u0022:\u0022kwazulu-natal\u0022,\u0022code\u0022:\u0022KZN\u0022,\u0022name\u0022:\u0022KwaZulu-Natal\u0022,\u0022count\u0022:50,\u0022cities\u0022:[{\u0022name\u0022:\u0022Durban\u0022,\u0022slug\u0022:\u0022durban\u0022,\u0022count\u0022:38},{\u0022name\u0022:\u0022Pietermaritzburg\u0022,\u0022slug\u0022:\u0022pietermaritzburg\u0022,\u0022count\u0022:12}]},{\u0022slug\u0022:\u0022eastern-cape\u0022,\u0022code\u0022:\u0022EC\u0022,\u0022name\u0022:\u0022Eastern Cape\u0022,\u0022count\u0022:75,\u0022cities\u0022:[{\u0022name\u0022:\u0022Gqeberha\u0022,\u0022slug\u0022:\u0022gqeberha\u0022,\u0022count\u0022:38},{\u0022name\u0022:\u0022East London\u0022,\u0022slug\u0022:\u0022east-london\u0022,\u0022count\u0022:22},{\u0022name\u0022:\u0022Mthatha\u0022,\u0022slug\u0022:\u0022mthatha\u0022,\u0022count\u0022:15}]},{\u0022slug\u0022:\u0022free-state\u0022,\u0022code\u0022:\u0022FS\u0022,\u0022name\u0022:\u0022Free State\u0022,\u0022count\u0022:28,\u0022soleCity\u0022:\u0022Bloemfontein\u0022},{\u0022slug\u0022:\u0022limpopo\u0022,\u0022code\u0022:\u0022LP\u0022,\u0022name\u0022:\u0022Limpopo\u0022,\u0022count\u0022:43,\u0022cities\u0022:[{\u0022name\u0022:\u0022Polokwane\u0022,\u0022slug\u0022:\u0022polokwane\u0022,\u0022count\u0022:39},{\u0022name\u0022:\u0022Rustenburg\u0022,\u0022slug\u0022:\u0022rustenburg\u0022,\u0022count\u0022:10}]},{\u0022slug\u0022:\u0022mpumalanga\u0022,\u0022code\u0022:\u0022MP\u0022,\u0022name\u0022:\u0022Mpumalanga\u0022,\u0022count\u0022:43,\u0022soleCity\u0022:\u0022Mbombela\u0022},{\u0022slug\u0022:\u0022north-west\u0022,\u0022code\u0022:\u0022NW\u0022,\u0022name\u0022:\u0022North West\u0022,\u0022count\u0022:11},{\u0022slug\u0022:\u0022northern-cape\u0022,\u0022code\u0022:\u0022NC\u0022,\u0022name\u0022:\u0022Northern Cape\u0022,\u0022count\u0022:13,\u0022cities\u0022:[{\u0022name\u0022:\u0022Kimberley\u0022,\u0022slug\u0022:\u0022kimberley\u0022,\u0022count\u0022:7},{\u0022name\u0022:\u0022Upington\u0022,\u0022slug\u0022:\u0022upington\u0022,\u0022count\u0022:6}]}]},{\u0022code\u0022:\u0022LS\u0022,\u0022name\u0022:\u0022Lesotho\u0022,\u0022count\u0022:3},{\u0022code\u0022:\u0022NA\u0022,\u0022name\u0022:\u0022Namibia\u0022,\u0022count\u0022:1},{\u0022code\u0022:\u0022BW\u0022,\u0022name\u0022:\u0022Botswana\u0022,\u0022count\u0022:3},{\u0022code\u0022:\u0022SZ\u0022,\u0022name\u0022:\u0022eSwatini\u0022,\u0022count\u0022:1},{\u0022code\u0022:\u0022ZW\u0022,\u0022name\u0022:\u0022Zimbabwe\u0022,\u0022count\u0022:0}]},\u0022sel\u0022:{\u0022country\u0022:null,\u0022province\u0022:null,\u0022city\u0022:null}}'))" 349 @keydown.escape.window="closePanel()" 350 @click.outside="closePanel()" 351 class="relative" 352> 353 354 355 356 357 <div class="flex items-center gap-0.5"> 358 359 <!--[if BLOCK]><![endif]--> 360 <button 361 x-ref="pill" 362 type="button"
363 @click="openPanel()" 364 :aria-expanded="open ? 'true' : 'false'" 365 aria-haspopup="dialog" 366 title="All of Southern Africa" 367 aria-label="Location filter: All of Southern Africa" 368 class="inline-flex items-center justify-center w-10 h-10 rounded-lg border border-transparent transition cursor-pointer hover:bg-soft hover:border-rule focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[--brand-deep]" 369 > 370 <!--[if BLOCK]><![endif]--> <!--[if BLOCK]><![endif]--> <svg 371 width="20" 372 height="20" 373 viewBox="0 0 24 24" 374 fill="none" 375 stroke="currentColor" 376 stroke-width="1.8" 377 stroke-linecap="round" 378 stroke-linejoin="round" 379 class="flex-shrink-0 text-ink-2" 380 ><circle cx="12" cy="12" r="10"/><path d="M12 2a14.5 14.5 0 0 0 0 20 14.5 14.5 0 0 0 0-20"/><path d="M2 12h20"/></svg> 381<!--[if ENDBLOCK]><![endif]--> <!--[if ENDBLOCK]><![endif]--> </button> 382 <!--[if ENDBLOCK]><![endif]--> 383 </div> 384 385 386 387 388 389 <div 390 x-cloak 391 x-show="open && isDesktop" 392 x-transition:enter="transition ease-out duration-[150ms]" 393 x-transition:enter-start="opacity-0 scale-95 -translate-y-0.5" 394 x-transition:enter-end="opacity-100 scale-100 translate-y-0" 395 x-transition:leave="transition ease-in duration-100" 396 x-transition:leave-start="opacity-100 scale-100" 397 x-transition:leave-end="opacity-0 scale-95" 398 class="absolute top-full mt-2 w-[348px] z-50 rounded-xl border overflow-hidden right-0" 399 style="background:var(--surface);border-color:var(--geo-edge);box-shadow:0 0 0 1px var(--geo-ring), 0 18px 44px var(--geo-shadow)" 400 role="dialog" 401 aria-modal="false" 402 aria-label="Location filter" 403 > 404 <div class="flex items-center min-h-12 px-3.5 border-b shrink-0 gap-2" style="border-color:var(--rule-soft)"> 405 406 407 <span 408 x-show="view.level === 'root'" 409 class="text-sm font-medium" 410 style="color:var(--ink-2)" 411 > 412 Southern Africa 413 </span> 414 415 416 <div x-show="view.level !== 'root'" class="flex items-center gap-2 w-full min-w-0"> 417 418 <button 419 type="button" 420 data-geo-item 421 @click="back()" 422 @keydown.arrow-down.prevent="focusNext()" 423 @keydown.arrow-up.prevent="focusPrev()" 424 class="flex items-center gap-1 text-sm font-medium shrink-0 rounded-md px-1 py-1 -ml-1 transition focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[--brand-deep]" 425 style="color:var(--muted)" 426 > 427 <!--[if BLOCK]><![endif]--> <svg 428 width="15" 429 height="15"
430 viewBox="0 0 24 24" 431 fill="none" 432 stroke="currentColor" 433 stroke-width="1.8" 434 stroke-linecap="round" 435 stroke-linejoin="round" 436 class="flex-shrink-0 shrink-0" 437 ><polyline points="15 18 9 12 15 6"/></svg> 438<!--[if ENDBLOCK]><![endif]--> Back 439 </button> 440 441 <nav aria-label="Location breadcrumb" class="flex items-center gap-1 text-xs overflow-hidden min-w-0"> 442 <button type="button" 443 @click="view = { level: 'root', code: null, prov: null }; dir = -1" 444 class="hover:underline transition truncate focus-visible:outline-none" 445 style="color:var(--muted)" 446 >Southern Africa</button> 447 448 <span x-show="view.level === 'country' || view.level === 'province'" style="color:var(--muted)">âº</span> 449 450 <button 451 type="button" 452 x-show="view.level === 'province'" 453 @click="drillCountry('ZA'); dir = -1" 454 class="hover:underline transition truncate focus-visible:outline-none" 455 style="color:var(--muted)" 456 >South Africa</button> 457 458 <span x-show="view.level === 'province'" style="color:var(--muted)">âº</span> 459 460 <span 461 x-show="view.level === 'country'" 462 class="font-semibold truncate" 463 style="color:var(--ink)" 464 >South Africa</span> 465 466 <span 467 x-show="view.level === 'province'" 468 class="font-semibold truncate" 469 x-text="currentProvinceNode?.name || ''" 470 style="color:var(--ink)" 471 ></span> 472 </nav> 473 474 <!--[if BLOCK]><![endif]--><!--[if ENDBLOCK]><![endif]--> </div> 475 476 <!--[if BLOCK]><![endif]--><!--[if ENDBLOCK]><![endif]--> 477</div> 478 479 480 481<div 482 class="overflow-y-auto overscroll-contain " 483 style="max-height:432px" 484 @keydown.arrow-down.prevent="focusNext()" 485 @keydown.arrow-up.prevent="focusPrev()" 486 @keydown.home.prevent="focusFirst()" 487 @keydown.end.prevent="focusLast()" 488> 489 490 491 <div 492 x-show="view.level === 'root'" 493 :class="view.level === 'root' ? levelContentClass : ''" 494 > 495 496 <div class="px-2 pt-2 pb-0"> 497 <button 498 type="button" 499 data-geo-item 500 @click="commitSel(null, null, null)" 501 class="w-full flex items-center gap-[11px] px-3 rounded-lg text-left transition min-h-[44px] focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[--brand-deep]" 502 :class="!sel.country ? 'bg-[--brand-soft]' : 'hover:bg-[--soft]'" 503 > 504 505 <span class="inline-flex items-center justify-center w-[30px] h-[30px] rounded-full shrink-0" style="background:var(--soft-2);color:var(--muted)"> 506 <!--[if BLOCK]><![endif]--> <svg 507 width="15" 508 height="15"
509 viewBox="0 0 24 24" 510 fill="none" 511 stroke="currentColor" 512 stroke-width="1.8" 513 stroke-linecap="round" 514 stroke-linejoin="round" 515 class="flex-shrink-0" 516 ><circle cx="12" cy="12" r="10"/><path d="M12 2a14.5 14.5 0 0 0 0 20 14.5 14.5 0 0 0 0-20"/><path d="M2 12h20"/></svg> 517<!--[if ENDBLOCK]><![endif]--> </span> 518 519 <span class="flex-1 text-[14.5px] font-[500] leading-tight" :class="!sel.country ? 'font-[600]' : ''" style="color:var(--ink)"> 520 All of Southern Africa 521 </span> 522 523 <span class="ml-auto text-[12.5px] tabular-nums shrink-0" style="font-family:var(--font-mono);color:var(--muted)"> 524 500 525 </span> 526 527 <span class="shrink-0 w-4 h-4" :class="!sel.country ? 'opacity-100' : 'opacity-0'"> 528 <!--[if BLOCK]><![endif]--> <svg 529 width="17" 530 height="17" 531 viewBox="0 0 24 24" 532 fill="none" 533 stroke="currentColor" 534 stroke-width="2.4" 535 stroke-linecap="round" 536 stroke-linejoin="round" 537 style="color:var(--brand)" class="flex-shrink-0" 538 ><polyline points="20 6 9 17 4 12"/></svg> 539<!--[if ENDBLOCK]><![endif]--> </span> 540 </button> 541 </div> 542 543 544 <p class="px-3.5 pt-3 pb-1.5 text-[10.5px] uppercase tracking-[0.1em] font-semibold" style="font-family:var(--font-mono);color:var(--muted)">Country</p> 545 546 547 <div class="px-2 pb-2"> 548 <template x-for="c in tree.countries" :key="c.code"> 549 <button 550 type="button" 551 data-geo-item 552 @click="c.code === 'ZA' ? drillCountry(c.code) : commitSel(c.code, null, null)" 553 class="w-full flex items-center gap-[11px] px-3 rounded-lg text-left transition min-h-[44px] focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[--brand-deep]" 554 :class="sel.country === c.code && c.code !== 'ZA' ? 'bg-[--brand-soft]' : 'hover:bg-[--soft]'" 555 > 556 557 <span 558 class="inline-flex items-center justify-center w-[30px] h-[30px] rounded-[6px] text-[11px] font-semibold shrink-0" 559 style="font-family:var(--font-mono);background:var(--ink);color:var(--bg)" 560 x-text="c.code" 561 ></span> 562 563 <span 564 class="flex-1 text-[14.5px] font-[500] leading-tight" 565 :class="sel.country === c.code && c.code !== 'ZA' ? 'font-[600]' : ''" 566 style="color:var(--ink)" 567 x-text="c.name" 568 ></span> 569 570 <span class="ml-auto text-[12.5px] tabular-nums shrink-0" style="font-family:var(--font-mono);color:var(--muted)" x-text="c.count"></span> 571 572 573 <span class="shrink-0 w-4 h-4 flex items-center justify-center" style="color:var(--muted)"> 574 <template x-if="c.code === 'ZA'"> 575 <!--[if BLOCK]><![endif]--> <svg 576 width="16" 577 height="16"
578 viewBox="0 0 24 24" 579 fill="none" 580 stroke="currentColor" 581 stroke-width="1.8" 582 stroke-linecap="round" 583 stroke-linejoin="round" 584 class="flex-shrink-0" 585 ><polyline points="9 18 15 12 9 6"/></svg> 586<!--[if ENDBLOCK]><![endif]--> </template> 587 <template x-if="c.code !== 'ZA' && sel.country === c.code"> 588 <!--[if BLOCK]><![endif]--> <svg 589 width="17" 590 height="17" 591 viewBox="0 0 24 24" 592 fill="none" 593 stroke="currentColor" 594 stroke-width="2.4" 595 stroke-linecap="round" 596 stroke-linejoin="round" 597 style="color:var(--brand)" class="flex-shrink-0" 598 ><polyline points="20 6 9 17 4 12"/></svg> 599<!--[if ENDBLOCK]><![endif]--> </template> 600 </span> 601 </button> 602 </template> 603 </div> 604 </div> 605 606 607 608 <div 609 x-show="view.level === 'country'" 610 :class="view.level === 'country' ? levelContentClass : ''" 611 > 612 613 <div class="px-2 pt-2 pb-0"> 614 <button 615 type="button" 616 data-geo-item 617 @click="commitSel('ZA', null, null)" 618 class="w-full flex items-center gap-[11px] px-3 rounded-lg text-left transition min-h-[44px] focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[--brand-deep]" 619 :class="sel.country === 'ZA' && !sel.province ? 'bg-[--brand-soft]' : 'hover:bg-[--soft]'" 620 > 621 <span class="inline-flex items-center justify-center w-[30px] h-[30px] rounded-full shrink-0" style="background:var(--soft-2);color:var(--muted)"> 622 <!--[if BLOCK]><![endif]--> <svg 623 width="15" 624 height="15"
625 viewBox="0 0 24 24" 626 fill="none" 627 stroke="currentColor" 628 stroke-width="1.8" 629 stroke-linecap="round" 630 stroke-linejoin="round" 631 class="flex-shrink-0" 632 ><circle cx="12" cy="12" r="10"/><path d="M12 2a14.5 14.5 0 0 0 0 20 14.5 14.5 0 0 0 0-20"/><path d="M2 12h20"/></svg> 633<!--[if ENDBLOCK]><![endif]--> </span> 634 <span 635 class="flex-1 text-[14.5px] font-[500] leading-tight" 636 :class="sel.country === 'ZA' && !sel.province ? 'font-[600]' : ''" 637 style="color:var(--ink)" 638 >All of South Africa</span> 639 <span class="ml-auto text-[12.5px] tabular-nums shrink-0" style="font-family:var(--font-mono);color:var(--muted)" x-text="currentCountryNode?.count"></span> 640 <span class="shrink-0 w-4 h-4" :class="sel.country === 'ZA' && !sel.province ? 'opacity-100' : 'opacity-0'"> 641 <!--[if BLOCK]><![endif]--> <svg 642 width="17" 643 height="17"
644 viewBox="0 0 24 24" 645 fill="none" 646 stroke="currentColor" 647 stroke-width="2.4" 648 stroke-linecap="round" 649 stroke-linejoin="round" 650 style="color:var(--brand)" class="flex-shrink-0" 651 ><polyline points="20 6 9 17 4 12"/></svg> 652<!--[if ENDBLOCK]><![endif]--> </span> 653 </button> 654 </div> 655 656 <p class="px-3.5 pt-3 pb-1.5 text-[10.5px] uppercase tracking-[0.1em] font-semibold" style="font-family:var(--font-mono);color:var(--muted)">Province</p> 657 658 <div class="px-2 pb-2"> 659 <template x-for="p in (currentCountryNode?.provinces || [])" :key="p.slug"> 660 <button 661 type="button" 662 data-geo-item 663 @click="_provCityCount(p) > 1 ? drillProvince(p.slug) : commitSel('ZA', p.slug, null)" 664 class="w-full flex items-center gap-[11px] px-3 rounded-lg text-left transition min-h-[44px] focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[--brand-deep]" 665 :class="sel.province === p.slug && _provCityCount(p) <= 1 ? 'bg-[--brand-soft]' : 'hover:bg-[--soft]'" 666 > 667 668 <span 669 class="inline-flex items-center justify-center w-[30px] h-[30px] rounded-[6px] text-[11px] font-semibold shrink-0 border" 670 style="font-family:var(--font-mono);background:var(--brand-soft);color:var(--brand-deeper);border-color:var(--brand-line)" 671 x-text="p.code || p.slug.slice(0,2).toUpperCase()" 672 ></span> 673 674 <span class="flex-1 min-w-0"> 675 <span 676 class="block text-[14.5px] font-[500] leading-tight truncate" 677 :class="sel.province === p.slug ? 'font-[600]' : ''" 678 style="color:var(--ink)" 679 x-text="p.name" 680 ></span> 681 <small 682 x-show="p.soleCity" 683 class="block text-xs leading-tight truncate" 684 style="color:var(--muted)" 685 x-text="p.soleCity" 686 ></small> 687 </span> 688 689 <span class="ml-auto text-[12.5px] tabular-nums shrink-0" style="font-family:var(--font-mono);color:var(--muted)" x-text="p.count"></span> 690 691 <span class="shrink-0 w-4 h-4 flex items-center justify-center" style="color:var(--muted)"> 692 <template x-if="_provCityCount(p) > 1"> 693 <!--[if BLOCK]><![endif]--> <svg 694 width="16" 695 height="16"
696 viewBox="0 0 24 24" 697 fill="none" 698 stroke="currentColor" 699 stroke-width="1.8" 700 stroke-linecap="round" 701 stroke-linejoin="round" 702 class="flex-shrink-0" 703 ><polyline points="9 18 15 12 9 6"/></svg> 704<!--[if ENDBLOCK]><![endif]--> </template> 705 <template x-if="_provCityCount(p) <= 1 && sel.province === p.slug"> 706 <!--[if BLOCK]><![endif]--> <svg 707 width="17" 708 height="17" 709 viewBox="0 0 24 24" 710 fill="none" 711 stroke="currentColor" 712 stroke-width="2.4" 713 stroke-linecap="round" 714 stroke-linejoin="round" 715 style="color:var(--brand)" class="flex-shrink-0" 716 ><polyline points="20 6 9 17 4 12"/></svg> 717<!--[if ENDBLOCK]><![endif]--> </template> 718 </span> 719 </button> 720 </template> 721 </div> 722 </div> 723 724 725 726 <div 727 x-show="view.level === 'province'" 728 :class="view.level === 'province' ? levelContentClass : ''" 729 > 730 731 <div class="px-2 pt-2 pb-0"> 732 <button 733 type="button" 734 data-geo-item 735 @click="commitSel('ZA', view.prov, null)" 736 class="w-full flex items-center gap-[11px] px-3 rounded-lg text-left transition min-h-[44px] focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[--brand-deep]" 737 :class="sel.province === view.prov && !sel.city ? 'bg-[--brand-soft]' : 'hover:bg-[--soft]'" 738 > 739 <span class="inline-flex items-center justify-center w-[30px] h-[30px] rounded-full shrink-0" style="background:var(--soft-2);color:var(--muted)"> 740 <!--[if BLOCK]><![endif]--> <svg 741 width="15" 742 height="15"
743 viewBox="0 0 24 24" 744 fill="none" 745 stroke="currentColor" 746 stroke-width="1.8" 747 stroke-linecap="round" 748 stroke-linejoin="round" 749 class="flex-shrink-0" 750 ><circle cx="12" cy="12" r="10"/><path d="M12 2a14.5 14.5 0 0 0 0 20 14.5 14.5 0 0 0 0-20"/><path d="M2 12h20"/></svg> 751<!--[if ENDBLOCK]><![endif]--> </span> 752 <span 753 class="flex-1 text-[14.5px] font-[500] leading-tight" 754 :class="sel.province === view.prov && !sel.city ? 'font-[600]' : ''" 755 style="color:var(--ink)" 756 >All of <span x-text="currentProvinceNode?.name || ''"></span></span> 757 <span class="ml-auto text-[12.5px] tabular-nums shrink-0" style="font-family:var(--font-mono);color:var(--muted)" x-text="currentProvinceNode?.count"></span> 758 <span class="shrink-0 w-4 h-4" :class="sel.province === view.prov && !sel.city ? 'opacity-100' : 'opacity-0'"> 759 <!--[if BLOCK]><![endif]--> <svg 760 width="17" 761 height="17"
762 viewBox="0 0 24 24" 763 fill="none" 764 stroke="currentColor" 765 stroke-width="2.4" 766 stroke-linecap="round" 767 stroke-linejoin="round" 768 style="color:var(--brand)" class="flex-shrink-0" 769 ><polyline points="20 6 9 17 4 12"/></svg> 770<!--[if ENDBLOCK]><![endif]--> </span> 771 </button> 772 </div> 773 774 <p class="px-3.5 pt-3 pb-1.5 text-[10.5px] uppercase tracking-[0.1em] font-semibold" style="font-family:var(--font-mono);color:var(--muted)">City</p> 775 776 <div class="px-2 pb-2"> 777 <template x-for="ci in (currentProvinceNode?.cities || [])" :key="ci.slug"> 778 <button 779 type="button" 780 data-geo-item 781 @click="commitSel('ZA', view.prov, ci.slug)" 782 class="w-full flex items-center gap-[11px] px-3 rounded-lg text-left transition min-h-[44px] focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[--brand-deep]" 783 :class="sel.city === ci.slug ? 'bg-[--brand-soft]' : 'hover:bg-[--soft]'" 784 > 785 786 <span class="inline-flex items-center justify-center w-[30px] h-[30px] rounded-full shrink-0" style="background:var(--soft-2);color:var(--muted)"> 787 <!--[if BLOCK]><![endif]--> <svg 788 width="14" 789 height="14"
790 viewBox="0 0 24 24" 791 fill="none" 792 stroke="currentColor" 793 stroke-width="1.8" 794 stroke-linecap="round" 795 stroke-linejoin="round" 796 class="flex-shrink-0" 797 ><path d="M20 10c0 4.993-5.539 10.193-7.399 11.799a1 1 0 0 1-1.202 0C9.539 20.193 4 14.993 4 10a8 8 0 0 1 16 0"/><circle cx="12" cy="10" r="3"/></svg> 798<!--[if ENDBLOCK]><![endif]--> </span> 799 800 <span 801 class="flex-1 text-[14.5px] font-[500] leading-tight" 802 :class="sel.city === ci.slug ? 'font-[600]' : ''" 803 style="color:var(--ink)" 804 x-text="ci.name" 805 ></span> 806 807 <span class="ml-auto text-[12.5px] tabular-nums shrink-0" style="font-family:var(--font-mono);color:var(--muted)" x-text="ci.count"></span> 808 809 <span class="shrink-0 w-4 h-4" :class="sel.city === ci.slug ? 'opacity-100' : 'opacity-0'"> 810 <!--[if BLOCK]><![endif]--> <svg 811 width="17" 812 height="17"
813 viewBox="0 0 24 24" 814 fill="none" 815 stroke="currentColor" 816 stroke-width="2.4" 817 stroke-linecap="round" 818 stroke-linejoin="round" 819 style="color:var(--brand)" class="flex-shrink-0" 820 ><polyline points="20 6 9 17 4 12"/></svg> 821<!--[if ENDBLOCK]><![endif]--> </span> 822 </button> 823 </template> 824 </div> 825 </div> 826 827</div> </div> 828 829 830 831 832 833 <div 834 x-cloak 835 x-show="open && !isDesktop" 836 @click="closePanel()" 837 x-transition:enter="transition-opacity duration-200" 838 x-transition:enter-start="opacity-0" 839 x-transition:enter-end="opacity-100" 840 x-transition:leave="transition-opacity duration-200" 841 x-transition:leave-start="opacity-100" 842 x-transition:leave-end="opacity-0" 843 class="fixed inset-0 z-[200]" 844 style="background:rgba(10,22,40,.45)" 845 aria-hidden="true" 846 ></div> 847 848 849 850 851 852 <div 853 x-cloak 854 x-show="open && !isDesktop" 855 x-transition:enter="transition-transform ease-[cubic-bezier(.2,.8,.25,1)] duration-[260ms] motion-reduce:duration-0" 856 x-transition:enter-start="translate-y-full" 857 x-transition:enter-end="translate-y-0" 858 x-transition:leave="transition-transform ease-in duration-200 motion-reduce:duration-0" 859 x-transition:leave-start="translate-y-0" 860 x-transition:leave-end="translate-y-full" 861 class="fixed inset-x-0 bottom-0 z-[201] flex flex-col overflow-hidden" 862 style="border-radius:18px 18px 0 0;background:var(--surface);max-height:86dvh" 863 role="dialog" 864 aria-modal="true" 865 aria-label="Location filter" 866 > 867 868 <div class="shrink-0 w-10 h-1 rounded-full mx-auto mt-2.5" style="background:var(--rule)"></div> 869 870 <div class="flex items-center min-h-12 px-3.5 border-b shrink-0 gap-2" style="border-color:var(--rule-soft)"> 871 872 873 <span 874 x-show="view.level === 'root'" 875 class="text-sm font-medium" 876 style="color:var(--ink-2)" 877 > 878 Southern Africa 879 </span> 880 881 882 <div x-show="view.level !== 'root'" class="flex items-center gap-2 w-full min-w-0"> 883 884 <button 885 type="button" 886 data-geo-item 887 @click="back()" 888 @keydown.arrow-down.prevent="focusNext()" 889 @keydown.arrow-up.prevent="focusPrev()" 890 class="flex items-center gap-1 text-sm font-medium shrink-0 rounded-md px-1 py-1 -ml-1 transition focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[--brand-deep]" 891 style="color:var(--muted)" 892 > 893 <!--[if BLOCK]><![endif]--> <svg 894 width="15" 895 height="15"
896 viewBox="0 0 24 24" 897 fill="none" 898 stroke="currentColor" 899 stroke-width="1.8" 900 stroke-linecap="round" 901 stroke-linejoin="round" 902 class="flex-shrink-0 shrink-0" 903 ><polyline points="15 18 9 12 15 6"/></svg> 904<!--[if ENDBLOCK]><![endif]--> Back 905 </button> 906 907 <nav aria-label="Location breadcrumb" class="flex items-center gap-1 text-xs overflow-hidden min-w-0"> 908 <button type="button" 909 @click="view = { level: 'root', code: null, prov: null }; dir = -1" 910 class="hover:underline transition truncate focus-visible:outline-none" 911 style="color:var(--muted)" 912 >Southern Africa</button> 913 914 <span x-show="view.level === 'country' || view.level === 'province'" style="color:var(--muted)">âº</span> 915 916 <button 917 type="button" 918 x-show="view.level === 'province'" 919 @click="drillCountry('ZA'); dir = -1" 920 class="hover:underline transition truncate focus-visible:outline-none" 921 style="color:var(--muted)" 922 >South Africa</button> 923 924 <span x-show="view.level === 'province'" style="color:var(--muted)">âº</span> 925 926 <span 927 x-show="view.level === 'country'" 928 class="font-semibold truncate" 929 style="color:var(--ink)" 930 >South Africa</span> 931 932 <span 933 x-show="view.level === 'province'" 934 class="font-semibold truncate" 935 x-text="currentProvinceNode?.name || ''" 936 style="color:var(--ink)" 937 ></span> 938 </nav> 939 940 <!--[if BLOCK]><![endif]--> 941 <button 942 type="button" 943 @click="closePanel()" 944 class="ml-auto shrink-0 w-[34px] h-[34px] rounded-full border flex items-center justify-center transition focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[--brand-deep]" 945 style="border-color:var(--rule);color:var(--muted)" 946 aria-label="Close" 947 > 948 <!--[if BLOCK]><![endif]--> <svg 949 width="17" 950 height="17"
951 viewBox="0 0 24 24" 952 fill="none" 953 stroke="currentColor" 954 stroke-width="1.8" 955 stroke-linecap="round" 956 stroke-linejoin="round" 957 class="flex-shrink-0" 958 ><line x1="18" x2="6" y1="6" y2="18"/><line x1="6" x2="18" y1="6" y2="18"/></svg> 959<!--[if ENDBLOCK]><![endif]--> </button> 960 <!--[if ENDBLOCK]><![endif]--> </div> 961 962 <!--[if BLOCK]><![endif]--> 963 <button 964 type="button" 965 x-show="view.level === 'root'" 966 @click="closePanel()" 967 class="ml-auto shrink-0 w-[34px] h-[34px] rounded-full border flex items-center justify-center transition focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[--brand-deep]" 968 style="border-color:var(--rule);color:var(--muted)" 969 aria-label="Close" 970 > 971 <!--[if BLOCK]><![endif]--> <svg 972 width="17" 973 height="17" 974 viewBox="0 0 24 24" 975 fill="none" 976 stroke="currentColor" 977 stroke-width="1.8" 978 stroke-linecap="round" 979 stroke-linejoin="round" 980 class="flex-shrink-0" 981 ><line x1="18" x2="6" y1="6" y2="18"/><line x1="6" x2="18" y1="6" y2="18"/></svg> 982<!--[if ENDBLOCK]><![endif]--> </button> 983 <!--[if ENDBLOCK]><![endif]--> 984</div> 985 986 987 988<div 989 class="overflow-y-auto overscroll-contain flex-1" 990 style="" 991 @keydown.arrow-down.prevent="focusNext()" 992 @keydown.arrow-up.prevent="focusPrev()" 993 @keydown.home.prevent="focusFirst()" 994 @keydown.end.prevent="focusLast()" 995> 996 997 998 <div 999 x-show="view.level === 'root'" 1000 :class="view.level === 'root' ? levelContentClass : ''" 1001 > 1002 1003 <div class="px-2 pt-2 pb-0"> 1004 <button 1005 type="button" 1006 data-geo-item 1007 @click="commitSel(null, null, null)" 1008 class="w-full flex items-center gap-[11px] px-3 rounded-lg text-left transition min-h-[44px] focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[--brand-deep]" 1009 :class="!sel.country ? 'bg-[--brand-soft]' : 'hover:bg-[--soft]'" 1010 > 1011 1012 <span class="inline-flex items-center justify-center w-[30px] h-[30px] rounded-full shrink-0" style="background:var(--soft-2);color:var(--muted)"> 1013 <!--[if BLOCK]><![endif]--> <svg 1014 width="15" 1015 height="15"
1016 viewBox="0 0 24 24" 1017 fill="none" 1018 stroke="currentColor" 1019 stroke-width="1.8" 1020 stroke-linecap="round" 1021 stroke-linejoin="round" 1022 class="flex-shrink-0" 1023 ><circle cx="12" cy="12" r="10"/><path d="M12 2a14.5 14.5 0 0 0 0 20 14.5 14.5 0 0 0 0-20"/><path d="M2 12h20"/></svg> 1024<!--[if ENDBLOCK]><![endif]--> </span> 1025 1026 <span class="flex-1 text-[14.5px] font-[500] leading-tight" :class="!sel.country ? 'font-[600]' : ''" style="color:var(--ink)"> 1027 All of Southern Africa 1028 </span> 1029 1030 <span class="ml-auto text-[12.5px] tabular-nums shrink-0" style="font-family:var(--font-mono);color:var(--muted)"> 1031 500 1032 </span> 1033 1034 <span class="shrink-0 w-4 h-4" :class="!sel.country ? 'opacity-100' : 'opacity-0'"> 1035 <!--[if BLOCK]><![endif]--> <svg 1036 width="17" 1037 height="17" 1038 viewBox="0 0 24 24" 1039 fill="none" 1040 stroke="currentColor" 1041 stroke-width="2.4" 1042 stroke-linecap="round" 1043 stroke-linejoin="round" 1044 style="color:var(--brand)" class="flex-shrink-0" 1045 ><polyline points="20 6 9 17 4 12"/></svg> 1046<!--[if ENDBLOCK]><![endif]--> </span> 1047 </button> 1048 </div> 1049 1050 1051 <p class="px-3.5 pt-3 pb-1.5 text-[10.5px] uppercase tracking-[0.1em] font-semibold" style="font-family:var(--font-mono);color:var(--muted)">Country</p> 1052 1053 1054 <div class="px-2 pb-2"> 1055 <template x-for="c in tree.countries" :key="c.code"> 1056 <button 1057 type="button" 1058 data-geo-item 1059 @click="c.code === 'ZA' ? drillCountry(c.code) : commitSel(c.code, null, null)" 1060 class="w-full flex items-center gap-[11px] px-3 rounded-lg text-left transition min-h-[44px] focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[--brand-deep]" 1061 :class="sel.country === c.code && c.code !== 'ZA' ? 'bg-[--brand-soft]' : 'hover:bg-[--soft]'" 1062 > 1063 1064 <span 1065 class="inline-flex items-center justify-center w-[30px] h-[30px] rounded-[6px] text-[11px] font-semibold shrink-0" 1066 style="font-family:var(--font-mono);background:var(--ink);color:var(--bg)" 1067 x-text="c.code" 1068 ></span> 1069 1070 <span 1071 class="flex-1 text-[14.5px] font-[500] leading-tight" 1072 :class="sel.country === c.code && c.code !== 'ZA' ? 'font-[600]' : ''" 1073 style="color:var(--ink)" 1074 x-text="c.name" 1075 ></span> 1076 1077 <span class="ml-auto text-[12.5px] tabular-nums shrink-0" style="font-family:var(--font-mono);color:var(--muted)" x-text="c.count"></span> 1078 1079 1080 <span class="shrink-0 w-4 h-4 flex items-center justify-center" style="color:var(--muted)"> 1081 <template x-if="c.code === 'ZA'"> 1082 <!--[if BLOCK]><![endif]--> <svg 1083 width="16" 1084 height="16"
1085 viewBox="0 0 24 24" 1086 fill="none" 1087 stroke="currentColor" 1088 stroke-width="1.8" 1089 stroke-linecap="round" 1090 stroke-linejoin="round" 1091 class="flex-shrink-0" 1092 ><polyline points="9 18 15 12 9 6"/></svg> 1093<!--[if ENDBLOCK]><![endif]--> </template> 1094 <template x-if="c.code !== 'ZA' && sel.country === c.code"> 1095 <!--[if BLOCK]><![endif]--> <svg 1096 width="17" 1097 height="17" 1098 viewBox="0 0 24 24" 1099 fill="none" 1100 stroke="currentColor" 1101 stroke-width="2.4" 1102 stroke-linecap="round" 1103 stroke-linejoin="round" 1104 style="color:var(--brand)" class="flex-shrink-0" 1105 ><polyline points="20 6 9 17 4 12"/></svg> 1106<!--[if ENDBLOCK]><![endif]--> </template> 1107 </span> 1108 </button> 1109 </template> 1110 </div> 1111 </div> 1112 1113 1114 1115 <div 1116 x-show="view.level === 'country'" 1117 :class="view.level === 'country' ? levelContentClass : ''" 1118 > 1119 1120 <div class="px-2 pt-2 pb-0"> 1121 <button 1122 type="button" 1123 data-geo-item 1124 @click="commitSel('ZA', null, null)" 1125 class="w-full flex items-center gap-[11px] px-3 rounded-lg text-left transition min-h-[44px] focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[--brand-deep]" 1126 :class="sel.country === 'ZA' && !sel.province ? 'bg-[--brand-soft]' : 'hover:bg-[--soft]'" 1127 > 1128 <span class="inline-flex items-center justify-center w-[30px] h-[30px] rounded-full shrink-0" style="background:var(--soft-2);color:var(--muted)"> 1129 <!--[if BLOCK]><![endif]--> <svg 1130 width="15" 1131 height="15"
1132 viewBox="0 0 24 24" 1133 fill="none" 1134 stroke="currentColor" 1135 stroke-width="1.8" 1136 stroke-linecap="round" 1137 stroke-linejoin="round" 1138 class="flex-shrink-0" 1139 ><circle cx="12" cy="12" r="10"/><path d="M12 2a14.5 14.5 0 0 0 0 20 14.5 14.5 0 0 0 0-20"/><path d="M2 12h20"/></svg> 1140<!--[if ENDBLOCK]><![endif]--> </span> 1141 <span 1142 class="flex-1 text-[14.5px] font-[500] leading-tight" 1143 :class="sel.country === 'ZA' && !sel.province ? 'font-[600]' : ''" 1144 style="color:var(--ink)" 1145 >All of South Africa</span> 1146 <span class="ml-auto text-[12.5px] tabular-nums shrink-0" style="font-family:var(--font-mono);color:var(--muted)" x-text="currentCountryNode?.count"></span> 1147 <span class="shrink-0 w-4 h-4" :class="sel.country === 'ZA' && !sel.province ? 'opacity-100' : 'opacity-0'"> 1148 <!--[if BLOCK]><![endif]--> <svg 1149 width="17" 1150 height="17"
1151 viewBox="0 0 24 24" 1152 fill="none" 1153 stroke="currentColor" 1154 stroke-width="2.4" 1155 stroke-linecap="round" 1156 stroke-linejoin="round" 1157 style="color:var(--brand)" class="flex-shrink-0" 1158 ><polyline points="20 6 9 17 4 12"/></svg> 1159<!--[if ENDBLOCK]><![endif]--> </span> 1160 </button> 1161 </div> 1162 1163 <p class="px-3.5 pt-3 pb-1.5 text-[10.5px] uppercase tracking-[0.1em] font-semibold" style="font-family:var(--font-mono);color:var(--muted)">Province</p> 1164 1165 <div class="px-2 pb-2"> 1166 <template x-for="p in (currentCountryNode?.provinces || [])" :key="p.slug"> 1167 <button 1168 type="button" 1169 data-geo-item 1170 @click="_provCityCount(p) > 1 ? drillProvince(p.slug) : commitSel('ZA', p.slug, null)" 1171 class="w-full flex items-center gap-[11px] px-3 rounded-lg text-left transition min-h-[44px] focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[--brand-deep]" 1172 :class="sel.province === p.slug && _provCityCount(p) <= 1 ? 'bg-[--brand-soft]' : 'hover:bg-[--soft]'" 1173 > 1174 1175 <span 1176 class="inline-flex items-center justify-center w-[30px] h-[30px] rounded-[6px] text-[11px] font-semibold shrink-0 border" 1177 style="font-family:var(--font-mono);background:var(--brand-soft);color:var(--brand-deeper);border-color:var(--brand-line)" 1178 x-text="p.code || p.slug.slice(0,2).toUpperCase()" 1179 ></span> 1180 1181 <span class="flex-1 min-w-0"> 1182 <span 1183 class="block text-[14.5px] font-[500] leading-tight truncate" 1184 :class="sel.province === p.slug ? 'font-[600]' : ''" 1185 style="color:var(--ink)" 1186 x-text="p.name" 1187 ></span> 1188 <small 1189 x-show="p.soleCity" 1190 class="block text-xs leading-tight truncate" 1191 style="color:var(--muted)" 1192 x-text="p.soleCity" 1193 ></small> 1194 </span> 1195 1196 <span class="ml-auto text-[12.5px] tabular-nums shrink-0" style="font-family:var(--font-mono);color:var(--muted)" x-text="p.count"></span> 1197 1198 <span class="shrink-0 w-4 h-4 flex items-center justify-center" style="color:var(--muted)"> 1199 <template x-if="_provCityCount(p) > 1"> 1200 <!--[if BLOCK]><![endif]--> <svg 1201 width="16" 1202 height="16"
1203 viewBox="0 0 24 24" 1204 fill="none" 1205 stroke="currentColor" 1206 stroke-width="1.8" 1207 stroke-linecap="round" 1208 stroke-linejoin="round" 1209 class="flex-shrink-0" 1210 ><polyline points="9 18 15 12 9 6"/></svg> 1211<!--[if ENDBLOCK]><![endif]--> </template> 1212 <template x-if="_provCityCount(p) <= 1 && sel.province === p.slug"> 1213 <!--[if BLOCK]><![endif]--> <svg 1214 width="17" 1215 height="17" 1216 viewBox="0 0 24 24" 1217 fill="none" 1218 stroke="currentColor" 1219 stroke-width="2.4" 1220 stroke-linecap="round" 1221 stroke-linejoin="round" 1222 style="color:var(--brand)" class="flex-shrink-0" 1223 ><polyline points="20 6 9 17 4 12"/></svg> 1224<!--[if ENDBLOCK]><![endif]--> </template> 1225 </span> 1226 </button> 1227 </template> 1228 </div> 1229 </div> 1230 1231 1232 1233 <div 1234 x-show="view.level === 'province'" 1235 :class="view.level === 'province' ? levelContentClass : ''" 1236 > 1237 1238 <div class="px-2 pt-2 pb-0"> 1239 <button 1240 type="button" 1241 data-geo-item 1242 @click="commitSel('ZA', view.prov, null)" 1243 class="w-full flex items-center gap-[11px] px-3 rounded-lg text-left transition min-h-[44px] focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[--brand-deep]" 1244 :class="sel.province === view.prov && !sel.city ? 'bg-[--brand-soft]' : 'hover:bg-[--soft]'" 1245 > 1246 <span class="inline-flex items-center justify-center w-[30px] h-[30px] rounded-full shrink-0" style="background:var(--soft-2);color:var(--muted)"> 1247 <!--[if BLOCK]><![endif]--> <svg 1248 width="15" 1249 height="15"
1250 viewBox="0 0 24 24" 1251 fill="none" 1252 stroke="currentColor" 1253 stroke-width="1.8" 1254 stroke-linecap="round" 1255 stroke-linejoin="round" 1256 class="flex-shrink-0" 1257 ><circle cx="12" cy="12" r="10"/><path d="M12 2a14.5 14.5 0 0 0 0 20 14.5 14.5 0 0 0 0-20"/><path d="M2 12h20"/></svg> 1258<!--[if ENDBLOCK]><![endif]--> </span> 1259 <span 1260 class="flex-1 text-[14.5px] font-[500] leading-tight" 1261 :class="sel.province === view.prov && !sel.city ? 'font-[600]' : ''" 1262 style="color:var(--ink)" 1263 >All of <span x-text="currentProvinceNode?.name || ''"></span></span> 1264 <span class="ml-auto text-[12.5px] tabular-nums shrink-0" style="font-family:var(--font-mono);color:var(--muted)" x-text="currentProvinceNode?.count"></span> 1265 <span class="shrink-0 w-4 h-4" :class="sel.province === view.prov && !sel.city ? 'opacity-100' : 'opacity-0'"> 1266 <!--[if BLOCK]><![endif]--> <svg 1267 width="17" 1268 height="17"
1269 viewBox="0 0 24 24" 1270 fill="none" 1271 stroke="currentColor" 1272 stroke-width="2.4" 1273 stroke-linecap="round" 1274 stroke-linejoin="round" 1275 style="color:var(--brand)" class="flex-shrink-0" 1276 ><polyline points="20 6 9 17 4 12"/></svg> 1277<!--[if ENDBLOCK]><![endif]--> </span> 1278 </button> 1279 </div> 1280 1281 <p class="px-3.5 pt-3 pb-1.5 text-[10.5px] uppercase tracking-[0.1em] font-semibold" style="font-family:var(--font-mono);color:var(--muted)">City</p> 1282 1283 <div class="px-2 pb-2"> 1284 <template x-for="ci in (currentProvinceNode?.cities || [])" :key="ci.slug"> 1285 <button 1286 type="button" 1287 data-geo-item 1288 @click="commitSel('ZA', view.prov, ci.slug)" 1289 class="w-full flex items-center gap-[11px] px-3 rounded-lg text-left transition min-h-[44px] focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[--brand-deep]" 1290 :class="sel.city === ci.slug ? 'bg-[--brand-soft]' : 'hover:bg-[--soft]'" 1291 > 1292 1293 <span class="inline-flex items-center justify-center w-[30px] h-[30px] rounded-full shrink-0" style="background:var(--soft-2);color:var(--muted)"> 1294 <!--[if BLOCK]><![endif]--> <svg 1295 width="14" 1296 height="14"
1297 viewBox="0 0 24 24" 1298 fill="none" 1299 stroke="currentColor" 1300 stroke-width="1.8" 1301 stroke-linecap="round" 1302 stroke-linejoin="round" 1303 class="flex-shrink-0" 1304 ><path d="M20 10c0 4.993-5.539 10.193-7.399 11.799a1 1 0 0 1-1.202 0C9.539 20.193 4 14.993 4 10a8 8 0 0 1 16 0"/><circle cx="12" cy="10" r="3"/></svg> 1305<!--[if ENDBLOCK]><![endif]--> </span> 1306 1307 <span 1308 class="flex-1 text-[14.5px] font-[500] leading-tight" 1309 :class="sel.city === ci.slug ? 'font-[600]' : ''" 1310 style="color:var(--ink)" 1311 x-text="ci.name" 1312 ></span> 1313 1314 <span class="ml-auto text-[12.5px] tabular-nums shrink-0" style="font-family:var(--font-mono);color:var(--muted)" x-text="ci.count"></span> 1315 1316 <span class="shrink-0 w-4 h-4" :class="sel.city === ci.slug ? 'opacity-100' : 'opacity-0'"> 1317 <!--[if BLOCK]><![endif]--> <svg 1318 width="17" 1319 height="17"
1320 viewBox="0 0 24 24" 1321 fill="none" 1322 stroke="currentColor" 1323 stroke-width="2.4" 1324 stroke-linecap="round" 1325 stroke-linejoin="round" 1326 style="color:var(--brand)" class="flex-shrink-0" 1327 ><polyline points="20 6 9 17 4 12"/></svg> 1328<!--[if ENDBLOCK]><![endif]--> </span> 1329 </button> 1330 </template> 1331 </div> 1332 </div> 1333 1334</div> </div> 1335 1336 1337 1338</div> 1339 1340 <a 1341 href="https://runningcalendar.co.za/me/saved" 1342 aria-label="Saved races" 1343 title="Saved races" 1344 class="inline-flex items-center justify-center w-10 h-10 rounded-lg text-ink-2 border border-transparent transition hover:bg-soft hover:border-rule" 1345 > 1346 <svg 1347 width="20" 1348 height="20" 1349 viewBox="0 0 24 24" 1350 fill="none" 1351 stroke="currentColor" 1352 stroke-width="1.8" 1353 stroke-linecap="round" 1354 stroke-linejoin="round" 1355 class="flex-shrink-0" 1356 ><path d="m19 21-7-4-7 4V5a2 2 0 0 1 2-2h10a2 2 0 0 1 2 2v16z"/></svg> 1357 </a> 1358 1359 1360 1361 1362 <a href="https://runningcalendar.co.za/login" class="inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-lg font-medium transition border border-transparent bg-brand-500 text-white hover:bg-brand-600 px-3 py-1.5 text-sm min-h-9"> 1363 Sign in 1364 </a> 1365 1366 </div> 1367 1368 1369 1370 1371 1372 1373 <div 1374 x-show="calOpen" 1375 x-cloak 1376 x-transition:enter="transition ease-out duration-[160ms]" 1377 x-transition:enter-start="opacity-0" 1378 x-transition:enter-end="opacity-100" 1379 x-transition:leave="transition ease-in duration-[100ms]" 1380 x-transition:leave-start="opacity-100" 1381 x-transition:leave-end="opacity-0" 1382 class="fixed inset-x-0 bottom-0 z-[45] pointer-events-none" 1383 style="top:65px;background:rgba(10,22,40,.30)" 1384 aria-hidden="true" 1385 ></div> 1386 1387 1388 <div 1389 x-show="calOpen" 1390 x-cloak 1391 x-transition:enter="transition ease-out duration-[160ms]" 1392 x-transition:enter-start="opacity-0 -translate-y-1.5" 1393 x-transition:enter-end="opacity-100 translate-y-0" 1394 x-transition:leave="transition ease-in duration-[100ms]" 1395 x-transition:leave-start="opacity-100 translate-y-0" 1396 x-transition:leave-end="opacity-0 -translate-y-1.5" 1397 class="absolute left-0 top-full z-50 flex rounded-xl border border-rule overflow-hidden origin-top-left" 1398 style="width:900px;max-width:calc(100vw - 48px);background:var(--surface);box-shadow:var(--sh-lg)" 1399 role="menu" 1400 aria-label="Calendar browse shortcuts" 1401 > 1402 1403 <div class="shrink-0 border-r" style="width:236px;background:var(--brand-50);border-color:var(--rule-soft);padding:18px 16px"> 1404 <p class="font-mono uppercase text-muted mb-3" style="font-size:10.5px;letter-spacing:.12em">JUMP IN</p> 1405 1406 1407 <div class="space-y-0.5"> 1408 <a 1409 href="https://runningcalendar.co.za/calendar?range=this-week" 1410 role="menuitem" 1411 @click="calOpen = false" 1412 class="flex items-center gap-2.5 rounded px-2 py-[7px] transition hover:bg-surface" 1413 > 1414 <span class="shrink-0 flex items-center justify-center rounded-[6px] border" style="width:30px;height:30px;background:var(--soft);border-color:var(--rule-soft)"> 1415 <svg 1416 width="14" 1417 height="14"
1418 viewBox="0 0 24 24" 1419 fill="none" 1420 stroke="currentColor" 1421 stroke-width="1.8" 1422 stroke-linecap="round" 1423 stroke-linejoin="round" 1424 style="color:var(--brand-deep)" class="flex-shrink-0" 1425 ><circle cx="12" cy="12" r="10"/><polyline points="12 6 12 12 16 14"/></svg> 1426 </span> 1427 <span style="font-size:14.5px;font-weight:600;color:var(--ink)">This week</span> 1428 </a> 1429 <a 1430 href="https://runningcalendar.co.za/calendar?range=this-month" 1431 role="menuitem" 1432 @click="calOpen = false" 1433 class="flex items-center gap-2.5 rounded px-2 py-[7px] transition hover:bg-surface" 1434 > 1435 <span class="shrink-0 flex items-center justify-center rounded-[6px] border" style="width:30px;height:30px;background:var(--soft);border-color:var(--rule-soft)"> 1436 <svg 1437 width="14" 1438 height="14"
1439 viewBox="0 0 24 24" 1440 fill="none" 1441 stroke="currentColor" 1442 stroke-width="1.8" 1443 stroke-linecap="round" 1444 stroke-linejoin="round" 1445 style="color:var(--brand-deep)" class="flex-shrink-0" 1446 ><path d="M8 2v4"/><path d="M16 2v4"/><rect width="18" height="18" x="3" y="4" rx="2"/><path d="M3 10h18"/></svg> 1447 </span> 1448 <span style="font-size:14.5px;font-weight:600;color:var(--ink)">This month</span> 1449 </a> 1450 <a 1451 href="https://runningcalendar.co.za/calendar" 1452 role="menuitem" 1453 @click="calOpen = false" 1454 class="flex items-center gap-2.5 rounded px-2 py-[7px] transition hover:bg-surface" 1455 > 1456 <span class="shrink-0 flex items-center justify-center rounded-[6px] border" style="width:30px;height:30px;background:var(--soft);border-color:var(--rule-soft)"> 1457 <svg 1458 width="14" 1459 height="14"
1460 viewBox="0 0 24 24" 1461 fill="none" 1462 stroke="currentColor" 1463 stroke-width="1.8" 1464 stroke-linecap="round" 1465 stroke-linejoin="round" 1466 style="color:var(--brand-deep)" class="flex-shrink-0" 1467 ><polyline points="22 7 13.5 15.5 8.5 10.5 2 17"/><polyline points="16 7 22 7 22 13"/></svg> 1468 </span> 1469 <span style="font-size:14.5px;font-weight:600;color:var(--ink)">All upcoming</span> 1470 </a> 1471 <a 1472 href="https://runningcalendar.co.za/calendar?view=map" 1473 role="menuitem" 1474 @click="calOpen = false" 1475 class="flex items-center gap-2.5 rounded px-2 py-[7px] transition hover:bg-surface" 1476 > 1477 <span class="shrink-0 flex items-center justify-center rounded-[6px] border" style="width:30px;height:30px;background:var(--soft);border-color:var(--rule-soft)"> 1478 <svg 1479 width="14" 1480 height="14"
1481 viewBox="0 0 24 24" 1482 fill="none" 1483 stroke="currentColor" 1484 stroke-width="1.8" 1485 stroke-linecap="round" 1486 stroke-linejoin="round" 1487 style="color:var(--brand-deep)" class="flex-shrink-0" 1488 ><polygon points="3 6 9 3 15 6 21 3 21 18 15 21 9 18 3 21"/><line x1="9" x2="9" y1="3" y2="18"/><line x1="15" x2="15" y1="6" y2="21"/></svg> 1489 </span> 1490 <span style="font-size:14.5px;font-weight:600;color:var(--ink)">Map view</span> 1491 </a> 1492 <a 1493 href="https://runningcalendar.co.za/calendar?featured=1" 1494 role="menuitem" 1495 @click="calOpen = false" 1496 class="flex items-center gap-2.5 rounded px-2 py-[7px] transition hover:bg-surface" 1497 > 1498 <span class="shrink-0 flex items-center justify-center rounded-[6px] border" style="width:30px;height:30px;background:var(--soft);border-color:var(--rule-soft)"> 1499 <svg 1500 width="14" 1501 height="14"
1502 viewBox="0 0 24 24" 1503 fill="none" 1504 stroke="currentColor" 1505 stroke-width="1.8" 1506 stroke-linecap="round" 1507 stroke-linejoin="round" 1508 style="color:var(--brand-deep)" class="flex-shrink-0" 1509 ><polygon points="12 2 15.09 8.26 22 9.27 17 14.14 18.18 21.02 12 17.77 5.82 21.02 7 14.14 2 9.27 8.91 8.26 12 2"/></svg> 1510 </span> 1511 <span style="font-size:14.5px;font-weight:600;color:var(--ink)">Featured races</span> 1512 </a> 1513 </div> 1514 </div> 1515 1516 1517 <div class="flex-1 bg-surface" style="padding:20px 22px"> 1518 <div style="display:grid;grid-template-columns:1fr 1fr;gap:18px 26px"> 1519 1520 1521 <div style="grid-column:1/-1"> 1522 <div class="flex items-center gap-1 mb-2.5"> 1523 <svg 1524 width="12" 1525 height="12"
1526 viewBox="0 0 24 24" 1527 fill="none" 1528 stroke="currentColor" 1529 stroke-width="2" 1530 stroke-linecap="round" 1531 stroke-linejoin="round" 1532 class="flex-shrink-0 text-muted shrink-0" 1533 ><path d="M21.3 8.7L8.7 21.3a2.4 2.4 0 0 1-3.4 0L2.7 18.7a2.4 2.4 0 0 1 0-3.4L15.3 2.7a2.4 2.4 0 0 1 3.4 0l2.6 2.6a2.4 2.4 0 0 1 0 3.4z"/><path d="m7.5 10.5 2 2"/><path d="m10.5 7.5 2 2"/><path d="m13.5 4.5 2 2"/><path d="m4.5 13.5 2 2"/></svg> 1534 <p class="font-mono uppercase text-muted" style="font-size:10.5px;letter-spacing:.12em">Distance</p> 1535 </div> 1536 <div class="flex flex-wrap gap-1.5"> 1537 <a 1538 href="https://runningcalendar.co.za/races/distance/5km" 1539 role="menuitem" 1540 @click="calOpen = false" 1541 class="inline-flex items-center rounded-full hover:brightness-[.96] transition-[filter]" 1542 style="padding:4px 11px;font-size:13px;font-weight:600;background:var(--c-5k-soft);color:var(--c-5k-ink)" 1543 >5 km</a> 1544 <a 1545 href="https://runningcalendar.co.za/races/distance/10km" 1546 role="menuitem" 1547 @click="calOpen = false" 1548 class="inline-flex items-center rounded-full hover:brightness-[.96] transition-[filter]" 1549 style="padding:4px 11px;font-size:13px;font-weight:600;background:var(--c-10k-soft);color:var(--c-10k-ink)" 1550 >10 km</a> 1551 <a 1552 href="https://runningcalendar.co.za/races/distance/15km" 1553 role="menuitem" 1554 @click="calOpen = false" 1555 class="inline-flex items-center rounded-full hover:brightness-[.96] transition-[filter]" 1556 style="padding:4px 11px;font-size:13px;font-weight:600;background:var(--c-15k-soft);color:var(--c-15k-ink)" 1557 >15 km</a> 1558 <a 1559 href="https://runningcalendar.co.za/races/distance/21km" 1560 role="menuitem" 1561 @click="calOpen = false" 1562 class="inline-flex items-center rounded-full hover:brightness-[.96] transition-[filter]" 1563 style="padding:4px 11px;font-size:13px;font-weight:600;background:var(--c-21k-soft);color:var(--c-21k-ink)" 1564 >21.1 km</a> 1565 <a 1566 href="https://runningcalendar.co.za/races/distance/30km" 1567 role="menuitem" 1568 @click="calOpen = false" 1569 class="inline-flex items-center rounded-full hover:brightness-[.96] transition-[filter]" 1570 style="padding:4px 11px;font-size:13px;font-weight:600;background:var(--c-30k-soft);color:var(--c-30k-ink)" 1571 >30 km</a> 1572 <a 1573 href="https://runningcalendar.co.za/races/distance/42km" 1574 role="menuitem" 1575 @click="calOpen = false" 1576 class="inline-flex items-center rounded-full hover:brightness-[.96] transition-[filter]" 1577 style="padding:4px 11px;font-size:13px;font-weight:600;background:var(--c-42k-soft);color:var(--c-42k-ink)" 1578 >42.2 km</a> 1579 <a 1580 href="https://runningcalendar.co.za/races/distance/ultra" 1581 role="menuitem" 1582 @click="calOpen = false" 1583 class="inline-flex items-center rounded-full hover:brightness-[.96] transition-[filter]" 1584 style="padding:4px 11px;font-size:13px;font-weight:600;background:var(--c-ultra-soft);color:var(--c-ultra-ink)" 1585 >Ultra</a> 1586 <a 1587 href="https://runningcalendar.co.za/races/terrain/trail" 1588 role="menuitem" 1589 @click="calOpen = false" 1590 class="inline-flex items-center rounded-full hover:brightness-[.96] transition-[filter]" 1591 style="padding:4px 11px;font-size:13px;font-weight:600;background:var(--c-trail-soft);color:var(--c-trail-ink)" 1592 >Trail</a> 1593 </div> 1594 </div> 1595 1596 1597 <div> 1598 <div class="flex items-center gap-1 mb-2.5"> 1599 <svg 1600 width="12" 1601 height="12"
1602 viewBox="0 0 24 24" 1603 fill="none" 1604 stroke="currentColor" 1605 stroke-width="2" 1606 stroke-linecap="round" 1607 stroke-linejoin="round" 1608 class="flex-shrink-0 text-muted shrink-0" 1609 ><path d="M4 15s1-1 4-1 5 2 8 2 4-1 4-1V3s-1 1-4 1-5-2-8-2-4 1-4 1z"/><line x1="4" x2="4" y1="22" y2="15"/></svg> 1610 <p class="font-mono uppercase text-muted" style="font-size:10.5px;letter-spacing:.12em">Province</p> 1611 </div> 1612 <div class="flex flex-wrap gap-1.5"> 1613 <a href="https://runningcalendar.co.za/races/province/western-cape" role="menuitem" @click="calOpen = false" class="cal-npill">Western Cape</a> 1614 <a href="https://runningcalendar.co.za/races/province/gauteng" role="menuitem" @click="calOpen = false" class="cal-npill">Gauteng</a> 1615 <a href="https://runningcalendar.co.za/races/province/kwazulu-natal" role="menuitem" @click="calOpen = false" class="cal-npill">KwaZulu-Natal</a> 1616 <a href="https://runningcalendar.co.za/races/province/eastern-cape" role="menuitem" @click="calOpen = false" class="cal-npill">Eastern Cape</a> 1617 <a href="https://runningcalendar.co.za/races/province/free-state" role="menuitem" @click="calOpen = false" class="cal-npill">Free State</a> 1618 <a href="https://runningcalendar.co.za/races/province/limpopo" role="menuitem" @click="calOpen = false" class="cal-npill">Limpopo</a> 1619 <a href="https://runningcalendar.co.za/races/province/mpumalanga" role="menuitem" @click="calOpen = false" class="cal-npill">Mpumalanga</a> 1620 <a href="https://runningcalendar.co.za/races/province/north-west" role="menuitem" @click="calOpen = false" class="cal-npill">North West</a> 1621 <a href="https://runningcalendar.co.za/races/province/northern-cape" role="menuitem" @click="calOpen = false" class="cal-npill">Northern Cape</a> 1622 </div> 1623 </div> 1624 1625 1626 <div> 1627 <div class="flex items-center gap-1 mb-2.5"> 1628 <svg 1629 width="12" 1630 height="12"
1631 viewBox="0 0 24 24" 1632 fill="none" 1633 stroke="currentColor" 1634 stroke-width="2" 1635 stroke-linecap="round" 1636 stroke-linejoin="round" 1637 class="flex-shrink-0 text-muted shrink-0" 1638 ><circle cx="12" cy="12" r="10"/><path d="M12 2a14.5 14.5 0 0 0 0 20 14.5 14.5 0 0 0 0-20"/><path d="M2 12h20"/></svg> 1639 <p class="font-mono uppercase text-muted" style="font-size:10.5px;letter-spacing:.12em">Country</p> 1640 </div> 1641 <div class="flex flex-wrap gap-1.5"> 1642 <a href="https://runningcalendar.co.za/races/country/za" role="menuitem" @click="calOpen = false" class="cal-npill inline-flex items-center gap-1.5"> 1643 <img src="https://runningcalendar.co.za/images/flags/za.svg" 1644 alt="" width="18" height="13" loading="lazy" 1645 class="shrink-0 rounded-[2px] ring-1 ring-black/5 object-cover"> 1646 South Africa 1647 </a> 1648 <a href="https://runningcalendar.co.za/races/country/ls" role="menuitem" @click="calOpen = false" class="cal-npill inline-flex items-center gap-1.5"> 1649 <img src="https://runningcalendar.co.za/images/flags/ls.svg" 1650 alt="" width="18" height="13" loading="lazy" 1651 class="shrink-0 rounded-[2px] ring-1 ring-black/5 object-cover"> 1652 Lesotho 1653 </a> 1654 <a href="https://runningcalendar.co.za/races/country/na" role="menuitem" @click="calOpen = false" class="cal-npill inline-flex items-center gap-1.5"> 1655 <img src="https://runningcalendar.co.za/images/flags/na.svg" 1656 alt="" width="18" height="13" loading="lazy" 1657 class="shrink-0 rounded-[2px] ring-1 ring-black/5 object-cover"> 1658 Namibia 1659 </a> 1660 <a href="https://runningcalendar.co.za/races/country/bw" role="menuitem" @click="calOpen = false" class="cal-npill inline-flex items-center gap-1.5"> 1661 <img src="https://runningcalendar.co.za/images/flags/bw.svg" 1662 alt="" width="18" height="13" loading="lazy" 1663 class="shrink-0 rounded-[2px] ring-1 ring-black/5 object-cover"> 1664 Botswana 1665 </a> 1666 <a href="https://runningcalendar.co.za/races/country/sz" role="menuitem" @click="calOpen = false" class="cal-npill inline-flex items-center gap-1.5"> 1667 <img src="https://runningcalendar.co.za/images/flags/sz.svg" 1668 alt="" width="18" height="13" loading="lazy" 1669 class="shrink-0 rounded-[2px] ring-1 ring-black/5 object-cover"> 1670 eSwatini 1671 </a> 1672 <a href="https://runningcalendar.co.za/races/country/zw" role="menuitem" @click="calOpen = false" class="cal-npill inline-flex items-center gap-1.5"> 1673 <img src="https://runningcalendar.co.za/images/flags/zw.svg" 1674 alt="" width="18" height="13" loading="lazy" 1675 class="shrink-0 rounded-[2px] ring-1 ring-black/5 object-cover"> 1676 Zimbabwe 1677 </a> 1678 </div> 1679 </div> 1680 1681 1682 <div style="grid-column:1/-1"> 1683 <div class="flex items-center gap-1 mb-2.5"> 1684 <svg 1685 width="12" 1686 height="12"
1687 viewBox="0 0 24 24" 1688 fill="none" 1689 stroke="currentColor" 1690 stroke-width="2" 1691 stroke-linecap="round" 1692 stroke-linejoin="round" 1693 class="flex-shrink-0 text-muted shrink-0" 1694 ><path d="M20 10c0 4.993-5.539 10.193-7.399 11.799a1 1 0 0 1-1.202 0C9.539 20.193 4 14.993 4 10a8 8 0 0 1 16 0"/><circle cx="12" cy="10" r="3"/></svg> 1695 <p class="font-mono uppercase text-muted" style="font-size:10.5px;letter-spacing:.12em">Popular cities</p> 1696 </div> 1697 <div style="columns:2;column-gap:16px"> 1698 <a href="https://runningcalendar.co.za/races/city/bloemfontein" role="menuitem" @click="calOpen = false" 1699 class="block text-sm text-ink-2 hover:text-brand-deeper transition py-0.5">Bloemfontein</a> 1700 <a href="https://runningcalendar.co.za/races/city/cape-town" role="menuitem" @click="calOpen = false" 1701 class="block text-sm text-ink-2 hover:text-brand-deeper transition py-0.5">Cape Town</a> 1702 <a href="https://runningcalendar.co.za/races/city/durban" role="menuitem" @click="calOpen = false" 1703 class="block text-sm text-ink-2 hover:text-brand-deeper transition py-0.5">Durban</a> 1704 <a href="https://runningcalendar.co.za/races/city/east-london" role="menuitem" @click="calOpen = false" 1705 class="block text-sm text-ink-2 hover:text-brand-deeper transition py-0.5">East London</a> 1706 <a href="https://runningcalendar.co.za/races/city/george" role="menuitem" @click="calOpen = false" 1707 class="block text-sm text-ink-2 hover:text-brand-deeper transition py-0.5">George</a> 1708 <a href="https://runningcalendar.co.za/races/city/gqeberha" role="menuitem" @click="calOpen = false" 1709 class="block text-sm text-ink-2 hover:text-brand-deeper transition py-0.5">Gqeberha</a> 1710 <a href="https://runningcalendar.co.za/races/city/johannesburg" role="menuitem" @click="calOpen = false" 1711 class="block text-sm text-ink-2 hover:text-brand-deeper transition py-0.5">Johannesburg</a> 1712 <a href="https://runningcalendar.co.za/races/city/kimberley" role="menuitem" @click="calOpen = false" 1713 class="block text-sm text-ink-2 hover:text-brand-deeper transition py-0.5">Kimberley</a> 1714 <a href="https://runningcalendar.co.za/races/city/mbombela" role="menuitem" @click="calOpen = false" 1715 class="block text-sm text-ink-2 hover:text-brand-deeper transition py-0.5">Mbombela</a> 1716 <a href="https://runningcalendar.co.za/races/city/mthatha" role="menuitem" @click="calOpen = false" 1717 class="block text-sm text-ink-2 hover:text-brand-deeper transition py-0.5">Mthatha</a> 1718 <a href="https://runningcalendar.co.za/cities" role="menuitem" @click="calOpen = false" 1719 class="block text-sm font-medium text-brand-deeper hover:underline transition py-0.5">Browse all â</a> 1720 </div> 1721 </div> 1722 1723 1724 <div style="grid-column:1/-1"> 1725 <div class="flex items-center gap-1 mb-2.5"> 1726 <svg 1727 width="12" 1728 height="12"
1729 viewBox="0 0 24 24" 1730 fill="none" 1731 stroke="currentColor" 1732 stroke-width="2" 1733 stroke-linecap="round" 1734 stroke-linejoin="round" 1735 class="flex-shrink-0 text-muted shrink-0" 1736 ><path d="M6 9H4.5a2.5 2.5 0 0 1 0-5H6"/><path d="M18 9h1.5a2.5 2.5 0 0 0 0-5H18"/><path d="M4 22h16"/><path d="M10 14.66V17c0 .55-.47.98-.97 1.21C7.85 18.75 7 20.24 7 22"/><path d="M14 14.66V17c0 .55.47.98.97 1.21C16.15 18.75 17 20.24 17 22"/><path d="M18 2H6v7a6 6 0 0 0 12 0V2z"/></svg> 1737 <p class="font-mono uppercase text-muted" style="font-size:10.5px;letter-spacing:.12em">Qualifiers</p> 1738 </div> 1739 <div class="flex flex-wrap gap-1.5"> 1740 <a href="https://runningcalendar.co.za/races/qualifier/comrades" role="menuitem" @click="calOpen = false" 1741 class="cal-npill" style="color:var(--st-postponed)">Comrades</a> 1742 <a href="https://runningcalendar.co.za/races/qualifier/two-oceans" role="menuitem" @click="calOpen = false" 1743 class="cal-npill" style="color:var(--st-results)">Two Oceans</a> 1744 </div> 1745 </div> 1746 1747 </div> 1748 </div> 1749 </div> 1750 1751 </div> 1752 1753 1754 1755 1756 <div class="flex lg:hidden items-center gap-2.5 py-3 px-3.5"> 1757 1758 1759 <a href="https://runningcalendar.co.za" aria-label="RunningCalendar home"> 1760 <img 1761 src="https://runningcalendar.co.za/images/logo/running-calendar-logo.png" 1762 alt="RunningCalendar" 1763 width="32" 1764 height="32" 1765 class="h-8 w-8 object-contain" 1766 > 1767 </a> 1768 1769 1770 <button 1771 type="button" 1772 @click="$dispatch('open-search-modal')" 1773 class="flex flex-1 items-center gap-2.5 py-2.5 px-3.5 bg-soft rounded-lg text-muted min-h-11 cursor-pointer" 1774 aria-label="Search races, towns" 1775 > 1776 <svg 1777 width="18" 1778 height="18"
1779 viewBox="0 0 24 24" 1780 fill="none" 1781 stroke="currentColor" 1782 stroke-width="1.8" 1783 stroke-linecap="round" 1784 stroke-linejoin="round" 1785 class="flex-shrink-0" 1786 ><circle cx="11" cy="11" r="7"/><path d="m20 20-3.5-3.5"/></svg> 1787 <span class="text-base hidden sm:inline">Search races, townsâ¦</span> 1788 <span class="text-base sm:hidden">Searchâ¦</span> 1789 </button> 1790 1791 1792 1793 1794 <button 1795 type="button" 1796 @click="drawerOpen = true" 1797 class="flex flex-col gap-1 items-center justify-center w-11 h-11 bg-soft rounded-lg shrink-0 border border-transparent hover:border-rule transition" 1798 aria-label="Open navigation menu" 1799 > 1800 <span class="block w-[18px] h-0.5 rounded-sm bg-muted"></span> 1801 <span class="block w-[18px] h-0.5 rounded-sm bg-muted"></span> 1802 <span class="block w-[18px] h-0.5 rounded-sm bg-muted"></span> 1803 </button> 1804 1805 </div> 1806 1807 </header> 1808 1809 1810 1811 1812 1813 1814 <div 1815 x-show="drawerOpen && !isDesktop" 1816 x-cloak 1817 x-transition:enter="transition-opacity duration-200" 1818 x-transition:enter-start="opacity-0" 1819 x-transition:enter-end="opacity-100" 1820 x-transition:leave="transition-opacity duration-200" 1821 x-transition:leave-start="opacity-100" 1822 x-transition:leave-end="opacity-0" 1823 @click="drawerOpen = false" 1824 class="fixed inset-0 bg-black/40 z-[55]" 1825 aria-hidden="true" 1826 ></div> 1827 1828 1829 <div 1830 x-show="drawerOpen && !isDesktop" 1831 x-cloak 1832 x-transition:enter="transition duration-[220ms] ease-[cubic-bezier(.2,.7,.3,1)]" 1833 x-transition:enter-start="opacity-0 translate-y-3.5" 1834 x-transition:enter-end="opacity-100 translate-y-0" 1835 x-transition:leave="transition ease-in duration-150" 1836 x-transition:leave-start="opacity-100 translate-y-0" 1837 x-transition:leave-end="opacity-0 translate-y-3.5" 1838 @keydown.escape.window="drawerOpen = false" 1839 x-effect="drawerOpen ? document.body.style.overflow = 'hidden' : document.body.style.overflow = ''" 1840 class="fixed inset-0 z-[60] flex flex-col bg-surface" 1841 role="dialog" 1842 aria-modal="true" 1843 aria-label="Navigation menu" 1844 > 1845 1846 1847 <div class="flex items-center justify-between px-4 pt-4 pb-3 shrink-0"> 1848 <a href="https://runningcalendar.co.za" @click="drawerOpen = false" class="flex items-center gap-2 text-ink font-semibold"> 1849 <img src="https://runningcalendar.co.za/images/logo/running-calendar-logo.png" alt="" width="28" height="28" class="h-7 w-7 object-contain"> 1850 RunningCalendar 1851 </a> 1852 <button type="button" @click="drawerOpen = false" class="flex items-center justify-center w-10 h-10 rounded-lg bg-soft text-ink-2 hover:text-ink transition" aria-label="Close menu"> 1853 <svg 1854 width="20" 1855 height="20"
1856 viewBox="0 0 24 24" 1857 fill="none" 1858 stroke="currentColor" 1859 stroke-width="1.8" 1860 stroke-linecap="round" 1861 stroke-linejoin="round" 1862 class="flex-shrink-0" 1863 ><line x1="18" x2="6" y1="6" y2="18"/><line x1="6" x2="18" y1="6" y2="18"/></svg> 1864 </button> 1865 </div> 1866 1867 1868 <div class="flex gap-1 px-4 pb-3 shrink-0"> 1869 <button 1870 type="button" 1871 @click="tab = 'menu'" 1872 class="flex-1 h-10 rounded-lg text-sm font-semibold transition" 1873 :style="tab === 'menu' ? 'background:var(--brand-deep);color:#fff' : 'background:var(--soft);color:var(--ink-2)'" 1874 >Menu</button> 1875 <button 1876 type="button" 1877 @click="tab = 'browse'" 1878 class="flex-1 h-10 rounded-lg text-sm font-semibold transition" 1879 :style="tab === 'browse' ? 'background:var(--brand-deep);color:#fff' : 'background:var(--soft);color:var(--ink-2)'" 1880 >Browse</button> 1881 <button 1882 type="button" 1883 @click="tab = 'account'" 1884 class="flex-1 h-10 rounded-lg text-sm font-semibold transition" 1885 :style="tab === 'account' ? 'background:var(--brand-deep);color:#fff' : 'background:var(--soft);color:var(--ink-2)'" 1886 >Account</button> 1887 </div> 1888 1889 1890 <div class="flex-1 overflow-y-auto px-4 pb-4"> 1891 1892 1893 <div x-show="tab === 'menu'"> 1894 <div class="py-1"> 1895 <a href="https://runningcalendar.co.za" @click="drawerOpen = false" class="flex items-center gap-3 py-3.5"> 1896 <span class="m-tile"><svg 1897 width="18" 1898 height="18"
1899 viewBox="0 0 24 24" 1900 fill="none" 1901 stroke="currentColor" 1902 stroke-width="1.8" 1903 stroke-linecap="round" 1904 stroke-linejoin="round" 1905 class="flex-shrink-0" 1906 ><path d="m3 9 9-7 9 7v11a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z"/><polyline points="9 22 9 12 15 12 15 22"/></svg> 1907</span> 1908 <span class="text-base font-semibold text-ink">Home</span> 1909 </a> 1910 <a href="https://runningcalendar.co.za/calendar" @click="drawerOpen = false" class="flex items-center gap-3 py-3.5"> 1911 <span class="m-tile"><svg 1912 width="18" 1913 height="18" 1914 viewBox="0 0 24 24" 1915 fill="none" 1916 stroke="currentColor" 1917 stroke-width="1.8" 1918 stroke-linecap="round" 1919 stroke-linejoin="round" 1920 class="flex-shrink-0" 1921 ><path d="M8 2v4"/><path d="M16 2v4"/><rect width="18" height="18" x="3" y="4" rx="2"/><path d="M3 10h18"/></svg> 1922</span> 1923 <span class="text-base font-semibold text-ink">Calendar</span> 1924 </a> 1925 <a href="https://runningcalendar.co.za/near-me" @click="drawerOpen = false" class="flex items-center gap-3 py-3.5"> 1926 <span class="m-tile"><svg 1927 width="18" 1928 height="18"
1929 viewBox="0 0 24 24" 1930 fill="none" 1931 stroke="currentColor" 1932 stroke-width="1.8" 1933 stroke-linecap="round" 1934 stroke-linejoin="round" 1935 class="flex-shrink-0" 1936 ><path d="M20 10c0 4.993-5.539 10.193-7.399 11.799a1 1 0 0 1-1.202 0C9.539 20.193 4 14.993 4 10a8 8 0 0 1 16 0"/><circle cx="12" cy="10" r="3"/></svg> 1937</span> 1938 <span class="text-base font-semibold text-ink">Near Me</span> 1939 </a> 1940 <a href="https://runningcalendar.co.za/results" @click="drawerOpen = false" class="flex items-center gap-3 py-3.5"> 1941 <span class="m-tile"><svg 1942 width="18" 1943 height="18" 1944 viewBox="0 0 24 24" 1945 fill="none" 1946 stroke="currentColor" 1947 stroke-width="1.8" 1948 stroke-linecap="round" 1949 stroke-linejoin="round" 1950 class="flex-shrink-0" 1951 ><path d="M6 9H4.5a2.5 2.5 0 0 1 0-5H6"/><path d="M18 9h1.5a2.5 2.5 0 0 0 0-5H18"/><path d="M4 22h16"/><path d="M10 14.66V17c0 .55-.47.98-.97 1.21C7.85 18.75 7 20.24 7 22"/><path d="M14 14.66V17c0 .55.47.98.97 1.21C16.15 18.75 17 20.24 17 22"/><path d="M18 2H6v7a6 6 0 0 0 12 0V2z"/></svg> 1952</span> 1953 <span class="text-base font-semibold text-ink">Results</span> 1954 </a> 1955 <a href="https://runningcalendar.co.za/advertise" @click="drawerOpen = false" class="flex items-center gap-3 py-3.5"> 1956 <span class="m-tile"><svg 1957 width="18" 1958 height="18"
1959 viewBox="0 0 24 24" 1960 fill="none" 1961 stroke="currentColor" 1962 stroke-width="1.8" 1963 stroke-linecap="round" 1964 stroke-linejoin="round" 1965 class="flex-shrink-0" 1966 ><path d="m3 11 18-5v12L3 14v-3z"/><path d="M11.6 16.8a3 3 0 1 1-5.8-1.6"/></svg> 1967</span> 1968 <span class="text-base font-semibold text-ink">Advertise</span> 1969 </a> 1970 </div> 1971 1972 1973 <p class="font-mono uppercase text-muted pt-3 pb-1" style="font-size:10.5px;letter-spacing:.12em">Settings</p> 1974 <div class="flex items-center justify-between gap-3 py-1"> 1975 <span class="text-[15px] font-medium text-ink">Theme</span> 1976 <ui-radio-group class="block flex p-1 rounded-lg bg-zinc-800/5 dark:bg-white/10 h-10 p-1" x-data="" x-model="$flux.appearance" aria-label="Theme" data-flux-radio-group-segmented> 1977 <ui-radio class="flex whitespace-nowrap flex-1 justify-center items-center gap-2 rounded-md data-checked:shadow-xs text-sm font-medium text-zinc-600 hover:text-zinc-800 dark:hover:text-white dark:text-white/70 data-checked:text-zinc-800 dark:data-checked:text-white data-checked:bg-white dark:data-checked:bg-white/20 [&[disabled]]:opacity-50 dark:[&[disabled]]:opacity-75 [&[disabled]]:cursor-default [&[disabled]]:pointer-events-none px-4" value="light" data-flux-control data-flux-radio-segmented tabindex="-1"> 1978 <svg class="shrink-0 [:where(&)]:size-5 text-zinc-500 dark:text-zinc-400 [ui-radio[data-checked]_&]:text-zinc-800 dark:[ui-radio[data-checked]_&]:text-white" data-flux-icon xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor" aria-hidden="true" data-slot="icon"> 1979 <path d="M10 2a.75.75 0 0 1 .75.75v1.5a.75.75 0 0 1-1.5 0v-1.5A.75.75 0 0 1 10 2ZM10 15a.75.75 0 0 1 .75.75v1.5a.75.75 0 0 1-1.5 0v-1.5A.75.75 0 0 1 10 15ZM10 7a3 3 0 1 0 0 6 3 3 0 0 0 0-6ZM15.657 5.404a.75.75 0 1 0-1.06-1.06l-1.061 1.06a.75.75 0 0 0 1.06 1.06l1.06-1.06ZM6.464 14.596a.75.75 0 1 0-1.06-1.06l-1.06 1.06a.75.75 0 0 0 1.06 1.06l1.06-1.06ZM18 10a.75.75 0 0 1-.75.75h-1.5a.75.75 0 0 1 0-1.5h1.5A.75.75 0 0 1 18 10ZM5 10a.75.75 0 0 1-.75.75h-1.5a.75.75 0 0 1 0-1.5h1.5A.75.75 0 0 1 5 10ZM14.596 15.657a.75.75 0 0 0 1.06-1.06l-1.06-1.061a.75.75 0 1 0-1.06 1.06l1.06 1.06ZM5.404 6.464a.75.75 0 0 0 1.06-1.06l-1.06-1.06a.75.75 0 1 0-1.061 1.06l1.06 1.06Z"/> 1980</svg> 1981 1982 1983 1984 1985 </ui-radio> 1986 <ui-radio class="flex whitespace-nowrap flex-1 justify-center items-center gap-2 rounded-md data-checked:shadow-xs text-sm font-medium text-zinc-600 hover:text-zinc-800 dark:hover:text-white dark:text-white/70 data-checked:text-zinc-800 dark:data-checked:text-white data-checked:bg-white dark:data-checked:bg-white/20 [&[disabled]]:opacity-50 dark:[&[disabled]]:opacity-75 [&[disabled]]:cursor-default [&[disabled]]:pointer-events-none px-4" value="system" data-flux-control data-flux-radio-segmented tabindex="-1"> 1987 <svg class="shrink-0 [:where(&)]:size-5 text-zinc-500 dark:text-zinc-400 [ui-radio[data-checked]_&]:text-zinc-800 dark:[ui-radio[data-checked]_&]:text-white" data-flux-icon xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor" aria-hidden="true" data-slot="icon"> 1988 <path fill-rule="evenodd" d="M2 4.25A2.25 2.25 0 0 1 4.25 2h11.5A2.25 2.25 0 0 1 18 4.25v8.5A2.25 2.25 0 0 1 15.75 15h-3.105a3.501 3.501 0 0 0 1.1 1.677A.75.75 0 0 1 13.26 18H6.74a.75.75 0 0 1-.484-1.323A3.501 3.501 0 0 0 7.355 15H4.25A2.25 2.25 0 0 1 2 12.75v-8.5Zm1.5 0a.75.75 0 0 1 .75-.75h11.5a.75.75 0 0 1 .75.75v7.5a.75.75 0 0 1-.75.75H4.25a.75.75 0 0 1-.75-.75v-7.5Z" clip-rule="evenodd"/> 1989</svg> 1990 1991 1992 1993 1994 </ui-radio> 1995 <ui-radio class="flex whitespace-nowrap flex-1 justify-center items-center gap-2 rounded-md data-checked:shadow-xs text-sm font-medium text-zinc-600 hover:text-zinc-800 dark:hover:text-white dark:text-white/70 data-checked:text-zinc-800 dark:data-checked:text-white data-checked:bg-white dark:data-checked:bg-white/20 [&[disabled]]:opacity-50 dark:[&[disabled]]:opacity-75 [&[disabled]]:cursor-default [&[disabled]]:pointer-events-none px-4" value="dark" data-flux-control data-flux-radio-segmented tabindex="-1"> 1996 <svg class="shrink-0 [:where(&)]:size-5 text-zinc-500 dark:text-zinc-400 [ui-radio[data-checked]_&]:text-zinc-800 dark:[ui-radio[data-checked]_&]:text-white" data-flux-icon xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor" aria-hidden="true" data-slot="icon"> 1997 <path fill-rule="evenodd" d="M7.455 2.004a.75.75 0 0 1 .26.77 7 7 0 0 0 9.958 7.967.75.75 0 0 1 1.067.853A8.5 8.5 0 1 1 6.647 1.921a.75.75 0 0 1 .808.083Z" clip-rule="evenodd"/> 1998</svg> 1999 2000 2001 2002 2003 </ui-radio> 2004 </ui-radio-group> 2005 </div> 2006 <div class="flex items-center justify-between gap-3 py-2">
2007 <span class="text-[15px] font-medium text-ink">Location</span> 2008 <div wire:snapshot="{"data":{"iconOnly":false},"memo":{"id":"taeXL1KYMDwRidu2frm8","name":"locale-selector","path":"contact","method":"GET","release":"a-a-a","children":[],"scripts":[],"assets":[],"errors":[],"locale":"en"},"checksum":"d96668e7bbc8184874298d8304f28ce86785ca1d86bfc82e84cf0d99aed57345"}" wire:effects="{"partials":[]}" wire:id="taeXL1KYMDwRidu2frm8" 2009 x-data="geoSelector(JSON.parse('{\u0022tree\u0022:{\u0022resetLabel\u0022:\u0022All of Southern Africa\u0022,\u0022total\u0022:500,\u0022countries\u0022:[{\u0022code\u0022:\u0022ZA\u0022,\u0022name\u0022:\u0022South Africa\u0022,\u0022count\u0022:492,\u0022provinces\u0022:[{\u0022slug\u0022:\u0022western-cape\u0022,\u0022code\u0022:\u0022WC\u0022,\u0022name\u0022:\u0022Western Cape\u0022,\u0022count\u0022:125,\u0022cities\u0022:[{\u0022name\u0022:\u0022Cape Town\u0022,\u0022slug\u0022:\u0022cape-town\u0022,\u0022count\u0022:84},{\u0022name\u0022:\u0022George\u0022,\u0022slug\u0022:\u0022george\u0022,\u0022count\u0022:41}]},{\u0022slug\u0022:\u0022gauteng\u0022,\u0022code\u0022:\u0022GP\u0022,\u0022name\u0022:\u0022Gauteng\u0022,\u0022count\u0022:99,\u0022cities\u0022:[{\u0022name\u0022:\u0022Johannesburg\u0022,\u0022slug\u0022:\u0022johannesburg\u0022,\u0022count\u0022:78},{\u0022name\u0022:\u0022Pretoria\u0022,\u0022slug\u0022:\u0022pretoria\u0022,\u0022count\u0022:52}]},{\u0022slug\u0022:\u0022kwazulu-natal\u0022,\u0022code\u0022:\u0022KZN\u0022,\u0022name\u0022:\u0022KwaZulu-Natal\u0022,\u0022count\u0022:50,\u0022cities\u0022:[{\u0022name\u0022:\u0022Durban\u0022,\u0022slug\u0022:\u0022durban\u0022,\u0022count\u0022:38},{\u0022name\u0022:\u0022Pietermaritzburg\u0022,\u0022slug\u0022:\u0022pietermaritzburg\u0022,\u0022count\u0022:12}]},{\u0022slug\u0022:\u0022eastern-cape\u0022,\u0022code\u0022:\u0022EC\u0022,\u0022name\u0022:\u0022Eastern Cape\u0022,\u0022count\u0022:75,\u0022cities\u0022:[{\u0022name\u0022:\u0022Gqeberha\u0022,\u0022slug\u0022:\u0022gqeberha\u0022,\u0022count\u0022:38},{\u0022name\u0022:\u0022East London\u0022,\u0022slug\u0022:\u0022east-london\u0022,\u0022count\u0022:22},{\u0022name\u0022:\u0022Mthatha\u0022,\u0022slug\u0022:\u0022mthatha\u0022,\u0022count\u0022:15}]},{\u0022slug\u0022:\u0022free-state\u0022,\u0022code\u0022:\u0022FS\u0022,\u0022name\u0022:\u0022Free State\u0022,\u0022count\u0022:28,\u0022soleCity\u0022:\u0022Bloemfontein\u0022},{\u0022slug\u0022:\u0022limpopo\u0022,\u0022code\u0022:\u0022LP\u0022,\u0022name\u0022:\u0022Limpopo\u0022,\u0022count\u0022:43,\u0022cities\u0022:[{\u0022name\u0022:\u0022Polokwane\u0022,\u0022slug\u0022:\u0022polokwane\u0022,\u0022count\u0022:39},{\u0022name\u0022:\u0022Rustenburg\u0022,\u0022slug\u0022:\u0022rustenburg\u0022,\u0022count\u0022:10}]},{\u0022slug\u0022:\u0022mpumalanga\u0022,\u0022code\u0022:\u0022MP\u0022,\u0022name\u0022:\u0022Mpumalanga\u0022,\u0022count\u0022:43,\u0022soleCity\u0022:\u0022Mbombela\u0022},{\u0022slug\u0022:\u0022north-west\u0022,\u0022code\u0022:\u0022NW\u0022,\u0022name\u0022:\u0022North West\u0022,\u0022count\u0022:11},{\u0022slug\u0022:\u0022northern-cape\u0022,\u0022code\u0022:\u0022NC\u0022,\u0022name\u0022:\u0022Northern Cape\u0022,\u0022count\u0022:13,\u0022cities\u0022:[{\u0022name\u0022:\u0022Kimberley\u0022,\u0022slug\u0022:\u0022kimberley\u0022,\u0022count\u0022:7},{\u0022name\u0022:\u0022Upington\u0022,\u0022slug\u0022:\u0022upington\u0022,\u0022count\u0022:6}]}]},{\u0022code\u0022:\u0022LS\u0022,\u0022name\u0022:\u0022Lesotho\u0022,\u0022count\u0022:3},{\u0022code\u0022:\u0022NA\u0022,\u0022name\u0022:\u0022Namibia\u0022,\u0022count\u0022:1},{\u0022code\u0022:\u0022BW\u0022,\u0022name\u0022:\u0022Botswana\u0022,\u0022count\u0022:3},{\u0022code\u0022:\u0022SZ\u0022,\u0022name\u0022:\u0022eSwatini\u0022,\u0022count\u0022:1},{\u0022code\u0022:\u0022ZW\u0022,\u0022name\u0022:\u0022Zimbabwe\u0022,\u0022count\u0022:0}]},\u0022sel\u0022:{\u0022country\u0022:null,\u0022province\u0022:null,\u0022city\u0022:null}}'))" 2010 @keydown.escape.window="closePanel()" 2011 @click.outside="closePanel()" 2012 class="relative" 2013> 2014 2015 2016 2017 2018 <div class="flex items-center gap-0.5"> 2019 2020 <!--[if BLOCK]><![endif]--> <button 2021 x-ref="pill" 2022 type="button"
2023 @click="openPanel()" 2024 :aria-expanded="open ? 'true' : 'false'" 2025 aria-haspopup="dialog" 2026 class="flex items-center gap-2 h-10 px-3 rounded-lg border text-sm font-medium transition focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[--brand-deep] 2027 border-rule bg-transparent text-ink-2 hover:bg-soft" 2028 2029 > 2030 <!--[if BLOCK]><![endif]--> <!--[if BLOCK]><![endif]--> <svg 2031 width="15" 2032 height="15" 2033 viewBox="0 0 24 24" 2034 fill="none" 2035 stroke="currentColor" 2036 stroke-width="1.8" 2037 stroke-linecap="round" 2038 stroke-linejoin="round" 2039 class="flex-shrink-0 text-muted shrink-0" 2040 ><circle cx="12" cy="12" r="10"/><path d="M12 2a14.5 14.5 0 0 0 0 20 14.5 14.5 0 0 0 0-20"/><path d="M2 12h20"/></svg> 2041<!--[if ENDBLOCK]><![endif]--> <!--[if ENDBLOCK]><![endif]--> 2042 <span class="text-ink-2 font-medium leading-none whitespace-nowrap">All of Southern Africa</span> 2043 2044 <!--[if BLOCK]><![endif]--><!--[if ENDBLOCK]><![endif]--> 2045 <!--[if BLOCK]><![endif]--> <!--[if BLOCK]><![endif]--> <svg 2046 width="14" 2047 height="14"
2048 viewBox="0 0 24 24" 2049 fill="none" 2050 stroke="currentColor" 2051 stroke-width="1.8" 2052 stroke-linecap="round" 2053 stroke-linejoin="round" 2054 class="flex-shrink-0 text-muted shrink-0" 2055 ><polyline points="6 9 12 15 18 9"/></svg> 2056<!--[if ENDBLOCK]><![endif]--> <!--[if ENDBLOCK]><![endif]--> </button> 2057 2058 2059 <!--[if BLOCK]><![endif]--><!--[if ENDBLOCK]><![endif]--> <!--[if ENDBLOCK]><![endif]--> 2060 </div> 2061 2062 2063 2064 2065 2066 <div 2067 x-cloak 2068 x-show="open && isDesktop" 2069 x-transition:enter="transition ease-out duration-[150ms]" 2070 x-transition:enter-start="opacity-0 scale-95 -translate-y-0.5" 2071 x-transition:enter-end="opacity-100 scale-100 translate-y-0" 2072 x-transition:leave="transition ease-in duration-100" 2073 x-transition:leave-start="opacity-100 scale-100" 2074 x-transition:leave-end="opacity-0 scale-95" 2075 class="absolute top-full mt-2 w-[348px] z-50 rounded-xl border overflow-hidden left-0" 2076 style="background:var(--surface);border-color:var(--geo-edge);box-shadow:0 0 0 1px var(--geo-ring), 0 18px 44px var(--geo-shadow)" 2077 role="dialog" 2078 aria-modal="false" 2079 aria-label="Location filter" 2080 > 2081 <div class="flex items-center min-h-12 px-3.5 border-b shrink-0 gap-2" style="border-color:var(--rule-soft)"> 2082 2083 2084 <span 2085 x-show="view.level === 'root'" 2086 class="text-sm font-medium" 2087 style="color:var(--ink-2)" 2088 > 2089 Southern Africa 2090 </span> 2091 2092 2093 <div x-show="view.level !== 'root'" class="flex items-center gap-2 w-full min-w-0"> 2094 2095 <button 2096 type="button" 2097 data-geo-item 2098 @click="back()" 2099 @keydown.arrow-down.prevent="focusNext()" 2100 @keydown.arrow-up.prevent="focusPrev()" 2101 class="flex items-center gap-1 text-sm font-medium shrink-0 rounded-md px-1 py-1 -ml-1 transition focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[--brand-deep]" 2102 style="color:var(--muted)" 2103 > 2104 <!--[if BLOCK]><![endif]--> <svg 2105 width="15" 2106 height="15"
2107 viewBox="0 0 24 24" 2108 fill="none" 2109 stroke="currentColor" 2110 stroke-width="1.8" 2111 stroke-linecap="round" 2112 stroke-linejoin="round" 2113 class="flex-shrink-0 shrink-0" 2114 ><polyline points="15 18 9 12 15 6"/></svg> 2115<!--[if ENDBLOCK]><![endif]--> Back 2116 </button> 2117 2118 <nav aria-label="Location breadcrumb" class="flex items-center gap-1 text-xs overflow-hidden min-w-0"> 2119 <button type="button" 2120 @click="view = { level: 'root', code: null, prov: null }; dir = -1" 2121 class="hover:underline transition truncate focus-visible:outline-none" 2122 style="color:var(--muted)" 2123 >Southern Africa</button> 2124 2125 <span x-show="view.level === 'country' || view.level === 'province'" style="color:var(--muted)">âº</span> 2126 2127 <button 2128 type="button" 2129 x-show="view.level === 'province'" 2130 @click="drillCountry('ZA'); dir = -1" 2131 class="hover:underline transition truncate focus-visible:outline-none" 2132 style="color:var(--muted)" 2133 >South Africa</button> 2134 2135 <span x-show="view.level === 'province'" style="color:var(--muted)">âº</span> 2136 2137 <span 2138 x-show="view.level === 'country'" 2139 class="font-semibold truncate" 2140 style="color:var(--ink)" 2141 >South Africa</span> 2142 2143 <span 2144 x-show="view.level === 'province'" 2145 class="font-semibold truncate" 2146 x-text="currentProvinceNode?.name || ''" 2147 style="color:var(--ink)" 2148 ></span> 2149 </nav> 2150 2151 <!--[if BLOCK]><![endif]--><!--[if ENDBLOCK]><![endif]--> </div> 2152 2153 <!--[if BLOCK]><![endif]--><!--[if ENDBLOCK]><![endif]--> 2154</div> 2155 2156 2157 2158<div 2159 class="overflow-y-auto overscroll-contain " 2160 style="max-height:432px" 2161 @keydown.arrow-down.prevent="focusNext()" 2162 @keydown.arrow-up.prevent="focusPrev()" 2163 @keydown.home.prevent="focusFirst()" 2164 @keydown.end.prevent="focusLast()" 2165> 2166 2167 2168 <div 2169 x-show="view.level === 'root'" 2170 :class="view.level === 'root' ? levelContentClass : ''" 2171 > 2172 2173 <div class="px-2 pt-2 pb-0"> 2174 <button 2175 type="button" 2176 data-geo-item 2177 @click="commitSel(null, null, null)" 2178 class="w-full flex items-center gap-[11px] px-3 rounded-lg text-left transition min-h-[44px] focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[--brand-deep]" 2179 :class="!sel.country ? 'bg-[--brand-soft]' : 'hover:bg-[--soft]'" 2180 > 2181 2182 <span class="inline-flex items-center justify-center w-[30px] h-[30px] rounded-full shrink-0" style="background:var(--soft-2);color:var(--muted)"> 2183 <!--[if BLOCK]><![endif]--> <svg 2184 width="15" 2185 height="15"
2186 viewBox="0 0 24 24" 2187 fill="none" 2188 stroke="currentColor" 2189 stroke-width="1.8" 2190 stroke-linecap="round" 2191 stroke-linejoin="round" 2192 class="flex-shrink-0" 2193 ><circle cx="12" cy="12" r="10"/><path d="M12 2a14.5 14.5 0 0 0 0 20 14.5 14.5 0 0 0 0-20"/><path d="M2 12h20"/></svg> 2194<!--[if ENDBLOCK]><![endif]--> </span> 2195 2196 <span class="flex-1 text-[14.5px] font-[500] leading-tight" :class="!sel.country ? 'font-[600]' : ''" style="color:var(--ink)"> 2197 All of Southern Africa 2198 </span> 2199 2200 <span class="ml-auto text-[12.5px] tabular-nums shrink-0" style="font-family:var(--font-mono);color:var(--muted)"> 2201 500 2202 </span> 2203 2204 <span class="shrink-0 w-4 h-4" :class="!sel.country ? 'opacity-100' : 'opacity-0'"> 2205 <!--[if BLOCK]><![endif]--> <svg 2206 width="17" 2207 height="17" 2208 viewBox="0 0 24 24" 2209 fill="none" 2210 stroke="currentColor" 2211 stroke-width="2.4" 2212 stroke-linecap="round" 2213 stroke-linejoin="round" 2214 style="color:var(--brand)" class="flex-shrink-0" 2215 ><polyline points="20 6 9 17 4 12"/></svg> 2216<!--[if ENDBLOCK]><![endif]--> </span> 2217 </button> 2218 </div> 2219 2220 2221 <p class="px-3.5 pt-3 pb-1.5 text-[10.5px] uppercase tracking-[0.1em] font-semibold" style="font-family:var(--font-mono);color:var(--muted)">Country</p> 2222 2223 2224 <div class="px-2 pb-2"> 2225 <template x-for="c in tree.countries" :key="c.code"> 2226 <button 2227 type="button" 2228 data-geo-item 2229 @click="c.code === 'ZA' ? drillCountry(c.code) : commitSel(c.code, null, null)" 2230 class="w-full flex items-center gap-[11px] px-3 rounded-lg text-left transition min-h-[44px] focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[--brand-deep]" 2231 :class="sel.country === c.code && c.code !== 'ZA' ? 'bg-[--brand-soft]' : 'hover:bg-[--soft]'" 2232 > 2233 2234 <span 2235 class="inline-flex items-center justify-center w-[30px] h-[30px] rounded-[6px] text-[11px] font-semibold shrink-0" 2236 style="font-family:var(--font-mono);background:var(--ink);color:var(--bg)" 2237 x-text="c.code" 2238 ></span> 2239 2240 <span 2241 class="flex-1 text-[14.5px] font-[500] leading-tight" 2242 :class="sel.country === c.code && c.code !== 'ZA' ? 'font-[600]' : ''" 2243 style="color:var(--ink)" 2244 x-text="c.name" 2245 ></span> 2246 2247 <span class="ml-auto text-[12.5px] tabular-nums shrink-0" style="font-family:var(--font-mono);color:var(--muted)" x-text="c.count"></span> 2248 2249 2250 <span class="shrink-0 w-4 h-4 flex items-center justify-center" style="color:var(--muted)"> 2251 <template x-if="c.code === 'ZA'"> 2252 <!--[if BLOCK]><![endif]--> <svg 2253 width="16" 2254 height="16"
2255 viewBox="0 0 24 24" 2256 fill="none" 2257 stroke="currentColor" 2258 stroke-width="1.8" 2259 stroke-linecap="round" 2260 stroke-linejoin="round" 2261 class="flex-shrink-0" 2262 ><polyline points="9 18 15 12 9 6"/></svg> 2263<!--[if ENDBLOCK]><![endif]--> </template> 2264 <template x-if="c.code !== 'ZA' && sel.country === c.code"> 2265 <!--[if BLOCK]><![endif]--> <svg 2266 width="17" 2267 height="17" 2268 viewBox="0 0 24 24" 2269 fill="none" 2270 stroke="currentColor" 2271 stroke-width="2.4" 2272 stroke-linecap="round" 2273 stroke-linejoin="round" 2274 style="color:var(--brand)" class="flex-shrink-0" 2275 ><polyline points="20 6 9 17 4 12"/></svg> 2276<!--[if ENDBLOCK]><![endif]--> </template> 2277 </span> 2278 </button> 2279 </template> 2280 </div> 2281 </div> 2282 2283 2284 2285 <div 2286 x-show="view.level === 'country'" 2287 :class="view.level === 'country' ? levelContentClass : ''" 2288 > 2289 2290 <div class="px-2 pt-2 pb-0"> 2291 <button 2292 type="button" 2293 data-geo-item 2294 @click="commitSel('ZA', null, null)" 2295 class="w-full flex items-center gap-[11px] px-3 rounded-lg text-left transition min-h-[44px] focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[--brand-deep]" 2296 :class="sel.country === 'ZA' && !sel.province ? 'bg-[--brand-soft]' : 'hover:bg-[--soft]'" 2297 > 2298 <span class="inline-flex items-center justify-center w-[30px] h-[30px] rounded-full shrink-0" style="background:var(--soft-2);color:var(--muted)"> 2299 <!--[if BLOCK]><![endif]--> <svg 2300 width="15" 2301 height="15"
2302 viewBox="0 0 24 24" 2303 fill="none" 2304 stroke="currentColor" 2305 stroke-width="1.8" 2306 stroke-linecap="round" 2307 stroke-linejoin="round" 2308 class="flex-shrink-0" 2309 ><circle cx="12" cy="12" r="10"/><path d="M12 2a14.5 14.5 0 0 0 0 20 14.5 14.5 0 0 0 0-20"/><path d="M2 12h20"/></svg> 2310<!--[if ENDBLOCK]><![endif]--> </span> 2311 <span 2312 class="flex-1 text-[14.5px] font-[500] leading-tight" 2313 :class="sel.country === 'ZA' && !sel.province ? 'font-[600]' : ''" 2314 style="color:var(--ink)" 2315 >All of South Africa</span> 2316 <span class="ml-auto text-[12.5px] tabular-nums shrink-0" style="font-family:var(--font-mono);color:var(--muted)" x-text="currentCountryNode?.count"></span> 2317 <span class="shrink-0 w-4 h-4" :class="sel.country === 'ZA' && !sel.province ? 'opacity-100' : 'opacity-0'"> 2318 <!--[if BLOCK]><![endif]--> <svg 2319 width="17" 2320 height="17"
2321 viewBox="0 0 24 24" 2322 fill="none" 2323 stroke="currentColor" 2324 stroke-width="2.4" 2325 stroke-linecap="round" 2326 stroke-linejoin="round" 2327 style="color:var(--brand)" class="flex-shrink-0" 2328 ><polyline points="20 6 9 17 4 12"/></svg> 2329<!--[if ENDBLOCK]><![endif]--> </span> 2330 </button> 2331 </div> 2332 2333 <p class="px-3.5 pt-3 pb-1.5 text-[10.5px] uppercase tracking-[0.1em] font-semibold" style="font-family:var(--font-mono);color:var(--muted)">Province</p> 2334 2335 <div class="px-2 pb-2"> 2336 <template x-for="p in (currentCountryNode?.provinces || [])" :key="p.slug"> 2337 <button 2338 type="button" 2339 data-geo-item 2340 @click="_provCityCount(p) > 1 ? drillProvince(p.slug) : commitSel('ZA', p.slug, null)" 2341 class="w-full flex items-center gap-[11px] px-3 rounded-lg text-left transition min-h-[44px] focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[--brand-deep]" 2342 :class="sel.province === p.slug && _provCityCount(p) <= 1 ? 'bg-[--brand-soft]' : 'hover:bg-[--soft]'" 2343 > 2344 2345 <span 2346 class="inline-flex items-center justify-center w-[30px] h-[30px] rounded-[6px] text-[11px] font-semibold shrink-0 border" 2347 style="font-family:var(--font-mono);background:var(--brand-soft);color:var(--brand-deeper);border-color:var(--brand-line)" 2348 x-text="p.code || p.slug.slice(0,2).toUpperCase()" 2349 ></span> 2350 2351 <span class="flex-1 min-w-0"> 2352 <span 2353 class="block text-[14.5px] font-[500] leading-tight truncate" 2354 :class="sel.province === p.slug ? 'font-[600]' : ''" 2355 style="color:var(--ink)" 2356 x-text="p.name" 2357 ></span> 2358 <small 2359 x-show="p.soleCity" 2360 class="block text-xs leading-tight truncate" 2361 style="color:var(--muted)" 2362 x-text="p.soleCity" 2363 ></small> 2364 </span> 2365 2366 <span class="ml-auto text-[12.5px] tabular-nums shrink-0" style="font-family:var(--font-mono);color:var(--muted)" x-text="p.count"></span> 2367 2368 <span class="shrink-0 w-4 h-4 flex items-center justify-center" style="color:var(--muted)"> 2369 <template x-if="_provCityCount(p) > 1"> 2370 <!--[if BLOCK]><![endif]--> <svg 2371 width="16" 2372 height="16"
2373 viewBox="0 0 24 24" 2374 fill="none" 2375 stroke="currentColor" 2376 stroke-width="1.8" 2377 stroke-linecap="round" 2378 stroke-linejoin="round" 2379 class="flex-shrink-0" 2380 ><polyline points="9 18 15 12 9 6"/></svg> 2381<!--[if ENDBLOCK]><![endif]--> </template> 2382 <template x-if="_provCityCount(p) <= 1 && sel.province === p.slug"> 2383 <!--[if BLOCK]><![endif]--> <svg 2384 width="17" 2385 height="17" 2386 viewBox="0 0 24 24" 2387 fill="none" 2388 stroke="currentColor" 2389 stroke-width="2.4" 2390 stroke-linecap="round" 2391 stroke-linejoin="round" 2392 style="color:var(--brand)" class="flex-shrink-0" 2393 ><polyline points="20 6 9 17 4 12"/></svg> 2394<!--[if ENDBLOCK]><![endif]--> </template> 2395 </span> 2396 </button> 2397 </template> 2398 </div> 2399 </div> 2400 2401 2402 2403 <div 2404 x-show="view.level === 'province'" 2405 :class="view.level === 'province' ? levelContentClass : ''" 2406 > 2407 2408 <div class="px-2 pt-2 pb-0"> 2409 <button 2410 type="button" 2411 data-geo-item 2412 @click="commitSel('ZA', view.prov, null)" 2413 class="w-full flex items-center gap-[11px] px-3 rounded-lg text-left transition min-h-[44px] focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[--brand-deep]" 2414 :class="sel.province === view.prov && !sel.city ? 'bg-[--brand-soft]' : 'hover:bg-[--soft]'" 2415 > 2416 <span class="inline-flex items-center justify-center w-[30px] h-[30px] rounded-full shrink-0" style="background:var(--soft-2);color:var(--muted)"> 2417 <!--[if BLOCK]><![endif]--> <svg 2418 width="15" 2419 height="15"
2420 viewBox="0 0 24 24" 2421 fill="none" 2422 stroke="currentColor" 2423 stroke-width="1.8" 2424 stroke-linecap="round" 2425 stroke-linejoin="round" 2426 class="flex-shrink-0" 2427 ><circle cx="12" cy="12" r="10"/><path d="M12 2a14.5 14.5 0 0 0 0 20 14.5 14.5 0 0 0 0-20"/><path d="M2 12h20"/></svg> 2428<!--[if ENDBLOCK]><![endif]--> </span> 2429 <span 2430 class="flex-1 text-[14.5px] font-[500] leading-tight" 2431 :class="sel.province === view.prov && !sel.city ? 'font-[600]' : ''" 2432 style="color:var(--ink)" 2433 >All of <span x-text="currentProvinceNode?.name || ''"></span></span> 2434 <span class="ml-auto text-[12.5px] tabular-nums shrink-0" style="font-family:var(--font-mono);color:var(--muted)" x-text="currentProvinceNode?.count"></span> 2435 <span class="shrink-0 w-4 h-4" :class="sel.province === view.prov && !sel.city ? 'opacity-100' : 'opacity-0'"> 2436 <!--[if BLOCK]><![endif]--> <svg 2437 width="17" 2438 height="17"
2439 viewBox="0 0 24 24" 2440 fill="none" 2441 stroke="currentColor" 2442 stroke-width="2.4" 2443 stroke-linecap="round" 2444 stroke-linejoin="round" 2445 style="color:var(--brand)" class="flex-shrink-0" 2446 ><polyline points="20 6 9 17 4 12"/></svg> 2447<!--[if ENDBLOCK]><![endif]--> </span> 2448 </button> 2449 </div> 2450 2451 <p class="px-3.5 pt-3 pb-1.5 text-[10.5px] uppercase tracking-[0.1em] font-semibold" style="font-family:var(--font-mono);color:var(--muted)">City</p> 2452 2453 <div class="px-2 pb-2"> 2454 <template x-for="ci in (currentProvinceNode?.cities || [])" :key="ci.slug"> 2455 <button 2456 type="button" 2457 data-geo-item 2458 @click="commitSel('ZA', view.prov, ci.slug)" 2459 class="w-full flex items-center gap-[11px] px-3 rounded-lg text-left transition min-h-[44px] focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[--brand-deep]" 2460 :class="sel.city === ci.slug ? 'bg-[--brand-soft]' : 'hover:bg-[--soft]'" 2461 > 2462 2463 <span class="inline-flex items-center justify-center w-[30px] h-[30px] rounded-full shrink-0" style="background:var(--soft-2);color:var(--muted)"> 2464 <!--[if BLOCK]><![endif]--> <svg 2465 width="14" 2466 height="14"
2467 viewBox="0 0 24 24" 2468 fill="none" 2469 stroke="currentColor" 2470 stroke-width="1.8" 2471 stroke-linecap="round" 2472 stroke-linejoin="round" 2473 class="flex-shrink-0" 2474 ><path d="M20 10c0 4.993-5.539 10.193-7.399 11.799a1 1 0 0 1-1.202 0C9.539 20.193 4 14.993 4 10a8 8 0 0 1 16 0"/><circle cx="12" cy="10" r="3"/></svg> 2475<!--[if ENDBLOCK]><![endif]--> </span> 2476 2477 <span 2478 class="flex-1 text-[14.5px] font-[500] leading-tight" 2479 :class="sel.city === ci.slug ? 'font-[600]' : ''" 2480 style="color:var(--ink)" 2481 x-text="ci.name" 2482 ></span> 2483 2484 <span class="ml-auto text-[12.5px] tabular-nums shrink-0" style="font-family:var(--font-mono);color:var(--muted)" x-text="ci.count"></span> 2485 2486 <span class="shrink-0 w-4 h-4" :class="sel.city === ci.slug ? 'opacity-100' : 'opacity-0'"> 2487 <!--[if BLOCK]><![endif]--> <svg 2488 width="17" 2489 height="17"
2490 viewBox="0 0 24 24" 2491 fill="none" 2492 stroke="currentColor" 2493 stroke-width="2.4" 2494 stroke-linecap="round" 2495 stroke-linejoin="round" 2496 style="color:var(--brand)" class="flex-shrink-0" 2497 ><polyline points="20 6 9 17 4 12"/></svg> 2498<!--[if ENDBLOCK]><![endif]--> </span> 2499 </button> 2500 </template> 2501 </div> 2502 </div> 2503 2504</div> </div> 2505 2506 2507 2508 2509 2510 <div 2511 x-cloak 2512 x-show="open && !isDesktop" 2513 @click="closePanel()" 2514 x-transition:enter="transition-opacity duration-200" 2515 x-transition:enter-start="opacity-0" 2516 x-transition:enter-end="opacity-100" 2517 x-transition:leave="transition-opacity duration-200" 2518 x-transition:leave-start="opacity-100" 2519 x-transition:leave-end="opacity-0" 2520 class="fixed inset-0 z-[200]" 2521 style="background:rgba(10,22,40,.45)" 2522 aria-hidden="true" 2523 ></div> 2524 2525 2526 2527 2528 2529 <div 2530 x-cloak 2531 x-show="open && !isDesktop" 2532 x-transition:enter="transition-transform ease-[cubic-bezier(.2,.8,.25,1)] duration-[260ms] motion-reduce:duration-0" 2533 x-transition:enter-start="translate-y-full" 2534 x-transition:enter-end="translate-y-0" 2535 x-transition:leave="transition-transform ease-in duration-200 motion-reduce:duration-0" 2536 x-transition:leave-start="translate-y-0" 2537 x-transition:leave-end="translate-y-full" 2538 class="fixed inset-x-0 bottom-0 z-[201] flex flex-col overflow-hidden" 2539 style="border-radius:18px 18px 0 0;background:var(--surface);max-height:86dvh" 2540 role="dialog" 2541 aria-modal="true" 2542 aria-label="Location filter" 2543 > 2544 2545 <div class="shrink-0 w-10 h-1 rounded-full mx-auto mt-2.5" style="background:var(--rule)"></div> 2546 2547 <div class="flex items-center min-h-12 px-3.5 border-b shrink-0 gap-2" style="border-color:var(--rule-soft)"> 2548 2549 2550 <span 2551 x-show="view.level === 'root'" 2552 class="text-sm font-medium" 2553 style="color:var(--ink-2)" 2554 > 2555 Southern Africa 2556 </span> 2557 2558 2559 <div x-show="view.level !== 'root'" class="flex items-center gap-2 w-full min-w-0"> 2560 2561 <button 2562 type="button" 2563 data-geo-item 2564 @click="back()" 2565 @keydown.arrow-down.prevent="focusNext()" 2566 @keydown.arrow-up.prevent="focusPrev()" 2567 class="flex items-center gap-1 text-sm font-medium shrink-0 rounded-md px-1 py-1 -ml-1 transition focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[--brand-deep]" 2568 style="color:var(--muted)" 2569 > 2570 <!--[if BLOCK]><![endif]--> <svg 2571 width="15" 2572 height="15"
2573 viewBox="0 0 24 24" 2574 fill="none" 2575 stroke="currentColor" 2576 stroke-width="1.8" 2577 stroke-linecap="round" 2578 stroke-linejoin="round" 2579 class="flex-shrink-0 shrink-0" 2580 ><polyline points="15 18 9 12 15 6"/></svg> 2581<!--[if ENDBLOCK]><![endif]--> Back 2582 </button> 2583 2584 <nav aria-label="Location breadcrumb" class="flex items-center gap-1 text-xs overflow-hidden min-w-0"> 2585 <button type="button" 2586 @click="view = { level: 'root', code: null, prov: null }; dir = -1" 2587 class="hover:underline transition truncate focus-visible:outline-none" 2588 style="color:var(--muted)" 2589 >Southern Africa</button> 2590 2591 <span x-show="view.level === 'country' || view.level === 'province'" style="color:var(--muted)">âº</span> 2592 2593 <button 2594 type="button" 2595 x-show="view.level === 'province'" 2596 @click="drillCountry('ZA'); dir = -1" 2597 class="hover:underline transition truncate focus-visible:outline-none" 2598 style="color:var(--muted)" 2599 >South Africa</button> 2600 2601 <span x-show="view.level === 'province'" style="color:var(--muted)">âº</span> 2602 2603 <span 2604 x-show="view.level === 'country'" 2605 class="font-semibold truncate" 2606 style="color:var(--ink)" 2607 >South Africa</span> 2608 2609 <span 2610 x-show="view.level === 'province'" 2611 class="font-semibold truncate" 2612 x-text="currentProvinceNode?.name || ''" 2613 style="color:var(--ink)" 2614 ></span> 2615 </nav> 2616 2617 <!--[if BLOCK]><![endif]--> 2618 <button 2619 type="button" 2620 @click="closePanel()" 2621 class="ml-auto shrink-0 w-[34px] h-[34px] rounded-full border flex items-center justify-center transition focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[--brand-deep]" 2622 style="border-color:var(--rule);color:var(--muted)" 2623 aria-label="Close" 2624 > 2625 <!--[if BLOCK]><![endif]--> <svg 2626 width="17" 2627 height="17"
2628 viewBox="0 0 24 24" 2629 fill="none" 2630 stroke="currentColor" 2631 stroke-width="1.8" 2632 stroke-linecap="round" 2633 stroke-linejoin="round" 2634 class="flex-shrink-0" 2635 ><line x1="18" x2="6" y1="6" y2="18"/><line x1="6" x2="18" y1="6" y2="18"/></svg> 2636<!--[if ENDBLOCK]><![endif]--> </button> 2637 <!--[if ENDBLOCK]><![endif]--> </div> 2638 2639 <!--[if BLOCK]><![endif]--> 2640 <button 2641 type="button" 2642 x-show="view.level === 'root'" 2643 @click="closePanel()" 2644 class="ml-auto shrink-0 w-[34px] h-[34px] rounded-full border flex items-center justify-center transition focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[--brand-deep]" 2645 style="border-color:var(--rule);color:var(--muted)" 2646 aria-label="Close" 2647 > 2648 <!--[if BLOCK]><![endif]--> <svg 2649 width="17" 2650 height="17" 2651 viewBox="0 0 24 24" 2652 fill="none" 2653 stroke="currentColor" 2654 stroke-width="1.8" 2655 stroke-linecap="round" 2656 stroke-linejoin="round" 2657 class="flex-shrink-0" 2658 ><line x1="18" x2="6" y1="6" y2="18"/><line x1="6" x2="18" y1="6" y2="18"/></svg> 2659<!--[if ENDBLOCK]><![endif]--> </button> 2660 <!--[if ENDBLOCK]><![endif]--> 2661</div> 2662 2663 2664 2665<div 2666 class="overflow-y-auto overscroll-contain flex-1" 2667 style="" 2668 @keydown.arrow-down.prevent="focusNext()" 2669 @keydown.arrow-up.prevent="focusPrev()" 2670 @keydown.home.prevent="focusFirst()" 2671 @keydown.end.prevent="focusLast()" 2672> 2673 2674 2675 <div 2676 x-show="view.level === 'root'" 2677 :class="view.level === 'root' ? levelContentClass : ''" 2678 > 2679 2680 <div class="px-2 pt-2 pb-0"> 2681 <button 2682 type="button" 2683 data-geo-item 2684 @click="commitSel(null, null, null)" 2685 class="w-full flex items-center gap-[11px] px-3 rounded-lg text-left transition min-h-[44px] focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[--brand-deep]" 2686 :class="!sel.country ? 'bg-[--brand-soft]' : 'hover:bg-[--soft]'" 2687 > 2688 2689 <span class="inline-flex items-center justify-center w-[30px] h-[30px] rounded-full shrink-0" style="background:var(--soft-2);color:var(--muted)"> 2690 <!--[if BLOCK]><![endif]--> <svg 2691 width="15" 2692 height="15"
2693 viewBox="0 0 24 24" 2694 fill="none" 2695 stroke="currentColor" 2696 stroke-width="1.8" 2697 stroke-linecap="round" 2698 stroke-linejoin="round" 2699 class="flex-shrink-0" 2700 ><circle cx="12" cy="12" r="10"/><path d="M12 2a14.5 14.5 0 0 0 0 20 14.5 14.5 0 0 0 0-20"/><path d="M2 12h20"/></svg> 2701<!--[if ENDBLOCK]><![endif]--> </span> 2702 2703 <span class="flex-1 text-[14.5px] font-[500] leading-tight" :class="!sel.country ? 'font-[600]' : ''" style="color:var(--ink)"> 2704 All of Southern Africa 2705 </span> 2706 2707 <span class="ml-auto text-[12.5px] tabular-nums shrink-0" style="font-family:var(--font-mono);color:var(--muted)"> 2708 500 2709 </span> 2710 2711 <span class="shrink-0 w-4 h-4" :class="!sel.country ? 'opacity-100' : 'opacity-0'"> 2712 <!--[if BLOCK]><![endif]--> <svg 2713 width="17" 2714 height="17" 2715 viewBox="0 0 24 24" 2716 fill="none" 2717 stroke="currentColor" 2718 stroke-width="2.4" 2719 stroke-linecap="round" 2720 stroke-linejoin="round" 2721 style="color:var(--brand)" class="flex-shrink-0" 2722 ><polyline points="20 6 9 17 4 12"/></svg> 2723<!--[if ENDBLOCK]><![endif]--> </span> 2724 </button> 2725 </div> 2726 2727 2728 <p class="px-3.5 pt-3 pb-1.5 text-[10.5px] uppercase tracking-[0.1em] font-semibold" style="font-family:var(--font-mono);color:var(--muted)">Country</p> 2729 2730 2731 <div class="px-2 pb-2"> 2732 <template x-for="c in tree.countries" :key="c.code"> 2733 <button 2734 type="button" 2735 data-geo-item 2736 @click="c.code === 'ZA' ? drillCountry(c.code) : commitSel(c.code, null, null)" 2737 class="w-full flex items-center gap-[11px] px-3 rounded-lg text-left transition min-h-[44px] focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[--brand-deep]" 2738 :class="sel.country === c.code && c.code !== 'ZA' ? 'bg-[--brand-soft]' : 'hover:bg-[--soft]'" 2739 > 2740 2741 <span 2742 class="inline-flex items-center justify-center w-[30px] h-[30px] rounded-[6px] text-[11px] font-semibold shrink-0" 2743 style="font-family:var(--font-mono);background:var(--ink);color:var(--bg)" 2744 x-text="c.code" 2745 ></span> 2746 2747 <span 2748 class="flex-1 text-[14.5px] font-[500] leading-tight" 2749 :class="sel.country === c.code && c.code !== 'ZA' ? 'font-[600]' : ''" 2750 style="color:var(--ink)" 2751 x-text="c.name" 2752 ></span> 2753 2754 <span class="ml-auto text-[12.5px] tabular-nums shrink-0" style="font-family:var(--font-mono);color:var(--muted)" x-text="c.count"></span> 2755 2756 2757 <span class="shrink-0 w-4 h-4 flex items-center justify-center" style="color:var(--muted)"> 2758 <template x-if="c.code === 'ZA'"> 2759 <!--[if BLOCK]><![endif]--> <svg 2760 width="16" 2761 height="16"
2762 viewBox="0 0 24 24" 2763 fill="none" 2764 stroke="currentColor" 2765 stroke-width="1.8" 2766 stroke-linecap="round" 2767 stroke-linejoin="round" 2768 class="flex-shrink-0" 2769 ><polyline points="9 18 15 12 9 6"/></svg> 2770<!--[if ENDBLOCK]><![endif]--> </template> 2771 <template x-if="c.code !== 'ZA' && sel.country === c.code"> 2772 <!--[if BLOCK]><![endif]--> <svg 2773 width="17" 2774 height="17" 2775 viewBox="0 0 24 24" 2776 fill="none" 2777 stroke="currentColor" 2778 stroke-width="2.4" 2779 stroke-linecap="round" 2780 stroke-linejoin="round" 2781 style="color:var(--brand)" class="flex-shrink-0" 2782 ><polyline points="20 6 9 17 4 12"/></svg> 2783<!--[if ENDBLOCK]><![endif]--> </template> 2784 </span> 2785 </button> 2786 </template> 2787 </div> 2788 </div> 2789 2790 2791 2792 <div 2793 x-show="view.level === 'country'" 2794 :class="view.level === 'country' ? levelContentClass : ''" 2795 > 2796 2797 <div class="px-2 pt-2 pb-0"> 2798 <button 2799 type="button" 2800 data-geo-item 2801 @click="commitSel('ZA', null, null)" 2802 class="w-full flex items-center gap-[11px] px-3 rounded-lg text-left transition min-h-[44px] focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[--brand-deep]" 2803 :class="sel.country === 'ZA' && !sel.province ? 'bg-[--brand-soft]' : 'hover:bg-[--soft]'" 2804 > 2805 <span class="inline-flex items-center justify-center w-[30px] h-[30px] rounded-full shrink-0" style="background:var(--soft-2);color:var(--muted)"> 2806 <!--[if BLOCK]><![endif]--> <svg 2807 width="15" 2808 height="15"
2809 viewBox="0 0 24 24" 2810 fill="none" 2811 stroke="currentColor" 2812 stroke-width="1.8" 2813 stroke-linecap="round" 2814 stroke-linejoin="round" 2815 class="flex-shrink-0" 2816 ><circle cx="12" cy="12" r="10"/><path d="M12 2a14.5 14.5 0 0 0 0 20 14.5 14.5 0 0 0 0-20"/><path d="M2 12h20"/></svg> 2817<!--[if ENDBLOCK]><![endif]--> </span> 2818 <span 2819 class="flex-1 text-[14.5px] font-[500] leading-tight" 2820 :class="sel.country === 'ZA' && !sel.province ? 'font-[600]' : ''" 2821 style="color:var(--ink)" 2822 >All of South Africa</span> 2823 <span class="ml-auto text-[12.5px] tabular-nums shrink-0" style="font-family:var(--font-mono);color:var(--muted)" x-text="currentCountryNode?.count"></span> 2824 <span class="shrink-0 w-4 h-4" :class="sel.country === 'ZA' && !sel.province ? 'opacity-100' : 'opacity-0'"> 2825 <!--[if BLOCK]><![endif]--> <svg 2826 width="17" 2827 height="17"
2828 viewBox="0 0 24 24" 2829 fill="none" 2830 stroke="currentColor" 2831 stroke-width="2.4" 2832 stroke-linecap="round" 2833 stroke-linejoin="round" 2834 style="color:var(--brand)" class="flex-shrink-0" 2835 ><polyline points="20 6 9 17 4 12"/></svg> 2836<!--[if ENDBLOCK]><![endif]--> </span> 2837 </button> 2838 </div> 2839 2840 <p class="px-3.5 pt-3 pb-1.5 text-[10.5px] uppercase tracking-[0.1em] font-semibold" style="font-family:var(--font-mono);color:var(--muted)">Province</p> 2841 2842 <div class="px-2 pb-2"> 2843 <template x-for="p in (currentCountryNode?.provinces || [])" :key="p.slug"> 2844 <button 2845 type="button" 2846 data-geo-item 2847 @click="_provCityCount(p) > 1 ? drillProvince(p.slug) : commitSel('ZA', p.slug, null)" 2848 class="w-full flex items-center gap-[11px] px-3 rounded-lg text-left transition min-h-[44px] focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[--brand-deep]" 2849 :class="sel.province === p.slug && _provCityCount(p) <= 1 ? 'bg-[--brand-soft]' : 'hover:bg-[--soft]'" 2850 > 2851 2852 <span 2853 class="inline-flex items-center justify-center w-[30px] h-[30px] rounded-[6px] text-[11px] font-semibold shrink-0 border" 2854 style="font-family:var(--font-mono);background:var(--brand-soft);color:var(--brand-deeper);border-color:var(--brand-line)" 2855 x-text="p.code || p.slug.slice(0,2).toUpperCase()" 2856 ></span> 2857 2858 <span class="flex-1 min-w-0"> 2859 <span 2860 class="block text-[14.5px] font-[500] leading-tight truncate" 2861 :class="sel.province === p.slug ? 'font-[600]' : ''" 2862 style="color:var(--ink)" 2863 x-text="p.name" 2864 ></span> 2865 <small 2866 x-show="p.soleCity" 2867 class="block text-xs leading-tight truncate" 2868 style="color:var(--muted)" 2869 x-text="p.soleCity" 2870 ></small> 2871 </span> 2872 2873 <span class="ml-auto text-[12.5px] tabular-nums shrink-0" style="font-family:var(--font-mono);color:var(--muted)" x-text="p.count"></span> 2874 2875 <span class="shrink-0 w-4 h-4 flex items-center justify-center" style="color:var(--muted)"> 2876 <template x-if="_provCityCount(p) > 1"> 2877 <!--[if BLOCK]><![endif]--> <svg 2878 width="16" 2879 height="16"
2880 viewBox="0 0 24 24" 2881 fill="none" 2882 stroke="currentColor" 2883 stroke-width="1.8" 2884 stroke-linecap="round" 2885 stroke-linejoin="round" 2886 class="flex-shrink-0" 2887 ><polyline points="9 18 15 12 9 6"/></svg> 2888<!--[if ENDBLOCK]><![endif]--> </template> 2889 <template x-if="_provCityCount(p) <= 1 && sel.province === p.slug"> 2890 <!--[if BLOCK]><![endif]--> <svg 2891 width="17" 2892 height="17" 2893 viewBox="0 0 24 24" 2894 fill="none" 2895 stroke="currentColor" 2896 stroke-width="2.4" 2897 stroke-linecap="round" 2898 stroke-linejoin="round" 2899 style="color:var(--brand)" class="flex-shrink-0" 2900 ><polyline points="20 6 9 17 4 12"/></svg> 2901<!--[if ENDBLOCK]><![endif]--> </template> 2902 </span> 2903 </button> 2904 </template> 2905 </div> 2906 </div> 2907 2908 2909 2910 <div 2911 x-show="view.level === 'province'" 2912 :class="view.level === 'province' ? levelContentClass : ''" 2913 > 2914 2915 <div class="px-2 pt-2 pb-0"> 2916 <button 2917 type="button" 2918 data-geo-item 2919 @click="commitSel('ZA', view.prov, null)" 2920 class="w-full flex items-center gap-[11px] px-3 rounded-lg text-left transition min-h-[44px] focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[--brand-deep]" 2921 :class="sel.province === view.prov && !sel.city ? 'bg-[--brand-soft]' : 'hover:bg-[--soft]'" 2922 > 2923 <span class="inline-flex items-center justify-center w-[30px] h-[30px] rounded-full shrink-0" style="background:var(--soft-2);color:var(--muted)"> 2924 <!--[if BLOCK]><![endif]--> <svg 2925 width="15" 2926 height="15"
2927 viewBox="0 0 24 24" 2928 fill="none" 2929 stroke="currentColor" 2930 stroke-width="1.8" 2931 stroke-linecap="round" 2932 stroke-linejoin="round" 2933 class="flex-shrink-0" 2934 ><circle cx="12" cy="12" r="10"/><path d="M12 2a14.5 14.5 0 0 0 0 20 14.5 14.5 0 0 0 0-20"/><path d="M2 12h20"/></svg> 2935<!--[if ENDBLOCK]><![endif]--> </span> 2936 <span 2937 class="flex-1 text-[14.5px] font-[500] leading-tight" 2938 :class="sel.province === view.prov && !sel.city ? 'font-[600]' : ''" 2939 style="color:var(--ink)" 2940 >All of <span x-text="currentProvinceNode?.name || ''"></span></span> 2941 <span class="ml-auto text-[12.5px] tabular-nums shrink-0" style="font-family:var(--font-mono);color:var(--muted)" x-text="currentProvinceNode?.count"></span> 2942 <span class="shrink-0 w-4 h-4" :class="sel.province === view.prov && !sel.city ? 'opacity-100' : 'opacity-0'"> 2943 <!--[if BLOCK]><![endif]--> <svg 2944 width="17" 2945 height="17"
2946 viewBox="0 0 24 24" 2947 fill="none" 2948 stroke="currentColor" 2949 stroke-width="2.4" 2950 stroke-linecap="round" 2951 stroke-linejoin="round" 2952 style="color:var(--brand)" class="flex-shrink-0" 2953 ><polyline points="20 6 9 17 4 12"/></svg> 2954<!--[if ENDBLOCK]><![endif]--> </span> 2955 </button> 2956 </div> 2957 2958 <p class="px-3.5 pt-3 pb-1.5 text-[10.5px] uppercase tracking-[0.1em] font-semibold" style="font-family:var(--font-mono);color:var(--muted)">City</p> 2959 2960 <div class="px-2 pb-2"> 2961 <template x-for="ci in (currentProvinceNode?.cities || [])" :key="ci.slug"> 2962 <button 2963 type="button" 2964 data-geo-item 2965 @click="commitSel('ZA', view.prov, ci.slug)" 2966 class="w-full flex items-center gap-[11px] px-3 rounded-lg text-left transition min-h-[44px] focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[--brand-deep]" 2967 :class="sel.city === ci.slug ? 'bg-[--brand-soft]' : 'hover:bg-[--soft]'" 2968 > 2969 2970 <span class="inline-flex items-center justify-center w-[30px] h-[30px] rounded-full shrink-0" style="background:var(--soft-2);color:var(--muted)"> 2971 <!--[if BLOCK]><![endif]--> <svg 2972 width="14" 2973 height="14"
2974 viewBox="0 0 24 24" 2975 fill="none" 2976 stroke="currentColor" 2977 stroke-width="1.8" 2978 stroke-linecap="round" 2979 stroke-linejoin="round" 2980 class="flex-shrink-0" 2981 ><path d="M20 10c0 4.993-5.539 10.193-7.399 11.799a1 1 0 0 1-1.202 0C9.539 20.193 4 14.993 4 10a8 8 0 0 1 16 0"/><circle cx="12" cy="10" r="3"/></svg> 2982<!--[if ENDBLOCK]><![endif]--> </span> 2983 2984 <span 2985 class="flex-1 text-[14.5px] font-[500] leading-tight" 2986 :class="sel.city === ci.slug ? 'font-[600]' : ''" 2987 style="color:var(--ink)" 2988 x-text="ci.name" 2989 ></span> 2990 2991 <span class="ml-auto text-[12.5px] tabular-nums shrink-0" style="font-family:var(--font-mono);color:var(--muted)" x-text="ci.count"></span> 2992 2993 <span class="shrink-0 w-4 h-4" :class="sel.city === ci.slug ? 'opacity-100' : 'opacity-0'"> 2994 <!--[if BLOCK]><![endif]--> <svg 2995 width="17" 2996 height="17"
2997 viewBox="0 0 24 24" 2998 fill="none" 2999 stroke="currentColor" 3000 stroke-width="2.4" 3001 stroke-linecap="round" 3002 stroke-linejoin="round" 3003 style="color:var(--brand)" class="flex-shrink-0" 3004 ><polyline points="20 6 9 17 4 12"/></svg> 3005<!--[if ENDBLOCK]><![endif]--> </span> 3006 </button> 3007 </template> 3008 </div> 3009 </div> 3010 3011</div> </div> 3012 3013 3014 3015</div> </div> 3016 3017 3018 <p class="font-mono uppercase text-muted pt-3 pb-1" style="font-size:10.5px;letter-spacing:.12em">For organisers</p> 3019 <a href="https://runningcalendar.co.za/organisers#submit" @click="drawerOpen = false" class="flex items-center justify-between py-2.5 text-[15px] font-medium text-ink hover:text-brand-deeper transition"> 3020 List an event 3021 <span class="px-1.5 py-0.5 text-[10px] font-bold rounded uppercase" style="background:var(--st-verified);color:#fff">FREE</span> 3022 </a> 3023 <a href="https://runningcalendar.co.za/organisers#verification" @click="drawerOpen = false" class="block py-2.5 text-[15px] font-medium text-ink hover:text-brand-deeper transition">Verification</a> 3024 <a href="https://runningcalendar.co.za/organisers#premium" @click="drawerOpen = false" class="block py-2.5 text-[15px] font-medium text-ink hover:text-brand-deeper transition">Premium listing</a> 3025 3026 3027 <p class="font-mono uppercase text-muted pt-3 pb-1" style="font-size:10.5px;letter-spacing:.12em">Advertise</p> 3028 <a href="https://runningcalendar.co.za/advertise#rates" @click="drawerOpen = false" class="block py-2.5 text-[15px] font-medium text-ink hover:text-brand-deeper transition">Rates & audience</a> 3029 <a href="https://runningcalendar.co.za/advertise#featured" @click="drawerOpen = false" class="block py-2.5 text-[15px] font-medium text-ink hover:text-brand-deeper transition">Featured placement</a> 3030 <a href="https://runningcalendar.co.za/advertise#enquire" @click="drawerOpen = false" class="block py-2.5 text-[15px] font-medium text-ink hover:text-brand-deeper transition">Enquire</a> 3031 3032 3033 <p class="font-mono uppercase text-muted pt-3 pb-1" style="font-size:10.5px;letter-spacing:.12em">Resources</p> 3034 <a href="https://runningcalendar.co.za/articles" @click="drawerOpen = false" class="block py-2.5 text-[15px] font-medium text-ink hover:text-brand-deeper transition">Articles</a> 3035 <a href="https://runningcalendar.co.za/training-programs" @click="drawerOpen = false" class="block py-2.5 text-[15px] font-medium text-ink hover:text-brand-deeper transition">Training Programs</a> 3036 <a href="https://runningcalendar.co.za/ad-free" @click="drawerOpen = false" class="block py-2.5 text-[15px] font-medium text-ink hover:text-brand-deeper transition">Ad-free · R29/mo</a> 3037 3038 3039 <div class="mt-4 pt-3 border-t border-rule-soft"> 3040 <div class="flex flex-wrap gap-x-2 gap-y-1 text-sm text-muted"> 3041 <a href="https://runningcalendar.co.za/about" @click="drawerOpen = false" class="hover:text-ink transition">About</a> 3042 <span aria-hidden="true">·</span> 3043 <a href="https://runningcalendar.co.za/contact" @click="drawerOpen = false" class="hover:text-ink transition">Contact</a> 3044 <span aria-hidden="true">·</span> 3045 <a href="https://runningcalendar.co.za/policies" @click="drawerOpen = false" class="hover:text-ink transition">Policies</a> 3046 <span aria-hidden="true">·</span> 3047 3048 <button 3049 type="button" 3050 @click="drawerOpen = false; $nextTick(() => window.dispatchEvent(new CustomEvent('open-cookie-settings')))" 3051 class="hover:text-ink transition cursor-pointer" 3052 style="background:none;border:none;padding:0;font:inherit;color:inherit" 3053 >Cookies</button>
3054 <span aria-hidden="true">·</span> 3055 <a href="https://runningcalendar.co.za/sitemap" @click="drawerOpen = false" class="hover:text-ink transition">Sitemap</a> 3056 </div> 3057 <p class="text-xs text-muted mt-2">© 2026 RunningCalendar.co.za · Est. 2016</p> 3058 </div> 3059 </div> 3060 3061 3062 <div x-show="tab === 'browse'" x-cloak> 3063 3064 3065 <div class="flex items-center gap-1 pt-3 pb-2"> 3066 <svg 3067 width="12" 3068 height="12" 3069 viewBox="0 0 24 24" 3070 fill="none" 3071 stroke="currentColor" 3072 stroke-width="2" 3073 stroke-linecap="round" 3074 stroke-linejoin="round" 3075 class="flex-shrink-0 text-muted shrink-0" 3076 ><circle cx="12" cy="12" r="10"/><polyline points="12 6 12 12 16 14"/></svg> 3077 <p class="font-mono uppercase text-muted" style="font-size:10.5px;letter-spacing:.12em">When</p> 3078 </div> 3079 <div class="flex flex-wrap gap-1.5"> 3080 <a href="https://runningcalendar.co.za/calendar?range=this-week" @click="drawerOpen = false" class="inline-flex items-center rounded-full text-[13px] font-semibold px-3 py-1.5" style="background:var(--brand-deep);color:#fff">This week</a> 3081 <a href="https://runningcalendar.co.za/calendar?range=this-month" @click="drawerOpen = false" class="cal-npill">This month</a> 3082 <a href="https://runningcalendar.co.za/calendar?range=next-3-months" @click="drawerOpen = false" class="cal-npill">Next 3 months</a> 3083 <a href="https://runningcalendar.co.za/calendar?range=next-6-months" @click="drawerOpen = false" class="cal-npill">Next 6 months</a> 3084 <a href="https://runningcalendar.co.za/calendar" @click="drawerOpen = false" class="cal-npill">All upcoming</a> 3085 </div> 3086 3087 3088 <div class="flex items-center gap-1 pt-4 pb-2"> 3089 <svg 3090 width="12" 3091 height="12"
3092 viewBox="0 0 24 24" 3093 fill="none" 3094 stroke="currentColor" 3095 stroke-width="2" 3096 stroke-linecap="round" 3097 stroke-linejoin="round" 3098 class="flex-shrink-0 text-muted shrink-0" 3099 ><path d="M21.3 8.7L8.7 21.3a2.4 2.4 0 0 1-3.4 0L2.7 18.7a2.4 2.4 0 0 1 0-3.4L15.3 2.7a2.4 2.4 0 0 1 3.4 0l2.6 2.6a2.4 2.4 0 0 1 0 3.4z"/><path d="m7.5 10.5 2 2"/><path d="m10.5 7.5 2 2"/><path d="m13.5 4.5 2 2"/><path d="m4.5 13.5 2 2"/></svg> 3100 <p class="font-mono uppercase text-muted" style="font-size:10.5px;letter-spacing:.12em">Distance</p> 3101 </div> 3102 <div class="flex flex-wrap gap-1.5"> 3103 <a href="https://runningcalendar.co.za/races/distance/5km" @click="drawerOpen = false" class="inline-flex items-center rounded-full" style="padding:4px 11px;font-size:13px;font-weight:600;background:var(--c-5k-soft);color:var(--c-5k-ink)">5 km</a> 3104 <a href="https://runningcalendar.co.za/races/distance/10km" @click="drawerOpen = false" class="inline-flex items-center rounded-full" style="padding:4px 11px;font-size:13px;font-weight:600;background:var(--c-10k-soft);color:var(--c-10k-ink)">10 km</a> 3105 <a href="https://runningcalendar.co.za/races/distance/15km" @click="drawerOpen = false" class="inline-flex items-center rounded-full" style="padding:4px 11px;font-size:13px;font-weight:600;background:var(--c-15k-soft);color:var(--c-15k-ink)">15 km</a> 3106 <a href="https://runningcalendar.co.za/races/distance/21km" @click="drawerOpen = false" class="inline-flex items-center rounded-full" style="padding:4px 11px;font-size:13px;font-weight:600;background:var(--c-21k-soft);color:var(--c-21k-ink)">21.1 km</a> 3107 <a href="https://runningcalendar.co.za/races/distance/30km" @click="drawerOpen = false" class="inline-flex items-center rounded-full" style="padding:4px 11px;font-size:13px;font-weight:600;background:var(--c-30k-soft);color:var(--c-30k-ink)">30 km</a> 3108 <a href="https://runningcalendar.co.za/races/distance/42km" @click="drawerOpen = false" class="inline-flex items-center rounded-full" style="padding:4px 11px;font-size:13px;font-weight:600;background:var(--c-42k-soft);color:var(--c-42k-ink)">42.2 km</a> 3109 <a href="https://runningcalendar.co.za/races/distance/ultra" @click="drawerOpen = false" class="inline-flex items-center rounded-full" style="padding:4px 11px;font-size:13px;font-weight:600;background:var(--c-ultra-soft);color:var(--c-ultra-ink)">Ultra</a> 3110 <a href="https://runningcalendar.co.za/races/terrain/trail" @click="drawerOpen = false" class="inline-flex items-center rounded-full" style="padding:4px 11px;font-size:13px;font-weight:600;background:var(--c-trail-soft);color:var(--c-trail-ink)">Trail</a> 3111 </div> 3112 3113 3114 <div class="flex items-center gap-1 pt-4 pb-2"> 3115 <svg 3116 width="12" 3117 height="12"
3118 viewBox="0 0 24 24" 3119 fill="none" 3120 stroke="currentColor" 3121 stroke-width="2" 3122 stroke-linecap="round" 3123 stroke-linejoin="round" 3124 class="flex-shrink-0 text-muted shrink-0" 3125 ><path d="M4 15s1-1 4-1 5 2 8 2 4-1 4-1V3s-1 1-4 1-5-2-8-2-4 1-4 1z"/><line x1="4" x2="4" y1="22" y2="15"/></svg> 3126 <p class="font-mono uppercase text-muted" style="font-size:10.5px;letter-spacing:.12em">Province</p> 3127 </div> 3128 <div class="grid grid-cols-2 gap-x-4"> 3129 <a href="https://runningcalendar.co.za/races/province/western-cape" @click="drawerOpen = false" class="block py-1.5 text-sm text-ink-2 hover:text-brand-deeper transition">Western Cape</a> 3130 <a href="https://runningcalendar.co.za/races/province/gauteng" @click="drawerOpen = false" class="block py-1.5 text-sm text-ink-2 hover:text-brand-deeper transition">Gauteng</a> 3131 <a href="https://runningcalendar.co.za/races/province/kwazulu-natal" @click="drawerOpen = false" class="block py-1.5 text-sm text-ink-2 hover:text-brand-deeper transition">KwaZulu-Natal</a> 3132 <a href="https://runningcalendar.co.za/races/province/eastern-cape" @click="drawerOpen = false" class="block py-1.5 text-sm text-ink-2 hover:text-brand-deeper transition">Eastern Cape</a> 3133 <a href="https://runningcalendar.co.za/races/province/free-state" @click="drawerOpen = false" class="block py-1.5 text-sm text-ink-2 hover:text-brand-deeper transition">Free State</a> 3134 <a href="https://runningcalendar.co.za/races/province/limpopo" @click="drawerOpen = false" class="block py-1.5 text-sm text-ink-2 hover:text-brand-deeper transition">Limpopo</a> 3135 <a href="https://runningcalendar.co.za/races/province/mpumalanga" @click="drawerOpen = false" class="block py-1.5 text-sm text-ink-2 hover:text-brand-deeper transition">Mpumalanga</a> 3136 <a href="https://runningcalendar.co.za/races/province/north-west" @click="drawerOpen = false" class="block py-1.5 text-sm text-ink-2 hover:text-brand-deeper transition">North West</a> 3137 <a href="https://runningcalendar.co.za/races/province/northern-cape" @click="drawerOpen = false" class="block py-1.5 text-sm text-ink-2 hover:text-brand-deeper transition">Northern Cape</a> 3138 </div> 3139 3140 3141 <div class="flex items-center gap-1 pt-4 pb-2"> 3142 <svg 3143 width="12" 3144 height="12"
3145 viewBox="0 0 24 24" 3146 fill="none" 3147 stroke="currentColor" 3148 stroke-width="2" 3149 stroke-linecap="round" 3150 stroke-linejoin="round" 3151 class="flex-shrink-0 text-muted shrink-0" 3152 ><circle cx="12" cy="12" r="10"/><path d="M12 2a14.5 14.5 0 0 0 0 20 14.5 14.5 0 0 0 0-20"/><path d="M2 12h20"/></svg> 3153 <p class="font-mono uppercase text-muted" style="font-size:10.5px;letter-spacing:.12em">Country</p> 3154 </div> 3155 <div class="flex flex-wrap gap-1.5"> 3156 <a href="https://runningcalendar.co.za/races/country/za" @click="drawerOpen = false" class="cal-npill inline-flex items-center gap-1.5"> 3157 <img src="https://runningcalendar.co.za/images/flags/za.svg" 3158 alt="" width="18" height="13" loading="lazy" 3159 class="shrink-0 rounded-[2px] ring-1 ring-black/5 object-cover"> 3160 South Africa 3161 </a> 3162 <a href="https://runningcalendar.co.za/races/country/ls" @click="drawerOpen = false" class="cal-npill inline-flex items-center gap-1.5"> 3163 <img src="https://runningcalendar.co.za/images/flags/ls.svg" 3164 alt="" width="18" height="13" loading="lazy" 3165 class="shrink-0 rounded-[2px] ring-1 ring-black/5 object-cover"> 3166 Lesotho 3167 </a> 3168 <a href="https://runningcalendar.co.za/races/country/na" @click="drawerOpen = false" class="cal-npill inline-flex items-center gap-1.5"> 3169 <img src="https://runningcalendar.co.za/images/flags/na.svg" 3170 alt="" width="18" height="13" loading="lazy" 3171 class="shrink-0 rounded-[2px] ring-1 ring-black/5 object-cover"> 3172 Namibia 3173 </a> 3174 <a href="https://runningcalendar.co.za/races/country/bw" @click="drawerOpen = false" class="cal-npill inline-flex items-center gap-1.5"> 3175 <img src="https://runningcalendar.co.za/images/flags/bw.svg" 3176 alt="" width="18" height="13" loading="lazy" 3177 class="shrink-0 rounded-[2px] ring-1 ring-black/5 object-cover"> 3178 Botswana 3179 </a> 3180 <a href="https://runningcalendar.co.za/races/country/sz" @click="drawerOpen = false" class="cal-npill inline-flex items-center gap-1.5"> 3181 <img src="https://runningcalendar.co.za/images/flags/sz.svg" 3182 alt="" width="18" height="13" loading="lazy" 3183 class="shrink-0 rounded-[2px] ring-1 ring-black/5 object-cover"> 3184 eSwatini 3185 </a> 3186 <a href="https://runningcalendar.co.za/races/country/zw" @click="drawerOpen = false" class="cal-npill inline-flex items-center gap-1.5"> 3187 <img src="https://runningcalendar.co.za/images/flags/zw.svg" 3188 alt="" width="18" height="13" loading="lazy" 3189 class="shrink-0 rounded-[2px] ring-1 ring-black/5 object-cover"> 3190 Zimbabwe 3191 </a> 3192 </div> 3193 3194 3195 <div class="flex items-center gap-1 pt-4 pb-2"> 3196 <svg 3197 width="12" 3198 height="12"
3199 viewBox="0 0 24 24" 3200 fill="none" 3201 stroke="currentColor" 3202 stroke-width="2" 3203 stroke-linecap="round" 3204 stroke-linejoin="round" 3205 class="flex-shrink-0 text-muted shrink-0" 3206 ><path d="M20 10c0 4.993-5.539 10.193-7.399 11.799a1 1 0 0 1-1.202 0C9.539 20.193 4 14.993 4 10a8 8 0 0 1 16 0"/><circle cx="12" cy="10" r="3"/></svg> 3207 <p class="font-mono uppercase text-muted" style="font-size:10.5px;letter-spacing:.12em">City</p> 3208 </div> 3209 <div class="grid grid-cols-2 gap-x-4"> 3210 <a href="https://runningcalendar.co.za/races/city/bloemfontein" @click="drawerOpen = false" class="block py-1.5 text-sm text-ink-2 hover:text-brand-deeper transition">Bloemfontein</a> 3211 <a href="https://runningcalendar.co.za/races/city/cape-town" @click="drawerOpen = false" class="block py-1.5 text-sm text-ink-2 hover:text-brand-deeper transition">Cape Town</a> 3212 <a href="https://runningcalendar.co.za/races/city/durban" @click="drawerOpen = false" class="block py-1.5 text-sm text-ink-2 hover:text-brand-deeper transition">Durban</a> 3213 <a href="https://runningcalendar.co.za/races/city/east-london" @click="drawerOpen = false" class="block py-1.5 text-sm text-ink-2 hover:text-brand-deeper transition">East London</a> 3214 <a href="https://runningcalendar.co.za/races/city/george" @click="drawerOpen = false" class="block py-1.5 text-sm text-ink-2 hover:text-brand-deeper transition">George</a> 3215 <a href="https://runningcalendar.co.za/races/city/gqeberha" @click="drawerOpen = false" class="block py-1.5 text-sm text-ink-2 hover:text-brand-deeper transition">Gqeberha</a> 3216 <a href="https://runningcalendar.co.za/races/city/johannesburg" @click="drawerOpen = false" class="block py-1.5 text-sm text-ink-2 hover:text-brand-deeper transition">Johannesburg</a> 3217 <a href="https://runningcalendar.co.za/races/city/kimberley" @click="drawerOpen = false" class="block py-1.5 text-sm text-ink-2 hover:text-brand-deeper transition">Kimberley</a> 3218 <a href="https://runningcalendar.co.za/races/city/mbombela" @click="drawerOpen = false" class="block py-1.5 text-sm text-ink-2 hover:text-brand-deeper transition">Mbombela</a> 3219 <a href="https://runningcalendar.co.za/races/city/mthatha" @click="drawerOpen = false" class="block py-1.5 text-sm text-ink-2 hover:text-brand-deeper transition">Mthatha</a> 3220 </div> 3221 <a href="https://runningcalendar.co.za/cities" @click="drawerOpen = false" class="inline-block mt-2 text-sm font-medium text-brand-deeper hover:underline">Browse all cities â</a> 3222 3223 3224 <div class="flex items-center gap-1 pt-4 pb-2"> 3225 <svg 3226 width="12" 3227 height="12"
3228 viewBox="0 0 24 24" 3229 fill="none" 3230 stroke="currentColor" 3231 stroke-width="2" 3232 stroke-linecap="round" 3233 stroke-linejoin="round" 3234 class="flex-shrink-0 text-muted shrink-0" 3235 ><path d="M6 9H4.5a2.5 2.5 0 0 1 0-5H6"/><path d="M18 9h1.5a2.5 2.5 0 0 0 0-5H18"/><path d="M4 22h16"/><path d="M10 14.66V17c0 .55-.47.98-.97 1.21C7.85 18.75 7 20.24 7 22"/><path d="M14 14.66V17c0 .55.47.98.97 1.21C16.15 18.75 17 20.24 17 22"/><path d="M18 2H6v7a6 6 0 0 0 12 0V2z"/></svg> 3236 <p class="font-mono uppercase text-muted" style="font-size:10.5px;letter-spacing:.12em">Qualifiers</p> 3237 </div> 3238 <div class="flex flex-wrap gap-1.5"> 3239 <a href="https://runningcalendar.co.za/races/qualifier/comrades" @click="drawerOpen = false" 3240 class="cal-npill" style="color:var(--st-postponed)">Comrades</a> 3241 <a href="https://runningcalendar.co.za/races/qualifier/two-oceans" @click="drawerOpen = false" 3242 class="cal-npill" style="color:var(--st-results)">Two Oceans</a> 3243 </div> 3244 </div> 3245 3246 3247 <div x-show="tab === 'account'" x-cloak> 3248 <div class="rounded-xl p-4 mt-2" style="background:var(--brand-50);border:1px solid var(--brand-line)"> 3249 <p class="text-base font-bold text-ink">Track your races</p> 3250 <p class="text-sm text-ink-2 mt-1">Save events, log your results and get start-time reminders.</p> 3251 <div class="flex gap-2 mt-3"> 3252 <a href="https://runningcalendar.co.za/login" class="flex-1 inline-flex items-center justify-center h-10 rounded-lg text-sm font-semibold text-white" style="background:var(--brand-deep)">Sign in</a> 3253 <a href="https://runningcalendar.co.za/register" class="flex-1 inline-flex items-center justify-center h-10 rounded-lg text-sm font-semibold text-ink bg-surface" style="border:1px solid var(--rule)">Register</a> 3254 </div> 3255 </div> 3256 </div> 3257 3258 </div> 3259 3260 3261 <div class="shrink-0 px-4 py-3 border-t border-rule-soft"> 3262 <a href="https://runningcalendar.co.za/ad-free" @click="drawerOpen = false" class="m-upsell"> 3263 <span class="flex items-center gap-3"> 3264 <svg 3265 width="22" 3266 height="22"
3267 viewBox="0 0 24 24" 3268 fill="none" 3269 stroke="currentColor" 3270 stroke-width="2.2" 3271 stroke-linecap="round" 3272 stroke-linejoin="round" 3273 style="color:#FBBF24" class="flex-shrink-0" 3274 ><polygon points="12 2 15.09 8.26 22 9.27 17 14.14 18.18 21.02 12 17.77 5.82 21.02 7 14.14 2 9.27 8.91 8.26 12 2"/></svg> 3275 <span class="flex flex-col text-left leading-tight"> 3276 <span class="text-white font-semibold text-[15px]">Go ad-free</span> 3277 <span class="text-white/70 text-xs">No ads · support local races</span> 3278 </span> 3279 </span> 3280 <span class="m-pricepill"><b style="font-size:14px;font-weight:700">R29</b> /mo</span> 3281 </a> 3282 </div> 3283 </div> 3284 3285</div> 3286 3287 3288 <div wire:snapshot="{"data":{"isOpen":false,"query":"","results":[{"events":[[],{"s":"arr"}],"organisers":[[],{"s":"arr"}]},{"s":"arr"}]},"memo":{"id":"15BjElyuFN3mHvY2Akkg","name":"search.search-modal","path":"contact","method":"GET","release":"a-a-a","children":[],"scripts":[],"assets":[],"errors":[],"locale":"en"},"checksum":"c507ab76e50b1b80cdae726f244f4e4e1b3a5ede70ab38185dc2843857c39dfd"}" wire:effects="{"partials":[],"listeners":["open-search-modal"]}" wire:id="15BjElyuFN3mHvY2Akkg" 3289 x-data="{ 3290 open: window.Livewire.find('15BjElyuFN3mHvY2Akkg').entangle('isOpen').live, 3291 highlighted: -1, 3292 recentSearches: [], 3293 3294 init() { 3295 try { 3296 this.recentSearches = JSON.parse(localStorage.getItem('rc.recent_searches') || '[]'); 3297 } catch (e) { 3298 this.recentSearches = []; 3299 } 3300 3301 window.addEventListener('open-search-modal', () => { this.open = true; }); 3302 3303 // Focus whenever the panel opens â regardless of trigger (header button, 3304 // Cmd/Ctrl-K, or the Livewire open() listener). $nextTick waits for the 3305 // x-show display flip; requestAnimationFrame waits for the paint so the 3306 // input is actually focusable (focusing a display:none element is a no-op). 3307 this.$watch('open', (value) => { 3308 if (value) { 3309 this.$nextTick(() => requestAnimationFrame(() => this.$refs.searchInput?.focus())); 3310 } 3311 }); 3312 3313 this.$wire.$watch('query', () => { this.highlighted = -1; }); 3314 }, 3315 3316 pushRecent(term) { 3317 if (!term || !term.trim()) return; 3318 const t = term.trim(); 3319 const list = this.recentSearches.filter(s => s !== t); 3320 list.unshift(t); 3321 this.recentSearches = list.slice(0, 5); 3322 localStorage.setItem('rc.recent_searches', JSON.stringify(this.recentSearches)); 3323 }, 3324 3325 navigate(url) { 3326 this.pushRecent(this.$refs.searchInput?.value); 3327 window.location.href = url; 3328 }, 3329 3330 allOptions() { 3331 return Array.from(this.$el.querySelectorAll('[role=option]')); 3332 }, 3333 3334 arrowDown() { 3335 const items = this.allOptions(); 3336 if (!items.length) return; 3337 this.highlighted = Math.min(this.highlighted + 1, items.length - 1); 3338 items[this.highlighted]?.scrollIntoView({ block: 'nearest' }); 3339 }, 3340 3341 arrowUp() { 3342 const items = this.allOptions(); 3343 if (!items.length) return; 3344 this.highlighted = Math.max(this.highlighted - 1, 0); 3345 items[this.highlighted]?.scrollIntoView({ block: 'nearest' }); 3346 }, 3347 3348 selectHighlighted() { 3349 const item = this.allOptions()[this.highlighted]; 3350 if (item) { 3351 item.click(); 3352 } else if (this.$refs.searchInput?.value.trim()) { 3353 window.location.href = 'https://runningcalendar.co.za/search?q=' + encodeURIComponent(this.$refs.searchInput.value.trim()); 3354 } 3355 }, 3356 }" 3357 @keydown.escape.window="if (open) { open = false }" 3358> 3359 3360 3361 3362 <div 3363 x-show="open" 3364 x-cloak 3365 x-transition:enter="transition ease-out duration-150" 3366 x-transition:enter-start="opacity-0" 3367 x-transition:enter-end="opacity-100" 3368 x-transition:leave="transition ease-in duration-100" 3369 x-transition:leave-start="opacity-100" 3370 x-transition:leave-end="opacity-0" 3371 class="fixed inset-0 z-50 hidden bg-black/50 lg:block" 3372 @click="open = false" 3373 aria-hidden="true" 3374 ></div> 3375 3376 3377 3378 3379 3380 <div 3381 x-show="open" 3382 x-cloak 3383 x-transition:enter="transition ease-out duration-150" 3384 x-transition:enter-start="opacity-0 scale-95" 3385 x-transition:enter-end="opacity-100 scale-100" 3386 x-transition:leave="transition ease-in duration-100" 3387 x-transition:leave-start="opacity-100 scale-100" 3388 x-transition:leave-end="opacity-0 scale-95" 3389 role="dialog" 3390 aria-modal="true" 3391 aria-labelledby="search-modal-title" 3392 class="fixed inset-0 z-50 flex flex-col bg-surface 3393 lg:inset-auto lg:inset-x-0 lg:top-16 lg:mx-auto lg:w-full lg:max-w-xl 3394 lg:rounded-2xl lg:border lg:border-rule
3395 lg:shadow-2xl lg:max-h-[600px] lg:flex-none" 3396 @click.stop 3397 > 3398 3399 <div class="flex items-center gap-3 border-b border-rule-soft px-4 py-3 shrink-0"> 3400 3401 <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" 3402 class="h-5 w-5 shrink-0 text-muted" aria-hidden="true"> 3403 <path stroke-linecap="round" stroke-linejoin="round" d="m21 21-5.197-5.197m0 0A7.5 7.5 0 1 0 5.196 5.196a7.5 7.5 0 0 0 10.607 10.607Z" /> 3404 </svg> 3405 3406 <input 3407 x-ref="searchInput" 3408 type="search" 3409 wire:model.live.debounce.200ms="query" 3410 placeholder="Search races, organisers..." 3411 aria-label="Search races and organisers" 3412 id="search-modal-title" 3413 autocomplete="off" 3414 @keydown.arrow-down.prevent="arrowDown" 3415 @keydown.arrow-up.prevent="arrowUp" 3416 @keydown.enter.prevent="selectHighlighted" 3417 class="min-w-0 flex-1 bg-transparent text-sm text-ink placeholder-muted outline-none" 3418 > 3419 3420 3421 <span wire:loading wire:target="query" class="text-muted" aria-hidden="true"> 3422 <svg class="h-4 w-4 animate-spin" fill="none" viewBox="0 0 24 24"> 3423 <circle class="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" stroke-width="4"></circle> 3424 <path class="opacity-75" fill="currentColor" d="M4 12a8 8 0 0 1 8-8V0C5.373 0 0 5.373 0 12h4z"></path> 3425 </svg> 3426 </span> 3427 3428 3429 <button 3430 @click="open = false" 3431 type="button" 3432 aria-label="Close search" 3433 class="flex h-7 w-7 shrink-0 items-center justify-center rounded-lg text-muted transition hover:bg-soft hover:text-ink-2" 3434 > 3435 <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" 3436 class="h-4 w-4" aria-hidden="true"> 3437 <path stroke-linecap="round" stroke-linejoin="round" d="M6 18 18 6M6 6l12 12" /> 3438 </svg> 3439 </button> 3440 </div> 3441 3442 3443 <div class="flex-1 overflow-y-auto py-2" role="listbox" aria-label="Search results"> 3444 3445 <!--[if BLOCK]><![endif]--> 3446 3447 <template x-if="recentSearches.length > 0"> 3448 <div> 3449 <p class="px-4 py-1.5 text-xs font-semibold uppercase tracking-wider text-muted" 3450 aria-label="Recent searches">Recent searches</p> 3451 <template x-for="(term, i) in recentSearches" :key="i"> 3452 <button 3453 type="button" 3454 @click="$wire.set('query', term)" 3455 class="flex w-full items-center gap-3 px-4 py-2.5 text-sm text-ink-2 hover:bg-soft" 3456 > 3457 <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" 3458 stroke="currentColor" class="h-4 w-4 shrink-0 text-muted" aria-hidden="true"> 3459 <path stroke-linecap="round" stroke-linejoin="round" 3460 d="M12 6v6h4.5m4.5 0a9 9 0 1 1-18 0 9 9 0 0 1 18 0Z" /> 3461 </svg> 3462 <span x-text="term" class="text-left"></span> 3463 </button> 3464 </template> 3465 </div> 3466 </template> 3467 3468 <template x-if="recentSearches.length === 0"> 3469 <p class="px-4 py-6 text-center text-sm text-muted"> 3470 Start typing to search races and organisers. 3471 </p> 3472 </template> 3473 3474 <!--[if ENDBLOCK]><![endif]--> 3475 </div> 3476 </div> 3477</div>
3478 <main id="main-content" class="flex-1 pb-16 lg:pb-0"> 3479 <div class="rc"> 3480 3481 <div class="pg-crumb"> 3482 <a href="https://runningcalendar.co.za">Home</a> 3483 <svg 3484 width="14" 3485 height="14" 3486 viewBox="0 0 24 24" 3487 fill="none" 3488 stroke="currentColor" 3489 stroke-width="1.8" 3490 stroke-linecap="round" 3491 stroke-linejoin="round" 3492 style="color: var(--muted)" class="flex-shrink-0" 3493 ><polyline points="9 18 15 12 9 6"/></svg> 3494 <b>Contact</b> 3495 </div> 3496 3497 <div class="pg-head"> 3498 <div class="eyebrow">Get in touch</div> 3499 <h1>Talk to a real person.</h1> 3500 <p class="lede">Race correction, missing event, broken link, partnership, or just want to say hello â fill in the form and we'll get back to you within one working day.</p> 3501 </div> 3502 3503 <div class="contact-body"> 3504 3505 3506 <div wire:snapshot="{"data":{"name":"","email":"","phone":"","topic":"","relatedRace":"","message":"","sendCopy":true,"website":"","formRenderedAt":1791227376935,"sent":false,"rateLimitError":""},"memo":{"id":"0YU3LymYXzW5LR1eZQzr","name":"contact.contact-form","path":"contact","method":"GET","release":"a-a-a","children":[],"scripts":[],"assets":[],"errors":[],"locale":"en"},"checksum":"c32c70e5c5f21bd3e444bec47c076da289d30193b48c1fd090c1f6a71bc5511f"}" wire:effects="{"partials":[]}" wire:id="0YU3LymYXzW5LR1eZQzr" class="contact-form"> 3507 <!--[if BLOCK]><![endif]--> <h2>Send us a message</h2> 3508 <p class="sub">All fields except phone are required. We never share your email.</p> 3509 3510 3511 <div style="display:none;" aria-hidden="true"> 3512 <input type="text" wire:model="website" tabindex="-1" autocomplete="off"> 3513 </div> 3514 3515 <!--[if BLOCK]><![endif]--><!--[if ENDBLOCK]><![endif]--> 3516 <div class="grid-2"> 3517 <div class="field"> 3518 <label for="cf-name">Your name</label> 3519 <input id="cf-name" wire:model="name" type="text" placeholder="Jane Doe" autocomplete="name"> 3520 <!--[if BLOCK]><![endif]--><!--[if ENDBLOCK]><![endif]--> </div> 3521 <div class="field"> 3522 <label for="cf-email">Email</label> 3523 <input id="cf-email" wire:model="email" type="email" placeholder="[email protected]" autocomplete="email"> 3524 <!--[if BLOCK]><![endif]--><!--[if ENDBLOCK]><![endif]--> </div> 3525 </div> 3526 3527 <div class="grid-2"> 3528 <div class="field"> 3529 <label for="cf-topic">Topic</label> 3530 <select id="cf-topic" wire:model="topic"> 3531 <option value="">â select a topic â</option> 3532 <!--[if BLOCK]><![endif]--> <option value="Race correction / missing event">Race correction / missing event</option> 3533 <option value="Submit a race">Submit a race</option> 3534 <option value="Premium / advertising">Premium / advertising</option> 3535 <option value="Privacy / data request">Privacy / data request</option> 3536 <option value="Press enquiry">Press enquiry</option> 3537 <option value="Something else">Something else</option> 3538 <!--[if ENDBLOCK]><![endif]--> </select> 3539 <!--[if BLOCK]><![endif]--><!--[if ENDBLOCK]><![endif]--> </div> 3540 <div class="field"> 3541 <label for="cf-phone">Phone <span class="opt">(optional)</span></label> 3542 <input id="cf-phone" wire:model="phone" type="tel" placeholder="+27 â¦" autocomplete="tel"> 3543 <!--[if BLOCK]><![endif]--><!--[if ENDBLOCK]><![endif]--> </div> 3544 </div> 3545 3546 <div class="field"> 3547 <label for="cf-race">Related race <span class="opt">(if applicable)</span></label> 3548 <input id="cf-race" wire:model="relatedRace" type="text" placeholder="e.g. Cape Town Marathon · 18 Oct 2026"> 3549 <div class="hint">Leave blank for general enquiries.</div> 3550 </div> 3551 3552 <div class="field"> 3553 <label for="cf-msg">Message</label> 3554 <textarea id="cf-msg" wire:model="message" placeholder="What can we help with?"></textarea> 3555 <!--[if BLOCK]><![endif]--><!--[if ENDBLOCK]><![endif]--> </div> 3556 3557 <div style="display:flex; align-items:center; gap:12px; margin-top:6px; flex-wrap:wrap;"> 3558 <label style="display:flex; gap:8px; align-items:center; font-size:13px; color:var(--ink-2); cursor:pointer;"> 3559 <input type="checkbox" wire:model="sendCopy" style="accent-color:var(--brand);"> 3560 Send me a copy 3561 </label> 3562 <!--[if BLOCK]><![endif]--><button 3563 class="inline-flex items-center justify-center gap-2 rounded-lg font-medium transition border border-transparent bg-brand-500 text-white hover:bg-brand-600 px-4.5 py-2.5 text-sm min-h-11 cf-submit" type="button" style="margin-left:auto;" wire:click.prevent="submit" 3564> 3565 <!--[if BLOCK]><![endif]--><!--[if ENDBLOCK]><![endif]--> Send message 3566 <!--[if BLOCK]><![endif]--><!--[if ENDBLOCK]><![endif]--></button> 3567<!--[if ENDBLOCK]><![endif]--> </div> 3568 <!--[if ENDBLOCK]><![endif]--></div> 3569 <div class="contact-side"> 3570 <div class="card"> 3571 <h3>Contact</h3> 3572 <div class="row">
3573 <span class="label">Email</span> 3574 <span class="v"> 3575 <a href="/cdn-cgi/l/email-protection#cca5a2aaa38cbeb9a2a2a5a2abafada0a9a2a8adbee2afa3e2b6ad"><span class="__cf_email__" data-cfemail="50393e363f1022253e3e393e3733313c353e3431227e333f7e2a31">[email protected]</span></a> 3576 </span> 3577 </div> 3578 <div class="row"> 3579 <span class="label">WhatsApp</span> 3580 <span class="v">+27 68 623 9340</span> 3581 </div> 3582 <div class="row"> 3583 <span class="label">Hours</span> 3584 <span class="v">MonâFri · 09:00â17:00 SAST</span> 3585 </div> 3586 </div> 3587 3588 3589 </div> 3590 3591 </div> 3592 3593</div> 3594 </main> 3595 3596 3597 <div class="rc-footer-wrap"> 3598 <footer role="contentinfo" style="background:#0A0E14"> 3599 3600 3601 <div class="mx-auto max-w-screen-xl px-8 pt-16 pb-12 lg:grid lg:items-start" style="gap:64px;grid-template-columns:minmax(280px,340px) 1fr"> 3602 3603 3604 <div> 3605 <img src="https://runningcalendar.co.za/images/logo/running-calendar-logo.png" alt="RunningCalendar" width="36" height="36" class="h-9 w-9 object-contain mb-5"> 3606 3607 <h4 class="t-h3 text-white mb-3" style="font-size:18px;line-height:1.3;font-weight:600;letter-spacing:-0.01em"> 3608 Every road race in Southern Africa, in one calendar. 3609 </h4> 3610 3611 <p class="text-sm mb-6" style="color:var(--muted)"> 3612 Independent. Verified. Free for runners, free for clubs. Updated daily across all 9 provinces. 3613 </p> 3614 3615 3616 <form 3617 action="https://runningcalendar.co.za/newsletter" 3618 method="GET" 3619 class="mb-5" 3620 aria-label="Newsletter signup" 3621 > 3622 <div class="flex gap-2"> 3623 <input 3624 id="newsletter-form" 3625 type="email" 3626 name="email" 3627 placeholder="[email protected]" 3628 class="min-w-0 flex-1 rounded-lg px-3 py-2 text-sm text-white placeholder-gray-500 focus:outline-none focus:ring-2 focus:ring-brand-500" 3629 style="background:rgba(255,255,255,.08);border:1px solid rgba(255,255,255,.12)" 3630 > 3631 <button 3632 type="submit" 3633 class="shrink-0 rounded-lg px-3 py-2 text-sm font-medium text-white transition hover:bg-brand-600" 3634 style="background:#2F6FC2" 3635 > 3636 Subscribe 3637 </button> 3638 </div> 3639 </form> 3640 3641 3642 <div class="flex gap-3 items-center"> 3643 <a href="https://x.com/runningcalza" target="_blank" rel="noopener noreferrer" aria-label="RunningCalendar on X/Twitter" 3644 class="footer-social-link transition" style="color:var(--muted)" onmouseover="this.style.color='#fff'" onmouseout="this.style.color='var(--muted)'"> 3645 <svg 3646 width="20" 3647 height="20"
3648 viewBox="0 0 24 24" 3649 fill="none" 3650 stroke="currentColor" 3651 stroke-width="1.8" 3652 stroke-linecap="round" 3653 stroke-linejoin="round" 3654 style="color: currentColor" class="flex-shrink-0" 3655 ><path d="M22 4s-.7 2.1-2 3.4c1.6 10-9.4 17.3-18 11.6 2.2.1 4.4-.6 6-2C3 15.5.5 9.6 3 5c2.2 2.6 5.6 4.1 9 4-.9-4.2 4-6.6 7-3.8 1.1 0 3-1.2 3-1.2z"/></svg> 3656 </a> 3657 <a href="https://www.facebook.com/runningcalendarza" target="_blank" rel="noopener noreferrer" aria-label="RunningCalendar on Facebook" 3658 class="footer-social-link transition" style="color:var(--muted)" onmouseover="this.style.color='#fff'" onmouseout="this.style.color='var(--muted)'"> 3659 <svg 3660 width="20" 3661 height="20" 3662 viewBox="0 0 24 24" 3663 fill="none" 3664 stroke="currentColor" 3665 stroke-width="1.8" 3666 stroke-linecap="round" 3667 stroke-linejoin="round" 3668 style="color: currentColor" class="flex-shrink-0" 3669 ><path d="M18 2h-3a5 5 0 0 0-5 5v3H7v4h3v8h4v-8h3l1-4h-4V7a1 1 0 0 1 1-1h3z"/></svg> 3670 </a> 3671 <a href="https://www.instagram.com/runningcalendarza/" target="_blank" rel="noopener noreferrer" aria-label="RunningCalendar on Instagram" 3672 class="footer-social-link transition" style="color:var(--muted)" onmouseover="this.style.color='#fff'" onmouseout="this.style.color='var(--muted)'"> 3673 <svg 3674 width="20" 3675 height="20"
3676 viewBox="0 0 24 24" 3677 fill="none" 3678 stroke="currentColor" 3679 stroke-width="1.8" 3680 stroke-linecap="round" 3681 stroke-linejoin="round" 3682 style="color: currentColor" class="flex-shrink-0" 3683 ><rect width="20" height="20" x="2" y="2" rx="5" ry="5"/><path d="M16 11.37A4 4 0 1 1 12.63 8 4 4 0 0 1 16 11.37z"/><line x1="17.5" x2="17.51" y1="6.5" y2="6.5"/></svg> 3684 </a> 3685 <a href="https://www.strava.com/athletes/1691850820" target="_blank" rel="noopener noreferrer" aria-label="RunningCalendar on Strava" 3686 class="footer-social-link transition" style="color:var(--muted)" onmouseover="this.style.color='#fff'" onmouseout="this.style.color='var(--muted)'"> 3687 <svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="currentColor"> 3688 <path d="M15.387 17.944l-2.089-4.116h-3.065L15.387 24l5.15-10.172h-3.066m-7.008-5.599l2.836 5.598h4.172L10.463 0l-7 13.828h4.169"/> 3689 </svg> 3690 </a> 3691 <a href="https://whatsapp.com/channel/0029VbBFieCDJ6H8IiHmde3E" target="_blank" rel="noopener noreferrer" aria-label="RunningCalendar on WhatsApp" 3692 class="footer-social-link transition" style="color:var(--muted)" onmouseover="this.style.color='#fff'" onmouseout="this.style.color='var(--muted)'"> 3693 <svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="currentColor"> 3694 <path d="M17.472 14.382c-.297-.149-1.758-.867-2.03-.967-.273-.099-.471-.148-.67.15-.197.297-.767.966-.94 1.164-.173.199-.347.223-.644.075-.297-.15-1.255-.463-2.39-1.475-.883-.788-1.48-1.761-1.653-2.059-.173-.297-.018-.458.13-.606.134-.133.298-.347.446-.52.149-.174.198-.298.298-.497.099-.198.05-.371-.025-.52-.075-.149-.669-1.612-.916-2.207-.242-.579-.487-.5-.669-.51-.173-.008-.371-.01-.57-.01-.198 0-.52.074-.792.372-.272.297-1.04 1.016-1.04 2.479 0 1.462 1.065 2.875 1.213 3.074.149.198 2.096 3.2 5.077 4.487.709.306 1.262.489 1.694.625.712.227 1.36.195 1.871.118.571-.085 1.758-.719 2.006-1.413.248-.694.248-1.289.173-1.413-.074-.124-.272-.198-.57-.347m-5.421 7.403h-.004a9.87 9.87 0 01-5.031-1.378l-.361-.214-3.741.982.998-3.648-.235-.374a9.86 9.86 0 01-1.51-5.26c.001-5.45 4.436-9.884 9.888-9.884 2.64 0 5.122 1.03 6.988 2.898a9.825 9.825 0 012.893 6.994c-.003 5.45-4.437 9.884-9.885 9.884m8.413-18.297A11.815 11.815 0 0012.05 0C5.495 0 .16 5.335.157 11.892c0 2.096.547 4.142 1.588 5.945L.057 24l6.305-1.654a11.882 11.882 0 005.683 1.448h.005c6.554 0 11.89-5.335 11.893-11.893a11.821 11.821 0 00-3.48-8.413z"/> 3695 </svg> 3696 </a> 3697 <a href="/cdn-cgi/l/email-protection#2a4445584f5a46536a474b434604585f444443444d494b464f444e4b5804494504504b" aria-label="Email RunningCalendar" class="footer-social-link transition" style="color:var(--muted)" onmouseover="this.style.color='#fff'" onmouseout="this.style.color='var(--muted)'"> 3698 <svg 3699 width="20" 3700 height="20"
3701 viewBox="0 0 24 24" 3702 fill="none" 3703 stroke="currentColor" 3704 stroke-width="1.8" 3705 stroke-linecap="round" 3706 stroke-linejoin="round" 3707 style="color: currentColor" class="flex-shrink-0" 3708 ><rect width="20" height="16" x="2" y="4" rx="2"/><path d="m22 7-8.97 5.7a1.94 1.94 0 0 1-2.06 0L2 7"/></svg> 3709 </a> 3710 </div> 3711 </div> 3712 3713 3714 <div class="hidden lg:grid" style="grid-template-columns:repeat(4,1fr);gap:36px"> 3715 3716 3717 <div> 3718 <h5 class="footer-eyebrow">BROWSE</h5> 3719 <ul class="space-y-2.5 text-sm"> 3720 <li><a href="https://runningcalendar.co.za/calendar?range=this-week" class="footer-link">This week</a></li> 3721 <li><a href="https://runningcalendar.co.za/calendar" class="footer-link">Upcoming</a></li> 3722 <li><a href="https://runningcalendar.co.za/calendar?view=map" class="footer-link">Map view</a></li> 3723 <li><a href="https://runningcalendar.co.za/near-me" class="footer-link">Near me</a></li> 3724 <li><a href="https://runningcalendar.co.za/cities" class="footer-link">Browse cities</a></li> 3725 <li><a href="https://runningcalendar.co.za/races/qualifier/comrades" class="footer-link">Comrades qualifiers</a></li> 3726 <li><a href="https://runningcalendar.co.za/races/qualifier/two-oceans" class="footer-link">Two Oceans qualifiers</a></li> 3727 <li><a href="https://runningcalendar.co.za/results" class="footer-link">Race results</a></li> 3728 <li><a href="https://runningcalendar.co.za/countries" class="footer-link" style="color:#8AB1E6">All countries â</a></li> 3729 </ul> 3730 </div> 3731 3732 3733 <div> 3734 <h5 class="footer-eyebrow">CITIES</h5> 3735 <ul class="space-y-2.5 text-sm"> 3736 <li><a href="https://runningcalendar.co.za/races/city/cape-town" class="footer-link">Cape Town</a></li> 3737 <li><a href="https://runningcalendar.co.za/races/city/johannesburg" class="footer-link">Johannesburg</a></li> 3738 <li><a href="https://runningcalendar.co.za/races/city/durban" class="footer-link">Durban</a></li> 3739 <li><a href="https://runningcalendar.co.za/races/city/gqeberha" class="footer-link">Gqeberha</a></li> 3740 <li><a href="https://runningcalendar.co.za/races/city/pretoria" class="footer-link">Pretoria</a></li> 3741 <li><a href="https://runningcalendar.co.za/races/city/east-london" class="footer-link">East London</a></li> 3742 <li><a href="https://runningcalendar.co.za/cities" class="footer-link" style="color:#8AB1E6">All cities â</a></li> 3743 </ul> 3744 </div> 3745 3746 3747 <div> 3748 <h5 class="footer-eyebrow">PROVINCES</h5> 3749 <ul class="space-y-2.5 text-sm"> 3750 <li><a href="https://runningcalendar.co.za/races/province/western-cape" class="footer-link">Western Cape</a></li> 3751 <li><a href="https://runningcalendar.co.za/races/province/gauteng" class="footer-link">Gauteng</a></li> 3752 <li><a href="https://runningcalendar.co.za/races/province/kwazulu-natal" class="footer-link">KwaZulu-Natal</a></li> 3753 <li><a href="https://runningcalendar.co.za/races/province/eastern-cape" class="footer-link">Eastern Cape</a></li> 3754 <li><a href="https://runningcalendar.co.za/races/province/free-state" class="footer-link">Free State</a></li> 3755 <li><a href="https://runningcalendar.co.za/races/province/limpopo" class="footer-link">Limpopo</a></li> 3756 <li><a href="https://runningcalendar.co.za/provinces" class="footer-link" style="color:#8AB1E6">All provinces â</a></li> 3757 </ul> 3758 </div> 3759 3760 3761 <div> 3762 <h5 class="footer-eyebrow">RESOURCES</h5> 3763 <ul class="space-y-2.5 text-sm"> 3764 <li><a href="https://runningcalendar.co.za/submit-race" class="footer-link">Submit a race</a></li> 3765 <li> 3766 <a href="https://runningcalendar.co.za/organisers#submit" class="footer-link"> 3767 List an event
3768 <span class="inline-block px-1.5 py-0.5 text-[10px] font-bold rounded-full uppercase ml-1" style="background:rgba(34,197,94,.16);color:#5be584;border:1px solid rgba(34,197,94,.3)">FREE</span> 3769 </a> 3770 </li> 3771 <li><a href="https://runningcalendar.co.za/organisers" class="footer-link">Organiser Portal</a></li> 3772 <li> 3773 <a href="https://runningcalendar.co.za/advertise" class="footer-link"> 3774 Advertise 3775 <span class="inline-block px-1.5 py-0.5 text-[10px] font-bold rounded-full uppercase ml-1" style="background:rgba(74,137,220,.18);color:#8AB1E6;border:1px solid rgba(74,137,220,.35)">NEW</span> 3776 </a> 3777 </li> 3778 <li><a href="https://runningcalendar.co.za/training-programs" class="footer-link">Training Programs</a></li> 3779 <li><a href="https://runningcalendar.co.za/ad-free" class="footer-link">Ad-free Premium</a></li> 3780 <li><a href="https://runningcalendar.co.za/articles" class="footer-link">Articles</a></li> 3781 <li><a href="https://runningcalendar.co.za/newsletter" class="footer-link">Newsletter</a></li> 3782 </ul> 3783 </div> 3784 3785 </div> 3786 3787 </div> 3788 3789 3790 <div class="mx-auto max-w-screen-xl px-8 py-5 flex flex-wrap justify-between items-center gap-4" style="border-top:1px solid rgba(255,255,255,.09)"> 3791 <p class="text-xs" style="color:rgba(255,255,255,.5)"> 3792 © 2026 Running Calendar · Cape Town, ZA · Built for runners 3793 </p> 3794 <div class="flex flex-wrap items-center" style="font-size:13px"> 3795 3796 <a href="https://runningcalendar.co.za/about" class="footer-legal-link">About</a> 3797 <a href="https://runningcalendar.co.za/contact" class="footer-legal-link footer-legal-link--sep">Contact</a> 3798 <a href="https://runningcalendar.co.za/sitemap" class="footer-legal-link footer-legal-link--sep">Sitemap</a> 3799 <a href="https://runningcalendar.co.za/policies" class="footer-legal-link footer-legal-link--sep">Policies</a> 3800 <button type="button" class="footer-legal-link footer-legal-link--sep" style="background:none;border:none;cursor:pointer" onclick="window.dispatchEvent(new CustomEvent('open-cookie-settings'))">Cookie settings</button> 3801 <a href="https://runningcalendar.co.za/advertise" class="footer-legal-link footer-legal-link--sep">Advertise</a> 3802 </div> 3803 </div> 3804 3805</footer> 3806 </div> 3807 3808 <nav 3809 class="fixed bottom-0 inset-x-0 z-50 border-t border-rule bg-surface lg:hidden" 3810 style="padding-bottom: env(safe-area-inset-bottom, 0)" 3811 aria-label="Main navigation" 3812 data-bottom-tabs 3813> 3814 <div class="flex"> 3815 <a 3816 href="https://runningcalendar.co.za" 3817 role="link" 3818 class="flex flex-1 flex-col items-center justify-center gap-0.5 py-2 text-xs font-medium transition 3819 3820 text-muted hover:text-ink" 3821 > 3822 <svg 3823 width="24" 3824 height="24"
3825 viewBox="0 0 24 24" 3826 fill="none" 3827 stroke="currentColor" 3828 stroke-width="1.7" 3829 stroke-linecap="round" 3830 stroke-linejoin="round" 3831 class="flex-shrink-0" aria-hidden="true" 3832 ><path d="m3 9 9-7 9 7v11a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z"/><polyline points="9 22 9 12 15 12 15 22"/></svg> 3833 <span>Home</span> 3834 </a> 3835 <a 3836 href="https://runningcalendar.co.za/calendar" 3837 role="link" 3838 class="flex flex-1 flex-col items-center justify-center gap-0.5 py-2 text-xs font-medium transition 3839 3840 text-muted hover:text-ink" 3841 > 3842 <svg 3843 width="24" 3844 height="24" 3845 viewBox="0 0 24 24" 3846 fill="none" 3847 stroke="currentColor" 3848 stroke-width="1.7" 3849 stroke-linecap="round" 3850 stroke-linejoin="round" 3851 class="flex-shrink-0" aria-hidden="true" 3852 ><path d="M8 2v4"/><path d="M16 2v4"/><rect width="18" height="18" x="3" y="4" rx="2"/><path d="M3 10h18"/></svg> 3853 <span>Calendar</span> 3854 </a> 3855 <a 3856 href="https://runningcalendar.co.za/results" 3857 role="link" 3858 class="flex flex-1 flex-col items-center justify-center gap-0.5 py-2 text-xs font-medium transition 3859 relative 3860 text-muted hover:text-ink" 3861 > 3862 <svg 3863 width="28" 3864 height="28"
3865 viewBox="0 0 24 24" 3866 fill="none" 3867 stroke="currentColor" 3868 stroke-width="1.7" 3869 stroke-linecap="round" 3870 stroke-linejoin="round" 3871 class="flex-shrink-0" aria-hidden="true" 3872 ><path d="M6 9H4.5a2.5 2.5 0 0 1 0-5H6"/><path d="M18 9h1.5a2.5 2.5 0 0 0 0-5H18"/><path d="M4 22h16"/><path d="M10 14.66V17c0 .55-.47.98-.97 1.21C7.85 18.75 7 20.24 7 22"/><path d="M14 14.66V17c0 .55.47.98.97 1.21C16.15 18.75 17 20.24 17 22"/><path d="M18 2H6v7a6 6 0 0 0 12 0V2z"/></svg> 3873 <span>Results</span> 3874 </a> 3875 <a 3876 href="https://runningcalendar.co.za/me/saved" 3877 role="link" 3878 class="flex flex-1 flex-col items-center justify-center gap-0.5 py-2 text-xs font-medium transition 3879 3880 text-muted hover:text-ink" 3881 > 3882 <svg 3883 width="24" 3884 height="24" 3885 viewBox="0 0 24 24" 3886 fill="none" 3887 stroke="currentColor" 3888 stroke-width="1.7" 3889 stroke-linecap="round" 3890 stroke-linejoin="round" 3891 class="flex-shrink-0" aria-hidden="true" 3892 ><path d="m19 21-7-4-7 4V5a2 2 0 0 1 2-2h10a2 2 0 0 1 2 2v16z"/></svg> 3893 <span>Saved</span> 3894 </a> 3895 <a 3896 href="/login" 3897 role="link" 3898 class="flex flex-1 flex-col items-center justify-center gap-0.5 py-2 text-xs font-medium transition 3899 3900 text-muted hover:text-ink" 3901 > 3902 <svg 3903 width="24" 3904 height="24"
3905 viewBox="0 0 24 24" 3906 fill="none" 3907 stroke="currentColor" 3908 stroke-width="1.7" 3909 stroke-linecap="round" 3910 stroke-linejoin="round" 3911 class="flex-shrink-0" aria-hidden="true" 3912 ><path d="M19 21v-2a4 4 0 0 0-4-4H9a4 4 0 0 0-4 4v2"/><circle cx="12" cy="7" r="4"/></svg> 3913 <span>Account</span> 3914 </a> 3915 </div> 3916</nav> 3917 3918 3919<div class="h-16 lg:hidden" aria-hidden="true"></div> 3920 3921 3922 <div class="toast-vp rc" 3923 x-data="{}" 3924 @toast.window="$store.toasts.push($event.detail)" 3925 role="region" 3926 aria-label="Notifications"> 3927 3928 <template x-for="t in $store.toasts.items" :key="t.id"> 3929 <div class="toast-slot" :class="{ leaving: t.leaving }"> 3930 <div 3931 class="rc" 3932 :aria-live="(t.type === 'error' || t.type === 'warning') ? 'assertive' : 'polite'" 3933 role="status"> 3934 <div class="toast" :class="{ 'has-x': t.showClose }"> 3935 3936 3937 <div class="toast-ic" :class="t.type"> 3938 <template x-if="t.type === 'success'"> 3939 <svg 3940 width="20" 3941 height="20"
3942 viewBox="0 0 24 24" 3943 fill="none" 3944 stroke="currentColor" 3945 stroke-width="1.8" 3946 stroke-linecap="round" 3947 stroke-linejoin="round" 3948 style="width:19px;height:19px;stroke-width:2.1" class="flex-shrink-0" 3949 ><polyline points="20 6 9 17 4 12"/></svg> 3950 </template> 3951 <template x-if="t.type === 'error'"> 3952 <svg 3953 width="20" 3954 height="20" 3955 viewBox="0 0 24 24" 3956 fill="none" 3957 stroke="currentColor" 3958 stroke-width="1.8" 3959 stroke-linecap="round" 3960 stroke-linejoin="round" 3961 style="width:19px;height:19px;stroke-width:2.1" class="flex-shrink-0" 3962 ><circle cx="12" cy="12" r="10"/><line x1="12" x2="12" y1="8" y2="12"/><line x1="12" x2="12.01" y1="16" y2="16"/></svg> 3963 </template> 3964 <template x-if="t.type === 'info'"> 3965 <svg 3966 width="20" 3967 height="20" 3968 viewBox="0 0 24 24" 3969 fill="none" 3970 stroke="currentColor" 3971 stroke-width="1.8" 3972 stroke-linecap="round" 3973 stroke-linejoin="round" 3974 style="width:19px;height:19px;stroke-width:2.1" class="flex-shrink-0" 3975 ><circle cx="12" cy="12" r="10"/><line x1="12" x2="12" y1="16" y2="12"/><line x1="12" x2="12.01" y1="8" y2="8"/></svg> 3976 </template> 3977 <template x-if="t.type === 'warning'"> 3978 <svg 3979 width="20" 3980 height="20"
3981 viewBox="0 0 24 24" 3982 fill="none" 3983 stroke="currentColor" 3984 stroke-width="1.8" 3985 stroke-linecap="round" 3986 stroke-linejoin="round" 3987 style="width:19px;height:19px;stroke-width:2.1" class="flex-shrink-0" 3988 ><path d="m21.73 18-8-14a2 2 0 0 0-3.48 0l-8 14A2 2 0 0 0 4 21h16a2 2 0 0 0 1.73-3Z"/><path d="M12 9v4"/><path d="M12 17h.01"/></svg> 3989 </template> 3990 <template x-if="t.type === 'loading'"> 3991 <svg 3992 width="20" 3993 height="20" 3994 viewBox="0 0 24 24" 3995 fill="none" 3996 stroke="currentColor" 3997 stroke-width="1.8" 3998 stroke-linecap="round" 3999 stroke-linejoin="round" 4000 style="width:19px;height:19px;stroke-width:2.1" class="flex-shrink-0" 4001 ><line x1="12" x2="12" y1="2" y2="6"/><line x1="12" x2="12" y1="18" y2="22"/><line x1="4.93" x2="7.76" y1="4.93" y2="7.76"/><line x1="16.24" x2="19.07" y1="16.24" y2="19.07"/><line x1="2" x2="6" y1="12" y2="12"/><line x1="18" x2="22" y1="12" y2="12"/><line x1="4.93" x2="7.76" y1="19.07" y2="16.24"/><line x1="16.24" x2="19.07" y1="7.76" y2="4.93"/></svg> 4002 </template> 4003 </div> 4004 4005 4006 <div class="toast-body"> 4007 <div class="toast-title" x-text="t.title"></div> 4008 <div class="toast-desc" x-show="t.desc" x-text="t.desc"></div> 4009 4010 4011 <div class="toast-acts" x-show="t.actions && t.actions.length > 0"> 4012 <template x-for="(action, i) in t.actions" :key="i"> 4013 <button 4014 :class="action.primary ? 'a-primary' : 'a-ghost'" 4015 @click="action.handler && action.handler(); 4016 action.event && window.dispatchEvent(new CustomEvent(action.event, { detail: action.detail || {} })); 4017 $store.toasts.remove(t.id)" 4018 x-text="action.label"> 4019 </button> 4020 </template> 4021 </div> 4022 </div> 4023 4024 4025 <button 4026 x-show="t.showClose" 4027 class="toast-x" 4028 aria-label="Dismiss notification" 4029 @click="$store.toasts.remove(t.id)"> 4030 <svg 4031 width="20" 4032 height="20"
4033 viewBox="0 0 24 24" 4034 fill="none" 4035 stroke="currentColor" 4036 stroke-width="1.8" 4037 stroke-linecap="round" 4038 stroke-linejoin="round" 4039 style="width:15px;height:15px" class="flex-shrink-0" 4040 ><line x1="18" x2="6" y1="6" y2="18"/><line x1="6" x2="18" y1="6" y2="18"/></svg> 4041 </button> 4042 4043 4044 <span 4045 x-show="t.duration && t.type !== 'loading'" 4046 class="toast-prog" 4047 :class="t.type" 4048 :style="t.duration ? `animation: ct-shrink ${t.duration}ms linear forwards` : ''"> 4049 </span> 4050 4051 </div> 4052 </div> 4053 </div> 4054 </template> 4055</div> 4056 <style> 4057.rc .cm-scrim { 4058 position: fixed; 4059 inset: 0; 4060 z-index: 50; 4061 display: flex; 4062 align-items: center; 4063 justify-content: center; 4064 padding: 20px; 4065 background: rgba(10, 22, 40, .55); 4066 backdrop-filter: blur(3px); 4067 -webkit-backdrop-filter: blur(3px); 4068} 4069 4070.rc .cm-card { 4071 position: relative; 4072 width: 100%; 4073 background: var(--surface); 4074 border-radius: var(--r-xl); 4075 box-shadow: 0 24px 64px rgba(10, 22, 40, .28), 0 2px 8px rgba(10, 22, 40, .12); 4076 overflow: hidden; 4077} 4078 4079.rc .cm-close { 4080 position: absolute; 4081 top: 14px; 4082 right: 14px; 4083 width: 32px; 4084 height: 32px; 4085 border-radius: var(--r-md); 4086 border: none; 4087 background: transparent; 4088 color: var(--muted); 4089 display: flex; 4090 align-items: center; 4091 justify-content: center; 4092 cursor: pointer; 4093 transition: background .12s, color .12s; 4094 flex-shrink: 0; 4095} 4096.rc .cm-close:hover { background: var(--soft); color: var(--ink); } 4097 4098.rc .cm-body { padding: 28px 28px 0; } 4099 4100.rc .cm-badge { 4101 width: 46px; 4102 height: 46px; 4103 border-radius: 13px; 4104 display: flex; 4105 align-items: center; 4106 justify-content: center; 4107 margin-bottom: 16px; 4108 flex-shrink: 0; 4109} 4110 4111.rc .cm-eyebrow { 4112 font-family: 'JetBrains Mono', monospace; 4113 font-size: 11px; 4114 text-transform: uppercase; 4115 letter-spacing: 0.1em; 4116 font-weight: 600; 4117 margin-bottom: 8px; 4118} 4119 4120.rc .cm-card h3 { 4121 font-size: 20px; 4122 font-weight: 700; 4123 letter-spacing: -0.02em; 4124 line-height: 1.22; 4125 color: var(--ink); 4126 margin-bottom: 8px; 4127} 4128 4129.rc .cm-card p { 4130 font-size: 15px; 4131 color: var(--ink-2); 4132 line-height: 1.55; 4133} 4134 4135.rc .cm-card p b { color: var(--ink); font-weight: 600; } 4136 4137/* ââ Consequence list ââ */ 4138.rc .cm-list { 4139 list-style: none; 4140 margin: 18px 0 0; 4141 padding: 0; 4142 border: 1px solid var(--rule-soft); 4143 border-radius: var(--r-md); 4144 overflow: hidden; 4145} 4146.rc .cm-list li { 4147 display: flex; 4148 gap: 10px; 4149 padding: 11px 13px; 4150 font-size: 14px; 4151 color: var(--ink-2); 4152 line-height: 1.45; 4153 align-items: flex-start; 4154 border-top: 1px solid var(--rule-soft); 4155} 4156.rc .cm-list li:first-child { border-top: none; } 4157 4158/* ââ Brand info callout ââ */ 4159.rc .cm-note { 4160 display: flex; 4161 gap: 9px; 4162 align-items: center; 4163 margin-top: 16px; 4164 padding: 11px 13px; 4165 background: var(--brand-soft); 4166 border: 1px solid var(--brand-line); 4167 border-radius: var(--r-md); 4168 font-size: 13.5px; 4169 color: var(--brand-deeper); 4170} 4171 4172/* ââ Typed confirm input ââ */ 4173.rc .cm-field { margin-top: 16px; } 4174.rc .cm-label { 4175 font-size: 13px; 4176 color: var(--ink-2); 4177 display: block; 4178 margin-bottom: 7px; 4179} 4180.rc .cm-label b { 4181 font-family: 'JetBrains Mono', monospace; 4182 background: var(--st-cancelled-soft); 4183 color: var(--st-cancelled); 4184 padding: 1px 6px; 4185 border-radius: 4px; 4186 font-weight: 600; 4187} 4188.rc .cm-input { 4189 width: 100%; 4190 height: 44px; 4191 border: 1px solid var(--rule); 4192 border-radius: var(--r-md); 4193 padding: 0 13px; 4194 font-size: 15px; 4195 font-family: 'JetBrains Mono', monospace; 4196 letter-spacing: 0.04em; 4197 outline: none; 4198 transition: border-color .12s, box-shadow .12s; 4199 background: var(--surface); 4200 color: var(--ink); 4201} 4202.rc .cm-input:focus { 4203 border-color: var(--st-cancelled); 4204 box-shadow: 0 0 0 3px var(--st-cancelled-soft); 4205} 4206 4207/* ââ Don't-ask-again check row ââ */ 4208.rc .cm-check { 4209 display: flex; 4210 align-items: center; 4211 gap: 9px; 4212 margin-top: 18px; 4213 padding-top: 16px; 4214 border-top: 1px solid var(--rule-soft); 4215 font-size: 14px; 4216 color: var(--ink-2); 4217 cursor: pointer; 4218 user-select: none; 4219} 4220.rc .cm-check-box { 4221 width: 18px; 4222 height: 18px; 4223 border: 1.5px solid var(--rule); 4224 border-radius: 5px; 4225 display: flex; 4226 align-items: center; 4227 justify-content: center; 4228 flex-shrink: 0; 4229 transition: background .12s, border-color .12s; 4230} 4231.rc .cm-check-box.on { background: var(--brand-deep); border-color: var(--brand-deep); color: #fff; } 4232 4233/* ââ Footer ââ */ 4234.rc .cm-foot { 4235 display: flex; 4236 gap: 10px; 4237 justify-content: flex-end; 4238 align-items: center; 4239 padding: 24px 28px 26px; 4240 margin-top: 24px; 4241} 4242.rc .cm-foot.bordered { border-top: 1px solid var(--rule-soft); } 4243.rc .cm-foot.spread { justify-content: space-between; } 4244.rc .cm-foot .cm-foot-grp { display: flex; gap: 10px; } 4245 4246/* ââ Disabled confirm button ââ */ 4247.rc .cm-foot button:disabled { opacity: .4;
4247 cursor: not-allowed; } 4248 4249/* ââ Modal buttons ââ */ 4250.rc .cm-btn { 4251 display: inline-flex; 4252 align-items: center; 4253 gap: 6px; 4254 padding: 10px 18px; 4255 border-radius: var(--r-md); 4256 font-size: 14px; 4257 font-weight: 600; 4258 line-height: 1; 4259 cursor: pointer; 4260 border: 1px solid transparent; 4261 transition: background .12s, color .12s, border-color .12s; 4262 white-space: nowrap; 4263 text-decoration: none; 4264} 4265.rc .cm-btn-secondary { 4266 background: var(--surface); 4267 color: var(--ink); 4268 border-color: var(--rule); 4269} 4270.rc .cm-btn-secondary:hover:not(:disabled) { background: var(--soft); } 4271 4272.rc .cm-btn-primary { 4273 background: var(--btn-primary, #1F548F); 4274 color: #fff; 4275 border-color: transparent; 4276} 4277.rc .cm-btn-primary:hover:not(:disabled) { background: var(--btn-primary-hover, #143B66); } 4278 4279.rc .cm-btn-danger { 4280 background: var(--st-cancelled, #B91C1C); 4281 color: #fff; 4282 border-color: transparent; 4283} 4284.rc .cm-btn-danger:hover:not(:disabled) { background: color-mix(in srgb, var(--st-cancelled, #B91C1C) 85%, #000); } 4285 4286/* ââ Transitions ââ */ 4287.cm-enter { animation: cm-in .18s cubic-bezier(0.16, 1, 0.3, 1) both; } 4288.cm-leave { animation: cm-out .14s ease-in both; } 4289 4290@keyframes cm-in { 4291 from { opacity: 0; transform: scale(.94) translateY(8px); } 4292 to { opacity: 1; transform: scale(1) translateY(0); } 4293} 4294@keyframes cm-out { 4295 from { opacity: 1; transform: scale(1) translateY(0); } 4296 to { opacity: 0; transform: scale(.96) translateY(4px); } 4297} 4298</style> 4299 4300 4301<div class="rc" 4302 x-data="{}" 4303 @confirm-modal.window="$store.confirmModal.open($event.detail)" 4304 @keydown.escape.window="$store.confirmModal.cancel()"> 4305 4306 <div class="cm-scrim" 4307 x-show="$store.confirmModal.visible" 4308 x-transition:enter="transition ease-out duration-150" 4309 x-transition:enter-start="opacity-0" 4310 x-transition:enter-end="opacity-100" 4311 x-transition:leave="transition ease-in duration-100" 4312 x-transition:leave-start="opacity-100" 4313 x-transition:leave-end="opacity-0" 4314 @click.self="$store.confirmModal.cancel()" 4315 style="display:none;" 4316 role="dialog" 4317 aria-modal="true" 4318 :aria-labelledby="'cm-title-' + $store.confirmModal._id"> 4319 4320 4321 <div class="cm-card cm-enter" 4322 :style="'max-width:' + $store.confirmModal.width + 'px; ' + $store.confirmModal.badgeVars" 4323 @click.stop> 4324 4325 4326 <button class="cm-close" @click="$store.confirmModal.cancel()" aria-label="Close dialog"> 4327 <svg 4328 width="16" 4329 height="16"
4330 viewBox="0 0 24 24" 4331 fill="none" 4332 stroke="currentColor" 4333 stroke-width="1.8" 4334 stroke-linecap="round" 4335 stroke-linejoin="round" 4336 class="flex-shrink-0" 4337 ><line x1="18" x2="6" y1="6" y2="18"/><line x1="6" x2="18" y1="6" y2="18"/></svg> 4338 </button> 4339 4340 4341 <div class="cm-body"> 4342 4343 4344 <div x-show="$store.confirmModal.icon" 4345 class="cm-badge" 4346 style="background: var(--cm-badge-bg); color: var(--cm-badge-fg);"> 4347 4348 <template x-if="$store.confirmModal.icon === 'trash'"> 4349 <svg 4350 width="22" 4351 height="22" 4352 viewBox="0 0 24 24" 4353 fill="none" 4354 stroke="currentColor" 4355 stroke-width="2" 4356 stroke-linecap="round" 4357 stroke-linejoin="round" 4358 class="flex-shrink-0" 4359 ><path d="M3 6h18"/><path d="M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6"/><path d="M8 6V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2"/><line x1="10" x2="10" y1="11" y2="17"/><line x1="14" x2="14" y1="11" y2="17"/></svg> 4360 </template> 4361 <template x-if="$store.confirmModal.icon === 'alert-triangle'"> 4362 <svg 4363 width="22" 4364 height="22"
4365 viewBox="0 0 24 24" 4366 fill="none" 4367 stroke="currentColor" 4368 stroke-width="2" 4369 stroke-linecap="round" 4370 stroke-linejoin="round" 4371 class="flex-shrink-0" 4372 ><path d="m21.73 18-8-14a2 2 0 0 0-3.48 0l-8 14A2 2 0 0 0 4 21h16a2 2 0 0 0 1.73-3Z"/><path d="M12 9v4"/><path d="M12 17h.01"/></svg> 4373 </template> 4374 <template x-if="$store.confirmModal.icon === 'log-out'"> 4375 <svg 4376 width="22" 4377 height="22" 4378 viewBox="0 0 24 24" 4379 fill="none" 4380 stroke="currentColor" 4381 stroke-width="2" 4382 stroke-linecap="round" 4383 stroke-linejoin="round" 4384 class="flex-shrink-0" 4385 ><path d="M9 21H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h4"/><polyline points="16 17 21 12 16 7"/><line x1="21" x2="9" y1="12" y2="12"/></svg> 4386 </template> 4387 <template x-if="$store.confirmModal.icon === 'check-circle'"> 4388 <svg 4389 width="22" 4390 height="22"
4391 viewBox="0 0 24 24" 4392 fill="none" 4393 stroke="currentColor" 4394 stroke-width="2" 4395 stroke-linecap="round" 4396 stroke-linejoin="round" 4397 class="flex-shrink-0" 4398 ><path d="M22 11.08V12a10 10 0 1 1-5.93-9.14"/><polyline points="22 4 12 14.01 9 11.01"/></svg> 4399 </template> 4400 <template x-if="$store.confirmModal.icon === 'arrow-up-right'"> 4401 <svg 4402 width="22" 4403 height="22" 4404 viewBox="0 0 24 24" 4405 fill="none" 4406 stroke="currentColor" 4407 stroke-width="2" 4408 stroke-linecap="round" 4409 stroke-linejoin="round" 4410 class="flex-shrink-0" 4411 ><path d="M7 7h10v10"/><path d="M7 17 17 7"/></svg> 4412 </template> 4413 <template x-if="$store.confirmModal.icon === 'alert-octagon'"> 4414 <svg 4415 width="22" 4416 height="22" 4417 viewBox="0 0 24 24" 4418 fill="none" 4419 stroke="currentColor" 4420 stroke-width="2" 4421 stroke-linecap="round" 4422 stroke-linejoin="round" 4423 class="flex-shrink-0" 4424 ><polygon points="7.86 2 16.14 2 22 7.86 22 16.14 16.14 22 7.86 22 2 16.14 2 7.86 7.86 2"/><line x1="12" x2="12" y1="8" y2="12"/><line x1="12" x2="12.01" y1="16" y2="16"/></svg> 4425 </template> 4426 <template x-if="$store.confirmModal.icon === 'bell'"> 4427 <svg 4428 width="22" 4429 height="22"
4430 viewBox="0 0 24 24" 4431 fill="none" 4432 stroke="currentColor" 4433 stroke-width="2" 4434 stroke-linecap="round" 4435 stroke-linejoin="round" 4436 class="flex-shrink-0" 4437 ><path d="M6 8a6 6 0 0 1 12 0c0 7 3 9 3 9H3s3-2 3-9"/><path d="M10.3 21a1.94 1.94 0 0 0 3.4 0"/></svg> 4438 </template> 4439 <template x-if="$store.confirmModal.icon === 'info'"> 4440 <svg 4441 width="22" 4442 height="22" 4443 viewBox="0 0 24 24" 4444 fill="none" 4445 stroke="currentColor" 4446 stroke-width="2" 4447 stroke-linecap="round" 4448 stroke-linejoin="round" 4449 class="flex-shrink-0" 4450 ><circle cx="12" cy="12" r="10"/><line x1="12" x2="12" y1="16" y2="12"/><line x1="12" x2="12.01" y1="8" y2="8"/></svg> 4451 </template> 4452 <template x-if="$store.confirmModal.icon === 'ban'"> 4453 <svg 4454 width="22" 4455 height="22" 4456 viewBox="0 0 24 24" 4457 fill="none" 4458 stroke="currentColor" 4459 stroke-width="2" 4460 stroke-linecap="round" 4461 stroke-linejoin="round" 4462 class="flex-shrink-0" 4463 ><circle cx="12" cy="12" r="10"/><line x1="4.93" x2="19.07" y1="4.93" y2="19.07"/></svg> 4464 </template> 4465 </div> 4466 4467 4468 <div x-show="$store.confirmModal.eyebrow" 4469 class="cm-eyebrow" 4470 style="color: var(--cm-badge-fg);" 4471 x-text="$store.confirmModal.eyebrow"> 4472 </div> 4473 4474 4475 <h3 :id="'cm-title-' + $store.confirmModal._id" 4476 x-text="$store.confirmModal.title"> 4477 </h3> 4478 4479 4480 <p x-show="$store.confirmModal.body" 4481 x-html="$store.confirmModal.body"> 4482 </p> 4483 4484 4485 <ul class="cm-list" 4486 x-show="$store.confirmModal.items && $store.confirmModal.items.length > 0"> 4487 <template x-for="(item, i) in $store.confirmModal.items" :key="i"> 4488 <li> 4489 <template x-if="item.icon === 'check'"> 4490 <svg 4491 width="15" 4492 height="15"
4493 viewBox="0 0 24 24" 4494 fill="none" 4495 stroke="currentColor" 4496 stroke-width="2.2" 4497 stroke-linecap="round" 4498 stroke-linejoin="round" 4499 style="color: var(--st-verified)" class="flex-shrink-0" 4500 ><polyline points="20 6 9 17 4 12"/></svg> 4501 </template> 4502 <template x-if="item.icon === 'ban'"> 4503 <svg 4504 width="15" 4505 height="15" 4506 viewBox="0 0 24 24" 4507 fill="none" 4508 stroke="currentColor" 4509 stroke-width="2.2" 4510 stroke-linecap="round" 4511 stroke-linejoin="round" 4512 style="color: var(--st-cancelled)" class="flex-shrink-0" 4513 ><circle cx="12" cy="12" r="10"/><line x1="4.93" x2="19.07" y1="4.93" y2="19.07"/></svg> 4514 </template> 4515 <template x-if="item.icon === 'info'"> 4516 <svg 4517 width="15" 4518 height="15" 4519 viewBox="0 0 24 24" 4520 fill="none" 4521 stroke="currentColor" 4522 stroke-width="2.2" 4523 stroke-linecap="round" 4524 stroke-linejoin="round" 4525 style="color: var(--brand-deeper)" class="flex-shrink-0" 4526 ><circle cx="12" cy="12" r="10"/><line x1="12" x2="12" y1="16" y2="12"/><line x1="12" x2="12.01" y1="8" y2="8"/></svg> 4527 </template> 4528 <span x-html="item.text"></span> 4529 </li> 4530 </template> 4531 </ul> 4532 4533 4534 <div class="cm-note" x-show="$store.confirmModal.note"> 4535 <svg 4536 width="15" 4537 height="15"
4538 viewBox="0 0 24 24" 4539 fill="none" 4540 stroke="currentColor" 4541 stroke-width="2" 4542 stroke-linecap="round" 4543 stroke-linejoin="round" 4544 style="color: var(--brand-deeper)" class="flex-shrink-0" 4545 ><circle cx="12" cy="12" r="10"/><line x1="12" x2="12" y1="16" y2="12"/><line x1="12" x2="12.01" y1="8" y2="8"/></svg> 4546 <span x-text="$store.confirmModal.note"></span> 4547 </div> 4548 4549 4550 <div class="cm-field" x-show="$store.confirmModal.typedConfirm"> 4551 <label class="cm-label"> 4552 Type <b x-text="$store.confirmModal.typedConfirm"></b> to confirm 4553 </label> 4554 <input class="cm-input" 4555 type="text" 4556 :placeholder="$store.confirmModal.typedConfirm" 4557 x-model="$store.confirmModal.typedValue" 4558 spellcheck="false" 4559 autocomplete="off" /> 4560 </div> 4561 4562 </div> 4563 4564 4565 <div x-show="$store.confirmModal.buttonOrder !== 'flipped'" 4566 class="cm-foot" 4567 :class="{ 'bordered': $store.confirmModal.tone === 'destructive' && $store.confirmModal.typedConfirm }"> 4568 <button class="cm-btn cm-btn-secondary" 4569 @click="$store.confirmModal.cancel()" 4570 x-text="$store.confirmModal.cancelLabel"> 4571 </button> 4572 <button :class="$store.confirmModal.tone === 'info' || $store.confirmModal.tone === 'success' || $store.confirmModal.tone === 'neutral' 4573 ? 'cm-btn cm-btn-primary' 4574 : 'cm-btn cm-btn-danger'" 4575 :disabled="!$store.confirmModal.confirmEnabled" 4576 @click="$store.confirmModal.confirm()" 4577 x-text="$store.confirmModal.confirmLabel"> 4578 </button> 4579 </div> 4580 4581 4582 <div x-show="$store.confirmModal.buttonOrder === 'flipped'" 4583 class="cm-foot bordered spread"> 4584 <button class="cm-btn cm-btn-danger" 4585 @click="$store.confirmModal.confirm()" 4586 x-text="$store.confirmModal.confirmLabel"> 4587 </button> 4588 <button class="cm-btn cm-btn-primary" 4589 @click="$store.confirmModal.cancel()" 4590 x-text="$store.confirmModal.cancelLabel"> 4591 </button> 4592 </div> 4593 4594 </div> 4595 </div> 4596</div> 4597 <div x-data="cookieNotice" x-cloak> 4598 4599 4600 <div x-show="show && isDesktop" class="ck-desktop rc" data-cookie-notice> 4601 4602 4603 <div x-show="view === 'banner'"> 4604 <div class="ck"> 4605 <div class="ck-head"> 4606 <div class="ck-medal"> 4607 <svg 4608 width="20" 4609 height="20"
4610 viewBox="0 0 24 24" 4611 fill="none" 4612 stroke="currentColor" 4613 stroke-width="1.8" 4614 stroke-linecap="round" 4615 stroke-linejoin="round" 4616 style="width:22px;height:22px;color:var(--brand-deep);stroke-width:1.9" class="flex-shrink-0" 4617 ><path d="M12 2a10 10 0 1 0 10 10 4 4 0 0 1-5-5 4 4 0 0 1-5-5"/><path d="M8.5 8.5v.01"/><path d="M16 15.5v.01"/><path d="M12 12v.01"/><path d="M11 17v.01"/><path d="M7 14v.01"/></svg> 4618 </div> 4619 <div> 4620 <h4>We use cookies</h4> 4621 <div class="sub">POPIA · runningcalendar.co.za</div> 4622 </div> 4623 </div> 4624 <p> 4625 We use cookies to keep you signed in, remember your saved races, and understand which events 4626 runners are looking for. You can accept all, reject non-essential, or choose what you allow. 4627 See our <a href="https://runningcalendar.co.za/cookies">Cookie Policy</a>. 4628 </p> 4629 <div class="ck-actions"> 4630 <button 4631 class="inline-flex items-center justify-center gap-2 rounded-lg font-medium transition border border-transparent bg-surface text-ink border-rule hover:bg-soft px-3 py-1.5 text-sm min-h-9" type="button" @click="rejectAll()" 4632> 4633 Reject all 4634 </button> 4635 <button 4636 class="inline-flex items-center justify-center gap-2 rounded-lg font-medium transition border border-transparent bg-brand-500 text-white hover:bg-brand-600 px-3 py-1.5 text-sm min-h-9" type="button" @click="acceptAll()" 4637> 4638 Accept all 4639 </button> 4640 <span class="grow"></span> 4641 <button class="ck-managelink" @click="view = 'prefs'" type="button"> 4642 <svg 4643 width="20" 4644 height="20"
4645 viewBox="0 0 24 24" 4646 fill="none" 4647 stroke="currentColor" 4648 stroke-width="1.8" 4649 stroke-linecap="round" 4650 stroke-linejoin="round" 4651 style="width:15px;height:15px" class="flex-shrink-0" 4652 ><line x1="21" x2="14" y1="4" y2="4"/><line x1="10" x2="3" y1="4" y2="4"/><line x1="21" x2="12" y1="12" y2="12"/><line x1="8" x2="3" y1="12" y2="12"/><line x1="21" x2="16" y1="20" y2="20"/><line x1="12" x2="3" y1="20" y2="20"/><line x1="14" x2="14" y1="2" y2="6"/><line x1="8" x2="8" y1="10" y2="14"/><line x1="16" x2="16" y1="18" y2="22"/></svg> 4653 Manage 4654 </button> 4655 </div> 4656 </div> 4657 </div> 4658 4659 4660 <div x-show="view === 'prefs'"> 4661 <div class="ck ck-wide"> 4662 <div class="ck-head"> 4663 <div class="ck-medal"> 4664 <svg 4665 width="20" 4666 height="20" 4667 viewBox="0 0 24 24" 4668 fill="none" 4669 stroke="currentColor" 4670 stroke-width="1.8" 4671 stroke-linecap="round" 4672 stroke-linejoin="round" 4673 style="width:20px;height:20px;color:var(--brand-deep);stroke-width:1.9" class="flex-shrink-0" 4674 ><line x1="21" x2="14" y1="4" y2="4"/><line x1="10" x2="3" y1="4" y2="4"/><line x1="21" x2="12" y1="12" y2="12"/><line x1="8" x2="3" y1="12" y2="12"/><line x1="21" x2="16" y1="20" y2="20"/><line x1="12" x2="3" y1="20" y2="20"/><line x1="14" x2="14" y1="2" y2="6"/><line x1="8" x2="8" y1="10" y2="14"/><line x1="16" x2="16" y1="18" y2="22"/></svg> 4675 </div> 4676 <div> 4677 <h4>Manage cookie preferences</h4> 4678 <div class="sub">POPIA · choose what you allow</div> 4679 </div> 4680 </div> 4681 4682 <div class="ck-prefs"> 4683 4684 <div class="ck-pref"> 4685 <div class="pic"> 4686 <svg 4687 width="20" 4688 height="20"
4689 viewBox="0 0 24 24" 4690 fill="none" 4691 stroke="currentColor" 4692 stroke-width="1.8" 4693 stroke-linecap="round" 4694 stroke-linejoin="round" 4695 style="width:18px;height:18px" class="flex-shrink-0" 4696 ><path d="M20 13c0 5-3.5 7.5-7.66 8.95a1 1 0 0 1-.67-.01C7.5 20.5 4 18 4 13V6a1 1 0 0 1 1-1c2 0 4.5-1.2 6.24-2.72a1.17 1.17 0 0 1 1.52 0C14.51 3.81 17 5 19 5a1 1 0 0 1 1 1z"/></svg> 4697 </div> 4698 <div class="grow"> 4699 <div class="nm"> 4700 Strictly necessary 4701 <span class="req">Always on</span> 4702 </div> 4703 <div class="ds">Required for the site to work â search, saved races, and your login session. Always on.</div> 4704 </div> 4705 <button class="ck-sw locked" role="switch" aria-checked="true" aria-disabled="true" type="button"></button> 4706 </div> 4707 4708 4709 <div class="ck-pref"> 4710 <div class="pic"> 4711 <svg 4712 width="20" 4713 height="20"
4714 viewBox="0 0 24 24" 4715 fill="none" 4716 stroke="currentColor" 4717 stroke-width="1.8" 4718 stroke-linecap="round" 4719 stroke-linejoin="round" 4720 style="width:18px;height:18px" class="flex-shrink-0" 4721 ><line x1="12" x2="12" y1="20" y2="10"/><line x1="18" x2="18" y1="20" y2="4"/><line x1="6" x2="6" y1="20" y2="16"/></svg> 4722 </div> 4723 <div class="grow"> 4724 <div class="nm">Analytics</div> 4725 <div class="ds">Anonymous stats on which races and pages runners visit, so we can improve the calendar.</div> 4726 </div> 4727 <button 4728 class="ck-sw" 4729 :class="{ on: prefs.analytics }" 4730 role="switch" 4731 :aria-checked="prefs.analytics ? 'true' : 'false'" 4732 @click="prefs.analytics = !prefs.analytics" 4733 type="button"> 4734 </button> 4735 </div> 4736 4737 4738 <div class="ck-pref"> 4739 <div class="pic"> 4740 <svg 4741 width="20" 4742 height="20"
4743 viewBox="0 0 24 24" 4744 fill="none" 4745 stroke="currentColor" 4746 stroke-width="1.8" 4747 stroke-linecap="round" 4748 stroke-linejoin="round" 4749 style="width:18px;height:18px" class="flex-shrink-0" 4750 ><path d="m3 11 18-5v12L3 14v-3z"/><path d="M11.6 16.8a3 3 0 1 1-5.8-1.6"/></svg> 4751 </div> 4752 <div class="grow"> 4753 <div class="nm">Advertising</div> 4754 <div class="ds">Lets our partners show race-related ads. Turning this off enables the ad-free experience.</div> 4755 </div> 4756 <button 4757 class="ck-sw" 4758 :class="{ on: prefs.advertising }" 4759 role="switch" 4760 :aria-checked="prefs.advertising ? 'true' : 'false'" 4761 @click="prefs.advertising = !prefs.advertising" 4762 type="button"> 4763 </button> 4764 </div> 4765 </div> 4766 4767 <div class="ck-actions"> 4768 <button 4769 class="inline-flex items-center justify-center gap-2 rounded-lg font-medium transition border border-transparent bg-surface text-ink border-rule hover:bg-soft px-3 py-1.5 text-sm min-h-9" type="button" @click="view = 'banner'" 4770> 4771 Back 4772 </button> 4773 <button 4774 class="inline-flex items-center justify-center gap-2 rounded-lg font-medium transition border border-transparent bg-surface text-ink border-rule hover:bg-soft px-3 py-1.5 text-sm min-h-9" type="button" @click="savePrefs()" 4775> 4776 Save preferences 4777 </button> 4778 <span class="grow"></span> 4779 <button 4780 class="inline-flex items-center justify-center gap-2 rounded-lg font-medium transition border border-transparent bg-brand-500 text-white hover:bg-brand-600 px-3 py-1.5 text-sm min-h-9" type="button" @click="manageAcceptAll()" 4781> 4782 Accept all 4783 </button> 4784 </div> 4785 </div> 4786 </div> 4787 4788 </div> 4789 4790 4791 <div x-show="show && !isDesktop" class="ck-mobile rc" data-cookie-notice> 4792 4793 4794 <div x-show="view === 'banner'"> 4795 <div class="ck"> 4796 <div class="ck-head"> 4797 <div class="ck-medal"> 4798 <svg 4799 width="20" 4800 height="20"
4801 viewBox="0 0 24 24" 4802 fill="none" 4803 stroke="currentColor" 4804 stroke-width="1.8" 4805 stroke-linecap="round" 4806 stroke-linejoin="round" 4807 style="width:22px;height:22px;color:var(--brand-deep);stroke-width:1.9" class="flex-shrink-0" 4808 ><path d="M12 2a10 10 0 1 0 10 10 4 4 0 0 1-5-5 4 4 0 0 1-5-5"/><path d="M8.5 8.5v.01"/><path d="M16 15.5v.01"/><path d="M12 12v.01"/><path d="M11 17v.01"/><path d="M7 14v.01"/></svg> 4809 </div> 4810 <div> 4811 <h4>We use cookies</h4> 4812 <div class="sub">POPIA · co.za</div> 4813 </div> 4814 </div> 4815 <p> 4816 We use cookies to keep you signed in and remember your saved races. 4817 See our <a href="https://runningcalendar.co.za/cookies">Cookie Policy</a>. 4818 </p> 4819 <div style="display:flex;flex-direction:column;gap:9px"> 4820 <button 4821 class="inline-flex items-center justify-center gap-2 rounded-lg font-medium transition border border-transparent bg-brand-500 text-white hover:bg-brand-600 px-4.5 py-2.5 text-sm min-h-11 w-full" type="button" @click="acceptAll()" 4822> 4823 Accept all 4824 </button> 4825 <div style="display:flex;gap:9px"> 4826 <button 4827 class="inline-flex items-center justify-center gap-2 rounded-lg font-medium transition border border-transparent bg-surface text-ink border-rule hover:bg-soft px-4.5 py-2.5 text-sm min-h-11 w-full" type="button" @click="rejectAll()" 4828> 4829 Reject all 4830 </button> 4831 <button 4832 class="inline-flex items-center justify-center gap-2 rounded-lg font-medium transition border border-transparent bg-surface text-ink border-rule hover:bg-soft px-4.5 py-2.5 text-sm min-h-11 w-full" type="button" @click="view = 'prefs'" 4833> 4834 Manage 4835 </button> 4836 </div> 4837 </div> 4838 </div> 4839 </div> 4840 4841 4842 <div x-show="view === 'prefs'"> 4843 <div class="ck"> 4844 <div class="ck-head"> 4845 <div class="ck-medal"> 4846 <svg 4847 width="20" 4848 height="20"
4849 viewBox="0 0 24 24" 4850 fill="none" 4851 stroke="currentColor" 4852 stroke-width="1.8" 4853 stroke-linecap="round" 4854 stroke-linejoin="round" 4855 style="width:20px;height:20px;color:var(--brand-deep);stroke-width:1.9" class="flex-shrink-0" 4856 ><line x1="21" x2="14" y1="4" y2="4"/><line x1="10" x2="3" y1="4" y2="4"/><line x1="21" x2="12" y1="12" y2="12"/><line x1="8" x2="3" y1="12" y2="12"/><line x1="21" x2="16" y1="20" y2="20"/><line x1="12" x2="3" y1="20" y2="20"/><line x1="14" x2="14" y1="2" y2="6"/><line x1="8" x2="8" y1="10" y2="14"/><line x1="16" x2="16" y1="18" y2="22"/></svg> 4857 </div> 4858 <div> 4859 <h4>Manage cookie preferences</h4> 4860 <div class="sub">POPIA · choose what you allow</div> 4861 </div> 4862 </div> 4863 4864 <div class="ck-prefs"> 4865 <div class="ck-pref"> 4866 <div class="pic"><svg 4867 width="20" 4868 height="20"
4869 viewBox="0 0 24 24" 4870 fill="none" 4871 stroke="currentColor" 4872 stroke-width="1.8" 4873 stroke-linecap="round" 4874 stroke-linejoin="round" 4875 style="width:18px;height:18px" class="flex-shrink-0" 4876 ><path d="M20 13c0 5-3.5 7.5-7.66 8.95a1 1 0 0 1-.67-.01C7.5 20.5 4 18 4 13V6a1 1 0 0 1 1-1c2 0 4.5-1.2 6.24-2.72a1.17 1.17 0 0 1 1.52 0C14.51 3.81 17 5 19 5a1 1 0 0 1 1 1z"/></svg> 4877</div> 4878 <div class="grow"> 4879 <div class="nm">Strictly necessary <span class="req">Always on</span></div> 4880 <div class="ds">Required for the site to work. Always on.</div> 4881 </div> 4882 <button class="ck-sw locked" role="switch" aria-checked="true" aria-disabled="true" type="button"></button> 4883 </div> 4884 <div class="ck-pref"> 4885 <div class="pic"><svg 4886 width="20" 4887 height="20" 4888 viewBox="0 0 24 24" 4889 fill="none" 4890 stroke="currentColor" 4891 stroke-width="1.8" 4892 stroke-linecap="round" 4893 stroke-linejoin="round" 4894 style="width:18px;height:18px" class="flex-shrink-0" 4895 ><line x1="12" x2="12" y1="20" y2="10"/><line x1="18" x2="18" y1="20" y2="4"/><line x1="6" x2="6" y1="20" y2="16"/></svg> 4896</div> 4897 <div class="grow"> 4898 <div class="nm">Analytics</div> 4899 <div class="ds">Anonymous usage stats to improve the calendar.</div> 4900 </div> 4901 <button class="ck-sw" :class="{ on: prefs.analytics }" role="switch" 4902 :aria-checked="prefs.analytics ? 'true' : 'false'" 4903 @click="prefs.analytics = !prefs.analytics" type="button"></button> 4904 </div> 4905 <div class="ck-pref"> 4906 <div class="pic"><svg 4907 width="20" 4908 height="20"
4909 viewBox="0 0 24 24" 4910 fill="none" 4911 stroke="currentColor" 4912 stroke-width="1.8" 4913 stroke-linecap="round" 4914 stroke-linejoin="round" 4915 style="width:18px;height:18px" class="flex-shrink-0" 4916 ><path d="m3 11 18-5v12L3 14v-3z"/><path d="M11.6 16.8a3 3 0 1 1-5.8-1.6"/></svg> 4917</div> 4918 <div class="grow"> 4919 <div class="nm">Advertising</div> 4920 <div class="ds">Race-related ads that fund this free calendar.</div> 4921 </div> 4922 <button class="ck-sw" :class="{ on: prefs.advertising }" role="switch" 4923 :aria-checked="prefs.advertising ? 'true' : 'false'" 4924 @click="prefs.advertising = !prefs.advertising" type="button"></button> 4925 </div> 4926 </div> 4927 4928 <div style="display:flex;flex-direction:column;gap:9px"> 4929 <button 4930 class="inline-flex items-center justify-center gap-2 rounded-lg font-medium transition border border-transparent bg-brand-500 text-white hover:bg-brand-600 px-4.5 py-2.5 text-sm min-h-11 w-full" type="button" @click="manageAcceptAll()" 4931> 4932 Accept all 4933 </button> 4934 <div style="display:flex;gap:9px"> 4935 <button 4936 class="inline-flex items-center justify-center gap-2 rounded-lg font-medium transition border border-transparent bg-surface text-ink border-rule hover:bg-soft px-4.5 py-2.5 text-sm min-h-11 w-full" type="button" @click="view = 'banner'" 4937> 4938 Back 4939 </button> 4940 <button 4941 class="inline-flex items-center justify-center gap-2 rounded-lg font-medium transition border border-transparent bg-surface text-ink border-rule hover:bg-soft px-4.5 py-2.5 text-sm min-h-11 w-full" type="button" @click="savePrefs()" 4942> 4943 Save preferences 4944 </button> 4945 </div> 4946 </div> 4947 </div> 4948 </div> 4949 4950 </div> 4951 4952</div> 4953 <div x-data="pwaInstall" x-cloak class="rc"> 4954 <div x-show="visible" x-transition.opacity class="pwa-banner" role="dialog" aria-label="Install RunningCalendar"> 4955 4956 <button type="button" class="pwa-banner-close" @click="dismiss()" aria-label="Dismiss"> 4957 <svg 4958 width="18" 4959 height="18"
4960 viewBox="0 0 24 24" 4961 fill="none" 4962 stroke="currentColor" 4963 stroke-width="2" 4964 stroke-linecap="round" 4965 stroke-linejoin="round" 4966 class="flex-shrink-0" 4967 ><line x1="18" x2="6" y1="6" y2="18"/><line x1="6" x2="18" y1="6" y2="18"/></svg> 4968 </button> 4969 4970 <div class="pwa-banner-mark"> 4971 <img src="/icons/icon-192.png" alt="" width="44" height="44"> 4972 </div> 4973 4974 4975 <template x-if="canInstall"> 4976 <div class="pwa-banner-body"> 4977 <h4>Install RunningCalendar</h4> 4978 <p>Add it to your home screen for a faster, full-screen, app-like experience.</p> 4979 <div class="pwa-banner-acts"> 4980 <button type="button" class="pwa-btn pwa-btn-primary" @click="install()"> 4981 <svg 4982 width="16" 4983 height="16" 4984 viewBox="0 0 24 24" 4985 fill="none" 4986 stroke="currentColor" 4987 stroke-width="2" 4988 stroke-linecap="round" 4989 stroke-linejoin="round" 4990 class="flex-shrink-0" 4991 ><path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"/><polyline points="7 10 12 15 17 10"/><line x1="12" x2="12" y1="15" y2="3"/></svg> 4992 Add to home screen 4993 </button> 4994 <button type="button" class="pwa-btn pwa-btn-ghost" @click="dismiss()">Not now</button> 4995 </div> 4996 </div> 4997 </template> 4998 4999 5000 <template x-if="isIos && !canInstall"> 5001 <div class="pwa-banner-body"> 5002 <h4>Add to your Home Screen</h4> 5003 <p> 5004 Tap <span class="pwa-inline-icon"><svg 5005 width="15" 5006 height="15"
5007 viewBox="0 0 24 24" 5008 fill="none" 5009 stroke="currentColor" 5010 stroke-width="2" 5011 stroke-linecap="round" 5012 stroke-linejoin="round" 5013 class="flex-shrink-0" 5014 ><circle cx="18" cy="5" r="3"/><circle cx="6" cy="12" r="3"/><circle cx="18" cy="19" r="3"/><line x1="8.59" x2="15.42" y1="13.51" y2="17.49"/><line x1="15.41" x2="8.59" y1="6.51" y2="10.49"/></svg> 5015</span> 5016 <strong>Share</strong>, then choose 5017 <span class="pwa-inline-icon"><svg 5018 width="15" 5019 height="15" 5020 viewBox="0 0 24 24" 5021 fill="none" 5022 stroke="currentColor" 5023 stroke-width="2" 5024 stroke-linecap="round" 5025 stroke-linejoin="round" 5026 class="flex-shrink-0" 5027 ><line x1="12" x2="12" y1="5" y2="19"/><line x1="5" x2="19" y1="12" y2="12"/></svg> 5028</span> 5029 <strong>Add to Home Screen</strong>. 5030 </p> 5031 <div class="pwa-banner-acts"> 5032 <button type="button" class="pwa-btn pwa-btn-ghost" @click="dismiss()">Got it</button> 5033 </div> 5034 </div> 5035 </template> 5036 5037 </div> 5038</div> 5039 5040 5041 <div 5042 x-data="imageLightbox" 5043 x-show="open" 5044 x-cloak 5045 @open-lightbox.window="show($event.detail)" 5046 @keydown.escape.window="close()" 5047 class="rc-lightbox" 5048 role="dialog" 5049 aria-modal="true" 5050 aria-label="Image viewer" 5051 > 5052 <button type="button" class="rc-lightbox-close" @click="close()" aria-label="Close image viewer"> 5053 <svg 5054 width="22" 5055 height="22"
5056 viewBox="0 0 24 24" 5057 fill="none" 5058 stroke="currentColor" 5059 stroke-width="2" 5060 stroke-linecap="round" 5061 stroke-linejoin="round" 5062 class="flex-shrink-0" 5063 ><line x1="18" x2="6" y1="6" y2="18"/><line x1="6" x2="18" y1="6" y2="18"/></svg> 5064 </button> 5065 <div class="rc-lightbox-stage" @click.self="close()"> 5066 <img :src="src" :alt="alt" :class="{ 'is-zoomed': zoomed }" @click="toggleZoom()" draggable="false"> 5067 </div> 5068 <p class="rc-lightbox-hint" x-text="zoomed ? 'Tap image to zoom out' : 'Tap image to zoom · drag/scroll to pan'"></p> 5069 </div>
vendor: 114 bytes, lines 5069-5071
5069 5070 5071 <script data-cfasync="false" src="/cdn-cgi/scripts/5c5dd728/cloudflare-static/email-decode.min.js"></script>
5071<script src="https://runningcalendar.co.za/flux/flux.min.js?id=20391e00" data-navigate-once></script>
vendor: 1 bytes, line 5071
5071
5072<script src="/livewire/livewire.min.js?id=6f2ea2c9" data-csrf="3xb9r3YBUSfm6nHsaFEbe6oegveNR1tmzpnMPFpt" data-update-uri="/livewire/update" data-navigate-once="true"></script>
vendor: 1 bytes, line 5072
5072
5073<script>(function(){function c(){var b=a.contentDocument||(a.contentWindow&&a.contentWindow.document);if(b){var d=b.createElement('script');d.innerHTML="window.__CF$cv$params={r:'a45eb8c13e38ebce',t:'MTc5MTIyNzM3Ng=='};var a=document.createElement('script');a.src='/cdn-cgi/challenge-platform/scripts/jsd/main.js';document.getElementsByTagName('head')[0].appendChild(a);";b.getElementsByTagName('head')[0].appendChild(d)}}if(document.body){var a=document.createElement('iframe');a.height=1;a.width=1;a.style.position='absolute';a.style.top=0;a.style.left=0;a.style.border='none';a.style.visibility='hidden';document.body.appendChild(a);if('loading'!==document.readyState)c();else if(window.addEventListener)document.addEventListener('DOMContentLoaded',c);else{var e=document.onreadystatechange||function(){};document.onreadystatechange=function(b){e(b);'loading'!==document.readyState&&(document.onreadystatechange=e,c())}}}})();</script>
5073<script type="module" src="https://static.cloudflareinsights.com/beacon.min.js/v31edd6df95cf4e85bb4c19e7a9bdbcba1788362987495" integrity="sha512-iIg7k2xntmwu6/uSb5tpc/hySgZc4eoL31yB29W6tJFo2akwjPWcEqnCEdJvGexCL0KEQwVYv5BlowfhVz26hg==" data-cf-beacon='{"version":"2024.11.0","token":"1e1462db51774232945d29045d166056","r":1,"spa":2}' crossorigin="anonymous"></script>
5073 5074</body> 5075 5076</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.