# Application 1 — Crypto Wallet · Design System

> Single source of truth for continuing App 1. Any new screen **must** use only the tokens, components and patterns below. If something is missing, add it here first, then build.

- Entry file: `apps/app-1/App 1 - Crypto.html`
- Source: `apps/app-1/src/` → `market.js` (data), `charts.jsx` (charts + formatters), `ui.jsx` (icons, status bar, tab bar, primitives), `screens.jsx` (screens + phone shell + app)
- Stack: React 18 + Babel in-browser, plain CSS in the HTML `<style>` block. No CSS framework.

---

## 1. Principles

1. **Monochrome first.** Near-black and near-white do 95% of the work. One accent (lime) marks positive and active states. Coin colours appear only in data (sparklines, charts, allocation).
2. **Soft, large radii.** Everything is a rounded card sitting on a light grey canvas.
3. **Data is real and alive.** Prices tick, numbers count up, charts are interactive (hover/tap scrubbing). Never ship static fake charts when real data exists.
4. **Quiet typography.** Only Poppins, mostly weight 400/500. Hierarchy comes from size, not bold.
5. **Dense but calm.** Small type (7.5–11px on a 302px phone), generous card padding.

---

## 2. Canvas & device

| Token | Value |
|---|---|
| Stage | `1024 × 768`, scaled to fit the viewport (`Math.min(w/1024, h/768)`) |
| Page bg | `#efefef` |
| Phone outer | `302 × 634`, radius `52`, bg `#111`, padding `9` |
| Screen | radius `44`, bg `#f7f7f7` |
| Dynamic Island | `84 × 24`, radius `14`, top `10` |
| Status bar | height `44`, 13px/600, time is live |
| Tab bar | height `72`, bg `#111`, pinned bottom, 4 icons |
| Home indicator | `98 × 3.5`, white, bottom `8` |
| Content area | `.view` = `inset: 44px 0 0 0` (below status bar) |
| Phone positions | Phone 1 `left:200 top:34` · Phone 2 `left:522 top:106` |

All sizes are in CSS px **at phone scale** (the phone is 302px wide, not 390). Keep this scale for new screens.

---

## 3. Colour tokens

| Name | Hex | Use |
|---|---|---|
| `ink` | `#111111` | Primary text, active tab, dark buttons, selected bar, tooltip |
| `ink-2` | `#1c1c1c` | Dark card frame (Expenses total block) |
| `canvas` | `#efefef` | Page background |
| `surface` | `#f7f7f7` | Screen background |
| `card` | `#ffffff` | Cards, rows |
| `line` | `#ececec` | Row borders, 1px |
| `line-2` | `#e3e3e3` | Vertical dividers (action row) |
| `track` | `#e8e8e8` / `#e6e6e6` | Idle bars, progress track, segmented bg (`#ececec`) |
| `muted` | `#666` | Secondary labels (ticker, "Balance") |
| `muted-2` | `#888` / `#999` | Tertiary (axis labels, "Now", day names) |
| `tab-idle` | `#555` | Inactive tab icon stroke |
| `lime` | `#d6f56a` | Accent pill, primary CTA (Buy), notification dot, hover on launcher |
| `lime-bar` | `#d4ef66` | Progress fill |
| `up` | `#3a9a4a` | Positive % (flash: text `#2f8a3e`, bg `#e6f6e8`) |
| `down` | `#d8453a` | Negative % (flash: text `#c23b30`, bg `#fbe9e7`) |

**Coin colours (data only)**

| Coin | Colour |
|---|---|
| BTC | `#4cc15a` |
| USDT | `#5fd1b0` |
| ETH | `#6a64c8` |
| BNB | `#d6b43a` |
| DOGE | `#d8453a` |

---

## 4. Typography

Font: **Poppins** (Google Fonts, weights 300/400/500/600). `-webkit-font-smoothing: antialiased`. Numbers use `font-variant-numeric: tabular-nums`.

| Role | Size / weight | Example |
|---|---|---|
| Hero balance | 25px / 500, letter-spacing -0.3 | `$7,899.21` |
| Detail price | 22px / 500 | Coin detail price |
| Total (on dark) | 21px / 400 | `$50,290.00` |
| Screen title | 16–16.5px / 500 | `Welcome`, `Expenses` |
| Card title | 11–11.5px / 400 | `Highlighted currencies` |
| Row primary / price | 9.5–11px / 400 | `Bitcoin`, `$120,890.00` |
| Label | 8.5px / 400–500 | `Balance`, action labels |
| Caption | 7.5px | Ticker, `Now`, % |
| Micro | 6.5–7px | Chart axis, day names |

**Cents rule:** in hero numbers the `.xx` part gets `opacity: .4` (`.cents`).
**% format:** comma decimal with sign, e.g. `+78,6%`, via `fmtPct()`.
**Currency:** `fmtUsd()` gives 2 decimals, or 4 when the value is under $1. Hero balance always uses 2.

---

## 5. Spacing & radius

- Horizontal screen gutter: **11px** (cards inside the Expenses screen use 6–9px).
- Row gap: **8px**. Card inner padding: **12px 11px**.
- Radius scale: `5` (tooltip/chip) · `8` (bars, seg item) · `10` (pills, seg) · `12` (rows, stat tiles, buttons) · `17–20` (cards) · `44/52` (device).
- Circles: 35px (header buttons), 28px (coin badge), 38px (detail coin badge).

---

## 6. Components

### Layout / chrome (`ui.jsx`)
- **`<StatusBar/>`**: live clock, signal, wifi, battery icons.
- **`<TabBar tab setTab/>`**: keys `home | inbox | stats | user`. Active = white stroke, idle = `#555`.
- **`<Avatar/>`**: 35px circle, grey gradient with a silhouette.
- **`<Seg opts val set/>`**: segmented control. Bg `#ececec`, active item `ink` with white text.
- **`Ic.*`**: 1.2–1.6px stroke line icons, drawn on a 16 or 24 viewBox. Add new icons here in the same style: no fills, rounded joins.
- **`<Glyph g/>`**: coin symbol inside `.coin`.

### Data (`charts.jsx`)
- **`<Sparkline data color w=56 h=24/>`**: smooth Catmull-Rom path, stroke fades from transparent to the coin colour left→right, solid end dot plus a pulsing halo.
- **`<AreaChart data color w=262 h=118 tf onHover/>`**: line + gradient area (28% → 0), dashed grid, min/max labels, pointer scrubbing (dashed crosshair, dot, date chip).
- **`<Donut parts sel onSel/>`**: allocation ring, 16px stroke, 2px gaps, selected segment +5px thicker, others fade to 35%.
- **`useCount(target)`**: count-up animation (700ms ease-out cubic). Skips the animation when starting from 0.
- **`useMarket()`**: subscribes to live `Market` updates.

### Patterns (`screens.jsx` + CSS)
- **Coin row `.row`**: 48px tall, 1px `line` border, radius 12. Layout: coin badge · name/ticker · sparkline (flex:1) · price/% (right). Tap → Coin detail.
- **Action row `.acts`**: 3 equal columns, icon above label, 1px vertical dividers.
- **Dark frame card `.exp`**: `ink-2` frame with 3px padding, white inner card on top, white text block below.
- **Bar chart `.bars`**: 15px-wide bars, radius 8, idle `track`, selected `ink`. Floating tooltip is a black pill with a double ring (white, then black) and a 1.5px stem. Bars grow in with a 35ms stagger.
- **Pill `.pill`**: lime, 8px/500, radius 10.
- **Progress `.prog`**: 7px track, lime fill, animated width.
- **Stat tile `.stats div`**: white, radius 12, caption plus a 10.5px/500 value, in a 2-column grid.
- **Buttons `.btn`**: 34px tall, radius 12. Primary = lime fill; secondary = white with a 1px border.
- **Price flash `<Flash value>`**: 600ms green/red background when the value changes.
- **Skeleton `.skel`**: shimmering grey block while data loads.

---

## 7. Motion

| Pattern | Spec |
|---|---|
| Tab change | `fade` .35s: opacity 0 → 1, translateY 6px |
| Push (detail) | `push` .35s `cubic-bezier(.2,.8,.2,1)`: translateX 40px → 0 |
| Bars | scaleY 0 → 1, .5s, staggered 35ms |
| Numbers | count-up 700ms |
| Live dot | pulse 1.8s infinite |
| Press | `scale(.98)` on rows, opacity .5 on action buttons |

---

## 8. Data layer (`market.js`)

- `window.Market` → `{ COINS, TF, prices, spark, live, klines(id, tf), subscribe(fn) }`
- Source: Binance public REST (`data-api.binance.vision`, then `api.binance.com` as backup). Ticker refreshes every 5s. Kline results are cached for 60s.
- Timeframes: `1H(1m×60) 1D(15m×96) 1W(1h×168) 1M(4h×180) 1Y(1d×365)`.
- USDT is derived by inverting `USDCUSDT`.
- **Offline fallback:** a synthetic random walk around base prices, so the UI never goes blank. `Market.live` tells you whether the data is real.
- Portfolio holdings are mocked in `HOLD` (screens.jsx). Expenses data is seeded mock (`expenseData`).

---

## 9. Screens (current)

| Screen | Reached by | Notes |
|---|---|---|
| Home | tab `home` | Balance (live portfolio), actions, coin list |
| Coin detail | tap row / "Charts" | Area chart, timeframes, 24h stats, Buy/Sell |
| Analytics | tab `inbox` / "Analytics" | Donut + allocation list |
| Expenses | tab `stats` / "Deposit" | Weekly/monthly bars, total, limit, cash |
| Profile | tab `user` | **TODO**, currently falls back to Home |

## 10. Adding a new screen: checklist

1. Build it as a component in `screens.jsx` (or a new `src/*.jsx` file that exports to `window`).
2. Register it in `Phone()` routing.
3. Use only the tokens above. The top bar is the `.top` pattern (back button left, 16px title centred).
4. Leave **≥ 80px** of bottom clearance for the tab bar, or make the content scroll (`padding-bottom: 70px`).
5. Numbers: tabular, `fmtUsd`/`fmtPct`, cents at 40% opacity when shown large.
6. Add press states and entry motion from §7.
7. Update §9 of this file.
