IBM
MIT
Enterprise-grade design system with IBM's iconic blue accent, sophisticated typography hierarchy, and fluid spacing built on Carbon principles—ideal for corporate products and SaaS platforms
Layout StudioImport this kit into a Studio project and start editing.
CLI installRun it in any project. No account needed.
npx @layoutdesign/context install ibm# layout.md — IBM.com Design System
---
## 0. Quick Reference
**Stack:** IBM Carbon Design System · CSS custom properties (extracted-css-vars, medium confidence, 19 props found) · Vanilla CSS + Bootstrap detected · `--ibm-*` curated token prefix over original `--cds-*` vars.
**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 {
/* Colour */
--ibm-accent: rgb(15, 98, 254); /* IBM Blue — primary CTA, links, h3 text */
/* Typography */
--ibm-font-sans: "IBM Plex Sans", "Helvetica Neue", Arial, sans-serif;
--ibm-font-mono: "IBM Plex Mono", "Courier New", monospace;
--ibm-font-size-xs: 13.3333px; /* Pagination labels */
--ibm-font-size-sm: 14px; /* Body small, labels, links */
--ibm-font-size-md: 16px; /* Body default, buttons, tabs */
--ibm-font-size-lg: 21.8824px; /* Lead paragraph */
--ibm-font-size-2xl: 42px; /* Stats / callout numbers */
--ibm-font-size-3xl: 53.6469px; /* H1 / H2 display */
--ibm-font-weight-regular: 300; /* Display headings */
--ibm-font-weight-medium: 400; /* Body, buttons, nav */
--ibm-font-weight-semibold: 600; /* Section labels, emphasis */
/* Spacing */
--ibm-space-md: 24px; /* Component internal padding */
--ibm-space-lg: 32px; /* Heading margin-bottom */
--ibm-space-xl: 48px; /* Section sub-gaps */
/* Layout */
--cds-grid-columns: 16; /* Carbon 16-column grid */
--cds-grid-gutter: 2rem; /* 32px column gutter */
--cds-grid-margin: 1.5rem; /* 24px page margin */
--vertical-spacing-default: clamp(2rem, 0.9908rem + 3.6697cqi, 4rem); /* Fluid section gap */
/* Motion */
--ibm-duration-fast: 0.07s; /* Micro-interactions */
--ibm-ease-default: ease; /* Default easing */
--ibm-ease-productive: cubic-bezier(0.2, 0, 0.38, 0.9); /* Carbon productive motion */
}
```
```tsx
// Primary CTA Button — IBM Carbon pattern
const PrimaryButton = ({ label, onClick, disabled }: ButtonProps) => (
<button
className="cds--btn cds--btn--primary"
onClick={onClick}
disabled={disabled}
style={{
backgroundColor: disabled ? 'transparent' : 'var(--ibm-accent)',
color: '#ffffff',
fontFamily: 'var(--ibm-font-sans)',
fontSize: 'var(--ibm-font-size-md)',
fontWeight: 'var(--ibm-font-weight-medium)',
padding: '0 var(--ibm-space-md)',
height: 'var(--cds-layout-size-height-lg)', /* 48px */
borderRadius: '0px',
border: 'none',
cursor: disabled ? 'not-allowed' : 'pointer',
transition: 'background-color var(--ibm-duration-fast) var(--ibm-ease-productive)',
}}
>
{label}
</button>
);
```
**NEVER rules:**
- **NEVER** use `border-radius` > 0 on Carbon buttons — IBM buttons are square (0px radius)
- **NEVER** use Inter, Roboto, or system-ui as the primary font — always `"IBM Plex Sans"` first
- **NEVER** hardcode `#0f62fe` — always use `var(--ibm-accent)` or `var(--cds-border-interactive, #0f62fe)`
- **NEVER** use spacing values off the 4px grid — no `1px` gaps or arbitrary margins
- **NEVER** use fewer than 16 grid columns — IBM Carbon uses a 16-column grid, not 12
- **NEVER** omit hover/focus/active/disabled states on interactive elements — Carbon enforces all four
- **NEVER** use `font-weight: 700` (bold) — IBM Plex Sans weight scale tops at `600` (semibold)
<!-- Quick Reference truncated to fit the 75-line cap. See later sections for the full design system. -->
## 1. Design Direction & Philosophy
### Character & Aesthetic Intent
IBM.com expresses **enterprise precision and technical authority**. The visual language is derived from the IBM Carbon Design System — a rigorously structured, accessibility-first system built for global scale.
**Mood:** Professional, intelligent, confident. Not warm. Not playful. Not decorative.
**Primary visual signals:**
- **Sharp geometry everywhere** — `border-radius: 0px` on all buttons, cards, inputs, modals. The only rounded element is the Watson chat launcher button (28px), which is a third-party widget anomaly.
- **Type-led hierarchy** — scale jumps from 14px body small to 53.6px display are dramatic and intentional. Headlines at `font-weight: 300` create an unexpected lightness against IBM Blue accents.
- **Monochromatic with one electric blue** — `rgb(15, 98, 254)` is the sole accent. It appears on CTAs, links, h3 text, and interactive states. All other UI is black (`#161616`), white, and neutral grays.
- **16-column grid discipline** — content is always contained in the Carbon grid. Sections never break out of the column structure.
### What This Design Explicitly Rejects
- **NEVER** rounded corners on interactive components (buttons, inputs, cards, tabs)
- **NEVER** drop shadows for card elevation — Carbon uses border or background-color to differentiate surfaces
- **NEVER** warm colour tones (orange, yellow, red except for semantic danger states)
- **NEVER** decorative typography (serif for display, mixed font stacks for personality)
- **NEVER** dense information layouts — generous whitespace between sections via `clamp(2rem, ..., 4rem)` vertical rhythm
- **NEVER** pill-shaped buttons on brand UI — the 28px radius on the chat launcher is a chat widget, not an IBM brand pattern
---
## 2. Colour System
### Tier 1 — Primitive Values
```css
:root {
/* Blues */
--primitive-blue-60: rgb(15, 98, 254); /* #0f62fe — IBM Blue 60 */
--primitive-blue-70: rgb(0, 80, 230); /* #0050e6 — Blue 70, hover */
--primitive-blue-80: rgb(0, 45, 156); /* #002d9c — Blue 80, active */
--primitive-blue-40: rgb(0, 67, 206); /* #0043ce — link hover */
/* Neutrals */
--primitive-black-100: rgb(22, 22, 22); /* #161616 — IBM Black */
--primitive-gray-80: rgb(57, 57, 57); /* #393939 — secondary button bg */
--primitive-gray-70: rgb(82, 82, 82); /* #525252 — button_primary text (nav context) */
--primitive-gray-60: rgb(111, 111, 111); /* #6f6f6f — secondary active bg */
--primitive-gray-40: rgb(141, 141, 141); /* #8d8d8d — disabled text */
--primitive-gray-30: rgb(224, 224, 224); /* #e0e0e0 — button separator */
--primitive-gray-10: rgb(244, 244, 244); /* #f4f4f4 — input bg, tab bg */
--primitive-white: rgb(255, 255, 255); /* #ffffff — text on dark, modal bg */
--primitive-label: rgb(51, 51, 51); /* #333333 — label/dropdown text */
/* Semantic feedback */
--primitive-red-60: rgb(218, 30, 40); /* #da1e28 — danger primary */
--primitive-red-70: rgb(184, 25, 33); /* #b81921 — danger hover */
--primitive-red-80: rgb(117, 14, 19); /* #750e13 — danger active */
}
```
### Tier 2 — Semantic Aliases (original `--cds-*` names preserved)
```css
:root {
/* Interactive */
--ibm-accent: rgb(15, 98, 254); /* = --brand-primary-cta; primary action, links, h3 */
--cds-border-interactive: #0f62fe; /* definition term hover/focus underline */
--cds-focus: #0f62fe; /* focus ring inset colour */
--cds-background: #fff; /* page/modal background for focus ring offset */
/* Button semantic tokens (Carbon originals) */
--cds-button-primary-hover: #0050e6; /* primary button :hover bg */
--cds-button-primary-active: #002d9c; /* primary button :active bg */
--cds-button-secondary-hover: #474747; /* secondary button :hover bg */
--cds-button-secondary-active: #6f6f6f; /* secondary button :active bg */
--cds-button-tertiary-hover: #0050e6; /* tertiary button :hover bg */
--cds-button-tertiary-active: #002d9c; /* tertiary button :active bg */
--cds-button-danger-primary: #da1e28; /* danger CTA fill */
--cds-button-danger-hover: #b81921; /* danger :hover */
--cds-button-danger-active: #750e13; /* danger :active */
--cds-button-focus-color: var(--cds-focus, #0f62fe); /* focus ring colour */
--cds-button-separator: #e0e0e0; /* button set divider */
/* Text */
--cds-text-on-color: #fff; /* text on coloured backgrounds */
--cds-text-on-color-disabled: #8d8d8d; /* disabled text on colour */
--cds-text-disabled: rgba(22, 22, 22, 0.25); /* disabled text on white */
--cds-text-inverse: #fff; /* text-inverse on dark surfaces */
--cds-link-primary: rgb(15, 98, 254); /* default link colour */
--cds-link-primary-hover: #0043ce; /* link :hover */
/* Surfaces */
--cds-layer-hover: hsla(0, 0%, 55.3%, 0.12); /* ghost button hover overlay */
--cds-background-hover: hsla(0, 0%, 55.3%, 0.12); /* ghost button hover bg */
--cds-background-active: hsla(0, 0%, 55.3%, 0.5); /* ghost button active bg */
--cds-layer-accent-01: #e0e0e0; /* skeleton shimmer base */
/* Feedback / danger */
--cds-icon-on-color: #fff; /* icon on coloured surfaces */
}
```
### Tier 3 — Component Tokens
| Component | Property | Token | Value |
|---|---|---|---|
| Primary button | background | `--cds-button-primary` | `var(--ibm-accent)` |
| Primary button hover | background | `--cds-button-primary-hover` | `#0050e6` |
| Primary button active | background | `--cds-button-primary-active` | `#002d9c` |
| Secondary button | background | `--cds-button-secondary` | `rgb(57, 57, 57)` |
| Input | background | — | `rgb(244, 244, 244)` |
| Tab (inactive) | background | — | `rgb(244, 244, 244)` |
| H3 / subsection heading | color | `--ibm-accent` | `rgb(15, 98, 254)` |
| Body text | color | `--primitive-black-100` | `rgb(22, 22, 22)` |
| Disabled text | color | `--cds-text-on-color-disabled` | `#8d8d8d` |
---
## 3. Typography System
### Font Stack
```css
:root {
--ibm-font-sans: "IBM Plex Sans", "Helvetica Neue", Arial, sans-serif; /* primary — all UI */
--ibm-font-mono: "IBM Plex Mono", "Courier New", monospace; /* code, data */
--ibm-font-serif: "IBM Plex Serif", Georgia, serif; /* long-form editorial (rare) */
/* Note: Helvetica and Source Sans Pro loaded via consent banner — NOT brand fonts */
}
```
### Composite Type Scales
```css
:root {
/* ── Display / H1 ── */
--type-display: {
font-family: var(--ibm-font-sans);
font-size: 53.6469px; /* --ibm-font-size-3xl */
font-weight: 300; /* --ibm-font-weight-regular — intentionally light */
line-height: 62.7669px; /* ~1.17 ratio */
letter-spacing: normal;
/* Used on: h1, primary h2 */
}
/* ── H2 / Section Title ── */
--type-heading-2: {
font-family: var(--ibm-font-sans);
font-size: 53.6469px;
font-weight: 300;
line-height: 62.7669px;
letter-spacing: normal;
/* margin-bottom: 32px (h2) or 64px (h1) */
}
/* ── H3 / Subsection ── */
--type-heading-3: {
font-family: var(--ibm-font-sans);
font-size: 32px;
font-weight: 400; /* --ibm-font-weight-medium */
line-height: 40px;
letter-spacing: normal;
color: var(--ibm-accent); /* IBM Blue — h3 rendered in brand blue */
/* margin-bottom: 32px */
}
/* ── Stats / Callout Number ── */
--type-stat: {
font-family: var(--ibm-font-sans);
font-size: 42px; /* --ibm-font-size-2xl */
font-weight: 400;
line-height: 52px; /* inferred ~1.24 */
letter-spacing: normal;
}
/* ── Lead Paragraph ── */
--type-lead: {
font-family: var(--ibm-font-sans);
font-size: 21.8824px; /* --ibm-font-size-lg */
font-weight: 400;
line-height: 28px;
letter-spacing: normal;
}
/* ── Body Default ── */
--type-body: {
font-family: var(--ibm-font-sans);
font-size: 20px; /* body computed style */
font-weight: 400;
line-height: 28px;
letter-spacing: normal;
}
/* ── Body / UI Default (Carbon body-01) ── */
--type-body-sm: {
font-family: var(--ibm-font-sans);
font-size: 16px; /* --ibm-font-size-md */
font-weight: 400;
line-height: 24px;
letter-spacing: normal;
}
/* ── Label / Helper / Link ── */
--type-label: {
font-family: var(--ibm-font-sans); /* Helvetica for consent forms only */
font-size: 14px; /* --ibm-font-size-sm */
font-weight: 400;
line-height: 18px; /* --ibm-line-height-tight */
letter-spacing: 0.16px;
/* Used on: labels, links, badges, button secondary, tooltips, dropdowns */
}
/* ── Caption / Micro ── */
--type-caption: {
font-family: var(--ibm-font-sans);
font-size: 13.3333px; /* --ibm-font-size-xs */
font-weight: 400;
line-height: 18px;
letter-spacing: 0.16px;
/* Used on: pagination, footnotes */
}
/* ── Section Eyebrow ── */
--type-eyebrow: {
font-family: var(--ibm-font-sans);
font-size: 16px;
font-weight: 600; /* --ibm-font-weight-semibold */
line-height: 22px; /* --ibm-line-height-normal */
letter-spacing: normal;
/* Used on: "Recommended for you" labels */
}
}
```
### Weight Scale
| Token | Value | Usage |
|---|---|---|
| `--ibm-font-weight-regular` | `300` | Display headings (h1, h2) |
| `--ibm-font-weight-medium` | `400` | Body, UI, buttons, nav |
| `--ibm-font-weight-semibold` | `600` | Section labels, emphasis |
**Note:** `300` is named "regular" in the IBM token system — this is not a typo. IBM Plex Sans Light (300) is the display weight.
---
## 4. Spacing & Layout
### Spacing Scale
```css
:root {
/* Component height scale (Carbon layout sizing) */
--cds-layout-size-height-xs: 24px; /* icon buttons, compact rows */
--cds-layout-size-height-sm: 32px; /* small inputs, compact buttons */
--cds-layout-size-height-md: 40px; /* default inputs */
--cds-layout-size-height-lg: 48px; /* large buttons, standard CTAs */
--cds-layout-size-height-xl: 64px; /* navigation bar height */
--cds-layout-size-height-2xl: 80px; /* hero CTAs, jumbo inputs */
/* Inline padding density (Carbon layout density) */
--cds-layout-density-padding-inline-condensed: 8px; /* tight mode */
--cds-layout-density-padding-inline-normal: 16px; /* default mode */
/* Curated spacing scale */
--ibm-space-md: 24px; /* component padding, label margin */
--ibm-space-lg: 32px; /* heading margin-bottom, section rhythm */
--ibm-space-xl: 48px; /* dropdown margin, card gaps */
/* Fluid vertical section spacing */
--vertical-spacing-default: clamp(2rem, 0.9908rem + 3.6697cqi, 4rem); /* 32px → 64px fluid */
--vertical-spacing-reduced: calc(var(--vertical-spacing-default) * 0.75);
--vertical-spacing-expanded: calc(var(--vertical-spacing-default) * 1.5);
--vertical-spacing: var(--vertical-spacing-default); /* apply this to section gaps */
/* DO NOT USE: --ibm-space-xs (1px) or --ibm-space-2xl (999999999px) — both are off-grid artifacts */
}
```
### Grid System
```css
:root {
--cds-grid-columns: 16; /* IBM Carbon 16-column grid — not 12 */
--cds-grid-gutter: 2rem; /* 32px between columns */
--cds-grid-margin: 1.5rem; /* 24px page edge margin */
}
/* Carbon grid applied */
.ibm-grid {
display: grid;
grid-template-columns: repeat(var(--cds-grid-columns), 1fr);
gap: var(--cds-grid-gutter);
margin-inline: var(--cds-grid-margin);
}
```
### Breakpoints
IBM Carbon uses these named breakpoints (inferred from media query census):
| Name | Width | Notes |
|---|---|---|
| `sm` | 320px | Mobile start |
| `md` | 672px | Tablet |
| `lg` | 1056px | Desktop |
| `xlg` | 1312px | Wide desktop |
| `max` | 1584px | Full-width cap |
Additional breakpoints at 768px, 1024px, 1200px detected (likely legacy or Bootstrap overlap).
---
## 5. Page Structure & Layout Patterns
> **Source:** Inferred from LAYOUT DIGEST component inventory, computed styles, and CTA census. No screenshots available. Rows marked `(inferred)` are not visually confirmed.
### 5.1 Section Map
| Order | Section | Layout Type | Approx. Height | Key Elements |
|---|---|---|---|---|
| 1 | Global Navigation | `display:block`, sticky | 64px (`--cds-layout-size-height-xl`) | Logo, nav links (16px/400), search, menu |
| 2 | Hero / Masthead | Full-width, 16-col grid | 480–720px (inferred) | H1 (53.6px/300), lead text, primary CTA (IBM Blue) |
| 3 | Feature Card Grid | Grid, 4-up or 3-up | ~400px (inferred) | 143 card instances detected; cards `display:block`, no shadow |
| 4 | Stats / Callout Band | Flex row, full-width | ~200px (inferred) | 42px stat numbers, `--ibm-font-size-2xl` |
| 5 | Content / Editorial | 2-col grid (text + image) | ~600px (inferred) | H3 in IBM Blue, body 20px/400, secondary CTAs |
| 6 | Tabbed Content Section | Role=tab pattern | ~500px (inferred) | `role_tab` with `background: rgb(244,244,244)`, 32px padding, `border-radius: 4px 0 0 4px` on active |
| 7 | Dropdown / Filter Section | Block, 16-col | ~120px (inferred) | Dropdown with `margin: 24px 0 48px`, 14px text |
| 8 | Newsletter / Subscribe | Block with input | ~300px (inferred) | Input (`bg: rgb(244,244,244)`), subscribe button |
| 9 | Modal / Dialog | Overlay | Full viewport | `role_dialog`, `display:inline`, IBM Blue focus ring |
| 10 | Footer | Block, 16-col, multi-row | ~400px (inferred) | Nav links 14px/400, legal text 13.3px |
### 5.2 Layout Patterns
**Navigation:**
- `display: block` container; internal items use `display: flex, flex-direction: row`
- Height locked to `--cds-layout-size-height-xl` (64px)
- No border-radius, no shadow — flat bar
**Hero:**
- 16-column grid; headline typically spans 8–12 cols at `lg` breakpoint (inferred)
- H1 at `53.6469px / 300 weight` — counterintuitively light for maximum scale impact
- Primary CTA: IBM Blue (`rgb(15, 98, 254)`), `height: 48px`, `border-radius: 0px`, `padding: 16px`
**Card Grid:**
- `display: block` per card; grid container wraps at 1–4 columns across breakpoints
- No `box-shadow` — surface differentiation via background color only
- Card icon/accent in IBM Blue (`rgb(15, 98, 254)`)
- Gap: `var(--cds-grid-gutter)` = 32px
**Tab Component:**
- Active tab: `background: rgb(244, 244, 244)`, `border-radius: 4px 0px 0px 4px`, `padding: 32px`
- Transition: `background 0.3s cubic-bezier(0.2, 0, 0.38, 0.9)` (Carbon productive easing)
- Inactive tabs: `filter: grayscale(1) opacity(0.8)`
**Content Columns:**
- 2-column at `lg`+: text (left, ~8 cols) + media (right, ~8 cols) (inferred)
- Column gap: `var(--cds-grid-gutter)` (32px)
### 5.3 Visual Hierarchy
1. **H1/H2 display text** at 53.6px/300 — largest element, low weight for elegant scale
2. **IBM Blue** (`#0f62fe`) as the single accent — all CTAs, links, and H3 rendered in this colour
3. **Primary CTA buttons** — IBM Blue fill, white text, 48px height, square corners; always visible above the fold
4. **Cards** are flat (no shadow) — hierarchy from whitespace and type scale, not elevation
5. **Section rhythm** driven by `clamp(2rem, ..., 4rem)` vertical-spacing — sections breathe
### 5.4 Content Patterns
**Card pattern (143 instances):**
- Icon or image (IBM Blue icon font `ibm_icons`)
- H3 or label (IBM Blue, 14–16px)
- Body text (black, 14–16px)
- Link or CTA (`display:flex, gap:4px, align:center` — icon+text inline)
**Link pattern:**
- `display: flex`, `flex-direction: row`, `align-items: center`, `gap: 4px`
- IBM Blue text + trailing arrow icon from `ibm_icons` font
- `margin-bottom: 16px` between stacked links
**CTA census result:**
- Primary button: IBM Blue (`rgb(15, 98, 254)`) — confirmed on 2+ detected instances
- Secondary button: Dark gray (`rgb(57, 57, 57)`) — `display:flex, justify-content:space-between` with trailing icon
- Ghost/tertiary: transparent background, IBM Blue text
---
## 6. Component Patterns
### 6.1 Button — Primary (`cds--btn--primary`)
**Anatomy:** Container → Label text → Optional trailing icon
**State table:**
| State | Background | Text | Border | Shadow |
|---|---|---|---|---|
| Default | `rgb(15, 98, 254)` | `#fff` | none | none |
| Hover | `var(--cds-button-primary-hover, #0050e6)` | `#fff` | none | none |
| Focus | `rgb(15, 98, 254)` | `#fff` | none | `inset 0 0 0 1px #0f62fe, inset 0 0 0 2px #fff` |
| Active | `var(--cds-button-primary-active, #002d9c)` | `#fff` | none | none |
| Disabled | transparent | `#8d8d8d` | none | none |
```tsx
import { useState } from 'react';
interface PrimaryButtonProps {
label: string;
onClick?: () => void;
disabled?: boolean;
loading?: boolean;
}
export const PrimaryButton = ({ label, onClick, disabled, loading }: PrimaryButtonProps) => {
const [isFocused, setIsFocused] = useState(false);
return (
<button
onClick={onClick}
disabled={disabled || loading}
onFocus={() => setIsFocused(true)}
onBlur={() => setIsFocused(false)}
style={{
display: 'flex',
alignItems: 'center',
justifyContent: 'space-between',
gap: '1rem',
height: 'var(--cds-layout-size-height-lg)', /* 48px */
paddingInline: 'var(--cds-layout-density-padding-inline-normal)', /* 16px */
backgroundColor: disabled || loading ? 'transparent' : 'var(--ibm-accent)',
color: disabled ? 'var(--cds-text-on-color-disabled, #8d8d8d)' : 'var(--cds-text-on-color, #fff)',
fontFamily: 'var(--ibm-font-sans)',
fontSize: 'var(--ibm-font-size-md)', /* 16px */
fontWeight: 'var(--ibm-font-weight-medium)', /* 400 */
lineHeight: 'var(--ibm-font-size-md)',
borderRadius: '0px', /* NEVER round IBM buttons */
border: 'none',
cursor: disabled ? 'not-allowed' : 'pointer',
boxShadow: isFocused
? 'inset 0 0 0 1px var(--cds-button-focus-color, #0f62fe), inset 0 0 0 2px var(--cds-background, #fff)'
: 'none',
transition: `background-color var(--ibm-duration-fast) var(--ibm-ease-productive),
box-shadow var(--ibm-duration-fast) var(--ibm-ease-productive)`,
}}
onMouseOver={(e) => {
if (!disabled && !loading) {
(e.currentTarget as HTMLButtonElement).style.backgroundColor =
'var(--cds-button-primary-hover, #0050e6)';
}
}}
onMouseOut={(e) => {
if (!disabled && !loading) {
(e.currentTarget as HTMLButtonElement).style.backgroundColor = 'var(--ibm-accent)';
}
}}
onMouseDown={(e) => {
if (!disabled && !loading) {
(e.currentTarget as HTMLButtonElement).style.backgroundColor =
'var(--cds-button-primary-active, #002d9c)';
}
}}
onMouseUp={(e) => {
if (!disabled && !loading) {
(e.currentTarget as HTMLButtonElement).style.backgroundColor = 'var(--ibm-accent)';
}
}}
>
{loading ? <span aria-label="Loading…" className="cds--loading" /> : label}
{!loading && <span aria-hidden="true" style={{ fontFamily: 'ibm_icons' }}>→</span>}
</button>
);
};
```
---
### 6.2 Button — Secondary (`cds--btn--secondary`)
**Anatomy:** Container (`flex, space-between`) → Label → Trailing icon
| State | Background | Text |
|---|---|---|
| Default | `rgb(57, 57, 57)` | `#fff` |
| Hover | `var(--cds-button-secondary-hover, #474747)` | `#fff` |
| Focus | `rgb(57, 57, 57)` + inset shadow | `#fff` |
| Active | `var(--cds-button-secondary-active, #6f6f6f)` | `#fff` |
| Disabled | transparent | `#8d8d8d` |
Extracted styles: `display:flex`, `justify-content:space-between`, `align-items:center`, `padding: 1px 0px 1px 16px`, `border-radius:0px`, `font-size:14px`, `letter-spacing:0.16px`.
---
### 6.3 Input
**Anatomy:** Label → Input field → Helper text / Error message
| State | Background | Border-bottom | Text |
|---|---|---|---|
| Default | `rgb(244, 244, 244)` | — | `rgb(22, 22, 22)` |
| Focus | `rgb(244, 244, 244)` | IBM Blue focus ring | `rgb(22, 22, 22)` |
| Disabled | [TBD — extract manually] | — | `rgba(22,22,22,0.25)` |
| Error | [TBD — extract manually] | `#da1e28` | `rgb(22, 22, 22)` |
Extracted styles: `padding: 0px 16px`, `border-radius: 0px`, `font-size: 14px`, `letter-spacing: 0.16px`, `line-height: 18px`.
Transition: `background-color 0.07s cubic-bezier(0.2, 0, 0.38, 0.9), outline 0.07s cubic-bezier(0.2, 0, 0.38, 0.9)`.
```tsx
export const TextInput = ({ label, id, placeholder, disabled, error }: InputProps) => (
<div style={{ display: 'block' }}>
<label
htmlFor={id}
style={{
display: 'block',
fontFamily: 'var(--ibm-font-sans)',
fontSize: 'var(--ibm-font-size-sm)', /* 14px */
fontWeight: 'var(--ibm-font-weight-medium)', /* 400 */
lineHeight: '18px',
letterSpacing: '0.16px',
color: 'rgb(51, 51, 51)',
margin: '16px 0 8px',
}}
>
{label}
</label>
<input
id={id}
placeholder={placeholder}
disabled={disabled}
aria-invalid={!!error}
style={{
display: 'block',
width: '100%',
height: 'var(--cds-layout-size-height-md)', /* 40px */
padding: '0 var(--cds-layout-density-padding-inline-normal)',
backgroundColor: 'rgb(244, 244, 244)',
border: 'none',
borderBottom: error ? '2px solid #da1e28' : '1px solid transparent',
borderRadius: '0px',
fontFamily: 'var(--ibm-font-sans)',
fontSize: 'var(--ibm-font-size-sm)',
color: disabled ? 'rgba(22,22,22,0.25)' : 'rgb(22, 22, 22)',
transition: 'background-color 0.07s cubic-bezier(0.2, 0, 0.38, 0.9), outline 0.07s cubic-bezier(0.2, 0, 0.38, 0.9)',
cursor: disabled ? 'not-allowed' : 'text',
}}
/>
{error && (
<p style={{ color: '#da1e28', fontSize: 'var(--ibm-font-size-sm)', margin: '4px 0 0' }}>
{error}
</p>
)}
</div>
);
```
---
### 6.4 Card
**Anatomy:** Icon/image → Tag/Badge → Heading → Body text → Link CTA
| State | Background | Border | Shadow |
|---|---|---|---|
| Default | transparent | none | none |
| Hover | [TBD — extract manually] | none | none |
| Focus | focus ring via outline | — | — |
| Disabled | [TBD] | — | — |
Extracted styles: `display:block`, `border-radius:0px`, `padding:0px`, no `box-shadow`. Icon color: `rgb(15, 98, 254)`.
```tsx
export const IBMCard = ({ tag, heading, body, linkLabel, href }: CardProps) => (
<article
style={{
display: 'block',
borderRadius: '0px', /* NEVER add border-radius to cards */
padding: '0',
backgroundColor: 'transparent',
}}
>
{tag && (
<span style={{
fontFamily: 'var(--ibm-font-sans)',
fontSize: 'var(--ibm-font-size-sm)',
fontWeight: 'var(--ibm-font-weight-medium)',
color: 'rgb(22, 22, 22)',
lineHeight: '18px',
letterSpacing: '0.16px',
display: 'block',
marginBottom: '8px',
}}>
{tag}
</span>
)}
<h3 style={{
fontFamily: 'var(--ibm-font-sans)',
fontSize: '32px',
fontWeight: 'var(--ibm-font-weight-medium)',
lineHeight: '40px',
color: 'var(--ibm-accent)', /* h3 always IBM Blue */
marginBottom: 'var(--ibm-space-lg)',
}}>
{heading}
</h3>
<p style={{
fontFamily: 'var(--ibm-font-sans)',
fontSize: 'var(--ibm-font-size-md)',
fontWeight: 'var(--ibm-font-weight-medium)',
lineHeight: '24px',
color: 'rgb(22, 22, 22)',
}}>
{body}
</p>
<a
href={href}
style={{
display: 'flex',
flexDirection: 'row',
alignItems: 'center',
gap: '4px',
fontFamily: 'var(--ibm-font-sans)',
fontSize: 'var(--ibm-font-size-sm)',
fontWeight: 'var(--ibm-font-weight-medium)',
color: 'var(--ibm-accent)',
textDecoration: 'none',
marginBottom: 'var(--ibm-space-md)',
}}
>
{linkLabel}
</a>
</article>
);
```
---
### 6.5 Tab (`role="tab"`)
**Anatomy:** Tab list → Tab buttons → Tab panel
| State | Background | Filter | Radius |
|---|---|---|---|
| Inactive | `rgb(244, 244, 244)` | `grayscale(1) opacity(0.8)` | `4px 0 0 4px` |
| Active | `rgb(244, 244, 244)` | `none` | `4px 0 0 4px` |
| Hover | `var(--cds-layer-hover)` | — | `4px 0 0 4px` |
| Focus | focus ring inset | none | `4px 0 0 4px` |
Extracted: `padding:32px`, `display:flex`, `justify-content:center`, `align-items:center`.
Transition: `background 0.3s cubic-bezier(0.2, 0, 0.38, 0.9), filter 0.3s cubic-bezier(0.2, 0, 0.38, 0.9)`.
---
### 6.6 Tooltip
Extracted: `font-size:14px`, `line-height:18px`, `border-radius:0px`, `text-align:left`, `padding:0`. Background and border color [TBD — extract manually from tooltip open state].
---
### 6.7 Dropdown
Extracted: `font-size:14px`, `line-height:14px`, `letter-spacing:normal`, `padding:0 16px`, `border-radius:0px`, `color:rgb(51,51,51)`, `margin:24px 0 48px`.
---
## 7. Elevation & Depth
IBM Carbon explicitly avoids shadow-based elevation. Surfaces are differentiated by **background color and borders only**.
```css
:root {
/* IBM Carbon uses NO decorative box-shadows for elevation */
/* The only shadows are functional: focus rings and button separators */
/* Focus ring — applied via box-shadow inset */
--ibm-shadow-focus:
inset 0 0 0 1px var(--cds-button-focus-color, #0f62fe),
inset 0 0 0 2px var(--cds-background, #fff);
/* Button set separator */
--ibm-shadow-btn-separator:
-0.0625rem 0 0 0 var(--cds-button-separator, #e0e0e0);
/* Stacked button separator */
--ibm-shadow-btn-separator-stacked:
0 -0.0625rem 0 0 var(--cds-button-separator, #e0e0e0);
/* Accessibility focus (consent/TrustArc): distinct blue halo */
--ibm-shadow-focus-halo:
rgb(255, 255, 255) 0px 0px 0px 1px,
rgb(54, 153, 241) 0px 0px 0px 4px;
}
```
### Z-Index Scale
```css
:root {
/* Inferred from Carbon popover and sticky header usage */
--z-base: 1;
--z-dropdown: 1000;
--z-sticky: 1100;
--z-popover: 6001; /* --cds-popover-tab-tip z-index extracted */
--z-modal: 9000; /* inferred from role_dialog */
--z-toast: 9100; /* inferred */
--z-tooltip: 9200; /* inferred */
}
```
**Layering principle:** No shadows. Overlapping surfaces use `z-index` + solid background, never `box-shadow: 0 4px 8px rgba(0,0,0,0.1)` style decorative shadows.
---
## 8. Motion
```css
:root {
/* Duration */
--ibm-duration-fast: 0.07s; /* micro: input bg, button bg — extracted */
--ibm-duration-moderate: 0.3s; /* tabs, tooltips, tooltipfade — extracted from role_tab */
--ibm-duration-slow: [TBD — extract manually]; /* page transitions */
/* Easing */
--ibm-ease-default: ease; /* generic — extracted */
--ibm-ease-productive: cubic-bezier(0.2, 0, 0.38, 0.9); /* Carbon productive — extracted from input/tab */
--ibm-ease-expressive: cubic-bezier(0.4, 0.14, 0.3, 1); /* Carbon expressive — inferred */
}
```
### Keyframe Animations (extracted)
| Name | Purpose | Duration |
|---|---|---|
| `cds--skeleton` | Skeleton loading shimmer | Continuous |
| `cds--tooltip-fade` | Tooltip appear/disappear | `--ibm-duration-moderate` |
| `cds--hide-feedback` | Copy feedback disappear | `--ibm-duration-fast` |
| `cds--show-feedback` | Copy feedback appear | `--ibm-duration-fast` |
| `cds--progress-bar-indeterminate` | Progress bar loading | Continuous |
| `expand` / `collapse` | Accordion open/close | `--ibm-duration-moderate` |
| `sticky-header-slide-in` | Nav re-attach on scroll | `--ibm-duration-moderate` |
| `fp-fade-in` / `fp-fade-out` | Slide/carousel transitions | `--ibm-duration-moderate` |
### Motion Rules
- **Micro-interactions** (button bg, input bg): `0.07s ease` — barely perceptible, feels responsive
- **Component state changes** (tab active, tooltip): `0.3s cubic-bezier(0.2, 0, 0.38, 0.9)` — productive motion
- **Skeleton loading**: Use `cds--skeleton` keyframe animation — never fake with opacity pulse alone
- **NEVER animate layout properties** (width, height, margin) — only `background-color`, `opacity`, `transform`, `box-shadow`
- **Respect prefers-reduced-motion** — wrap all animations in `@media (prefers-reduced-motion: no-preference)`
---
## 9. Anti-Patterns & Constraints
1. **Hardcoded colour values → Why it fails → What to do instead.**
AI agents default to writing `color: #0f62fe` directly in component code. When IBM updates brand blue or when theming is applied, all hardcoded values must be manually hunted down across the codebase. **Use `var(--ibm-accent)` or `var(--cds-border-interactive, #0f62fe)` everywhere. The fallback value documents intent while the variable enables theming.**
2. **Rounded button corners → Why it fails → What to do instead.**
Agents trained on Bootstrap/Material patterns automatically add `border-radius: 4px` or `border-radius: 8px` to buttons. IBM Carbon buttons are **strictly square** (`border-radius: 0px`). Adding any radius breaks the Carbon design language and fails IBM brand review. **Explicitly set `border-radius: 0` on every button, input, card, and tab. Only the Watson chat launcher (a third-party widget) uses 28px radius — do not use this as a precedent.**
3. **Wrong font family → Why it fails → What to do instead.**
Agents default to Inter, Roboto, or system-ui because these are the most common modern web fonts. IBM.com's entire identity is built on IBM Plex Sans. Using any other font breaks typographic brand fidelity immediately. **Always declare `font-family: "IBM Plex Sans", "Helvetica Neue", Arial, sans-serif` — never omit the "IBM Plex Sans" first entry, never swap in Inter or Roboto.**
4. **12-column grid instead of 16 → Why it fails → What to do instead.**
Bootstrap and most CSS frameworks use 12-column grids. Agents trained on Bootstrap will generate `col-md-6` (6/12 = 50%) for two-column layouts, which is technically correct but misses Carbon's intent. IBM Carbon uses **16 columns** (`--cds-grid-columns: 16`) — a 50% column is 8 of 16 columns. **Always specify `grid-template-columns: repeat(16, 1fr)` and size spans accordingly.**
5. **Arbitrary spacing values → Why it fails → What to do instead.**
Agents generate `margin: 20px` or `padding: 15px` when they approximate spacing from visual inspection. IBM Carbon uses a strict 8px base grid with `--cds-layout-size-height-*` and `--ibm-space-*` tokens. Off-grid values (e.g. the extracted `1px` space) break visual rhythm and fail grid alignment. **Every margin and padding must map to a spacing token. If no token exists, round to the nearest 8px multiple.**
6. **Missing interactive states → Why it fails → What to do instead.**
Agents frequently implement only `default` and `hover` states, omitting `focus`, `active`, and `disabled`. IBM Carbon's accessibility requirements mandate visible `focus` rings (the inset double-ring: `inset 0 0 0 1px #0f62fe, inset 0 0 0 2px #fff`) and explicit `disabled` cursor (`not-allowed`). Missing these causes WCAG failures. **Implement all five states: default, hover, focus, active, disabled — in every interactive component.**
7. **Box shadows for card elevation → Why it fails → What to do instead.**
Agents applying Material Design conventions add `box-shadow: 0 2px 8px rgba(0,0,0,0.15)` to cards to signal elevation. IBM Carbon explicitly rejects decorative shadows — all surface elevation is expressed through background colour (`rgb(244,244,244)` vs `#ffffff`) or subtle border. **NEVER add decorative box-shadow to cards, modals, or panels. Use background-color differentiation only.**
8. **Dynamic Tailwind class construction → Why it fails → What to do instead.**
In Tailwind projects, agents write `className={\`bg-[\${color}]\`}` with dynamic interpolation. Tailwind's JIT compiler cannot scan dynamic string concatenation and will purge the class, rendering the component unstyled in production. **Always use complete static class names: `bg-[var(--ibm-accent)]`. For truly dynamic values, use inline `style` with CSS custom properties.**
9. **Using font-weight 700 (bold) → Why it fails → What to do instead.**
Agents default to `font-weight: bold` or `font-weight: 700` for emphasis. IBM Plex Sans's weight scale tops at `600` (SemiBold). Weight 700 is not included in any of the loaded font files and will cause the browser to synthesise a faux-bold, degrading typographic quality. **Use `--ibm-font-weight-semibold: 600` for maximum emphasis. Never use 700 or `bold`.**
10. **Inline styles over CSS custom properties → Why it fails → What to do instead.**
Agents writing quick components hardcode `style={{ backgroundColor: '#0f62fe' }}` as a shortcut. This makes theming impossible, breaks dark mode support, and creates maintenance debt. Every literal value must be traced to its source when the brand updates. **Always reference design tokens: `style={{ backgroundColor: 'var(--ibm-accent)' }}`. Inline styles are acceptable only when they reference CSS custom properties.**
11. **Absolute positioning for layout structure → Why it fails → What to do instead.**
Agents use `position: absolute` to align nav items or card badges because it "works" visually at one viewport. IBM Carbon's navigation and grid are built on `display:flex` and `display:grid`. Absolute positioning breaks responsive reflow and accessibility tab order. **Use `display: flex` with `justify-content` and `align-items`, or `display: grid` with the 16-column system. Reserve `position: absolute` only for true overlays (tooltips, popovers, modals).**
12. **Adding `!important` to override Carbon → Why it fails → What to do instead.**
When integrating with the existing Carbon stylesheet, agents add `!important` to "win" specificity battles. This creates an unresolvable specificity arms race and makes the stylesheet unmaintainable. It also signals that the component is fighting the design system rather than working with it. **Understand Carbon's BEM class structure (`cds--btn--primary`) and apply overrides at the same or higher specificity using the component's own class hierarchy, or use CSS custom property overrides at `:root`.**
---
## 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 (43) */
--brand-primary-cta: rgb(15, 98, 254); /* Primary CTA background, dominant on 2 buttons — e.g. "Wechseln" /* mined from computed styles */ */
--ibm-accent: rgb(15, 98, 254);
--primitive-blue-60: rgb(15, 98, 254);
--primitive-blue-70: rgb(0, 80, 230);
--primitive-blue-80: rgb(0, 45, 156);
--primitive-blue-40: rgb(0, 67, 206);
--primitive-black-100: rgb(22, 22, 22);
--primitive-gray-80: rgb(57, 57, 57);
--primitive-gray-70: rgb(82, 82, 82);
--primitive-gray-60: rgb(111, 111, 111);
--primitive-gray-40: rgb(141, 141, 141);
--primitive-gray-30: rgb(224, 224, 224);
--primitive-gray-10: rgb(244, 244, 244);
--primitive-white: rgb(255, 255, 255);
--primitive-label: rgb(51, 51, 51);
--primitive-red-60: rgb(218, 30, 40);
--primitive-red-70: rgb(184, 25, 33);
--primitive-red-80: rgb(117, 14, 19);
--cds-border-interactive: #0f62fe;
--cds-focus: #0f62fe;
--cds-background: #fff;
--cds-button-primary-hover: #0050e6;
--cds-button-primary-active: #002d9c;
--cds-button-secondary-hover: #474747;
--cds-button-secondary-active: #6f6f6f;
--cds-button-tertiary-hover: #0050e6;
--cds-button-tertiary-active: #002d9c;
--cds-button-danger-primary: #da1e28;
--cds-button-danger-hover: #b81921;
--cds-button-danger-active: #750e13;
--cds-button-focus-color: var(--cds-focus, #0f62fe);
--cds-button-separator: #e0e0e0;
--cds-text-on-color: #fff;
--cds-text-on-color-disabled: #8d8d8d;
--cds-text-disabled: rgba(22, 22, 22, 0.25);
--cds-text-inverse: #fff;
--cds-link-primary: rgb(15, 98, 254);
--cds-link-primary-hover: #0043ce;
--cds-layer-hover: hsla(0, 0%, 55.3%, 0.12);
--cds-background-hover: hsla(0, 0%, 55.3%, 0.12);
--cds-background-active: hsla(0, 0%, 55.3%, 0.5);
--cds-layer-accent-01: #e0e0e0;
--cds-icon-on-color: #fff;
/* Typography (33) */
--cds-layout-size-height-xs: 24px;
--cds-layout-size-height-sm: 32px;
--cds-layout-size-height-md: 40px;
--cds-layout-size-height-lg: 48px;
--cds-layout-size-height-xl: 64px;
--cds-layout-size-height-2xl: 80px;
--cds-layout-size-height-min: 0px;
--cds-layout-size-height-max: 999999999px;
--font-size-xs: 13.3333px; /* 4 elements — e.g. button "1", button "2", button "3" /* mined from computed styles */ */
--font-size-sm: 14px; /* 35 elements — e.g. span "Webinar", span "Insight", span "Report" /* mined from computed styles */ */
--font-size-md: 16px; /* 57 elements — e.g. h5 "Recommended for you", p "A New Way to Make AI", p "IBM Launches Sports " /* mined from computed styles */ */
--font-size-lg: 21.8824px; /* 5 elements — e.g. p "From next-generation", span "From next-generation", a "software" /* mined from computed styles */ */
--font-size-2xl: 42px; /* 2 elements — e.g. div "USD 4.5 Billion", div "15K" /* mined from computed styles */ */
--font-size-3xl: 53.6469px; /* 6 elements — e.g. h1 "Become an AI-first e", h2 "Products announced a", h2 "Smarter business. Re" /* mined from computed styles */ */
--font-weight-regular: 300; /* 6 elements — e.g. h1 "Become an AI-first e", h2 "Products announced a", h2 "Smarter business. Re" /* mined from computed styles */ */
--font-weight-medium: 400; /* 108 elements — e.g. h2 "Stay connected", h2 "What's New at IBM ne", h3 "IBM" /* mined from computed styles */ */
--font-weight-semibold: 600; /* 1 element — e.g. h5 "Recommended for you" /* mined from computed styles */ */
--line-height-tight: 18.0001px; /* 34 elements — e.g. span "Webinar", span "Insight", span "Report" /* mined from computed styles */ */
--line-height-normal: 22px; /* 15 elements — e.g. p "Sie scheinen sich in", span "Explore 5 plays to b", span "See what you missed " /* mined from computed styles */ */
--ibm-font-sans: "IBM Plex Sans", "Helvetica Neue", Arial, sans-serif;
--ibm-font-mono: "IBM Plex Mono", "Courier New", monospace;
--ibm-font-size-xs: 13.3333px;
--ibm-font-size-sm: 14px;
--ibm-font-size-md: 16px;
--ibm-font-size-lg: 21.8824px;
--ibm-font-size-2xl: 42px;
--ibm-font-size-3xl: 53.6469px;
--ibm-font-weight-regular: 300;
--ibm-font-weight-medium: 400;
--ibm-font-weight-semibold: 600;
--ibm-font-serif: "IBM Plex Serif", Georgia, serif;
--ibm-line-height-tight: 18.0001px;
--ibm-line-height-normal: 22px;
/* Spacing (24) */
--cds-grid-gutter: 2rem;
--cds-grid-margin: 1.5rem;
--cds-layout-density-padding-inline-condensed: 8px;
--cds-layout-density-padding-inline-normal: 16px;
--cds-layout-density-padding-inline-min: 0px;
--cds-layout-density-padding-inline-max: 999999999px;
--vertical-spacing-default: clamp(2rem, 0.9908rem + 3.6697cqi, 4rem);
--vertical-spacing-reduced: calc(var(--vertical-spacing-default) * 0.75);
--vertical-spacing-expanded: calc(var(--vertical-spacing-default) * 1.5);
--vertical-spacing: var(--vertical-spacing-default);
--space-xs: 1px; /* 4 elements — e.g. div .cmp-tabs__tabs-container, div .cmp-tabs__tabs-container, div .cmp-tabs__tabs-container /* mined from computed styles */ */
--space-md: 24px; /* 2 elements — e.g. div .tile-group-container, div .tile-group-container /* mined from computed styles */ */
--space-lg: 32px; /* 17 elements — e.g. section .cds--grid, section .cds--grid, section .cds--grid /* mined from computed styles */ */
--space-xl: 48px; /* 3 elements — e.g. div .tile-group-container, div .tile-group-container, div .intro-section--flex /* mined from computed styles */ */
--space-2xl: 72px; /* 1 element — e.g. div .cds--row /* mined from computed styles */ */
--ibm-space-md: 24px;
--ibm-space-lg: 32px;
--ibm-space-xl: 48px;
--cds-layout-size-height-xs: 24px;
--cds-layout-size-height-sm: 32px;
--cds-layout-size-height-md: 40px;
--cds-layout-size-height-lg: 48px;
--cds-layout-size-height-xl: 64px;
--cds-layout-size-height-2xl: 80px;
/* Radius (5) */
--radius-sm: 0px 8px 0px 0px; /* 4 elements — e.g. button .cds--btn--icon-only, button .cds--btn--icon-only, button .cds--btn--icon-only /* mined from computed styles */ */
--radius-md: 4px; /* 1 element — e.g. button .mktoButton "Subscribe" /* mined from computed styles */ */
--radius-lg: 8px 0px 0px; /* 2 elements — e.g. button .cds--btn--icon-only, button .cds--btn--icon-only /* mined from computed styles */ */
--radius-full: 28px; /* 2 elements — e.g. button .WACLauncher__Button, button .WACLauncher__Button /* mined from computed styles */ */
--ibm-radius-md: 4px;
/* Effects (5) */
--cds-grid-columns: 16;
--ibm-shadow-focus: inset 0 0 0 1px #0f62fe, inset 0 0 0 2px #fff;
--ibm-shadow-btn-separator: -0.0625rem 0 0 0 var(--cds-button-separator, #e0e0e0);
--ibm-shadow-btn-separator-stacked: 0 -0.0625rem 0 0 var(--cds-button-separator, #e0e0e0);
--ibm-shadow-focus-halo: rgb(255, 255, 255) 0px 0px 0px 1px,
rgb(54, 153, 241) 0px 0px 0px 4px;
/* Motion (78) */
----motion-cds--hide-feedback: @keyframes cds--hide-feedback {
0% { opacity: 1; visibility: inherit; }
100% { opacity: 0; visibility: hidden; }
}; /* @keyframes cds--hide-feedback */
----motion-cds--show-feedback: @keyframes cds--show-feedback {
0% { opacity: 0; visibility: hidden; }
100% { opacity: 1; visibility: inherit; }
}; /* @keyframes cds--show-feedback */
----motion-cds--skeleton: @keyframes cds--skeleton {
0% { opacity: 0.3; transform: scaleX(0); transform… <0.5KB elided>; /* @keyframes cds--skeleton */
----motion-cds--tooltip-fade: @keyframes cds--tooltip-fade {
0% { opacity: 0; }
100% { opacity: 1; }
}; /* @keyframes cds--tooltip-fade */
----motion-expand: @keyframes expand {
0% { max-block-size: 0px; overflow-y: hidden; }
100% { max-block-size: 100%; }
}; /* @keyframes expand */
----motion-collapse: @keyframes collapse {
0% { max-block-size: 100vh; }
100% { max-block-size: 0px; }
}; /* @keyframes collapse */
----motion-loading-animation: @keyframes loading-animation {
0% { background-position: 0px 50%; }
50% { background-position: 100% 50%; }
100% { background-position: 0px 50%; }
}; /* @keyframes loading-animation */
----motion-sticky-header-slide-in: @keyframes sticky-header-slide-in {
0% { inset-block-start: -100%; }
100% { inset-block-start: var(--c4d-sticky-header-height); }
}; /* @keyframes sticky-header-slide-in */
----motion-loadingAnimation: @keyframes loadingAnimation {
0% { background-position: 0px 50%; }
50% { background-position: 100% 50%; }
100% { background-position: 0px 50%; }
}; /* @keyframes loadingAnimation */
----motion-spin: @keyframes spin {
0% { transform: rotate(0deg); }
100% { transform: rotate(1turn); }
}; /* @keyframes spin */
----motion-ajo-jc-skeleton-pulse: @keyframes ajo-jc-skeleton-pulse {
0% { opacity: 1; }
50% { opacity: 0.4; }
100% { opacity: 1; }
}; /* @keyframes ajo-jc-skeleton-pulse */
----motion-ajo-tc-skeleton-pulse: @keyframes ajo-tc-skeleton-pulse {
0% { opacity: 1; }
50% { opacity: 0.4; }
100% { opacity: 1; }
}; /* @keyframes ajo-tc-skeleton-pulse */
----motion-wrap-border: @keyframes wrap-border {
0% { --percentage: 0%; }
100% { --percentage: 100%; }
}; /* @keyframes wrap-border */
----motion-fp-fade-in-down: @keyframes fp-fade-in-down {
0% { opacity: 0; transform: translate3d(0px, -20px, 0px); }
100% { opacity: 1; transform: translateZ(0px); }
}; /* @keyframes fp-fade-in-down */
----motion-fp-slide-left: @keyframes fp-slide-left {
0% { transform: translateZ(0px); }
100% { transform: translate3d(-100%, 0px, 0px); }
}; /* @keyframes fp-slide-left */
----motion-fp-slide-left-new: @keyframes fp-slide-left-new {
0% { transform: translate3d(100%, 0px, 0px); }
100% { transform: translateZ(0px); }
}; /* @keyframes fp-slide-left-new */
----motion-fp-slide-right: @keyframes fp-slide-right {
0% { transform: translateZ(0px); }
100% { transform: translate3d(100%, 0px, 0px); }
}; /* @keyframes fp-slide-right */
----motion-fp-slide-right-new: @keyframes fp-slide-right-new {
0% { transform: translate3d(-100%, 0px, 0px); }
100% { transform: translateZ(0px); }
}; /* @keyframes fp-slide-right-new */
----motion-fp-fade-out: @keyframes fp-fade-out {
0% { opacity: 1; }
100% { opacity: 0; }
}; /* @keyframes fp-fade-out */
----motion-fp-fade-in: @keyframes fp-fade-in {
0% { opacity: 0; }
100% { opacity: 1; }
}; /* @keyframes fp-fade-in */
----motion-cds--rotate: @keyframes cds--rotate {
0% { transform: rotate(0deg); }
100% { transform: rotate(1turn); }
}; /* @keyframes cds--rotate */
----motion-cds--rotate-end-p1: @keyframes cds--rotate-end-p1 {
100% { transform: rotate(1turn); }
}; /* @keyframes cds--rotate-end-p1 */
----motion-cds--rotate-end-p2: @keyframes cds--rotate-end-p2 {
100% { transform: rotate(-1turn); }
}; /* @keyframes cds--rotate-end-p2 */
----motion-cds--init-stroke: @keyframes cds--init-stroke {
0% { stroke-dashoffset: 276.461; }
100% { stroke-dashoffset: 52.5276; }
}; /* @keyframes cds--init-stroke */
----motion-cds--stroke-end: @keyframes cds--stroke-end {
0% { stroke-dashoffset: 52.5276; }
100% { stroke-dashoffset: 276.461; }
}; /* @keyframes cds--stroke-end */
----motion-prefix--stroke: @keyframes prefix--stroke {
100% { stroke-dashoffset: 0; }
}; /* @keyframes prefix--stroke */
----motion-cds--progress-bar-indeterminate: @keyframes cds--progress-bar-indeterminate {
0% { background-position-x: 25%; }
80%, 100% { background-position-x: -105%; }
}; /* @keyframes cds--progress-bar-indeterminate */
----motion-cds--progress-bar-indeterminate-rtl: @keyframes cds--progress-bar-indeterminate-rtl {
0% { background-position-x: -105%; }
80%, 100% { background-position-x: 25%; }
}; /* @keyframes cds--progress-bar-indeterminate-rtl */
----motion-ai-skeleton-animation: @keyframes ai-skeleton-animation {
0% { transform: translateX(-100%); }
100% { transform: translateX(100%); }
}; /* @keyframes ai-skeleton-animation */
----motion-WACFadeIn: @keyframes WACFadeIn {
0% { opacity: 0; }
100% { opacity: 1; }
}; /* @keyframes WACFadeIn */
----motion-WACFadeInUp: @keyframes WACFadeInUp {
0% { opacity: 0; transform: translateY(32px); }
50% { transform: translateY(0px); }
100% { opacity: 1; }
}; /* @keyframes WACFadeInUp */
----motion-WACFadeOut: @keyframes WACFadeOut {
0% { opacity: 1; }
100% { opacity: 0; }
}; /* @keyframes WACFadeOut */
----motion-WACSlideInFromRight: @keyframes WACSlideInFromRight {
0% { left: 100%; }
100% { left: 0px; }
}; /* @keyframes WACSlideInFromRight */
----motion-WACSlideOutToRight: @keyframes WACSlideOutToRight {
0% { left: 0px; }
100% { left: 100%; }
}; /* @keyframes WACSlideOutToRight */
----motion-WACSlideOutToTop: @keyframes WACSlideOutToTop {
0% { top: 0px; }
100% { top: -100%; }
}; /* @keyframes WACSlideOutToTop */
----motion-WACSlideInFromLeft: @keyframes WACSlideInFromLeft {
0% { right: 100%; }
100% { right: 0px; }
}; /* @keyframes WACSlideInFromLeft */
----motion-WACSlideOutToLeft: @keyframes WACSlideOutToLeft {
0% { right: 0px; }
100% { right: 100%; }
}; /* @keyframes WACSlideOutToLeft */
----motion-WACSlideInFromBottom: @keyframes WACSlideInFromBottom {
0% { top: 100%; }
100% { top: 0px; }
}; /* @keyframes WACSlideInFromBottom */
----motion-WACSlideOutToBottom: @keyframes WACSlideOutToBottom {
0% { top: 0px; }
100% { top: 100%; }
}; /* @keyframes WACSlideOutToBottom */
----motion-WACLauncherIn: @keyframes WACLauncherIn {
0% { bottom: calc(var(--cds-chat-LAUNCHER-position-bottom) - 16px); opacity: 0; }
100% { bottom: var(--cds-chat-LAUNCHER-position-bottom); opacity: 1; }
}; /* @keyframes WACLauncherIn */
----motion-WACAnimateHeight: @keyframes WACAnimateHeight {
0% { height: var(--cds-chat-Animate-Start-Height); }
100% { height: var(--cds-chat-Animate-End-Height); }
}; /* @keyframes WACAnimateHeight */
----motion-WACFadeInUpBackButton: @keyframes WACFadeInUpBackButton {
0% { opacity: 0; transform: translate(-50%… <0.2KB elided>; /* @keyframes WACFadeInUpBackButton */
----motion-WACAnimAlternateSuggestionsContainer__Button--slide-in: @keyframes WACAnimAlternateSuggestionsContainer__Button--slide-in {
0% { bottom: -48px; }
100% { bottom: 6px; }
}; /* @keyframes WACAnimAlternateSuggestionsContainer__Button--slide-in */
----motion-WACAnimAlternateSuggestionsContainer__Button--slide-out: @keyframes WACAnimAlternateSuggestionsContainer__Button--slide-out {
0% { bottom: 0px; }
100% { bottom: -48px; }
}; /* @keyframes WACAnimAlternateSuggestionsContainer__Button--slide-out */
----motion-WACAnimAlternateSuggestionsContainer__Button--bounce-in: @keyframes WACAnimAlternateSuggestionsContainer__Button--bounce-in {
0% { bottom: 6px; }
100% { bottom: 0px; }
}; /* @keyframes WACAnimAlternateSuggestionsContainer__Button--bounce-in */
----motion-WACAnimAlternateSuggestionsOptionsPanel: @keyframes WACAnimAlternateSuggestionsOptionsPanel {
0% { top: var(--cds-chat… <0.2KB elided>; /* @keyframes WACAnimAlternateSuggestionsOptionsPanel */
----motion-WACLauncherBounce: @keyframes WACLauncherBounce {
0% { transform: translateY(0px); }
30% { tra… <0.2KB elided>; /* @keyframes WACLauncherBounce */
----motion-WACAnimLauncherComplex__FadeInSlideUp: @keyframes WACAnimLauncherComplex__FadeInSlideUp {
0% { bottom: calc(16px + v… <0.4KB elided>; /* @keyframes WACAnimLauncherComplex__FadeInSlideUp */
----motion-WACAnimLauncherComplex__FadeInText: @keyframes WACAnimLauncherComplex__FadeInText {
0% { opacity: 0; }
40% { opacity: 0; }
100% { opacity: 1; }
}; /* @keyframes WACAnimLauncherComplex__FadeInText */
----motion-WACAnimLauncherComplex__SmallLauncherResizeReposition: @keyframes WACAnimLauncherComplex__SmallLauncherResizeReposition {
0% { right… <0.4KB elided>; /* @keyframes WACAnimLauncherComplex__SmallLauncherResizeReposition */
----motion-WACAnimLauncherComplex__SmallLauncherResizeRepositionRTL: @keyframes WACAnimLauncherComplex__SmallLauncherResizeRepositionRTL {
0% { le… <0.4KB elided>; /* @keyframes WACAnimLauncherComplex__SmallLauncherResizeRepositionRTL */
----motion-WACAnimLauncherComplex__FadeInCloseButton: @keyframes WACAnimLauncherComplex__FadeInCloseButton {
0% { opacity: 0; }
80% { opacity: 0; }
100% { opacity: 1; }
}; /* @keyframes WACAnimLauncherComplex__FadeInCloseButton */
----motion-WACAnimLauncherComplex__AvatarResize: @keyframes WACAnimLauncherComplex__AvatarResize {
0% { height: 32px; width: 32px; }
100% { height: 48px; width: 48px; }
}; /* @keyframes WACAnimLauncherComplex__AvatarResize */
----motion-WACAnimLauncherComplex__FadeInSlideUpSmallExpandedLauncher: @keyframes WACAnimLauncherComplex__FadeInSlideUpSmallExpandedLauncher {
0% { bottom: -160px; opacity: 0; }
30% { opacity: 0; }
100% { bottom: -80px; opacity: 1; }
}; /* @keyframes WACAnimLauncherComplex__FadeInSlideUpSmallExpandedLauncher */
----motion-WACAnimLauncherComplex__FadeOutSlideDown: @keyframes WACAnimLauncherComplex__FadeOutSlideDown {
0% { bottom: 64px; back… <0.4KB elided>; /* @keyframes WACAnimLauncherComplex__FadeOutSlideDown */
----motion-WACAnimLauncherComplex__FadeOut: @keyframes WACAnimLauncherComplex__FadeOut {
0% { opacity: 1; }
40% { opacity: 0; }
100% { opacity: 0; }
}; /* @keyframes WACAnimLauncherComplex__FadeOut */
----motion-WACAnimLauncherComplex__SmallLauncherDefaultSizePosition: @keyframes WACAnimLauncherComplex__SmallLauncherDefaultSizePosition {
0% { ri… <0.4KB elided>; /* @keyframes WACAnimLauncherComplex__SmallLauncherDefaultSizePosition */
----motion-WACAnimLauncherComplex__SmallLauncherDefaultSizePositionRTL: @keyframes WACAnimLauncherComplex__SmallLauncherDefaultSizePositionRTL {
0% {… <0.4KB elided>; /* @keyframes WACAnimLauncherComplex__SmallLauncherDefaultSizePositionRTL */
----motion-WACLauncherIconTo32: @keyframes WACLauncherIconTo32 {
0% { width: 24px; }
100% { width: 32px; }
}; /* @keyframes WACLauncherIconTo32 */
----motion-WACLauncherIconTo24: @keyframes WACLauncherIconTo24 {
0% { width: 32px; }
100% { width: 24px; }
}; /* @keyframes WACLauncherIconTo24 */
----motion-WACLauncherPartiallyRound: @keyframes WACLauncherPartiallyRound {
0% { border-radius: 28px; }
100% { border-radius: 14px; }
}; /* @keyframes WACLauncherPartiallyRound */
----motion-WACLauncherCompletelyRound: @keyframes WACLauncherCompletelyRound {
0% { border-radius: 14px; }
100% { border-radius: 28px; }
}; /* @keyframes WACLauncherCompletelyRound */
----motion-WACLauncherExtend: @keyframes WACLauncherExtend {
0% { width: var(--cds-chat-LAUNCHER-default-size); }
100% { width: var(--cds-chat--LAUNCHER-EXTENDED-width); }
}; /* @keyframes WACLauncherExtend */
----motion-WACLauncherReduce: @keyframes WACLauncherReduce {
0% { width: var(--cds-chat--LAUNCHER-EXTENDED-width); }
100% { width: var(--cds-chat-LAUNCHER-default-size); }
}; /* @keyframes WACLauncherReduce */
----motion-WACLauncherExtendedElementFadeIn: @keyframes WACLauncherExtendedElementFadeIn {
0% { bottom: -12px; opacity: 0; }
50%, 100% { bottom: 0px; opacity: 1; }
}; /* @keyframes WACLauncherExtendedElementFadeIn */
----motion-WACLauncherExtendedElementFadeOut: @keyframes WACLauncherExtendedElementFadeOut {
0% { top: 0px; opacity: 1; }
50%, 100% { top: -12px; opacity: 0; }
}; /* @keyframes WACLauncherExtendedElementFadeOut */
----motion-swiper-preloader-spin: @keyframes swiper-preloader-spin {
0% { transform: rotate(0deg); }
100% { transform: rotate(1turn); }
}; /* @keyframes swiper-preloader-spin */
----motion-WACfadeInImg: @keyframes WACfadeInImg {
0% { opacity: 0; filter: grayscale(100%); }
100% { opacity: 1; filter: grayscale(0); }
}; /* @keyframes WACfadeInImg */
----motion-WACWidgetIn: @keyframes WACWidgetIn {
0% { bottom: calc(var(--cds-chat-BASE-bottom-position) - 32px); opacity: 0; }
100% { bottom: var(--cds-chat-BASE-bottom-position); opacity: 1; }
}; /* @keyframes WACWidgetIn */
----motion-WACWidgetOut: @keyframes WACWidgetOut {
0% { opacity: 1; }
100% { opacity: 0; }
}; /* @keyframes WACWidgetOut */
----motion-WACAnimBackgroundCover: @keyframes WACAnimBackgroundCover {
0% { opacity: 0; }
100% { opacity: 0.5; }
}; /* @keyframes WACAnimBackgroundCover */
----motion-WACLoadingBar__ConnectingAnimationKeyFrames: @keyframes WACLoadingBar__ConnectingAnimationKeyFrames {
0% { background-position: 0px 0px; }
100% { background-position: -200% 0px; }
}; /* @keyframes WACLoadingBar__ConnectingAnimationKeyFrames */
----motion-WACMessageIn: @keyframes WACMessageIn {
0% { opacity: 0; }
100% { opacity: 1; }
}; /* @keyframes WACMessageIn */
----motion-spin-flow-status: @keyframes spin-flow-status {
0% { transform: rotate(0deg); }
100% { transform: rotate(1turn); }
}; /* @keyframes spin-flow-status */
----motion-c-inline-spinner-kf: @keyframes c-inline-spinner-kf {
0% { transform: rotate(0deg); }
100% { transform: rotate(1turn); }
}; /* @keyframes c-inline-spinner-kf */
----motion-shimmer: @keyframes shimmer {
0% { stroke: var(--cds-layer-accent-01,#e0e0e0); }
20% { stroke: rgb(255, 255, 255); opacity: 0.5; }
100% { stroke: var(--cds-layer-accent-01,#e0e0e0); }
}; /* @keyframes shimmer */
--duration-fast: 0.07s; /* 52 elements — e.g. button, button, button /* mined from computed styles */ */
--ease-default: ease; /* 219 elements — e.g. button, button, button /* mined from computed styles */ */
```
## Appendix B: Token Source Metadata
```
tokenSource: extracted-css-vars
site: ibm.com
extractionDate: [TBD]
confidence: medium
cssVarsFound: 19 custom properties in :root / computed styles
curatedTokens: 24 tokens mapped to --ibm-* prefix
librariesDetected: IBM Carbon Design System (cds--* classes), Bootstrap (overlap)
fontFiles: IBM Plex Sans (300/400/600 normal+italic), IBM Plex Mono (300/400/600),
IBM Plex Serif (300/400/600 via Watson widget), ibm_icons (icon font)
```
**Confidence notes:**
- `--ibm-accent: rgb(15, 98, 254)` — **high confidence** (extracted from `--brand-primary-cta`, confirmed on 2+ button computed styles and h3 color)
- Font size/weight tokens — **high confidence** (extracted from multiple element computed styles with element counts)
- `--ibm-space-md/lg/xl` — **high confidence** (appear in heading margins, component padding, dropdown margins)
- `--ibm-radius-sm: 0px 8px 0px 0px` and `--ibm-radius-lg: 8px 0px 0px` — **low confidence for brand use** (found only on `cds--btn--icon-only` elements; likely Carbon internal; NEVER use for standard buttons)
- `--ibm-radius-full: 28px` — **low confidence for brand use** (found only on Watson chat launcher widget, not IBM brand UI)
- `--ibm-space-2xl: 999999999px` — **excluded as artifact** (maps to `--cds-layout-density-padding-inline-max`, a Carbon sentinel value, not a real spacing token)
- Colour tokens beyond `--ibm-accent` — **medium confidence** (synthesised from button hover/active CSS rules which reference Carbon fallback values)
- Section layout (Section 5) — **inferred** (no screenshots; derived from component inventory counts: 143 cards, 53 buttons, 54 content instances, computed style layout properties)
**Clustering method for synthesised tokens:**
Spacing values clustered into 8px grid multiples: 8px (condensed density), 16px (normal density), 24px, 32px, 48px. Values of `1px` and `999999999px` excluded as off-grid artifacts. Colour values clustered by hue family (IBM Blue at #0f62fe with hover/active variants at -10E/#0050e6 and -20E/#002d9c).More from the gallery
Browse all kits →You may also like

Contra
MITPlayful yet professional design system with teal and purple accents, bold typography, and vibrant accent surfaces—built for modern SaaS platforms and landing pages
03
lightboldsaaslanding-page

DoorDash
MITClean, accessible food-delivery system with DoorDash's signature red accent, light neutral palette, and system-font typography—built for rapid product development
03
lightecommsaasmobile

Wise
MITClean, accessible financial design system with lime-green accents and Swiss typography, built for fintech products that prioritise clarity and trust
05
lightfintechminimalsaas