The mark, the surfaces, the palette, the type. Every value below is resolved out of the live stylesheet when the page loads, so the kit cannot quietly disagree with the app it documents. Use it for partner integrations, press and ecosystem work — and don’t redraw, recolour or repurpose it.
[ 01 — the mark ]
One scope. Two lockups.
A ring, four cardinal ticks, a vermillion centre dot. The ring and ticks inherit currentColor; only the dot and the .exchange suffix are pinned to tokens, so the mark flips with its surface instead of needing a second file for dark.
snipe.exchange
lockup · wordmark + domain
snipe.
lockup · wordmark + accent period
clearspace · 1u = 24px at 96 · one tick length
22 · 32 · 48 · inline cuts96 · standard
snipe.
on cream · the light ground
snipe.
on coal · the dark ground
[ 02 — the surfaces ]
Two axes, not one.
data-theme on the document is global and belongs to the reader. data-surface on any wrapper is local and belongs to the layout. The second one is theme-dependent, which is the part people get wrong: under light, contrast is a full inversion to coal; under dark it is one elevation step, because a cream band inside a dark app is a bug, not a band.
no attribute
Whatever the reader's theme resolves to. This is the page's own ground.
All 28 colour tokens, declared six times over — once per palette and surface block. Three of those declarations are duplicates of another, so the system has three distinct value sets, and the table below is grouped that way rather than flattened to one column. Every token except --focus is also published to Tailwind as --color-<name>, so bg-, text- and border- utilities are available for it. Reach --focus through var() instead.
Values are read out of the live stylesheet on load, not transcribed, and each chip is painted from the same custom property its value was read from. Translucent tokens are shown over --paper of their own block — an alpha without its ground is not a colour. The hairline around each chip is that block’s --rule-2, so near-transparent tokens still read as a rectangle. Click a token name to copy it.
The three columns hold in either theme, but the two light surface blocks cannot be read from a dark document at all: an element carrying data-surface matches both its own block and the one keyed on the document’s theme, and the later declaration wins. That is the axis working as designed — base means “reset to the current theme’s default”, so a cream island inside a coal document is not a thing that exists. Switch to the light theme to cross-check those two.
Every colour token in the design system, resolved in each of the three distinct palette/surface value sets.
Declared once at :root and deliberately not restated in any of the six blocks — they are the two grounds themselves, named so a component can reach for coal or cream when it must not flip. Listed apart rather than as three identical columns, which would imply a per-block declaration that does not exist.
Colour constants that do not vary by theme or surface.
—
—
—
[ 04 — the type ]
Bricolage Grotesque + Spline Sans Mono.
Display and body are one family; everything numeric, labelled or terminal is the mono. The split is the design — a price in the body face reads as prose, and prose in the mono face reads as output.
Trade everything. Miss nothing.
display · font-display · text-h2
Body copy in Bricolage Grotesque. Numerals break out into the mono face so a figure is legible as a figure: a position at $98,250.00 settling in 04:11:36 is two different kinds of thing on the same line, and the faces say so.
body · font-body · text-body
[ 04 — the type ]
label · snipe-label · uppercase mono at 0.14em
The faces
Two families, wired by next/font in app/layout.tsx and bound to the tokens in theme.css. The resolved stack below is the proof rather than the claim: next/font mints a hashed family name per face, and the hash carries the real family inside it.
The type face tokens and their resolved font stacks.
--sn-font-displaydisplay + headings
—
--sn-font-bodybody copy
—
--sn-font-mononumerals, labels, terminal
—
The scale
Every step is fluid. The third column is a live measurement of a probe element sized from the token at this viewport — resize the window and it moves, which is the point: a fixed number beside a clamp() would be true at one width and wrong at every other.
The type scale tokens, their declared clamps, and their rendered size at the current viewport.
token
declared
measured here
--sn-text-displayhero display
—
—
--sn-text-display-ssection display
—
—
--sn-text-h2h2
—
—
--sn-text-h3h3
—
—
--sn-text-h4h4
—
—
--sn-text-statstat numeral
—
—
--sn-text-ledelede
—
—
--sn-text-bodybody
—
—
--sn-text-smsmall
—
—
--sn-text-nummono numeral
—
—
--sn-text-labelmono label
—
—
--sn-text-label-smmono label · small
—
—
--sn-text-micromono micro
—
—
Tracking · leading · weight
Tracking, leading and weight tokens.
--track-displaydisplay tracking
—
--track-h2h2 tracking
—
--track-h3h3 / h4 tracking
—
--track-numnumeral tracking
—
--sn-track-labelmono label tracking
—
--track-label-2mono label tracking · loose
—
--sn-leading-displaydisplay leading
—
--sn-leading-h2heading leading
—
--sn-leading-bodybody leading
—
--weight-displaydisplay weight
—
--weight-headingheading weight
—
--weight-monomono weight
—
[ 05 — do · don’t ]
A few rules, plainly.
✓Do: the mark, inheriting the surface ink
×Don’t: recoloured
×Don’t: distorted
×Don’t: rotated
Do
Take the mark from app/components/snipe/ScopeMark.tsx and let the ring and ticks inherit currentColor, so it takes the ink of whatever surface it lands on.
Use one of the two authorised lockups: wordmark + .exchange, or wordmark + the accent period. Both come from lib/brand.ts — never type the wordmark by hand.
Reach for --accent-bright whenever accent lands on small text. That is the token’s entire reason to exist.
Lead with mono numerals for prices, sizes and expiries; the terminal read is the design.
Spend vermillion like a signal — a kicker, a period, one call to action in a view. It stops working as an accent the moment there are two of them.
Don’t
Recolour, rotate, distort or redraw the mark, or strip the ring and its four ticks.
Put plain --accent on small text. On cream it measures 4.41 : 1 at label sizes — below the 4.5 : 1 floor — which is why the bright step exists.
Hardcode a colour literal anywhere. Every consumer references a token; this page is the only file in the app allowed to print one, and only as text a reader copies.
Reach for a dark: variant. It keys on the global axis only, so it stays off inside a light-theme contrast band — which is exactly where it would be needed. If you want one, the token mapping is wrong.
Use emoji as feature icons or status markers.
[ 06 — using the kit ]
Take it from the source.
There is no asset bundle to download yet, and pointing you at a stale one is how this page went wrong the last time. Until a packaged set ships, every canonical artefact lives in the repository — which is also the only copy that is guaranteed to match what you see here.
app/theme.cssThe token source of truth. Every value on this page is read out of it at runtime.
app/components/snipe/ScopeMark.tsxThe mark. Pure SVG, no raster fallback, sized by a single prop.
lib/brand.tsWordmark, domain and legal entity — env-overridable, so nothing hardcodes the name.
docs/UI_REVAMP_PLAN.mdThe architecture behind the tables above: two axes, six blocks, and the deliberate deviations from the supplied system with the contrast measurements that forced each one.
Press PNGs and a packaged SVG set are queued. Until then, take the mark out of the component rather than screenshotting this page — a screenshot bakes one theme, one surface and one viewport into something the system deliberately keeps fluid.