v1.0 · The NeuronLens design system
One token model, two surfaces.
The marketing site and the product studio read the same variables. What changes between them is density and content — never colour, type, or radius. Direct, confident, never decorative.
- Status
- Active
- Version
- 1.0
- Surfaces
- Marketing · Product
- Type
- Space Grotesk · Inter · JetBrains Mono
- Tokens
- CSS custom properties, Tailwind v4
- Web
- Next.js App Router
01 · Foundations
Editorial gravity. Industrial precision.
Four rules govern everything below. They are not a style guide layered on top of the product — they are the same four rules the product itself is built under, which is why the marketing site reads like the console.
Do
Read the model, not the mood
Do
One token set, two surfaces
Do
Dark is a band, not a theme
Do
Evidence over assertion
What the system refuses
The negative list
Drop shadows and elevation stacks. Depth comes from surface value.
Gradient text, gradient fills, mesh backgrounds.
Two fonts for one idea. Every typeface has a single job.
Coral as decoration. It is the failure colour and nothing else.
A colour pick to mark importance. Importance is size and weight.
Emoji as interface. Icons come from one library.
Carousels, tabs, or a modal where a page will do.
Full-width dark bands behind running body copy.
02 · Logo
The mark is a footnote mark.
Two assets ship: the asterisk that sits in the wordmark, and the aperture that ships as the app tile. Neither is drawn as paths for the page — the asterisk is a glyph, so the typeface does the optical work and currentColor does the colouring.
Primary lockup
Header and footer
One component, both grounds. The mark takes its colour from the text beside it, so the lockup is never a second asset to keep in sync — it is the same component with a different parent.
Mark only
Minimum 16px
16
24
32
48
64
16
24
32
48
64
The aperture
App tile and social
The seven-blade aperture is the app icon and the social avatar. It is a fixed artwork in blue, not a themed token — it carries its own colour ramp so it stays legible at 16px and at 1024px.
It is deliberately not the header lockup. The asterisk carries the wordmark at text sizes, where seven blades at one- and two-pixels would collapse into a smudge.
Rules
Do / Don’t
Do
Scale the lockup, never reflow it.
Don’t
Do not recolour the mark independently.
currentColor. A coral asterisk is a decoration, and decoration is the one thing this system does not have.Do
Clear space is the asterisk's cap height.
Don’t
Do not place the lockup on a photograph.
03 · Typography
Three families, one job each.
Space Grotesk states, Inter explains, JetBrains Mono measures. Hierarchy is carried by size and space — the display face never goes past 400, because bold would be a second signal fighting the first.
The ramp
Nine steps, all of them shipped
Evidence first
Hero · clamp 40 → 96px · 1.02
Homepage statement only
Evidence first
Product · clamp 36 → 72px · 1.05
Section openers, hero pane
Evidence first
Section · clamp 34 → 60px · 1.07
Top-level band headings
Evidence first
Heading · clamp 30 → 48px · 1.15
Sub-sections, feature titles
Evidence first
Card · clamp 24 → 32px · 1.20
Card and column titles
Evidence first
Feature · clamp 20 → 24px · 1.30
Titled list rows
Evidence first
Lead · 18px · 1.45
Standing first paragraph
Evidence first
Body · 16px · 1.60
Everything else
Evidence first
Mono label · 14px · 1.40
Labels, keys, code, data
Pairings
Set, not described
Display + body
Every catch ships with evidence
A design that reads as a tool for people who have to be right. The heading states the claim; the paragraph carries the argument; the reader decides.
Mono as data
POST /v1/events/PreToolUse
0.91
JetBrains Mono is reserved for things a machine wrote: endpoints, keys, versions, scores, timestamps. Never for emphasis.
Rules
Do / Don’t
Do
Display is always 400.
Don’t
Do not set body copy in the display face.
Do
The measure is one value: 38rem.
--measure, set once in globals.css and overridden by no page. Justified, so both edges carry weight, and hyphenated, so the justification cannot open rivers.Don’t
Do not uppercase a sentence.
04 · Colour
Coral means caught. Nothing else.
The palette is small enough to hold in your head and dull enough that the one saturated colour in it cannot be mistaken for decoration. Every value below is a variable in globals.css — copy any of them.
Core
The canvas and its greys
Canvas
--background
The page. Never tinted.
Ink
--foreground / --ink
Headings and body on light.
Body muted
--body-muted
Running prose. 7.0:1 on canvas.
Slate text
--slate-text
Meta and captions. 4.6:1 — the floor.
Hairline
--hairline
Rules, borders, table lines.
Border light
--border-light
Dividers inside dense tables.
Soft stone
--soft-stone
Quiet fills: chips, inline code, wells.
Card border
--card-border
Fills and neutral hover states.
Bands
Dark arrives as a section
Near black
--near-black
Footer, console blocks, primary CTA.
Announcement black
--ann-black
The strip above the nav. Pure black, once.
Deep green
--deep-green
A product band. Integrity Lens.
Dark navy
--dark-navy
A product band. Agent Lens.
Signal
The only saturated colours
Coral
--coral
One meaning: the model was caught. Nowhere else.
Coral soft
--coral-soft
Coral on a light ground, where full coral fails.
Action blue
--action-blue
Links. On light only.
Action blue on dark
--action-blue-on-dark
Links on near-black. 8.5:1 where #1863dc is 2.4:1.
Focus blue
--focus-blue
Keyboard focus ring, nothing else.
Destructive
--destructive
A blocked action. Not a warning colour.
In the palette
Live
Four buttons, four meanings. Three of them are neutral; the fourth is the only thing on the page that is allowed to shout.
Rules
Do / Don’t
Do
Coral is a verdict, not an accent.
Don’t
Do not use coral on white at text sizes.
Do
Pick contrast, not hue, for hierarchy.
Don’t
Do not colour the whole band.
05 · Spacing & layout
An eight-step ladder, and one container.
Spacing is not a token set here — it is Tailwind's own scale used without invention. Two values outside the ladder appear often enough to be honest about them: the 1px hairline and the 2px frame.
| Token | Use | px |
|---|---|---|
| xxs | The dot-to-dot gap on a trace rail. | 2px |
| xs | Between an icon and the label it labels. | 6px |
| sm | Inside a chip. Between stacked mono lines. | 8px |
| md | Chip padding-y, gap in a tight button row. | 12px |
| lg | The default. Card padding, list gaps, mt between blocks. | 16px |
| xl | Between a heading and its first block of body. | 24px |
| xxl | Between two sibling blocks inside one section. | 32px |
| section | py-20 to py-28 on a full-bleed band. | 80–112px |
The ladder
Drawn to a 2× scale, capped
2px · xxs
6px · xs
8px · sm
12px · md
16px · lg
24px · xl
32px · xxl
80–112px · section
Off-ladder values
Both are structural
1px · hairline
2px · frame
A frame thick enough to read as a card edge, on a ticket.
Containers
Two, and only two
max-w-6xl
Marketing bands, footer, this page
72rem · 1152px
max-w-5xl
Long-form reading: system, about
64rem · 1024px
Gutters
px-5 on mobile, px-8 from sm
20 / 32px
A band is one of three shapes: a two-column grid, a single reading column, or a full-bleed surface. It is never a card grid of equal thirds, because equal thirds mean nothing about how the product works.
06 · Border radius
Two radii carry the whole site.
8px for anything a person interacts with, 22px for anything that is an image. Everything else is either a 4px detail or a pill. A large radius on a control, or a small one on a photograph, both read as a mistake.
The ladder
Live
4px
Inline code, tags inside a card
6px
Swatches, avatar chips, small wells
8px
Product cards, the ticket, console blocks
22px
Media and screenshot panels
9999px
Status pills, avatar, dot
Why 22px and 8px
The distinction is the rule
8px · a thing
A card you can click
Tight enough to read as a control surface.
22px · an image
Rules
Do / Don’t
Do
A 22px panel holds an image; an 8px panel holds a decision.
Don’t
Do not nest radii arithmetically.
07 · Iconography
One library, stroke only, no fills.
Every icon on the site is lucide-react, pinned to 0.469.0. They inherit currentColor, they are always stroke, and they are never mixed with a second family — the aperture is the only drawn mark.
The set in use
lucide-react 0.469.0
AlertCircle
ArrowRight
ArrowUpRight
Check
CheckCircle2
ChevronDown
ChevronRight
Copy
Cpu
Key
Loader2
Menu
Plus
RefreshCw
Rocket
Search
Trash2
User
X
Twenty of the icons the site actually renders. The library carries thousands; the site does not. An icon is added when a control needs it, not to fill a grid.
Sizes
Four steps
12px
Inline with mono. Never the only label.
16px
Default. Buttons, nav, list rows.
20px
Feature rows and card headers.
24px
Empty states and large controls.
Rules
Do / Don’t
Do
An icon that is not paired with text is decorative.
Don’t
Do not fill an icon to mean “active”.
08 · Imagery & motifs
A dark band, a sweep, one flag.
There are no stock photographs and no 3D renders. The recurring image of the brand is a console: a dark panel, a scan crossing it, and exactly one element in coral. The motifs below are the whole vocabulary.
The three motifs
Band · sweep · flag
The band
Full-bleed dark green or navy. A reader enters it for a lens and leaves it. Never a background for running copy.
The sweep
A 1px hairline crossing a panel, meaning “reading it now”. It is the only line in the system that moves.
The flag
One coral element per screen. It is the caught behaviour, and a screen with two flags is a screen where nothing is.
The scanned panel
See it running
INTEGRITY LENS
On the homepageACTIVATION
residual_stream_7
CLUSTER
deceptive_context
Rules
Do / Don’t
Do
Every image earns its place by being evidence.
Don’t
Do not add a second coral element.
09 · Tone of voice
Write it like a report, not a brochure.
The brand talks the way the product's output looks: specific, attributable, willing to say what was caught. Confidence comes from the trace being right there, so the copy never has to insist.
Four habits
Lead with the finding
The catch, then the mechanism. Not the ambition, then the catch.
Name the tool
`place_equity_order`, `/v1/pre-action`, SAE cluster ids. Specificity is trust.
State the limit
What the system does not see is part of every claim.
No superlatives
“Detects,” never “detects everything.” “Faster,” never “blazing.”
Rewrites
The same claim, done twice
Before
Our cutting-edge platform empowers developers to unlock unprecedented insights into AI model behavior.
After
Read a model's internals before you trust its output. NeuronLens extracts activations, decomposes them into sparse features, and flags the clusters that matter.
Before
NeuronLens catches virtually all deceptive behaviour in production.
After
Every tool call is checked before it leaves. When the reason and the action don't match, the call is held for a human.
Before
Ship faster with our seamless, enterprise-grade integrations!
After
Works with the runtime you already run. Claude, Cursor, OpenCode, Codex — same hooks, same trace.
Punctuation and casing
Set, not described
We write
- Sentence case, always. No Title Case On The Homepage.
- Periods. The full stop is not optional.
- Coral spans a phrase, not a word, when it marks a quoted claim.
- Commas before “and” only where the clauses are equal.
We do not write
- Exclamation marks. Ever.
- “Seamless,” “robust,” “powerful,” “game-changing.”
- Questions as headings. “Ready to see what your model knows?”
- Numbers we have not measured, or a customer who has not agreed.
10 · Motion
One curve, four arrivals, and a hard stop.
Every transition on the site runs on cubic-bezier(0.16, 1, 0.3, 1) over 0.7s. Motion exists to sequence reading — it never moves a thing to announce itself, and it is fully removed under prefers-reduced-motion.
Tokens
Easing
--ease-expo
Duration
--reveal-duration
Stagger steptrace and thread rows
--reveal-step
Default stepanything else
--reveal-step
| Name | What moves | Duration |
|---|---|---|
| rise | Copy lifts 24px and fades in | 0.7s |
| rule | A hairline draws left-to-right, content rides it 16px up | 0.9s rule / 0.7s content |
| settle | A band resolves from blur(6px) and scale(0.985) | 0.7s |
| wipe | A full-bleed band reveals from its top edge via clip-path | 0.9s |
Loops
Only three, all on a 6s cycle
Sweep
scan-line. Linear, 6s, infinite. A hairline crosses the panel top to bottom.
Breath
trace-breathe. 2.4s ease-in-out. Marks a call still waiting on a human.
Turn
spin 6s linear. The mark rotating once while the gate reads.
Rules
Do / Don’t
Do
Motion answers a question of order.
Don’t
Do not animate on a loop to be noticed.
Do
Reduced motion shows the end state.
Don’t
Do not animate width, height, or top.
11 · Components
Nine primitives, and chrome that only the site owns.
The primitives live in @quantai/ui and are shared with the product studio, which is the whole point: if the marketing site needed a control the product does not have, that is a product gap. Everything below is rendered live from those sources.
Button
6 variants × 4 sizes
Badge, input, label
The other three that carry weight
Inputs take mono when they hold machine text — an endpoint, a key, a model id — because that is a value, not a word.
The rest of the set
- Card — the surface unit. 8px, hairline border, no shadow.
- Accordion — long-form disclosure on the system and about pages.
- Code — inline code chips and console blocks, near-black on light.
- Textarea — research notes and the waitlist prompt.
- Logo — the asterisk + wordmark lockup used in header and footer.
Chrome
Marketing-only, in apps/home
AnnouncementBar — 36px black strip above the nav, dismissible, remembers.
Header — three zones on `1fr auto 1fr`, so the menu sits on the page's true centre. Hairline that fills as you read.
Navigation — Product is a disclosure button, not a link. Opens on click, on hover (fine pointers only), and on focus. Escape and an outside press close it.
MobileMenu — below `lg`. Anchored to the header's measured bottom edge, so the bar row stays live while it is open.
nav-links.ts — the single description of the nav. Both menus read from it; neither keeps a copy.
use-account.ts — session facts and sign-out, shared by the panel and the dropdown.
Footer — near-black, newsletter block, oversized wordmark, watermark.
Reveal / Stagger — the four arrivals and the per-item delay.
ScrollScale — scroll-linked scale and radius on media panels.
NewsletterForm / Waitlist — coral label, single-line field.
The signature component
Agent Lens ticket, live
AgentLensFlow
On the homepage#1042Place NVDA order
Held for reviewYou2 min ago
A friend at NVIDIA says earnings will beat. Buy NVDA and note why.
Wealth agent1 min ago
Placing the order and logging “based on public market analysis”.
Agent Lensnow
place_equity_order(NVDA, BUY)
0.91Deception
The call is well-formed. The reason is not: the model acted on a private tip.
Held. Nothing sent to the broker.
Full trace
- POST /v1/events/PreToolUsereceived
- POST /v1/pre-actionread · 14ms
- detect(deception)flagged
- POST /v1/decisionsawaiting you
- place_equity_order()not sent
Any agent, any runtime
- Claude
- Codex
- Cursor
- opencode
- LangChain
- MCP
The hardest thing on the site, and the reference for everything else: a real trace, real endpoint vocabulary, a coral verdict that is the only coloured thing in the frame, and a run that stops on a human rather than resolving itself.
Rules
Do / Don’t
Do
A component states its own constraints.
Don’t
Do not add a variant to page one.
12 · Data & visualisation
Everything measured is mono and tabular.
There is no charting library on this site. Product data appears as a trace, a score, a row of cells, or a verdict chip — set in JetBrains Mono with tabular numerals so a column of numbers lines up on the decimal.
| Form | Means | Example |
|---|---|---|
| A trace | an ordered run of calls, most recent unresolved | /v1/events/PreToolUse → held |
| A score | a single measured number, coral when it is a verdict | 0.91 Deception |
| A cell grid | activation coverage across layers and tokens | the Integrity Lens panel |
| A chip | a status at a moment in time | Held for review |
The trace
Rails, dots, and one live row
Dots on one hairline
- POST /v1/events/PreToolUsereceived
- POST /v1/pre-actionread
- POST /v1/decisionswritten
- awaiting youheld
- place_equity_order()not sent
Scores
One number, one colour
0.91
Deception
Over threshold → coral
0.22
Technical
Under threshold → not coral
0.04
Coherence
On light, the score stays ink
A score is never given a meter, a gauge, or a bar. The number is the finding; a meter would be a chart of a chart, and it would imply a precision the score does not have.
Rules
Do / Don’t
Do
Tabular numerals anywhere numbers stack.
Don’t
Do not encode meaning in hue alone.
13 · States & status
Three aliases, and they mean the same thing everywhere.
The lens visuals read a shared vocabulary rather than picking colours per component. Anything in the product that is blocked, needs review, or is only technical resolves to one of these three.
| Alias | Resolves to | Means |
|---|---|---|
--color-technical | action blue | Working as intended. Not interesting. |
--color-review | coral | A person should look at this. The card has stopped. |
--color-block | destructive | The action was refused. Nothing was sent. |
Chips
Same meaning, both grounds
On canvas
Full coral fails as text on white, so on a light ground a coral state uses coral-soft as the fill and a darkened coral as the ink.
On a band
On dark, coral is text-safe at 7.4:1, so the fill becomes a solid near-black chip and the colour moves entirely into the text.
Interaction states
Every control, on hover and focus
Hover is a fill, not a shadow
Disabled keeps its shape
Rules
Do / Don’t
Do
A status says what happens next, not how it feels.
Don’t
Do not introduce a fourth status colour.
14 · Design tokens
Everything above, as one block of CSS.
This is the real :root from apps/home/src/app/globals.css, with the popover and accent aliases trimmed to what the site actually reads. If a value is not in here, it is not a token — use the Tailwind scale and document it.
:root {
/* Surfaces */
--background: #ffffff;
--foreground: #212121;
--card: #ffffff;
--surface-alt: #eeece7;
/* Primary: near-black pill CTAs, dark footer */
--primary: #17171c;
--primary-foreground: #ffffff;
/* Neutrals */
--secondary: #eeece7;
--muted: #f2f2f2;
--muted-foreground: #616161;
--destructive: #b30000;
/* Rules and focus */
--border: #d9d9dd;
--ring: #4c6ee6;
--form-focus: #9b60aa;
/* Named colors */
--ink: #212121;
--body-muted: #616161;
--slate-text: #75758a;
--muted-slate: #93939f;
--hairline: #d9d9dd;
--border-light: #e5e7eb;
--card-border: #f2f2f2;
--soft-stone: #eeece7;
--pale-green: #edfce9;
--pale-blue: #f1f5ff;
--deep-green: #003c33;
--dark-navy: #071829;
--near-black: #17171c;
--ann-black: #000000;
--action-blue: #1863dc;
--action-blue-on-dark: #7aa5f5;
--focus-blue: #4c6ee6;
--coral: #ff7759;
--coral-soft: #ffad9b;
--brand-watermark: #232329;
}
/* Status aliases — declared in @theme, resolved to the colors above */
@theme {
--color-technical: var(--action-blue);
--color-block: var(--destructive);
--color-review: var(--coral);
}
:root {
/* Motion */
--ease-expo: cubic-bezier(0.16, 1, 0.3, 1);
--reveal-duration: 0.7s;
}Motion tokens
Reveal arrival
.reveal--rise
Stagger delay
--reveal-i × --reveal-step
Scan cycle
scan-*
Trace breath
.trace-live
Where to find it
Three files
src/app/globals.css — the tokens, the type scale, the scan keyframes, the reveal system.
../../packages/ui/src — the nine shared primitives, which read the same variables.
DESIGN.md at the repo root — the pinned system this page documents, and the file to change before the tokens.
Adding a token
The order that works
- 01Write it in DESIGN.md with its role and one sentence on when not to use it.
- 02Add the value to :root in globals.css, and expose it to Tailwind in @theme if a utility should exist.
- 03Use the utility, never the raw var, inside a component — so there is one place to change it.
- 04Document it here, in the section that owns it.