Handoff: The Daily Cyborg — V1 “Muted Phosphor” Finish
Handoff: The Daily Cyborg — V1 “Muted Phosphor” Finish
Overview
This handoff refines the look and feel of The Daily Cyborg — an existing Jekyll site. The visual direction (green-on-black, techno/matrix + Harry Potter blackletter) stays. What changes is the finish: pull the saturation and glow way down, add print-y texture, push the whole thing further into “terminal archaeology” territory — an archived, slightly decaying CRT that still feels like a newspaper.
The structure, copy, nav, layout, and content model are unchanged. This is a CSS + light-JS refresh.
About the Design Files
The files in reference/ are design references — an HTML/React prototype showing the intended look. They are not production code to copy directly.
The target codebase is a Jekyll site (see https://github.com/jasonpauljohnston/thedailycyborg). The task is to update:
assets/css/main.css— the main stylesheet (existing tokens are well-organized; replace values, don’t rewrite structure)assets/js/main.js— add the small JS effects (glyph rain canvas + glitch hover)_includes/head.html— already loads the right Google Fonts; no changes expected- Body markup in
_includes/header.html,_includes/footer.html,_includes/post-card.html,_layouts/*— minor additions only (a<canvas>for rain,data-glitchattributes for hover scramble)
Implement the design using the existing Liquid templates + vanilla CSS/JS. Do not introduce React or a bundler.
Fidelity
High-fidelity. Exact colors, typography, spacing, and effects are specified below. Recreate pixel-perfectly.
Palette (oklch — replace old :root tokens)
The existing CSS uses HSL/hex. Replace with these. Keep variable names where they exist; add new ones where noted.
| Token | New value | Notes |
|---|---|---|
--bg-primary |
#070b07 |
slightly warmer than before |
--bg-secondary |
#0a100a |
panel / ticker bg |
--bg-card |
#0c110c |
card bg |
--text-primary (paper) |
oklch(0.92 0.02 95) |
warm off-white for headlines |
--phosphor (was --accent) |
oklch(0.78 0.11 142) |
main green. much less saturated than #39ff14 |
--phosphor-dim |
oklch(0.55 0.06 142) |
body copy, nav inactive |
--phosphor-mute |
oklch(0.38 0.035 142) |
hairlines, separators |
--amber (new) |
oklch(0.68 0.11 75) |
shadow/alert accent (ticker label, stardates) |
--amber-dim (new) |
oklch(0.45 0.07 75) |
|
--rule |
oklch(0.55 0.06 142 / 0.55) |
primary hairline |
--rule-faint |
oklch(0.55 0.06 142 / 0.18) |
sub-hairline |
--accent-teal |
remove | no teal in V1 |
Glow policy
Remove all text-shadow glow and box-shadow glow throughout the site — with one exception: the masthead title keeps a gentle residual glow:
.masthead-title {
text-shadow:
0 0 18px oklch(0.78 0.11 142 / 0.28),
0 0 2px oklch(0.78 0.11 142 / 0.6);
}
Everything else (.rule, .post-card-title:hover, .read-more:hover, .pull-quote, .section-header::before, etc.) should drop its glow. Hover states use a color/border change only.
Typography (unchanged families, tightened usage)
Families already loaded — keep them:
--font-masthead: 'UnifrakturMaguntia', serif;— masthead only--font-body: 'Lora', Georgia, serif;— body copy, excerpts--font-headline: 'Courier Prime', monospace;— headlines, nav, buttons (UPPERCASE)--font-label: 'VT323', monospace;— labels, ticker, meta, tags--font-mono: 'Share Tech Mono', monospace;— code blocks
Type spec changes
| Element | Family | Size | Weight | Tracking | Case |
|---|---|---|---|---|---|
.masthead-title |
Unifraktur | clamp(3rem, 8vw, 6.5rem) |
400 | 0.01em |
sentence |
.masthead-tagline |
VT323 | 1.1rem |
— | 0.32em |
UPPERCASE |
wrap with em-dashes: — Dispatches from the Human-Machine Frontier — |
|||||
.masthead-meta |
VT323 | 0.95rem |
— | 0.12em |
sentence |
.ticker-bar |
VT323 | 0.95rem |
— | 0.08em |
sentence |
.ticker-label text |
VT323 bold | — | 700 | 0.08em |
NEURAL WEATHER ∷ (use ∷ instead of :) |
.site-nav a |
Courier Prime | 0.75rem |
700 | 0.25em |
UPPERCASE |
.post-card-title |
Courier Prime | 1.25rem (non-lead), 1.875rem (lead) |
700 | 0.02em |
UPPERCASE |
.post-card-excerpt |
Lora | 0.95rem |
400 | normal | sentence |
.post-card-issue (stardate) |
VT323 | 0.875rem |
— | 0.18em |
color: --amber |
.tag |
VT323 | 0.8rem |
— | 0.1em |
UPPERCASE, color --phosphor-dim |
.read-more |
Courier Prime | 0.7rem |
700 | 0.22em |
UPPERCASE, prefix > , suffix ` _` |
.footer-text |
VT323 | 0.875rem |
— | 0.12em |
sentence |
Line-height: body copy 1.65, headlines 1.15–1.2.
Textures & Effects (the “finish”)
1. CRT scanlines — global overlay
Add once, covers the whole viewport. Non-interactive.
body::after {
content: '';
position: fixed; inset: 0;
pointer-events: none;
z-index: 9999;
background-image: repeating-linear-gradient(
0deg,
rgba(0,0,0,0.22) 0 1px,
transparent 1px 3px
);
mix-blend-mode: multiply;
}
2. Subtle 60Hz flicker
Apply to a wrapper around the main content (not the scanline overlay).
@keyframes v1flicker {
0%, 100% { opacity: 0.97; }
3% { opacity: 0.93; }
50% { opacity: 1; }
97% { opacity: 0.95; }
}
.page-flicker { animation: v1flicker 4.5s infinite; }
Wrap the <body> inner content (everything except the two fixed overlays) with class="page-flicker".
3. Newsprint grain — fixed overlay
Warm-toned SVG turbulence at opacity: 0.08, mix-blend-mode: overlay.
body::before {
content: '';
position: fixed; inset: 0;
pointer-events: none;
z-index: 1;
opacity: 0.08;
mix-blend-mode: overlay;
background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='160' height='160'><filter id='n'><feTurbulence baseFrequency='0.9' numOctaves='2' seed='5'/><feColorMatrix values='0 0 0 0 0.6 0 0 0 0 0.9 0 0 0 0 0.6 0 0 0 0.6 0'/></filter><rect width='100%' height='100%' filter='url(%23n)'/></svg>");
}
This replaces the current circuit-board SVG background.
4. Glyph rain — subtle canvas behind content
A sparse matrix-rain canvas, not dominant. Target: opacity: 0.22 at the canvas level, with a very low density.
Add <canvas id="glyph-rain"></canvas> as the first child of <body>. CSS:
#glyph-rain {
position: fixed; inset: 0;
width: 100%; height: 100%;
z-index: 0;
opacity: 0.22;
pointer-events: none;
}
JS (assets/js/main.js) — see reference/shared.jsx useGlyphRain for the full algorithm. Port to vanilla JS with these params:
- font:
13px "Share Tech Mono", monospace - character set:
アイウエオカキクケコサシスセソタチツテトナニヌネノ01010110+-*/<>[]{} - head color:
oklch(0.72 0.09 142 / 0.35)(new glyph this frame) - trail color:
oklch(0.55 0.06 142 / 0.18)(glyph behind head) - fade rect color per frame:
rgba(5,15,5,0.06)(low = long trails) - density multiplier:
0.7(cols =width / fontSize * 0.7) - fall speed:
0.55rows per frame - reset rule: when
y > height && Math.random() > 0.975, resetdrops[i] = 0
5. Glitch hover — character scramble
Apply to: .post-card-title a, .site-nav a, .masthead-title a.
Algorithm: on mouseenter, for each character in the element’s text, schedule a scramble window (start = random 0–8 frames, end = start + 4–14 frames). During the window, render a random character from !<>-_\\/[]{}—=+*^?#01. After end, lock in the original. Advance one requestAnimationFrame per tick.
See reference/shared.jsx GlitchText component for the reference implementation. Port to vanilla JS — select all matching elements on DOMContentLoaded and bind mouseenter.
Component Specs
Masthead (.site-header, .masthead)
- Background:
--bg-primary. border-bottom: single1px solid var(--rule)(was 3px double).- Top and bottom 1px gradient accents removed (
.masthead::before/::after— delete). - Title keeps the blackletter with the residual glow spec above.
- Tagline wrapped with em-dashes on each side:
— DISPATCHES FROM THE HUMAN-MACHINE FRONTIER —. - Meta separator dots: use
·in--phosphor-mute.
Ticker (.ticker-bar)
- Background:
--bg-secondary. - Borders top & bottom:
1px solid var(--rule-faint). - Label
NEURAL WEATHER ∷in--amber. - Items separated by
·in--phosphor-mute. - Keep the existing scroll animation; speed unchanged.
Nav (.site-nav)
- Background:
--bg-secondary. - Border-bottom:
1px solid var(--rule). - Links: padding
0.875rem 1.375rem. Dividers:1px solid var(--rule-faint)between items (not on first-item left edge). - Active state: color
--text-primary(paper), backgroundoklch(0.55 0.06 142 / 0.08), no glow. - Hover state: color
--phosphor(brighter). No text-shadow. - Glitch scramble fires on hover.
Section header (.section-header)
- Rules: single 1px solid
--rule(not the current 3px double with glow). - Title text: prefix with
∷and suffix ` ∷. Font VT323, tracking0.35em, color–phosphor`. No glow.
Post card (.post-card)
- Remove all glow on hover.
.post-card-title a:hover→ color--phosphor, no text-shadow.- Lead story (
:first-child): keep the 2-col split layout; change the column divider from1px solid --accent-dimto1px solid var(--rule-faint). Remove the3px doublebottom border — use1px solid var(--rule). - Stardate line:
Issue No. {n} · STARDATE {date}in--amber, VT323. .read-moretext:"> READ FULL TRANSMISSION _"(prefix>, suffix ` _). Border1px solid –phosphor, no hover glow — hover fills with–phosphorand switches text to–bg-primary`.
Tags (.tag)
- Border:
1px solid var(--rule-faint). - Color:
--phosphor-dim(was--accent). - No background change.
Rules (.rule, .rule-single, .article-rule)
- Collapse all to
1px solid var(--rule), no glow, no double-line. If you want emphasis on article breaks, usewidth: 60%margin-auto only — no shadow.
Footer (.site-footer)
- Border-top:
1px solid var(--rule)(was 3px double). - No box-shadow.
- Text color
--phosphor-mute, VT323.
Drop cap (post body p:first-of-type::first-letter)
- Keep Unifraktur, 5rem, float-left.
- Color:
--phosphorwith no text-shadow (current version glows — remove it).
Pull quote (.pull-quote, .post-body blockquote)
- Remove
box-shadow: var(--accent-glow)andinsetshadow. - Borders left/right:
2px solid var(--phosphor)(thinner; was 3px). - Inner text color:
--phosphor(was accent-teal; V1 drops the teal). - Opening quote mark: keep Unifraktur, color
--phosphoratopacity: 0.3.
Interactions & Behavior
| Interaction | Behavior |
|---|---|
| Nav hover | Color brightens to --phosphor; background tint oklch(0.55 0.06 142 / 0.08); glitch-scramble text (~180ms) |
| Headline hover | Glitch-scramble text; color brightens to --phosphor |
| Read-more hover | Fills to --phosphor background, text becomes --bg-primary. No glow. |
| Ticker | Existing horizontal scroll, unchanged |
| Glyph rain | Autoplays on load, pauses on prefers-reduced-motion: reduce |
| CRT flicker | Autoplays; must respect prefers-reduced-motion: reduce → disable the v1flicker animation |
@media (prefers-reduced-motion: reduce) {
.page-flicker { animation: none; }
#glyph-rain { display: none; }
}
Design Tokens (summary — for quick reference)
:root {
/* Backgrounds */
--bg-primary: #070b07;
--bg-secondary: #0a100a;
--bg-card: #0c110c;
/* Foreground */
--text-primary: oklch(0.92 0.02 95);
/* Phosphor (main green — desaturated) */
--phosphor: oklch(0.78 0.11 142);
--phosphor-dim: oklch(0.55 0.06 142);
--phosphor-mute: oklch(0.38 0.035 142);
/* Amber (shadow accent) */
--amber: oklch(0.68 0.11 75);
--amber-dim: oklch(0.45 0.07 75);
/* Rules */
--rule: oklch(0.55 0.06 142 / 0.55);
--rule-faint: oklch(0.55 0.06 142 / 0.18);
/* Aliases for back-compat with existing CSS selectors */
--accent: var(--phosphor);
--accent-dim: var(--rule-faint);
--rule-color: var(--phosphor-dim);
/* Remove: --accent-teal, --accent-glow, --teal-glow */
/* Fonts — unchanged */
--font-masthead: 'UnifrakturMaguntia', serif;
--font-headline: 'Courier Prime', monospace;
--font-body: 'Lora', Georgia, serif;
--font-label: 'VT323', monospace;
--font-mono: 'Share Tech Mono', monospace;
}
Spacing
Unchanged from current CSS — existing scale is fine.
Border radius
Zero. Everything is hard-edged.
Shadows
None, except the residual masthead glow documented above.
Assets
No new image assets. Everything is CSS/SVG/canvas.
Fonts already loaded via Google Fonts in _includes/head.html — no changes needed.
Files to change
| File | Change |
|---|---|
assets/css/main.css |
Token replacement + glow removal + rule simplification. Follow this doc section-by-section. |
assets/js/main.js |
Add glyph-rain canvas loop + glitch-hover binder. Port from reference/shared.jsx. |
_layouts/default.html |
Add <canvas id="glyph-rain"></canvas> as first child of <body>; wrap existing body contents with <div class="page-flicker">. |
_includes/head.html |
No change (fonts already loaded). |
_includes/header.html |
Tweak tagline text to — Dispatches from the Human-Machine Frontier —; label to NEURAL WEATHER ∷. |
Reference Files
In reference/:
v1-preview.html— open in a browser to see the exact intended result.v1-muted-phosphor.jsx— the React component source. Read this for exact spacing, structure, and inline style values.shared.jsx— canonical implementations ofuseGlyphRainandGlitchText. Port these to vanilla JS.
To preview locally:
cd reference
python3 -m http.server 8000
# open http://localhost:8000/v1-preview.html
Done criteria
- All teal and neon-glow are gone; only the masthead has a soft residual green glow.
- Green hue reads as “aged phosphor,” not laser.
- Amber appears only in stardates and the
NEURAL WEATHER ∷label. - CRT scanlines visible at normal viewing distance; not overpowering.
- Glyph rain visible but subtle — a backdrop, not a feature.
- Headlines, nav, and masthead glitch-scramble on hover.
prefers-reduced-motion: reducedisables the flicker animation and hides the glyph rain.- No layout regressions on mobile (existing
@media (max-width: 768px)and480pxbreakpoints still apply).