Pixel Noir is a hybrid aesthetic that fuses the blocky, constrained visual language of classic pixel art with the moody, shadow-drenched atmosphere of film noir. The result is a dark, narrative-driven style built on severely limited color palettes, deliberate dithering patterns, and a pervasive sense of rain-slicked mystery. Where standard pixel art celebrates bright primaries and playful sprites, Pixel Noir strips the palette down to blacks, deep grays, muted ambers, and the occasional blood-red accent – evoking smoky detective offices, rain-soaked alleyways, and flickering neon signs rendered at low resolution.
The aesthetic draws from two distinct lineages. On one side, it inherits the technical constraints of 8-bit and 16-bit era gaming: tile-based construction, bitmap fonts, sprite animation, and the creative use of dithering to simulate gradients with only a handful of colors. On the other, it channels the cinematic language of 1940s and 1950s film noir – chiaroscuro lighting, venetian-blind shadow patterns, fog, cigarette smoke, and morally ambiguous narratives. Games like Pecaminosa (Cereal Games), Pixel Noir (SWDTech Games), and The Red Strings Club have demonstrated how pixel art can carry genuine noir weight, using intricate low-resolution detail to reflect the grimy essence of noir cinema while occasionally introducing vibrant neon tones for mesmerizing contrast.
In web and UI design, Pixel Noir translates to dark, textured backgrounds with visible dithering patterns, monospaced bitmap typography, harsh single-pixel borders, and carefully rationed warm accents that feel like lamplight cutting through darkness. Every element should feel like it was rendered on a CRT monitor in a dimly lit room. The style rewards restraint: limited palettes force creative problem-solving, and the coarse pixel grid demands that every single pixel earn its place. Animation is minimal and deliberate – a blinking cursor, a flickering light, rain trickling down a window – never gratuitous. The overall mood is contemplative, atmospheric, and just slightly dangerous.
The Pixel Noir palette is built on extreme darkness punctuated by carefully rationed warm and cool accents. The majority of the palette lives in the black-to-dark-gray range, with dithering used to create intermediate values. Accent colors are borrowed from the noir visual vocabulary: amber streetlamps, red neon bar signs, cold blue moonlight, and the sickly green of fluorescent tubes in empty hallways.
| Swatch | Hex | Role / Usage |
|---|---|---|
| Void Black | #080808 |
Primary background, deepest shadows, letterboxing |
| Soot | #121212 |
Secondary background, card surfaces, panel fills |
| Charcoal | #1C1C1E |
Elevated surfaces, navigation backgrounds, code blocks |
| Gunmetal | #2A2A2D |
Borders, dividers, inactive UI elements |
| Smoke | #3A3A3E |
Dithering mid-tone, subtle backgrounds, disabled text |
| Ash | #555558 |
Secondary text, captions, muted UI labels |
| Fog | #7A7A80 |
Tertiary text, timestamps, metadata |
| Bone | #C8C0B0 |
Primary text, body copy on dark backgrounds |
| Lamplight Amber | #D4A020 |
Primary warm accent, links, active states, highlights |
| Whiskey Gold | #B8860B |
Secondary warm accent, hover states, subtle emphasis |
| Blood Red | #8B1A1A |
Danger states, critical alerts, narrative emphasis |
| Neon Red | #CC2222 |
Error states, destructive actions, neon sign glow |
| Midnight Blue | #1A1A2E |
Cool accent backgrounds, moonlit panels |
| Rain Blue | #4A6580 |
Cool accent, secondary interactive elements |
| Fluorescent Green | #2A8A2A |
Success states, terminal text, data confirmations |
:root {
/* Backgrounds */
--noir-bg-void: #080808;
--noir-bg-soot: #121212;
--noir-bg-charcoal: #1c1c1e;
--noir-bg-gunmetal: #2a2a2d;
/* Grays / Dither tones */
--noir-smoke: #3a3a3e;
--noir-ash: #555558;
--noir-fog: #7a7a80;
/* Text */
--noir-text-primary: #c8c0b0;
--noir-text-secondary: #7a7a80;
--noir-text-muted: #555558;
/* Warm accents */
--noir-amber: #d4a020;
--noir-gold: #b8860b;
--noir-red: #8b1a1a;
--noir-neon-red: #cc2222;
/* Cool accents */
--noir-midnight: #1a1a2e;
--noir-rain-blue: #4a6580;
--noir-green: #2a8a2a;
/* Glows (used for box-shadow and text-shadow) */
--noir-glow-amber: 0 0 6px rgba(212, 160, 32, 0.4), 0 0 20px rgba(212, 160, 32, 0.1);
--noir-glow-red: 0 0 6px rgba(204, 34, 34, 0.5), 0 0 20px rgba(204, 34, 34, 0.15);
/* Borders */
--noir-border: 1px solid #2a2a2d;
--noir-border-amber: 1px solid rgba(212, 160, 32, 0.3);
/* Pixel rendering */
--noir-pixel-size: 4px;
}
Pixel Noir typography is strictly bitmap and monospaced, evoking typewritten case reports, dot-matrix printouts, and old terminal screens. All text must render crisply on the pixel grid with no anti-aliasing, no sub-pixel rendering, and no smooth curves. Letterforms feel stamped, mechanical, and utilitarian – the kind of text that emerges from a teletype machine in a 1940s police station, filtered through the lo-fi screen of a retro computer.
| Font | Style | Best For |
|---|---|---|
| Press Start 2P | Bitmap, arcade | Display headings, hero text, titles |
| VT323 | Terminal monospace | Body text, narrative passages, dialogue |
| Silkscreen | Clean bitmap | UI labels, navigation, metadata |
| Share Tech Mono | Techy monospace | Data readouts, code blocks, stats |
| IBM Plex Mono | Clean monospace | Long-form body text, readable passages |
| Space Mono | Retro-futuristic mono | Secondary headings, editorial layouts |
| DotGothic16 | Japanese pixel | Atmospheric accents, decorative labels |
| Pixelify Sans | Modern pixel | Subheadings, badges, tags |
| Heading Font | Body Font | Character |
|---|---|---|
| Press Start 2P (400) | VT323 (400) | Classic pixel noir, game-inspired |
| Press Start 2P (400) | IBM Plex Mono (400) | Pixel headings with readable body |
| Silkscreen (700) | VT323 (400) | Clean UI with terminal narrative |
| Pixelify Sans (700) | Share Tech Mono (400) | Modern pixel with tech readouts |
| Space Mono (700) | VT323 (400) | Retro-futuristic noir editorial |
/* Import fonts */
@import url('https://fonts.googleapis.com/css2?family=Press+Start+2P&family=VT323&family=Silkscreen:wght@400;700&display=swap');
/* Force pixel-perfect rendering */
* {
-webkit-font-smoothing: none;
-moz-osx-font-smoothing: unset;
text-rendering: optimizeSpeed;
}
/* Headings */
h1, h2, h3, h4, h5, h6 {
font-family: 'Press Start 2P', monospace;
color: var(--noir-text-primary);
text-transform: uppercase;
letter-spacing: 0.05em;
line-height: 2;
image-rendering: pixelated;
}
/* Display / Hero text with amber glow */
.noir-display {
font-family: 'Press Start 2P', monospace;
font-size: clamp(1.5rem, 4vw, 3rem);
color: var(--noir-amber);
text-shadow: 2px 2px 0 #080808, 0 0 8px rgba(212, 160, 32, 0.3);
text-transform: uppercase;
letter-spacing: 0.08em;
line-height: 2;
}
/* Body / narrative text */
body {
font-family: 'VT323', monospace;
font-size: 1.25rem;
line-height: 1.8;
color: var(--noir-text-primary);
}
/* UI labels */
.noir-label {
font-family: 'Silkscreen', monospace;
font-size: 0.75rem;
letter-spacing: 0.1em;
text-transform: uppercase;
color: var(--noir-text-secondary);
}
/* Data readout */
.noir-data {
font-family: 'Share Tech Mono', monospace;
font-size: 0.85rem;
color: var(--noir-green);
line-height: 1.6;
}
/* Checkerboard dithering pattern using CSS */
.noir-dither {
background-color: var(--noir-bg-void);
background-image:
linear-gradient(45deg,
var(--noir-bg-soot) 25%, transparent 25%,
transparent 75%, var(--noir-bg-soot) 75%),
linear-gradient(45deg,
var(--noir-bg-soot) 25%, transparent 25%,
transparent 75%, var(--noir-bg-soot) 75%);
background-size: 4px 4px;
background-position: 0 0, 2px 2px;
}
/* Vertical dither fade (top to bottom) */
.noir-dither-fade {
position: relative;
}
.noir-dither-fade::after {
content: '';
position: absolute;
inset: 0;
background:
repeating-linear-gradient(
0deg,
transparent 0px,
transparent 2px,
rgba(8, 8, 8, 0.3) 2px,
rgba(8, 8, 8, 0.3) 4px
);
pointer-events: none;
mix-blend-mode: multiply;
}
.noir-card {
background: var(--noir-bg-soot);
border: 1px solid var(--noir-bg-gunmetal);
padding: 24px;
position: relative;
image-rendering: pixelated;
transition: border-color 0.2s ease;
}
.noir-card:hover {
border-color: var(--noir-amber);
}
/* Pixel corner accents (case file staple marks) */
.noir-card::before {
content: '';
position: absolute;
top: 4px;
left: 4px;
width: 8px;
height: 8px;
border-top: 2px solid var(--noir-amber);
border-left: 2px solid var(--noir-amber);
}
.noir-card::after {
content: '';
position: absolute;
bottom: 4px;
right: 4px;
width: 8px;
height: 8px;
border-bottom: 2px solid var(--noir-amber);
border-right: 2px solid var(--noir-amber);
}
/* Card with dithered header */
.noir-card__header {
font-family: 'Press Start 2P', monospace;
font-size: 0.7rem;
color: var(--noir-amber);
text-transform: uppercase;
letter-spacing: 0.1em;
padding-bottom: 12px;
margin-bottom: 16px;
border-bottom: 1px solid var(--noir-bg-gunmetal);
}
.noir-card__body {
font-family: 'VT323', monospace;
font-size: 1.1rem;
color: var(--noir-text-primary);
line-height: 1.7;
}
/* Card grid */
.noir-card-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
gap: 16px;
}
.noir-btn {
display: inline-block;
background: transparent;
color: var(--noir-amber);
border: 2px solid var(--noir-amber);
padding: 12px 28px;
font-family: 'Press Start 2P', monospace;
font-size: 0.65rem;
letter-spacing: 0.08em;
text-transform: uppercase;
text-decoration: none;
cursor: pointer;
image-rendering: pixelated;
transition: background 0.15s ease, color 0.15s ease;
position: relative;
}
.noir-btn:hover {
background: var(--noir-amber);
color: var(--noir-bg-void);
box-shadow: var(--noir-glow-amber);
}
.noir-btn:active {
transform: translate(2px, 2px);
box-shadow: none;
}
/* Pixel shadow (retro press effect) */
.noir-btn--pixel-shadow {
box-shadow: 4px 4px 0 var(--noir-bg-gunmetal);
}
.noir-btn--pixel-shadow:active {
box-shadow: none;
transform: translate(4px, 4px);
}
/* Danger variant */
.noir-btn--danger {
color: var(--noir-neon-red);
border-color: var(--noir-neon-red);
}
.noir-btn--danger:hover {
background: var(--noir-neon-red);
color: var(--noir-bg-void);
box-shadow: var(--noir-glow-red);
}
/* Ghost variant (minimal) */
.noir-btn--ghost {
border-color: var(--noir-bg-gunmetal);
color: var(--noir-text-secondary);
}
.noir-btn--ghost:hover {
border-color: var(--noir-amber);
color: var(--noir-amber);
}
.noir-nav {
display: flex;
align-items: center;
justify-content: space-between;
max-width: 960px;
margin: 0 auto;
padding: 12px 24px;
background: var(--noir-bg-soot);
border-bottom: 2px solid var(--noir-bg-gunmetal);
}
.noir-nav__logo {
font-family: 'Press Start 2P', monospace;
font-size: 0.75rem;
color: var(--noir-amber);
text-decoration: none;
text-transform: uppercase;
letter-spacing: 0.12em;
text-shadow: 2px 2px 0 #080808;
}
.noir-nav__links {
display: flex;
gap: 24px;
list-style: none;
margin: 0;
padding: 0;
}
.noir-nav__links a {
font-family: 'Silkscreen', monospace;
font-size: 0.75rem;
color: var(--noir-text-secondary);
text-decoration: none;
text-transform: uppercase;
letter-spacing: 0.06em;
padding: 4px 0;
border-bottom: 2px solid transparent;
transition: color 0.2s ease, border-color 0.2s ease;
}
.noir-nav__links a:hover,
.noir-nav__links a.active {
color: var(--noir-amber);
border-bottom-color: var(--noir-amber);
}
/* Tab-style nav variant (case file tabs) */
.noir-nav--tabs .noir-nav__links a {
background: var(--noir-bg-charcoal);
border: 1px solid var(--noir-bg-gunmetal);
border-bottom: none;
padding: 8px 16px;
position: relative;
top: 2px;
}
.noir-nav--tabs .noir-nav__links a.active {
background: var(--noir-bg-soot);
border-color: var(--noir-amber);
color: var(--noir-amber);
}
.noir-hero {
position: relative;
min-height: 80vh;
display: flex;
align-items: center;
justify-content: center;
text-align: center;
padding: 80px 24px;
background: var(--noir-bg-void);
overflow: hidden;
}
/* Scan line overlay */
.noir-hero::before {
content: '';
position: absolute;
inset: 0;
background: repeating-linear-gradient(
0deg,
transparent,
transparent 2px,
rgba(200, 192, 176, 0.015) 2px,
rgba(200, 192, 176, 0.015) 4px
);
pointer-events: none;
z-index: 2;
}
/* Venetian blind shadow effect */
.noir-hero::after {
content: '';
position: absolute;
inset: 0;
background: repeating-linear-gradient(
0deg,
transparent 0px,
transparent 20px,
rgba(0, 0, 0, 0.3) 20px,
rgba(0, 0, 0, 0.3) 28px
);
transform: skewY(-5deg);
pointer-events: none;
z-index: 1;
opacity: 0.4;
}
.noir-hero__content {
position: relative;
z-index: 3;
max-width: 700px;
}
.noir-hero__content h1 {
font-family: 'Press Start 2P', monospace;
font-size: clamp(1.5rem, 4vw, 2.5rem);
color: var(--noir-amber);
text-shadow: 3px 3px 0 #080808, 0 0 12px rgba(212, 160, 32, 0.25);
margin-bottom: 2rem;
line-height: 2;
}
.noir-hero__content p {
font-family: 'VT323', monospace;
font-size: 1.3rem;
color: var(--noir-text-secondary);
max-width: 560px;
margin: 0 auto 2.5rem;
line-height: 1.8;
}
/* Rain animation overlay */
@keyframes noir-rain {
0% { background-position: 0 0; }
100% { background-position: -20px 200px; }
}
.noir-hero--rain::before {
background:
repeating-linear-gradient(
0deg,
transparent,
transparent 2px,
rgba(200, 192, 176, 0.015) 2px,
rgba(200, 192, 176, 0.015) 4px
),
url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='4' height='40'%3E%3Crect x='1' y='0' width='1' height='3' fill='rgba(120,140,160,0.15)'/%3E%3C/svg%3E");
animation: noir-rain 0.8s linear infinite;
}
@media (max-width: 768px) {
.noir-hero {
min-height: auto;
padding: 48px 16px;
}
}
/* Standalone venetian blind shadow utility */
.noir-blinds {
position: relative;
}
.noir-blinds::after {
content: '';
position: absolute;
inset: 0;
background: repeating-linear-gradient(
0deg,
transparent 0px,
transparent 16px,
rgba(0, 0, 0, 0.25) 16px,
rgba(0, 0, 0, 0.25) 24px
);
transform: skewY(-3deg);
pointer-events: none;
opacity: 0.5;
}
/* CRT-style vignette darkening at edges */
.noir-vignette {
position: relative;
}
.noir-vignette::after {
content: '';
position: absolute;
inset: 0;
background: radial-gradient(
ellipse at center,
transparent 50%,
rgba(8, 8, 8, 0.6) 100%
);
pointer-events: none;
}
@keyframes noir-flicker {
0%, 19%, 21%, 23%, 25%, 54%, 56%, 100% {
text-shadow:
0 0 4px var(--noir-neon-red),
0 0 12px rgba(204, 34, 34, 0.4),
0 0 24px rgba(204, 34, 34, 0.15);
opacity: 1;
}
20%, 24%, 55% {
text-shadow: none;
opacity: 0.7;
}
}
.noir-neon {
font-family: 'Press Start 2P', monospace;
color: var(--noir-neon-red);
animation: noir-flicker 4s infinite;
}
.noir-neon--amber {
color: var(--noir-amber);
animation-name: noir-flicker-amber;
}
@keyframes noir-flicker-amber {
0%, 19%, 21%, 23%, 25%, 54%, 56%, 100% {
text-shadow:
0 0 4px var(--noir-amber),
0 0 12px rgba(212, 160, 32, 0.4),
0 0 24px rgba(212, 160, 32, 0.15);
opacity: 1;
}
20%, 24%, 55% {
text-shadow: none;
opacity: 0.7;
}
}
image-rendering: pixelated to all pixel art elements so they scale sharply without browser anti-aliasing| Aesthetic | Relationship to Pixel Noir |
|---|---|
| 8-Bit | Shares pixel grid constraints and bitmap fonts, but 8-Bit is bright, playful, and colorful while Pixel Noir is dark, moody, and restrained |
| Cyberpunk | Both use dark backgrounds with colored accents, but Cyberpunk is neon-saturated and futuristic while Pixel Noir is desaturated and retro-nostalgic |
| Dark Mode Neon | Shares the dark-canvas-with-accents approach, but lacks the pixel grid constraints and noir narrative atmosphere |
| Dark Academia | Both evoke moodiness and intellectual mystery, but Dark Academia uses rich textures and serif typography rather than pixel grids |
| Film Noir (classic) | The direct cinematic ancestor; Pixel Noir translates noir’s chiaroscuro, shadows, and moral ambiguity into low-resolution digital form |
| Synthwave / Laser Grid | Shares retro-digital nostalgia and dark palettes, but Synthwave is vibrant and celebratory where Pixel Noir is somber and investigative |
| Industrial Gothic | Both are dark and atmospheric, but Industrial Gothic uses metal textures and heavy type while Pixel Noir uses pixel grids and bitmap fonts |
| Four Colors | Shares the severely limited palette concept, but Four Colors is a general constraint exercise while Pixel Noir applies it to a specific noir narrative |
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Pixel Noir Page</title>
<link href="https://fonts.googleapis.com/css2?family=Press+Start+2P&family=VT323&family=Silkscreen:wght@400;700&display=swap" rel="stylesheet">
<style>
:root {
/* Backgrounds */
--noir-bg-void: #080808;
--noir-bg-soot: #121212;
--noir-bg-charcoal: #1c1c1e;
--noir-bg-gunmetal: #2a2a2d;
/* Grays */
--noir-smoke: #3a3a3e;
--noir-ash: #555558;
--noir-fog: #7a7a80;
/* Text */
--noir-text-primary: #c8c0b0;
--noir-text-secondary: #7a7a80;
--noir-text-muted: #555558;
/* Accents */
--noir-amber: #d4a020;
--noir-gold: #b8860b;
--noir-red: #8b1a1a;
--noir-neon-red: #cc2222;
--noir-midnight: #1a1a2e;
--noir-rain-blue: #4a6580;
--noir-green: #2a8a2a;
/* Glows */
--noir-glow-amber: 0 0 6px rgba(212, 160, 32, 0.4), 0 0 20px rgba(212, 160, 32, 0.1);
--noir-glow-red: 0 0 6px rgba(204, 34, 34, 0.5), 0 0 20px rgba(204, 34, 34, 0.15);
}
* {
margin: 0;
padding: 0;
box-sizing: border-box;
-webkit-font-smoothing: none;
-moz-osx-font-smoothing: unset;
}
body {
background: var(--noir-bg-void);
color: var(--noir-text-primary);
font-family: 'VT323', monospace;
font-size: 1.25rem;
line-height: 1.8;
image-rendering: pixelated;
}
h1, h2, h3, h4 {
font-family: 'Press Start 2P', monospace;
text-transform: uppercase;
letter-spacing: 0.05em;
line-height: 2;
}
a {
color: var(--noir-amber);
text-decoration: none;
border-bottom: 1px solid transparent;
transition: border-color 0.2s;
}
a:hover {
border-bottom-color: var(--noir-amber);
}
.container {
max-width: 960px;
margin: 0 auto;
padding: 0 24px;
}
/* ---------- NAVIGATION ---------- */
nav {
background: var(--noir-bg-soot);
border-bottom: 2px solid var(--noir-bg-gunmetal);
position: sticky;
top: 0;
z-index: 100;
}
.nav-inner {
display: flex;
align-items: center;
justify-content: space-between;
max-width: 960px;
margin: 0 auto;
padding: 12px 24px;
}
.logo {
font-family: 'Press Start 2P', monospace;
font-size: 0.7rem;
color: var(--noir-amber);
text-decoration: none;
text-transform: uppercase;
letter-spacing: 0.12em;
text-shadow: 2px 2px 0 #080808;
border-bottom: none;
}
.logo:hover {
border-bottom: none;
}
.nav-links {
display: flex;
gap: 20px;
list-style: none;
}
.nav-links a {
font-family: 'Silkscreen', monospace;
font-size: 0.75rem;
color: var(--noir-text-secondary);
text-decoration: none;
text-transform: uppercase;
letter-spacing: 0.06em;
padding: 4px 0;
border-bottom: 2px solid transparent;
transition: color 0.2s, border-color 0.2s;
}
.nav-links a:hover,
.nav-links a.active {
color: var(--noir-amber);
border-bottom-color: var(--noir-amber);
}
/* ---------- HERO ---------- */
.hero {
position: relative;
min-height: 80vh;
display: flex;
align-items: center;
justify-content: center;
text-align: center;
padding: 80px 24px;
overflow: hidden;
}
/* Scan lines */
.hero::before {
content: '';
position: absolute;
inset: 0;
background: repeating-linear-gradient(
0deg,
transparent,
transparent 2px,
rgba(200, 192, 176, 0.015) 2px,
rgba(200, 192, 176, 0.015) 4px
);
pointer-events: none;
z-index: 2;
}
/* Venetian blind shadows */
.hero::after {
content: '';
position: absolute;
inset: 0;
background: repeating-linear-gradient(
0deg,
transparent 0px,
transparent 20px,
rgba(0, 0, 0, 0.3) 20px,
rgba(0, 0, 0, 0.3) 28px
);
transform: skewY(-5deg);
pointer-events: none;
z-index: 1;
opacity: 0.35;
}
.hero-content {
position: relative;
z-index: 3;
max-width: 680px;
}
.hero-content h1 {
font-size: clamp(1.2rem, 3.5vw, 2rem);
color: var(--noir-amber);
text-shadow: 3px 3px 0 #080808, 0 0 12px rgba(212, 160, 32, 0.2);
margin-bottom: 2rem;
}
.hero-content .tagline {
font-family: 'VT323', monospace;
font-size: 1.4rem;
color: var(--noir-text-secondary);
margin-bottom: 2.5rem;
max-width: 520px;
margin-left: auto;
margin-right: auto;
}
.btn {
display: inline-block;
background: transparent;
color: var(--noir-amber);
border: 2px solid var(--noir-amber);
padding: 12px 28px;
font-family: 'Press Start 2P', monospace;
font-size: 0.6rem;
letter-spacing: 0.08em;
text-transform: uppercase;
text-decoration: none;
cursor: pointer;
transition: background 0.15s, color 0.15s;
box-shadow: 4px 4px 0 var(--noir-bg-gunmetal);
}
.btn:hover {
background: var(--noir-amber);
color: var(--noir-bg-void);
box-shadow: var(--noir-glow-amber);
border-bottom-color: var(--noir-amber);
}
.btn:active {
transform: translate(4px, 4px);
box-shadow: none;
}
.btn--danger {
color: var(--noir-neon-red);
border-color: var(--noir-neon-red);
box-shadow: 4px 4px 0 var(--noir-bg-gunmetal);
}
.btn--danger:hover {
background: var(--noir-neon-red);
color: var(--noir-bg-void);
box-shadow: var(--noir-glow-red);
}
/* ---------- DITHERED DIVIDER ---------- */
.dither-divider {
height: 8px;
background-color: var(--noir-bg-void);
background-image:
linear-gradient(45deg,
var(--noir-bg-soot) 25%, transparent 25%,
transparent 75%, var(--noir-bg-soot) 75%),
linear-gradient(45deg,
var(--noir-bg-soot) 25%, transparent 25%,
transparent 75%, var(--noir-bg-soot) 75%);
background-size: 4px 4px;
background-position: 0 0, 2px 2px;
}
/* ---------- CASE FILES SECTION ---------- */
.case-files {
padding: 64px 0;
}
.case-files h2 {
font-size: 0.85rem;
color: var(--noir-text-primary);
margin-bottom: 8px;
}
.case-files .subtitle {
font-family: 'VT323', monospace;
font-size: 1.1rem;
color: var(--noir-text-secondary);
margin-bottom: 40px;
padding-bottom: 16px;
border-bottom: 1px solid var(--noir-bg-gunmetal);
}
.card-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
gap: 16px;
}
.card {
background: var(--noir-bg-soot);
border: 1px solid var(--noir-bg-gunmetal);
padding: 24px;
position: relative;
transition: border-color 0.2s;
}
.card:hover {
border-color: var(--noir-amber);
}
.card::before {
content: '';
position: absolute;
top: 4px;
left: 4px;
width: 8px;
height: 8px;
border-top: 2px solid var(--noir-amber);
border-left: 2px solid var(--noir-amber);
}
.card::after {
content: '';
position: absolute;
bottom: 4px;
right: 4px;
width: 8px;
height: 8px;
border-bottom: 2px solid var(--noir-amber);
border-right: 2px solid var(--noir-amber);
}
.card-label {
font-family: 'Silkscreen', monospace;
font-size: 0.7rem;
color: var(--noir-amber);
text-transform: uppercase;
letter-spacing: 0.1em;
margin-bottom: 12px;
}
.card h3 {
font-size: 0.65rem;
color: var(--noir-text-primary);
margin-bottom: 12px;
}
.card p {
font-size: 1.1rem;
color: var(--noir-text-secondary);
line-height: 1.6;
}
.card-status {
display: inline-block;
font-family: 'Silkscreen', monospace;
font-size: 0.65rem;
text-transform: uppercase;
letter-spacing: 0.06em;
padding: 4px 8px;
margin-top: 16px;
border: 1px solid;
}
.card-status--open {
color: var(--noir-neon-red);
border-color: var(--noir-neon-red);
}
.card-status--closed {
color: var(--noir-green);
border-color: var(--noir-green);
}
.card-status--cold {
color: var(--noir-rain-blue);
border-color: var(--noir-rain-blue);
}
/* ---------- NARRATIVE SECTION ---------- */
.narrative {
padding: 64px 0;
max-width: 640px;
margin: 0 auto;
}
.narrative h2 {
font-size: 0.85rem;
color: var(--noir-amber);
margin-bottom: 24px;
}
.narrative p {
margin-bottom: 1.5rem;
color: var(--noir-text-primary);
}
.narrative blockquote {
border-left: 3px solid var(--noir-amber);
padding-left: 20px;
margin: 24px 0;
color: var(--noir-text-secondary);
font-style: italic;
}
/* ---------- EVIDENCE TABLE ---------- */
.evidence {
padding: 64px 0;
}
.evidence h2 {
font-size: 0.85rem;
color: var(--noir-text-primary);
margin-bottom: 24px;
}
.noir-table {
width: 100%;
border-collapse: collapse;
font-family: 'VT323', monospace;
font-size: 1.1rem;
}
.noir-table th {
font-family: 'Silkscreen', monospace;
font-size: 0.65rem;
letter-spacing: 0.1em;
text-transform: uppercase;
color: var(--noir-amber);
text-align: left;
padding: 12px 16px;
border-bottom: 2px solid var(--noir-bg-gunmetal);
}
.noir-table td {
padding: 10px 16px;
color: var(--noir-text-primary);
border-bottom: 1px solid var(--noir-bg-gunmetal);
}
.noir-table tr:hover td {
background: rgba(212, 160, 32, 0.03);
}
/* ---------- CTA SECTION ---------- */
.cta {
text-align: center;
padding: 64px 24px;
position: relative;
}
/* Dithered background */
.cta::before {
content: '';
position: absolute;
inset: 0;
background-color: var(--noir-bg-void);
background-image:
linear-gradient(45deg,
var(--noir-bg-soot) 25%, transparent 25%,
transparent 75%, var(--noir-bg-soot) 75%),
linear-gradient(45deg,
var(--noir-bg-soot) 25%, transparent 25%,
transparent 75%, var(--noir-bg-soot) 75%);
background-size: 4px 4px;
background-position: 0 0, 2px 2px;
z-index: 0;
}
.cta > * {
position: relative;
z-index: 1;
}
.cta h2 {
font-size: 0.85rem;
color: var(--noir-neon-red);
text-shadow: 0 0 8px rgba(204, 34, 34, 0.3);
margin-bottom: 16px;
}
.cta p {
color: var(--noir-text-secondary);
margin-bottom: 2rem;
font-size: 1.2rem;
}
/* ---------- FOOTER ---------- */
footer {
border-top: 2px solid var(--noir-bg-gunmetal);
padding: 24px;
text-align: center;
}
.footer-inner {
max-width: 960px;
margin: 0 auto;
font-family: 'Silkscreen', monospace;
font-size: 0.65rem;
color: var(--noir-text-muted);
text-transform: uppercase;
letter-spacing: 0.08em;
}
.footer-inner .case-number {
color: var(--noir-fog);
}
/* ---------- NEON FLICKER ---------- */
@keyframes flicker {
0%, 19%, 21%, 23%, 25%, 54%, 56%, 100% {
opacity: 1;
text-shadow: 0 0 4px var(--noir-neon-red),
0 0 12px rgba(204, 34, 34, 0.4);
}
20%, 24%, 55% {
opacity: 0.7;
text-shadow: none;
}
}
.neon-flicker {
animation: flicker 4s infinite;
}
/* ---------- CRT VIGNETTE ---------- */
.vignette {
position: fixed;
inset: 0;
background: radial-gradient(
ellipse at center,
transparent 60%,
rgba(8, 8, 8, 0.5) 100%
);
pointer-events: none;
z-index: 9999;
}
/* ---------- RESPONSIVE ---------- */
@media (max-width: 768px) {
.hero {
min-height: auto;
padding: 48px 16px;
}
.nav-inner {
flex-direction: column;
gap: 12px;
}
.nav-links {
gap: 12px;
flex-wrap: wrap;
justify-content: center;
}
.card-grid {
grid-template-columns: 1fr;
}
.noir-table {
font-size: 1rem;
}
.noir-table th,
.noir-table td {
padding: 8px;
}
}
@media (max-width: 480px) {
.hero-content h1 {
font-size: 0.9rem;
}
.hero-content .tagline {
font-size: 1.1rem;
}
.btn {
padding: 10px 20px;
font-size: 0.5rem;
}
}
</style>
</head>
<body>
<!-- CRT Vignette Overlay -->
<div class="vignette"></div>
<!-- Navigation -->
<nav>
<div class="nav-inner">
<a href="#" class="logo">Shade City</a>
<ul class="nav-links">
<li><a href="#cases" class="active">Cases</a></li>
<li><a href="#narrative">Dispatch</a></li>
<li><a href="#evidence">Evidence</a></li>
<li><a href="#contact">Contact</a></li>
</ul>
</div>
</nav>
<!-- Hero Section -->
<section class="hero">
<div class="hero-content">
<h1>The rain never stops in this city</h1>
<p class="tagline">
Private investigations. Missing persons. Corporate secrets.
Every case has a price. Every shadow hides a story.
</p>
<a href="#cases" class="btn">Open case file</a>
</div>
</section>
<!-- Dithered Divider -->
<div class="dither-divider"></div>
<!-- Case Files Section -->
<section class="case-files" id="cases">
<div class="container">
<h2>Active case files</h2>
<p class="subtitle">
// Case archive -- Shade City Private Investigations
</p>
<div class="card-grid">
<div class="card">
<div class="card-label">Case #0041</div>
<h3>The Vanishing Witness</h3>
<p>
Key witness in the Mallory embezzlement case disappeared from
a locked apartment on 5th and Vine. No signs of forced entry.
Neighbors heard nothing but rain.
</p>
<span class="card-status card-status--open">Open</span>
</div>
<div class="card">
<div class="card-label">Case #0038</div>
<h3>Neon District Forgeries</h3>
<p>
Series of counterfeit documents circulating through the harbor
district. Paper stock traced to a decommissioned print shop
on Water Street.
</p>
<span class="card-status card-status--open">Open</span>
</div>
<div class="card">
<div class="card-label">Case #0035</div>
<h3>The Ashworth Letters</h3>
<p>
Anonymous letters threatening city councilwoman Ashworth.
Typewriter analysis matches a 1947 Remington. Only six
known registered owners remain in the city.
</p>
<span class="card-status card-status--cold">Cold</span>
</div>
<div class="card">
<div class="card-label">Case #0029</div>
<h3>Dockside Double Cross</h3>
<p>
Insurance fraud at the harbor. Cargo manifest discrepancies
point to systematic rerouting. Trail leads to the shipping
magnate's private office.
</p>
<span class="card-status card-status--closed">Closed</span>
</div>
</div>
</div>
</section>
<!-- Dithered Divider -->
<div class="dither-divider"></div>
<!-- Narrative Section -->
<section class="narrative" id="narrative">
<div class="container">
<h2>// Field Dispatch</h2>
<p>
The call came in at 2 AM. That is when they always come. Nobody
calls a private investigator during business hours -- those people
have lawyers. The ones who call at 2 AM have problems that lawyers
cannot fix.
</p>
<p>
She said her name was Marlowe. I did not ask if it was real. In
this line of work, you learn that names are just another kind of
shadow -- they look solid until the light shifts.
</p>
<blockquote>
"The city keeps its secrets in the spaces between streetlights.
You have to learn to read the dark."
</blockquote>
<p>
I took the case. I always take the case. The rent does not pay
itself, and curiosity is the only vice I have not managed to quit.
Three days later I was standing in the rain outside a warehouse on
the east side, watching a door that nobody was supposed to know
about.
</p>
</div>
</section>
<!-- Dithered Divider -->
<div class="dither-divider"></div>
<!-- Evidence Table -->
<section class="evidence" id="evidence">
<div class="container">
<h2>Evidence log</h2>
<table class="noir-table">
<thead>
<tr>
<th>Item</th>
<th>Type</th>
<th>Location</th>
<th>Status</th>
</tr>
</thead>
<tbody>
<tr>
<td>Matchbook (Club Paradox)</td>
<td>Physical</td>
<td>Apartment 4B</td>
<td>Logged</td>
</tr>
<tr>
<td>Typewritten letter fragment</td>
<td>Document</td>
<td>Waste bin, alley</td>
<td>Analysis pending</td>
</tr>
<tr>
<td>Photograph (dock, 3 subjects)</td>
<td>Photo</td>
<td>Hidden compartment</td>
<td>Identified (2/3)</td>
</tr>
<tr>
<td>Ledger pages (partial)</td>
<td>Financial</td>
<td>Print shop basement</td>
<td>Cross-referencing</td>
</tr>
<tr>
<td>Audio reel (conversation)</td>
<td>Recording</td>
<td>Office safe</td>
<td>Transcribed</td>
</tr>
</tbody>
</table>
</div>
</section>
<!-- Dithered Divider -->
<div class="dither-divider"></div>
<!-- CTA Section -->
<section class="cta" id="contact">
<h2 class="neon-flicker">Got a case?</h2>
<p>
Leave a message at the front desk. I will find you.
</p>
<a href="#" class="btn btn--danger">Make contact</a>
</section>
<!-- Footer -->
<footer>
<div class="footer-inner">
<p>
<span class="case-number">[Shade City Private Investigations]</span>
// Est. 1947 // All records confidential
</p>
</div>
</footer>
</body>
</html>
image-rendering: pixelated (or -ms-interpolation-mode: nearest-neighbor for IE) on all pixel art assets to prevent browsers from smoothing scaled-up sprites with bilinear filtering; sharp, blocky edges are essential to the aesthetic-webkit-font-smoothing: none and text-rendering: optimizeSpeed to ensure bitmap fonts render with hard pixel edges rather than sub-pixel anti-aliased curvesposition: fixed and pointer-events: none so it persists across scroll without interfering with interaction; use a radial-gradient from transparent center to dark edges@keyframes and do not require JavaScript, reducing load and maintaining the stripped-down aesthetic