patx/afterdarklabs
indexerd.html 1
Commit 73c995d · patx · 2026-09-03T00:28:35-04:00
Comments
No comments yet.
Diff
diff --git a/docs/indexerd.html b/docs/indexerd.html
new file mode 100644
index 0000000..123ee56
--- /dev/null
+++ b/docs/indexerd.html
@@ -0,0 +1,1045 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+ <meta charset="UTF-8">
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
+ <link rel="icon" href="https://afterdarklabs.io/logo_assets/favicon.ico">
+ <link rel="icon" type="image/svg+xml" href="https://afterdarklabs.io/logo_assets/badge.svg">
+ <link rel="icon" type="image/png" sizes="32x32" href="https://afterdarklabs.io/logo_assets/favicon-32.png">
+ <link rel="icon" type="image/png" sizes="16x16" href="https://afterdarklabs.io/logo_assets/favicon-16.png">
+ <link rel="apple-touch-icon" sizes="180x180" href="https://afterdarklabs.io/logo_assets/apple-touch-icon.png">
+ <link rel="manifest" href="https://afterdarklabs.io/site.webmanifest">
+ <title>Website Design & Development in South Florida | After Dark Labs</title>
+ <meta name="description" content="South Florida website design and development for custom websites, Shopify stores, mobile apps, SaaS platforms, APIs, AI integrations, and business tools.">
+ <meta name="robots" content="index,follow,max-image-preview:large">
+ <link rel="canonical" href="https://afterdarklabs.io/">
+ <meta property="og:title" content="Website Design & Development in South Florida | After Dark Labs">
+ <meta property="og:description" content="South Florida website design and development for custom websites, Shopify stores, mobile apps, SaaS platforms, APIs, AI integrations, and business tools.">
+ <meta property="og:image" content="https://afterdarklabs.io/twitter-card.png?v=3">
+ <meta property="og:image:width" content="1200">
+ <meta property="og:image:height" content="630">
+ <meta property="og:image:alt" content="After Dark Labs websites and tools that help businesses stand out">
+ <meta property="og:type" content="website">
+ <meta property="og:url" content="https://afterdarklabs.io/">
+ <meta property="og:site_name" content="After Dark Labs">
+ <meta property="og:locale" content="en_US">
+ <meta name="twitter:card" content="summary_large_image">
+ <meta name="twitter:title" content="Website Design & Development in South Florida | After Dark Labs">
+ <meta name="twitter:description" content="South Florida website design and development for custom websites, Shopify stores, mobile apps, SaaS platforms, APIs, AI integrations, and business tools.">
+ <meta name="twitter:image" content="https://afterdarklabs.io/twitter-card.png?v=3">
+ <meta name="twitter:image:alt" content="After Dark Labs websites and tools that help businesses stand out">
+ <link rel="preload" href="https://afterdarklabs.io/fonts/ubuntu-400-latin.woff2" as="font" type="font/woff2" crossorigin>
+ <link rel="preload" href="https://afterdarklabs.io/fonts/ubuntu-700-latin.woff2" as="font" type="font/woff2" crossorigin>
+ <link rel="stylesheet" href="https://afterdarklabs.io/index.tailwind.css?v=4">
+ <style>
+ @font-face {
+ font-family: 'Ubuntu';
+ font-style: normal;
+ font-weight: 400;
+ font-display: swap;
+ src: url('https://afterdarklabs.io/fonts/ubuntu-400-latin.woff2') format('woff2');
+ }
+
+ @font-face {
+ font-family: 'Ubuntu';
+ font-style: normal;
+ font-weight: 500;
+ font-display: swap;
+ src: url('https://afterdarklabs.io/fonts/ubuntu-500-latin.woff2') format('woff2');
+ }
+
+ @font-face {
+ font-family: 'Ubuntu';
+ font-style: normal;
+ font-weight: 700;
+ font-display: swap;
+ src: url('https://afterdarklabs.io/fonts/ubuntu-700-latin.woff2') format('woff2');
+ }
+
+ :root {
+ --neon: #ccff00;
+ --page-bg: #ffffff;
+ --page-bg-rgb: 23, 33, 43;
+ --site-nav-height: 5.75rem;
+ }
+
+ html { scroll-behavior: smooth; }
+
+ @media (min-width: 1024px) {
+ :root {
+ --site-nav-height: 5.5rem;
+ }
+
+ html {
+ font-size: 125%;
+ }
+
+ nav img[src*="/logo_assets/mark"],
+ footer img[src*="/logo_assets/mark"] {
+ width: 3rem;
+ height: 3rem;
+ }
+
+ .hero-content h1 {
+ font-size: 4.5rem;
+ }
+ }
+
+ @media (min-width: 1600px) {
+ .hero-content h1 {
+ font-size: 6rem;
+ }
+ }
+
+ body {
+ background: var(--page-bg);
+ font-family: 'Ubuntu', system-ui, sans-serif;
+ }
+
+ .heading,
+ .logo-font { font-family: inherit; color: #000; }
+
+ .hero-bg { background: var(--page-bg); }
+
+ .bg-black,
+ .bg-zinc-950 {
+ background-color: var(--page-bg) !important;
+ }
+
+ .neon-ink {
+ color: #000;
+ }
+
+ .bg-black\/90 {
+ background-color: #fff; !important;
+ }
+
+ .neon-text {
+ position: relative;
+ isolation: isolate;
+ display: inline-flex;
+ align-items: baseline;
+ font: inherit;
+ letter-spacing: inherit;
+ line-height: inherit;
+ color: var(--neon);
+ white-space: nowrap;
+ }
+
+ .neon-text::before {
+ content: "";
+ position: absolute;
+ inset: -0.24em -0.42em -0.18em;
+ background: radial-gradient(ellipse at 50% 58%, rgba(204,255,0,0.38), rgba(204,255,0,0.16) 42%, transparent 74%);
+ filter: blur(0.18em);
+ opacity: 0.9;
+ pointer-events: none;
+ z-index: -2;
+ }
+
+ .neon-letter,
+ .neon-gap {
+ position: relative;
+ display: inline-block;
+ font: inherit;
+ letter-spacing: inherit;
+ line-height: inherit;
+ }
+
+ .neon-letter {
+ color: #ccff00;
+ -webkit-text-fill-color: currentColor;
+ -webkit-text-stroke: 0.006em rgba(235,255,120,0.58);
+ filter:
+ drop-shadow(0 0 0.012em rgba(235,255,120,0.54))
+ drop-shadow(0 0 0.045em rgba(204,255,0,0.72))
+ drop-shadow(0 0 0.105em rgba(204,255,0,0.28))
+ drop-shadow(0 0 0.24em rgba(204,255,0,0.16));
+ text-shadow:
+ 0 0 0.026em rgba(235,255,120,0.38),
+ 0 0 0.095em rgba(204,255,0,0.42);
+ }
+
+ .neon-letter::after {
+ content: attr(data-letter);
+ position: absolute;
+ inset: 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: neon-letter-flicker var(--flicker-duration, 12s) steps(1, end) infinite;
+ animation-delay: var(--flicker-delay, 0s);
+ }
+
+ .neon-gap {
+ width: 0.18em;
+ }
+
+ .hero-content {
+ position: relative;
+ z-index: 2;
+ max-width: none;
+ padding-inline: 0;
+ padding-block: 0;
+ }
+
+ #hero {
+ box-sizing: border-box;
+ height: 100svh;
+ min-height: 100svh;
+ padding-top: var(--site-nav-height);
+ padding-bottom: 0;
+ }
+
+ .nav-brand {
+ transform-origin: left center;
+ }
+
+ .nav-brand-ready .nav-brand {
+ visibility: hidden;
+ opacity: 0;
+ clip-path: inset(20% 100% 20% 0 round 1rem);
+ filter: blur(0.3rem);
+ pointer-events: none;
+ transform: translate3d(-1.5rem, 0, 0) skewX(-10deg) scaleX(0.45);
+ transition:
+ opacity 160ms ease,
+ transform 280ms ease,
+ filter 220ms ease,
+ clip-path 280ms ease,
+ visibility 0s linear 280ms;
+ will-change: transform, opacity, clip-path, filter;
+ }
+
+ .nav-brand-ready .nav-brand.is-visible {
+ visibility: visible;
+ opacity: 1;
+ clip-path: none;
+ filter: none;
+ pointer-events: auto;
+ transform: none;
+ animation: nav-brand-swish-in 720ms cubic-bezier(0.16, 1, 0.3, 1);
+ transition: none;
+ }
+
+ .hero-vignette {
+ position: absolute;
+ inset: 0;
+ background: #fff;
+ pointer-events: none;
+ z-index: 1;
+ }
+
+ @media (max-width: 767px) {
+ #hero {
+ --mobile-nav-height: 5.75rem;
+ box-sizing: border-box;
+ height: var(--mobile-hero-height, 100svh);
+ min-height: var(--mobile-hero-height, 100svh);
+ align-items: stretch;
+ padding-top: var(--mobile-nav-height);
+ padding-bottom: 0;
+ }
+
+ .hero-content {
+ align-content: center;
+ gap: 0;
+ padding-block: clamp(1.25rem, 4svh, 2rem);
+ }
+
+ .hero-content h1 {
+ font-size: clamp(2.75rem, 17vw, 4.5rem);
+ font-size: clamp(2.75rem, min(17vw, 9.5svh), 4.5rem);
+ }
+
+ }
+
+ .hero-content h1 {
+ width: max-content;
+ padding-right: 0.1em;
+ font-size: 53vw;
+ font-size: min(53vw, calc((100svh - var(--site-nav-height)) * 1.25));
+ line-height: 0.8;
+ letter-spacing: -0.075em;
+ }
+
+ @keyframes nav-brand-swish-in {
+ 0% {
+ opacity: 0;
+ clip-path: polygon(0 43%, 0 43%, 0 57%, 0 57%);
+ filter: blur(0.45rem);
+ transform: translate3d(-3rem, 0.25rem, 0) skewX(-22deg) scale(0.3, 1.28);
+ }
+ 38% {
+ opacity: 1;
+ clip-path: polygon(0 -7%, 104% 6%, 97% 108%, -2% 91%);
+ filter: blur(0);
+ transform: translate3d(0.7rem, -0.08rem, 0) skewX(8deg) scale(1.08, 0.88);
+ }
+ 58% {
+ clip-path: polygon(0 5%, 98% -4%, 103% 95%, 2% 103%);
+ transform: translate3d(-0.3rem, 0.04rem, 0) skewX(-5deg) scale(0.96, 1.08);
+ }
+ 78% {
+ clip-path: polygon(0 -1%, 101% 2%, 99% 101%, 0 98%);
+ transform: translate3d(0.12rem, 0, 0) skewX(2deg) scale(1.02, 0.98);
+ }
+ 100% {
+ opacity: 1;
+ clip-path: polygon(0 0, 100% 0, 100% 100%, 0 100%);
+ filter: blur(0);
+ transform: none;
+ }
+ }
+
+ @keyframes neon-letter-flicker {
+ 0%, 4.8%, 5.4%, 5.9%, 37.5%, 38%, 38.6%, 100% {
+ opacity: 1;
+ -webkit-text-stroke-color: rgba(235,255,120,0.58);
+ filter:
+ drop-shadow(0 0 0.012em rgba(235,255,120,0.54))
+ drop-shadow(0 0 0.045em rgba(204,255,0,0.72))
+ drop-shadow(0 0 0.105em rgba(204,255,0,0.28))
+ drop-shadow(0 0 0.24em rgba(204,255,0,0.16));
+ }
+ 5%, 37.8% {
+ opacity: 0.08;
+ -webkit-text-stroke-color: rgba(204,255,0,0.18);
+ filter: none;
+ }
+ 5.7%, 38.3% {
+ opacity: 0.38;
+ -webkit-text-stroke-color: rgba(204,255,0,0.36);
+ filter:
+ drop-shadow(0 0 0.012em rgba(204,255,0,0.34))
+ drop-shadow(0 0 0.036em rgba(204,255,0,0.20));
+ }
+ }
+
+ .work-intro {
+ position: relative;
+ height: 100svh;
+ background: var(--page-bg);
+ }
+
+ .work-intro-stage {
+ position: sticky;
+ top: var(--site-nav-height);
+ display: flex;
+ box-sizing: border-box;
+ align-items: flex-start;
+ overflow: hidden;
+ padding: clamp(0.75rem, 1.5vw, 1.25rem) clamp(1.5rem, 5vw, 4rem);
+ }
+
+ .work-heading {
+ display: flex;
+ width: 100%;
+ max-width: 78rem;
+ flex-wrap: wrap;
+ gap: 0 0.2em;
+ margin: 0 auto;
+ color: #000;
+ font-size: clamp(2.85rem, 8vw, 7rem);
+ font-weight: 700;
+ line-height: 0.94;
+ letter-spacing: -0.065em;
+ text-wrap: balance;
+ }
+
+ .work-heading-words {
+ display: contents;
+ }
+
+ .work-heading-word {
+ display: inline-block;
+ }
+
+ .work-intro.is-scroll-ready .work-heading-word {
+ opacity: 0;
+ filter: blur(0.18em);
+ transform: translate3d(0, 0.42em, 0) rotate(1.5deg);
+ transform-origin: left bottom;
+ transition:
+ opacity 220ms ease,
+ filter 360ms ease,
+ transform 420ms cubic-bezier(0.16, 1, 0.3, 1);
+ will-change: opacity, filter, transform;
+ }
+
+ .work-intro.is-scroll-ready .work-heading-word.is-revealed {
+ opacity: 1;
+ filter: none;
+ transform: none;
+ }
+
+ @media (prefers-reduced-motion: reduce) {
+ .nav-brand-ready .nav-brand,
+ .nav-brand-ready .nav-brand.is-visible {
+ animation: none;
+ transition: none;
+ }
+
+ .neon-letter,
+ .neon-letter--flicker {
+ animation: none;
+ }
+
+ .work-intro {
+ height: auto;
+ }
+
+ .work-intro-stage {
+ position: relative;
+ top: auto;
+ }
+
+ .work-intro.is-scroll-ready .work-heading-word {
+ opacity: 1;
+ filter: none;
+ transform: none;
+ transition: none;
+ }
+ }
+
+ .work-stage {
+ box-sizing: border-box;
+ padding: clamp(0.75rem, 1.5vw, 1.5rem) clamp(1rem, 2vw, 2rem) clamp(5rem, 9vw, 8rem);
+ }
+
+ .work-stage-content {
+ width: 100%;
+ max-width: none;
+ min-width: 0;
+ margin-inline: auto;
+ }
+
+ #work-scroller {
+ display: grid;
+ grid-template-columns: minmax(0, 1fr);
+ gap: clamp(0.3rem, 0.6vw, 0.65rem);
+ overflow: visible;
+ padding: 0;
+ }
+
+ #work-scroller > article {
+ position: relative;
+ isolation: isolate;
+ width: 100%;
+ min-width: 0;
+ aspect-ratio: 16 / 9;
+ border-radius: 0;
+ }
+
+ #work-scroller > article > a {
+ display: block;
+ width: 100%;
+ height: 100%;
+ border-radius: 0;
+ }
+
+ #work-scroller > article > a > img {
+ width: 100%;
+ height: 100%;
+ aspect-ratio: auto;
+ object-fit: cover;
+ transition: transform 600ms cubic-bezier(0.16, 1, 0.3, 1);
+ }
+
+ #work-scroller > article > div {
+ position: absolute;
+ inset: 0;
+ z-index: 2;
+ display: flex;
+ box-sizing: border-box;
+ align-items: center;
+ overflow: hidden;
+ padding: clamp(1rem, 2.5vw, 2.75rem);
+ background: rgba(255, 255, 255, 0.94);
+ opacity: 0;
+ clip-path: inset(100% 0 0 0);
+ pointer-events: none;
+ transform: translate3d(0, 7%, 0) skewY(1.2deg);
+ transform-origin: center bottom;
+ transition:
+ opacity 180ms ease,
+ clip-path 480ms cubic-bezier(0.16, 1, 0.3, 1),
+ transform 520ms cubic-bezier(0.16, 1, 0.3, 1);
+ backdrop-filter: blur(0.35rem);
+ }
+
+ #work-scroller > article:hover > div,
+ #work-scroller > article:focus-within > div,
+ #work-scroller > article.is-description-visible > div {
+ opacity: 1;
+ clip-path: inset(0);
+ transform: none;
+ }
+
+ #work-scroller > article:hover > a > img,
+ #work-scroller > article:focus-within > a > img,
+ #work-scroller > article.is-description-visible > a > img {
+ transform: scale(1.025);
+ }
+
+ #work-scroller > article:focus-within {
+ outline: 2px solid var(--neon);
+ outline-offset: -2px;
+ }
+
+ #work-scroller > article > div > p {
+ width: 100%;
+ margin: 0;
+ color: #000;
+ font-size: clamp(1.2rem, 3vw, 3.5rem);
+ font-weight: 500;
+ line-height: 0.98;
+ letter-spacing: -0.04em;
+ text-wrap: balance;
+ }
+
+ .portfolio-description {
+ display: block;
+ color: #000;
+ }
+
+ .portfolio-name {
+ font-weight: 700;
+ }
+
+ .portfolio-scroll-ready #work-scroller > article {
+ opacity: var(--card-opacity, 0);
+ filter: blur(var(--card-blur, 0.4rem));
+ transform:
+ translate3d(var(--card-x, 0), var(--card-y, 5rem), 0)
+ rotate(var(--card-rotate, 0deg))
+ skewY(var(--card-skew, 0deg))
+ scale(var(--card-scale-x, 0.94), var(--card-scale-y, 1.04));
+ transform-origin: center bottom;
+ will-change: opacity, filter, transform;
+ }
+
+ @media (min-width: 768px) {
+ #work-scroller {
+ grid-template-columns: repeat(2, minmax(0, 1fr));
+ }
+
+ }
+
+ @media (prefers-reduced-motion: reduce) {
+ .portfolio-scroll-ready #work-scroller > article {
+ opacity: 1;
+ filter: none;
+ transform: none;
+ }
+
+ #work-scroller > article > a > img,
+ #work-scroller > article > div {
+ transition: none;
+ }
+ }
+
+ </style>
+ <script type="application/ld+json">
+ {
+ "@context": "https://schema.org",
+ "@graph": [
+ {
+ "@type": "Organization",
+ "@id": "https://afterdarklabs.io/#organization",
+ "name": "After Dark Labs",
+ "url": "https://afterdarklabs.io/",
+ "logo": "https://afterdarklabs.io/logo_assets/icon-512.png",
+ "founder": {
+ "@type": "Person",
+ "name": "Harrison Erd",
+ "url": "https://harrisonerd.com/"
+ },
+ "areaServed": {
+ "@type": "Country",
+ "name": "United States"
+ },
+ "description": "After Dark Labs provides South Florida website design and development for custom websites, Shopify stores, mobile apps, SaaS platforms, APIs, AI integrations, branding, hosting, and business tools."
+ },
+ {
+ "@type": "WebSite",
+ "@id": "https://afterdarklabs.io/#website",
+ "url": "https://afterdarklabs.io/",
+ "name": "After Dark Labs",
+ "alternateName": "After Dark Labs Florida",
+ "publisher": {
+ "@id": "https://afterdarklabs.io/#organization"
+ },
+ "description": "After Dark Labs provides website design and development for custom websites, Shopify stores, mobile apps, and business tools."
+ },
+ {
+ "@type": "Service",
+ "@id": "https://afterdarklabs.io/#digital-services",
+ "name": "Website, ecommerce, app, and business software development",
+ "description": "Custom websites, ecommerce stores, mobile apps, SaaS platforms, branding, hosting, APIs, AI chatbots, and intelligent automation.",
+ "provider": {
+ "@id": "https://afterdarklabs.io/#organization"
+ },
+ "areaServed": {
+ "@type": "Country",
+ "name": "United States"
+ },
+ "serviceType": [
+ "Custom website design and development",
+ "Shopify and ecommerce development",
+ "Mobile app development",
+ "Custom platforms, dashboards, and API integrations",
+ "Brand identity and digital marketing",
+ "Hosting and business technology",
+ "AI integrations, chatbots, and intelligent automation"
+ ],
+ "url": "https://afterdarklabs.io/"
+ }
+ ]
+ }
+ </script>
+</head>
+<body class="bg-black text-white overflow-x-hidden">
+ <nav class="fixed top-0 z-50 w-full bg-black/90 backdrop-blur-lg">
+ <div class="mx-auto max-w-7xl px-4 py-4 sm:px-6 lg:py-5">
+ <div class="flex items-center justify-between gap-3 lg:hidden">
+ <a href="#hero" class="nav-brand flex min-w-0 items-center rounded-2xl p-1.5 pr-3 text-left text-white transition-colors hover:bg-white/10 focus:outline-none focus-visible:ring-2 focus-visible:ring-[#ccff00]" aria-label="Go to top">
+ <span class="logo-font block text-2xl font-semibold tracking-tighter">ERD</span>
+ </a>
+ <a href="mailto:[email protected]" class="neon-ink shrink-0 rounded-2xl bg-[#fff] px-4 py-3 text-sm font-semibold transition-colors hover:bg-white">Let's Talk</a>
+ </div>
+
+ <div class="hidden items-center justify-between lg:flex">
+ <a href="#hero" class="nav-brand flex items-center gap-3" aria-label="Go to top">
+ <div>
+ <span class="logo-font block text-2xl font-semibold tracking-tighter">ERD</span>
+ </div>
+ </a>
+ <a href="mailto:[email protected]" class="neon-ink rounded-2xl bg-[#fff] px-6 py-3 font-semibold transition-colors hover:bg-white">Let's Talk</a>
+ </div>
+ </div>
+ </nav>
+
+ <main>
+ <section id="hero" class="hero-bg min-h-screen flex items-center pt-20" style="position:relative; overflow:hidden;">
+ <div class="hero-vignette"></div>
+
+ <div class="hero-content mx-auto grid w-full max-w-7xl justify-items-center gap-10 px-6 py-32 text-center">
+ <div>
+ <h1 class="heading text-7xl font-bold leading-none tracking-tighter md:text-8xl lg:text-7xl xl:text-8xl">
+ ERD
+ </h1>
+ </div>
+ </div>
+
+ </section>
+
+ <section class="work-intro" aria-labelledby="work-heading">
+ <div class="work-intro-stage">
+ <h2 id="work-heading" class="work-heading" aria-label="We build custom websites and apps. Take a look at some of our work.">
+ <span class="work-heading-words" aria-hidden="true">
+ <span class="work-heading-word">We</span>
+ <span class="work-heading-word">build</span>
+ <span class="work-heading-word">custom</span>
+ <span class="work-heading-word">websites</span>
+ <span class="work-heading-word">and</span>
+ <span class="work-heading-word">apps.</span>
+ <span class="work-heading-word">Take</span>
+ <span class="work-heading-word">a</span>
+ <span class="work-heading-word">look</span>
+ <span class="work-heading-word">at</span>
+ <span class="work-heading-word">some</span>
+ <span class="work-heading-word">of</span>
+ <span class="work-heading-word">our</span>
+ <span class="work-heading-word">work.</span>
+ </span>
+ </h2>
+ </div>
+ </section>
+
+ <section id="work" class="scroll-mt-24 border-t border-white/10 bg-black" aria-label="Featured work">
+ <div class="work-stage">
+ <div class="work-stage-content">
+ <div id="work-scroller" class="portfolio-grid">
+ <article class="w-[82vw] shrink-0 snap-start overflow-hidden rounded-3xl bg-zinc-950 sm:w-[28rem] md:w-[38rem]">
+ <a href="https://gardenfreshwholesale.com" target="_blank" rel="noopener noreferrer" class="block w-full overflow-hidden rounded-t-3xl text-left focus:outline-none focus-visible:ring-2 focus-visible:ring-[#ccff00] focus-visible:ring-offset-2 focus-visible:ring-offset-[#17212b]" aria-label="Visit Garden Fresh Wholesale website">
+ <img src="https://afterdarklabs.io/gardenfresh.webp?v=2" width="1200" height="702" loading="lazy" decoding="async" class="aspect-video w-full object-cover" alt="Garden Fresh Wholesale ecommerce web app project by After Dark Labs">
+ </a>
+ <div class="p-6">
+ <p class="text-sm font-medium text-white">
+ <span class="portfolio-description">We built <span class="portfolio-name">Garden Fresh Wholesale</span>'s business website and local SEO strategy that increased customer acquisition by 48% since launch.</span>
+ </p>
+ </div>
+ </article>
+ <article class="w-[82vw] shrink-0 snap-start overflow-hidden rounded-3xl bg-zinc-950 sm:w-[28rem] md:w-[38rem]">
+ <a href="https://miadruck.com" target="_blank" rel="noopener noreferrer" class="block w-full overflow-hidden rounded-t-3xl text-left focus:outline-none focus-visible:ring-2 focus-visible:ring-[#ccff00] focus-visible:ring-offset-2 focus-visible:ring-offset-[#17212b]" aria-label="Visit Mia Druck website">
+ <img src="https://afterdarklabs.io/miadruck.webp?v=3" width="1200" height="681" loading="lazy" decoding="async" class="aspect-video w-full object-cover" alt="Mia Druck real estate website project by After Dark Labs">
+ </a>
+ <div class="p-6">
+ <p class="text-sm font-medium text-white">
+ <span class="portfolio-description"><span class="portfolio-name">Mia Druck</span> needed a real estate website with heavy local SEO and a custom API for the most up-to-date listings and sales. We delivered this custom site in under a week.</span>
+ </p>
+ </div>
+ </article>
+ <article class="w-[82vw] shrink-0 snap-start overflow-hidden rounded-3xl bg-zinc-950 sm:w-[28rem] md:w-[38rem]">
+ <a href="https://coralvibefl.com" target="_blank" rel="noopener noreferrer" class="block w-full overflow-hidden rounded-t-3xl text-left focus:outline-none focus-visible:ring-2 focus-visible:ring-[#ccff00] focus-visible:ring-offset-2 focus-visible:ring-offset-[#17212b]" aria-label="Visit Coral Vibe website">
+ <img src="https://afterdarklabs.io/coralvibe.webp?v=1" width="1200" height="678" loading="lazy" decoding="async" class="aspect-video w-full object-cover" alt="Shopify store for Coral Vibe Florida project by After Dark Labs">
+ </a>
+ <div class="p-6">
+ <p class="text-sm font-medium text-white">
+ <span class="portfolio-description"><span class="portfolio-name">Coral Vibe</span> hired us to design their Shopify store and provide support for ecommerce operations, product management, and social media marketing. Since launch, store visits resulting in sales have increased by 86%.</span>
+ </p>
+ </div>
+ </article>
+ <article class="w-[82vw] shrink-0 snap-start overflow-hidden rounded-3xl bg-zinc-950 sm:w-[28rem] md:w-[38rem]">
+ <a href="https://frontlineboats.com" target="_blank" rel="noopener noreferrer" class="block w-full overflow-hidden rounded-t-3xl text-left focus:outline-none focus-visible:ring-2 focus-visible:ring-[#ccff00] focus-visible:ring-offset-2 focus-visible:ring-offset-[#17212b]" aria-label="Visit Frontline Boat Services website">
+ <img src="https://afterdarklabs.io/frontlineboats.webp?v=1" width="1200" height="700" loading="lazy" decoding="async" class="aspect-video w-full object-cover" alt="Frontline Boat Services marine services website project by After Dark Labs">
+ </a>
+ <div class="p-6">
+ <p class="text-sm font-medium text-white">
+ <span class="portfolio-description">For <span class="portfolio-name">Frontline Boat Services</span>, we built a highly focused business website with local SEO, custom payment links for customers, and an owner-managed photo gallery.</span>
+ </p>
+ </div>
+ </article>
+ <article class="w-[82vw] shrink-0 snap-start overflow-hidden rounded-3xl bg-zinc-950 sm:w-[28rem] md:w-[38rem]">
+ <a href="https://voldservices.com" target="_blank" rel="noopener noreferrer" class="block w-full overflow-hidden rounded-t-3xl text-left focus:outline-none focus-visible:ring-2 focus-visible:ring-[#ccff00] focus-visible:ring-offset-2 focus-visible:ring-offset-[#17212b]" aria-label="Visit Vold Services website">
+ <img src="https://afterdarklabs.io/voldservices.webp" width="1200" height="702" loading="lazy" decoding="async" class="aspect-video w-full object-cover" alt="Vold Services exterior cleaning website with a scroll-animated hero, designed by After Dark Labs">
+ </a>
+ <div class="p-6">
+ <p class="text-sm font-medium text-white">
+ <span class="portfolio-description"><span class="portfolio-name">Vold Services</span> hired us to create their business website with a scroll-animated hero, local SEO/GEO and an owner-managed photo gallery.</span>
+ </p>
+ </div>
+ </article>
+ <article class="w-[82vw] shrink-0 snap-start overflow-hidden rounded-3xl bg-zinc-950 sm:w-[28rem] md:w-[38rem]">
+ <a href="https://vegy.app/" target="_blank" rel="noopener noreferrer" class="block w-full overflow-hidden rounded-t-3xl text-left focus:outline-none focus-visible:ring-2 focus-visible:ring-[#ccff00] focus-visible:ring-offset-2 focus-visible:ring-offset-[#17212b]" aria-label="Visit Vegy website">
+ <img src="https://afterdarklabs.io/vegy.webp?v=1" width="1200" height="702" loading="lazy" decoding="async" class="aspect-video w-full object-cover" alt="Vegy wholesale ordering platform project by After Dark Labs">
+ </a>
+ <div class="p-6">
+ <p class="text-sm font-medium text-white">
+ <span class="portfolio-description">We have partnered with <span class="portfolio-name">Vegy</span> since 2023 to create a white-label web app for wholesale ordering with AI and email integrations, real-time updates, and advanced analytics. The app processed over $2 million in orders in the first year.</span>
+ </p>
+ </div>
+ </article>
+ <article class="w-[82vw] shrink-0 snap-start overflow-hidden rounded-3xl bg-zinc-950 sm:w-[28rem] md:w-[38rem]">
+ <a href="https://prima.vegy.app/" target="_blank" rel="noopener noreferrer" class="block w-full overflow-hidden rounded-t-3xl text-left focus:outline-none focus-visible:ring-2 focus-visible:ring-[#ccff00] focus-visible:ring-offset-2 focus-visible:ring-offset-[#17212b]" aria-label="Visit Prima Produce website">
+ <img src="https://afterdarklabs.io/prima.webp?v=1" width="1200" height="702" loading="lazy" decoding="async" class="aspect-video w-full object-cover" alt="Prima Produce business website project by After Dark Labs">
+ </a>
+ <div class="p-6">
+ <p class="text-sm font-medium text-white">
+ <span class="portfolio-description">Our partner <span class="portfolio-name">Prima Produce</span> hired us to build their business website with custom online ordering and cohesive branding. Working with their existing logo, we created a complete online experience for Prima's customers.</span>
+ </p>
+ </div>
+ </article>
+ <article class="w-[82vw] shrink-0 snap-start overflow-hidden rounded-3xl bg-zinc-950 sm:w-[28rem] md:w-[38rem]">
+ <a href="https://invoiceotter.com" target="_blank" rel="noopener noreferrer" class="block w-full overflow-hidden rounded-t-3xl text-left focus:outline-none focus-visible:ring-2 focus-visible:ring-[#ccff00] focus-visible:ring-offset-2 focus-visible:ring-offset-[#17212b]" aria-label="Visit Invoice Otter website">
+ <img src="https://afterdarklabs.io/invoiceotter.webp?v=1" width="1200" height="673" loading="lazy" decoding="async" class="aspect-video w-full object-cover" alt="Invoice Otter SaaS project by After Dark Labs">
+ </a>
+ <div class="p-6">
+ <p class="text-sm font-medium text-white">
+ <span class="portfolio-description">We built the mobile app, web interface, and the APIs for <span class="portfolio-name">Invoice Otter</span>'s contractor invoicing and estimating solutions with subscriptions, integrated payments, a custom AI chatbot, and per-user customization.</span>
+ </p>
+ </div>
+ </article>
+ </div>
+ </div>
+ </div>
+ </section>
+
+ </main>
+
+ <footer class="border-t border-white/10 bg-black py-16">
+ <div class="mx-auto max-w-7xl px-6 text-center">
+ <a href="#hero" class="mb-6 inline-flex items-center justify-center gap-3">
+ <span class="min-w-0 text-left">
+ <span class="logo-font block text-3xl font-semibold tracking-tighter">ERD</span>
+ </span>
+ </a>
+ <p style="color: #000;">
+ <a href="https://share.google/inOLBEb4neFhKNkWb" target="_blank" rel="noopener noreferrer" class="transition-colors hover:text-[#ccff00]">★★★★★ on Google</a>
+ <br>
+ Let's work together → <a href="mailto:[email protected]" class="transition-colors hover:text-[#ccff00]" style="margin-top:50px;">[email protected]</a>
+ <br><br>
+ © 2026 <a href="https://harrisonerd.com/" target="_blank" rel="noopener noreferrer" class="transition-colors hover:text-[#ccff00]">Harrison Erd</a>
+ </p>
+
+ </div>
+ </footer>
+
+ <script>
+ (function () {
+ const hero = document.getElementById('hero');
+ if (!hero) return;
+
+ const nav = document.querySelector('nav');
+ const mobileLayout = window.matchMedia('(max-width: 767px)');
+ let lockedWidth = 0;
+ let resizeFrame = 0;
+
+ function lockMobileHeroHeight() {
+ resizeFrame = 0;
+
+ if (!mobileLayout.matches) {
+ hero.style.removeProperty('--mobile-hero-height');
+ hero.style.removeProperty('--mobile-nav-height');
+ lockedWidth = 0;
+ return;
+ }
+
+ const navHeight = Math.round(nav?.getBoundingClientRect().height || 0);
+ if (navHeight) hero.style.setProperty('--mobile-nav-height', `${navHeight}px`);
+
+ const layoutWidth = Math.round(document.documentElement.clientWidth);
+ if (Math.abs(layoutWidth - lockedWidth) < 2) return;
+
+ const visibleHeight = Math.round(window.visualViewport?.height || window.innerHeight);
+ if (!visibleHeight) return;
+
+ lockedWidth = layoutWidth;
+ hero.style.setProperty('--mobile-hero-height', `${visibleHeight}px`);
+ }
+
+ function scheduleHeroHeightLock() {
+ if (!resizeFrame) resizeFrame = window.requestAnimationFrame(lockMobileHeroHeight);
+ }
+
+ window.addEventListener('resize', scheduleHeroHeightLock);
+ window.visualViewport?.addEventListener('resize', scheduleHeroHeightLock);
+ mobileLayout.addEventListener?.('change', scheduleHeroHeightLock);
+ lockMobileHeroHeight();
+ })();
+
+ (function () {
+ const hero = document.getElementById('hero');
+ const nav = document.querySelector('nav');
+ const brands = Array.from(document.querySelectorAll('.nav-brand'));
+ if (!hero || !nav || !brands.length) return;
+
+ let updateFrame = 0;
+ let brandIsVisible = null;
+
+ function updateNavBrand() {
+ updateFrame = 0;
+ const revealBrand = hero.getBoundingClientRect().bottom <= nav.getBoundingClientRect().bottom + 1;
+ if (revealBrand === brandIsVisible) return;
+
+ brandIsVisible = revealBrand;
+ brands.forEach(brand => brand.classList.toggle('is-visible', revealBrand));
+ }
+
+ function scheduleNavBrandUpdate() {
+ if (!updateFrame) updateFrame = window.requestAnimationFrame(updateNavBrand);
+ }
+
+ document.documentElement.classList.add('nav-brand-ready');
+ window.addEventListener('scroll', scheduleNavBrandUpdate, { passive: true });
+ window.addEventListener('resize', scheduleNavBrandUpdate);
+ window.addEventListener('pageshow', scheduleNavBrandUpdate);
+ updateNavBrand();
+ })();
+
+ (function () {
+ const intro = document.querySelector('.work-intro');
+ const stage = intro?.querySelector('.work-intro-stage');
+ const words = Array.from(intro?.querySelectorAll('.work-heading-word') || []);
+ if (!intro || !stage || !words.length) return;
+
+ const nav = document.querySelector('nav');
+ const reduceMotion = window.matchMedia('(prefers-reduced-motion: reduce)');
+ let revealStart = 0;
+ let revealDistance = 1;
+ let revealedWords = -1;
+ let updateFrame = 0;
+ let resizeFrame = 0;
+
+ function updateWorkIntro() {
+ updateFrame = 0;
+
+ if (reduceMotion.matches) {
+ words.forEach(word => word.classList.add('is-revealed'));
+ revealedWords = words.length;
+ return;
+ }
+
+ const progress = Math.min(1, Math.max(0, (window.scrollY - revealStart) / revealDistance));
+ const nextRevealedWords = Math.ceil(progress * words.length);
+ if (nextRevealedWords === revealedWords) return;
+
+ revealedWords = nextRevealedWords;
+ words.forEach((word, index) => {
+ word.classList.toggle('is-revealed', index < revealedWords);
+ });
+ }
+
+ function measureWorkIntro() {
+ resizeFrame = 0;
+ intro.classList.toggle('is-scroll-ready', !reduceMotion.matches);
+
+ const introTop = intro.getBoundingClientRect().top + window.scrollY;
+ const navHeight = nav?.getBoundingClientRect().height || 0;
+ const viewportHeight = window.visualViewport?.height || window.innerHeight;
+ const stickyTravel = Math.max(0, intro.offsetHeight - stage.offsetHeight);
+ const revealEnd = introTop - navHeight + stickyTravel;
+
+ revealStart = introTop - Math.max(1, viewportHeight - navHeight);
+ revealDistance = Math.max(1, revealEnd - revealStart);
+ revealedWords = -1;
+ updateWorkIntro();
+ }
+
+ function scheduleWorkIntroUpdate() {
+ if (!updateFrame) updateFrame = window.requestAnimationFrame(updateWorkIntro);
+ }
+
+ function scheduleWorkIntroMeasure() {
+ if (!resizeFrame) resizeFrame = window.requestAnimationFrame(measureWorkIntro);
+ }
+
+ window.addEventListener('scroll', scheduleWorkIntroUpdate, { passive: true });
+ window.addEventListener('resize', scheduleWorkIntroMeasure);
+ window.addEventListener('pageshow', scheduleWorkIntroMeasure);
+ reduceMotion.addEventListener('change', scheduleWorkIntroMeasure);
+ document.fonts?.ready.then(scheduleWorkIntroMeasure);
+ measureWorkIntro();
+ })();
+
+ (function () {
+ const section = document.getElementById('work');
+ const cards = Array.from(section?.querySelectorAll('#work-scroller > article') || []);
+ if (!cards.length) return;
+
+ const reduceMotion = window.matchMedia('(prefers-reduced-motion: reduce)');
+ const touchLayout = window.matchMedia('(hover: none), (pointer: coarse)');
+ let cardTops = [];
+ let updateFrame = 0;
+ let resizeFrame = 0;
+
+ function clamp(value, minimum = 0, maximum = 1) {
+ return Math.min(maximum, Math.max(minimum, value));
+ }
+
+ function getDocumentTop(element) {
+ let top = 0;
+ let current = element;
+
+ while (current) {
+ top += current.offsetTop;
+ current = current.offsetParent;
+ }
+
+ return top;
+ }
+
+ function fitDescriptions() {
+ cards.forEach(card => {
+ const panel = card.querySelector(':scope > div');
+ const copy = panel?.querySelector('p');
+ if (!panel || !copy) return;
+
+ const panelStyle = window.getComputedStyle(panel);
+ const horizontalPadding = parseFloat(panelStyle.paddingLeft) + parseFloat(panelStyle.paddingRight);
+ const verticalPadding = parseFloat(panelStyle.paddingTop) + parseFloat(panelStyle.paddingBottom);
+ const availableWidth = Math.max(1, panel.clientWidth - horizontalPadding);
+ const availableHeight = Math.max(1, panel.clientHeight - verticalPadding);
+ let minimum = 12;
+ let maximum = Math.min(88, Math.max(34, card.clientWidth / 7.2));
+
+ for (let iteration = 0; iteration < 10; iteration += 1) {
+ const size = (minimum + maximum) / 2;
+ copy.style.fontSize = `${size}px`;
+
+ if (copy.scrollHeight <= availableHeight + 1 && copy.scrollWidth <= availableWidth + 1) {
+ minimum = size;
+ } else {
+ maximum = size;
+ }
+ }
+
+ copy.style.fontSize = `${Math.floor(minimum * 10) / 10}px`;
+ });
+ }
+
+ function updateCards() {
+ updateFrame = 0;
+ if (reduceMotion.matches) return;
+
+ const viewportHeight = window.visualViewport?.height || window.innerHeight;
+ const revealDistance = Math.max(240, viewportHeight * 0.58);
+ const travelX = Math.min(72, window.innerWidth * 0.06);
+
+ cards.forEach((card, index) => {
+ const progress = clamp((window.scrollY + viewportHeight * 0.94 - cardTops[index]) / revealDistance);
+ const eased = 1 - Math.pow(1 - progress, 3);
+ const remaining = 1 - eased;
+ const direction = index % 2 === 0 ? -1 : 1;
+ const wave = Math.sin(progress * Math.PI * 3) * remaining;
+ const x = direction * (remaining * travelX + wave * 20);
+ const y = remaining * 96 - Math.sin(progress * Math.PI) * 10;
+ const rotation = direction * (remaining * 5 + wave * 2.4);
+ const skew = direction * wave * 1.6;
+ const scaleX = 1 - remaining * 0.07 + Math.abs(wave) * 0.025;
+ const scaleY = 1 + remaining * 0.065 - wave * 0.02;
+ const opacity = clamp(progress * 1.65);
+ const blur = remaining * 7;
+
+ card.style.setProperty('--card-x', `${x.toFixed(2)}px`);
+ card.style.setProperty('--card-y', `${y.toFixed(2)}px`);
+ card.style.setProperty('--card-rotate', `${rotation.toFixed(2)}deg`);
+ card.style.setProperty('--card-skew', `${skew.toFixed(2)}deg`);
+ card.style.setProperty('--card-scale-x', scaleX.toFixed(4));
+ card.style.setProperty('--card-scale-y', scaleY.toFixed(4));
+ card.style.setProperty('--card-opacity', opacity.toFixed(4));
+ card.style.setProperty('--card-blur', `${blur.toFixed(2)}px`);
+ });
+ }
+
+ function measureCards() {
+ resizeFrame = 0;
+ cardTops = cards.map(getDocumentTop);
+ fitDescriptions();
+ updateCards();
+ }
+
+ function scheduleCardUpdate() {
+ if (!updateFrame) updateFrame = window.requestAnimationFrame(updateCards);
+ }
+
+ function scheduleCardMeasure() {
+ if (!resizeFrame) resizeFrame = window.requestAnimationFrame(measureCards);
+ }
+
+ cards.forEach(card => {
+ const link = card.querySelector(':scope > a');
+ link?.addEventListener('click', event => {
+ if (!touchLayout.matches || card.classList.contains('is-description-visible')) return;
+
+ event.preventDefault();
+ cards.forEach(otherCard => otherCard.classList.remove('is-description-visible'));
+ card.classList.add('is-description-visible');
+ });
+ });
+
+ document.addEventListener('pointerdown', event => {
+ if (!touchLayout.matches || event.target.closest('#work-scroller > article')) return;
+ cards.forEach(card => card.classList.remove('is-description-visible'));
+ }, { passive: true });
+
+ section.classList.add('portfolio-scroll-ready');
+ window.addEventListener('scroll', scheduleCardUpdate, { passive: true });
+ window.addEventListener('resize', scheduleCardMeasure);
+ window.visualViewport?.addEventListener('resize', scheduleCardMeasure);
+ window.addEventListener('pageshow', scheduleCardMeasure);
+ reduceMotion.addEventListener('change', scheduleCardMeasure);
+ document.fonts?.ready.then(scheduleCardMeasure);
+ measureCards();
+ })();
+
+ </script>
+</body>
+</html>