Skip to main content

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

TokenHexUse
--paper#F4F1E8Default screen background (warm sand)
--paper-hi#FCFAF4Raised cards, chips, inputs
--dark#071410Camera / scanner / mid-payment screens
--ink#0A2B22Primary text — all transactional text
--ink-2#33544ASecondary text
--ink-3#62796FNon-transactional labels only
--teal-ink#04382CText on teal fills
--teal#00D4AAPrimary actions, progress, locked-QR outline
--teal-deep#009B7APositive amounts, "no fee", approved states
--sunset#FF9F43"Coming soon" labels, pending states
--coral#FF6B6BErrors only — expired, offline, insufficient
--violet#A78BFAOn-chain / USDC contact tag (not used in MVP — no on-chain features)
--ocean#4ECDC4Reserved accent (rarely used)
--shakalinear-gradient(180deg, #00D4AA, #009B7A)Logo mark + success burst ONLY
--hairlinergba(10,43,34,0.14)1.5px borders, dividers
--hairline-strongrgba(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 --ink or --ink-2.

Radii (the Shaka cut)

Every rounded surface keeps one near-hard corner — the bottom-left, by default.

TokenValueUse
--r-btn26px 26px 26px 6pxButtons
--r-card24px 24px 24px 6pxCards, tiles
--r-chip12px 12px 12px 3pxChips, small pills, rail slots
--r-sheet44px 14px 0 0Bottom 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 numeralsfont-variant-numeric: tabular-nums lining-nums. Applied via .rd-num in the prototype; the RN equivalent is variant: 'tabular-nums' where supported, otherwise a font-feature-settings equivalent.

Reference sizes (from the 402×874 artboard)

ElementSize
Balance (home)68 / 40 (integer / cents)
Confirm amount62
Success amount88
Screen titles35–44
Section labels12 (uppercase)
Body13–16.5
Minimum body text12.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:

PurposeDurationEasing
Rise / fade on screen change150–260msease
Bottom sheet slide-up190mscubic-bezier(0.2, 0.9, 0.3, 1)
Success burst420mscubic-bezier(0.2, 0.8, 0.3, 1)
Stamp (success text)260–320mseased pop
Toast slide-in from top420mseased
Logo rock (idle)0.9s loop±7° soft; ±16° during Paying
Scanner scanline sweep2.0s looplinear
Marquee (auto-scrolling chips)continuouslinear translateX
Any animationanyzeroed 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 supports borderTopLeftRadius / borderTopRightRadius / borderBottomLeftRadius / borderBottomRightRadius. Or use borderRadius combined 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.ts file.
  • 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-svg sparingly.

See components for the shared component patterns that consume these tokens.