@deriv-ds/design-intelligence-layer 0.6.0 → 0.6.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -26,23 +26,29 @@ BEFORE using any component:
26
26
 
27
27
  ```
28
28
  NEVER use:
29
- ❌ Hardcoded hex: #2323FF, #FFFFFF, etc.
29
+ ❌ Hardcoded hex: #FF444F, #FFFFFF, etc.
30
30
  ❌ Raw Tailwind palette: bg-gray-100, text-zinc-500, text-slate-400, bg-black, bg-white
31
31
  ❌ Raw opacity on non-tokens: bg-black/50 (use bg-overlay instead)
32
32
  ❌ Arbitrary color values: bg-[#FF6600], text-[rgba(0,0,0,0.5)]
33
33
  ❌ hsl(var(--token)) syntax — this is Tailwind v3. This project uses Tailwind v4.
34
34
  ❌ Non-existent tokens: bg-hover, bg-badge-rank, text-primary-foreground, text-on-decorative
35
- ❌ border-border — deprecated alias; use border-border-subtle or border-border-prominent
35
+ ❌ border-border — deprecated alias; prefer border-default or border-selected
36
+ ❌ bg-prominent, bg-subtle — these map to TEXT foreground values, not surfaces
37
+ ❌ text-on-prominent for body/headings — this token is ALWAYS-WHITE; use text-prominent
38
+ ❌ text-semantic-win, text-semantic-loss — NOT utility classes (use text-success / text-error)
36
39
 
37
40
  ALWAYS use semantic tokens:
38
- ✅ bg-prominent, bg-card, bg-popover, bg-subtle, bg-overlay
39
- ✅ text-on-prominent, text-on-subtle
40
- ✅ border-border-subtle, border-border-prominent, ring-ring
41
+ ✅ bg-primary-canvas, bg-primary-surface, bg-secondary-surface, bg-secondary-canvas, bg-overlay
42
+ ✅ text-prominent, text-subtle, text-on-prominent-static-inverse
43
+ ✅ border-default, border-selected, ring-ring
41
44
  ✅ bg-primary, bg-primary-hover, bg-secondary-hover
42
- ✅ text-semantic-win, text-semantic-loss, text-semantic-warning
43
- Opacity on a token IS allowed: bg-primary/20, border-border-subtle/50, ring-primary/10
45
+ ✅ text-warning, text-info, text-success, text-error (the four status text utilities)
46
+ text-on-primary / text-on-success / text-on-error / text-on-warning / text-on-info (foreground on a solid coloured surface)
47
+ ✅ Opacity on a token IS allowed: bg-primary/20, border-default/50, ring-primary/10
44
48
  ```
45
49
 
50
+ > **Status colors:** All four status text utilities exist — `text-warning`, `text-info`, `text-success`, `text-error` (each mapped to its `--text-*-default` value, theme-aware). The older `text-[var(--text-success-default)]` / `text-[var(--text-error-default)]` form still resolves (the package's own blocks use it) but new code should prefer the bare utilities. Foundation background tints `--background-success-default` / `--background-error-default` remain available via `bg-[var(--background-success-default)]`, or use `bg-success/10` for a quick tint.
51
+
46
52
  ### Rule 3 — Layout utilities are exempt
47
53
 
48
54
  ```
@@ -59,7 +65,7 @@ Token rules apply ONLY to:
59
65
  ### Rule 4 — Do NOT install or import these separately
60
66
 
61
67
  ```
62
- ❌ lucide-react or any icon library — icons come from FontAwesome Pro via the package's <Icon /> component (see icon-reference.md in this folder)
68
+ ❌ lucide-react or any icon library — icons come from @deriv/quill-icons via the package's <Icon /> component (see icon-reference.md in this folder)
63
69
  ❌ tailwindcss — the package ships its own Tailwind v4 config
64
70
  ❌ @apply with hsl(var(--token)) — Tailwind v4 uses CSS variables directly
65
71
  ❌ tailwind.config.js — configuration is handled by the package via CSS
@@ -90,13 +96,13 @@ npm install @deriv-ds/design-intelligence-layer@latest --safe-chain-skip-minimum
90
96
  In your main CSS file (e.g. `globals.css` or `index.css`):
91
97
 
92
98
  ```css
93
- @import url("https://fonts.googleapis.com/css2?family=Plus+Jakarta+Sans:wght@300;400;500;600;700;800&display=swap");
99
+ @import url("https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700;800&display=swap");
94
100
  @import "tailwindcss";
95
101
  @import "@deriv-ds/design-intelligence-layer/styles";
96
102
  @source "../node_modules/@deriv-ds/design-intelligence-layer/dist";
97
103
  ```
98
104
 
99
- > **Note:** Fonts are loaded via a direct Google Fonts `@import` URL. Do NOT use `next/font`.
105
+ > **Note:** Fonts are loaded via a direct Google Fonts `@import` URL. Do NOT use `next/font`. The font is **Inter** — `--font-plus-jakarta-sans` is a deprecated alias and resolves to Inter.
100
106
 
101
107
  ### Step 3 — Set base HTML class
102
108
 
@@ -116,50 +122,60 @@ import { Button, Card, Badge } from "@deriv-ds/design-intelligence-layer"
116
122
 
117
123
  ### 2.1 — Backgrounds
118
124
 
119
- | CSS Variable | Tailwind Class | Usage |
120
- | ---------------- | ---------------- | ------------------------- |
121
- | `--prominent` | `bg-prominent` | Main page background |
122
- | `--card` | `bg-card` | Cards, panels, modals |
123
- | `--popover` | `bg-popover` | Popovers, elevated cards |
124
- | `--subtle` | `bg-subtle` | Muted / secondary surfaces|
125
- | `--overlay` | `bg-overlay` | Modal/dialog/drawer/sheet backdrop (semi-transparent) |
126
- | `--tabs` | `bg-tabs` | Tab container / tab bar background (`variant="default"`) — 4% black alpha, adapts to any surface |
127
- | `--tabs-active` | `bg-tabs-active` | Active / selected tab background — solid white |
125
+ | CSS Variable | Tailwind Class | Usage |
126
+ | ---------------------------------- | ----------------------- | ------------------------- |
127
+ | `--background-primary-surface` | `bg-primary-surface` | Cards, panels, modals |
128
+ | `--background-primary-canvas` | `bg-primary-canvas` | Main page / canvas background |
129
+ | `--background-secondary-surface` | `bg-secondary-surface` | Secondary / muted surfaces |
130
+ | `--background-secondary-canvas` | `bg-secondary-canvas` | Secondary canvas areas |
131
+ | `--overlay` | `bg-overlay` | Modal/dialog/drawer/sheet backdrop (semi-transparent) |
132
+ | `--tabs` | `bg-tabs` | Tab container / tab bar background — 4% alpha, adapts to any surface |
133
+ | `--tabs-active` | `bg-tabs-active` | Active / selected tab background |
134
+
135
+ > **Avoid as backgrounds:** `bg-prominent`, `bg-subtle` — these classes resolve, but they map to TEXT foreground values, so using them as surfaces is a bug. `bg-card` and `bg-popover` are fine — they alias `bg-primary-surface`.
128
136
 
129
- ### 2.2 — Primary (Brand Blue)
137
+ ### 2.2 — Primary (Brand Coral)
130
138
 
131
139
  | CSS Variable | Tailwind Class | Usage |
132
140
  | --------------------- | ------------------- | ------------------------- |
133
- | `--primary` | `bg-primary` / `text-primary` | Primary CTA, brand color, interactive elements |
134
- | `--primary-hover` | `bg-primary-hover` | Hover & pressed states on primary elements |
141
+ | `--primary` | `bg-primary` / `text-primary` | Primary CTA, brand coral (#FF444F), interactive elements |
142
+ | `--primary-hover` | `bg-primary-hover` | Hover & pressed states on primary elements (coral-800) |
135
143
 
136
- ### 2.3 — Semantic (Trading Status)
144
+ ### 2.3 — Semantic (Status Colors)
137
145
 
138
- | CSS Variable | Tailwind Class | Usage |
139
- | -------------------- | ----------------------- | ------------------------- |
140
- | `--semantic-win` | `text-semantic-win` / `bg-semantic-win` | Win / Profit / Positive outcomes |
141
- | `--semantic-loss` | `text-semantic-loss` / `bg-semantic-loss` | Loss / Negative outcomes |
142
- | `--semantic-warning` | `text-semantic-warning` / `bg-semantic-warning` | Warning / Caution / Non-destructive alerts |
143
- | `--semantic-info` | `text-semantic-info` / `bg-semantic-info` | Informational alerts |
146
+ | CSS Variable | Tailwind Class | Usage |
147
+ | ---------------------------- | ------------------------------------ | ------------------------- |
148
+ | `--text-warning-default` | `text-warning` | Warning / Caution / Non-destructive alerts (yellow-900 light, yellow-500 dark) |
149
+ | `--text-information-default` | `text-info` | Informational alerts (blue-900 light, blue-500 dark) |
150
+ | `--text-success-default` | `text-success` | Success / Profit / Positive outcomes (green-900 light, green-500 dark) |
151
+ | `--text-error-default` | `text-error` | Error / Loss / Negative outcomes (red-900 light, red-500 dark) |
144
152
 
145
- > All semantic tokens support opacity variants (e.g. `bg-semantic-warning/10` for tinted backgrounds). For structured alpha surfaces, use the primitive alpha scales see Section 2.10.
153
+ > **All four status colours are now bare utility classes:** `text-warning`, `text-info`, `text-success`, `text-error` (each mapped to its `--text-*-default` value — theme-aware, and opacity-friendly like `bg-success/10`, `bg-error/10`). The older `text-[var(--text-success-default)]` / `text-[var(--text-error-default)]` form still resolves and remains valid (the package's own blocks such as `hero-mobile-transaction.tsx` predate the utilities), but new code should prefer `text-success` / `text-error`. Foundation background tokens are also available: `--background-success-default`, `--background-error-default`, `--background-warning-default`, `--background-information-default`.
154
+ >
155
+ > **Foreground on a solid coloured surface:** use `text-on-primary` / `text-on-success` / `text-on-error` / `text-on-warning` / `text-on-info` for text and icons placed **on the solid brand/status colour** (`bg-primary`, `bg-success`, etc.). These resolve to the always-legible static-inverse foreground. On a status *tint* (`bg-success/10`) use `text-success` / `text-error` instead — not the `on-*` foreground.
156
+ >
157
+ > **Opaque status surfaces:** `bg-success-surface` / `bg-error-surface` / `bg-warning-surface` / `bg-info-surface` are **solid** (non-alpha) status tints built with `color-mix`. Unlike the alpha tints (`bg-success/10`, `bg-[var(--background-success-default)]`), they read identically on **any** background — use them for badges/chips that sit on a coloured card or hero where an alpha tint would bleed through. They are theme-aware (auto-adapt under `.dark`).
146
158
 
147
159
  ### 2.4 — Text & Icon Colors
148
160
 
149
161
  | CSS Variable | Tailwind Class | Usage |
150
162
  | ------------------------------- | --------------------------------------- | ------------------------- |
151
- | `--on-prominent` | `text-on-prominent` | Primary text (headings, body) |
152
- | `--on-prominent-static-inverse` | `text-on-prominent-static-inverse` | Always-white text (e.g. on primary blue buttons) |
153
- | `--on-subtle` | `text-on-subtle` | Secondary text (descriptions, labels) |
163
+ | `--text-prominent-default` | `text-prominent` | Primary text (headings, body) — slate-1200 light, slate-50 dark |
164
+ | `--on-prominent-static-inverse` | `text-on-prominent-static-inverse` | Always-white text (e.g. on primary coral buttons) |
165
+ | `--text-subtle-default` | `text-subtle` | Secondary text (descriptions, labels) — slate @ 48% alpha |
166
+
167
+ > **Watch out:** `text-on-prominent` still resolves, but it is **always-white** (aliases `--on-prominent-static-inverse`) — meant for text on dark/primary surfaces, NOT page body text. Use `text-prominent` for headings and body. `text-on-subtle` also still resolves (same value as `text-subtle`).
154
168
 
155
169
  ### 2.5 — Borders & Inputs
156
170
 
157
- | CSS Variable | Tailwind Class | Usage |
158
- | ------------------- | ------------------------- | ------------------------- |
159
- | `--border-subtle` | `border-border-subtle` | Default light border |
160
- | `--border-prominent`| `border-border-prominent` | Strong / emphasized border|
161
- | `--input` | `border-input` | Input resting state border|
162
- | `--ring` | `ring-ring` / `border-ring` | Focus ring and focus border color |
171
+ | CSS Variable | Tailwind Class | Usage |
172
+ | --------------------------- | ------------------------- | ------------------------- |
173
+ | `--border-default-default` | `border-default` | Default border (slate @ 16% alpha) |
174
+ | `--border-selected-default` | `border-selected` | Selected / emphasized border (solid slate-1200) |
175
+ | `--input` | `border-input` | Input resting state border |
176
+ | `--ring` | `ring-ring` | Focus ring color (blue-800 `#1789E1` chosen to clear WCAG 1.4.11's 3:1 minimum on both light and dark surfaces; see issue #38). Pair with `ring-2 ring-offset-2 ring-offset-primary-surface`, not `border-ring` |
177
+
178
+ > **Prefer the new names:** `border-default` / `border-selected`. The older `border-border-subtle` / `border-border-prominent` still resolve (deprecated aliases) but should not be used in new code.
163
179
 
164
180
  ### 2.6 — Supporting Colors
165
181
 
@@ -181,7 +197,7 @@ import { Button, Card, Badge } from "@deriv-ds/design-intelligence-layer"
181
197
  | Subtle hover tint | `bg-primary/[0.08]` |
182
198
  | Medium highlight | `bg-primary/[0.16]` |
183
199
  | Selected/active tint | `bg-primary/10` |
184
- | Status badge tint backgrounds | `bg-semantic-win/10`, `bg-semantic-loss/10`, etc. |
200
+ | Status tint backgrounds | `bg-warning/10`, `bg-info/10`, `bg-success/10`, `bg-error/10` (all utilities); or the foundation tints `bg-[var(--background-success-default)]` / `bg-[var(--background-error-default)]` |
185
201
 
186
202
  ### 2.8 — Interactive States
187
203
 
@@ -191,7 +207,7 @@ import { Button, Card, Badge } from "@deriv-ds/design-intelligence-layer"
191
207
 
192
208
  | State | Background | Text |
193
209
  | -------- | -------------------- | ---------------------------------- |
194
- | Default | transparent | `text-on-prominent` or `text-on-subtle` |
210
+ | Default | transparent | `text-prominent` or `text-subtle` |
195
211
  | Hover | `bg-secondary-hover` | `text-primary` |
196
212
  | Selected | `bg-secondary-hover` | `text-primary font-semibold` |
197
213
 
@@ -224,41 +240,38 @@ import { Button, Card, Badge } from "@deriv-ds/design-intelligence-layer"
224
240
  <div className="transition-colors duration-fast ease-standard">...</div>
225
241
  ```
226
242
 
243
+ **Reduced motion:** the base layer includes a global `@media (prefers-reduced-motion: reduce)` rule that collapses all `animation-duration` / `transition-duration` to `0.01ms` and forces `scroll-behavior: auto` for every element. This is automatic — components using the duration/easing tokens above don't need to add anything extra. If you hand-roll a custom animation outside these tokens (e.g. a raw `@keyframes` or a JS-driven animation library), you must independently respect `prefers-reduced-motion` since the CSS rule only overrides CSS-driven animations/transitions.
244
+
227
245
  ### 2.10 — Primitive Alpha Scales
228
246
 
229
- > Raw alpha (opacity) variants of the mono and blue primitives. These are **internal CSS variables only** — not exposed as Tailwind utility classes. Reference them only from semantic tokens, never directly in components.
247
+ > Raw alpha (opacity) variants. These are **internal CSS variables only** — not exposed as Tailwind utility classes. Reference them only from semantic or component tokens, never directly in components.
230
248
 
231
249
  **Naming convention:** `--primitive-[color]-alpha-[stop]`
232
250
 
233
- **Mono alpha scale** (black `oklch(0 0 0 / X%)`)
234
-
235
- | CSS Variable | Opacity | Typical use |
236
- | ----------------------------- | ------- | ---------------------------------------- |
237
- | `--primitive-mono-alpha-4` | 4% | Tab container background (`--tabs`) |
238
- | `--primitive-mono-alpha-8` | 8% | Subtle hover tint |
239
- | `--primitive-mono-alpha-16` | 16% | Pressed / active surface tint |
240
- | `--primitive-mono-alpha-24` | 24% | Medium-weight tinted surface |
241
- | `--primitive-mono-alpha-32` | 32% | Disabled state overlay |
242
- | `--primitive-mono-alpha-40` | 40% | Strong tint / scrim |
243
- | `--primitive-mono-alpha-50` | 50% | Backdrop overlay (replaces `--primitive-black-50`) |
244
- | `--primitive-mono-alpha-64` | 64% | Heavy overlay |
245
- | `--primitive-mono-alpha-80` | 80% | Near-opaque overlay |
246
-
247
- **Blue alpha scale** (brand blue — `oklch(0.476 0.297 267.4 / X%)`)
248
-
249
- | CSS Variable | Opacity | Typical use |
250
- | ----------------------------- | ------- | ---------------------------------------- |
251
- | `--primitive-blue-alpha-4` | 4% | Extremely subtle brand tint |
252
- | `--primitive-blue-alpha-8` | 8% | Hover tint on brand surfaces |
253
- | `--primitive-blue-alpha-16` | 16% | Selected / active brand tint |
254
- | `--primitive-blue-alpha-24` | 24% | Medium brand surface highlight |
255
- | `--primitive-blue-alpha-32` | 32% | Strong brand tint |
256
- | `--primitive-blue-alpha-40` | 40% | Slider range fill (via `--slider-range`) |
257
- | `--primitive-blue-alpha-50` | 50% | Brand overlay |
258
- | `--primitive-blue-alpha-64` | 64% | Heavy brand overlay |
259
- | `--primitive-blue-alpha-80` | 80% | Near-opaque brand overlay |
260
-
261
- > **`--primitive-black-50` is deprecated.** It now aliases `--primitive-mono-alpha-50`. The `--overlay` semantic token is unaffected — it still resolves to the same 50% black value.
251
+ All alpha scales share the same stop progression: `50` (0%), `75` (4%), `100` (8%), `200` (16%), `300` (24%), `400` (32%), `500` (40%), `600` (48%), `700` (56%), `800` (64%), `900` (72%), `1000` (80%), `1100` (88%).
252
+
253
+ **Slate alpha scale** (dark text/surface base — `oklch(0.227 0.019 266.2 / X%)`)
254
+
255
+ | CSS Variable | Opacity | Typical use |
256
+ | ------------------------------- | ------- | ---------------------------------------- |
257
+ | `--primitive-slate-alpha-75` | 4% | Tab container background (`--tabs`) |
258
+ | `--primitive-slate-alpha-100` | 8% | Subtle hover tint, secondary-hover, subtle borders |
259
+ | `--primitive-slate-alpha-200` | 16% | Pressed / active surface tint, default borders |
260
+ | `--primitive-slate-alpha-300` | 24% | Disabled text |
261
+ | `--primitive-slate-alpha-500` | 40% | Subtle text (via `--text-subtle-default`) |
262
+ | `--primitive-slate-alpha-600` | 48% | Placeholder text |
263
+
264
+ **Color alpha scales** — Coral, Green, Red, Yellow, Blue and others all follow the same stop pattern:
265
+
266
+ | Scale prefix | Base color | Typical use |
267
+ | --------------------------- | ---------- | ---------------------------------------- |
268
+ | `--primitive-coral-alpha-*` | `oklch(0.665 0.222 22.7)` | Brand alpha tints (primary hover, glow effects) |
269
+ | `--primitive-green-alpha-*` | `oklch(0.546 0.160 147.5)` | Success backgrounds, field success tint |
270
+ | `--primitive-yellow-alpha-*`| `oklch(0.777 0.171 65.3)` | Warning backgrounds, section message |
271
+ | `--primitive-red-alpha-*` | `oklch(0.588 0.232 29.5)` | Error backgrounds, field error tint |
272
+ | `--primitive-blue-alpha-*` | `oklch(0.676 0.177 251.1)` | Information backgrounds, badge status |
273
+
274
+ > The `--overlay` semantic token resolves to black at 50% opacity. Use `bg-overlay` for modal/dialog/sheet/drawer backdrops — do not manually reconstruct with `bg-black/50`.
262
275
 
263
276
  ---
264
277
 
@@ -268,26 +281,27 @@ import { Button, Card, Badge } from "@deriv-ds/design-intelligence-layer"
268
281
 
269
282
  | IF you need to... | THEN use | NEVER use |
270
283
  | -------------------------------------- | --------------------------------- | -------------------------------------- |
271
- | Pick a primary CTA button color | `bg-primary` | Green, or any other color for primary CTA |
272
- | Show WIN / profit / positive | `text-semantic-win` | Primary blue for profit |
273
- | Show LOSS / negative | `text-semantic-loss` | Any non-token red |
274
- | Show WARNING / caution | `text-semantic-warning` | Raw orange hex or primary tint |
275
- | Color a tab container background | `bg-tabs` | `bg-subtle` for tabs |
276
- | Color an active/selected tab | `bg-tabs-active` | `bg-prominent` for active tab |
277
- | Color a page background | `bg-prominent` | `bg-white` directly |
284
+ | Pick a primary CTA button color | `bg-primary` | Green, blue, or any other color for primary CTA |
285
+ | Show SUCCESS / profit / positive | `text-success` | Primary coral for success, non-token green |
286
+ | Show ERROR / loss / negative | `text-error` | Primary coral for error, non-token red |
287
+ | Show WARNING / caution | `text-warning` | Raw orange hex or primary tint |
288
+ | Color a tab container background | `bg-tabs` | `bg-secondary-surface` for tabs |
289
+ | Color an active/selected tab | `bg-tabs-active` | `bg-primary-surface` for active tab |
290
+ | Color a page background | `bg-primary-canvas` | `bg-white` or `bg-prominent` directly |
291
+ | Color a card or panel | `bg-primary-surface` | `bg-card`, arbitrary gray |
292
+ | Color a secondary/muted surface | `bg-secondary-surface` | `bg-subtle`, `bg-gray-*` |
278
293
  | Color a modal/dialog backdrop | `bg-overlay` | `bg-black/50` or raw black opacity |
279
- | Color a card or panel | `bg-card` | Arbitrary gray |
280
- | Color an elevated surface (popover) | `bg-popover` | `bg-card` for popovers |
281
- | Write primary heading text | `text-on-prominent` | Pure white, raw hex colors |
282
- | Write body / description text | `text-on-subtle` | `text-on-prominent` for descriptions |
283
- | Write a subtle label | `text-on-subtle` | Raw gray values |
284
- | Add a default border | `border-border-subtle` | Solid black borders, `border-border` |
285
- | Add a strong border | `border-border-prominent` | — |
294
+ | Write primary heading text | `text-prominent` | `text-on-prominent`, pure white, raw hex |
295
+ | Write body / description text | `text-subtle` | `text-prominent` for descriptions |
296
+ | Write a subtle label | `text-subtle` | Raw gray values |
297
+ | Add a default border | `border-default` | Solid black borders, `border-border-subtle` |
298
+ | Add a selected/strong border | `border-selected` | `border-border-prominent` |
286
299
  | Style an input (resting) | `border-input` | Solid colored backgrounds |
287
- | Style an input (focused) | `border-ring` + `ring-[3px] ring-ring/50` | Generic shadows on inputs |
300
+ | Style an interactive element (focused) | `ring-2 ring-ring ring-offset-2 ring-offset-primary-surface` | `ring-ring/50` (fails 3:1 contrast), generic shadows |
301
+ | Style an input (focused) | Border-based: `border-field-*-border-focus` (see Section 8.5 Input) | `ring-ring` on inputs — inputs use border, not ring, focus indication |
288
302
  | Pick a heading font | `font-display` | System fonts, raw font-family names |
289
303
  | Pick a body font | `font-body` | Raw font-family names |
290
- | Style button text | `font-display font-bold`, sentence case | `uppercase` on buttons |
304
+ | Style button text | `font-display font-extrabold`, sentence case | `uppercase` on buttons, `font-bold` |
291
305
  | Write white text on a dark surface | `text-on-prominent-static-inverse`| `text-white` or raw white hex |
292
306
 
293
307
  ---
@@ -296,7 +310,7 @@ import { Button, Card, Badge } from "@deriv-ds/design-intelligence-layer"
296
310
 
297
311
  ### 4.1 — Font Setup
298
312
 
299
- All text uses **Plus Jakarta Sans** (loaded weights: 300–800). Three Tailwind aliases are available — they all resolve to the same font:
313
+ All text uses **Inter** (loaded weights: 300–800). Three Tailwind aliases are available — they all resolve to the same font:
300
314
 
301
315
  | Tailwind Class | Purpose |
302
316
  | --------------- | ------------------------------- |
@@ -304,31 +318,35 @@ All text uses **Plus Jakarta Sans** (loaded weights: 300–800). Three Tailwind
304
318
  | `font-body` | Body text, UI elements |
305
319
  | `font-sans` | Default sans-serif fallback |
306
320
 
321
+ > `--font-plus-jakarta-sans` is a **deprecated alias** — it resolves to Inter and should not be referenced in new code.
322
+
307
323
  ### 4.2 — Pre-built Typography Classes
308
324
 
309
- The npm package ships these ready-to-use CSS classes. All include `text-transform: uppercase`:
310
-
311
- | Class | Size | Line Height | Weight | Letter Spacing |
312
- | ------------- | ----- | ----------- | ------ | -------------- |
313
- | `heading-h1` | 72px | 72px | 600 | 1.5px |
314
- | `heading-h2` | 64px | 64px | 600 | 1.5px |
315
- | `heading-h3` | 48px | 48px | 600 | 1.5px |
316
- | `heading-h4` | 40px | 40px | 600 | 1.5px |
317
- | `heading-xs` | 24px | 24px | 600 | 1.5px |
318
- | `body-lg` | 18px | 28px | 600 | |
319
- | `body-md` | 16px | 24px | 600 | |
320
- | `body-sm` | 12px | 16px | 600 | |
321
- | `body-xs` | 8px | 12px | 600 | |
322
-
323
- **Responsive heading sizes** (headings scale down on mobile):
324
-
325
- | Class | Desktop | Mobile |
326
- | ------------ | ------- | ------ |
327
- | `heading-h1` | 72px | 48px |
328
- | `heading-h2` | 64px | 48px |
329
- | `heading-h3` | 48px | 40px |
330
- | `heading-h4` | 40px | 32px |
331
- | `heading-xs` | 24px | 20px |
325
+ The npm package ships these ready-to-use CSS classes:
326
+
327
+ **Heading scale** (Inter · ExtraBold 800 · letter-spacing: -0.02em):
328
+
329
+ | Class | Size | Line Height | Weight | Letter Spacing |
330
+ | -------------- | ----- | ----------- | ------ | -------------- |
331
+ | `heading-hero` | 64px | 64px | 800 | -0.02em |
332
+ | `heading-h1` | 56px | 56px | 800 | -0.02em |
333
+ | `heading-h2` | 40px | 40px | 800 | -0.02em |
334
+ | `heading-h3` | 32px | 32px | 800 | -0.02em |
335
+ | `heading-h4` | 24px | 24px | 800 | -0.02em |
336
+ | `heading-h5` | 20px | 20px | 800 | -0.02em |
337
+ | `heading-h6` | 16px | 16px | 800 | -0.02em |
338
+
339
+ > `heading-xs` is **deprecated** use `heading-h4` instead (same size: 24px/24px/800).
340
+
341
+ **Body scale** (Inter · Regular 400):
342
+
343
+ | Class | Size | Line Height | Weight |
344
+ | ---------- | ----- | ----------- | ------ |
345
+ | `body-xl` | 20px | 30px | 400 |
346
+ | `body-lg` | 18px | 27px | 400 |
347
+ | `body-md` | 16px | 24px | 400 |
348
+ | `body-sm` | 14px | 21px | 400 |
349
+ | `body-xs` | 12px | 18px | 400 |
332
350
 
333
351
  ### 4.3 — Custom Text Size Overrides
334
352
 
@@ -348,16 +366,16 @@ These sizes differ from standard Tailwind defaults — use the design system val
348
366
 
349
367
  | Context | Class | Weight |
350
368
  | ------------------------ | -------------- | ------------------- |
351
- | Page headings | `font-display` | `font-semibold` (600) |
352
- | Button labels | `font-display` | `font-bold` (700), sentence case |
353
- | Body text | `font-body` | `font-semibold` (600) |
354
- | Tiny labels / decorative | `font-body` | `font-semibold` (600) at 8px |
369
+ | Page headings | `font-display` | `font-extrabold` (800) |
370
+ | Button labels | `font-display` | `font-extrabold` (800), sentence case |
371
+ | Body text | `font-body` | `font-normal` (400) |
372
+ | Tiny labels / decorative | `font-body` | `font-medium` (500) |
355
373
 
356
374
  ### 4.5 — Letter Spacing Tokens
357
375
 
358
376
  | Token value | Usage |
359
377
  | ----------- | ------------------------ |
360
- | 1.5px | Buttons, headings |
378
+ | -0.02em | Headings (all levels) |
361
379
  | -0.4px | Paragraphs, tight text |
362
380
  | -0.8px | Tight display text |
363
381
 
@@ -388,42 +406,47 @@ The design system uses a custom radius scale (base = 10px). Use these named toke
388
406
 
389
407
  ### 6.1 — Variants
390
408
 
391
- | Variant | Background | Text Color | Border | Hover |
392
- | ----------- | ---------------------- | ---------------------------------- | ----------------------------------- | ----------------------- |
393
- | `primary` | `bg-primary` | `text-on-prominent-static-inverse` | none | `bg-primary-hover` |
394
- | `secondary` | transparent | `text-on-prominent` | `border-[1.5px] border-border-prominent` | `bg-secondary-hover` |
395
- | `tertiary` | transparent | `text-primary` | none | `bg-primary/[0.08]` |
409
+ | Variant | Background | Text Color | Border | Hover |
410
+ | ----------- | ------------------------------ | ---------------------------------- | ----------------------------------------- | ------------------------------ |
411
+ | `primary` | `bg-button-primary-bg` | `text-on-prominent-static-inverse` | none | `bg-button-primary-bg-hover` |
412
+ | `secondary` | transparent | `text-prominent` | `border-[1.5px] border-button-secondary-border` | `bg-button-secondary-bg-hover` |
413
+ | `tertiary` | `bg-button-tertiary-bg` | `text-prominent` | none | `bg-button-tertiary-bg-hover` |
414
+ | `ghost` | transparent | `text-prominent` | none | `bg-button-ghost-bg-hover` |
415
+
416
+ > All button variants support `normal`, `inverse`, `static-light`, and `static-dark` sub-variants via component tokens.
396
417
 
397
418
  ### 6.2 — Sizes
398
419
 
399
- | Size | Height | Padding X | Font Size | Icon Size | Radius |
400
- | --------- | ------ | --------- | --------- | --------- | ------ |
401
- | `lg` | 48px | 24px | 16px | 16px | 4px |
402
- | `md` | 40px | 16px | 14px | 16px | 4px |
403
- | `sm` | 32px | 12px | 12px | 14px | 4px |
404
- | `xs` | 24px | 8px | 12px | 12px | 4px |
420
+ | Size | Height | Padding X | Font Size | Min Width | Radius |
421
+ | --------- | ------ | --------- | --------- | --------- | -------------- |
422
+ | `xl` | 56px | 24px | 20px | 112px | `rounded-full` |
423
+ | `lg` | 48px | 20px | 18px | 96px | `rounded-full` |
424
+ | `md` | 40px | 16px | 16px | 80px | `rounded-full` |
425
+ | `sm` | 32px | 12px | 14px | 64px | `rounded-full` |
426
+ | `xs` | 24px | 8px | 12px | — | `rounded-full` |
405
427
 
406
428
  **Icon-only sizes:**
407
429
 
408
430
  | Size | Dimensions | Icon Size |
409
431
  | ---------- | ---------- | --------- |
410
- | `icon-lg` | 48×48px | 16px |
432
+ | `icon-xl` | 56×56px | 24px |
433
+ | `icon-lg` | 48×48px | 20px |
411
434
  | `icon-md` | 40×40px | 16px |
412
- | `icon-sm` | 28×28px | 16px |
413
- | `icon-xs` | 24×24px | 12px |
435
+ | `icon-sm` | 32×32px | 16px |
436
+ | `icon-xs` | 24×24px | 14px |
414
437
 
415
438
  ### 6.3 — Button Typography & States
416
439
 
417
- All buttons: `font-display font-bold`, sentence case (no `uppercase`, no `tracking-wide`).
440
+ All buttons: `font-display font-extrabold` (800), sentence case (no `uppercase`, no `tracking-wide`).
418
441
 
419
442
  | State | Behavior |
420
443
  | -------- | ------------------------------------------------ |
421
444
  | Default | Base styling per variant |
422
445
  | Hover | Color shift per variant (see above) |
423
- | Focus | 3px ring with `ring-ring/50` opacity |
424
- | Pressed | `active:opacity-60` |
425
- | Loading | `opacity-24`, `pointer-events-none`, `data-loading`, `aria-busy` — applies to all variants (primary, secondary, tertiary) |
426
- | Disabled | `opacity-24`, `pointer-events-none` — applies to all variants (primary, secondary, tertiary) |
446
+ | Focus | 2px `ring-ring` (full opacity, blue-800) + 2px `ring-offset-primary-surface` — clears WCAG 1.4.11 3:1 |
447
+ | Pressed | Pressed bg token per variant (e.g. `bg-button-primary-bg-pressed`) |
448
+ | Loading | `opacity-24`, `pointer-events-none`, `data-loading`, `aria-busy` — applies to all variants |
449
+ | Disabled | Dedicated disabled tokens: `bg-button-disabled-normal-bg`, `text-button-disabled-normal-text` — not generic opacity |
427
450
 
428
451
  ---
429
452
 
@@ -497,11 +520,8 @@ import { Dialog, DialogTrigger, DialogContent, DialogHeader, DialogTitle, Dialog
497
520
  | Component | Tag | Sub-components |
498
521
  |-----------|-----|----------------|
499
522
  | Accordion | [composed] | AccordionItem, AccordionTrigger, AccordionContent |
500
- | Alert | [composed] | AlertTitle, AlertDescription |
501
- | AlertDialog | [complex] | AlertDialogTrigger, AlertDialogContent, AlertDialogHeader, AlertDialogFooter, AlertDialogTitle, AlertDialogDescription, AlertDialogAction, AlertDialogCancel, AlertDialogMedia |
502
523
  | AspectRatio | [simple] | — |
503
524
  | Avatar | [composed] | AvatarImage, AvatarFallback, AvatarBadge, AvatarGroup, AvatarGroupCount |
504
- | Badge | [simple] | — |
505
525
  | Breadcrumb | [composed] | BreadcrumbList, BreadcrumbItem, BreadcrumbLink, BreadcrumbPage, BreadcrumbSeparator, BreadcrumbEllipsis |
506
526
  | Button | [simple] | — |
507
527
  | Calendar | [complex] | — |
@@ -517,64 +537,66 @@ import { Dialog, DialogTrigger, DialogContent, DialogHeader, DialogTitle, Dialog
517
537
  | DirectionProvider | [simple] | — |
518
538
  | Drawer | [complex] | DrawerTrigger, DrawerContent, DrawerHeader, DrawerFooter, DrawerTitle, DrawerDescription, DrawerClose |
519
539
  | DropdownMenu | [composed] | DropdownMenuTrigger, DropdownMenuContent, DropdownMenuItem, DropdownMenuLabel, DropdownMenuSeparator, DropdownMenuCheckboxItem, DropdownMenuRadioGroup, DropdownMenuRadioItem, DropdownMenuSub, DropdownMenuSubTrigger, DropdownMenuSubContent, DropdownMenuShortcut |
520
- | EmailOrPhoneInput | [simple] | — (login field that auto-morphs from email Input to PhoneInput when the user types 2+ leading digits) |
521
540
  | Empty | [composed] | EmptyHeader, EmptyMedia, EmptyTitle, EmptyDescription, EmptyContent |
522
541
  | Field | [complex] | FieldLabel, FieldDescription, FieldError, FieldGroup, FieldLegend, FieldSet, FieldContent, FieldTitle, FieldSeparator |
523
542
  | Form | [complex] | FormField, FormItem, FormLabel, FormControl, FormDescription, FormMessage |
524
543
  | HoverCard | [composed] | HoverCardTrigger, HoverCardContent |
525
544
  | Input | [simple] | — |
526
545
  | InputGroup | [composed] | InputGroupAddon, InputGroupInput, InputGroupButton, InputGroupText, InputGroupTextarea |
527
- | InputOTP | [composed] | InputOTPGroup, InputOTPSlot, InputOTPSeparator |
528
546
  | Item | [composed] | ItemGroup, ItemContent, ItemTitle, ItemDescription, ItemMedia, ItemActions, ItemHeader, ItemFooter, ItemSeparator |
529
547
  | Kbd | [simple] | KbdGroup |
530
548
  | Label | [simple] | — |
531
549
  | Link | [simple] | — |
532
- | LoadingSpinner | [simple] | — |
533
- | NavigationMenu | [complex] | NavigationMenuList, NavigationMenuItem, NavigationMenuTrigger, NavigationMenuContent, NavigationMenuLink, NavigationMenuIndicator, NavigationMenuViewport, navigationMenuTriggerStyle |
534
550
  | NativeSelect | [simple] | NativeSelectOption, NativeSelectOptGroup |
551
+ | NavigationMenu | [complex] | NavigationMenuList, NavigationMenuItem, NavigationMenuTrigger, NavigationMenuContent, NavigationMenuLink, NavigationMenuIndicator, NavigationMenuViewport, navigationMenuTriggerStyle |
552
+ | NotificationBanner | [simple] | — (`title`, `description`, `onClose` — dismissible full-width banner bar) |
553
+ | OTPField | [composed] | OTPFieldGroup, OTPFieldSlot, OTPFieldSeparator |
535
554
  | Pagination | [composed] | PaginationContent, PaginationItem, PaginationLink, PaginationPrevious, PaginationNext, PaginationEllipsis |
536
- | PhoneInput | [simple] | — (country dial-code dropdown + numeric phone field; also exports `COUNTRIES`, `DEFAULT_COUNTRY`, `Country`) |
537
555
  | Popover | [composed] | PopoverTrigger, PopoverContent, PopoverHeader, PopoverTitle, PopoverDescription |
538
556
  | Progress | [simple] | — |
539
557
  | RadioGroup | [composed] | RadioGroupItem |
540
558
  | Resizable | [complex] | ResizablePanelGroup, ResizablePanel, ResizableHandle |
541
559
  | ScrollArea | [simple] | ScrollBar |
560
+ | SectionMessage | [composed] | SectionMessageTitle, SectionMessageDescription (inline alert; `role="alert"`; variants: `default \| information \| success \| warning \| danger`) |
542
561
  | Select | [composed] | SelectTrigger, SelectValue, SelectContent, SelectGroup, SelectLabel, SelectItem, SelectSeparator |
543
562
  | Separator | [simple] | — |
544
563
  | Sheet | [complex] | SheetTrigger, SheetContent, SheetHeader, SheetFooter, SheetTitle, SheetDescription, SheetClose |
545
564
  | Sidebar | [complex] | SidebarProvider, SidebarTrigger, SidebarInset, SidebarHeader, SidebarContent, SidebarFooter, SidebarGroup, SidebarGroupLabel, SidebarGroupContent, SidebarMenu, SidebarMenuItem, SidebarMenuButton, SidebarRail, useSidebar |
546
565
  | Skeleton | [simple] | — |
547
566
  | Slider | [simple] | — |
548
- | Sonner (Toaster) | [simple] | — (also import `toast` from `sonner`) |
567
+ | Sonner (Toaster) | [simple] | — (the imperative `toast` is re-exported from the package: `import { Snackbar, toast } from "@deriv-ds/design-intelligence-layer"`) |
549
568
  | Spinner | [simple] | — |
550
569
  | Stepper | [simple] | — |
551
570
  | Switch | [simple] | — |
552
571
  | Table | [composed] | TableHeader, TableBody, TableFooter, TableHead, TableRow, TableCell, TableCaption |
553
572
  | Tabs | [composed] | TabsList (`variant`: default/line, `size`: sm/md/lg), TabsTrigger (`iconPosition`: inline/top), TabsContent. Root accepts `orientation`: horizontal/vertical. |
573
+ | Tag | [simple] | — |
554
574
  | Textarea | [simple] | — |
555
575
  | TicketCard | [composed] | — |
556
576
  | Toggle | [simple] | — |
557
577
  | ToggleGroup | [composed] | ToggleGroupItem |
558
578
  | Tooltip | [composed] | TooltipTrigger, TooltipContent, TooltipProvider |
559
579
 
580
+ > **`Alert` does not exist.** Use `SectionMessage` for inline status/alert messages. Use `NotificationBanner` for dismissible full-width banner bars. Never invent an `Alert` or `Banner` import.
581
+
560
582
  ### Component styling notes
561
583
 
562
584
  These are styling behaviors you can't discover from TypeScript types alone:
563
585
 
564
586
  | Component | Note |
565
587
  |-----------|------|
566
- | Button | `font-display font-bold`, sentence case (no `uppercase`). Primary: `text-on-prominent-static-inverse`. Tertiary hover: `bg-primary/[0.08]` |
567
- | Card | Flat by default (no shadow). Add elevation manually: `className="shadow-sm"` |
568
- | Input | Resting: `border-input`. Focus: `border-ring` + `ring-[3px] ring-ring/50`. Radius: `rounded-sm` (6px) |
569
- | PhoneInput | Numeric-only field (non-digits blocked on keydown). Flags load from `@deriv/quill-icons/Flags` via the country's `flagKey`. Pass `floatingLabel` for the inset-label layout (mirrors Input). `onDialCodeChange(dialCode, country)` returns the full `Country`. |
570
- | EmailOrPhoneInput | Single login field renders `Input` (email) until 2+ leading digits are typed, then swaps to `PhoneInput`, carrying the digits across; clearing them reverts. `onValueChange(value, mode, dialCode?)` reports `"email"`/`"phone"`. `showLastUsed` clips a "Last used" Tag above the top-right corner. |
571
- | Tooltip | Bubble: `bg-primary` + `text-on-prominent-static-inverse` (not `bg-popover`). Always wrap in `<TooltipProvider>` |
588
+ | Button | `font-display font-extrabold` (800), sentence case (no `uppercase`). Primary: `text-on-prominent-static-inverse`. Radius: `rounded-full` (pill). 4 variants: primary, secondary, tertiary, ghost |
589
+ | Card | Flat by default (no shadow). Add elevation manually: `className="shadow-sm"` or use elevation tokens `var(--elevation-100)` through `var(--elevation-500)` |
590
+ | Input | Resting: `border-input`. Focus: border-based (`border-field-*-border-focus` + border-width step-up), no ring. Radius: `rounded-sm` (6px). **Variants:** `outline` (default), `fill`, `inverse` (sunken translucent fill + light foregrounds — for inputs ON a brand/coloured surface; also on `InputGroup`). **`readOnly`** renders a distinct borderless, softly-filled "display only" state (separate from the faded `disabled` state). |
591
+ | SectionMessage | Inline alert block. `role="alert"`. Variants: `default`, `information`, `success`, `warning`, `danger`. Use instead of `Alert`. **Icon contract:** `icon` prop — omit for the variant's default status icon, `null` to hide, or pass a node to override (composing a `SectionMessageIcon` child still works and suppresses the default). Also accepts `action` (buttons under the message) and `onDismiss` (renders a × button). |
592
+ | NotificationBanner | Dismissible full-width banner bar. Props: `title`, `description`, `onClose`. Use instead of `Banner`. **`variant`** (`information` \| `success` \| `warning` \| `danger`, default `information`) drives the default icon + colour; **`icon`** follows the same contract (omit = variant default, `null` = hide, node = override). |
593
+ | Tooltip | Bubble: uses component tokens `--tooltip-bg-default` + `--tooltip-text-default`. Always wrap in `<TooltipProvider>` |
572
594
  | Sidebar | Menu buttons use `rounded-sm`. Selection: `bg-secondary-hover` + `text-primary` + `font-semibold` |
573
- | Breadcrumb | Active page: `text-primary font-medium`. Links: `text-on-subtle` |
574
- | Tabs | **Variants:** `default` (pill, `bg-tabs`) and `line` (underline, transparent bg). **Sizes:** `sm` (h-8, text-xs), `md` (h-10, text-sm, default), `lg` (h-12, text-base). **Icon position:** `inline` (default) or `top` (stacks icon above label). **Orientation:** `horizontal` (default) or `vertical` (line variant renders left-edge indicator). Hover: `bg-secondary-hover` (default) / `text-primary` (line). Selected: `bg-tabs-active` + `text-primary font-semibold`. Line variant underline: `bg-primary`. |
595
+ | Breadcrumb | Active page: `text-primary font-medium`. Links: `text-subtle` |
596
+ | Tabs | **Variants:** `default` (pill, `bg-tabs`) and `line` (underline, transparent bg). **Sizes:** `sm` (32px, 14px text), `md` (40px, 16px text, default), `lg` (48px, 18px text). **Icon position:** `inline` (default) or `top` (stacks icon above label). **Orientation:** `horizontal` (default) or `vertical` (line variant renders left-edge indicator). Hover: `bg-secondary-hover` (default) / `text-primary` (line). Selected: `bg-tabs-active` + `text-primary font-semibold`. |
575
597
  | Select | Item hover: `bg-primary/[0.08]`. Selected: `text-primary font-medium` + checkmark. `SelectTrigger` accepts `readOnly` prop: blocks interaction, retains full default appearance, chevron renders at `opacity-30` |
576
- | Progress | Track: `bg-primary/20`. Indicator: `bg-primary`. Radius: `rounded-2xs` |
577
- | LoadingSpinner | Arc spinner. Color comes from `--loading-spinner-bg-default` token (coral `#ff444f`). Size defaults to `size-4` (16px); override via `className` (e.g. `size-6`, `size-8`). |
598
+ | Progress | Track and indicator use component tokens `--progress-bar-bg-*`. Sizes: sm (4px height) and md (8px height). Radius: `rounded-full` |
599
+ | Spinner | Uses `--loading-spinner-bg-default` (coral-700). Inherits parent text color for custom use. Size defaults to `size-4`; override via `className`. |
578
600
  | Stepper | Numeric input flanked by `−` / `+` tertiary `icon-xs` buttons. Composes `InputGroup` internally. Props: `value`, `defaultValue`, `onValueChange`, `min`, `max`, `step` (default 1), `disabled`, `placeholder`. Supports controlled & uncontrolled modes, keyboard Arrow Up/Down, and floating-point steps. Default width: `w-32` |
579
601
  | Switch | Checked track: `bg-slider-range`. Checked thumb: `bg-primary` |
580
602
  | Slider | Thumb: square `rounded-[4px]`, `bg-primary`. Track range: `bg-slider-range` |
@@ -590,6 +612,7 @@ These are styling behaviors you can't discover from TypeScript types alone:
590
612
  > Blocks are fully composed UI sections built from design system primitives. They appear in the **Blocks** tab of the playground.
591
613
  > - Blocks **are exported** from the npm package — import them by name from `@deriv-ds/design-intelligence-layer` (e.g. `import { Navbar, Section } from "@deriv-ds/design-intelligence-layer"`). When a user asks for a block by name, import it directly instead of recreating it.
592
614
  > - Do NOT mistake a Block for a component — it will not appear in Rule 1's component list.
615
+ > - **Responsive convention:** prefer blocks that are responsive out of the box or take a single `layout="mobile" | "desktop"` prop (like `Navbar`, which renders a sidebar ≥768px and a bottom bar below). Some heroes still ship as explicit `HeroMobile*` / `HeroDesktop*` pairs — pick the one matching the viewport. New blocks should favour the `layout`-prop pattern over shipping separate mobile/desktop exports.
593
616
 
594
617
  ### NavBar
595
618
 
@@ -603,7 +626,7 @@ A landing page top navigation bar with Desktop and Mobile breakpoint variants.
603
626
 
604
627
  **Components used:** `Button` (variants: `ghost`, `primary`, `secondary`; sizes: `sm`, `icon-sm`)
605
628
 
606
- **Tokens used:** `bg-prominent`, `bg-primary`, `border-border-subtle`, `rounded-xs`, `rounded-md`
629
+ **Tokens used:** `bg-primary-surface`, `bg-primary`, `border-default`, `rounded-xs`, `rounded-md`
607
630
 
608
631
  ---
609
632
 
@@ -617,9 +640,9 @@ Landing page hero sections in multiple layout types.
617
640
  | Type 1 — Mobile | Single column stacked: text content centred above, image panel full-width below |
618
641
  | Type 2 — Desktop | Centred single-column: tagline pill + heading + body + single primary CTA with `<Icon name="arrow-right" />`; no image |
619
642
 
620
- **Components used:** `Button` (default `sm`, `secondary sm`); `<Icon name="arrow-up-right" />`, `<Icon name="arrow-right" />` (FontAwesome Pro via the `Icon` component)
643
+ **Components used:** `Button` (default `sm`, `secondary sm`); `<Icon name="arrow-up-right" />`, `<Icon name="arrow-right" />` (`@deriv/quill-icons` via the `Icon` component)
621
644
 
622
- **Tokens used:** `bg-prominent`, `bg-subtle`, `border-border-subtle`, `text-on-prominent`, `text-on-subtle`, `bg-semantic-win`, `rounded-xl`, `rounded-full`, `px-layout-margin-inline`, `gap-layout-gutter`, `py-24`, `text-5xl`, `font-semibold`, `font-display`, `tracking-tight`, `text-lg`, `font-body`, `text-sm`, `shadow-sm`, `max-w-2xl`
645
+ **Tokens used:** `bg-primary-surface`, `bg-secondary-surface`, `border-default`, `text-prominent`, `text-subtle`, `bg-[var(--background-success-default)]`, `rounded-xl`, `rounded-full`, `px-layout-margin-inline`, `gap-layout-gutter`, `py-24`, `text-5xl`, `font-display`, `text-lg`, `font-body`, `text-sm`, `shadow-sm`, `max-w-2xl`
623
646
 
624
647
  ---
625
648
 
@@ -646,9 +669,9 @@ import { Section } from "@deriv-ds/design-intelligence-layer"
646
669
 
647
670
  **Props:** `title`, `description`, `titleSize`, `showTag` + `tag`, `showTitle`, `showChevron` + `onTitleClick`, `showControlSection`, `showButton` + `buttonLabel` + `onButtonClick`, `showNavigation` + `onPrev`/`onNext`, `controlSegments`, `showDescription`, `showSegmentedControl` + `segments` + `value`/`onValueChange`, `children`. All flags default off except `showTitle`; `titleSize="loading"` renders a skeleton title.
648
671
 
649
- **Components used:** `Tag` (`outline-neutral`, size `2xs`), `Icon` (`chevron-left`/`chevron-right`), `SegmentedControl`, `Skeleton`
672
+ **Components used:** `Tag`, `Icon` (`chevron-left`/`chevron-right`), `SegmentedControl`, `Skeleton`
650
673
 
651
- **Tokens used:** `bg-primary-surface`, `text-prominent`, `text-subtle`, `--background-default-opacity-default`, `--background-hover-default`, `body-md`, `rounded-2xl`, `rounded-full`
674
+ **Tokens used:** `bg-primary-surface`, `text-prominent`, `text-subtle`, `body-md`, `rounded-2xl`, `rounded-full`
652
675
 
653
676
  ---
654
677
 
@@ -656,31 +679,38 @@ import { Section } from "@deriv-ds/design-intelligence-layer"
656
679
 
657
680
  | Mistake | Correct Approach |
658
681
  | ------- | ---------------- |
659
- | Using hardcoded hex (`#2323FF`) for primary | Use `bg-primary` or `text-primary` |
660
- | Using `bg-white` or `bg-black` | Use `bg-prominent` or `bg-overlay` |
661
- | Using `border-border` | Use `border-border-subtle` or `border-border-prominent` |
682
+ | Using hardcoded hex (`#FF444F`) for primary | Use `bg-primary` or `text-primary` |
683
+ | Using `bg-white` or `bg-black` | Use `bg-primary-canvas` or `bg-overlay` |
684
+ | Using `bg-prominent` or `bg-subtle` | Use `bg-primary-canvas`, `bg-primary-surface`, `bg-secondary-surface` — `prominent`/`subtle` are text tokens |
685
+ | Using `text-on-prominent` for headings/body | Use `text-prominent` — `text-on-prominent` is always-white (for dark surfaces) |
686
+ | Using `border-border` | Use `border-default` or `border-selected` |
687
+ | Using `border-border-subtle` / `border-border-prominent` | Use `border-default` / `border-selected` |
688
+ | Using `text-semantic-win`, `text-semantic-loss` | These don't exist. Use the status utilities `text-success` / `text-error` (or `text-warning` / `text-info`) |
662
689
  | Using `bg-hover` | Use `bg-primary/[0.08]` or `bg-secondary-hover` |
663
690
  | Using `text-primary-foreground` | Use `text-on-prominent-static-inverse` |
664
- | Using `text-on-decorative` | Use `text-on-subtle` |
665
- | Using `font-mono` expecting Plus Jakarta Sans | Use `font-display` or `font-body` |
666
- | Using `font-bold` for headings | Use `font-semibold` (600) for headings |
691
+ | Using `text-on-decorative` or `text-on-subtle` | Use `text-subtle` |
692
+ | Using `font-mono` expecting Inter | Use `font-display` or `font-body` |
693
+ | Using `font-semibold` for headings | Use `font-extrabold` (800) for headings |
694
+ | Using `font-bold` or `font-semibold` for buttons | Use `font-extrabold` (800) for buttons |
667
695
  | Using `uppercase` on buttons | Buttons use sentence case (no `uppercase`) |
696
+ | Using small radius on buttons | Buttons use `rounded-full` (pill shape, 999px) |
668
697
  | Using standard TW sizes for headings (e.g. `text-6xl` = 60px) | Use design system values (`text-6xl` = 64px in this system) |
669
- | Forgetting responsive heading sizes | Headings scale down on mobile (see Section 4.2) |
670
698
  | Using `rounded-[4px]` or `rounded-[2px]` | Use `rounded-xs` (4px) or `rounded-2xs` (2px) |
671
- | Installing or importing `lucide-react` | Use `<Icon name="..." weight="..." />` (FontAwesome Pro) — catalog in `icon-reference.md` |
699
+ | Installing or importing `lucide-react` | Use `<Icon name="..." weight="..." />` (`@deriv/quill-icons`) — catalog in `icon-reference.md` |
672
700
  | Adding `tailwind.config.js` | Tailwind v4 uses CSS config via the package |
673
701
  | Using `bg-gray-*`, `text-zinc-*`, etc. | Use semantic tokens only |
702
+ | Using `Alert` or `Banner` component | Use `SectionMessage` (inline alerts) or `NotificationBanner` (dismissible banner bars) |
703
+ | Using `Plus Jakarta Sans` font | Font is **Inter** — `--font-plus-jakarta-sans` is a deprecated alias |
674
704
 
675
705
  ---
676
706
 
677
707
  ## 10 — Accessibility Notes
678
708
 
679
- 1. **Primary blue text on white** (~3.0:1) — reserve for large/bold UI labels only.
680
- 2. **Secondary text `text-on-subtle` on white** (~4.5:1) — meets WCAG AA for normal text.
681
- 3. **Secondary text `text-on-subtle` on white** (~4.5:1) — meets WCAG AA for normal text.
682
- 4. **Win green on white** (~5.0:1) — safe for normal text at AA.
683
- 5. **Loss red on white** (~3.9:1) — use at 18px+ bold or pair with icons.
709
+ 1. **Primary coral text on white** (`text-primary` / coral-700 #FF444F, ~4.5:1) — check contrast for small text; reserve for large/bold UI labels if ratio is borderline.
710
+ 2. **Secondary text `text-subtle` on white** (~4.5:1) — meets WCAG AA for normal text.
711
+ 3. **Success green on white** (green-900 #007A22, ~5.0:1) — safe for normal text at AA.
712
+ 4. **Error red on white** (red-900 #C40000, ~4.5:1) — safe for normal text at AA in light theme.
713
+ 5. **Warning yellow on white** (yellow-900 #C47D00) — check contrast; pair with icons.
684
714
  6. Always pair semantic colors with **icons or labels** — never communicate meaning through color alone.
685
715
 
686
716
  ---
@@ -689,13 +719,13 @@ import { Section } from "@deriv-ds/design-intelligence-layer"
689
719
 
690
720
  **Primary CTA:**
691
721
  ```tsx
692
- <Button variant="primary" size="lg">Trade Now</Button>
722
+ <Button variant="primary" size="lg">Get Started</Button>
693
723
  ```
694
724
 
695
- **Profit/Loss display:**
725
+ **Success/Error display:**
696
726
  ```tsx
697
- <span className="text-semantic-win font-body font-semibold">+$84.00</span>
698
- <span className="text-semantic-loss font-body font-semibold">-$120.00</span>
727
+ <span className="text-success font-body font-semibold">+$84.00</span>
728
+ <span className="text-error font-body font-semibold">-$120.00</span>
699
729
  ```
700
730
 
701
731
  **Heading:**
@@ -712,3 +742,11 @@ import { Section } from "@deriv-ds/design-intelligence-layer"
712
742
  ```tsx
713
743
  <Input type="email" placeholder="Enter your email" />
714
744
  ```
745
+
746
+ **Inline alert:**
747
+ ```tsx
748
+ <SectionMessage variant="warning">
749
+ <SectionMessageTitle>Verification required</SectionMessageTitle>
750
+ <SectionMessageDescription>Please verify your identity to continue.</SectionMessageDescription>
751
+ </SectionMessage>
752
+ ```