Klarna
MIT
Clean, modern fintech interface with Klarna's signature pink accents and dark eggplant typography, designed for seamless payment and shopping experiences
Colour (195)
color.cta10#FFD0E2
color.cta20#FFD0E2
color.cta30#FFA8CD
color.cta60#FFA8CD
color.cta80#E27EAC
color.focus#7B57D8
color.cta100#E27EAC
color.brand10#EFECFF
color.brand20#E4E0F7
color.brand30#D9C2FB
color.brand40#AA89F2
color.brand50#7B57D8
color.brand60#7039E2
color.brand70#5C32B8
color.brand80#3D2A70
color.brand90#2C2242
color.border10#F3F3F5
color.border20#E2E2E7
color.border40#C4C3CA
color.border60#615F6D
color.border95#1D192A
color.brand100#0B051D
color.saletext#e61919
color.balloon35#B798BE
color.border100#0B051D
color.content10#feede2
color.content20#f3d5d0
color.content40#e2beb7
color.content60#bc627b
color.content80#910737
color.content90#3d0f1f
color.warning10#F9F0AA
color.warning20#F0E788
color.warning30#DBCA6E
color.warning40#A79542
color.warning50#7C7027
color.warning60#6D621D
color.warning70#554C14
color.warning80#423900
color.negative10#FFE9E9
color.negative30#F5BECA
color.negative40#E47B93
color.negative50#B94966
color.negative70#942546
color.negative80#6A152F
color.positive10#CCF9D4
color.positive20#A8F3B7
color.positive50#287E59
Spacing (26)
spacing.headingsizexxs0.875rem
spacing.headingsizexs1rem
spacing.headingsizes1.25rem
spacing.headingsizem1.625rem
spacing.headingsizel2rem
spacing.headingsizexl2.5625rem
spacing.headingsizexxl3.25rem
spacing.spacesspace44px
spacing.spacesspace88px
spacing.spacesspace1212px
spacing.spacesspace1616px
spacing.headinglhxxs18px
spacing.headerbordervar(--border20)
spacing.spacesspace2020px
spacing.headinglhxs22px
spacing.spacesspace2424px
spacing.headinglhs26px
spacing.headinglhm32px
spacing.spacesspace3232px
spacing.headinglhl36px
spacing.spacesspace4040px
spacing.headinglhxl42px
spacing.spacesspace4848px
spacing.headinglhxxl52px
spacing.spacesspace6464px
spacing.spacesspace8080px
Radius (11)
radiusxs2px
radiuss4px
radiusm12px
radiusl16px
radiussm20px
radiusxl24px
radiusxxl32px
radiusmd50px
radiuslg100px
radiusfull100%
radiusesradiusround99999px
Shadow (23)
effect.shadowlgrgb(226, 226, 231) 0px 2px 6px 0px
effect.shadowmdrgba(0, 0, 0, 0) 0px 0px 0px 1px inset
effect.shadowsmrgb(228, 227, 223) 0px 0px 0px 1px inset
effect.weightsbold700
effect.weightmedium500
effect.weightnormal400
effect.shadowprimarynone
effect.headingcontentvar(--grayscale100)
effect.shadowsshadowl0px 12px 24px 0px rgba(0,0,0,0.1)
effect.shadowsshadowm0px 6px 12px 0px rgba(0,0,0,0.1)
effect.shadowsshadows0px 2px 4px 0px rgba(0,0,0,0.1)
effect.lineheightsbodymobilescalc(20px + (1rem - 16px) * 0.9412)
effect.lineheightsbodydesktoplcalc(28px + (1rem - 16px) * 0.8235)
effect.lineheightsdisplaymobilelcalc(50px + (1rem - 16px) * 0.5)
effect.lineheightsdisplaymobilescalc(32px + (1rem - 16px) * 0.7647)
effect.lineheightsheadingmobilescalc(24px + (1rem - 16px) * 0.8824)
effect.lineheightsdisplaydesktoplcalc(62px + (1rem - 16px) * 0.3235)
effect.lineheightsdisplaydesktopmcalc(52px + (1rem - 16px) * 0.4706)
effect.lineheightsdisplaydesktopscalc(40px + (1rem - 16px) * 0.6471)
effect.lineheightsdisplaymobilexlcalc(66px + (1rem - 16px) * 0.2647)
effect.lineheightsheadingdesktoplcalc(48px + (1rem - 16px) * 0.5294)
effect.lineheightsdisplaydesktopxlcalc(80px + (1rem - 16px) * 0.0588)
effect.lineheightsheadingdesktopxlcalc(56px + (1rem - 16px) * 0.4118)
# layout.md — Klarna Design System
---
## 0. Quick Reference
**Stack:** Extracted CSS custom properties (538 vars, high confidence) · Bootstrap detected · Custom font: Klarna Title / Klarna Text with system fallbacks · Token source: `extracted-css-vars` (1:1 fidelity).
**How to apply:** Use as `var(--token-name)` in CSS, `style={{ prop: 'var(--token-name)' }}` in JSX, or `bg-[var(--token-name)]` in Tailwind.
```css
:root {
/* Backgrounds */
--colors-bg-page: #FFFFFF;
--colors-bg-subtle: #F3F3F5;
--colors-bg-inverse: #0B051D;
--colors-bg-brand: #FFA8CD; /* Klarna pink — hero/CTA backgrounds */
/* Text */
--colors-text-default: #0B051D; /* Primary text, near-black eggplant */
--colors-text-body: #282636; /* Body copy */
--colors-text-subtle: #504F5F; /* Secondary/supporting text */
--colors-text-inverse: #F9F8F5; /* Text on dark surfaces */
--colors-text-link: #582FB4; /* Links */
/* Actions */
--colors-btn-primary: #0B051D; /* Primary button bg */
--colors-btn-brand: #FFA8CD; /* Brand/CTA button bg */
--colors-btn-secondary: #F3F3F5; /* Secondary button bg */
--primary-action-hover: #28272E; /* Primary button hover bg */
--button-background-secondary-hover: #E2E2E7;
/* Borders & Focus */
--colors-border-default: #E2E2E7;
--headerBorder: #ebeff5;
--focus: #7B57D8; /* Focus ring — purple */
/* Status */
--colors-bg-positive: #046234;
--colors-bg-warning: #FBC64D;
--colors-bg-negative: #AE1D1D;
/* Radius — pill-shaped brand buttons */
--radius-sm: 8px; /* Cards, chips */
--radius-lg: 100px; /* Primary pill buttons */
--radiuses-radius-round: 99999px; /* Circular elements */
/* Spacing (4px grid) */
--spaces-space-4: 4px;
--spaces-space-8: 8px;
--spaces-space-16: 16px;
--spaces-space-24: 24px;
--spaces-space-48: 48px;
--spaces-space-64: 64px;
/* Motion */
--duration-fast: 0.2s;
--duration-base: 0.3s;
--ease-default: ease;
/* Typography */
--fonts-font-brand-title: "Klarna Title", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Arial, sans-serif;
--fonts-font-brand-text: "Klarna Text", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Arial, sans-serif;
}
```
```tsx
// Primary button — correct token usage
<button className="btn-primary" style={{
backgroundColor: 'var(--colors-btn-primary)',
color: 'var(--colors-text-inverse)',
borderRadius: 'var(--radius-lg)',
fontFamily: 'var(--fonts-font-brand-text)',
transition: 'background var(--duration-base) var(--ease-default)',
}}>Pay Now</button>
```
**NEVER rules:**
- NEVER use `border-radius` values other than `--radius-sm` (8px), `--radius-lg` (100px), or `--radiuses-radius-round` (99999px) on buttons.
- NEVER hardcode `#FFA8CD` — use `var(--colors-bg-brand)` or `var(--colors-btn-brand)`.
<!-- Quick Reference truncated to fit the 75-line cap. See later sections for the full design system. -->
## 1. Design Direction & Philosophy
### Character & Aesthetic Intent
Klarna's design is **confident, modern fintech** with a distinctive brand personality: dark near-black eggplant (`#0B051D`) paired with signature Klarna pink (`#FFA8CD`) creates a premium-yet-playful contrast. The aesthetic is clean and minimal with generous whitespace, large display typography, and smooth rounded pill-shaped CTAs. The brand communicates trust through restraint — no gradients, no decorative noise on core UI — while injecting personality through brand color accents.
**Typefaces define the hierarchy:** `Klarna Title` (a custom heading face) carries authority and brand distinctiveness; `Klarna Text` and the system font stack handle body copy readability. Display type scales dramatically large (90px h1) to create impactful hero moments.
### What This Design Explicitly Rejects
- **No sharp-cornered buttons.** All interactive pill elements use `border-radius: 100px` or `99999px`. A rectangular button is never correct for primary or brand CTAs.
- **No warm neutral palettes.** Klarna's neutrals are cool-gray (`#F3F3F5`, `#E2E2E7`) with a purple-eggplant undertone, not warm beige.
- **No decorative drop shadows on cards by default.** Cards use subtle inset borders on hover (`inset 0 0 0 1px var(--border100)`), not floating box shadows.
- **No arbitrary purple.** The purple accent (`#7039E2`, `#582FB4`) is reserved for accent text, badge accents, and focus rings — never as a primary button color.
- **No dark mode switching** (single light mode is the canonical surface for the brand marketing site).
---
## 2. Colour System
### Tier 1 — Primitives (from extracted CSS vars)
```css
/* Brand Scale */
--brand10: #EFECFF;
--brand20: #E4E0F7;
--brand30: #D9C2FB;
--brand40: #AA89F2;
--brand50: #7B57D8;
--brand60: #7039E2;
--brand70: #5C32B8;
--brand80: #3D2A70;
--brand90: #2C2242;
--brand100: #0B051D;
/* Klarna Named Palette */
--colors-klarna-pink: #FFA8CD; /* Signature pink */
--colors-klarna-eggplant: #2F1F5A; /* Deep eggplant */
--colors-klarna-black: #0B051D; /* Near-black */
--colors-klarna-balloon: #B798BE; /* Muted mauve */
--colors-klarna-off-white: #F9F8F5; /* Warm off-white */
--colors-klarna-herring: #E4E3DF; /* Warm light gray */
--colors-klarna-sticky-note: #E6FFA9; /* Lime accent */
/* CTA Pink Scale */
--cta10: #FFD0E2;
--cta20: #FFD0E2;
--cta30: #FFA8CD; /* Base brand CTA */
--cta60: #FFA8CD;
--cta80: #E27EAC; /* Darker hover state */
--cta100: #E27EAC;
/* Border Scale */
--border10: #F3F3F5;
--border20: #E2E2E7;
--border40: #C4C3CA;
--border60: #615F6D;
--border95: #1D192A;
--border100: #0B051D;
/* Status — Positive */
--positive10: #CCF9D4;
--positive20: #A8F3B7;
--colors-bg-positive: #046234;
--colors-bg-positive-subtle: #E6FCEB;
--colors-text-positive: #046234;
--colors-text-positive-heading: #06884A;
/* Status — Warning */
--warning10: #F9F0AA;
--colors-bg-warning: #FBC64D;
--colors-bg-warning-subtle: #FFF5E4;
--colors-text-warning: #664600;
/* Status — Negative */
--colors-bg-negative: #AE1D1D;
--colors-bg-negative-subtle: #FFE6E6;
--colors-text-negative: #931414;
--colors-text-negative-heading: #DC2B2B;
--colors-border-negative: #AE1D1D;
/* Sale */
--saleText: #e61919;
--saleBackground: #ffcfcf;
```
### Tier 2 — Semantic Aliases
```css
/* Surface */
--colors-bg-page: #FFFFFF; /* Page background */
--colors-bg-plain: #FFFFFF; /* Plain white surface */
--colors-bg-container: #F8F7FA; /* Container/section background */
--colors-bg-subtle: #F3F3F5; /* Subtle surface, secondary button bg */
--colors-bg-neutral: #E2E2E7; /* Neutral dividers and fills */
--colors-bg-inverse: #0B051D; /* Dark inverse (footer, hero dark bg) */
--colors-bg-accent: #7039E2; /* Accent surface (purple) */
--colors-bg-brand: #FFA8CD; /* Brand pink surface */
--colors-bg-accent-subtle: #EFECFF; /* Subtle accent surface */
--headerBackground: #fefefe; /* Header background */
--footerBackground: #0B051D; /* Footer background — inverse black */
/* Text */
--colors-text-default: #0B051D; /* Primary text — max contrast */
--colors-text-body: #282636; /* Body copy */
--colors-text-subtle: #504F5F; /* Subtle/secondary text */
--colors-text-disabled: #96959F; /* Disabled state text */
--colors-text-placeholder: #96959F; /* Input placeholder */
--colors-text-inverse: #F9F8F5; /* On dark surfaces */
--colors-text-accent: #582FB4; /* Accent/link text */
--colors-text-accent-heading: #7039E2; /* Accent headings */
--colors-text-link: #582FB4; /* Hyperlinks */
/* Borders */
--colors-border-default: #E2E2E7; /* Default border */
--colors-border-neutral: #C4C3CA; /* Neutral border (stronger) */
--colors-border-active: #0B051D; /* Active/selected border */
--headerBorder: #ebeff5; /* Header bottom border */
/* Focus */
--focus: #7B57D8; /* Focus ring — purple brand */
/* Overlays */
--colors-overlay-hover-default: rgba(0, 0, 0, 0.04);
--colors-overlay-press-default: rgba(0, 0, 0, 0.08);
--colors-overlay-dialog: rgba(0, 0, 0, 0.16);
--colors-overlay-fadeout: rgba(255, 255, 255, 0.56);
--colors-overlay-border-subtle: rgba(11, 5, 29, 0.12);
```
### Tier 3 — Component Tokens
```css
/* Buttons */
--colors-btn-primary: #0B051D; /* Primary button background */
--colors-btn-secondary: #F3F3F5; /* Secondary button background */
--colors-btn-tertiary: #FFFFFF; /* Tertiary button background */
--colors-btn-ghost: rgba(255, 255, 255, 0); /* Ghost button */
--colors-btn-brand: #FFA8CD; /* Brand/CTA pink button */
--colors-btn-danger: #AE1D1D; /* Danger/destructive button */
--colors-btn-disabled: #F3F3F5; /* Disabled button background */
--colors-btn-idle: #C4C3CA; /* Idle button state */
--primary-action-base: #0B051D; /* Primary action base */
--primary-action-hover: #28272E; /* Primary action hover */
--primary-action-active: #0B051D; /* Primary action active */
--primary-action-disabled: #E2E2E7; /* Primary action disabled */
--button-background-secondary: #F3F3F5;
--button-background-secondary-hover: #E2E2E7;
/* Badges */
--colors-badge-strong: #000000;
--colors-badge-pop: #CFF066; /* Lime pop badge */
--colors-badge-brand: #FFA8CD; /* Pink brand badge */
--colors-badge-accent: #E4E0F7; /* Subtle accent badge */
--colors-badge-accent-inverse: #7B57D8; /* Inverse accent badge */
--colors-badge-positive: #C1F4D1;
--colors-badge-positive-inverse: #06884A;
--colors-badge-negative: #FFB8B8;
--colors-badge-negative-inverse: #AE1D1D;
--colors-badge-warning: #FFE8B7;
--colors-badge-warning-inverse: #AD7C00;
/* Inputs */
--inputBackground: #FFFFFF;
--input-background: #FFFFFF;
--inputBackgroundDisabled: #E2E2E7;
--input-background-disabled: #E2E2E7;
/* Ribbons */
--ribbon-default-background: #E4E3DF;
--ribbon-default-text: #0B051D;
--ribbon-sale-background: #FCD3D3;
--ribbon-sale-text: #B62454;
--ribbon-watched-background: #E6FFA9;
--ribbon-watched-text: #0B051D;
--ribbon-in-stock-background: #A8F3B7;
--ribbon-in-stock-text: #00331D;
--ribbon-out-of-stock-background: #FDE2E2;
--ribbon-out-of-stock-text: #500D22;
--ribbon-rank-background: #E4E0F7;
--ribbon-rank-text: #0B051D;
--ribbon-popular-background: #E4E0F7;
--ribbon-popular-text: #0B051D;
--ribbon-unknown-stock-background: #F3F3F5;
--ribbon-unknown-stock-text: #37363F;
```
### Accent / Brand Subgroup (decorative, illustration, data viz)
```css
/* Unassigned brand accents — decorative tiles, illustration, charts */
--saleText: #e61919; /* Sale price text — red */
--colors-badge-warning-inverse: #AD7C00; /* Warning badge inverse */
--colors-text-accent-heading: #7039E2; /* Purple accent heading */
--stickynote30: #AAD336; /* Sticky-note lime */
--colors-data-6: #3F7FDC; /* Data series 6 — blue */
--colors-data-positive: #0EAA5D; /* Data positive — green */
--colors-data-1: #E57DAF; /* Chart series 1 */
--colors-data-2: #7039E2; /* Chart series 2 */
--colors-data-3: #379FAA; /* Chart series 3 */
--colors-data-4: #CF7F3E; /* Chart series 4 */
--colors-data-5: #A03DB3; /* Chart series 5 */
--colors-data-7: #1A6773; /* Chart series 7 */
--colors-data-8: #AC4A85; /* Chart series 8 */
```
| Role | Token | Value |
|------|-------|-------|
| Page bg | `--colors-bg-page` | `#FFFFFF` |
| Section bg | `--colors-bg-container` | `#F8F7FA` |
| Subtle bg | `--colors-bg-subtle` | `#F3F3F5` |
| Inverse bg | `--colors-bg-inverse` | `#0B051D` |
| Brand pink | `--colors-bg-brand` | `#FFA8CD` |
| Primary text | `--colors-text-default` | `#0B051D` |
| Body text | `--colors-text-body` | `#282636` |
| Subtle text | `--colors-text-subtle` | `#504F5F` |
| Inverse text | `--colors-text-inverse` | `#F9F8F5` |
| Link | `--colors-text-link` | `#582FB4` |
| Primary CTA bg | `--colors-btn-primary` | `#0B051D` |
| Brand CTA bg | `--colors-btn-brand` | `#FFA8CD` |
| Focus ring | `--focus` | `#7B57D8` |
---
## 3. Typography System
### Font Stacks
```css
--fonts-font-brand-title: "Klarna Title", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Arial, sans-serif;
--fonts-font-brand-text: "Klarna Text", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Arial, sans-serif;
--fonts-font-system: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Arial, sans-serif;
--fonts-font-monospace: monospace, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Arial, sans-serif;
```
### Weight Scale
```css
--weights-normal: 400;
--weights-medium: 500;
--weights-bold: 700;
```
### Composite Typography Groups
**Rule:** ALWAYS use heading composites together — never set `font-size` without also setting `font-family`, `font-weight`, and `line-height`.
```css
/* ── DISPLAY SCALE (Klarna Title, fluid/responsive) ── */
/* Display S — Mobile: ~32px → Desktop: ~40px */
.type-display-s {
font-family: var(--fonts-font-brand-title);
font-size: var(--textSizes-display-mobile-s); /* calc(32px + (1rem - 16px) * 0.4472) */
font-weight: var(--weights-bold); /* 700 */
line-height: var(--lineHeights-display-mobile-s); /* calc(32px + (1rem - 16px) * 0.7647) */
letter-spacing: normal;
}
/* Display M — Mobile: ~40px → Desktop: ~52px */
.type-display-m {
font-family: var(--fonts-font-brand-title);
font-size: var(--textSizes-display-mobile-m); /* calc(40px + (1rem - 16px) * 0.2709) */
font-weight: var(--weights-bold); /* 700 */
line-height: var(--lineHeights-display-mobile-m); /* calc(40px + (1rem - 16px) * 0.6471) */
letter-spacing: normal;
}
/* Display L — Mobile: ~52px → Desktop: ~64px */
.type-display-l {
font-family: var(--fonts-font-brand-title);
font-size: var(--textSizes-display-mobile-l); /* calc(52px + (1rem - 16px) * 0.1042) */
font-weight: var(--weights-bold); /* 700 */
line-height: var(--lineHeights-display-mobile-l); /* calc(50px + (1rem - 16px) * 0.5) */
letter-spacing: normal;
}
/* Display XL — Mobile: ~68px → Desktop: 84px */
.type-display-xl {
font-family: var(--fonts-font-brand-title);
font-size: var(--textSizes-display-desktop-xl); /* 84px — desktop max */
font-weight: var(--weights-bold); /* 700 — confirmed from h1 computed style */
line-height: var(--lineHeights-display-desktop-xl); /* calc(80px + ...) ≈ 99px on h1 */
letter-spacing: normal;
}
/* ── HEADING SCALE (Klarna Title, fluid) ── */
/* Heading S — ~20–24px */
.type-heading-s {
font-family: var(--fonts-font-brand-title);
font-size: var(--textSizes-heading-mobile-s); /* calc(20px + (1rem - 16px) * 0.8337) */
font-weight: var(--weights-medium); /* 500 */
line-height: var(--lineHeights-heading-mobile-s); /* calc(24px + ...) */
letter-spacing: normal;
}
/* Heading M — ~28–32px */
.type-heading-m {
font-family: var(--fonts-font-brand-title);
font-size: var(--textSizes-heading-mobile-m); /* calc(28px + (1rem - 16px) * 0.5585) */
font-weight: var(--weights-medium); /* 500 */
line-height: var(--lineHeights-heading-mobile-m); /* calc(32px + ...) */
letter-spacing: normal;
}
/* Heading L — ~40–44px */
.type-heading-l {
font-family: var(--fonts-font-brand-title);
font-size: var(--textSizes-heading-mobile-l); /* calc(40px + (1rem - 16px) * 0.2709) */
font-weight: var(--weights-medium); /* 500 — confirmed h2 computed */
line-height: var(--lineHeights-heading-mobile-l); /* calc(40px + ...) */
letter-spacing: normal;
}
/* Heading XL — ~44–52px */
.type-heading-xl {
font-family: var(--fonts-font-brand-title);
font-size: var(--textSizes-heading-mobile-xl); /* calc(44px + (1rem - 16px) * 0.2035) */
font-weight: var(--weights-medium); /* 500 */
line-height: var(--lineHeights-heading-mobile-xl); /* calc(48px + ...) */
letter-spacing: normal;
}
/* ── BODY / TEXT SCALE (Klarna Text / system font) ── */
/* Body XS — 12px / 1rem */
.type-body-xs {
font-family: var(--fonts-font-brand-text);
font-size: var(--textSizes-text-mobile-xs); /* min(0.75rem, ...) ≈ 12px */
font-weight: var(--weights-normal); /* 400 */
line-height: var(--lineHeights-body-mobile-xs); /* min(1rem, ...) ≈ 16px */
letter-spacing: normal;
}
/* Body S — 14px / 20px */
.type-body-s {
font-family: var(--fonts-font-brand-text);
font-size: var(--textSizes-text-mobile-s); /* min(0.875rem, ...) ≈ 14px */
font-weight: var(--weights-normal); /* 400 — confirmed body computed */
line-height: var(--lineHeights-body-mobile-s); /* calc(20px + ...) ≈ 20px */
letter-spacing: normal;
}
/* Body M — 16px / 24px */
.type-body-m {
font-family: var(--fonts-font-brand-text);
font-size: var(--textSizes-text-mobile-m); /* min(1rem, ...) ≈ 16px */
font-weight: var(--weights-normal); /* 400 */
line-height: var(--lineHeights-body-mobile-m); /* calc(24px + ...) ≈ 24px */
letter-spacing: normal;
}
/* Body L — 18–20px / 24-28px */
.type-body-l {
font-family: var(--fonts-font-brand-text);
font-size: var(--textSizes-text-mobile-l); /* calc(18px + ...) */
font-weight: var(--weights-normal); /* 400 */
line-height: var(--lineHeights-body-mobile-l); /* calc(24px + ...) */
letter-spacing: normal;
}
/* ── LABEL SCALE ── */
/* Label M — 16px / 20px (confirmed: label computed style) */
.type-label-m {
font-family: var(--fonts-font-brand-text);
font-size: var(--text-size-m); /* 1rem = 16px */
font-weight: var(--weights-medium); /* 500 */
line-height: var(--lineHeights-label-mobile-m); /* calc(20px + ...) ≈ 20px */
letter-spacing: normal;
}
/* Label S */
.type-label-s {
font-family: var(--fonts-font-brand-text);
font-size: var(--text-size-s); /* 0.875rem = 14px */
font-weight: var(--weights-medium); /* 500 */
line-height: var(--lineHeights-label-mobile-s); /* min(1rem, ...) ≈ 16px */
letter-spacing: normal;
}
```
### Typographic Pairing Rules
| Role | Font | Weight | Token |
|------|------|--------|-------|
| Hero / Display | Klarna Title | 700 | `--fonts-font-brand-title` + `--weights-bold` |
| Section Heading (h2) | Klarna Title | 500 | `--fonts-font-brand-title` + `--weights-medium` |
| Sub-heading (h3) | Klarna Title | 700 | `--fonts-font-brand-title` + `--weights-bold` |
| Body copy | Klarna Text / system | 400 | `--fonts-font-brand-text` + `--weights-normal` |
| Labels / UI text | Klarna Text / system | 500 | `--fonts-font-brand-text` + `--weights-medium` |
| Monospace | system mono | 400 | `--fonts-font-monospace` |
---
## 4. Spacing & Layout
### Base Unit: **4px**
All spacing values are multiples of 4px. NEVER use off-grid values.
```css
/* ── Complete Spacing Scale ── */
--spaces-space-4: 4px; /* Micro — icon gap, tight internal padding */
--spaces-space-8: 8px; /* XS — tag padding, inline gap */
--spaces-space-12: 12px; /* SM — compact component padding */
--spaces-space-16: 16px; /* Base — standard component padding */
--spaces-space-20: 20px; /* MD — button vertical padding approx */
--spaces-space-24: 24px; /* LG — card internal gap, form spacing */
--spaces-space-32: 32px; /* XL — section inner padding */
--spaces-space-40: 40px; /* 2XL — component vertical gap */
--spaces-space-48: 48px; /* 3XL — card grid gap (confirmed: card computed gap:48px) */
--spaces-space-64: 64px; /* 4XL — section vertical padding */
--spaces-space-80: 80px; /* 5XL — large section gap */
```
### Radius Scale
```css
--radius-xs: 2px; /* Micro radius */
--radius-s: 4px; /* Small chip/tag */
--radius-sm: 8px; /* Cards, modals, badges */
--radius-m: 12px; /* Medium panels */
--radius-l: 16px; /* Large panels, card surfaces (confirmed: card computed 16px) */
--radius-xl: 24px; /* XL panels */
--radius-xxl: 32px; /* XXL panels */
--radiuses-radius-round: 99999px; /* Fully pill/circular */
/* CANONICAL BUTTON RADII */
/* Small buttons: 20px (9 elements, confirmed mined) */
/* Standard pill buttons: 100px (7 elements, confirmed mined) — use for ALL primary/brand CTAs */
/* Circular icon buttons: 100% (2 elements, confirmed mined) */
```
### Grid System & Breakpoints
```css
/* ── Breakpoints ── */
/* Mobile base: < 640px */
/* Tablet: 640px */
/* Tablet+: 768px */
/* Small desktop: 1024px */
/* Large desktop: 1536px */
/* Additional intermediate breakpoints extracted: */
/* 400px, 425px, 426px, 476px, 480px, 530px, 550px, 600px, */
/* 639px, 849px, 850px, 896px, 1023px */
/* ── Navigation Layout (from computed: role_navigation) ── */
/* display: flex; flex-direction: row; gap: 48px; align-items: center */
/* ── Card Grid Layout (from computed: card) ── */
/* display: grid; gap: 48px; border-radius: 16px; */
/* ── Primary Button Layout (from computed: button_primary) ── */
/* display: flex; flex-direction: row; justify-content: center; align-items: center; */
/* border-radius: 100px; */
```
---
## 5. Page Structure & Layout Patterns
*No screenshots supplied. Sections inferred from layout digest, component inventory, and computed styles. Rows marked "(inferred)" are not visually confirmed.*
### 5.1 Section Map
| # | Section | Layout Type | Approx Height | Key Elements |
|---|---------|-------------|---------------|--------------|
| 1 | Header / Nav | `flex row`, `gap: 48px` | ~64–80px | Logo, nav links, Login CTA (`--colors-btn-primary`), Shopping link |
| 2 | Hero | Full-width dark (`--colors-bg-inverse: #0B051D`) | ~560–720px (inferred) | H1 @ 90px/700, brand pink accent text, pink CTA button (`--colors-btn-brand`) |
| 3 | Feature Grid / Cards | `display: grid`, `gap: 48px` | ~480–640px (inferred) | Card components with 16px radius, H2 @ 52px, body text, secondary CTAs |
| 4 | App / Product Highlights | Alternating content-image (inferred) | ~400px per row (inferred) | H2 heading, body paragraph, `--colors-btn-primary` CTA, product image |
| 5 | Testimonials / Ratings | Card or list layout (inferred) | ~320px (inferred) | Star rating, quote text, reviewer name, `--ratingBackground: #0B051D` |
| 6 | Badge / Ribbon Showcase | Horizontal scroll or grid (inferred) | ~200px (inferred) | Badge components, ribbon variants |
| 7 | CTA Banner | Full-width inverse or brand-pink bg (inferred) | ~240px (inferred) | H2, single primary CTA pill button |
| 8 | Footer | `display: flex` or grid, dark bg | ~320px (inferred) | `--footerBackground: #0B051D`, `--footer-top-content-text: #FFFFFF`, nav links, legal |
### 5.2 Layout Patterns
**Navigation:**
```
display: flex;
flex-direction: row;
align-items: center;
gap: 48px; /* confirmed: computed role_navigation */
border-bottom: 1px solid var(--headerBorder); /* #ebeff5 */
background: var(--headerBackground); /* #fefefe */
```
**Card Grid:**
```
display: grid;
gap: 48px; /* confirmed: computed card gap */
border-radius: 16px; /* confirmed: computed card border-radius */
background: var(--colors-klarna-off-white); /* #F9F8F5 */
```
**Hero Section (inferred from H1 computed style + bg-inverse token):**
```
background: var(--colors-bg-inverse); /* #0B051D */
color: var(--colors-text-inverse); /* #F9F8F5 */
/* H1: font-size: 90px; font-weight: 700; line-height: 99px; */
/* Primary CTA: background: var(--colors-btn-brand); border-radius: 100px; */
```
**Section containers (inferred from bg-container token):**
```
background: var(--colors-bg-container); /* #F8F7FA */
padding: var(--spaces-space-64) var(--spaces-space-48);
```
### 5.3 Visual Hierarchy
- **H1 at 90px / 700 weight (Klarna Title)** dominates the hero — the largest typographic element on the page.
- **H2 at 52px / 500 weight** heads feature sections; sometimes 41px for tighter sections.
- **Primary CTAs** are pill-shaped (`border-radius: 100px`), dark (`--colors-btn-primary: #0B051D`) or brand-pink (`--colors-btn-brand: #FFA8CD`). The login button is the primary dark CTA; brand/marketing CTAs use pink.
- **Cards** use `gap: 48px` internally (grid) — generous whitespace signals premium brand.
- **Footer** is always full-width inverse dark (`--footerBackground: #0B051D`) with white text.
- **Focus states** use purple ring: `box-shadow: 0 0 0 3px var(--focus)` (`#7B57D8`).
### 5.4 Content Patterns
**Card repeating pattern (inferred from grid + component inventory):**
```
[Icon or image]
[H3 heading — Klarna Title, 52px / 700]
[Body paragraph — Klarna Text, 16px / 400]
[Optional CTA link or button]
```
**Feature alternating row (inferred):**
```
[Left: text block → H2 + body + pill CTA]
[Right: product image or phone mockup]
Alternates L/R on each row.
```
**Badge/Ribbon labeling pattern (confirmed from ribbon token set):**
```
Ribbons appear on product cards: sale (pink/red), trending, popular, watched, rank, in-stock, out-of-stock.
Each ribbon uses a paired text + background token (e.g. --ribbon-sale-text + --ribbon-sale-background).
```
---
## 6. Component Patterns
### 6.1 Button
**Anatomy:** `[optional icon] [label text]`
**Token mappings:**
| State | Background | Text | Border/Shadow | Transform |
|-------|-----------|------|---------------|-----------|
| Default (primary) | `--colors-btn-primary` (#0B051D) | `--colors-text-inverse` (#F9F8F5) | none | — |
| Hover (primary) | `--primary-action-hover` (#28272E) | `--colors-text-inverse` | none | — |
| Active (primary) | `--primary-action-active` (#0B051D) | `--colors-text-inverse` | none | `scale(0.95)` |
| Focus-visible | — | — | `box-shadow: 0 0 0 3px var(--focus)` | — |
| Disabled | `--primary-action-disabled` (#E2E2E7) | `--colors-text-disabled` (#96959F) | none | — |
| Default (brand) | `--colors-btn-brand` (#FFA8CD) | `--colors-text-default` (#0B051D) | none | — |
| Hover (brand) | `--cta80` (#E27EAC) | `--colors-text-default` | none | — |
| Default (secondary) | `--colors-btn-secondary` (#F3F3F5) | `--colors-text-default` | none | — |
| Hover (secondary) | `--button-background-secondary-hover` (#E2E2E7) | `--colors-text-default` | none | — |
**Border radius:** ALWAYS `--radius-lg` (100px) for standard CTAs, `20px` for compact variants.
**Transition:** `box-shadow var(--duration-base) var(--ease-default), background var(--duration-base) var(--ease-default), transform var(--duration-base) var(--ease-default)`
```tsx
// Button.tsx — production-ready with full state handling
import React from 'react';
type ButtonVariant = 'primary' | 'brand' | 'secondary' | 'ghost';
interface ButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {
variant?: ButtonVariant;
isLoading?: boolean;
children: React.ReactNode;
}
const variantStyles: Record<ButtonVariant, React.CSSProperties> = {
primary: {
backgroundColor: 'var(--colors-btn-primary)',
color: 'var(--colors-text-inverse)',
},
brand: {
backgroundColor: 'var(--colors-btn-brand)',
color: 'var(--colors-text-default)',
},
secondary: {
backgroundColor: 'var(--colors-btn-secondary)',
color: 'var(--colors-text-default)',
},
ghost: {
backgroundColor: 'var(--colors-btn-ghost)',
color: 'var(--colors-text-default)',
border: '1px solid var(--colors-border-default)',
},
};
export function Button({
variant = 'primary',
isLoading = false,
disabled,
children,
...props
}: ButtonProps) {
const isDisabled = disabled || isLoading;
return (
<button
{...props}
disabled={isDisabled}
style={{
/* Layout */
display: 'inline-flex',
flexDirection: 'row',
justifyContent: 'center',
alignItems: 'center',
gap: 'var(--spaces-space-8)',
/* Sizing */
padding: '14px var(--spaces-space-24)',
/* Typography */
fontFamily: 'var(--fonts-font-brand-text)',
fontSize: 'var(--text-size-m)', /* 1rem / 16px */
fontWeight: 'var(--weights-normal)',
lineHeight: '1',
/* Appearance */
borderRadius: '100px', /* --radius-lg canonical value */
border: 'none',
cursor: isDisabled ? 'not-allowed' : 'pointer',
transition: [
`background var(--duration-base) var(--ease-default)`,
`box-shadow var(--duration-base) var(--ease-default)`,
`transform var(--duration-base) var(--ease-default)`,
`color var(--duration-base) var(--ease-default)`,
].join(', '),
/* Disabled override */
...(isDisabled ? {
backgroundColor: 'var(--colors-btn-disabled)',
color: 'var(--colors-text-disabled)',
} : variantStyles[variant]),
...props.style,
}}
onMouseEnter={(e) => {
if (isDisabled) return;
const el = e.currentTarget;
if (variant === 'primary') el.style.backgroundColor = 'var(--primary-action-hover)';
if (variant === 'brand') el.style.backgroundColor = 'var(--cta80)';
if (variant === 'secondary') el.style.backgroundColor = 'var(--button-background-secondary-hover)';
props.onMouseEnter?.(e);
}}
onMouseLeave={(e) => {
if (isDisabled) return;
const el = e.currentTarget;
const bg = variantStyles[variant].backgroundColor as string;
el.style.backgroundColor = bg;
props.onMouseLeave?.(e);
}}
onMouseDown={(e) => {
if (isDisabled) return;
e.currentTarget.style.transform = 'scale(0.95)';
props.onMouseDown?.(e);
}}
onMouseUp={(e) => {
e.currentTarget.style.transform = 'scale(1)';
props.onMouseUp?.(e);
}}
>
{isLoading ? (
<span aria-label="Loading" style={{ opacity: 0.6 }}>···</span>
) : children}
</button>
);
}
```
---
### 6.2 Card
**Anatomy:** `[image/media] [content: heading + body + optional CTA]`
| State | Background | Border/Shadow | Transition |
|-------|-----------|---------------|-----------|
| Default | `--colors-klarna-off-white` (#F9F8F5) | none | — |
| Hover | `--colors-klarna-off-white` | `inset 0 0 0 1px var(--border100)` | `0.6s ease-out` |
| Focus-visible | — | `box-shadow: 0 0 0 3px var(--focus)` | — |
```tsx
// Card.tsx
export function Card({ heading, body, children }: {
heading: string;
body: string;
children?: React.ReactNode;
}) {
const [isHovered, setIsHovered] = React.useState(false);
return (
<div
style={{
display: 'grid',
gap: 'var(--spaces-space-48)', /* confirmed: 48px from computed */
borderRadius: 'var(--radius-l)', /* 16px — confirmed computed */
backgroundColor: 'var(--colors-klarna-off-white)',
boxShadow: isHovered ? 'inset 0 0 0 1px var(--border100)' : 'none',
transition: '0.6s ease-out', /* confirmed: card computed transition */
overflow: 'hidden',
}}
onMouseEnter={() => setIsHovered(true)}
onMouseLeave={() => setIsHovered(false)}
>
{children}
<div style={{ padding: 'var(--spaces-space-32)' }}>
<h3 style={{
fontFamily: 'var(--fonts-font-brand-title)',
fontSize: '52px',
fontWeight: 'var(--weights-bold)',
lineHeight: '57.2px',
color: 'var(--colors-text-default)',
margin: '0 0 var(--spaces-space-16)',
}}>
{heading}
</h3>
<p style={{
fontFamily: 'var(--fonts-font-brand-text)',
fontSize: 'var(--text-size-m)',
fontWeight: 'var(--weights-normal)',
lineHeight: 'var(--text-lh-m)',
color: 'var(--colors-text-body)',
margin: 0,
}}>
{body}
</p>
</div>
</div>
);
}
```
---
### 6.3 Input
**Anatomy:** `[optional label] [input field] [optional helper/error text]`
| State | Background | Border | Shadow |
|-------|-----------|--------|--------|
| Default | `--inputBackground` (#FFF) | `1px solid var(--colors-border-neutral)` | none |
| Hover | `--inputBackground` | `1px solid var(--colors-border-active)` | none |
| Focus | `--inputBackground` | transparent | `box-shadow: 0 0 0 3px var(--focus)` |
| Disabled | `--inputBackgroundDisabled` (#E2E2E7) | `1px solid var(--colors-border-default)` | none |
| Error | `--inputBackground` | `1px solid var(--colors-border-negative)` | none |
**Border-radius:** `50px` — pill input (confirmed: computed input `border-radius: 50px`)
```tsx
// Input.tsx
interface InputProps extends React.InputHTMLAttributes<HTMLInputElement> {
label?: string;
error?: string;
helperText?: string;
}
export function Input({ label, error, helperText, disabled, id, ...props }: InputProps) {
return (
<div style={{ display: 'flex', flexDirection: 'column', gap: 'var(--spaces-space-8)' }}>
{label && (
<label
htmlFor={id}
style={{
fontFamily: 'var(--fonts-font-brand-text)',
fontSize: 'var(--text-size-m)',
fontWeight: 'var(--weights-medium)',
lineHeight: 'var(--text-lh-s)',
color: 'var(--colors-text-default)',
}}
>
{label}
</label>
)}
<input
{...props}
id={id}
disabled={disabled}
style={{
fontFamily: 'var(--fonts-font-brand-text)',
fontSize: 'var(--text-size-s)',
fontWeight: 'var(--weights-normal)',
color: disabled ? 'var(--colors-text-disabled)' : 'var(--colors-text-default)',
backgroundColor: disabled ? 'var(--inputBackgroundDisabled)' : 'var(--inputBackground)',
border: `1px solid ${error ? 'var(--colors-border-negative)' : 'var(--colors-border-neutral)'}`,
borderRadius: '50px', /* confirmed: input computed */
padding: '6px 35px 6px 15px', /* confirmed: input computed */
outline: 'none',
transition: `box-shadow var(--duration-fast) var(--ease-default),
border-color var(--duration-fast) var(--ease-default)`,
cursor: disabled ? 'not-allowed' : 'text',
width: '100%',
boxSizing: 'border-box',
}}
onFocus={(e) => {
e.currentTarget.style.boxShadow = '0 0 0 3px var(--focus)';
props.onFocus?.(e);
}}
onBlur={(e) => {
e.currentTarget.style.boxShadow = 'none';
props.onBlur?.(e);
}}
/>
{(error || helperText) && (
<span style={{
fontFamily: 'var(--fonts-font-brand-text)',
fontSize: 'var(--text-size-xs)',
color: error ? 'var(--colors-text-negative)' : 'var(--colors-text-subtle)',
}}>
{error ?? helperText}
</span>
)}
</div>
);
}
```
---
### 6.4 Badge
**Anatomy:** `[optional icon] [label text]`
| Variant | Background | Text |
|---------|-----------|------|
| Strong | `--colors-badge-strong` (#000) | `--colors-text-inverse` |
| Pop | `--colors-badge-pop` (#CFF066) | `--colors-text-default` |
| Brand | `--colors-badge-brand` (#FFA8CD) | `--colors-text-default` |
| Accent | `--colors-badge-accent` (#E4E0F7) | `--colors-text-accent` (#582FB4) |
| Positive | `--colors-badge-positive` (#C1F4D1) | `--colors-text-positive` (#046234) |
| Negative | `--colors-badge-negative` (#FFB8B8) | `--colors-text-negative` (#931414) |
| Warning | `--colors-badge-warning` (#FFE8B7) | `--colors-text-warning` (#664600) |
```tsx
// Badge.tsx
type BadgeVariant = 'strong' | 'pop' | 'brand' | 'accent' | 'positive' | 'negative' | 'warning';
const badgeTokens: Record<BadgeVariant, { bg: string; text: string }> = {
strong: { bg: 'var(--colors-badge-strong)', text: 'var(--colors-text-inverse)' },
pop: { bg: 'var(--colors-badge-pop)', text: 'var(--colors-text-default)' },
brand: { bg: 'var(--colors-badge-brand)', text: 'var(--colors-text-default)' },
accent: { bg: 'var(--colors-badge-accent)', text: 'var(--colors-text-accent)' },
positive: { bg: 'var(--colors-badge-positive)', text: 'var(--colors-text-positive)' },
negative: { bg: 'var(--colors-badge-negative)', text: 'var(--colors-text-negative)' },
warning: { bg: 'var(--colors-badge-warning)', text: 'var(--colors-text-warning)' },
};
export function Badge({ variant = 'accent', children }: {
variant?: BadgeVariant;
children: React.ReactNode;
}) {
const { bg, text } = badgeTokens[variant];
return (
<span style={{
display: 'inline-flex',
alignItems: 'center',
gap: 'var(--spaces-space-4)',
padding: '2px var(--spaces-space-8)',
borderRadius: 'var(--radiuses-radius-round)', /* pill badge */
backgroundColor: bg,
color: text,
fontFamily: 'var(--fonts-font-brand-text)',
fontSize: 'var(--text-size-xs)',
fontWeight: 'var(--weights-medium)',
lineHeight: 'var(--text-lh-xs)',
whiteSpace: 'nowrap',
}}>
{children}
</span>
);
}
```
---
### 6.5 Nav Item
**Anatomy:** `[label]` (optional icon suffix)
| State | Color | Decoration | Shadow |
|-------|-------|-----------|--------|
| Default | `--colors-text-default` (#0B051D) | none | none |
| Hover | `--colors-text-default` | underline | none |
| Focus-visible | `--colors-text-default` | none | `box-shadow: 0 0 0 3px var(--focus)` |
| Active | `--colors-text-default` | none | none |
**Layout:** Nav container `display: flex; flex-direction: row; gap: 48px; align-items: center` — confirmed from computed `role_navigation`.
```tsx
// NavItem.tsx
export function NavItem({ href, children }: { href: string; children: React.ReactNode }) {
return (
<a
href={href}
style={{
fontFamily: 'var(--fonts-font-brand-text)',
fontSize: 'var(--text-size-m)',
fontWeight: 'var(--weights-normal)',
lineHeight: 'var(--text-lh-m)',
color: 'var(--colors-text-default)',
textDecoration: 'none',
outline: 'none',
borderRadius: 'var(--radius-s)',
padding: '2px var(--spaces-space-4)',
transition: `color var(--duration-fast) var(--ease-default)`,
}}
onMouseEnter={(e) => { e.currentTarget.style.textDecoration = 'underline'; }}
onMouseLeave={(e) => { e.currentTarget.style.textDecoration = 'none'; }}
onFocus={(e) => { e.currentTarget.style.boxShadow = '0 0 0 3px var(--focus)'; }}
onBlur={(e) => { e.currentTarget.style.boxShadow = 'none'; }}
>
{children}
</a>
);
}
```
---
## 7. Elevation & Depth
```css
/* ── Shadow Tokens ── */
--shadows-shadow-s: 0px 2px 4px 0px rgba(0, 0, 0, 0.1); /* Small: input, chip */
--shadows-shadow-m: 0px 6px 12px 0px rgba(0, 0, 0, 0.1); /* Medium: dropdown, tooltip */
--shadows-shadow-l: 0px 12px 24px 0px rgba(0, 0, 0, 0.1); /* Large: modal, dialog */
/* ── Inset Shadow Tokens (from extracted vars) ── */
--shadow-sm: rgb(228, 227, 223) 0px 0px 0px 1px inset; /* Subtle inset border */
--shadow-md: rgba(0, 0, 0, 0) 0px 0px 0px 1px inset; /* Transparent inset (reset) */
--shadow-lg: rgb(226, 226, 231) 0px 2px 6px 0px; /* Light outer glow */
/* ── Card Hover State ── */
/* Cards use inset border on hover — NOT floating shadow */
/* hover: box-shadow: inset 0 0 0 1px var(--border100); */
/* ── Dialog Overlay ── */
--colors-overlay-dialog: rgba(0, 0, 0, 0.16);
/* ── Z-Index Scale (inferred — not extracted from CSS vars) ── */
/* Base content: z-index: 0 */
/* Sticky header: z-index: 100 */
/* Dropdown/menu: z-index: 200 */
/* Modal overlay: z-index: 300 */
/* Modal dialog: z-index: 400 */
/* Toast/alert: z-index: 500 */
```
**Layering principles:**
- Cards NEVER use `box-shadow` at rest — only on hover as an inset border.
- Modal dialogs use `--shadows-shadow-l` + `--colors-overlay-dialog` backdrop.
- The header uses `border-bottom: 1px solid var(--headerBorder)` for elevation separation, not a shadow.
---
## 8. Motion
```css
/* ── Duration Tokens ── */
--duration-fast: 0.2s; /* Micro-interactions: hover color, focus ring */
--duration-base: 0.3s; /* Standard transitions: button bg, nav items */
/* 0.6s ease-out: Card expand transitions — hardcoded in card component */
/* ── Easing Tokens ── */
--ease-default: ease; /* Used on 130+ elements — universal default */
/* ── Button Transition (extracted from computed) ── */
/* transition: box-shadow 0.3s, background 0.3s, color 0.3s, transform 0.3s; */
/* ── Button Active Press (extracted from interactive states) ── */
/* :active → transform: scale(0.95); transition-duration: 0s (immediate snap), 300ms (release) */
/* ── Card Transition (extracted from computed) ── */
/* transition: 0.6s ease-out; */
/* ── Focus Ring Animation ── */
/* focus-visible → box-shadow: 0 0 0 3px var(--focus) */
/* Transition: box-shadow var(--duration-fast) var(--ease-default) */
```
**When to animate:**
- Hover state color/background changes: always, `var(--duration-fast)`.
- Button active press: `scale(0.95)` snap (0s in), release 300ms.
- Card hover border: `0.6s ease-out` — intentionally slow for premium feel.
- Focus rings: `var(--duration-fast)` snap in, no transition out needed.
**When NOT to animate:**
- Disabled state changes (no transition on disabled — state is instant).
- Page-level background color changes.
- Text content changes.
- Decorative data-viz elements (use `prefers-reduced-motion` media query to disable).
```css
@media (prefers-reduced-motion: reduce) {
*, *::before, *::after {
transition-duration: 0.01ms !important;
animation-duration: 0.01ms !important;
}
}
```
---
## 9. Anti-Patterns & Constraints
1. **Hardcoded hex colours → AI confabulates off-brand values → use CSS var tokens.**
AI agents default to hardcoding `#FF69B4` or `#1A1A2E` when told "use Klarna pink" or "near-black". These hex values have no semantic meaning and bypass the token system. This causes inconsistency when the design updates. **Fix:** Always write `var(--colors-btn-brand)` for the Klarna pink and `var(--colors-btn-primary)` for the dark action button. Never write raw hex in component code.
2. **Rectangular buttons → AI uses 8px border-radius by default → Klarna requires pill-shaped buttons.**
When AI agents generate button components without explicit radius guidance, they default to `border-radius: 4px` or `8px` — which is completely wrong for Klarna's pill-shaped CTA system. This is the most common failure mode. **Fix:** ALWAYS specify `border-radius: 100px` (or `var(--radius-lg)`) for primary and brand CTAs. Only use `20px` for compact/chip-style buttons.
3. **Wrong font-family → AI defaults to Inter, Roboto, or system-ui → Klarna uses custom fonts.**
AI coding agents frequently output `font-family: 'Inter', sans-serif` or `font-family: system-ui` because these are the most common fonts in their training data. This completely loses the Klarna brand character. **Fix:** Always set `font-family: var(--fonts-font-brand-title)` for headings and `var(--fonts-font-brand-text)` for body copy. Both include system fallbacks automatically.
4. **Arbitrary spacing → AI generates `margin: 15px` or `padding: 18px` → breaks 4px grid.**
AI agents generate psychologically "reasonable" spacing values like 15px, 18px, 22px that feel visually close but are off-grid. The extraction found off-grid values (18px, 22px, 26px, 42px) in the source — do not replicate these. **Fix:** Use only `--spaces-space-*` tokens (4, 8, 12, 16, 20, 24, 32, 40, 48, 64, 80). If the closest value is `--spaces-space-16`, use it even if your instinct says 15px.
5. **Missing focus states → AI omits `:focus-visible` → WCAG 2.1 AA failure.**
AI agents generate the default, hover, and active states but routinely omit `:focus-visible`. On Klarna, focus is always `box-shadow: 0 0 0 3px var(--focus)` — the purple ring (`#7B57D8`) — never `outline: none` alone. **Fix:** Every interactive element MUST include a `focus-visible` handler that applies `box-shadow: 0 0 0 3px var(--focus)`. Outline is set to `none` only when the box-shadow focus ring is present.
6. **Floating card shadows → AI adds `box-shadow: 0 4px 12px rgba(0,0,0,0.1)` to cards → wrong brand pattern.**
Klarna cards do NOT float. At rest they have no shadow. On hover they use an inset border (`inset 0 0 0 1px var(--border100)`) not an outer shadow. AI agents trained on generic design patterns add drop shadows by default because most design systems do. **Fix:** Cards: `box-shadow: none` at rest. On hover: `box-shadow: inset 0 0 0 1px var(--border100)`. Use `--shadows-shadow-*` tokens only for modals and dropdowns.
7. **Purple as the primary brand color → AI assigns purple as the primary action → incorrect.**
The purple brand scale (`--brand60: #7039E2`, `--colors-text-accent-heading: #7039E2`) is highly saturated and visible. AI agents confuse "prominent brand color" with "primary action color." Purple is ONLY for: accent text, badge-accent, focus rings, and decorative illustration. **Fix:** Primary action buttons are `--colors-btn-primary: #0B051D` (near-black). Brand CTAs are `--colors-btn-brand: #FFA8CD` (pink). Purple is NEVER a button background color.
8. **Dynamic Tailwind class construction → AI writes `bg-[${variant}]` → PurgeCSS removes it.**
If using Tailwind alongside these tokens, AI agents frequently construct class names dynamically: `className={`bg-[var(--${variant})]`}`. PurgeCSS / Tailwind's content scanner cannot detect these and strips them in production builds. **Fix:** Use inline `style={{ backgroundColor: 'var(--colors-btn-primary)' }}` for dynamic token application, or map variants to complete pre-declared class names in a lookup object.
9. **`!important` to override states → AI uses !important for disabled/error states → breaks cascade.**
Disabled and error state overrides applied with `!important` prevent later valid state transitions (e.g. re-enabling a button). AI agents add `!important` when specificity conflicts arise during state handling. **Fix:** Use a single style object computed from props (as shown in the Button component example) that resolves state priority explicitly — no `!important` needed.
10. **Mixing inline styles and Tailwind arbitrarily → AI combines both without a consistent strategy → unmaintainable.**
AI agents will mix `style={{ color: '#0B051D' }}` with `className="text-[#0B051D]"` and `className="text-gray-900"` in the same component. This makes token updates require changes in multiple syntax systems. **Fix:** Pick ONE styling approach per project. For token fidelity, prefer CSS custom properties via `style={{ prop: 'var(--token)' }}` in JSX or CSS Modules with `var(--token)` values.
11. **Using generic carousel/modal component border-radius values as brand tokens → AI extracts wrong radius.**
Third-party plugin components (Bootstrap, cookie banners) may have large or unusual border-radius values that do not represent the Klarna design system. AI agents may see `border-radius: 8px` from an unrelated component and use it on primary buttons. **Fix:** Use only the four canonical radius values: `8px` (cards/panels), `100px` (pill CTAs), `99999px` (circular icons), `16px` (large card surfaces).
---
## Appendix A: Complete Token Reference
Every token extracted from the source. §0 CORE TOKENS is the primary AI signal; this appendix is reference material an AI can cross-check against when a curated role is missing.
```css
/* Colours (198) */
--text-on-background: #FFFFFF;
--colors-bg-container: #F8F7FA;
--button-background-secondary: #F3F3F5;
--button-background-secondary-hover: #E2E2E7;
--primary-action-active: #0B051D;
--colors-text-accent-heading: #7039E2;
--colors-border-negative: #AE1D1D;
--colors-bg-negative-subtle: #FFE6E6;
--colors-bg-warning: #FBC64D;
--colors-bg-warning-subtle: #FFF5E4;
--colors-text-positive: #046234;
--colors-bg-positive-subtle: #E6FCEB;
--colors-bg-accent-subtle: #EFECFF;
--colors-bg-brand: #FFA8CD;
--colors-text-body: #282636;
--colors-text-subtle: #504F5F;
--textDisabled: #96959F;
--colors-text-inverse: #F9F8F5;
--colors-text-accent: #582FB4;
--colors-text-negative: #931414;
--colors-text-negative-heading: #DC2B2B;
--colors-text-warning: #664600;
--colors-border-warning: #885F00;
--colors-text-positive-heading: #06884A;
--input-decoration-secondary-active: #C4C3CA;
--colors-btn-ghost: rgba(255,255,255,0);
--colors-badge-strong: #000000;
--stickynote20: #CFF066;
--ribbon-rank-background: #E4E0F7;
--focus: #7B57D8;
--colors-badge-positive: #C1F4D1;
--colors-badge-negative: #FFB8B8;
--colors-badge-warning: #FFE8B7;
--colors-badge-warning-inverse: #AD7C00;
--colors-overlay-hover-default: rgba(0,0,0,0.04);
--colors-overlay-hover-inverse: rgba(255, 255, 255, 0.12);
--colors-overlay-press-default: rgba(0,0,0,0.08);
--colors-overlay-press-inverse: rgba(255, 255, 255, 0.16);
--colors-overlay-fadeout: rgba(255,255,255,0.56);
--colors-overlay-dialog: rgba(0,0,0,0.16);
--colors-overlay-image-subtle: rgba(102, 102, 153, 0.05);
--colors-overlay-image-darken: rgba(0, 0, 0, 0.24);
--colors-overlay-border-subtle: rgba(11,5,29,0.12);
--stickynote30: #AAD336;
--colors-data-positive: #0EAA5D;
--colors-data-warning: #DFA200;
--colors-data-1: #E57DAF;
--colors-data-3: #379FAA;
--colors-data-4: #CF7F3E;
--colors-data-5: #A03DB3;
--colors-data-6: #3F7FDC;
--colors-data-7: #1A6773;
--colors-data-8: #AC4A85;
--brand80: #3D2A70;
--colors-data-10: #1F4DA3;
--colors-data-11: #984E22;
--colors-data-12: #65117D;
--colors-klarna-eggplant: #2F1F5A;
--balloon35: #B798BE;
--ribbon-default-background: #E4E3DF;
--ribbon-watched-background: #E6FFA9;
--brand30: #D9C2FB;
--brand40: #AA89F2;
--brand70: #5C32B8;
--brand90: #2C2242;
--primary-action-hover: #28272E;
--cta10: #FFD0E2;
--cta80: #E27EAC;
--content10: #feede2;
--content20: #f3d5d0;
--content40: #e2beb7;
--content60: #bc627b;
--content80: #910737;
--content90: #3d0f1f;
--textContentPrimary: #282b30;
--supportSecondary10: #CCF9D4;
--ribbon-in-stock-background: #A8F3B7;
--supportSecondary30: #88DBA5;
--supportSecondary40: #48A77B;
--positive50: #287E59;
--supportSecondary60: #136E43;
--positive70: #1A5B33;
--supportSecondary80: #014822;
--ribbon-in-stock-text: #00331D;
--warning10: #F9F0AA;
--warning20: #F0E788;
--warning30: #DBCA6E;
--warning40: #A79542;
--warning50: #7C7027;
--warning60: #6D621D;
--warning70: #554C14;
--warning80: #423900;
--negative10: #FFE9E9;
--ribbon-out-of-stock-background: #FDE2E2;
--negative30: #F5BECA;
--negative40: #E47B93;
--negative50: #B94966;
--ribbon-sale-text: #B62454;
--negative70: #942546;
--negative80: #6A152F;
--ribbon-out-of-stock-text: #500D22;
--grayscale50: #706E7B;
--border60: #615F6D;
--textSecondary: #37363F;
--saleText: #e61919;
--saleBackground: #ffcfcf;
--sponsored10: #f5f6f5;
--sponsored20: #d0dad4;
--sponsored60: #2e5e40;
--sponsored80: #2e5d40;
--border95: #1D192A;
--ribbon-sale-background: #FCD3D3;
--linkPrimaryHover: inherit;
--textTertiary: #a1a8b3;
--textContentSecondary: #5b6370;
--overlayPrimary: rgba(52, 52, 52, 0.7);
--overlaySecondary: rgba(255, 255, 255, 0.5);
--overlayContent: rgba(51, 53, 54, 0.04);
--overlayWatched: rgba(77, 150, 105, 0.05);
--overlaySale: rgba(215, 24, 24, 0.05);
--overlayTrending: rgba(19, 121, 212, 0.05);
--overlayContentImage: #52031e;
--ratingText: #fefefe;
--headerBorder: #ebeff5;
--header-background: var(--grayscale0);
--frameBackgroundHover: #f1f1f1;
--frameBackgroundPressed: #e2e2e2;
--brand-primary-cta: rgb(11, 5, 29); /* Primary CTA background, dominant on 1 button — e.g. "Login" /* mined from computed styles */ */
--brand-secondary-cta: rgb(255, 168, 205); /* Secondary CTA background, dominant on 2 buttons — e.g. "button" /* mined from computed styles */ */
--brand-surface-2: rgb(255, 208, 226); /* Brand surface, dominant on 1 element — e.g. "div" /* mined from computed styles */ */
--brand-surface-3: rgb(230, 255, 169); /* Brand surface, dominant on 1 element — e.g. ""Sehr schnelles und einfaches " /* mined from computed styles */ */
--colors-bg-page: #FFFFFF;
--colors-bg-subtle: #F3F3F5;
--colors-bg-inverse: #0B051D;
--colors-text-default: #0B051D;
--colors-text-link: #582FB4;
--colors-btn-primary: #0B051D;
--colors-btn-brand: #FFA8CD;
--colors-btn-secondary: #F3F3F5;
--colors-border-default: #E2E2E7;
--colors-bg-positive: #046234;
--colors-bg-negative: #AE1D1D;
--brand10: #EFECFF;
--brand20: #E4E0F7;
--brand50: #7B57D8;
--brand60: #7039E2;
--brand100: #0B051D;
--colors-klarna-pink: #FFA8CD;
--colors-klarna-black: #0B051D;
--colors-klarna-balloon: #B798BE;
--colors-klarna-off-white: #F9F8F5;
--colors-klarna-herring: #E4E3DF;
--colors-klarna-sticky-note: #E6FFA9;
--cta20: #FFD0E2;
--cta30: #FFA8CD;
--cta60: #FFA8CD;
--cta100: #E27EAC;
--border10: #F3F3F5;
--border20: #E2E2E7;
--border40: #C4C3CA;
--border100: #0B051D;
--positive10: #CCF9D4;
--positive20: #A8F3B7;
--colors-bg-plain: #FFFFFF;
--colors-bg-neutral: #E2E2E7;
--colors-bg-accent: #7039E2;
--headerBackground: #fefefe;
--footerBackground: #0B051D;
--colors-text-disabled: #96959F;
--colors-text-placeholder: #96959F;
--colors-border-neutral: #C4C3CA;
--colors-border-active: #0B051D;
--colors-btn-tertiary: #FFFFFF;
--colors-btn-danger: #AE1D1D;
--colors-btn-disabled: #F3F3F5;
--colors-btn-idle: #C4C3CA;
--primary-action-base: #0B051D;
--primary-action-disabled: #E2E2E7;
--colors-badge-pop: #CFF066;
--colors-badge-brand: #FFA8CD;
--colors-badge-accent: #E4E0F7;
--colors-badge-accent-inverse: #7B57D8;
--colors-badge-positive-inverse: #06884A;
--colors-badge-negative-inverse: #AE1D1D;
--inputBackground: #FFFFFF;
--input-background: #FFFFFF;
--inputBackgroundDisabled: #E2E2E7;
--input-background-disabled: #E2E2E7;
--ribbon-default-text: #0B051D;
--ribbon-watched-text: #0B051D;
--ribbon-rank-text: #0B051D;
--ribbon-popular-background: #E4E0F7;
--ribbon-popular-text: #0B051D;
--ribbon-unknown-stock-background: #F3F3F5;
--ribbon-unknown-stock-text: #37363F;
--colors-data-2: #7039E2;
--colors-text-warning-heading: #885F00;
--colors-border-positive: #06884A;
/* Typography (52) */
--fonts-font-system: -apple-system, ...;
--fonts-font-monospace: monospace, -apple-system, ...;
--fonts-font-brand-title: "Klarna Title", -apple-system, ...;
--fonts-font-brand-text: "Klarna Text", -apple-system, ...;
--textSizes-display-mobile-s: calc(32px + (1rem - 16px) * 0.4472);
--textSizes-display-desktop-s: calc(40px + (1rem - 16px) * 0.2709);
--textSizes-display-desktop-m: calc(52px + (1rem - 16px) * 0.1042);
--textSizes-display-desktop-l: calc(64px + (1rem - 16px) * 0.0254);
--textSizes-display-mobile-xl: calc(68px + (1rem - 16px) * 0.013);
--textSizes-display-desktop-xl: 84px;
--textSizes-heading-mobile-s: calc(20px + (1rem - 16px) * 0.8337);
--textSizes-heading-desktop-s: calc(24px + (1rem - 16px) * 0.687);
--textSizes-heading-mobile-m: calc(28px + (1rem - 16px) * 0.5585);
--textSizes-heading-desktop-l: calc(44px + (1rem - 16px) * 0.2035);
--textSizes-text-mobile-xs: min(0.75rem, calc(24px + (1rem - 32px) * 0.3435));
--textSizes-text-mobile-s: min(0.875rem, calc(28px + (1rem - 32px) * 0.2793));
--textSizes-text-mobile-m: min(1rem, calc(32px + (1rem - 32px) * 0.2236));
--textSizes-text-mobile-l: calc(18px + (1rem - 16px) * 0.9143);
--lineHeights-body-mobile-xs: min(1rem, calc(32px + (1rem - 32px) * 0.3824));
--lineHeights-label-mobile-xs: min(0.75rem, calc(24px + (1rem - 32px) * 0.4412));
--shadows-shadow-s: 0px 2px 4px 0px rgba(0, 0, 0, 0.1);
--shadows-shadow-m: 0px 6px 12px 0px rgba(0, 0, 0, 0.1);
--shadows-shadow-l: 0px 12px 24px 0px rgba(0, 0, 0, 0.1);
--text-tertiary: var(--grayscale60);
--text-content-primary: var(--text-primary);
--text-content-secondary: var(--text-secondary);
--rating-text: var(--text-on-background);
--text-size-xs: 0.75rem;
--text-size-s: 0.875rem;
--text-size-m: 1rem;
--text-size-l: 1.25rem;
--text-size-xl: 1.625rem;
--text-lh-xxs: 14px;
--text-lh-xs: 18px;
--text-lh-s: 20px;
--text-lh-m: 24px;
--text-lh-l: 32px;
--text-lh-xl: 36px;
--heading-size-l: 2rem;
--heading-size-xl: 2.5625rem;
--heading-size-xxl: 3.25rem;
--font-normal: Klarna Text;
--heading-font-normal: Klarna Title;
--font-size-xs: 12px; /* 14 elements — e.g. p "Kundenbewertungen sp", p "Sieh dir unsere 5-St", p "¹ Verdiene Cashback " /* mined from computed styles */ */
--font-size-md: 16px; /* 38 elements — e.g. p "4.8/5 im App Store", p "Bleib mit Klarnas Za", p "Shoppe mit Vertrauen" /* mined from computed styles */ */
--font-size-xl: 41px; /* 6 elements — e.g. h2 "Flexible Zahlungsmet", h2 "Keine Gebühren bei p", h2 "Reibungsloser Checko" /* mined from computed styles */ */
--font-size-2xl: 52px; /* 4 elements — e.g. h2 "Nutze Klarna überall", h2 "6 smarte Gründe für ", h2 "Finde großartige Dea" /* mined from computed styles */ */
--font-size-3xl: 90px; /* 4 elements — e.g. h1 "Bezahlesicher mitKla", span "Bezahle", span "sicher mit" /* mined from computed styles */ */
--font-weight-regular: 400; /* 38 elements — e.g. p "Vorsicht! Du könntes", p "Shoppe sicher und en", p "Erlebe sicheres Shop" /* mined from computed styles */ */
--font-weight-medium: 500; /* 43 elements — e.g. h2 "Nutze Klarna überall", h2 "6 smarte Gründe für ", h2 "Flexible Zahlungsmet" /* mined from computed styles */ */
--font-weight-semibold: 700; /* 9 elements — e.g. h1 "Bezahlesicher mitKla", h2 "Finde großartige Dea", h3 "Alle lieben Klarna" /* mined from computed styles */ */
--line-height-tight: 12.6px; /* 14 elements — e.g. p "Kundenbewertungen sp", p "Sieh dir unsere 5-St", p "¹ Verdiene Cashback " /* mined from computed styles */ */
/* Spacing (26) */
--spaces-space-4: 4px;
--spaces-space-8: 8px;
--spaces-space-12: 12px;
--spaces-space-16: 16px;
--spaces-space-20: 20px;
--spaces-space-24: 24px;
--heading-lh-m: 32px;
--spaces-space-40: 40px;
--spaces-space-48: 48px;
--spaces-space-64: 64px;
--spaces-space-80: 80px;
--header-border: var(--border20);
--heading-lh-xxs: 18px;
--heading-lh-xs: 22px;
--heading-lh-s: 26px;
--heading-lh-l: 36px;
--heading-lh-xl: 42px;
--heading-lh-xxl: 52px;
--spaces-space-32: 32px;
--heading-size-xxs: 0.875rem;
--heading-size-xs: 1rem;
--heading-size-s: 1.25rem;
--heading-size-m: 1.625rem;
--heading-size-l: 2rem;
--heading-size-xl: 2.5625rem;
--heading-size-xxl: 3.25rem;
/* Radius (13) */
--radius-s: 4px;
--radius-sm: 8px;
--radius-m: 12px;
--radius-l: 16px;
--radius-xl: 24px;
--radius-xxl: 32px;
--radiuses-radius-round: 99999px;
--radius-xs: 2px;
--radius-sm: 20px; /* 9 elements — e.g. button .sc-bb78919f-7, button .sc-221f0a72-0 "Entdecke Klarna", button .sc-221f0a72-0 "Shopping" /* mined from computed styles */ */
--radius-md: 50px; /* 1 element — e.g. input /* mined from computed styles */ */
--radius-lg: 100px; /* 7 elements — e.g. button .bOVWr0jn4Q, button .sc-221f0a72-0, button .sc-221f0a72-0 /* mined from computed styles */ */
--radius-full: 100%; /* 2 elements — e.g. button .pr-1a81ze9-Carousel-arrowButton-Carousel-arrowLeft, button .pr-1tgi3pt-Carousel-arrowButton-Carousel-arrowRight /* mined from computed styles */ */
--radius-lg: 100px;
/* Effects (26) */
--lineHeights-display-mobile-s: calc(32px + (1rem - 16px) * 0.7647);
--lineHeights-display-desktop-s: calc(40px + (1rem - 16px) * 0.6471);
--lineHeights-display-desktop-m: calc(52px + (1rem - 16px) * 0.4706);
--lineHeights-display-mobile-l: calc(50px + (1rem - 16px) * 0.5);
--lineHeights-display-desktop-l: calc(62px + (1rem - 16px) * 0.3235);
--lineHeights-display-mobile-xl: calc(66px + (1rem - 16px) * 0.2647);
--lineHeights-display-desktop-xl: calc(80px + (1rem - 16px) * 0.0588);
--lineHeights-heading-mobile-s: calc(24px + (1rem - 16px) * 0.8824);
--lineHeights-heading-desktop-l: calc(48px + (1rem - 16px) * 0.5294);
--lineHeights-heading-desktop-xl: calc(56px + (1rem - 16px) * 0.4118);
--lineHeights-body-mobile-s: calc(20px + (1rem - 16px) * 0.9412);
--lineHeights-body-desktop-l: calc(28px + (1rem - 16px) * 0.8235);
--weight-normal: 400;
--weight-medium: 500;
--weights-bold: 700;
--heading-content: var(--grayscale100);
--shadowPrimary: none;
--shadow-sm: rgb(228, 227, 223) 0px 0px 0px 1px inset; /* 2 elements — e.g. button .gY_w21Xq3A, button .OUxE8BVE5e /* mined from computed styles */ */
--shadow-md: rgba(0, 0, 0, 0) 0px 0px 0px 1px inset; /* 1 element — e.g. button .bOVWr0jn4Q /* mined from computed styles */ */
--shadow-lg: rgb(226, 226, 231) 0px 2px 6px 0px; /* 2 elements — e.g. button .pr-1a81ze9-Carousel-arrowButton-Carousel, button .pr-1tgi3pt-Carousel-arrowButton-Carousel /* mined from computed styles */ */
--shadows-shadow-s: 0px 2px 4px 0px rgba(0,0,0,0.1);
--shadows-shadow-m: 0px 6px 12px 0px rgba(0,0,0,0.1);
--shadows-shadow-l: 0px 12px 24px 0px rgba(0,0,0,0.1);
--shadow-sm: rgb(228,227,223) 0px 0px 0px 1px inset;
--shadow-md: rgba(0, 0, 0, 0) 0px 0px 0px 1px inset;
--shadow-lg: rgb(226,226,231) 0px 2px 6px 0px;
/* Motion (3) */
--duration-fast: 0.2s; /* 24 elements — e.g. button, button, button /* mined from computed styles */ */
--duration-base: 0.3s; /* 16 elements — e.g. button, button, button /* mined from computed styles */ */
--ease-default: ease; /* 130 elements — e.g. button, button, button /* mined from computed styles */ */
```
## Appendix B: Token Source Metadata
```
tokenSource: extracted-css-vars
site: klarna.com
confidence: high
totalVarsFound: 538
curatedTokens: 45 (mapped to standard roles with --klarna-* aliases)
preservedNames: yes — all original CSS variable names preserved 1:1
(e.g. --colors-bg-brand, --fonts-font-brand-title, --focus, --headerBorder)
Curated --klarna-* aliases are SUPPLEMENTARY identifiers only;
original names are the canonical references throughout this document.
clusteringMethod:
- Colour grouping: clustered by semantic role (surface, text, border, button, badge, ribbon,
status, data-viz) from extracted var name prefixes
- Radius: mined from 22 page elements; identified pill pattern (100px on 7 CTAs, 50px on input)
- Spacing: confirmed 4px grid from --spaces-space-* token set (11 steps: 4–80px)
- Typography: composite groups assembled from textSizes-*, lineHeights-*, fonts-*, weights-* vars
fontDeclarations:
- "Klarna Title" (weight: 400 declared; 700 computed on h1/h3 — weight applied via font-weight)
- "Klarna Text" (custom brand text face — referenced in CSS vars, not in @font-face extraction)
- System font stack as fallback throughout
bootstrapDetected: true (may introduce conflicting radius/spacing overrides — use CSS var tokens
to override Bootstrap defaults explicitly)
reconstructedTokens: none — all tokens derived from extracted CSS custom properties
(not from computed style clustering)
authorityNote:
This file documents klarna.com's live production CSS as of extraction date.
Tokens are implementation-accurate, not Figma design intent.
For authoritative design intent, cross-reference with the Klarna design system (Brix).
```More from the gallery
Browse all kits →You may also like

Xero
MITClean, modern SaaS design system built on navy and mint green with sharp corners and purposeful typography for accounting and business software
00
saasfintechlightminimal

Netflix
MITDark, bold streaming platform design system with signature red accent and cinematic motion, built for large-scale video content discovery and subscription flows
00
darkboldecommlanding-page

Cash App
MITBold, high-contrast fintech design system built on Cash App's signature neon green and black palette, optimised for mobile payment interfaces and developer implementation
00
fintechmobilebolddark