Design tokens
Every colour, radius, font, and motion value is defined once — in apps/mobile/design/prototype/redesign/rd-tokens.css. Port that file verbatim to the mobile app's theme system. No component ever hardcodes a hex value or a radius number.
Colours
| Token | Hex | Use |
|---|---|---|
--paper | #F4F1E8 | Default screen background (warm sand) |
--paper-hi | #FCFAF4 | Raised cards, chips, inputs |
--dark | #071410 | Camera / scanner / mid-payment screens |
--ink | #0A2B22 | Primary text — all transactional text |
--ink-2 | #33544A | Secondary text |
--ink-3 | #62796F | Non-transactional labels only |
--teal-ink | #04382C | Text on teal fills |
--teal | #00D4AA | Primary actions, progress, locked-QR outline |
--teal-deep | #009B7A | Positive amounts, "no fee", approved states |
--sunset | #FF9F43 | "Coming soon" labels, pending states |
--coral | #FF6B6B | Errors only — expired, offline, insufficient |
--violet | #A78BFA | On-chain / USDC contact tag (not used in MVP — no on-chain features) |
--ocean | #4ECDC4 | Reserved accent (rarely used) |
--shaka | linear-gradient(180deg, #00D4AA, #009B7A) | Logo mark + success burst ONLY |
--hairline | rgba(10,43,34,0.14) | 1.5px borders, dividers |
--hairline-strong | rgba(10,43,34,0.28) | Stronger borders |
Rules that don't fit in a table:
- The Shaka gradient is exposed as a token but must be importable only by the logo component and the success screen. Any other component that imports it is a build error worth catching in review.
- Coral never fills a whole screen. It goes on the signal element (icon tile, card border) with paper background behind.
- Ink-3 is for non-transactional labels only (
ACTIVITY,COMING SOON). Anything about money uses--inkor--ink-2.
Radii (the Shaka cut)
Every rounded surface keeps one near-hard corner — the bottom-left, by default.
| Token | Value | Use |
|---|---|---|
--r-btn | 26px 26px 26px 6px | Buttons |
--r-card | 24px 24px 24px 6px | Cards, tiles |
--r-chip | 12px 12px 12px 3px | Chips, small pills, rail slots |
--r-sheet | 44px 14px 0 0 | Bottom sheet — big cut top-left, bottom edges square |
Audit rule: No component uses uniform corner radii. If you see border-radius: 12px (single number) anywhere in the codebase, it's wrong — it should reference one of the tokens above.
Typography
- Display — Bricolage Grotesque 800. Letter-spacing −0.03em, line-height 0.98. Used for balances, screen titles, amounts.
- H1 — Bricolage Grotesque 700. −0.02em, 1.08.
- H3 — Hanken Grotesk 600. 1.25.
- Body — Hanken Grotesk 400. 1.45.
- Label — Hanken Grotesk 600, 12px, uppercase, +0.09em letter-spacing.
- Button labels — Bricolage Grotesque 700.
- All numerals —
font-variant-numeric: tabular-nums lining-nums. Applied via.rd-numin the prototype; the RN equivalent isvariant: 'tabular-nums'where supported, otherwise a font-feature-settings equivalent.
Reference sizes (from the 402×874 artboard)
| Element | Size |
|---|---|
| Balance (home) | 68 / 40 (integer / cents) |
| Confirm amount | 62 |
| Success amount | 88 |
| Screen titles | 35–44 |
| Section labels | 12 (uppercase) |
| Body | 13–16.5 |
| Minimum body text | 12.5 |
Fonts to load: Bricolage Grotesque (700, 800) + Hanken Grotesk (400, 600, 700). Both are Google Fonts.
Spacing & hit targets
- Screen horizontal padding: 24px (22px on Home).
- Top: 66px under the status bar.
- Bottom: 42px.
- All borders: 1.5px. Not 1, not 2.
- Primary CTA min-height: 64–76px.
- Secondary CTA min-height: 56–60px.
- All tap targets: ≥ 44px (iOS accessibility minimum).
Motion
Fast, functional, respectful. Full keyframes in the tokens CSS; the ones that matter:
| Purpose | Duration | Easing |
|---|---|---|
| Rise / fade on screen change | 150–260ms | ease |
| Bottom sheet slide-up | 190ms | cubic-bezier(0.2, 0.9, 0.3, 1) |
| Success burst | 420ms | cubic-bezier(0.2, 0.8, 0.3, 1) |
| Stamp (success text) | 260–320ms | eased pop |
| Toast slide-in from top | 420ms | eased |
| Logo rock (idle) | 0.9s loop | ±7° soft; ±16° during Paying |
| Scanner scanline sweep | 2.0s loop | linear |
| Marquee (auto-scrolling chips) | continuous | linear translateX |
| Any animation | any | zeroed under prefers-reduced-motion |
Porting notes (React Native)
- Colours — port to a theme file (
apps/mobile/theme/colors.ts) as named exports. Never inline hex. - Radii — the Shaka cut needs
borderRadius-per-corner support. React Native supportsborderTopLeftRadius/borderTopRightRadius/borderBottomLeftRadius/borderBottomRightRadius. Or useborderRadiuscombined with the corner-specific overrides. - Fonts — Bricolage Grotesque + Hanken Grotesk via
expo-font. Preload in the root layout. - Tabular numerals — use
fontVariant: ['tabular-nums']on Text components rendering money. Ensure the loaded font supports it. - Motion — Reanimated 3 for the slide-to-pay control and success burst; timing tokens shared from a
motion.tsfile. - Grain overlay — SVG fractal noise doesn't render efficiently in RN. Ship a pre-rendered PNG at 5% opacity as the paper background, or use
react-native-svgsparingly.
See components for the shared component patterns that consume these tokens.