patx/afterdarklabs

simplify the hero

Commit c017d19 · patx · 2026-07-08T16:55:32-04:00

Changeset
c017d1926bd2036fdd63dd0e8a1047f8406ff7f4
Parents
7edc16c8def6e00c7551a2dccce77eb911a3b630

View source at this commit

Comments

No comments yet.

Log in to comment

Diff

diff --git a/docs/index.html b/docs/index.html
index 5f3b720..176268a 100644
--- a/docs/index.html
+++ b/docs/index.html
@@ -26,7 +26,7 @@
     <meta name="twitter:image:alt" content="After Dark Labs Florida website design and development">
     <link rel="stylesheet" href="index.tailwind.css?v=2">
     <style>
-        @import url('https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700;800&family=Space+Grotesk:wght@500;600;700&family=Syne:wght@500;600;700;800&display=swap');
+        @import url('https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700;800&family=Space+Grotesk:wght@500;600;700&family=Syne:wght@500;600;700;800&family=Yellowtail&display=swap');
 
         :root {
             --neon: #ccff00;
@@ -54,22 +54,70 @@
         }
 
         .neon-text {
+            position: relative;
+            isolation: isolate;
+            display: inline-flex;
+            align-items: baseline;
+            font-family: 'Yellowtail', cursive;
+            font-size: clamp(0.94em, 18vw, 1.22em);
+            font-weight: 400;
+            letter-spacing: 0.01em;
+            line-height: 0.9;
             color: var(--neon);
-            text-shadow: 0 0 10px var(--neon), 0 0 25px var(--neon), 0 0 50px var(--neon);
+            transform: rotate(-1deg);
+            transform-origin: left center;
+            vertical-align: -0.03em;
+            white-space: nowrap;
+        }
+
+        .neon-letter,
+        .neon-gap {
+            position: relative;
+            display: inline-block;
+        }
+
+        .neon-letter {
+            color: #ccff00;
+            -webkit-text-fill-color: currentColor;
+            -webkit-text-stroke: 0.012em rgba(250,255,205,0.88);
+            filter:
+                drop-shadow(0 0 0.014em rgba(255,255,235,0.72))
+                drop-shadow(0 0 0.045em rgba(204,255,0,0.72))
+                drop-shadow(0 0 0.105em rgba(204,255,0,0.26));
+            text-shadow:
+                0 0 0.035em rgba(255,255,235,0.55),
+                0 0 0.095em rgba(204,255,0,0.42);
+            animation: neon-letter-idle 5.2s ease-in-out infinite;
+            animation-delay: var(--idle-delay, 0s);
         }
 
-        #hero-canvas {
+        .neon-letter::after {
+            content: attr(data-letter);
             position: absolute;
             inset: 0;
-            width: 100%;
-            height: 100%;
-            display: block;
-            z-index: 0;
+            color: transparent;
+            -webkit-text-fill-color: transparent;
+            -webkit-text-stroke: 0.018em rgba(4,8,10,0.46);
+            transform: translate(0.01em, 0.012em);
+            opacity: 0.45;
+            z-index: -1;
+        }
+
+        .neon-letter--flicker {
+            animation-name: neon-letter-idle, neon-letter-flicker;
+            animation-duration: 5.2s, var(--flicker-duration, 9s);
+            animation-timing-function: ease-in-out, linear;
+            animation-iteration-count: infinite, infinite;
+            animation-delay: var(--idle-delay, 0s), var(--flicker-delay, 0s);
+        }
+
+        .neon-gap {
+            width: 0.22em;
         }
 
         .hero-content {
             position: relative;
-            z-index: 1;
+            z-index: 2;
         }
 
         .hero-vignette {
@@ -82,6 +130,48 @@
             z-index: 1;
         }
 
+        @keyframes neon-letter-idle {
+            0%, 100% {
+                filter:
+                    drop-shadow(0 0 0.014em rgba(255,255,235,0.72))
+                    drop-shadow(0 0 0.045em rgba(204,255,0,0.72))
+                    drop-shadow(0 0 0.105em rgba(204,255,0,0.26));
+            }
+            50% {
+                filter:
+                    drop-shadow(0 0 0.018em rgba(255,255,235,0.84))
+                    drop-shadow(0 0 0.055em rgba(204,255,0,0.80))
+                    drop-shadow(0 0 0.13em rgba(204,255,0,0.32));
+            }
+        }
+
+        @keyframes neon-letter-flicker {
+            0%, 4%, 6%, 9%, 37%, 39%, 41%, 100% {
+                opacity: 1;
+                -webkit-text-stroke-color: rgba(250,255,205,0.88);
+            }
+            4.7%, 38% {
+                opacity: 0.22;
+                -webkit-text-stroke-color: rgba(204,255,0,0.28);
+                filter:
+                    drop-shadow(0 0 0.006em rgba(204,255,0,0.30))
+                    drop-shadow(0 0 0.025em rgba(204,255,0,0.18));
+            }
+            5.4%, 40% {
+                opacity: 0.64;
+            }
+            70%, 71.5% {
+                opacity: 0.48;
+            }
+        }
+
+        @media (prefers-reduced-motion: reduce) {
+            .neon-letter,
+            .neon-letter--flicker {
+                animation: none;
+            }
+        }
+
         .service-chip:has(input:checked) {
             border-color: rgba(204,255,0,0.8);
             background: rgba(204,255,0,0.12);
@@ -199,13 +289,12 @@
 
     <main>
         <section id="hero" class="hero-bg min-h-screen flex items-center pt-20" style="position:relative; overflow:hidden;">
-            <canvas id="hero-canvas"></canvas>
             <div class="hero-vignette"></div>
 
             <div class="hero-content mx-auto grid w-full max-w-7xl gap-10 px-6 py-32 text-left lg:grid-cols-[1.3fr_0.7fr] lg:items-end">
                 <div>
                     <h1 class="heading text-7xl font-bold leading-none tracking-tighter md:text-8xl lg:text-7xl xl:text-8xl">
-                        Websites and tools that help businesses<br><span class="neon-text">stand out</span>.
+                        Websites and tools that help businesses<br><span class="neon-text" aria-hidden="true"><span class="neon-letter neon-letter--flicker" data-letter="s" style="--idle-delay:-0.4s; --flicker-delay:-1.1s; --flicker-duration:11s;">s</span><span class="neon-letter" data-letter="t" style="--idle-delay:-1.6s;">t</span><span class="neon-letter neon-letter--flicker" data-letter="a" style="--idle-delay:-2.2s; --flicker-delay:-5.6s; --flicker-duration:13s;">a</span><span class="neon-letter" data-letter="n" style="--idle-delay:-0.8s;">n</span><span class="neon-letter neon-letter--flicker" data-letter="d" style="--idle-delay:-3.1s; --flicker-delay:-8.4s; --flicker-duration:15s;">d</span><span class="neon-gap"></span><span class="neon-letter" data-letter="o" style="--idle-delay:-1.2s;">o</span><span class="neon-letter neon-letter--flicker" data-letter="u" style="--idle-delay:-2.7s; --flicker-delay:-3.3s; --flicker-duration:12s;">u</span><span class="neon-letter" data-letter="t" style="--idle-delay:-3.6s;">t</span></span><span class="sr-only">stand out</span>
                     </h1>
                 </div>
                 <div class="mx-auto flex max-w-xl flex-col items-start gap-8 lg:mx-0">
@@ -667,166 +756,6 @@
             setStep(0, false);
         })();
 
-        /* ─── HERO CANVAS ANIMATION ──────────────────────────────── */
-        (function () {
-            const canvas  = document.getElementById('hero-canvas');
-            const section = canvas.closest('section');
-            const ctx     = canvas.getContext('2d');
-
-            const NODE_COUNT = 80;
-            const LINK_DIST  = 140;
-            const PULSE_SPEED = 0.012;
-
-            let W, H, nodes = [], mouse = { x: -9999, y: -9999 };
-
-            function resize() {
-                const rect = section.getBoundingClientRect();
-                W = canvas.width  = rect.width  * devicePixelRatio;
-                H = canvas.height = rect.height * devicePixelRatio;
-                canvas.style.width  = rect.width  + 'px';
-                canvas.style.height = rect.height + 'px';
-            }
-
-            function makeNode() {
-                return {
-                    x:  Math.random() * W,
-                    y:  Math.random() * H,
-                    vx: (Math.random() - 0.5) * 0.45,
-                    vy: (Math.random() - 0.5) * 0.45,
-                    r:  1.5 + Math.random() * 2,
-                    phase: Math.random() * Math.PI * 2,
-                };
-            }
-
-            function init() {
-                resize();
-                nodes = Array.from({ length: NODE_COUNT }, makeNode);
-            }
-
-            const ORBS = [
-                { cx: 0.20, cy: 0.35, r: 0.22, spd: 0.0007, off: 0 },
-                { cx: 0.75, cy: 0.60, r: 0.18, spd: 0.0011, off: 2.1 },
-                { cx: 0.50, cy: 0.25, r: 0.14, spd: 0.0009, off: 4.5 },
-                { cx: 0.85, cy: 0.20, r: 0.12, spd: 0.0013, off: 1.3 },
-            ];
-
-            function drawOrbs(t) {
-                ORBS.forEach(o => {
-                    const cx = (o.cx + Math.sin(t * o.spd + o.off) * 0.06) * W;
-                    const cy = (o.cy + Math.cos(t * o.spd * 1.3 + o.off) * 0.06) * H;
-                    const r  = o.r * Math.min(W, H);
-                    const g  = ctx.createRadialGradient(cx, cy, 0, cx, cy, r);
-                    g.addColorStop(0,   'rgba(204,255,0,0.10)');
-                    g.addColorStop(0.5, 'rgba(204,255,0,0.04)');
-                    g.addColorStop(1,   'rgba(204,255,0,0)');
-                    ctx.beginPath();
-                    ctx.arc(cx, cy, r, 0, Math.PI * 2);
-                    ctx.fillStyle = g;
-                    ctx.fill();
-                });
-            }
-
-            let rings = [];
-            section.addEventListener('mousemove', e => {
-                const rect = section.getBoundingClientRect();
-                mouse.x = (e.clientX - rect.left) * devicePixelRatio;
-                mouse.y = (e.clientY - rect.top)  * devicePixelRatio;
-                if (Math.random() < 0.08) {
-                    rings.push({ x: mouse.x, y: mouse.y, r: 0, alpha: 0.5 });
-                }
-            });
-            section.addEventListener('mouseleave', () => { mouse.x = mouse.y = -9999; });
-
-            function drawRings() {
-                rings = rings.filter(rg => rg.alpha > 0.01);
-                rings.forEach(rg => {
-                    rg.r     += 1.8;
-                    rg.alpha *= 0.93;
-                    ctx.beginPath();
-                    ctx.arc(rg.x, rg.y, rg.r, 0, Math.PI * 2);
-                    ctx.strokeStyle = `rgba(204,255,0,${rg.alpha})`;
-                    ctx.lineWidth = 1;
-                    ctx.stroke();
-                });
-            }
-
-            let t = 0;
-            function frame() {
-                t++;
-                ctx.clearRect(0, 0, W, H);
-                ctx.fillStyle = getComputedStyle(document.documentElement).getPropertyValue('--page-bg').trim() || '#17212b';
-                ctx.fillRect(0, 0, W, H);
-
-                drawOrbs(t);
-
-                nodes.forEach(n => {
-                    n.phase += PULSE_SPEED;
-                    n.x += n.vx;
-                    n.y += n.vy;
-                    if (n.x < 0 || n.x > W) n.vx *= -1;
-                    if (n.y < 0 || n.y > H) n.vy *= -1;
-
-                    const dx = n.x - mouse.x, dy = n.y - mouse.y;
-                    const d2 = dx * dx + dy * dy;
-                    if (d2 < 90000) {
-                        const f = (1 - d2 / 90000) * 0.4;
-                        n.vx += (dx / Math.sqrt(d2)) * f;
-                        n.vy += (dy / Math.sqrt(d2)) * f;
-                    }
-
-                    const spd = Math.sqrt(n.vx * n.vx + n.vy * n.vy);
-                    if (spd > 1.2) { n.vx /= spd / 1.2; n.vy /= spd / 1.2; }
-                });
-
-                ctx.lineWidth = 0.8;
-                for (let i = 0; i < nodes.length; i++) {
-                    for (let j = i + 1; j < nodes.length; j++) {
-                        const a = nodes[i], b = nodes[j];
-                        const dx = a.x - b.x, dy = a.y - b.y;
-                        const d  = Math.sqrt(dx * dx + dy * dy);
-                        if (d < LINK_DIST * devicePixelRatio) {
-                            const alpha = (1 - d / (LINK_DIST * devicePixelRatio)) * 0.35;
-                            ctx.strokeStyle = `rgba(204,255,0,${alpha})`;
-                            ctx.beginPath();
-                            ctx.moveTo(a.x, a.y);
-                            ctx.lineTo(b.x, b.y);
-                            ctx.stroke();
-                        }
-                    }
-                }
-
-                nodes.forEach(n => {
-                    const pulse = 0.5 + 0.5 * Math.sin(n.phase);
-                    const alpha = 0.55 + 0.45 * pulse;
-                    const glow  = ctx.createRadialGradient(n.x, n.y, 0, n.x, n.y, n.r * 4);
-                    glow.addColorStop(0,   `rgba(204,255,0,${alpha})`);
-                    glow.addColorStop(0.4, `rgba(204,255,0,${alpha * 0.3})`);
-                    glow.addColorStop(1,   'rgba(204,255,0,0)');
-                    ctx.beginPath();
-                    ctx.arc(n.x, n.y, n.r * 4 * devicePixelRatio, 0, Math.PI * 2);
-                    ctx.fillStyle = glow;
-                    ctx.fill();
-
-                    ctx.beginPath();
-                    ctx.arc(n.x, n.y, n.r * devicePixelRatio, 0, Math.PI * 2);
-                    ctx.fillStyle = `rgba(204,255,0,${alpha})`;
-                    ctx.fill();
-                });
-
-                drawRings();
-
-                for (let y = 0; y < H; y += 4) {
-                    ctx.fillStyle = 'rgba(255,255,255,0.018)';
-                    ctx.fillRect(0, y, W, 1);
-                }
-
-                requestAnimationFrame(frame);
-            }
-
-            window.addEventListener('resize', () => { resize(); });
-            init();
-            frame();
-        })();
     </script>
 </body>
 </html>