style guide
Dark base, single signal, radius zero. Everything is derived from
tokens.json and enforced by design-system-integrity.md.
This page is the living reference. Use the toggle to preview both modes.
logo
The logo is the 9×9 dot-field mark. The wordmark is not used — the mark alone identifies Gradient. Signal (#D94A12) is the same in both modes. The favicon collapses to a single lit dot below 40px.
SVG favicon: a single filled circle, signal on transparent. Works on any browser chrome regardless of light or dark tab bar. At 32×32 and below, the full 9×9 field is too small — use the single dot. At 48px+, use the full field.
Minimum clear space around the mark equals the diameter of one dot in the field. The mark is always centered in its bounding box. Never rotate, stretch, add effects, or change the color.
The favicon is an inline SVG data URI — no external file request. Transparent background so it adapts to any browser theme automatically.
<link rel="icon" href="data:image/svg+xml,
%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 32 32'%3E
%3Ccircle cx='16' cy='16' r='14' fill='%23D94A12'/%3E
%3C/svg%3E" />
modes
Dark is the base system. Light is a mirror, not a variant — every token has a counterpart.
Opt in via [data-theme="light"]. Signal (#D94A12) is the same in both modes.
Status colors shift for contrast on light grounds.
dark (default)
light (mirror)
dark status
light status
dark elevation
light elevation
color
Six core tokens. Signal appears at most once per view. Status uses a separate functional palette — signal is never status.
Depth by lightness, never shadow. Surfaces separate by stepping up the elevation ladder.
typography
Schibsted Grotesk for display and prose. Martian Mono for labels, data, and financial figures. Money is always two decimals, tabular nums.
$1,250,000.00
Balance overview
Recent activity
Card issuing and stablecoin settlement for financial institutions.
Submit a verification request to be enabled for real money on mainnet. Test freely with test funds — sends, deposits, and balances all work.
gradient reference
tr_gcN2cIp2gpeQdKwkDI2T $12,500.00 2026-09-29
spacing
Every spacing value sits on the 4px base. Banned values: 20, 28, 36. Row height is 32px. Control height is 40px. Section gap is 96px.
controls
40px control height. Radius zero. Signal for primary, border for secondary. Focus ring is 2px signal with 2px offset (ink on filled signal controls).
patterns
The card/row pattern from the transaction detail. Label on top, description below, value right-aligned. 32px row height minimum, 12px vertical padding. 1px line dividers between siblings.
identity
The mark is a lowercase g from a 5×7 display font, centered in a 9×9 dot field. Dots are round. Lit dots at full opacity, unlit at 0.08. Below 40px, collapse to a single lit dot. Avatars are square, radius 0. People are monograms only — never photographs.
Below 24px or when no logo is set. Two uppercase letters, mono font, elev-02 surface. People are always monograms — never photographs.
Preferred format: monochrome SVG. In tables and lists, render at 100% ink — never in the client's brand colors.
Full-color logos only at ≥64px on detail pages and press materials. Image media uses border-radius: 12px
(the only non-zero radius in the system). Shape is square. No circular crop on logos.
icons
Icons use the same 9×9 grid as the mark. Drawing area is the inner 7×7 well — the outer ring is always empty. Stroke is 1 unit, currentColor, square caps, miter joins. No curves, no fill. One icon per control.
links
Three link types. Prose links use signal-colored underline. Chrome links (nav, breadcrumbs) are muted with no underline — hover lifts to ink. Standalone links are uppercase mono with an arrow. Visited state is never shown. Color alone never indicates a link.
Read the account activation guide before submitting KYB.
states
Every view ships four states: populated, empty, loading, error. No spinners. No shimmer. Loading holds geometry identical to the result. Empty cells show an em dash (—), not blank. Under 400ms of loading, render nothing. No success toasts — row state change is the confirmation.
no transfers yet.
could not load activity. reload to retry.
An em dash in a cell means no data for that field. It is not a view-level empty state.
media
Three aspect ratios. Ground is always page color (#0A0A0A). No filters, no color-sampled
photography. Inset media gets border-radius: 12px — the only non-zero radius in the
system. Full-bleed media uses 0. Camera angles: 0° elevation or 15° three-quarter.
data visualization
Bar charts use signal color. The current/today bar is full opacity. Historical bars are at 0.35 opacity. Date labels left-aligned, value labels right-aligned. Axes use muted color, mono font. No gradients, no 3D, no shadows. D3 for rendering — never Canvas for data charts (accessibility).
Use for trailing balance history, time-series where the date axis reads top-to-bottom. Date labels left, value labels right.
Use for category comparison, volume by day/week/month, or any chart where the x-axis is the primary dimension. Y-axis ticks on the left, category labels below. Same opacity rules apply.
destructive
Four tiers of friction for destructive actions. No signal on destructive controls — never a red filled button. Default focus is always cancel. Minimum 24px gap between primary and destructive actions.
responsive
Four breakpoints on the token scale. Mobile is not a degraded desktop — it's a distinct layout with larger touch targets and stacked tables. Content never scrolls horizontally.
sm
< 640px
One column. 16px gutter. 44px touch targets. Tables stack into rows — never horizontal scroll.
md
640 – 1023px
Sidebar collapses to 56px icon rail. Two-column forms go single. Content fills width.
lg
1024 – 1439px
Full sidebar. Standard gutter (40px). Default comfortable density.
xl
≥ 1440px
Content caps at 1100px and centers. No stretch beyond max-width.
env(safe-area-inset-*).touch
Visual and hit targets must match. If the visual element is smaller than 44px, expand the hit target invisibly to meet the minimum. On desktop, 32px row height is acceptable; on mobile, every interactive element reaches 44px.
touch-action: manipulation on controls.interactions
Every flow is keyboard-operable. Tab order follows DOM order — no positive tabindex.
Focus rings are never removed. Overlays trap focus and return it on dismiss.
2px solid var(--signal), outline-offset: 2px. On filled signal controls, 2px solid var(--ink).:focus-visible over :focus to avoid distracting pointer users.tabindex. Skip link at top.<a> for navigation. Never <button> or <div>. Cmd+Click, middle-click must work.overscroll-behavior: contain on modals and drawers.useState.forms
Every control has a label. Enter submits single-input forms. Never block typing or paste. Errors appear next to the field, not in a toast. Submit stays enabled until the request fires.
<!-- Email — correct keyboard, autocomplete -->
<input type="email"
autocomplete="email"
spellCheck={false}
placeholder="you@yourinstitution.com" />
<!-- Numeric — number pad, no spinner -->
<input inputMode="numeric"
pattern="[0-9]*"
placeholder="50309" />
<!-- Sensitive — masked, no autocomplete -->
<input type="password"
autoComplete="off"
placeholder="XXX-XX-XXXX" />
<!-- Mono data — invite code -->
<input type="text"
spellCheck={false}
autoCapitalize="characters"
placeholder="GRD-XXXXX-XXXXX" />
<label> or aria-label. Clicking the label focuses the control.GRD-XXXXX-XXXXX). End with ellipsis for open-ended fields.autocomplete values. off for sensitive fields (SSN, EIN). Correct type for keyboards.Idempotency-Key header. Button shows loading state and original label.performance
The product is an SPA on Cloudflare Workers. Fast by default — keep it that way. Every interaction should feel instant. Network requests complete under 500ms.
font-display: swap to avoid invisible text.content-visibility: auto.accessibility
Financial software must be accessible to everyone. These screens end up in audit files, regulatory reviews, and compliance workflows. Accessibility is not optional.
<button>, <a>, <label>, <table>) before aria-*.<h1–h6>. One <h1> per page. Skip link at top of body.aria-label. Decorative icons use aria-hidden.prefers-reduced-motion. Blinks resolve to solid. No entrance animations.role="img" and aria-label on chart containers.aria-live="polite" for status changes and inline validation.Esc dismisses and returns focus to the trigger.voice
Second person, active voice. Sentence case everywhere except legal names. Name the action — never promise a feeling. The brand contract at /llms.txt is the source of truth for both humans and agents.
These never appear in any surface that carries the Gradient name.
translate="no" on "Gradient" and organization names.seo
Every public page must include these meta tags. The product UI is an SPA behind auth — only the root, style guide, and brand assets are indexable. Private routes return no content to crawlers.
<!-- SEO -->
<title>Gradient — Card issuing and stablecoin settlement</title>
<meta name="description" content="Card issuing and stablecoin
settlement for financial institutions." />
<meta name="robots" content="index, follow" />
<link rel="canonical" href="https://gradientsystems.com/" />
<!-- Theme color: both modes -->
<meta name="theme-color" content="#0A0A0A"
media="(prefers-color-scheme: dark)" />
<meta name="theme-color" content="#FAFAF9"
media="(prefers-color-scheme: light)" />
<meta property="og:type" content="website" />
<meta property="og:site_name" content="Gradient" />
<meta property="og:title" content="Gradient — Card issuing
and stablecoin settlement" />
<meta property="og:description" content="Card issuing and
stablecoin settlement for financial institutions." />
<meta property="og:url" content="https://gradientsystems.com/" />
<script type="application/ld+json">
{
"@context": "https://schema.org",
"@type": "Organization",
"name": "Gradient Systems",
"url": "https://gradientsystems.com",
"description": "Card issuing and stablecoin
settlement for financial institutions."
}
</script>
geo
Generative Engine Optimization ensures AI systems (ChatGPT, Claude, Perplexity, Gemini, Google AI Overviews) can discover, understand, and cite Gradient accurately. The goal is correct representation in AI-generated answers — not traffic.
The brand contract at /llms.txt is the machine-readable source of truth. It tells AI crawlers and agents what Gradient is, how to describe it, and what the design system rules are. Every surface generated by an agent must conform to this file.
# Gradient Systems — brand contract
# Canonical: https://gradientsystems.com/brand
# Machine reference: /brand/tokens.json
# Human reference: /brand
# rev 0.3
## Scope
Applies to every surface that carries the name:
marketing site, product UI, docs, decks, print,
and anything an agent generates on our behalf.
## Voice
Second person, active. Sentence case everywhere
except legal names. Name the action; never promise
a feeling. No exclamation marks.
Banned: "seamless", "revolutionary", "powerful",
"unlock", "supercharge".
robots.txt explicitly allows AI crawlers on public pages. Private product routes return
no content to unauthenticated requests — the SPA shell is empty without auth.
Content should be structured so AI systems can extract and cite specific claims accurately.
agents
AI agents working on Gradient surfaces (code, content, design) must follow these rules.
The agent contract chain is: AGENTS.md (repo) → tokens.json (design)
→ llms.txt (brand). If any conflict, the more specific file wins.
apps/web/src/brand/tokens.json. Every color, space, type, and radius value. Machine-parseable.# tokens.json declares the contract URL
{
"agentContract":
"https://gradientsystems.com/brand/llms.txt"
}
# index.html links to it
<link rel="author"
href="https://gradientsystems.com/llms.txt" />
# AI crawlers find it via robots.txt
Allow: /llms.txt
rules
source files
apps/web/src/brand/tokens.json — canonical design tokens/llms.txt — brand contract for humans and agentsdesign-system-integrity.md — PR review gatesapps/web/src/index.css — token-derived custom propertiesAGENTS.md — repo-level agent instructions/robots.txt — crawler access rules/sitemap.xml — indexable URLs