1<!doctype html> 2<html lang="en"> 3 <head> 4 <meta charset="utf-8" /> 5 <!-- Keep this as the first executable element in <head>. A secret-bearing auth 6 entry is moved through sessionStorage and hard-navigated to a clean document 7 before analytics can start. The clean document removes the storage record 8 before exposing a one-shot handoff to first-party auth code. If storage is 9 unavailable, the current document remains permanently analytics-blocked. 10 Ordinary marketing/UTM URLs are left byte-for-byte intact. --> 11 <script> 12 (function () { 13 var storageKey = '__workshop_auth_entry_v1'; 14 var maxAgeMs = 10 * 60 * 1000; 15 16 function isSensitiveAuthEntry(url) { 17 var params = url.searchParams; 18 var state = params.get('state'); 19 var isAuthRoute = url.pathname === '/signin' || url.pathname === '/signup'; 20 var hasAuthMarker = 21 params.has('auth_tx') || (isAuthRoute && !!state && /^[A-Za-z0-9_-]{43}$/.test(state)); 22 var hasEmailActionMarker = 23 isAuthRoute && (params.has('oobCode') || (params.has('apiKey') && params.has('mode'))); 24 return hasAuthMarker || hasEmailActionMarker; 25 } 26 27 function exposeOneShot(capturedUrl) { 28 window.__workshopAuthAnalyticsBlocked = true; 29 Object.defineProperty(window, '__takeWorkshopAuthEntry', { 30 value: function () { 31 var entry = capturedUrl ? { url: capturedUrl } : null; 32 capturedUrl = null; 33 delete window.__takeWorkshopAuthEntry; 34 return entry; 35 }, 36 configurable: true 37 }); 38 } 39 40 function suppressSensitiveNavigationReferrer() { 41 try { 42 var referrerPolicy = document.createElement('meta'); 43 referrerPolicy.name = 'referrer'; 44 referrerPolicy.content = 'no-referrer'; 45 document.head.appendChild(referrerPolicy); 46 } catch (e) {} 47 } 48 49 try { 50 var url = new URL(window.location.href); 51 if (isSensitiveAuthEntry(url)) { 52 var capturedUrl = url.toString(); 53 window.__workshopAuthAnalyticsBlocked = true; 54 window.__workshopAuthEntryDocumentUnsafe = true; 55 suppressSensitiveNavigationReferrer(); 56 var handoffStored = false; 57 try { 58 window.sessionStorage.setItem( 59 storageKey, 60 JSON.stringify({ 61 url: capturedUrl, 62 createdAt: Date.now() 63 }) 64 ); 65 handoffStored = true; 66 window.__workshopAuthEntryHardNavigationPending = true; 67 // Scrub before navigating so the clean document cannot inherit the 68 // secret-bearing URL through document.referrer or the Referer header. 69 window.history.replaceState(window.history.state, '', url.pathname); 70 window.location.replace(url.pathname); 71 return; 72 } catch (storageOrNavigationError) { 73 var handoffCleared = !handoffStored; 74 if (handoffStored) { 75 try { 76 window.sessionStorage.removeItem(storageKey); 77 handoffCleared = true; 78 } catch (e) {} 79 } 80 if (!handoffCleared) { 81 window.__workshopAuthEntryHardNavigationPending = true; 82 window.history.replaceState(window.history.state, '', url.pathname); 83 return; 84 } 85 window.__workshopAuthEntryHardNavigationPending = false; 86 exposeOneShot(capturedUrl); 87 window.history.replaceState(window.history.state, '', url.pathname); 88 return; 89 } 90 } 91 92 var stored = null; 93 try { 94 stored = window.sessionStorage.getItem(storageKey); 95 if (stored !== null) window.sessionStorage.removeItem(storageKey); 96 } catch (storageReadError) { 97 return; 98 } 99 if (!stored) return; 100 101 try { 102 var record = JSON.parse(stored); 103 var now = Date.now(); 104 var storedUrl = new URL(record.url); 105 var isFresh = 106 typeof record.createdAt === 'number' && 107 record.createdAt <= now + 60 * 1000 && 108 now - record.createdAt <= maxAgeMs; 109 if ( 110 !isFresh || 111 storedUrl.origin !== url.origin || 112 storedUrl.pathname !== url.pathname || 113 !isSensitiveAuthEntry(storedUrl) 114 ) 115 return; 116 exposeOneShot(storedUrl.toString()); 117 } catch (invalidRecordError) {} 118 } catch (e) {} 119 })(); 120 </script> 121 <script> 122 // The cross-origin prompt handoff arrives in the fragment, which keeps it
123 // out of request logs and out of the Referer header â but a fragment is 124 // still readable by anything running in this document, and GTM loads 125 // further down and reports location.href. The block above does not catch 126 // it: it only recognises auth markers, and all of those are query params. 127 // 128 // So the prompt is moved into the same localStorage inbox the auth screens 129 // already read from, and scrubbed off the URL, here â ahead of every tag. 130 // adoptHandoffPrompt() still runs later and is simply a no-op for the 131 // prompt once this has taken it; it goes on clearing theme and from. 132 (function () { 133 try { 134 if (!window.location.hash) return; 135 var fragment = new URLSearchParams(window.location.hash.slice(1)); 136 var handedPrompt = fragment.get('prompt'); 137 if (!handedPrompt) return; 138 139 try { 140 window.localStorage.setItem('memex-cached-prompt', handedPrompt); 141 } catch (storageError) { 142 // Private browsing: dropping the prompt beats leaving it on the 143 // URL for the tags below to collect. 144 } 145 146 fragment.delete('prompt'); 147 var rest = fragment.toString(); 148 window.history.replaceState( 149 window.history.state, 150 '', 151 window.location.pathname + window.location.search + (rest ? '#' + rest : '') 152 ); 153 } catch (e) {} 154 })(); 155 </script> 156 <meta name="viewport" content="width=device-width, initial-scale=1" /> 157 158 <!-- Preload critical fonts: heading (Sohne Halbfett) to minimize font-swap CLS --> 159 <link rel="preload" href="/fonts/Sohne-Halbfett.woff2" as="font" type="font/woff2" crossorigin /> 160 <!-- Preconnect to CDN for images and partner logos --> 161 <link rel="preconnect" href="https://static.workshop.ai" crossorigin /> 162 163 <!-- Critical CSS for layout stability - prevents CLS on slow connections --> 164 <style> 165 /* Base layout stability - loads immediately before any JS/CSS bundles */ 166 html, body { 167 margin: 0; 168 padding: 0; 169 background-color: var(--color-bg-base, #0a0a0a); 170 color: white; 171 min-height: var(--stable-100vh, 100vh); 172 } 173 174 /* Reserve space for fixed header to prevent content jump */ 175 .page-layout { 176 min-height: var(--stable-100vh, 100vh); 177 background-color: var(--color-bg-base, #0a0a0a); 178 } 179 180 /* Fixed header dimensions - prevents layout shift */ 181 .desktop-header, 182 .mobile-header { 183 position: fixed; 184 top: 0; 185 left: 0; 186 right: 0; 187 height: 64px; 188 z-index: 50; 189 } 190 191 /* Content area reserves space for fixed header */ 192 .content-area { 193 padding-top: 64px; 194 } 195 196 /* Prevent logo flash: hide all logo variants and constrain size before component CSS loads */ 197 .logo-memex, .logo-workshop-dark, .logo-workshop-light { display: none; height: 2rem; width: auto; } 198 .theme-memex .logo-memex { display: block; } 199 .theme-workshop-dark .logo-workshop-dark { display: block; } 200 .theme-workshop-light .logo-workshop-light { display: block; } 201 202 /* Hide desktop header on mobile, show mobile header */ 203 .desktop-header { display: none; } 204 .mobile-header { display: block; } 205 206 @media (min-width: 768px) { 207 .desktop-header { display: flex; } 208 .mobile-header { display: none !important; } 209 } 210 211 /* Skip link for accessibility - visually hidden until focused */ 212 .skip-link { 213 position: absolute; 214 width: 1px; 215 height: 1px; 216 padding: 0; 217 margin: -1px; 218 overflow: hidden; 219 clip: rect(0, 0, 0, 0); 220 white-space: nowrap; 221 border: 0; 222 } 223 .skip-link:focus { 224 position: fixed; 225 top: 0; 226 left: 0; 227 width: auto; 228 height: auto; 229 padding: 8px 16px; 230 margin: 0; 231 overflow: visible; 232 clip: auto; 233 white-space: normal; 234 background: #1d4ed8; 235 color: white; 236 z-index: 9999; 237 text-decoration: none; 238 font-weight: 500; 239 border-radius: 0 0 4px 0; 240 outline: 2px solid white; 241 outline-offset: 2px; 242 } 243 </style> 244 245 <!-- Theme initialization - runs synchronously before first paint to prevent FOUC --> 246 <script> 247 (function() { 248 var host = window.location.hostname; 249 var isWorkshop = host.includes('workshop.ai') || host === 'localhost' || host === '127.0.0.1'; 250 var h = document.documentElement; 251 252 if (!isWorkshop) { 253 h.className = 'dark theme-memex'; 254 return; 255 } 256 257 var stored = null; 258 try { stored = localStorage.getItem('beta-theme'); } catch(e) {} 259
260 // A ?theme= handed over from rayline.ai. localStorage cannot cross an 261 // origin, so without this a visitor who was on dark Rayline lands on 262 // whatever their OS prefers. Handled here rather than in the theme 263 // store because it has to resolve before first paint, and it is 264 // persisted so the rest of the Workshop session matches. 265 var handed = null; 266 try { 267 handed = new URLSearchParams(window.location.search).get('theme'); 268 if (handed !== 'dark' && handed !== 'light') handed = null; 269 if (handed) { stored = handed; localStorage.setItem('beta-theme', handed); } 270 } catch(e) {} 271 272 var pref = 'system'; 273 if (stored === 'dark' || stored === 'workshop-dark') pref = 'dark'; 274 else if (stored === 'light' || stored === 'workshop-light') pref = 'light'; 275 else if (stored === 'system') pref = 'system'; 276 277 var isDark; 278 if (pref === 'dark') isDark = true; 279 else if (pref === 'light') isDark = false; 280 else isDark = window.matchMedia('(prefers-color-scheme: dark)').matches; 281 282 var theme = isDark ? 'workshop-dark' : 'workshop-light'; 283 h.className = 'theme-' + theme + (isDark ? ' dark' : ''); 284 })(); 285 </script> 286 287 <!-- Lock the initial viewport height to prevent layout shift when mobile browser 288 toolbar hides on scroll. CSS viewport units (vh/svh/dvh) all resize dynamically 289 in Chromium-based mobile browsers, so we capture the stable value once via JS. 290 Large viewport changes (DevTools resize, orientation change) still update the 291 locked value; only small changes (<15%, typical of toolbar hide/show) are ignored. --> 292 <script> 293 (function(){ 294 var s=window.innerHeight; 295 document.documentElement.style.setProperty('--stable-100vh',s+'px'); 296 window.addEventListener('resize',function(){ 297 var h=window.innerHeight; 298 if(Math.abs(h-s)/s>0.15){s=h;document.documentElement.style.setProperty('--stable-100vh',h+'px');} 299 }); 300 })(); 301 </script> 302 303 <!-- Akkurat body font (self-hosted, non-critical body text) --> 304 305 <!-- Preload LCP hero background image (same-origin, runs after theme detection) --> 306 <script> 307 (function(){ 308 var isDark = document.documentElement.classList.contains('dark'); 309 var isWorkshop = window.location.hostname.includes('workshop.ai'); 310 if (!isWorkshop) return; 311 var w = window.innerWidth; 312 var size = w >= 1920 ? 'xl' : w >= 1024 ? 'lg' : w >= 640 ? 'md' : 'sm'; 313 var theme = isDark ? 'dark-' : ''; 314 var l = document.createElement('link'); 315 l.rel = 'preload'; 316 l.as = 'image'; 317 l.type = 'image/avif'; 318 l.fetchPriority = 'high'; 319 l.href = '/images/hero/leonardo-workshop-' + theme + size + '.avif'; 320 document.head.appendChild(l); 321 })(); 322 </script> 323 324 <!-- Google Tag Manager. Auth-entry documents defer this idempotent starter 325 until first-party code has consumed the private handoff. --> 326 <script> 327 (function (w, d) { 328 var started = false; 329 Object.defineProperty(w, '__startWorkshopGtm', { 330 value: function () { 331 if (started || w.__workshopAuthAnalyticsBlocked === true) return false; 332 started = true; 333 var hn = w.location.hostname; 334 var isLocal = hn === 'localhost' || hn === '127.0.0.1'; 335 var h = 336 hn.includes('workshop.ai') && !hn.includes('dev') 337 ? 'g.workshop.ai' 338 : hn.includes('memex.tech') 339 ? 'g.memex.tech' 340 : 'g-preview.workshop.ai'; 341 if (!isLocal) { 342 var preconnect = d.createElement('link'); 343 preconnect.rel = 'preconnect'; 344 preconnect.href = 'https://' + h; 345 d.head.appendChild(preconnect); 346 } 347 w.dataLayer = w.dataLayer || []; 348 w.dataLayer.push({ 'gtm.start': new Date().getTime(), event: 'gtm.js' }); 349 if (isLocal) return true; 350 var f = d.getElementsByTagName('script')[0], 351 j = d.createElement('script'); 352 j.async = true; 353 j.src = 'https://' + h + '/gtm.js?id=GTM-NJ8V8F5T'; 354 f.parentNode.insertBefore(j, f); 355 return true; 356 }, 357 configurable: true 358 }); 359 w.__startWorkshopGtm(); 360 })(window, document); 361 </script> 362 <!-- End Google Tag Manager --> 363 364
365 <link rel="modulepreload" href="/_app/immutable/entry/start.n_qAlcin.js"> 366 367 368 369 370 371 372 <link rel="modulepreload" href="/_app/immutable/entry/app.CKszG7GY.js"> 373 374 375 376 377 378 379 380 </head> 381 <body data-sveltekit-preload-data="hover"> 382 <!-- Google Tag Manager (noscript) --> 383 <noscript> 384 <iframe src="https://g.memex.tech/ns.html?id=GTM-NJ8V8F5T" 385 height="0" width="0" style="display:none;visibility:hidden" title="Google Tag Manager"></iframe> 386 <iframe src="https://g.workshop.ai/ns.html?id=GTM-NJ8V8F5T" 387 height="0" width="0" style="display:none;visibility:hidden" title="Google Tag Manager"></iframe> 388 </noscript> 389 <!-- End Google Tag Manager (noscript) --> 390 <!-- Skip to main content link for keyboard users --> 391 <a href="#main-content" class="skip-link">Skip to main content</a> 392 <div style="display: contents"> 393 <script> 394 { 395 __sveltekit_5fsdv4 = { 396 base: "" 397 }; 398 399 const element = document.currentScript.parentElement; 400 401 Promise.all([ 402 import("/_app/immutable/entry/start.n_qAlcin.js"), 403 import("/_app/immutable/entry/app.CKszG7GY.js") 404 ]).then(([kit, app]) => { 405 kit.start(app, element); 406 }); 407 } 408 </script> 409 </div> 410 411 </body> 412</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.