The cognitive overlay, in CSS terms
The game's interface is not a HUD skin — it is Vann's cognitive overlay, drawn as chamfered navy glass over a signal-blue grid. This page states the visual system as design tokens and CSS, exactly as it ships. This site's own stylesheet uses the same variables, so every demo below is rendered live.
Color tokens
Six base tokens carry the whole interface. Everything else is derived by mixing or fading them.
Derived tokens are alpha fades of the base set:
--rail: rgba(131, 195, 255, 0.55); /* signal @ 55% — the 1px outline everywhere */
--grid-major: rgba(131, 195, 255, 0.11); /* signal @ 11% — 64px grid lines */
--grid-minor: rgba(131, 195, 255, 0.05); /* signal @ 5% — 16px grid lines */
--muted-ink: rgba(208, 208, 208, 0.50); /* nav-ink @ 50% — footnotes, version tags */
--steel-rail: #B5CBE0; /* color-mix(in srgb, var(--nav-ink) 65%, var(--signal)) */
Color semantics — four voices
- SIGNAL CYAN — the overlay's own voice. Structure, rails, headers, anything active or hovered.
- ONLINE GREEN — confirmation. Systems online, success, credits, a pressed button.
- CASSIUS ORANGE — reserved. Only CASSIUS speaks in orange, so the companion can annotate the interface without appearing to own it.
- FOLD PERIWINKLE — exotic. Marks fold-drive tech and nothing mundane.
The reservation rule is the point: a color that can mean anything means nothing. Orange on this screen is always someone talking to you from outside.
Typography
Three working faces plus one reserve, each with one job:
Asimovian — display, titles onlyVINDICATOR // COGNITIVE OVERLAY
Geist — body copyThe gates are dark. Fold anyway. Body text is the only lowercase voice in the interface.
JetBrains Mono — data, headers, buttons (uppercase, letter-spaced)FOLD CHARGE 87% · HULL 100 · CREDITS 4,210
Doto — reserved numeric face (in repo, unused by the HUD yet)00:42:17
The in-game size ladder, in px — one source of truth, top to bottom:
| Step | px | Used for |
|---|---|---|
| display | 30 | screen titles (Asimovian) |
| dialog title | 26 | pause / codex / gallery dialogs |
| panel title | 22 | large panel headings |
| subheader | 16 | section headers |
| body | 14 | default text (Geist) |
| mono | 13 | mono body labels |
| data | 12 | telemetry values, buttons, chips |
| header | 11 | section kickers, CASSIUS comms |
| muted | 10 | footnotes |
| label | 9 | version tags, map labels |
| micro | 8 | map controls, legends, nameplates |
Shape — chamfer, never radius
Every surface cuts its corners at 45°. There is no border-radius anywhere in the language — on the web the cut is a clip-path octagon:
clip-path: polygon(
var(--c) 0, 100% 0,
100% calc(100% - var(--c)), calc(100% - var(--c)) 100%,
0 100%, 0 var(--c)
);
The cut size is per surface class:
Around every cut runs a 1px rail (--rail, signal @ 55%) — with one deliberate split: panels, tooltips and chips close the octagon (the rail follows the diagonals), while buttons leave the corners open (the rail skips the four 45° segments). In CSS that falls out of border + clip-path for free; in-game ChamferStyleBox.OpenCorners does the same. Below 900px viewport the panel chamfer drops to 8px.
Glass panel anatomy
This panel is the live recipe: navy gradient glass, a 1px highlight under the top edge, always-on scanlines, and a rail that shifts to signal on hover.
Four layers, bottom to top:
- Fill — vertical 2-stop gradient of panel navy, top stop lightened:
linear-gradient(180deg, rgba(14,24,38,.90), rgba(7,13,20,.95)). - Highlight — one 1px line just under the top edge at
rgba(214,228,238,.10). - Scanlines —
repeating-linear-gradient(0deg, rgba(131,195,255,.04) 0 1px, transparent 1px 3px). Always on, never animated. Chips skip them (noise at that size). - Rail — 1px
--railborder,--signalon hover.
Panels sit on a signal-tinted grid substrate — 16px minor lines at 5%, every fourth line (64px) major at 11%:
One decorative motion is allowed: a slow additive signal-tinted shimmer band travelling top to bottom (~20s per pass, 10% alpha). It never strobes, and it opts in per surface.
Buttons — the 3-state model
The game button (glass variant above — hover and press it) is a semantic three-state machine, not a brightness tween. Each state changes rail, label, and fill together:
| State | Rail (1px, @90%) | Fill = mix(bg-deep, rail color, w) | Label |
|---|---|---|---|
| rest | --steel-rail | w=10%, alpha .80 | --nav-ink |
| hover / focus | --signal | w=18%, alpha .85 | --signal |
| pressed | --online | w=24%, alpha .92 | --nav-ink |
The resting rail is deliberately desaturated steel — mix(nav-ink, signal 35%) — so the cyan hover reads as a clear step up, and the green press reads as commitment. The fill keeps the glass gradient (top stop lightened 6%) and the 3px scanlines at 3% in every state. Text is JetBrains Mono, uppercase, letter-spaced; padding 14×9px around a 12px label in-game.
.btn-glass { /* rest */
color: var(--nav-ink);
border: 1px solid rgba(181, 203, 224, 0.9); /* steel-rail @ 90% */
background: linear-gradient(180deg,
rgba(38, 44, 52, 0.80), /* mix(bg, steel, 10%), lightened 6% */
rgba(24, 30, 39, 0.80));
}
.btn-glass:hover, .btn-glass:focus-visible {
color: var(--signal);
border-color: rgba(131, 195, 255, 0.9);
background: linear-gradient(180deg,
rgba(43, 57, 73, 0.85), rgba(29, 44, 61, 0.85));
}
.btn-glass:active {
color: var(--nav-ink);
border-color: rgba(0, 230, 118, 0.9);
background: linear-gradient(180deg,
rgba(20, 75, 55, 0.92), rgba(5, 64, 42, 0.92));
}
The solid green .btn-primary is a site-only marketing CTA; in-game, green is a state, not a button style.
Chips
Chips are the smallest surface: 6–8px chamfer, mono caps at 11px with 2px letter-spacing, accent-tinted fill at ~6%, accent rail — and no scanlines. Accent color follows the voice rules above.
Provenance
Authoritative source is the game code: common/UiThemeTokens.cs (tokens, size ladder, state tables) and common/ChamferStyleBox.cs (the chamfered-glass draw model). The Godot theme resource vindicator_theme.tres is only an editor preview mirror — it is normalized from these tokens at startup. This site's vindicator.css mirrors the same values 1:1.