- Repo scaffolding: .gitignore, .env.example, Makefile, docker-compose.yml, README.md, CHANGELOG.md, pre-commit config. - Three-service stack: api (Flask 3), db (postgres:16-alpine), front (nginx serving the Vite bundle). Named volumes metamorph_db + metamorph_evidence. - Backend skeleton: Flask app factory, JSON structured logging on stdout, GET /api/v1/health, multi-stage Dockerfile, pyproject.toml driven by uv, Pydantic Settings with secret guard rails (refuses to boot in non-dev with placeholders), APP_ENV gating. - Frontend skeleton: Vite + React 18 + TypeScript strict + TailwindCSS, RTOps design tokens from tasks/design.md, self-hosted JetBrains Mono / IBM Plex Sans via @fontsource, base UI primitives (Card/Tag/SectionHeader/FlowNode/ Button), home page wired to /api/v1/health. - Engine-agnostic Makefile: auto-detects docker or podman, picks the matching compose driver. Targets: up/down/build/rebuild/dev/lint/fmt/test/migrate/ seed-mitre/print-install-token/e2e/inspect-health. - Playwright suite: e2e/tests/m0-smoke.spec.ts (8 tests) + HTML + JUnit reports + traces on retry. - Docs: tasks/spec.md (finalized after Q&A), tasks/design.md, tasks/todo.md (14 milestones), tasks/testing-m0.md, tasks/lessons.md. DoD: make up + make health + make e2e all pass on podman 5.x (Fedora) and docker. TLS terminated by external reverse proxy (spec §6 NF-network). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
14 KiB
Design System — Red Team Operations Map
Reusable design spec extracted from kypvas.github.io/red-team-map/. Dark "operator briefing / terminal" aesthetic: information-dense, color-coded taxonomy, monospace-first, zero ornament.
1. Philosophy
- Dark, flat, terminal-inspired. No gradients, no drop shadows, no glows. Depth comes from 1px borders on slightly lighter card backgrounds.
- Information over decoration. Every visual element serves data density — cards, tags, colored borders, inline code.
- Color as taxonomy. 10 accent hues are not decoration — each one means a category (red = evasion/payload, cyan = lateral, purple = C2, etc.). Reuse hues consistently across projects so color carries meaning.
- Monospace as identity.
JetBrains Monofor everything structural (titles, labels, code, tags).IBM Plex Sansonly for prose body. - Comment-style section markers. Headings begin with
//— carries the "source code / operator notes" metaphor.
2. Color Tokens
All colors are declared as CSS custom properties on :root. Copy-paste verbatim:
:root {
/* Surfaces */
--bg: #0a0e1a; /* page background — deep navy-black */
--bg-card: #111827; /* card / panel background */
--border: #1e2d3d; /* default 1px border, separators */
/* Text */
--text: #94a3b8; /* default body copy (slate) */
--text-bright: #f8fafc; /* titles, emphasis */
--text-dim: #64748b; /* metadata, subtitles, arrow labels */
/* #475569 used inline for code comments */
/* Accent palette — each one maps to a category */
--red: #ef4444; /* evasion, payload, privesc, danger */
--orange: #f59e0b; /* access, credentials, AD, MOTW */
--yellow: #eab308; /* exfil */
--green: #10b981; /* phishing, social */
--cyan: #06b6d4; /* lateral movement, default code highlight */
--blue: #3b82f6; /* infrastructure, cloud */
--purple: #8b5cf6; /* C2, macOS, tooling */
--pink: #ec4899; /* injection */
--rose: #f43f5e; /* OPSEC, vishing */
--teal: #14b8a6; /* persistence, linux */
}
Usage pattern — tinted fills
Never use accent color as a solid background. Always as rgba(accent, 0.10–0.15) behind solid-colored text:
.tag.c2 { background: rgba(139, 92, 246, 0.15); color: var(--purple); }
.tag.cred { background: rgba(245, 158, 11, 0.15); color: var(--orange); }
code { background: rgba(6, 182, 212, 0.08); color: var(--cyan); }
code.vuln { background: rgba(239, 68, 68, 0.10); color: var(--red); }
code.tool { background: rgba(139, 92, 246, 0.10); color: var(--purple); }
3. Typography
Font stack
<link href="https://fonts.googleapis.com/css2?family=JetBrains+Mono:wght@300;400;500;600;700&family=IBM+Plex+Sans:wght@300;400;500;600&display=swap" rel="stylesheet">
JetBrains Mono— headings, labels, code, tags, navigation, anything structural.IBM Plex Sans— prose body only (<p>, card descriptions).- Weights used: Mono
300 / 400 / 500 / 600 / 700, Plex Sans300 / 400 / 500 / 600.
Scale
| Role | Family | Size | Weight | Extras |
|---|---|---|---|---|
| Page title (h1) | JetBrains Mono | 28px | 700 | letter-spacing: -0.5px |
| Subtitle | JetBrains Mono | 14px | 300 | color --text-dim |
| Section (h2) | JetBrains Mono | 18px | 600 | border-bottom: 1px var(--border), padding-bottom: 12px |
| Card title (h3) | JetBrains Mono | 14px | 600 | color --text-bright |
| Card sub-label | JetBrains Mono | 10px | 400 | letter-spacing: 0.5px, --text-dim |
| Section desc | JetBrains Mono | 12px | 400 | --text-dim |
| Body copy | IBM Plex Sans | 12px | 400 | line-height: 1.7 |
| Flow node | JetBrains Mono | 10px | 400 | |
| Arrow label | JetBrains Mono | 8px | 400 | --text-dim |
| Tag / pill | JetBrains Mono | 9px | 600 | text-transform: uppercase; letter-spacing: 1px |
| Inline code | JetBrains Mono | 10px | 400 | |
<pre> block |
JetBrains Mono | 11px | 400 | line-height: 1.7 |
| Footer | JetBrains Mono | 11px | 400 | --text-dim |
Global body
body {
background: var(--bg);
color: var(--text);
font-family: 'IBM Plex Sans', sans-serif;
padding: 40px 60px;
line-height: 1.6;
}
4. Layout & Spacing
- Container:
max-width: 1400px; margin: 0 auto; - Page padding:
40px 60px(desktop-first, no mobile breakpoints in the source) - Grid for card collections:
display: grid; grid-template-columns: repeat(auto-fill, minmax(420px, 1fr)); gap: 16px; - Section rhythm:
margin-top: 60px; margin-bottom: 30pxon section headers. - Separators: thin hairlines only —
border-top: 1px solid var(--border); margin: 40px 0. - Line-height: 1.6 globally, 1.7 inside cards and
<pre>blocks for dense technical content.
5. Components
5.1 Header / Hero
<header>
<h1>Red Team <span>Operations</span> <span class="acc2">Architecture</span> Map v1.1</h1>
<div class="subtitle">Comprehensive Operator Reference — From Infrastructure to Impact</div>
</header>
header { text-align: center; margin-bottom: 50px; }
header h1 { font: 700 28px 'JetBrains Mono'; color: var(--text-bright); letter-spacing: -0.5px; margin-bottom: 8px; }
header h1 span { color: var(--red); }
header h1 .acc2 { color: var(--purple); }
header .subtitle { font: 300 14px 'JetBrains Mono'; color: var(--text-dim); }
Pattern: white title with two coloured accent words (red + purple). Reuse
<span>to highlight 1–2 keywords only.
5.2 Section heading
<div class="section-header">
<h2><span>//</span> Operation <span class="red">Flow Chains</span></h2>
<p class="section-desc">End-to-end attack chains ...</p>
</div>
.section-header { margin-top: 60px; margin-bottom: 30px; }
.section-header h2 { font: 600 18px 'JetBrains Mono'; color: var(--text-bright);
padding-bottom: 12px; border-bottom: 1px solid var(--border); }
.section-header h2 span { color: var(--cyan); } /* the "//" marker */
.section-header h2 .red { color: var(--red); } /* + .green / .orange / .purple / .pink / .teal / .yellow / .blue */
.section-desc { font: 12px 'JetBrains Mono'; color: var(--text-dim); margin-top: 8px; }
Signature move: every h2 starts with a cyan
//followed by a plain word and one colored word — source-code comment vibe.
5.3 Detail card
.detail-card {
background: var(--bg-card);
border: 1px solid var(--border);
border-radius: 10px;
padding: 20px;
}
.detail-card h3 { font: 600 14px 'JetBrains Mono'; color: var(--text-bright); margin-bottom: 4px; }
.detail-card .card-sub { font: 10px 'JetBrains Mono'; color: var(--text-dim); margin-bottom: 12px; letter-spacing: 0.5px; }
.detail-card .card-body { font-size: 12px; line-height: 1.7; }
/* accent-border variants */
.border-red { border-color: var(--red) !important; }
.border-cyan { border-color: var(--cyan) !important; }
/* ... one class per accent */
Cards share identical chrome; they are distinguished solely by border color. That single accent ties card → category → tag → flow-node without repeating the hue anywhere else.
5.4 Tag / pill
.tag {
font: 600 9px 'JetBrains Mono';
text-transform: uppercase;
letter-spacing: 1px;
padding: 3px 8px;
border-radius: 4px;
display: inline-block;
margin-bottom: 8px;
margin-right: 4px;
}
.tag.c2 { background: rgba(139, 92, 246, 0.15); color: var(--purple); }
.tag.evasion { background: rgba(239, 68, 68, 0.15); color: var(--red); }
.tag.lateral { background: rgba(6, 182, 212, 0.15); color: var(--cyan); }
/* ... one class per category */
5.5 Flow node + arrow
Nodes chain horizontally in a flex row with thin SVG arrows between them.
.flow-block { margin-bottom: 18px; }
.flow-title { font: 600 12px 'JetBrains Mono'; margin-bottom: 10px; }
.flow-title.red { color: var(--red); } /* one per accent */
.flow-row { display: flex; align-items: center; gap: 4px; flex-wrap: wrap; padding: 10px 0; }
.flow-node {
background: var(--bg-card);
border: 1px solid var(--border);
border-radius: 6px;
padding: 8px 12px;
font: 10px 'JetBrains Mono';
color: var(--text);
white-space: nowrap;
flex-shrink: 0;
}
.flow-node.hl-red { border-color: var(--red); color: var(--red); }
.flow-node.hl-cyan { border-color: var(--cyan); color: var(--cyan); }
/* ... one per accent */
.flow-arrow { display: flex; flex-direction: column; align-items: center; flex-shrink: 0; }
.flow-arrow svg { width: 36px; height: 20px; }
.flow-arrow .arrow-label { font: 8px 'JetBrains Mono'; color: var(--text-dim); margin-top: -2px; }
Arrow SVG template (inline, stroke colour = destination-node accent):
<svg viewBox="0 0 36 20">
<line x1="0" y1="10" x2="31" y2="10"
stroke="#10b981" stroke-width="1.5"
marker-end="url(#arrowG)"/>
</svg>
5.6 Data-flow / code card
.data-flow-card {
background: var(--bg-card);
border: 1px solid var(--border);
border-radius: 10px;
padding: 24px;
margin-bottom: 20px;
}
.data-flow-card h4 { font: 600 13px 'JetBrains Mono'; color: var(--text-bright); margin-bottom: 12px; }
.data-flow-card pre { font: 11px 'JetBrains Mono'; line-height: 1.7; color: var(--text-dim); overflow-x: auto; }
.data-flow-card pre .key { color: var(--cyan); font-weight: 600; }
.data-flow-card pre .val { color: var(--text-bright); }
.data-flow-card pre .type { color: var(--blue); }
.data-flow-card pre .comment { color: #475569; font-style: italic; }
.data-flow-card pre .danger { color: var(--red); font-weight: 600; }
Pseudo-syntax-highlighting via
<span class="key|val|type|comment|danger">inside<pre>blocks — mimics an IDE theme without a real parser.
5.7 Inline code
code { font: 10px 'JetBrains Mono'; padding: 2px 6px; border-radius: 3px;
background: rgba(6, 182, 212, 0.08); color: var(--cyan); }
code.vuln { background: rgba(239, 68, 68, 0.10); color: var(--red); }
code.tool { background: rgba(139, 92, 246, 0.10); color: var(--purple); }
5.8 List inside card
.card-list { list-style: none; padding: 0; }
.card-list li { padding: 3px 0; border-bottom: 1px solid rgba(255, 255, 255, 0.03); }
Near-invisible divider (
rgba(255,255,255,0.03)) — rhythm without visual noise.
5.9 Footer
footer {
text-align: center;
margin-top: 60px;
padding: 30px 0;
border-top: 1px solid var(--border);
font: 11px 'JetBrains Mono';
color: var(--text-dim);
}
6. Borders, Radii, Elevation
| Element | Radius | Border |
|---|---|---|
| Detail card | 10px | 1px solid var(--border) or accent |
| Data-flow card | 10px | 1px solid var(--border) |
| Flow node | 6px | 1px solid var(--border) or accent |
| Tag | 4px | none |
| Inline code | 3px | none |
- No
box-shadowanywhere. - No gradients. Surfaces are flat hex fills.
- Depth cue = border on a
#111827panel over a#0a0e1abackground. That's the whole elevation system.
7. Motion
The stylesheet defines no transitions, no hovers, no animations. Static document. If you add motion in derivative work, keep it restrained: ~120 ms fades on border-color at most. Don't introduce scale, shadow, or glow effects — they'd break the briefing aesthetic.
8. Iconography
No icon font, no Lucide/Heroicons. All pictograms are inline SVG arrows with stroke-width: 1.5 and <marker-end> arrowheads, one per accent color. Tags replace icons: [C2], [EVASION], [LATERAL] carry the same recognition load.
If icons are ever added, use a thin (1.5px) monochrome line set (e.g. Lucide strokeWidth={1.5}) and color them with accent vars.
9. Reusable Starter Template
Drop-in <head> + body baseline for a new project in this style:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Project Name</title>
<link href="https://fonts.googleapis.com/css2?family=JetBrains+Mono:wght@300;400;500;600;700&family=IBM+Plex+Sans:wght@300;400;500;600&display=swap" rel="stylesheet">
<style>
:root {
--bg: #0a0e1a; --bg-card: #111827; --border: #1e2d3d;
--text: #94a3b8; --text-bright: #f8fafc; --text-dim: #64748b;
--red:#ef4444; --orange:#f59e0b; --yellow:#eab308; --green:#10b981;
--cyan:#06b6d4; --blue:#3b82f6; --purple:#8b5cf6; --pink:#ec4899;
--rose:#f43f5e; --teal:#14b8a6;
}
* { margin: 0; padding: 0; box-sizing: border-box; }
body { background: var(--bg); color: var(--text); font-family: 'IBM Plex Sans', sans-serif; padding: 40px 60px; line-height: 1.6; }
.container { max-width: 1400px; margin: 0 auto; }
</style>
</head>
<body>
<div class="container">
<header>
<h1>Project <span style="color:var(--red)">Name</span> <span style="color:var(--purple)">Subtitle</span></h1>
<div class="subtitle">One-line mission statement</div>
</header>
<!-- sections with <h2>// Section <span class="red">Name</span></h2> ... -->
</div>
</body>
</html>
10. Checklist for "Does this match the style?"
- Background
#0a0e1a, cards#111827, borders#1e2d3d. - JetBrains Mono for structure, IBM Plex Sans for prose.
- Every section
<h2>starts with a cyan//. - Exactly one accent hue per category, reused across border + tag + code + flow node.
- Accent backgrounds are tinted (
rgba(accent, 0.10–0.15)), never solid. - Zero shadows, zero gradients, zero rounded > 10px.
- Tags are 9px uppercase mono with 1px letter-spacing.
- Container capped at 1400px, page padded
40px 60px. - No hover animations beyond border-color if any at all.