open source is social v-it.org
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

Deploy vit wordmark, favicon, and unified header across both sites

Replace plain text "vit" headers with the wordmark SVG on v-it.org and
explore.v-it.org. Add SVG favicon to explore. Unify header, navigation,
and footer across both sites so they feel like one product. Add hamburger
menu for mobile nav at 600px breakpoint. Explore gets the full cross-site
nav with "explore" active, plus a sub-nav for caps/beacons/stats.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

+531 -283
+67 -41
build.js
··· 78 78 .join('\n '); 79 79 } 80 80 81 + const wordmark = `<svg viewBox="0 0 56 34" xmlns="http://www.w3.org/2000/svg" height="28" aria-hidden="true"> 82 + <circle cx="16" cy="6" r="3" fill="#06D6A0"/> 83 + <path d="M5.5 11 L16 27 L26.5 11" stroke="#06D6A0" stroke-width="3.5" stroke-linecap="round" stroke-linejoin="round" fill="none"/> 84 + <circle cx="33.5" cy="6" r="3" fill="#06D6A0"/> 85 + <line x1="33.5" y1="12.5" x2="33.5" y2="27" stroke="#06D6A0" stroke-width="3.5" stroke-linecap="round"/> 86 + <line x1="45" y1="7" x2="45" y2="27" stroke="#06D6A0" stroke-width="3.5" stroke-linecap="round"/> 87 + <line x1="39" y1="12.5" x2="51" y2="12.5" stroke="#06D6A0" stroke-width="3.5" stroke-linecap="round"/> 88 + </svg>`; 89 + 81 90 function template({ title, description, activeSlug, content, hashRedirect }) { 82 91 return `<!DOCTYPE html> 83 92 <html lang="en"> ··· 112 121 padding: 24px 20px 32px; 113 122 } 114 123 115 - header h1 { 116 - margin: 0; 117 - font-size: 2rem; 118 - line-height: 1.2; 119 - color: var(--vit-green); 124 + header { 125 + border-bottom: 2px solid var(--vit-green); 126 + padding-bottom: 16px; 127 + margin-bottom: 24px; 120 128 } 121 129 122 - header h1 a { 123 - color: inherit; 124 - text-decoration: none; 125 - cursor: default; 130 + .header-bar { 131 + display: flex; 132 + align-items: center; 133 + justify-content: space-between; 134 + gap: 16px; 126 135 } 127 136 128 - .egg { 129 - opacity: 0; 130 - transition: opacity 200ms ease; 131 - color: #9ca3af; 137 + header h1 { 138 + margin: 0; 139 + line-height: 1; 132 140 } 133 141 134 - header h1:hover .egg { 135 - opacity: 1; 142 + header h1 a { 143 + display: inline-block; 144 + text-decoration: none; 136 145 } 137 146 138 - header h1.tapped .egg { 139 - opacity: 1; 147 + header h1 svg { 148 + display: block; 149 + height: 28px; 150 + width: auto; 140 151 } 141 152 142 153 .tagline { ··· 145 156 font-size: 1rem; 146 157 } 147 158 148 - .header-bar { 149 - display: flex; 150 - align-items: baseline; 151 - justify-content: space-between; 152 - gap: 16px; 153 - } 154 - 155 - header { 156 - border-bottom: 2px solid var(--vit-green); 157 - padding-bottom: 16px; 158 - margin-bottom: 24px; 159 - } 160 - 161 159 nav { 162 160 display: flex; 163 161 flex-wrap: wrap; ··· 178 176 text-decoration: underline; 179 177 text-decoration-color: var(--vit-green); 180 178 text-underline-offset: 3px; 179 + } 180 + 181 + .nav-toggle { 182 + display: none; 183 + background: none; 184 + border: none; 185 + font-size: 1.5rem; 186 + cursor: pointer; 187 + color: var(--vit-green-deep); 188 + padding: 0; 189 + line-height: 1; 181 190 } 182 191 183 192 a { ··· 266 275 color: var(--vit-green-deep); 267 276 } 268 277 269 - @media (max-width: 480px) { 278 + @media (max-width: 600px) { 279 + .nav-toggle { 280 + display: block; 281 + } 282 + 283 + .header-bar { 284 + flex-wrap: wrap; 285 + } 286 + 270 287 nav { 271 - gap: 10px; 272 - font-size: 0.9rem; 288 + display: none; 289 + width: 100%; 290 + flex-direction: column; 291 + gap: 8px; 292 + padding-top: 12px; 293 + } 294 + 295 + nav.open { 296 + display: flex; 273 297 } 274 298 } 275 299 </style> ··· 278 302 <div class="container"> 279 303 <header> 280 304 <div class="header-bar"> 281 - <h1><a href="/">vit<span class="egg">ality</span></a></h1> 305 + <h1><a href="/" aria-label="vit"> 306 + ${wordmark} 307 + </a></h1> 308 + <button class="nav-toggle" aria-label="Menu" aria-expanded="false">&#9776;</button> 282 309 <nav> 283 310 ${nav(activeSlug)} 284 311 </nav> ··· 305 332 </script> 306 333 ` : ''} 307 334 <script> 308 - // Easter egg tap toggle 309 - document.querySelector('header h1').addEventListener('touchstart', function(e) { 310 - this.classList.toggle('tapped'); 311 - }); 312 - document.addEventListener('touchstart', function(e) { 313 - var h1 = document.querySelector('header h1'); 314 - if (!h1.contains(e.target)) h1.classList.remove('tapped'); 335 + // Mobile nav toggle 336 + document.querySelector('.nav-toggle').addEventListener('click', function() { 337 + var nav = this.parentNode.querySelector('nav'); 338 + var open = nav.classList.toggle('open'); 339 + this.setAttribute('aria-expanded', open); 340 + this.textContent = open ? '\\u2715' : '\\u2630'; 315 341 }); 316 342 </script> 317 343 </body>
+65 -41
docs/architecture/index.html
··· 31 31 padding: 24px 20px 32px; 32 32 } 33 33 34 + header { 35 + border-bottom: 2px solid var(--vit-green); 36 + padding-bottom: 16px; 37 + margin-bottom: 24px; 38 + } 39 + 40 + .header-bar { 41 + display: flex; 42 + align-items: center; 43 + justify-content: space-between; 44 + gap: 16px; 45 + } 46 + 34 47 header h1 { 35 48 margin: 0; 36 - font-size: 2rem; 37 - line-height: 1.2; 38 - color: var(--vit-green); 49 + line-height: 1; 39 50 } 40 51 41 52 header h1 a { 42 - color: inherit; 53 + display: inline-block; 43 54 text-decoration: none; 44 - cursor: default; 45 55 } 46 56 47 - .egg { 48 - opacity: 0; 49 - transition: opacity 200ms ease; 50 - color: #9ca3af; 51 - } 52 - 53 - header h1:hover .egg { 54 - opacity: 1; 55 - } 56 - 57 - header h1.tapped .egg { 58 - opacity: 1; 57 + header h1 svg { 58 + display: block; 59 + height: 28px; 60 + width: auto; 59 61 } 60 62 61 63 .tagline { ··· 64 66 font-size: 1rem; 65 67 } 66 68 67 - .header-bar { 68 - display: flex; 69 - align-items: baseline; 70 - justify-content: space-between; 71 - gap: 16px; 72 - } 73 - 74 - header { 75 - border-bottom: 2px solid var(--vit-green); 76 - padding-bottom: 16px; 77 - margin-bottom: 24px; 78 - } 79 - 80 69 nav { 81 70 display: flex; 82 71 flex-wrap: wrap; ··· 99 88 text-underline-offset: 3px; 100 89 } 101 90 91 + .nav-toggle { 92 + display: none; 93 + background: none; 94 + border: none; 95 + font-size: 1.5rem; 96 + cursor: pointer; 97 + color: var(--vit-green-deep); 98 + padding: 0; 99 + line-height: 1; 100 + } 101 + 102 102 a { 103 103 color: var(--vit-green-deep); 104 104 } ··· 185 185 color: var(--vit-green-deep); 186 186 } 187 187 188 - @media (max-width: 480px) { 188 + @media (max-width: 600px) { 189 + .nav-toggle { 190 + display: block; 191 + } 192 + 193 + .header-bar { 194 + flex-wrap: wrap; 195 + } 196 + 189 197 nav { 190 - gap: 10px; 191 - font-size: 0.9rem; 198 + display: none; 199 + width: 100%; 200 + flex-direction: column; 201 + gap: 8px; 202 + padding-top: 12px; 203 + } 204 + 205 + nav.open { 206 + display: flex; 192 207 } 193 208 } 194 209 </style> ··· 197 212 <div class="container"> 198 213 <header> 199 214 <div class="header-bar"> 200 - <h1><a href="/">vit<span class="egg">ality</span></a></h1> 215 + <h1><a href="/" aria-label="vit"> 216 + <svg viewBox="0 0 56 34" xmlns="http://www.w3.org/2000/svg" height="28" aria-hidden="true"> 217 + <circle cx="16" cy="6" r="3" fill="#06D6A0"/> 218 + <path d="M5.5 11 L16 27 L26.5 11" stroke="#06D6A0" stroke-width="3.5" stroke-linecap="round" stroke-linejoin="round" fill="none"/> 219 + <circle cx="33.5" cy="6" r="3" fill="#06D6A0"/> 220 + <line x1="33.5" y1="12.5" x2="33.5" y2="27" stroke="#06D6A0" stroke-width="3.5" stroke-linecap="round"/> 221 + <line x1="45" y1="7" x2="45" y2="27" stroke="#06D6A0" stroke-width="3.5" stroke-linecap="round"/> 222 + <line x1="39" y1="12.5" x2="51" y2="12.5" stroke="#06D6A0" stroke-width="3.5" stroke-linecap="round"/> 223 + </svg> 224 + </a></h1> 225 + <button class="nav-toggle" aria-label="Menu" aria-expanded="false">&#9776;</button> 201 226 <nav> 202 227 <a href="/">home</a> 203 228 <a href="/start/">start</a> ··· 349 374 </div> 350 375 351 376 <script> 352 - // Easter egg tap toggle 353 - document.querySelector('header h1').addEventListener('touchstart', function(e) { 354 - this.classList.toggle('tapped'); 355 - }); 356 - document.addEventListener('touchstart', function(e) { 357 - var h1 = document.querySelector('header h1'); 358 - if (!h1.contains(e.target)) h1.classList.remove('tapped'); 377 + // Mobile nav toggle 378 + document.querySelector('.nav-toggle').addEventListener('click', function() { 379 + var nav = this.parentNode.querySelector('nav'); 380 + var open = nav.classList.toggle('open'); 381 + this.setAttribute('aria-expanded', open); 382 + this.textContent = open ? '\u2715' : '\u2630'; 359 383 }); 360 384 </script> 361 385 </body>
+65 -41
docs/doctrine/index.html
··· 31 31 padding: 24px 20px 32px; 32 32 } 33 33 34 + header { 35 + border-bottom: 2px solid var(--vit-green); 36 + padding-bottom: 16px; 37 + margin-bottom: 24px; 38 + } 39 + 40 + .header-bar { 41 + display: flex; 42 + align-items: center; 43 + justify-content: space-between; 44 + gap: 16px; 45 + } 46 + 34 47 header h1 { 35 48 margin: 0; 36 - font-size: 2rem; 37 - line-height: 1.2; 38 - color: var(--vit-green); 49 + line-height: 1; 39 50 } 40 51 41 52 header h1 a { 42 - color: inherit; 53 + display: inline-block; 43 54 text-decoration: none; 44 - cursor: default; 45 55 } 46 56 47 - .egg { 48 - opacity: 0; 49 - transition: opacity 200ms ease; 50 - color: #9ca3af; 51 - } 52 - 53 - header h1:hover .egg { 54 - opacity: 1; 55 - } 56 - 57 - header h1.tapped .egg { 58 - opacity: 1; 57 + header h1 svg { 58 + display: block; 59 + height: 28px; 60 + width: auto; 59 61 } 60 62 61 63 .tagline { ··· 64 66 font-size: 1rem; 65 67 } 66 68 67 - .header-bar { 68 - display: flex; 69 - align-items: baseline; 70 - justify-content: space-between; 71 - gap: 16px; 72 - } 73 - 74 - header { 75 - border-bottom: 2px solid var(--vit-green); 76 - padding-bottom: 16px; 77 - margin-bottom: 24px; 78 - } 79 - 80 69 nav { 81 70 display: flex; 82 71 flex-wrap: wrap; ··· 99 88 text-underline-offset: 3px; 100 89 } 101 90 91 + .nav-toggle { 92 + display: none; 93 + background: none; 94 + border: none; 95 + font-size: 1.5rem; 96 + cursor: pointer; 97 + color: var(--vit-green-deep); 98 + padding: 0; 99 + line-height: 1; 100 + } 101 + 102 102 a { 103 103 color: var(--vit-green-deep); 104 104 } ··· 185 185 color: var(--vit-green-deep); 186 186 } 187 187 188 - @media (max-width: 480px) { 188 + @media (max-width: 600px) { 189 + .nav-toggle { 190 + display: block; 191 + } 192 + 193 + .header-bar { 194 + flex-wrap: wrap; 195 + } 196 + 189 197 nav { 190 - gap: 10px; 191 - font-size: 0.9rem; 198 + display: none; 199 + width: 100%; 200 + flex-direction: column; 201 + gap: 8px; 202 + padding-top: 12px; 203 + } 204 + 205 + nav.open { 206 + display: flex; 192 207 } 193 208 } 194 209 </style> ··· 197 212 <div class="container"> 198 213 <header> 199 214 <div class="header-bar"> 200 - <h1><a href="/">vit<span class="egg">ality</span></a></h1> 215 + <h1><a href="/" aria-label="vit"> 216 + <svg viewBox="0 0 56 34" xmlns="http://www.w3.org/2000/svg" height="28" aria-hidden="true"> 217 + <circle cx="16" cy="6" r="3" fill="#06D6A0"/> 218 + <path d="M5.5 11 L16 27 L26.5 11" stroke="#06D6A0" stroke-width="3.5" stroke-linecap="round" stroke-linejoin="round" fill="none"/> 219 + <circle cx="33.5" cy="6" r="3" fill="#06D6A0"/> 220 + <line x1="33.5" y1="12.5" x2="33.5" y2="27" stroke="#06D6A0" stroke-width="3.5" stroke-linecap="round"/> 221 + <line x1="45" y1="7" x2="45" y2="27" stroke="#06D6A0" stroke-width="3.5" stroke-linecap="round"/> 222 + <line x1="39" y1="12.5" x2="51" y2="12.5" stroke="#06D6A0" stroke-width="3.5" stroke-linecap="round"/> 223 + </svg> 224 + </a></h1> 225 + <button class="nav-toggle" aria-label="Menu" aria-expanded="false">&#9776;</button> 201 226 <nav> 202 227 <a href="/">home</a> 203 228 <a href="/start/">start</a> ··· 346 371 </div> 347 372 348 373 <script> 349 - // Easter egg tap toggle 350 - document.querySelector('header h1').addEventListener('touchstart', function(e) { 351 - this.classList.toggle('tapped'); 352 - }); 353 - document.addEventListener('touchstart', function(e) { 354 - var h1 = document.querySelector('header h1'); 355 - if (!h1.contains(e.target)) h1.classList.remove('tapped'); 374 + // Mobile nav toggle 375 + document.querySelector('.nav-toggle').addEventListener('click', function() { 376 + var nav = this.parentNode.querySelector('nav'); 377 + var open = nav.classList.toggle('open'); 378 + this.setAttribute('aria-expanded', open); 379 + this.textContent = open ? '\u2715' : '\u2630'; 356 380 }); 357 381 </script> 358 382 </body>
+65 -41
docs/index.html
··· 31 31 padding: 24px 20px 32px; 32 32 } 33 33 34 + header { 35 + border-bottom: 2px solid var(--vit-green); 36 + padding-bottom: 16px; 37 + margin-bottom: 24px; 38 + } 39 + 40 + .header-bar { 41 + display: flex; 42 + align-items: center; 43 + justify-content: space-between; 44 + gap: 16px; 45 + } 46 + 34 47 header h1 { 35 48 margin: 0; 36 - font-size: 2rem; 37 - line-height: 1.2; 38 - color: var(--vit-green); 49 + line-height: 1; 39 50 } 40 51 41 52 header h1 a { 42 - color: inherit; 53 + display: inline-block; 43 54 text-decoration: none; 44 - cursor: default; 45 55 } 46 56 47 - .egg { 48 - opacity: 0; 49 - transition: opacity 200ms ease; 50 - color: #9ca3af; 51 - } 52 - 53 - header h1:hover .egg { 54 - opacity: 1; 55 - } 56 - 57 - header h1.tapped .egg { 58 - opacity: 1; 57 + header h1 svg { 58 + display: block; 59 + height: 28px; 60 + width: auto; 59 61 } 60 62 61 63 .tagline { ··· 64 66 font-size: 1rem; 65 67 } 66 68 67 - .header-bar { 68 - display: flex; 69 - align-items: baseline; 70 - justify-content: space-between; 71 - gap: 16px; 72 - } 73 - 74 - header { 75 - border-bottom: 2px solid var(--vit-green); 76 - padding-bottom: 16px; 77 - margin-bottom: 24px; 78 - } 79 - 80 69 nav { 81 70 display: flex; 82 71 flex-wrap: wrap; ··· 99 88 text-underline-offset: 3px; 100 89 } 101 90 91 + .nav-toggle { 92 + display: none; 93 + background: none; 94 + border: none; 95 + font-size: 1.5rem; 96 + cursor: pointer; 97 + color: var(--vit-green-deep); 98 + padding: 0; 99 + line-height: 1; 100 + } 101 + 102 102 a { 103 103 color: var(--vit-green-deep); 104 104 } ··· 185 185 color: var(--vit-green-deep); 186 186 } 187 187 188 - @media (max-width: 480px) { 188 + @media (max-width: 600px) { 189 + .nav-toggle { 190 + display: block; 191 + } 192 + 193 + .header-bar { 194 + flex-wrap: wrap; 195 + } 196 + 189 197 nav { 190 - gap: 10px; 191 - font-size: 0.9rem; 198 + display: none; 199 + width: 100%; 200 + flex-direction: column; 201 + gap: 8px; 202 + padding-top: 12px; 203 + } 204 + 205 + nav.open { 206 + display: flex; 192 207 } 193 208 } 194 209 </style> ··· 197 212 <div class="container"> 198 213 <header> 199 214 <div class="header-bar"> 200 - <h1><a href="/">vit<span class="egg">ality</span></a></h1> 215 + <h1><a href="/" aria-label="vit"> 216 + <svg viewBox="0 0 56 34" xmlns="http://www.w3.org/2000/svg" height="28" aria-hidden="true"> 217 + <circle cx="16" cy="6" r="3" fill="#06D6A0"/> 218 + <path d="M5.5 11 L16 27 L26.5 11" stroke="#06D6A0" stroke-width="3.5" stroke-linecap="round" stroke-linejoin="round" fill="none"/> 219 + <circle cx="33.5" cy="6" r="3" fill="#06D6A0"/> 220 + <line x1="33.5" y1="12.5" x2="33.5" y2="27" stroke="#06D6A0" stroke-width="3.5" stroke-linecap="round"/> 221 + <line x1="45" y1="7" x2="45" y2="27" stroke="#06D6A0" stroke-width="3.5" stroke-linecap="round"/> 222 + <line x1="39" y1="12.5" x2="51" y2="12.5" stroke="#06D6A0" stroke-width="3.5" stroke-linecap="round"/> 223 + </svg> 224 + </a></h1> 225 + <button class="nav-toggle" aria-label="Menu" aria-expanded="false">&#9776;</button> 201 226 <nav> 202 227 <a href="/" class="active">home</a> 203 228 <a href="/start/">start</a> ··· 249 274 </script> 250 275 251 276 <script> 252 - // Easter egg tap toggle 253 - document.querySelector('header h1').addEventListener('touchstart', function(e) { 254 - this.classList.toggle('tapped'); 255 - }); 256 - document.addEventListener('touchstart', function(e) { 257 - var h1 = document.querySelector('header h1'); 258 - if (!h1.contains(e.target)) h1.classList.remove('tapped'); 277 + // Mobile nav toggle 278 + document.querySelector('.nav-toggle').addEventListener('click', function() { 279 + var nav = this.parentNode.querySelector('nav'); 280 + var open = nav.classList.toggle('open'); 281 + this.setAttribute('aria-expanded', open); 282 + this.textContent = open ? '\u2715' : '\u2630'; 259 283 }); 260 284 </script> 261 285 </body>
+65 -41
docs/start/index.html
··· 31 31 padding: 24px 20px 32px; 32 32 } 33 33 34 + header { 35 + border-bottom: 2px solid var(--vit-green); 36 + padding-bottom: 16px; 37 + margin-bottom: 24px; 38 + } 39 + 40 + .header-bar { 41 + display: flex; 42 + align-items: center; 43 + justify-content: space-between; 44 + gap: 16px; 45 + } 46 + 34 47 header h1 { 35 48 margin: 0; 36 - font-size: 2rem; 37 - line-height: 1.2; 38 - color: var(--vit-green); 49 + line-height: 1; 39 50 } 40 51 41 52 header h1 a { 42 - color: inherit; 53 + display: inline-block; 43 54 text-decoration: none; 44 - cursor: default; 45 55 } 46 56 47 - .egg { 48 - opacity: 0; 49 - transition: opacity 200ms ease; 50 - color: #9ca3af; 51 - } 52 - 53 - header h1:hover .egg { 54 - opacity: 1; 55 - } 56 - 57 - header h1.tapped .egg { 58 - opacity: 1; 57 + header h1 svg { 58 + display: block; 59 + height: 28px; 60 + width: auto; 59 61 } 60 62 61 63 .tagline { ··· 64 66 font-size: 1rem; 65 67 } 66 68 67 - .header-bar { 68 - display: flex; 69 - align-items: baseline; 70 - justify-content: space-between; 71 - gap: 16px; 72 - } 73 - 74 - header { 75 - border-bottom: 2px solid var(--vit-green); 76 - padding-bottom: 16px; 77 - margin-bottom: 24px; 78 - } 79 - 80 69 nav { 81 70 display: flex; 82 71 flex-wrap: wrap; ··· 99 88 text-underline-offset: 3px; 100 89 } 101 90 91 + .nav-toggle { 92 + display: none; 93 + background: none; 94 + border: none; 95 + font-size: 1.5rem; 96 + cursor: pointer; 97 + color: var(--vit-green-deep); 98 + padding: 0; 99 + line-height: 1; 100 + } 101 + 102 102 a { 103 103 color: var(--vit-green-deep); 104 104 } ··· 185 185 color: var(--vit-green-deep); 186 186 } 187 187 188 - @media (max-width: 480px) { 188 + @media (max-width: 600px) { 189 + .nav-toggle { 190 + display: block; 191 + } 192 + 193 + .header-bar { 194 + flex-wrap: wrap; 195 + } 196 + 189 197 nav { 190 - gap: 10px; 191 - font-size: 0.9rem; 198 + display: none; 199 + width: 100%; 200 + flex-direction: column; 201 + gap: 8px; 202 + padding-top: 12px; 203 + } 204 + 205 + nav.open { 206 + display: flex; 192 207 } 193 208 } 194 209 </style> ··· 197 212 <div class="container"> 198 213 <header> 199 214 <div class="header-bar"> 200 - <h1><a href="/">vit<span class="egg">ality</span></a></h1> 215 + <h1><a href="/" aria-label="vit"> 216 + <svg viewBox="0 0 56 34" xmlns="http://www.w3.org/2000/svg" height="28" aria-hidden="true"> 217 + <circle cx="16" cy="6" r="3" fill="#06D6A0"/> 218 + <path d="M5.5 11 L16 27 L26.5 11" stroke="#06D6A0" stroke-width="3.5" stroke-linecap="round" stroke-linejoin="round" fill="none"/> 219 + <circle cx="33.5" cy="6" r="3" fill="#06D6A0"/> 220 + <line x1="33.5" y1="12.5" x2="33.5" y2="27" stroke="#06D6A0" stroke-width="3.5" stroke-linecap="round"/> 221 + <line x1="45" y1="7" x2="45" y2="27" stroke="#06D6A0" stroke-width="3.5" stroke-linecap="round"/> 222 + <line x1="39" y1="12.5" x2="51" y2="12.5" stroke="#06D6A0" stroke-width="3.5" stroke-linecap="round"/> 223 + </svg> 224 + </a></h1> 225 + <button class="nav-toggle" aria-label="Menu" aria-expanded="false">&#9776;</button> 201 226 <nav> 202 227 <a href="/">home</a> 203 228 <a href="/start/" class="active">start</a> ··· 266 291 </div> 267 292 268 293 <script> 269 - // Easter egg tap toggle 270 - document.querySelector('header h1').addEventListener('touchstart', function(e) { 271 - this.classList.toggle('tapped'); 272 - }); 273 - document.addEventListener('touchstart', function(e) { 274 - var h1 = document.querySelector('header h1'); 275 - if (!h1.contains(e.target)) h1.classList.remove('tapped'); 294 + // Mobile nav toggle 295 + document.querySelector('.nav-toggle').addEventListener('click', function() { 296 + var nav = this.parentNode.querySelector('nav'); 297 + var open = nav.classList.toggle('open'); 298 + this.setAttribute('aria-expanded', open); 299 + this.textContent = open ? '\u2715' : '\u2630'; 276 300 }); 277 301 </script> 278 302 </body>
+65 -41
docs/vocab/index.html
··· 31 31 padding: 24px 20px 32px; 32 32 } 33 33 34 + header { 35 + border-bottom: 2px solid var(--vit-green); 36 + padding-bottom: 16px; 37 + margin-bottom: 24px; 38 + } 39 + 40 + .header-bar { 41 + display: flex; 42 + align-items: center; 43 + justify-content: space-between; 44 + gap: 16px; 45 + } 46 + 34 47 header h1 { 35 48 margin: 0; 36 - font-size: 2rem; 37 - line-height: 1.2; 38 - color: var(--vit-green); 49 + line-height: 1; 39 50 } 40 51 41 52 header h1 a { 42 - color: inherit; 53 + display: inline-block; 43 54 text-decoration: none; 44 - cursor: default; 45 55 } 46 56 47 - .egg { 48 - opacity: 0; 49 - transition: opacity 200ms ease; 50 - color: #9ca3af; 51 - } 52 - 53 - header h1:hover .egg { 54 - opacity: 1; 55 - } 56 - 57 - header h1.tapped .egg { 58 - opacity: 1; 57 + header h1 svg { 58 + display: block; 59 + height: 28px; 60 + width: auto; 59 61 } 60 62 61 63 .tagline { ··· 64 66 font-size: 1rem; 65 67 } 66 68 67 - .header-bar { 68 - display: flex; 69 - align-items: baseline; 70 - justify-content: space-between; 71 - gap: 16px; 72 - } 73 - 74 - header { 75 - border-bottom: 2px solid var(--vit-green); 76 - padding-bottom: 16px; 77 - margin-bottom: 24px; 78 - } 79 - 80 69 nav { 81 70 display: flex; 82 71 flex-wrap: wrap; ··· 97 86 text-decoration: underline; 98 87 text-decoration-color: var(--vit-green); 99 88 text-underline-offset: 3px; 89 + } 90 + 91 + .nav-toggle { 92 + display: none; 93 + background: none; 94 + border: none; 95 + font-size: 1.5rem; 96 + cursor: pointer; 97 + color: var(--vit-green-deep); 98 + padding: 0; 99 + line-height: 1; 100 100 } 101 101 102 102 a { ··· 185 185 color: var(--vit-green-deep); 186 186 } 187 187 188 - @media (max-width: 480px) { 188 + @media (max-width: 600px) { 189 + .nav-toggle { 190 + display: block; 191 + } 192 + 193 + .header-bar { 194 + flex-wrap: wrap; 195 + } 196 + 189 197 nav { 190 - gap: 10px; 191 - font-size: 0.9rem; 198 + display: none; 199 + width: 100%; 200 + flex-direction: column; 201 + gap: 8px; 202 + padding-top: 12px; 203 + } 204 + 205 + nav.open { 206 + display: flex; 192 207 } 193 208 } 194 209 </style> ··· 197 212 <div class="container"> 198 213 <header> 199 214 <div class="header-bar"> 200 - <h1><a href="/">vit<span class="egg">ality</span></a></h1> 215 + <h1><a href="/" aria-label="vit"> 216 + <svg viewBox="0 0 56 34" xmlns="http://www.w3.org/2000/svg" height="28" aria-hidden="true"> 217 + <circle cx="16" cy="6" r="3" fill="#06D6A0"/> 218 + <path d="M5.5 11 L16 27 L26.5 11" stroke="#06D6A0" stroke-width="3.5" stroke-linecap="round" stroke-linejoin="round" fill="none"/> 219 + <circle cx="33.5" cy="6" r="3" fill="#06D6A0"/> 220 + <line x1="33.5" y1="12.5" x2="33.5" y2="27" stroke="#06D6A0" stroke-width="3.5" stroke-linecap="round"/> 221 + <line x1="45" y1="7" x2="45" y2="27" stroke="#06D6A0" stroke-width="3.5" stroke-linecap="round"/> 222 + <line x1="39" y1="12.5" x2="51" y2="12.5" stroke="#06D6A0" stroke-width="3.5" stroke-linecap="round"/> 223 + </svg> 224 + </a></h1> 225 + <button class="nav-toggle" aria-label="Menu" aria-expanded="false">&#9776;</button> 201 226 <nav> 202 227 <a href="/">home</a> 203 228 <a href="/start/">start</a> ··· 425 450 </div> 426 451 427 452 <script> 428 - // Easter egg tap toggle 429 - document.querySelector('header h1').addEventListener('touchstart', function(e) { 430 - this.classList.toggle('tapped'); 431 - }); 432 - document.addEventListener('touchstart', function(e) { 433 - var h1 = document.querySelector('header h1'); 434 - if (!h1.contains(e.target)) h1.classList.remove('tapped'); 453 + // Mobile nav toggle 454 + document.querySelector('.nav-toggle').addEventListener('click', function() { 455 + var nav = this.parentNode.querySelector('nav'); 456 + var open = nav.classList.toggle('open'); 457 + this.setAttribute('aria-expanded', open); 458 + this.textContent = open ? '\u2715' : '\u2630'; 435 459 }); 436 460 </script> 437 461 </body>
+5
explore/public/favicon.svg
··· 1 + <svg viewBox="0 0 32 32" xmlns="http://www.w3.org/2000/svg"> 2 + <!-- vit mark: a "v" with a social dot — alive, connected, approachable --> 3 + <circle cx="16" cy="5.5" r="3" fill="#06D6A0"/> 4 + <path d="M5.5 10 L16 26 L26.5 10" stroke="#06D6A0" stroke-width="3.5" stroke-linecap="round" stroke-linejoin="round" fill="none"/> 5 + </svg>
+134 -37
explore/public/index.html
··· 3 3 <head> 4 4 <meta charset="utf-8"> 5 5 <meta name="viewport" content="width=device-width, initial-scale=1"> 6 - <title>vit explore</title> 6 + <title>explore — vit</title> 7 7 <meta name="description" content="vit network explorer — live capability and vouch activity"> 8 - <link rel="icon" type="image/svg+xml" href="data:image/svg+xml,%3Csvg viewBox='0 0 32 32' xmlns='http://www.w3.org/2000/svg'%3E%3Ccircle cx='16' cy='5.5' r='3' fill='%2306D6A0'/%3E%3Cpath d='M5.5 10 L16 26 L26.5 10' stroke='%2306D6A0' stroke-width='3.5' stroke-linecap='round' stroke-linejoin='round' fill='none'/%3E%3C/svg%3E"> 8 + <link rel="icon" type="image/svg+xml" href="/favicon.svg"> 9 9 <style> 10 10 :root { 11 11 color-scheme: light; 12 + --vit-green: #06D6A0; 13 + --vit-green-deep: #059669; 12 14 } 13 15 14 16 body { ··· 26 28 padding: 24px 20px 32px; 27 29 } 28 30 29 - header h1 { 30 - margin: 0; 31 - font-size: 2rem; 32 - line-height: 1.2; 33 - cursor: default; 34 - } 35 - 36 - .tagline { 37 - margin: 6px 0 0; 38 - color: #4b5563; 39 - font-size: 1rem; 31 + header { 32 + border-bottom: 2px solid var(--vit-green); 33 + padding-bottom: 16px; 34 + margin-bottom: 24px; 40 35 } 41 36 42 37 .header-bar { 43 38 display: flex; 44 - align-items: baseline; 39 + align-items: center; 45 40 justify-content: space-between; 46 41 gap: 16px; 47 42 } 48 43 49 - header { 50 - border-bottom: 1px solid #e5e7eb; 51 - padding-bottom: 16px; 52 - margin-bottom: 24px; 44 + header h1 { 45 + margin: 0; 46 + line-height: 1; 47 + } 48 + 49 + header h1 a { 50 + display: inline-block; 51 + text-decoration: none; 52 + } 53 + 54 + header h1 svg { 55 + display: block; 56 + height: 28px; 57 + width: auto; 58 + } 59 + 60 + .tagline { 61 + margin: 6px 0 0; 62 + color: #4b5563; 63 + font-size: 1rem; 53 64 } 54 65 55 66 nav { ··· 59 70 } 60 71 61 72 nav a { 62 - color: #059669; 73 + color: var(--vit-green-deep); 63 74 text-decoration: none; 64 75 } 65 76 ··· 68 79 } 69 80 70 81 nav a.active { 71 - color: #06D6A0; 82 + color: var(--vit-green-deep); 72 83 text-decoration: underline; 84 + text-decoration-color: var(--vit-green); 73 85 text-underline-offset: 3px; 74 86 } 75 87 88 + .nav-toggle { 89 + display: none; 90 + background: none; 91 + border: none; 92 + font-size: 1.5rem; 93 + cursor: pointer; 94 + color: var(--vit-green-deep); 95 + padding: 0; 96 + line-height: 1; 97 + } 98 + 99 + a { 100 + color: var(--vit-green-deep); 101 + } 102 + 76 103 main { 77 104 min-height: 240px; 78 105 } 79 106 107 + .sub-nav { 108 + display: flex; 109 + gap: 16px; 110 + margin-bottom: 20px; 111 + padding-bottom: 12px; 112 + border-bottom: 1px solid #e5e7eb; 113 + } 114 + 115 + .sub-nav a { 116 + color: var(--vit-green-deep); 117 + text-decoration: none; 118 + font-weight: 500; 119 + font-size: 0.95rem; 120 + } 121 + 122 + .sub-nav a:hover { 123 + text-decoration: underline; 124 + } 125 + 126 + .sub-nav a.active { 127 + text-decoration: underline; 128 + text-decoration-color: var(--vit-green); 129 + text-underline-offset: 3px; 130 + } 131 + 80 132 main h1, 81 133 main h2, 82 134 main h3, ··· 121 173 122 174 hr { 123 175 border: 0; 124 - border-top: 1px solid #e5e7eb; 176 + border-top: 1px solid var(--vit-green); 125 177 margin: 1.5em 0; 126 178 } 127 179 ··· 134 186 } 135 187 136 188 footer a { 137 - color: #059669; 189 + color: var(--vit-green-deep); 138 190 } 139 191 140 192 .cap-item { ··· 157 209 } 158 210 159 211 .cap-meta a { 160 - color: #059669; 212 + color: var(--vit-green-deep); 161 213 text-decoration: none; 162 214 } 163 215 ··· 178 230 } 179 231 180 232 .beacon-name a { 181 - color: #06D6A0; 233 + color: var(--vit-green); 182 234 text-decoration: none; 183 235 font-weight: 600; 184 236 } ··· 203 255 background: #f3f4f6; 204 256 padding: 16px; 205 257 border-radius: 6px; 206 - border-left: 3px solid #06D6A0; 258 + border-left: 3px solid var(--vit-green); 207 259 } 208 260 209 261 .stat-number { 210 262 font-size: 2rem; 211 263 font-weight: 700; 212 264 line-height: 1.2; 213 - color: #06D6A0; 265 + color: var(--vit-green); 214 266 } 215 267 216 268 .stat-label { ··· 232 284 background: #f3f4f6; 233 285 border: 1px solid #e5e7eb; 234 286 border-radius: 6px; 235 - color: #059669; 287 + color: var(--vit-green-deep); 236 288 cursor: pointer; 237 289 font-size: 0.9rem; 238 290 font-family: inherit; ··· 249 301 font-weight: 600; 250 302 } 251 303 252 - @media (max-width: 480px) { 304 + @media (max-width: 600px) { 305 + .nav-toggle { 306 + display: block; 307 + } 308 + 309 + .header-bar { 310 + flex-wrap: wrap; 311 + } 312 + 313 + nav { 314 + display: none; 315 + width: 100%; 316 + flex-direction: column; 317 + gap: 8px; 318 + padding-top: 12px; 319 + } 320 + 321 + nav.open { 322 + display: flex; 323 + } 324 + 253 325 .stat-grid { 254 326 grid-template-columns: 1fr; 255 327 } ··· 269 341 <div class="container"> 270 342 <header> 271 343 <div class="header-bar"> 272 - <div> 273 - <h1><a href="https://v-it.org" style="color: #06D6A0; text-decoration: none;">vit explore</a></h1> 274 - <p class="tagline">network explorer</p> 275 - </div> 344 + <h1><a href="https://v-it.org" aria-label="vit"> 345 + <svg viewBox="0 0 56 34" xmlns="http://www.w3.org/2000/svg" height="28" aria-hidden="true"> 346 + <circle cx="16" cy="6" r="3" fill="#06D6A0"/> 347 + <path d="M5.5 11 L16 27 L26.5 11" stroke="#06D6A0" stroke-width="3.5" stroke-linecap="round" stroke-linejoin="round" fill="none"/> 348 + <circle cx="33.5" cy="6" r="3" fill="#06D6A0"/> 349 + <line x1="33.5" y1="12.5" x2="33.5" y2="27" stroke="#06D6A0" stroke-width="3.5" stroke-linecap="round"/> 350 + <line x1="45" y1="7" x2="45" y2="27" stroke="#06D6A0" stroke-width="3.5" stroke-linecap="round"/> 351 + <line x1="39" y1="12.5" x2="51" y2="12.5" stroke="#06D6A0" stroke-width="3.5" stroke-linecap="round"/> 352 + </svg> 353 + </a></h1> 354 + <button class="nav-toggle" aria-label="Menu" aria-expanded="false">&#9776;</button> 276 355 <nav> 277 - <a href="#">caps</a> 278 - <a href="#beacons">beacons</a> 279 - <a href="#stats">stats</a> 356 + <a href="https://v-it.org/">home</a> 357 + <a href="https://v-it.org/start/">start</a> 358 + <a href="/" class="active">explore</a> 359 + <a href="https://v-it.org/doctrine/">doctrine</a> 360 + <a href="https://v-it.org/vocab/">vocab</a> 361 + <a href="https://v-it.org/architecture/">architecture</a> 362 + <a href="https://github.com/solpbc/vit">github</a> 280 363 </nav> 281 364 </div> 365 + <p class="tagline">open source is social</p> 282 366 </header> 283 367 284 368 <main id="content"> 369 + <nav class="sub-nav"> 370 + <a href="#">caps</a> 371 + <a href="#beacons">beacons</a> 372 + <a href="#stats">stats</a> 373 + </nav> 285 374 <div id="view"></div> 286 375 </main> 287 376 288 377 <footer> 289 - part of <a href="https://solpbc.org">sol pbc</a> · <a href="https://v-it.org">v-it.org</a> 378 + part of <a href="https://solpbc.org">sol pbc</a>. created by <a href="https://bsky.app/profile/jeremie.com">Jeremie Miller</a>. vit is a trademark of sol pbc. 290 379 </footer> 291 380 </div> 292 381 293 382 <script> 383 + // Mobile nav toggle 384 + document.querySelector('.nav-toggle').addEventListener('click', function() { 385 + var nav = this.parentNode.querySelector('nav'); 386 + var open = nav.classList.toggle('open'); 387 + this.setAttribute('aria-expanded', open); 388 + this.textContent = open ? '\u2715' : '\u2630'; 389 + }); 390 + 294 391 let capsCursor = null; 295 392 let capsContainer = null; 296 393 let currentBeaconFilter = null; ··· 337 434 338 435 function updateNav() { 339 436 const route = getRoute(); 340 - document.querySelectorAll('nav a').forEach(function(a) { 437 + document.querySelectorAll('.sub-nav a').forEach(function(a) { 341 438 const href = a.getAttribute('href'); 342 439 if (route.view === 'caps') a.classList.toggle('active', href === '#'); 343 440 else if (route.view === 'beacons' || route.view === 'beacon') a.classList.toggle('active', href === '#beacons');