--- version: alpha name: Wealthsimple-design-analysis category: Fintech & Crypto website: https://www.wealthsimple.com description: A money brand that behaves like a magazine. Warm greyscale replaces the usual fintech blue, every product section claims its own full-bleed colour field, and the interface admits only one shadow. Two proprietary faces split the work — a geometric sans for the system, a serif for the moments that want to feel written rather than shipped — and they track in opposite directions. colors: ink: "#1c1b1b" ink-strong: "#32302f" ink-secondary: "#686664" ink-muted: "#868686" ink-inverse: "#fcfcfc" background: "#fcfcfc" background-white: "#ffffff" background-linen: "#eeece7" background-linen-light: "#faf8f5" background-warm: "#f5f3ef" background-midnight: "#09090a" slate-30: "#494645" slate-50: "#7a7674" slate-60: "#94908d" slate-70: "#afaaa7" slate-80: "#c9c6c4" slate-90: "#e4e2e1" slate-95: "#f1f0f0" slate-98: "#f8f8f8" greyscale-75: "#c2c2c2" greyscale-95: "#f2f2f2" outlines: "#e4e2e1" outlines-active: "#afaaa7" borders: "#32302f" celery-40: "#486635" celery-70: "#99b383" terracotta-40: "#a43d12" terracotta-70: "#ff8a71" background-error: "#f2dedb" field-ink: "#080f16" field-plum: "#5f5974" field-clay: "#564c47" field-forest: "#0c330d" field-butter: "#eee3b1" typography: editorial-hero: fontFamily: "tiempos, Tiempos Text, Georgia, serif" fontSize: 200px fontWeight: 400 lineHeight: 1.08 letterSpacing: -0.01em editorial-display: fontFamily: "tiempos, Tiempos Text, Georgia, serif" fontSize: 56px fontWeight: 400 lineHeight: 1.16 letterSpacing: -0.01em editorial-title: fontFamily: "tiempos, Tiempos Text, Georgia, serif" fontSize: 48px fontWeight: 400 lineHeight: 1.16 letterSpacing: -0.01em hero: fontFamily: "the-future, system-ui, Helvetica Neue, sans-serif" fontSize: 90px fontWeight: 400 lineHeight: 1 letterSpacing: 0em display: fontFamily: "the-future, system-ui, Helvetica Neue, sans-serif" fontSize: 64px fontWeight: 500 lineHeight: 1.16 letterSpacing: 0.005em title-lg: fontFamily: "the-future, system-ui, Helvetica Neue, sans-serif" fontSize: 48px fontWeight: 500 lineHeight: 1.16 letterSpacing: 0.005em title-md: fontFamily: "the-future, system-ui, Helvetica Neue, sans-serif" fontSize: 24px fontWeight: 600 lineHeight: 1.44 letterSpacing: 0em title-sm: fontFamily: "the-future, system-ui, Helvetica Neue, sans-serif" fontSize: 18px fontWeight: 500 lineHeight: 1.16 letterSpacing: 0.005em body: fontFamily: "the-future, system-ui, Helvetica Neue, sans-serif" fontSize: 18px fontWeight: 400 lineHeight: 1.4 letterSpacing: 0em body-medium: fontFamily: "the-future, system-ui, Helvetica Neue, sans-serif" fontSize: 16px fontWeight: 500 lineHeight: 1.4 letterSpacing: 0.005em label: fontFamily: "the-future, system-ui, Helvetica Neue, sans-serif" fontSize: 14px fontWeight: 500 lineHeight: 1.4 letterSpacing: 0.005em eyebrow: fontFamily: "the-future, system-ui, Helvetica Neue, sans-serif" fontSize: 12px fontWeight: 500 lineHeight: 1 letterSpacing: 0.08em rounded: none: 0px small: 4px normal: 12px large: 24px xlarge: 32px pill: 1000px circle: 50% spacing: xs: 4px sm: 8px md: 12px base: 16px lg: 24px xl: 32px xxl: 48px section-sm: 64px section: 96px section-lg: 160px container-inline: 40px components: header: backgroundColor: "{colors.ink-strong}" textColor: "{colors.ink-inverse}" typography: "{typography.label}" height: 92px button-solid: backgroundColor: "{colors.ink}" textColor: "{colors.ink-inverse}" typography: "{typography.label}" rounded: "{rounded.pill}" height: 44px padding: 12px 16px button-solid-active: backgroundColor: "{colors.ink-strong}" textColor: "{colors.ink-inverse}" rounded: "{rounded.pill}" button-solid-large: backgroundColor: "{colors.ink}" textColor: "{colors.ink-inverse}" typography: "{typography.body-medium}" rounded: "{rounded.pill}" height: 64px padding: 20px 32px button-inverse: backgroundColor: "{colors.ink-inverse}" textColor: "{colors.ink}" typography: "{typography.label}" rounded: "{rounded.pill}" height: 44px padding: 12px 16px button-translucent: backgroundColor: "color-mix(in srgb, #fcfcfc 20%, transparent)" textColor: "{colors.ink}" typography: "{typography.label}" rounded: "{rounded.pill}" height: 44px padding: 12px 16px nav-item: backgroundColor: transparent textColor: "{colors.ink-inverse}" typography: "{typography.label}" rounded: "{rounded.normal}" height: 32px padding: 6px 12px input: backgroundColor: "{colors.background-white}" textColor: "{colors.ink}" borderColor: "{colors.outlines}" typography: "{typography.body}" rounded: "{rounded.pill}" height: 64px padding: 20px 24px card: backgroundColor: "{colors.background-white}" borderColor: "{colors.outlines}" rounded: "{rounded.normal}" padding: "{spacing.lg}" section-field: backgroundColor: "{colors.field-plum}" textColor: "{colors.ink-inverse}" typography: "{typography.display}" padding: "{spacing.section}" footer: backgroundColor: "{colors.background}" textColor: "{colors.ink}" typography: "{typography.label}" --- ## Overview Wealthsimple is a money brand that has decided to look like **a magazine rather than a bank**. There is no fintech blue anywhere in the token set — the entire interface is built from a warm greyscale running `{colors.ink}` (#1c1b1b) through a `slate` ramp to `{colors.background}` (#fcfcfc), with linen tones for content grounds. What would elsewhere be an accent colour is instead full-bleed **colour fields**: each product claims a section-wide ground of its own, and the type flips to `{colors.ink-inverse}` or back to `{colors.ink}` for contrast. Two proprietary faces divide the work, and they track in opposite directions. `the-future`, a geometric sans, carries the system with slightly *positive* tracking (+0.005em) at almost every step. `tiempos`, a serif, appears for the moments meant to read as written rather than shipped — on the Trade page it sets a 200px headline with *negative* tracking. Both sit at weight 400 or 500; this system has no bold display voice. The interface itself is almost aggressively plain, which is what makes the colour fields work. There is exactly **one shadow** in the whole token set, `{component.card}` separation is a 1px `{colors.outlines}` rule, and every action is a pill. Radius carries a two-tier grammar: `{rounded.pill}` means you can press it, `{rounded.normal}` (12px) means it contains something. **Key Characteristics:** - No brand blue, no accent hue in the chrome — the palette is a warm greyscale plus linen. - Each product section gets a full-bleed colour field: plum, clay, forest, butter, near-black. - Two faces with inverse tracking — sans at +0.005em, serif at −0.01em. - Weights stop at 500 for display; 600 appears only at small title sizes. - Body copy is 18px, unusually large, and the reason the pages read as editorial. - One shadow token in the entire system; separation is otherwise a 1px rule. - Every control is `{rounded.pill}` — including the 64px input fields. - Semantic colour is named by material: `celery` for success, `terracotta` for error. - A single custom easing, `cubic-bezier(.241, .969, .635, .997)`, on 81 elements. ## Colors > **Source pages analyzed:** the Trade product page (/en-ca/trade), the Canadian homepage > (/en-ca) and Wealthsimple Magazine (/en-ca/magazine), plus the header and footer chrome > shared across all three. ### Brand & Accent There is no brand accent. The closest thing to one is the ink itself: - **Ink** (`{colors.ink}` — #1c1b1b): Text, and the fill of every primary action. - **Ink Strong** (`{colors.ink-strong}` — #32302f): Borders, the header ground, and the pressed state of a solid button. - **Ink Inverse** (`{colors.ink-inverse}` — #fcfcfc): Text and button fills on any dark field. Note this is the same value as the page background — the system inverts rather than introducing a second white. ### Section Fields The distinctive layer, and where the brand actually lives. These are not published as tokens; they are art direction applied per product section, each paired with its own text colour: - **Field Ink** (`{colors.field-ink}` — #080f16): The promotional band. Text `{colors.ink-inverse}`. - **Field Plum** (`{colors.field-plum}` — #5f5974): Chequing. - **Field Clay** (`{colors.field-clay}` — #564c47): Credit card. - **Field Forest** (`{colors.field-forest}` — #0c330d): Active trading. - **Field Butter** (`{colors.field-butter}` — #eee3b1): The newsletter block. Text returns to `{colors.ink}`. - **Warm Ground** (`{colors.background-warm}` — #f5f3ef): The default content ground between fields, and the most-used section colour on the homepage. ### Surface - **Background** (`{colors.background}` — #fcfcfc): The page. An off-white, never pure. - **White** (`{colors.background-white}` — #ffffff): Inputs and cards sitting on the off-white page — the one place pure white appears. - **Linen** (`{colors.background-linen}` — #eeece7) and **Linen Light** (`{colors.background-linen-light}` — #faf8f5): Warm content grounds. - **Midnight** (`{colors.background-midnight}` — #09090a): The darkest published ground. ### Text - **Ink** (`{colors.ink}`) for primary; **Secondary** (`{colors.ink-secondary}` — #686664) for supporting copy; **Muted** (`{colors.ink-muted}` — #868686) for placeholders and secondary headings. - The `slate` ramp (`{colors.slate-30}` #494645 through `{colors.slate-98}` #f8f8f8) supplies every intermediate value. It is warm-neutral, not blue-grey, which is why the pages feel like paper. ### Hairlines & Borders - **Outlines** (`{colors.outlines}` — #e4e2e1): The default 1px rule on inputs, cards and dividers. - **Outlines Active** (`{colors.outlines-active}` — #afaaa7): Focus and active borders. - **Borders** (`{colors.borders}` — #32302f): The heavy variant, used where a control needs a visible edge on a light ground. ### Semantic Named by material rather than by function, which is characteristic: - **Celery** (`{colors.celery-40}` — #486635 for text, `{colors.celery-70}` — #99b383 for fills): Success. - **Terracotta** (`{colors.terracotta-40}` — #a43d12 for text, `{colors.terracotta-70}` — #ff8a71 for fills): Error, with `{colors.background-error}` (#f2dedb) as the alert ground. ### Brand Gradient **No gradient tokens.** Depth comes from the colour fields and from photography inside them. ## Typography ### Font Family - **the-future** — the system face. Weights 400, 500 and 600 observed; it carries body, UI, labels and most display. Proprietary (Adobe Fonts). - **tiempos** — a serif, weights 400 and 500. Used for editorial display moments; on the Trade page it sets the hero. It does **not** appear on the magazine index, so its use is a deliberate per-page choice rather than a systematic role. - **futura-pt-condensed** (800) and **futura-pt-light** (200) — loaded and used sparingly as display accents. - `wealthsimple-sans` and `wealthsimple-display-sans` are also loaded but were not observed in use on the analyzed pages. ### Hierarchy | Token | Size | Weight | Line Height | Letter Spacing | Use | |---|---|---|---|---|---| | `{typography.editorial-hero}` | 200px | 400 | 1.08 | -0.01em | Trade page hero. **Serif** | | `{typography.hero}` | 90px | 400 | 1 | 0 | Magazine masthead | | `{typography.display}` | 64px | 500 | 1.16 | +0.005em | Homepage hero | | `{typography.editorial-display}` | 56px | 400 | 1.16 | -0.01em | Editorial section headline. **Serif** | | `{typography.title-lg}` | 48px | 500 | 1.16 | +0.005em | Section headline | | `{typography.editorial-title}` | 48px | 400 | 1.16 | -0.01em | Editorial sub-headline. **Serif** | | `{typography.title-md}` | 24px | 600 | 1.44 | 0 | Card headline — the only place weight 600 appears | | `{typography.title-sm}` | 18px | 500 | 1.16 | +0.005em | Menu and list headings | | `{typography.body}` | 18px | 400 | 1.4 | 0 | **Base size.** Body copy, list items | | `{typography.body-medium}` | 16px | 500 | 1.4 | +0.005em | Emphasised UI copy, large button labels | | `{typography.label}` | 14px | 500 | 1.4 | +0.005em | Buttons, nav items, footer links | | `{typography.eyebrow}` | 12px | 500 | 1 | +0.08em | Category labels, set lowercase | ### Principles - **The two faces track in opposite directions.** Sans runs +0.005em at almost every step; serif runs −0.01em. Applying one face's tracking to the other is the fastest way to break the voice. - **Weight stops at 500 for display.** 600 appears only at `{typography.title-md}`. There is no 700 anywhere in the observed set. - **Body is 18px.** Two to four pixels larger than most product sites, and the single biggest reason the pages read as a magazine. - **Eyebrows are lowercase with wide tracking** (+0.08em) rather than uppercase — quieter than the usual all-caps label. - **Line-height inverts with size**: 1 to 1.16 across display, 1.4 for body, 1.44 at the card-headline step. ### Note on Font Substitutes Both faces are proprietary (Adobe Fonts). Closest free substitutes: - **the-future** → **Neue Haas Grotesk** if licensed, otherwise **Inter** or **Manrope** at 400/500. Both run slightly tighter than the-future; keep the published +0.005em and add nothing further. - **tiempos** → **Newsreader** or **Source Serif 4** at weight 400. Both are marginally wider; add roughly a further `−0.005em` on top of the published −0.01em at display sizes. - Do not substitute a geometric display serif (Playfair, DM Serif) — Tiempos is a text serif, and the difference shows immediately at 200px. ## Layout ### Spacing System - **Base unit:** 4px. The published scale is `--ws-spacing-N` where N is the count of quarter-rem units: `1` = 4px, `4` = 16px, `8` = 32px, `16` = 64px, `24` = 96px, `40` = 160px, up to `64` = 256px. - **Tokens here:** `{spacing.xs}` 4px · `{spacing.sm}` 8px · `{spacing.md}` 12px · `{spacing.base}` 16px · `{spacing.lg}` 24px · `{spacing.xl}` 32px · `{spacing.xxl}` 48px · `{spacing.section-sm}` 64px · `{spacing.section}` 96px · `{spacing.section-lg}` 160px. ### Grid & Container | Context | Max width | Inline padding | |---|---|---| | Content container | 1264px | 40px | | Navigation container | 1440px | 40px | Colour-field sections run full-bleed; only the content inside them is capped at 1264px. The nav is allowed a wider container than the content, so the header spans further than the text beneath it. ### Whitespace Philosophy Generous and editorial. The spacing scale reaches 256px, and section fields are separated by their colour change rather than by a rule, so the whitespace inside each field can be large without the page losing structure. The 18px body and the wide field grounds work together: this is a layout built for reading, not for scanning. ## Elevation & Depth | Level | Treatment | Use | |---|---|---| | Flat | Colour-field change only | Sections — the primary structural device | | Rule | 1px `{colors.outlines}` | Cards, inputs, dividers, tables | | Floating | `0 1px 4px rgb(16 24 40/10%), 0 1px 2px rgb(16 24 40/6%)` | The only shadow in the system — menus and floating panels | | Blur | `backdrop-filter: blur(16px)` over `{colors.ink-strong}` at 90% | The header, and only the header | **Shadow philosophy.** One shadow token exists and it is deliberately weak — two stacked 1–4px offsets at 6–10% opacity. It appears on ten elements across the analyzed pages. Everything else is separated by a colour change or a hairline. A card in this system is a white rectangle with a 1px warm-grey edge, not a lifted surface. ### Decorative Depth - **Colour fields** carry all the visual weight. - **Translucency** is used through `color-mix(in srgb, …)` for button and hover fills rather than through opacity on the element, so text stays fully opaque. ## Shapes ### Border Radius Scale | Token | Value | Use | |---|---|---| | `{rounded.none}` | 0px | Full-bleed section fields | | `{rounded.small}` | 4px | Tags, the smallest chips | | `{rounded.normal}` | 12px | **Cards, panels, nav items** — 53–61 of the rounded elements per page | | `{rounded.large}` | 24px | Feature cards, media frames | | `{rounded.xlarge}` | 32px | Large containers | | `{rounded.pill}` | 1000px | **Every button, and every input** — 20–31 uses per page | | `{rounded.circle}` | 50% | Avatars, icon buttons | The grammar is two-tier and unusually strict: **pill means interactive, 12px means container**. The input fields are pills too, which is rare and is part of why forms here look friendly rather than administrative. ### Media Geometry Media sits in `{rounded.normal}` or `{rounded.large}` frames. Inside a colour field, imagery is often full-bleed and square-cornered, letting the field itself act as the frame. ## Components ### Top Navigation **`header`** — 92px tall (`5.75rem`), ground `{colors.ink-strong}` at 90% opacity with `backdrop-filter: blur(16px)`, so the field beneath shows through. Nav items are `{component.nav-item}`: transparent, `{rounded.normal}`, 32px tall, `{typography.label}`. The right cluster pairs `{component.button-translucent}` ("Log in") with `{component.button-solid}` ("Get started"). ### Buttons Every button is `{rounded.pill}`, in two sizes. **`button-solid`** — `{colors.ink}` fill, `{colors.ink-inverse}` label, `{typography.label}`, `12px 16px` padding, ~44px tall. Pressed moves to `{colors.ink-strong}`. **`button-solid-large`** — the same in `{typography.body-medium}` with `20px 32px` padding and a 64px height. Used once per section. **`button-inverse`** — `{colors.ink-inverse}` fill with `{colors.ink}` label, for use on a dark `{component.section-field}`. **`button-translucent`** — `color-mix(in srgb, #fcfcfc 20%, transparent)`. The secondary action on any field, light or dark, because it takes its character from whatever it sits on. ### Cards & Containers **`card`** — `{colors.background-white}` on the off-white page, a 1px `{colors.outlines}` rule, `{rounded.normal}`, `{spacing.lg}` padding. No shadow. **`section-field`** — the signature component. A full-bleed band in one of the field colours with its text colour flipped for contrast, holding a `{typography.display}` headline, body copy and one or two pill actions. ### Inputs & Forms **`input`** — `{colors.background-white}` fill, 1px `{colors.outlines}` border, **`{rounded.pill}`**, 64px tall, `{typography.body}` (18px), `20px 24px` padding. Focus draws a 3px ring in `color-mix(in srgb, #1c1b1b 50%, transparent)` at a 2px offset. Error text uses `{colors.terracotta-40}` on `{colors.background-error}`; success uses `{colors.celery-40}`. Disabled fields drop to 60% opacity with a `color-mix` fill. Error and success **tokens** are published; a rendered error state was not observed — see `## Known Gaps`. ### Footer **`footer`** — `{colors.background}` ground, links in `{typography.label}` at `{colors.ink}`, body text at `{typography.body}`. ## Do's and Don'ts ### Do - Build sections as full-bleed colour fields and flip the text colour for contrast. - Keep the chrome greyscale; let the field carry the colour. - Set body copy at `{typography.body}` (18px) — the editorial pace depends on it. - Track the sans positively (+0.005em) and the serif negatively (−0.01em). - Give every button and every input `{rounded.pill}`, and every container `{rounded.normal}`. - Separate cards with a 1px `{colors.outlines}` rule rather than a shadow. - Use `color-mix()` for translucent fills so the control adapts to the field behind it. - Animate with `cubic-bezier(.241, .969, .635, .997)` at 0.35s. - Set eyebrows lowercase at `{typography.eyebrow}` with +0.08em tracking. ### Don't - Don't introduce a brand accent colour; there is none, and adding one collapses the field system. - Don't use pure white as a page ground — `{colors.background}` is off-white, and pure white is reserved for cards and inputs. - Don't set display type above weight 500. - Don't square the inputs; the pill is deliberate. - Don't add a second shadow, or use the one shadow to lift a card. - Don't apply the sans tracking to the serif, or vice versa. - Don't set eyebrows in uppercase. ## Responsive Behavior ### Breakpoints The published constants are the container caps (1264px content, 1440px nav) and a 40px inline padding; mobile header padding drops to `1.25rem` left and `1rem` right. Type steps down through the published ladder rather than by fluid clamping. ### Touch Targets Buttons render at ~44px in the small size and 64px in the large size; inputs are 64px. Nav items sit at 32px, which is a desktop-density control — the mobile navigation replaces them with a menu. ### Collapsing Strategy - **Header:** the desktop menu collapses behind a trigger; the 92px height and the action pair persist. - **Colour fields:** stack vertically and keep their full-bleed grounds. - **Type:** display steps down; `{typography.body}` holds at 18px. ### Image Behavior Media keeps its frame radius across widths. Full-bleed imagery inside a field crops rather than scales, so the field height stays predictable. ## Iteration Guide 1. Decide the section's field colour first — it determines the text colour and which button variant is available. 2. Work on one component at a time, addressed by its YAML key (`{component.section-field}`, `{component.button-solid}`). 3. Use `{token.refs}` everywhere; never inline a hex once a token exists. 4. Document default and active/pressed states only — never hover. 5. The two rules that define this system: **colour lives in full-bleed fields, never in the chrome**, and **pill means interactive, 12px means container**. 6. Reach for the serif only where a moment should read as written; the sans is the default. 7. Before adding elevation, add a 1px rule or change the field. ## Known Gaps - **No rendered error or validation state was observed.** The token family (`--ws-color-text-error`, `--ws-color-background-error`, `--ws-color-input-*`) is complete and documented above, but no form on the analyzed pages was in an error condition. - **No dark theme is published.** The system has dark *fields* but no inverted token set; `{colors.background-midnight}` is a ground, not a theme. - **The serif's role is inferred from three pages.** `tiempos` set the hero on the Trade page and was absent from the homepage and the magazine index, so it reads as a per-page editorial choice rather than a defined role. A wider sample may show a rule. - **Two loaded faces were never seen in use.** `wealthsimple-sans` and `wealthsimple-display-sans` are fetched by the page but did not resolve on any measured element. - **The section field colours are not tokens.** They were read off rendered sections and are art direction; a fourth or fifth product page would likely add more. - **The spacing tokens above the section scale are derived.** Wealthsimple publishes `--ws-spacing-1` through `-64`; the section groupings named here are the dominant measured usages, not published semantics.