SPB Git

Repository Public

DESIGN.md 7.3 KB 108 lines markdown

1# SP Wallet — design system (v9)23One page. The system lives in `apps/web/src/styles.css` (tokens, component layer), `apps/web/src/ui.tsx` (shared4components), `apps/web/src/icons.tsx` (logos) and `apps/web/src/chart.tsx` (charts). Screens compose these; they do not5restyle themselves. The phone (390 × 844) is the reference; the desktop reuses the same pieces in wider grids.67## Principles891. **Calm, confident, premium.** One hero per screen, generous numerals, quiet chrome. The real logos are the colour10   accents; the brand colour is kept for the primary action.112. **Honest before handsome.** This app moves real money. A review shows every field in full; nothing is truncated on an12   approval; no figure the owner is about to approve is ever animated; fees, minimums and warnings are never folded away;13   SIMULATION / TESTNET / RÉEL stay unmistakable. Looks never change what is sent to the API.143. **Depth by layering, not by paint.** Hairlines, soft shadows, translucency (blurred header, tab bar, sheet scrim). The15   only gradient is the balance hero's aurora.164. **Colour never carries a meaning alone.** Gains and losses keep their sign and arrow, states keep icon + word,17   chart parts keep their name and share in text.185. **The finger is answered.** Every tappable thing is ≥ 44 pt and has a visible press state.196. **Motion is short and optional.** Transform and opacity only, ≤ 0.36 s, off under `prefers-reduced-motion`.2021## Type scale2223System fonts (SF Pro on Apple devices), no web font. Body text uses **tabular figures** so amounts align in lists;24display numerals use **proportional figures** (a hero amount in tabular figures looks loose).2526| Role | Size / weight | Where |27|---|---|---|28| Display (`.t-display`) | clamp(40, 12.6vw, 54) / 650, −0.04em | total balance, asset price, amount on the review receipt |29| Title (`.t-title`, every `main h1`) | 30 / 650, −0.028em | page titles (`PageTitle`) |30| Headline | 17 / 600 | card headings (`H`) |31| Body | 15 – 15.5 / 400–600 | rows, buttons |32| Callout / footnote | 13 – 14 | secondary lines, notices, hints |33| Eyebrow (`.t-eyebrow`) | 11.5 / 600, +0.06em, caps | list section labels (day groups, "held / supported") |34| Micro | 11 – 12 | tab labels, chart axis ends |3536Inputs are 16 px (no zoom on focus in iOS).3738## Spacing, radii, elevation3940- Spacing on a 4 pt grid: page gutter 20, card padding 20, row height ≥ 60 (68 for asset rows), section gap 16–20.41- Radii: 12 (thumbs, small tiles) · 16 (buttons, inputs, notices) · 22 (cards) · 28–30 (hero, sheets, QR plate) · full (chips, logos).42- Elevation tokens: `--e1` resting card · `--e2` raised control (centre tab action, QR plate, pull indicator) · `--e3` sheets.43  In dark, elevation is a lighter surface plus a 1 px inner highlight rather than a larger shadow.4445## Colour tokens and contrast (WCAG 2.x ratio; computed by `apps/web/scripts/contrast.mjs`)4647| Token | Light | on surface / bg / elev | Dark | on surface / bg / elev |48|---|---|---|---|---|49| `--bg` / `--surface` / `--elev` | `#f3f4f7` / `#ffffff` / `#eceef3` | — | `#06080c` / `#0f131b` / `#1a202c` | — |50| `--ink` | `#0a0d14` | 19.4 / 17.7 / 16.7 | `#f4f6fa` | 17.2 / 18.5 / 15.1 |51| `--mute` | `#596273` | 6.1 / 5.6 / 5.3 | `#98a2b6` | 7.2 / 7.8 / 6.4 |52| `--emerald` (gain, ok) | `#087a55` | 5.4 / 4.9 / 4.6 | `#35e7ac` | 11.7 / 12.6 / 10.2 |53| `--blue` (link, info, focus) | `#2257e0` | 6.0 / 5.4 / 5.2 | `#7ea6ff` | 7.8 / 8.4 / 6.8 |54| `--warn` | `#9a5b06` | 5.4 / 4.9 / 4.7 | `#f4b65b` | 10.4 / 11.2 / 9.1 |55| `--danger` (loss, error) | `#c22a40` | 5.7 / 5.2 / 4.9 | `#ff7d88` | 7.6 / 8.2 / 6.6 |56| `--primary` / `--onprimary` | `#0a0d14` / `#ffffff` | 19.4 | `#35e7ac` / `#04130d` | 11.9 |57| `--danger` / `--ondanger` (button) | `#c22a40` / `#ffffff` | 5.7 | `#ff7d88` / `#2a0508` | 7.6 |5859Every pair is ≥ 4.5 : 1 (AA for text), including each tone on its own 10 % wash (notices, pills: 4.7 – 9.7).60Hero text (white at 70 %) on the hero base is 9.6. Below AA on purpose: input placeholders (`--mute` at 70 %).61The dark theme is its own set of values (near-black `#06080c`, not a flip); a pure-black OLED variant is not shipped.6263**Data-viz series** (allocation bar): five fixed slots + "other", `--s1…--s5`, `--s-other` — blue, orange, aqua, yellow,64magenta, in that order, never cycled. Validated with the dataviz skill's `validate_palette.js` on both surfaces: light —65adjacent CVD ΔE 9.1, normal-vision 19.6, three slots under 3 : 1 against white (relief: every part is named with its share66in text); dark — CVD 8.4, normal 19.3, all ≥ 3 : 1.6768## Logos6970`AssetIcon` (historical alias `Coin`), `NetworkIcon` (alias `NetDot`), `VenueIcon`, `ProviderIcon` — real logos only,71self-hosted, sanitised; provenance in `apps/web/src/logos/SOURCES.md`. Every logo sits on a round plate with a hairline72edge: full-bleed discs cover it; a free-form mark keeps the plate (its brand's own background where it has one), so it73never vanishes on a light or dark surface and is never recoloured. A network badge (bottom-right, ring in the surface74colour) is shown whenever the asset is not on its home network, and always for a representation without its own mark75(USDC.e, BTC.b, BTCB, WBNB…). An unknown symbol keeps a neutral letter disc — no logo is invented.7677## Motion7879| What | How |80|---|---|81| Press | `.press`: scale 0.97, 140 ms; rows tint (`.row-press`) |82| Screen enter | `.rise`: 8 px, 280 ms |83| Sheet | scrim fade 200 ms, panel spring 360 ms, grabber, drag down to dismiss (`Sheet`; never on approval sheets) |84| Balance | `AnimatedNumber`: 520 ms glide, read-only figures only; the final value is exposed to assistive tech at once |85| Hero aurora | two blurred discs drifting 22 s / 26 s (transform only); hue follows the 24 h direction; decorative |86| Skeleton | `.skel` shimmer 1.4 s, shaped like the final layout (`SkeletonRows`) |87| Header | condenses after 6 px of scroll (an attribute toggled in a rAF, no re-render) |88| Pull to refresh | Home and Activity, passive listeners, 64 px threshold, a short vibration where the platform has one |8990All of it is disabled by `prefers-reduced-motion: reduce`.9192## Component inventory9394Surfaces `Card`, `.card`, `.hero`, `.nav-glass` · Structure `PageTitle`, `H`, `.t-eyebrow`, `EmptyState` ·95Actions `Btn` (primary / soft / ghost / danger), `Chips`, `Seg`, `CopyBtn` · Inputs `Field`, `inputCls` ·96Feedback `Notice`, `StatePill`, `Skeleton`, `SkeletonRows`, pull-to-refresh · Data `Money`, `Change`, `AnimatedNumber`,97`Addr`, `Spark`, `PriceChart`, `AllocationBar` · Logos `AssetIcon`, `NetworkIcon`, `VenueIcon`, `ProviderIcon` ·98Overlays `Sheet` and the shared sheet styling applied to every `role="dialog"` of the app.99100## Charts (dataviz skill: form first, colour last)101102- **Allocation** — one whole split into parts, above a list that already gives each part's name and amount: a thin103  segmented bar (8 px, rounded ends, 2 px gaps, no text on it), not a donut; ≤ 5 parts + "other"; legend with name and104  share in text colour; hover / focus emphasises a part.105- **Price** — one series, one axis, 2 px line, 10 % wash, hairline at the period's open, crosshair that snaps to the106  nearest point with a read-out in ink; min / max and the two dates as the only labels.107- **Sparklines** — decorative trend in the de-emphasis colour with an end marker; the adjacent text carries the value.108
Files main
Menu

Theme