Unify scroll reveals, hero entrance, nav active-underline, button springs,
the scroll-progress bar and backdrop parallax under one Motion system
(src/scripts/anim.ts), bundled into a self-hosted /_astro module so CSP
script-src 'self' holds. Progress bar + parallax now scroll()-driven and
cross-browser (was Chromium-only animation-timeline). Fail-open, reduced-motion
aware, content fully visible with JS off.
The tab logo and social preview were still on the old teal palette. Retone both
to the electric cyan→magenta theme matching the hero nameplate:
- favicon.svg: jw monogram + prompt-line + cursor on a cyan→magenta gradient.
- og.png (gen-og.mjs): name in the cyan→violet→magenta hero gradient, cyan
eyebrow/separators, magenta URL, cyan→magenta top bar + dual corner glows.
- bump ?v=2 on both refs (public/ assets are CF-edge-cached + social platforms
cache OG hard) so the new art shows immediately.
The hero name was a mostly---text gradient with a thin accent sweep; in light
mode it rested on low-contrast tones and the body text-halo washed it to a ghost.
Replace with a full cyan→violet→magenta fill driven by the theme-aware accent
tokens (deep on light, bright on dark) so it's unmissable in either mode, plus a
tight dark edge-shadow for legibility, the electric glow, and a one-shot light
sheen that parks off-screen. Opt the title out of the light text-halo.
Light mode: revert the heavy white-out scrim back to a moderate wash so the
board stays visible, and earn legibility with a soft light text-halo behind
running text instead (invisible on the solid cards, only works over the image).
Pairs with the darker light-mode text tokens.
Also append ?v=2 to every /diagrams/*.svg reference so the recoloured diagrams
bypass Cloudflare's 4h edge cache and show immediately (the SVG URLs aren't
content-hashed like the CSS bundle).
Body text washed out in light mode — the secondary/tertiary text tokens were
too light against the bright sandstone board image. Darken light --text-dim and
--text-faint, and heavily strengthen the light-theme scrim so the board drops
to a faint texture behind content. Dark mode unchanged.
The diagrams still used the old teal/green/blue scheme. Remap all six to the
electric theme: teal #0d9488 → cyan #0c8fce (primary), blue #3b6fb0 → violet
#7c3aed (containers/boundaries), green #2e8b57 → magenta #c026d3 (services).
Neutral slate + navy kept for lines and text; light card unchanged so the
fixed-colour art stays legible in both themes.
CSS animation-timeline: scroll() is Chromium-only, so the backdrop didn't move
for non-Chromium browsers. Replace it with a tiny rAF-throttled scroll handler
in site.js (the existing same-origin script — CSP stays strict, no inline JS)
that drives a --bg-shift CSS var off scroll position. The board now pans
vertically in lock-step with scroll and sits still at rest, in all browsers.
The backdrop's only motion was the scroll-driven pan (animation-timeline:
scroll()), which is Chromium-only — so in Firefox/Safari the board sat dead
still. Add a continuous timed top↔bottom drift (48s, alternates) as the
universal baseline; keep the scroll-coupled pan as a Chromium enhancement that
overrides it. Motion-safe: both gated behind prefers-reduced-motion.
The S→E→SE→NE loop wandered back near its start, so on a long page the
per-screen movement was imperceptible (worse once the image was zoomed to
215%). Replace it with a single continuous vertical pan (~40% travel) so the
board obviously drifts downward as the page scrolls.
- Backdrop image scaled 168% → 215% so the Bat-Computer board reads bigger
and more immersive, with more room for the scroll-pan.
- Retitle the least-privilege post "The most secure credential is the one
you never mount" → "Every pod holds a key to a door it never opens" so it
no longer mirrors the "...inbound port is the one you never open" post.
Bumps astro to 7.0.3 and @astrojs/check to the matching release. Vite 8
under the hood; @tailwindcss/vite/sitemap/rss already compatible, Node 22
satisfied. Verified end-to-end: typecheck (0 errors), build, dist scan,
audit gate, and visual render (hero + blog + Shiki) all clean under the new
Rust compiler + Markdown pipeline.
Pin the floating node:22-bookworm-slim tag to its index digest. The re-resolve
of this unpinned docker.io tag every build was the recurring CI 'hang'. Paired
with the bastion runner now pulling through the zot mirror, the base is fetched
once and cached. (nginx runtime stage was already digest-pinned.)
Least-privilege for Kubernetes workloads — own ServiceAccount + no auto-mounted
API token, then non-root + dropped caps, then Pod Security as the enforced floor.
Adds a matching house-style SVG diagram (workload-least-privilege).
Re-running the same commit collided with the prior run's deploy/<sha> branch
(non-fast-forward reject). The branch is a disposable deploy artifact; main is
the protected human-merge gate, so force-push is safe and makes re-runs work.
The branch push is the deploy artifact; opening the PR is best-effort.
Previously a no-timeout curl to the private Gitea API tripped split-horizon
DNS from the runner, hanging the step ~10min then failing the whole run.
Now: --connect-timeout 10 --max-time 30, failure is logged non-fatally, exit 0.
All JS moved to external /site.js → script-src 'self' with no inline JS,
hashes or eval. Full header set via nginx (CSP, nosniff, frame-deny,
referrer, permissions, COOP/CORP); HSTS stays at the CF edge. Shared
headers include avoids the location add_header reset footgun. Build-time
secret/inline-script/third-party scan gate. SECURITY.md documents posture.
Hand-authored inline-SVG Diagram component (no runtime JS, CSP-clean,
themeable) rendering edge-AI, IaC-fleet and homelab architectures on the
case studies. Staggered CSS hero entrance, motion-aware.
Projects + blog as schema-validated content collections; structured case
studies (problem/design/outcome), blog with tag pages, reading time, RSS
feed (drafts excluded), sitemap, and Shiki dual-theme code highlighting.
Real career history (Woolworths, Virtus Health, Linde, ELGAS, Darktime),
cloud-heavy skills matrix, education, LinkedIn, Sydney location, and
projects mapped to actual work. OG subtitle now smaller italic serif.