1<!doctype html> 2<html lang="en"> 3<head> 4 <meta charset="utf-8" /> 5 <meta name="viewport" content="width=device-width,initial-scale=1,viewport-fit=cover" /> 6 <title>DOODL</title> 7 8 <!-- Uses your DOODL system tokens + styles --> 9 <link rel="stylesheet" href="./doodl.css" /> 10 11 <style> 12 .lp{ 13 min-height:100vh; 14 display:flex; 15 align-items:center; 16 justify-content:center; 17 padding:calc(var(--safe-pad) * 2) var(--safe-pad); 18 text-align:center; 19 } 20 .lp-inner{ width:min(600px, 100%); } 21 22 .lp-logo{ 23 display:block; 24 width:clamp(320px, 42vw, 460px); 25 height:auto; 26 margin:0 auto 16px; 27 object-fit:contain; 28 object-position:center bottom; 29 display:block; 30 user-select:none; 31 -webkit-user-select:none; 32 -webkit-user-drag:none; 33 pointer-events:none; 34 } 35 36 .lp-tagline{ 37 margin:0 auto 28px; 38 color:var(--muted); 39 font-size:13px; 40 letter-spacing:.2px; 41 } 42 43 /* --- Launch Button (premium fill-to-ink) --- */ 44 .lp-cta{ 45 --btn-bg: #ffffff; 46 --btn-fg: #111111; 47 --btn-ink: #0a0a0a; 48 --btn-radius: 999px; 49 50 position:relative; 51 display:inline-flex; 52 align-items:center; 53 justify-content:center; 54 gap:10px; 55 padding:18px 32px; 56 border-radius:var(--btn-radius); 57 border:1px solid rgba(0,0,0,0.12); 58 background:var(--btn-bg); 59 color:var(--btn-fg); 60 font-weight:650; 61 text-decoration:none; 62 /* custom shadow so we can animate it */ 63 box-shadow: 0 14px 32px rgba(0,0,0,0.14), 0 2px 8px rgba(0,0,0,0.06); 64 cursor:pointer; 65 66 overflow:hidden; 67 -webkit-tap-highlight-color: transparent; 68 69 /* no bounce */ 70 transform:none; 71 transition: box-shadow 160ms ease, border-color 160ms ease, color 220ms ease; 72 margin-top: 46px; /* lower button / more breathing room */ 73 } 74 75 /* Ambient shadow sweep (subtle, premium) */ 76 .lp-cta{ 77 animation: shadowSweep 2.8s ease-in-out infinite; 78 } 79 .lp-cta.is-launching{ animation: none; } 80 @keyframes shadowSweep{ 81 0% { box-shadow: 0 14px 32px rgba(0,0,0,0.14), 0 2px 8px rgba(0,0,0,0.06); } 82 40% { box-shadow: 10px 16px 34px rgba(0,0,0,0.13), 0 2px 8px rgba(0,0,0,0.06); } 83 80% { box-shadow: -10px 16px 34px rgba(0,0,0,0.13), 0 2px 8px rgba(0,0,0,0.06); } 84 100% { box-shadow: 0 14px 32px rgba(0,0,0,0.14), 0 2px 8px rgba(0,0,0,0.06); } 85 } 86 87 /* Hover âblipâ (fast, sleek) */ 88 .lp-cta::after{ 89 content:""; 90 position:absolute; 91 inset:0; 92 background:rgba(10,10,10,0.08); 93 opacity:0; 94 pointer-events:none; 95 } 96 .lp-cta:hover{ 97 border-color: rgba(0,0,0,0.18); 98 } 99 .lp-cta:hover::after{ 100 animation: blip 240ms ease-out 1; 101 } 102 @keyframes blip{ 103 0%{ opacity:0; } 104 30%{ opacity:1; } 105 100%{ opacity:0; } 106 } 107 108 /* Progress fill layer */ 109 .lp-cta::before{ 110 content:""; 111 position:absolute; 112 inset:0; 113 background: var(--btn-ink); 114 transform: scaleX(0); 115 transform-origin: left center; 116 transition: transform 3000ms cubic-bezier(.2,.9,.2,1); 117 pointer-events:none; 118 z-index:0; 119 } 120 121 /* Content stays above fill */ 122 .lp-cta .brush, 123 .lp-cta .label{ 124 position:relative; 125 z-index:1; 126 } 127 128 /* Icon: dark by default */ 129 .lp-cta .brush{ 130 width:18px; 131 height:18px; 132 display:block; 133 filter:none; /* dark on light */ 134 opacity:.95; 135 transition: filter 220ms ease, opacity 220ms ease; 136 } 137 138 /* Launch state: fill + invert content */ 139 .lp-cta.is-launching{ 140 cursor:default; 141 pointer-events:none; 142 color:#ffffff; 143 border-color: rgba(0,0,0,0.20); 144 } 145 .lp-cta.is-launching::before{ 146 transform: scaleX(1); 147 } 148 .lp-cta.is-launching .brush{ 149 filter: invert(1); 150 opacity:1; 151 } 152 153 /* Reduced motion: instant swap, still clean */ 154 @media (prefers-reduced-motion: reduce){ 155 .lp-cta{ animation:none; } 156 .lp-cta::before{ transition:none; } 157 .lp-cta:hover::after{ animation:none; } 158 } 159 160 161 /* Subtle default sheen (premium, not quirky) */ 162 .lp-cta .gleam{ 163 position:absolute; 164 inset:-2px; 165 z-index:0; 166 pointer-events:none; 167 border-radius: var(--btn-radius); 168 background: linear-gradient(110deg, 169 rgba(255,255,255,0) 0%, 170 rgba(255,255,255,0.55) 18%, 171 rgba(255,255,255,0) 36%); 172 transform: translateX(-130%); 173 opacity: 0.6; 174 animation: gleam 3.8s ease-in-out infinite; 175 mix-blend-mode: overlay; 176 }
177 @keyframes gleam{ 178 0%{ transform: translateX(-130%); opacity:0.0; } 179 10%{ opacity:0.55; } 180 35%{ transform: translateX(130%); opacity:0.0; } 181 100%{ transform: translateX(130%); opacity:0.0; } 182 } 183 .lp-cta.is-launching .gleam{ opacity:0; animation:none; } 184 185 186 /* Compatible browsers */ 187 .lp-browsers{ 188 margin-top: clamp(240px, 24.0vh, 380px); 189 color:var(--muted); 190 font-size:12px; 191 user-select:none; 192 -webkit-user-select:none; 193 } 194 .lp-browser-row{ 195 margin-top:18px; 196 display:flex; 197 justify-content:center; 198 gap:34px; 199 align-items:center; 200 } 201 202 /* Browser icons (v3) */ 203 .bicon{ 204 position:relative; 205 display:inline-flex; 206 align-items: flex-end; 207 justify-content:center; 208 width:85px; 209 height:85px; 210 border-radius:20px; 211 text-decoration:none; 212 outline:none; 213 -webkit-tap-highlight-color: transparent; 214 } 215 .bicon:focus-visible{ box-shadow: 0 0 0 3px rgba(0,0,0,0.18); } 216 217 .bicon img{ 218 width:75px; 219 height:75px; 220 object-fit:contain; 221 opacity:.95; 222 transition: transform 120ms ease, opacity 120ms ease; 223 } 224 .bicon:hover img{ transform: translateY(-1px); opacity: 1; } 225 .bicon:active img{ transform: translateY(0px) scale(.98); } 226 227 228 .btip{ 229 position:absolute; 230 left:50%; 231 top: calc(100% + 2px); /* tighter to icon */ 232 transform: translate(-50%, 0); 233 background:#0a0a0a; 234 color:#fff; 235 font-size:11px; 236 padding:7px 10px; 237 border-radius:10px; 238 white-space:nowrap; 239 opacity:0; 240 pointer-events:none; 241 transition: opacity 120ms ease; 242 box-shadow: var(--shadow); 243 } 244 .btip::before{ 245 content:""; 246 position:absolute; 247 left:50%; 248 top:-6px; 249 transform: translateX(-50%); 250 width:0; height:0; 251 border-left:6px solid transparent; 252 border-right:6px solid transparent; 253 border-bottom:6px solid #0a0a0a; 254 } 255 .bicon:hover .btip, 256 .bicon:focus-visible .btip{ 257 opacity:1; 258 } 259 260.lp-foot{ 261 position:fixed; 262 left: var(--safe-pad); 263 bottom: var(--safe-pad); 264 z-index:4; 265 color: var(--muted); 266 font-size:12px; 267 user-select:none; 268 -webkit-user-select:none; 269 } 270 271 /* --- Mobile viewport safety: prevent overlap with fixed footer + info button --- */ 272 @media (max-width: 520px), (max-height: 760px){ 273 /* Give the main column extra breathing room above fixed UI */ 274 .lp{ 275 padding-bottom: calc(var(--safe-pad) * 7); 276 } 277 278 /* Pull the browser section UP so it doesn't collide with footer/info */ 279 .lp-browsers{ 280 margin-top: clamp(90px, 11vh, 170px); 281 } 282 283 /* Slightly reduce icon footprint on small screens */ 284 .bicon{ 285 width: 72px; 286 height: 72px; 287 } 288 .bicon img{ 289 width: 62px; 290 height: 62px; 291 } 292 293 /* Nudge fixed elements to respect safe areas */ 294 .lp-foot{ 295 bottom: calc(var(--safe-pad) + env(safe-area-inset-bottom)); 296 } 297 .info-wrap{ 298 bottom: calc(var(--safe-pad) + env(safe-area-inset-bottom)); 299 } 300 } 301 302 303 /* --- Page wipe transition (launch -> app) --- */ 304 .page-wipe{ 305 position: fixed; 306 inset: 0; 307 background: var(--bg, #f5f5f5); 308 transform: translateX(-110%); 309 z-index: 9999; 310 pointer-events: none; 311 transition: transform 480ms cubic-bezier(.2,.9,.2,1); 312 } 313 .page-wipe.is-active{ 314 transform: translateX(0%); 315 } 316 .page-wipe.is-flash{ 317 background: #ffffff; 318 transition: background 140ms ease; 319 } 320 @media (prefers-reduced-motion: reduce){ 321 .page-wipe{ transition: none; } 322 } 323 324 </style> 325 326 <meta name="description" content="DOODL â a simple web-based doodle pad. Draw anywhere, anytime." /> 327 328 <link rel="canonical" href="https://fatoe.com/suite/doodl/" /> 329 330 <meta property="og:url" content="https://fatoe.com/suite/doodl/" /> 331</head> 332 333<body> 334 <div class="page-wipe" id="pageWipe" aria-hidden="true"></div> 335 <main class="lp"> 336 <div class="lp-inner"> 337 <img id="lpLogo" class="lp-logo" alt="DOODL" /> 338 <p id="lpTagline" class="lp-tagline">A simple web-based doodle pad.</p> 339 340 <!-- Launch DOODL (click triggers fill, then navigates) --> 341 <a class="lp-cta" href="./app/" id="launchBtn" aria-label="Launch DOODL"><span class="gleam" aria-hidden="true"></span> 342 <img class="brush" alt="" src="https://fatoe.com/suite/doodl/assets/brush_icon.svg" />
343 <span class="label">Launch DOODL</span> 344 </a> 345 346 <div class="lp-browsers" aria-label="Compatible browsers"> 347 <div>Compatible browsers</div> 348 349 <div class="lp-browser-row"> 350 <a class="bicon" href="https://www.google.com/chrome/" target="_blank" rel="noopener noreferrer" 351 aria-label="Open Chrome download page"> 352 <img alt="Chrome" src="https://fatoe.com/suite/doodl/assets/logo_chrome.png" /> 353 <span class="btip" role="tooltip">Chrome</span> 354 </a> 355 356 <a class="bicon" href="https://www.mozilla.org/firefox/new/" target="_blank" rel="noopener noreferrer" 357 aria-label="Open Firefox download page"> 358 <img alt="Firefox" src="https://fatoe.com/suite/doodl/assets/logo_firefox.png" /> 359 <span class="btip" role="tooltip">Firefox</span> 360 </a> 361 362 <a class="bicon" href="https://chatgpt.com/atlas" target="_blank" rel="noopener noreferrer" 363 aria-label="Open Atlas browser website"> 364 <img alt="Atlas" src="https://fatoe.com/suite/doodl/assets/logo_atlas.png" /> 365 <span class="btip" role="tooltip">Atlas</span> 366 </a> 367 </div> 368 </div> 369 </div> 370 </main> 371 372 <div class="lp-foot">© 2026 Fatoe. Los Angeles, CA. Est. Y2K.</div> 373 374 <div class="info-wrap"> 375 <button class="info-btn" id="infoBtn" aria-label="Info" title="Info">i</button> 376 <div class="tooltip" id="tooltip" data-open="false"> 377 <span class="tip-title">DOODL</span> 378 <span class="tip-body"> 379 Best experience: Chrome, Firefox, and Atlas.<br /> 380 Developer note: Safari support still in development. 381 </span> 382 <span class="tip-sub">Tap Launch to begin.</span> 383 </div> 384 </div> 385 386
386<script> 387 // Random logo per load (avoid repeating last in this session) 388 (function(){ 389 const logos = [ 390 "https://fatoe.com/suite/doodl/assets/doodl_01.png", 391 "https://fatoe.com/suite/doodl/assets/doodl_02.png", 392 "https://fatoe.com/suite/doodl/assets/doodl_03.png", 393 "https://fatoe.com/suite/doodl/assets/doodl_04.png" 394 ]; 395 const last = Number(sessionStorage.getItem("doodl_lp_logo")) || -1; 396 let idx = Math.floor(Math.random() * logos.length); 397 if (logos.length > 1 && idx === last) idx = (idx + 1) % logos.length; 398 399 sessionStorage.setItem("doodl_lp_logo", String(idx)); 400 const img = document.getElementById("lpLogo"); 401 if (img) img.src = logos[idx]; 402 })(); 403 404 // Random tagline per load (avoid repeating last) 405 (function(){ 406 const taglines = [ 407 "A simple web-based doodle pad.", 408 "Draw anywhere, anytime.", 409 "Make something small. Make it yours.", 410 "Quick ideas, clean output.", 411 "A pocket sketchbook for the web." 412 ]; 413 const last = Number(sessionStorage.getItem("doodl_lp_tag")) || -1; 414 let idx = Math.floor(Math.random() * taglines.length); 415 if (taglines.length > 1 && idx === last) idx = (idx + 1) % taglines.length; 416
417 sessionStorage.setItem("doodl_lp_tag", String(idx)); 418 const el = document.getElementById("lpTagline"); 419 if (el) el.textContent = taglines[idx]; 420 })(); 421 422 // Info tooltip toggle 423 (function(){ 424 const btn = document.getElementById("infoBtn"); 425 const tip = document.getElementById("tooltip"); 426 if (!btn || !tip) return; 427 428 function close(){ tip.setAttribute("data-open","false"); } 429 function toggle(){ 430 const open = tip.getAttribute("data-open") === "true"; 431 tip.setAttribute("data-open", open ? "false" : "true"); 432 } 433 434 btn.addEventListener("click", function(e){ 435 e.stopPropagation(); 436 toggle(); 437 }); 438 439 document.addEventListener("click", close); 440 document.addEventListener("keydown", function(e){ 441 if (e.key === "Escape") close(); 442 }); 443 })(); 444 445 446 // Launch button: click -> fill-to-ink -> page wipe -> navigate 447 (function(){ 448 const a = document.getElementById("launchBtn"); 449 const wipe = document.getElementById("pageWipe"); 450 if (!a) return; 451 452 const reduceMotion = window.matchMedia && window.matchMedia("(prefers-reduced-motion: reduce)").matches; 453 454 // Total pacing target ~3s 455 const FILL_MS = reduceMotion ? 0 : 2400; 456 const WIPE_MS = reduceMotion ? 0 : 480; 457 const FLASH_MS = reduceMotion ? 0 : 140; 458 459 a.addEventListener("click", function(e){ 460 if (a.classList.contains("is-launching")) return; 461 e.preventDefault(); 462 463 a.classList.add("is-launching"); 464 a.setAttribute("aria-disabled", "true"); 465 466 window.setTimeout(function(){ 467 if (!wipe){ 468 window.location.href = a.getAttribute("href"); 469 return; 470 } 471 472 wipe.classList.add("is-active"); 473 474 window.setTimeout(function(){ 475 wipe.classList.add("is-flash"); 476 window.setTimeout(function(){ 477 window.location.href = a.getAttribute("href"); 478 }, FLASH_MS); 479 }, Math.max(0, WIPE_MS - 160)); 480 481 }, FILL_MS); 482 }); 483 })(); 484 485</script>
485 486</body> 487</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.