Changelog

What's been cracking at the lab, written up proper.

RSS feed

A Cleaner Wordmark, t'Desk Mouse Finally Sits Right, an' a Recipe for Next Time

Bit of a visual tidy-up day. T'big colourful "humbleha.us" logo up top got swapped for a fresh one — same neon look, but wi' cleaner edges. T'old one had a couple o' letters, t'b an' t'e, that looked a touch mucky against both t'light an' t'dark backgrounds; t'new one reads crisp either way. Shrunk t'file it ships as an' all, so it lands a bit quicker.

While t'bonnet were up, sorted t'faint mouse graphic that sits behind t'"about" blurb. It were floatin' in t'middle wi' a daft gap down t'right an' not quite reachin' t'top an' bottom. Now it hugs t'right edge proper an' fills t'card top to bottom, edge to edge. Also caught a wee flicker where it'd load lined up nice then jump back a beat later — two stylesheets were disagreein' wi' each other; got 'em singin' t'same tune.

Last job were writin' t'whole logo-swap down as a one-command recipe, so next time's a five-minute job 'stead o' an afternoon o' faffin'. There's a plan brewin' to rotate through a whole set o' logos like we already do wi' t'hero videos — that's one for another day.

  • Fresh hero wordmark — new transparent logo image, crisp on both t'light an' t'dark themes where t'old one looked mucky on one o' t'two. Four sizes still ship behind t'responsive picker, an' t'main format's actually lighter than before, so it lands quicker.
  • T'about-card mouse sits proper now — t'faint circuit-mouse behind t'blurb used to float wi' a gap down t'right; now it hugs t'right edge an' fills t'card top to bottom.
  • Load-time flicker gone — t'mouse used to load lined up right then snap back a beat later, 'cause two stylesheets held different instructions for it. Both agree now, so it's steady from t'first paint.
  • Logo swaps are a one-command job now — wrote t'whole process down as a reusable recipe: resize t'image to t'right set o' sizes, keep it sharp, check it reads clean on both themes, an' make sure nowt shifts about or slows t'page down. Groundwork for rotatin' through a set o' logos down t'line.
  • Page speed held steady — homepage stayed up in t'high 90s on mobile through t'lot, wi' nowt jumpin' about on load.

Deploy Pipe Cut in Half, an' 81 Robots Give t'Place a Proper Goin' Over

Housekeepin' day, but t'satisfyin' kind. Started by sweepin' up t'last few cobwebs from t'weekend's spring clean — a couple o' dead references in t'build config that pointed at files long gone, an' a stale copy o' t'site config that had no business sittin' where t'public could fetch it. Both sorted an' shipped.

Then t'deploy script got a right seein' to. Every deploy runs a full quality gate — Lighthouse checks on six pages, a dependency vulnerability scan, t'lot — an' it were all runnin' one thing after another like a queue at t'post office. Now t'slow bits run side by side, nowt got removed, an' a full deploy dropped from just under two minutes to about 44 seconds. Finished up by settin' 81 wee review agents loose on t'whole codebase — each findin' had to survive three sceptics tryin' to knock it down before it counted. Twenty survived, fifteen got fixed an' shipped t'same evening.

  • Deploys are 2× faster wi' nowt removed — t'six Lighthouse page checks now run three at a time 'stead o' single file, t'build generators fan out in parallel waves, an' t'dependency scan only re-runs when t'dependencies actually change (or a week passes, whichever's first). Every stage prints its own timin' now, so if t'pipe ever gets slow again we'll see exactly where.
  • Flaky test scores stopped cryin' wolf — Lighthouse single runs wobble by a few points, an' twice today a perfectly healthy homepage scored one point under t'bar an' failed an otherwise clean deploy. Now a failin' page gets one calm re-measure before t'gate makes its mind up. A real regression still fails both runs.
  • T'build can't ship a half-done site anymore — if any o' t'generators that stitch t'homepage together falls over partway, t'deploy now stops dead 'stead o' carryin' on an' quietly publishin' a mismatched build. That exact failure shape bit us back in May; door's shut on it now.
  • A frozen stat unfroze — t'homepage "tools" stat card had been quietly showin' t'same blurb since a refactor weeks back, 'cause t'script that writes it were readin' from a spot that no longer existed. Points at t'proper source now.
  • RSS feeds made properly robust — titles an' tags get escaped correctly now, so a future experiment named wi' an ampersand won't break t'feed for every reader. Feed entry ids also stay stable when two entries land on t'same day, so nobody's reader shows 'em summat as "new" that they've already read.
  • Security tightenin' across t'board — one public API now checks its input proper before spendin' quota on it, error replies stopped echoin' internal details back to whoever asked, a full set o' security headers went on t'remainin' API responses that lacked 'em, an' t'admin panel got stricter about escapin' owt it renders. None of it were bein' exploited — t'robots just found t'gaps before anyone else did.
  • Motion-sensitive visitors properly served — t'rule that switches animations off for folk who've asked their device for reduced motion had an invalid value in it, so browsers were binnin' it silently. Fixed; animations now genuinely stand still when asked.

TimeBlocks Lands, t'Hero Lights Up, an' t'Donations Stop Their Flashin'

Right marathon of a day. Started off addin' a new placeholder card for an app called TimeBlocks — a daily plan in 30-minute blocks, 5am to midnight, top-three priorities an' a notes square. Then t'homepage got two proper polish jobs: a fresh neon "humbleha.us" wordmark image swapped in where t'plain text used to be, an' t'apps row started behavin' like t'experiments row — newest card top-left, wi' a subtle orange glow round it.

Then things went sideways for a stretch. T'wee bit o' code that stamps t'live donation total into t'homepage at build time were quietly corruptin' t'layout — broke t'whole bento grid, stat cards squished into a column, hero card vanishin'. Took a couple o' reverts an' some head-scratchin' before t'real culprit were found an' put right. Spent t'rest o' t'evening makin' sure it can't happen again — added a markup checker to t'deploy pipeline, wrote down how t'homepage is meant to look an' how to recover it, an' shipped a one-command rollback script. Then re-architected t'donation card itself so it never flashes "$90 → live total" again for anyone wi' a return visit.

  • TimeBlocks app card on t'homepage — new entry in t'apps row, top-left, marked as an idea (not yet live). It's a digital version of t'paper time-block planner that lives on my desk — date, top three, notes, an' a half-hourly grid from 5am all t'way to midnight. Web version stays free; a native desktop version is planned for Gumroad.
  • Neon wordmark in t'hero — t'big "humbleha.us" text on t'homepage card is now a proper colourful logo image. Four sizes ship behind a responsive picker so phones grab a smaller variant an' big screens get t'sharp one. Alt text keeps t'SEO honest.
  • Apps row behaves like t'experiments row now — newest app sorts to t'top-left automatically, an' it gets t'same gentle orange pulse round it that t'newest experiment card has had for weeks. Same effect, same animation, same code path. Two birds, one stone.
  • Addin' a new app is one-file again — t'list o' apps an' t'list o' experiments now propagate from a single source o' truth on every deploy. Used to be that apps needed editin' in two places an' it bit us tonight when t'newest one forgot to appear. Sorted.
  • Donation card no longer flashes — used to load t'page wi' "$90" plain as day, then a beat later it'd jump to t'actual total. Daft, lookin' back. Now t'value is set inline durin' page parse, usin' whatever last-known total t'browser already has cached. Return visitors see t'right number from t'first paint. Brand-new visitors see a faint "$··" skeleton for a beat before t'live number lands.
  • Build pipeline grew a markup checker — before every deploy, t'script now sweeps t'homepage HTML for duplicate ids, mismatched open/close tags, an' a few other shapes that have actually shipped to prod an' caused mischief in t'past. Would've stopped tonight's slip cold. Fails fast wi' a clear reason if owt's amiss.
  • Layout guide written down — there's a new internal note that captures how t'homepage is meant to be laid out, t'order o' sections, which CSS rules are load-bearin', an' t'order o' things to try if it ever breaks in prod again. Future-me will thank present-me.
  • One-command rollback — new script that flips production back to t'most recent known-good deploy in one go. No git fiddlin', no manual file copyin'. Lists t'recent deploys, asks you to confirm, an' restores. Saved for when t'eyes are tired an' summat's gone off.

Switched Analytics, Sharpened t'Homepage, Got Back to Top Marks

Right marathon day. Started off tryin' a new lightweight analytics provider 'stead o' Plausible — got t'whole site wired up to it before realisin' our account weren't configured right on their end, so it's quietly off again. After that, turned attention to t'homepage Lighthouse scores, did a round o' tidy-up cheap wins an' got mobile back from a wobbly 86 to a tidy 97. Desktop's near-100 across perf, a11y an' SEO, wi' best-practices snappin' back to a full 100 once t'broken analytics were silenced. JS minification got added to t'deploy pipeline along t'way for nowt extra.

  • New analytics tried, an' it's off again — swapped Plausible (which we'd never actually paid for an' were silently recordin' nowt) for a lighter-weight provider, intendin' to finally start measurin' summat. Turned out t'new one needed dashboard config on their end before it'd accept events — every pageview came back wi' a "not allowed" reply. Same blank end as Plausible, just a fresh wrapper. Tags are commented out everywhere wi' a dated note so we can flick 'em back on once t'account side is sorted.
  • JS minification on every deploy — t'deploy script now squashes all t'JavaScript files before they ship. About 25% off t'shipped bytes per file (around 69 KB saved on a typical deploy). Mirrors what t'CSS minify step's been doin' for weeks.
  • Mouse icon went on a diet — t'little mouse in t'nav corner were 41 KB, drawn at 1024-by-1024 detail for summat displayed at 24 pixels. Squashed down to 18 KB wi' no visible difference at t'actual size.
  • Hero photo now serves smaller on mobile — t'background portrait on t'homepage hero card were 66 KB for everyone. Now there's a 28 KB mobile variant that phones grab instead. Browser picks t'right one based on viewport size.
  • Smarter cache rules for t'JavaScript — stable files (sponsored banner, slider, donate block) cache for a year. Main homepage script caches for an hour 'cause it carries t'experiments catalogue, an' new experiments need to show up sharpish for repeat visitors.
  • An obscure pre-deploy bug sorted — t'helper that maintains t'site security policy were misreadin' a script tag if its attributes appeared in a particular order, which had been quietly causin' day-on-day score flakes. Caught an' fixed.
  • Homepage scores back where they belong — mobile Lighthouse jumped from 86 → 97 wi' t'cheap-wins bundle. Desktop reportin' close-to-100 across perf, a11y an' SEO, an' best-practices is back to a full 100 wi' t'broken analytics silenced.

VibeRollol Lands, Deploy Pipe Gets a Right Seein' To

Right shop day — t'thermal printer app got rebranded properly, an' t'deploy pipeline picked itself up after four quiet days of changes that hadn't actually gone anywhere. Two bits o' housekeeping masqueradin' as a quick afternoon, but t'tools are sharper for it.

  • "Roll With It" is now VibeRollol — same daft app for printin' receipts, lists, doodles an' tiny art to a thermal printer, fresh name on t'card. Same tagline: print summat satisfyin', useful, daft.
  • Deploys are back to liftin' off cleanly — turned out near a fortnight's worth o' code changes had been queued up wi' nothin' goin' live, 'cause t'deploy script were quietly chokin' on a tool change we'd not spotted. Sorted. While we were in there, added some up-front checks so t'script catches t'common reasons a deploy fails (no internet, not logged in) before it wastes ten minutes climbin' uphill for nowt. An' if t'final upload hiccups on a flaky connection, t'script now waits an' retries 'stead o' just dyin' at first stumble.

Brief Lands, Ribbons On, Token Calc Sharpens Up

Big shop day — morning Discord brief shipped, MRR ribbons added to t'app cards, daily PSI now smooths its own noise wi' median-of-three samplin', an' a fat unsubset font got swapped out an' bumped AI Token Calc straight back to its proper score. Calmer dashboard an' tighter build gates t'boot.

  • Morning brief in Discord — fires every day at 09:00 EDT wi' five sections: PageSpeed scores (median + any real regressions), donation total + last-24h delta + recent donors, top affiliate clicks last 24h, Replicate spend month-to-date, an' a security gate status. One tidy embed 'stead o' three open tabs first thing.
  • MRR ribbons on t'app cards — corner overlay shows monthly revenue. Orange when earnin', muted dim grey at $00 so revenue-earnin' apps pop in t'grid. Compact format ready for big numbers ($1.2k, $12k, $1.5m) once we get there.
  • Donations card upgraded — recent donors row 'stead o' static blurb ("Anonymous ($3) — thank you for all the help & donations!"). No more $90 → $93 flash on page load either — caches t'last known total in t'browser, an' patches t'page seed at deploy time so first-time visitors see t'current number straight off.
  • Daily PSI now median-of-three on regressions — when a URL scores below threshold in t'initial run, t'cron fires two more samples for just that one an' uses t'median. Kills t'daily false-positive cycle where Lighthouse jitter (±5-10 points is normal) was triggerin' phantom alerts.
  • Perf dashboard calmer — Lighthouse infrastructure errors (timeouts, internal 500s) no longer scream red on cards. Strategies that didn't get measured today fall back to t'most recent good score wi' a small "cached" tag, so t'grid is never empty. Cache window tightened 5 min → 60s so force-runs show up quicker.
  • AI Token Calc back to proper scores (perf 87 → 95) — root cause were a 230 KB unsubset Inter font blockin' t'critical render path. Swapped to t'48 KB subset, font load time dropped 200ms+, LCP halved. The 830-line inline script were also moved out to its own file so HTML parsin' isn't blocked while t'calculator boots.
  • Build pipeline tightened — best-practices added to t'local Lighthouse gate alongside a11y + perf (catches CSP/console-error regressions before PSI does). Font-size gate fails t'deploy if any font asset is over 80 KB. Inline-block hashes auto-recompute now so editin' an inline style never silently breaks t'security policy. Three latent build scripts that were silently failin' for a month also tracked down an' fixed.
  • Experiment scaffolder — single command spins up a new placeholder experiment in seconds wi' all t'standards baked in (nav, sponsored banner placeholder, donate block, dark mode, mobile breakpoints). Idea-to-card in under a minute when summat new strikes.
  • Daily security probe — automated check that prods t'auth gates we rely on (admin endpoints, webhook tokens) an' alerts only when summat's drifted. Silent when all's well.
  • Donate links now tagged per page — every Ko-fi donate link across t'site carries a small page identifier in t'URL so we can attribute donations to t'experiment that sent 'em (once we verify Ko-fi passes that tag through). Sets up live per-experiment MRR on t'ribbons later.

Marathon Day — PageSpeed Dashboard, YouTube In t'Slider, an' Homepage Scripts Locked Down

Bumper Sunday — three sessions back to back. Built t'eye that watches everythin', bolted YouTube onto t'realtime slider, then locked t'homepage scripts down tight. Phase C (admin-tools CSP) queued for tomorrow.

  • PageSpeed Dashboard live at /experiments/perf-dashboard/ — colour-coded card grid, "show only failin'" toggle, deep-links to PSI reports. Mobile perf 60 → 100 after skeleton cards paint immediately for stable LCP
  • Daily PSI cron — hits Google PageSpeed Insights at 08:00 UTC, stores t'last 30 days, posts a tidy Discord summary
  • Perf budget gate added to deploy.sh alongside t'existin' a11y one — Lighthouse runs once per URL, both categories at once, fails t'deploy if perf drops below 90 mobile
  • YouTube embed in t'slider — server-side key (never touches t'browser), 30 min CDN cache, fetches on first slider-open so homepage perf pays nowt
  • Facade pattern — thumbnail first, click loads t'iframe. Workaround for older videos: maxresdefault.jpg 404s wi' image/jpeg content-type so onerror never fires (load hqdefault.jpg first, probe maxres in background, swap if real)
  • Slider rewritten to apply styles via Constructable Stylesheets — keeps t'Shadow DOM CSP-clean. Burger icon now on t'pull-tab instead o' "realtime" text — fits mobile dead-centre wi'out wrappin'
  • Homepage CSP tightened — inline JS externalized, anti-flash script hashed, inline handlers refactored to delegated listeners. Side effect: mobile perf 93 → 94 'cause externalized JS stopped blockin' FCP
  • CORS lockdown on t'YouTube edge fn — site-origin only now
  • Ko-fi webhook token comparison made timing-safe so response timing can't leak guess progress
  • Edge fn security headers — t'standard hardened header set now applies to edge responses (they don't inherit from t'static site config by default)
  • CSS extracted from inline to an external stylesheet (year-long immutable cache, preloaded early in <head>) — mobile perf 92 → 99
  • YT Climate Calc CLS sorted wi' a server-side sponsored-banner placeholder reservin' 50px o' vertical space; mobile perf 77 → 95+
  • "More Experiments" block now expands to match t'host container's width instead o' bein' capped narrow — perf-dashboard gets a tidy 3-across layout 'stead o' an awkward "2 on a row, 1 alone" wrap. Card cap bumped so wider layouts fill a second row too
  • CLAUDE.md standards expanded — perf budget section, CSS strategy (inline by default, extract when shared or > ~15KB, always preload extracted stylesheets), CSP per-route summary

Bumper Mornin' — Hardenin', Seven New Cards, Auto Blurbs an' a Glow Fix

Big run before lunch — three security fixes off t'back o' yesterday's audit, seven new project cards (three experiments + four apps), an auto-blurb pipeline for t'stat cards, an' a hover-glow regression squashed. PSI ended up at mobile 97/100/100/100, desktop 100/100/100/100; "fast 100s" rule saved as a memory bar for future homepage work.

  • Dark-mode contrast fix--accent-text bumped from #f06535 to #ff8a50 in both dark-mode blocks; .tool-category / .sponsored-visit / .app-visit-link all clear WCAG AA now
  • Penny Oracle placeholder/experiments/penny-oracle/ 404 fixed wi' a noindex-follow placeholder page, standard template (nav + sponsored + Ko-fi)
  • Ko-fi webhook replay prevention — request IDs cached so re-delivery of t'same notification can't inflate t'running donation total; legit retries still get a 200 OK so Ko-fi stops resendin'
  • Three new experiment cards — MiniMax Music 2.6 (008), OBS Effects (009), Streamer Start (010); placeholder landin' pages, SVG thumbs, all status: 'wip'
  • Four new app cards — Notary, VibeRollol, Gumroad Shipper, Codapanion; placeholder pages at /apps/{slug}/, SVG thumbs in /thumbs/apps/
  • WIP cards visible an' clickable — lifted t'status === 'live' filter in sync-catalogue.mjs for visible-non-archived; threaded newest-card class through t'wip branch so glow attaches correctly
  • App fallback SVG supportrenderAppCard now reads app.fallbackSVG as a third step in t'image fallback chain (AI image → static SVG → letter)
  • App thumbnail generatorscripts/generate-app-thumbnails.mjs, reuses t'experiment palette logic but writes to /public/thumbs/apps/{slug}.svg
  • Auto-generated stat-card blurbsscripts/generate-blurbs.mjs runs on every deploy; diff-based framin' for experiments/apps, top-5 SUGGESTED_TOOLS for tools, static thanks for donations; idempotent via _meta stashed in t'output file
  • humble-health an' humble-focus dropped — design padding cards, never went anywhere; APPS down to 5 (humbleha.us + 4 new)
  • Newest-card glow regression fixedrenderProjectCard wip branch now threads isNewest into class string
  • Apps idea-status hover glow — added orange (#e8531a/#f06535) border-top-color for data-status="idea"; every app card now glows on hover
  • Ultraprintify (sixth app) — Astro + Printful t'shirt shop, intended to be t'fastest-loadin' Shopify alternative; placeholder live at /apps/ultraprintify/
  • Lighthouse confirmed — desktop 100/100/100/100 (LCP 0.5s / TBT 0ms / CLS 0.032); mobile 97/100/100/100 wi' LCP 2.0s / TBT 40ms; "fast 100s" rule saved as memory for future homepage work

Long Day at t'Lab — Donations Get Live, Hero Gets Movin', Site Gets Tested

Right proper marathon. Donation counter went live wi' confetti milestones, sponsored + "More Experiments" rows became shared modules across every experiment, ran a four-agent a11y audit (with t'fixes baked into deploy.sh as a hard gate), hero photo got its video treatment wi' hot-link protection, an' dropped in t'overlay-slider component that'll grow into a proper life-dashboard. Six commits, no regressions.

  • Real-time donation counter — Ko-fi webhook persists totals server-side; frontend polls every 30s, visibility-aware. Stale-while-revalidate caching means Reddit-scale traffic only hits origin a few times per minute
  • Milestone confetti — fires on crossin' [500, 1000, 1500, 2000, 2500, 5000] OR any single donation ≥ $25. Self-hosted canvas-confetti lazy-loaded; reduced-motion gets a CSS pulse
  • Admin Donations tab — preset bumps + manual set behind admin auth; lets me test t'celebration pipeline without waitin' on a real donor
  • Sponsored row smoother — blur + asymmetric easing in/out (550ms emphasized + 600ms exponential ease-out); pause button preserved exactly as it were
  • Shared /sponsored.js module — same rotator on every experiment now; site-themed via CSS custom properties; ad-blocker-resistant class names (hls-sponsored__*)
  • Universal "More Experiments" block/more-experiments.js reads /experiments.json generated from catalogue; appears on every experiment, filters out t'current page, sorts by date desc; smart enough to know when summat's been removed
  • A11y audit + 4 fix batches — 14 blockers / 18 fix-this / 11 nice-to-have, all landed; ~5KB dead code stripped; full doc at docs/audits/2026-05-06-a11y-ui-audit.md
  • Accessibility gate in deploy.sh — runs Lighthouse on homepage + 4 experiments after every prod deploy; min score 95 enforced; --skip-a11y escape hatch
  • Hero video live — v1 + v2 random per-load (effective A/B); 600×600 all-keyframe encode; hover continuous-shuttle; idle full forward+reverse every 30s–3min; reduced-motion does native play/pause only
  • Hero hot-link / cost protection — third-party embeds blocked at t'edge, per-IP rate limit applied, immutable cache so t'CDN handles repeat fetches without invokin' t'function; mobile/save-data/no-hover skip removes t'<video> element entirely
  • Overlay slider integrated — Web Component, top-edge "realtime" pull-tab, site-themed; small upstream-safe patch so dialog gets t'host's aria-label
  • 003 ai-token-calculator restored — were renderin' blank from a leftover ${'${buildAffiliateBlock()}'} call after Batch 4 cleanup; one-line fix
  • health-at-53 empty space gone + hardcoded "More Experiments" block (which still pointed to a dead 002-alt SvelteKit version) replaced wi' t'shared module
  • No-JS graceful fallback — pre-seeded counts; <noscript> hides t'JS-rendered sections and shows a static catalogue card wi' all six experiments + RSS / Ko-fi links
  • Slider colour revert — back to dark pill / white text default; flips to orange-with-dark-text when t'panel's open ([open] reflected attribute)

Big One — Site Back Up, Penny Oracle Lands, Sponsored Row Stops Hidin'

Started t'day wi' t'production site half-broken (a botched edge-function commit had ripped @netlify/blobs imports out o' four functions on t'mistaken belief getStore were a runtime global — it isn't). Got everythin' back up, shipped a new experiment (Penny Oracle, renamed from Zoltar Redux after a USPTO check), tidied t'homepage apps row, sorted t'sponsored crossfade so ad blockers can't kill it, an' stubbed a hover-scrubbed hero video.

  • Production restored — blob-storage imports put back in four edge functions that'd been broken by a bad assumption about t'runtime; homepage thumbs, admin login an' OG cards all back up
  • New experiment 007 — Penny Oracle — digital fortune-teller, registered in catalogue, deployed live; renamed from Zoltar Redux after USPTO check showed t'ZOLTAR mark is actively held by Characters Unlimited Inc.
  • Apps section refactor — desktop now a three-column CSS grid (was a 340px-card horizontal scroll), mobile collapses to one full-width column at ≤720px; fixed dead #apps selector typo that'd left mobile cards stuck at 290px
  • Hero subtitle wraps onto two lines so it stops overlappin' t'photo on narrow viewports
  • Sponsored crossfade — eight-second rotation through all twenty-four affiliates in shuffled order, 400ms opacity fade, with a pause button for WCAG 2.2.2 compliance
  • Carousel arrows auto-hide when content isn't scrollable — no more orphan buttons pointin' at nowt
  • Ad-blocker bypass — every affiliate-* class and affiliateX ID renamed to sponsored-*; sponsored row now renders for users on uBlock and similar
  • Rotation works with reduced motion — used to short-circuit entirely; now still rotates, just skips t'fade transition
  • Touch-friendly pause logicmouseenter/focusin pause listeners now only attach on hover-capable devices, so a single tap doesn't freeze t'rotation forever
  • Sponsored populates synchronously — moved out of requestIdleCallback so t'row never renders blank during page load
  • Hero video stub — drop /public/hero-video.webm (ideally encoded -g 1 for clean reverse) to activate hover-scrubbed background video; JS handles speed-ramp on hover, rewind on leave, and random idle play cycles
  • Lighthouse NO_LCP fix — hero h1 font-size bumped so mobile actually has an LCP candidate to measure

Older entries live in the monthly archive above.