# Multibrand Design System

> Creates a complete, WCAG-checked multibrand design system directly in a Figma file — a four-tier token architecture (Base → Typography → Alias → Map) with all variables, 25 text styles, and 12 effect styles (8 directional drop shadows + 4 background blurs), built through the Figma MCP connection. Use this skill whenever the user wants to create a Figma design system, generate Figma variables or design tokens, set up a multibrand or themeable token system, or build design-system foundations for a new brand or project. Gathers brand config, shows a color preview for approval, then creates everything directly in Figma — no JSON file, no plugin needed.

- Skill: `ravindu997/multibrand-design-system` (Agent Skill, multi-file: 4 files)
- Install (CLI): `npx skillmds@latest add ravindu997/multibrand-design-system`
- Raw SKILL.md: https://api.skillmd.com/api/skills/ravindu997/multibrand-design-system/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Design & Media
- Author: Ravindu997 (https://skillmd.com/u/ravindu997)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/ravindu997/multibrand-design-system

---


# Multibrand Design System for Figma

Creates a complete four-tier design system directly in the user's Figma file
using the Figma MCP connection. No JSON file. No plugin. Everything appears
in Figma's variable panel and Styles panel automatically.

---

## Step 0 — Check the Figma connection

Before anything else, confirm you can write to the user's Figma file.

**Preferred path — Figma Console MCP Desktop Bridge** (works on any Figma plan,
and is the path this skill is written for). Check it with
`figma_get_status({ probe: true })`, then `figma_list_open_files` to confirm
which file is the active target. Every create/update step below runs through
`figma_execute` (raw Plugin API) or `figma_batch_create_variables`.

⚠ Under `documentAccess: dynamic-page` the synchronous Plugin API getters throw.
Always use the async forms inside `figma_execute`:
`getLocalVariablesAsync`, `getLocalVariableCollectionsAsync`,
`getVariableByIdAsync`, `getLocalEffectStylesAsync`, `getLocalTextStylesAsync`.

**Fallback — official Figma MCP** (`https://mcp.figma.com/mcp`) is read-oriented
(`get_variable_defs`, `get_design_context`) and cannot create variables. Use it
for inspection only; it is not sufficient for this skill.

**If neither is connected**, tell the user:

```
To create your design system directly in Figma, I need a write connection
to your Figma file. Here's how to set it up:

1. Install the Figma Console MCP server and open its Desktop Bridge plugin
   inside the Figma file you want to build in
2. Confirm the bridge is live — the plugin window shows the connected
   file name and port
3. Come back and run this skill again

The official Figma MCP (https://mcp.figma.com/mcp) can read a file but
cannot create variables, so it won't work for this on its own.

Alternative (no MCP): I can generate a JSON file instead that you import
via the "Variables Import/Export" Figma plugin
(https://www.figma.com/community/plugin/1253571037276775).
Just say "use JSON instead" and I'll switch to that approach.
```

Stop here until the user either connects MCP or asks for the JSON fallback.
If they ask for JSON fallback, jump to → APPENDIX: JSON Fallback.

---

## Step 1 — Gather brand configuration

Ask the user for all of the following in a single message:

```
To set up your design system, I need a few details:

1. Brand color   (default: Emerald) — your primary brand color
2. Accent color  (default: Violet)  — secondary highlight color
3. Neutral color (default: Gray)    — surfaces, borders, text
4. Success color (default: Green)
5. Warning color (default: Amber)
6. Error color   (default: Red)
7. Info color    (default: Blue)

Available Tailwind v4 hues:
  Gray · Slate · Red · Rose · Orange · Amber · Yellow · Lime ·
  Green · Emerald · Teal · Cyan · Sky · Blue · Indigo · Violet ·
  Purple · Fuchsia · Pink

8. Body font family  (default: Inter)       — used for body text styles
9. Heading font      (default: Roboto Mono) — used for h1–h6 styles
10. Project name     (e.g. "acme-corp")
```

If the user has already specified any of these in the conversation, use
those values and only ask for what's missing.

---

## Step 2 — Show color preview and get approval

Once you have the config, show a visual approval card BEFORE creating anything.

Generate an inline color preview using HTML/SVG in your response. For each
configured role show:
  - A filled color swatch (use the scale/500 hex for the chosen hue)
  - The role name (Brand, Accent, etc.)
  - The Tailwind hue name
  - The exact hex value at scale 500

Use the Tailwind v4 hex values from this reference table (scale 500):

```
Gray    #71717a    Slate   #64748b    Red     #ef4444    Rose    #f43f5e
Orange  #f97316    Amber   #f59e0b    Yellow  #eab308    Lime    #84cc16
Green   #22c55e    Emerald #10b981    Teal    #14b8a6    Cyan    #06b6d4
Sky     #0ea5e9    Blue    #3b82f6    Indigo  #6366f1    Violet  #8b5cf6
Purple  #a855f7    Fuchsia #d946ef    Pink    #ec4899
```

Then show the typography config:
  - Body font: [font name] — used for body xs through body lg styles
  - Heading font: [mono font name] — used for h1 through h6 styles

Then ask:

```
Does this look right? Reply "yes" to create the design system, or tell me
what to change (e.g. "change Brand to Blue" or "use DM Sans for headings").
```

**Do not create anything in Figma until the user approves.**

---

## Step 3 — Create variables in Figma via MCP

Once approved, create all four variable collections through the Desktop
Bridge. Tell the user: "Creating your design system in Figma now..."

Use `figma_batch_create_variables` for bulk creation, or `figma_execute` with
`figma.variables.createVariableCollection()` /
`figma.variables.createVariable()` when you need alias wiring in the same pass.
Create collections in tier order (Base → Typography → Alias → Map) so that
alias targets always exist before the variables that reference them.

### Collection 1 — Base (mode: Value)

**Colors** — grouped under `Colours/`, all 19 Tailwind v4 hues, each with
11 scales (50→950): `Colours/Gray/50` … `Colours/Pink/950` for
Gray, Slate, Red, Rose, Orange, Amber, Yellow, Lime, Green, Emerald,
Teal, Cyan, Sky, Blue, Indigo, Violet, Purple, Fuchsia, Pink
(Use the full hex table in references/architecture.md)

**Note**: There is NO alpha ramp in Base. Translucent alpha washes live in
the Alias collection (`Alpha/light mode/*` and `Alpha/dark mode/*` — see
Collection 3), because they are DERIVED from the user's chosen Neutral hue
(50 and 950 endpoints) and need separate light and dark variants.

**Spacing** — FLOAT variables, a compact Tailwind-style spacing scale
(replaces the old dense `size/*` linear scale). Includes two negative
values for inset/overlap use cases:
```
Spacing/-4   Spacing/-2   Spacing/0   Spacing/1   Spacing/2
Spacing/4    Spacing/6    Spacing/8   Spacing/12  Spacing/16
Spacing/20   Spacing/24   Spacing/32  Spacing/40  Spacing/48
Spacing/56   Spacing/64   Spacing/80  Spacing/120
```

**Radius** — FLOAT variables:
radius/none(0) · radius/xs(2) · radius/sm(4) · radius/md(6) ·
radius/lg(8) · radius/xl(12) · radius/2xl(16) · radius/3xl(24) ·
radius/full(9999)

### Collection 2 — Typography (mode: Value)

```
family/Body     STRING  → user's body font (e.g. "Inter")
family/Title    STRING  → user's heading font (e.g. "Roboto Mono")

weight/regular  FLOAT   → 400
weight/medium   FLOAT   → 500
weight/semibold FLOAT   → 600
weight/bold     FLOAT   → 700

size/body xs    FLOAT   → 10
size/body sm    FLOAT   → 12
size/body md    FLOAT   → 14
size/body rg    FLOAT   → 16
size/body lg    FLOAT   → 18
size/h6         FLOAT   → 20
size/h5         FLOAT   → 24
size/h4         FLOAT   → 32
size/h3         FLOAT   → 40
size/h2         FLOAT   → 56
size/h1         FLOAT   → 64

lh/body xs      FLOAT   → 16
lh/body sm      FLOAT   → 18
lh/body md      FLOAT   → 22
lh/body rg      FLOAT   → 24
lh/body lg      FLOAT   → 28
lh/h6           FLOAT   → 32
lh/h5           FLOAT   → 28
lh/h4           FLOAT   → 38
lh/h3           FLOAT   → 44
lh/h2           FLOAT   → 64
lh/h1           FLOAT   → 72

ls/tight        FLOAT   → -0.5
ls/normal       FLOAT   → 0
ls/relaxed      FLOAT   → 0.5
ls/loose        FLOAT   → 1

style/normal    STRING  → "normal"
style/italic    STRING  → "italic"
```

### Collection 3 — Alias (mode: Theme 1 (Default))

Each role maps the full 50→950 scale to the user's chosen Base hue.
Every value is an alias reference to Base, e.g.:
  Brand/500 → alias to Base / [chosen hue] / 500

Roles: Brand · Accent · Neutral · Success · Warning · Error · Info

Chart series (alias to specific Base scale steps):
```
Chart/series-1/light mode → Base / Blue / 500
Chart/series-1/dark mode  → Base / Blue / 400
Chart/series-2/light mode → Base / Amber / 400
Chart/series-2/dark mode  → Base / Amber / 300
Chart/series-3/light mode → Base / Rose / 600
Chart/series-3/dark mode  → Base / Rose / 400
Chart/series-4/light mode → Base / Teal / 400
Chart/series-4/dark mode  → Base / Teal / 300
Chart/series-5/light mode → Base / Violet / 700
Chart/series-5/dark mode  → Base / Violet / 400
```

Alpha washes — **derived from the user's Neutral role, not hardcoded**.

The derivation rule:
- `Alpha/light mode/*` takes the RGB of the user's chosen Neutral hue at
  scale **50** (i.e. whatever `Neutral/50` resolves to) and lowers only
  the opacity per step: 10%, 20%, 40%, 60%, 80%.
- `Alpha/dark mode/*` takes the RGB of the chosen Neutral hue at scale
  **950** (whatever `Neutral/950` resolves to) and applies the same
  opacity steps.

So if the user picks Gray as Neutral the washes are built on `#f9fafb` /
`#030712`; if they pick Slate they're built on `#f8fafc` / `#020617` —
always recompute from the configured Neutral hue's 50 and 950 hex values.

These are stored as raw COLOR values with translucency (NOT aliases) —
Figma variables cannot apply an opacity modifier on top of an aliased
color, so the RGB is baked in at creation time:
```
Alpha/light mode/100  → rgba([Neutral hue]/50, 10%)
Alpha/light mode/200  → rgba([Neutral hue]/50, 20%)
Alpha/light mode/400  → rgba([Neutral hue]/50, 40%)
Alpha/light mode/600  → rgba([Neutral hue]/50, 60%)
Alpha/light mode/800  → rgba([Neutral hue]/50, 80%)

Alpha/dark mode/100   → rgba([Neutral hue]/950, 10%)
Alpha/dark mode/200   → rgba([Neutral hue]/950, 20%)
Alpha/dark mode/400   → rgba([Neutral hue]/950, 40%)
Alpha/dark mode/600   → rgba([Neutral hue]/950, 60%)
Alpha/dark mode/800   → rgba([Neutral hue]/950, 80%)
```

Drop shadow tokens — TWO directional groups, `Down` (↓, positive Y) and
`Up` (↑, negative Y). X/Y/Blur/Spread are raw FLOATs; Color aliases to the
Alias `Alpha/dark mode` washes (shadows are always dark, in both themes).
sm/md/lg use the 20% wash; xl uses the deeper 40% wash. This is what
Step 5 binds the effect styles to:
```
Drop shadow/Down/sm ↓/X        FLOAT → 0
Drop shadow/Down/sm ↓/Y        FLOAT → 8
Drop shadow/Down/sm ↓/Blur     FLOAT → 8
Drop shadow/Down/sm ↓/Spread   FLOAT → -6
Drop shadow/Down/sm ↓/Color    COLOR → alias to Alias / Alpha/dark mode/200

Drop shadow/Down/md ↓/X        FLOAT → 0
Drop shadow/Down/md ↓/Y        FLOAT → 8
Drop shadow/Down/md ↓/Blur     FLOAT → 16
Drop shadow/Down/md ↓/Spread   FLOAT → -6
Drop shadow/Down/md ↓/Color    COLOR → alias to Alias / Alpha/dark mode/200

Drop shadow/Down/lg ↓/X        FLOAT → 0
Drop shadow/Down/lg ↓/Y        FLOAT → 8
Drop shadow/Down/lg ↓/Blur     FLOAT → 32
Drop shadow/Down/lg ↓/Spread   FLOAT → -6
Drop shadow/Down/lg ↓/Color    COLOR → alias to Alias / Alpha/dark mode/200

Drop shadow/Down/xl ↓/X        FLOAT → 0
Drop shadow/Down/xl ↓/Y        FLOAT → 8
Drop shadow/Down/xl ↓/Blur     FLOAT → 48
Drop shadow/Down/xl ↓/Spread   FLOAT → -12
Drop shadow/Down/xl ↓/Color    COLOR → alias to Alias / Alpha/dark mode/400

Drop shadow/Up/{size} ↑/*      — identical to the Down group, except
                                 Y → -8 for every size. Same Blur/Spread/
                                 Color per size (xl color → dark mode/400).
```

Background blur tokens (raw FLOATs — bound to the BACKGROUND_BLUR effect
styles in Step 5):
```
Background blur/sm   FLOAT → 5
Background blur/md   FLOAT → 10
Background blur/lg   FLOAT → 30
Background blur/xl   FLOAT → 100
```

### Collection 4 — Map (modes: Light · Dark)

All tokens alias to Alias collection. Full slot tables in
references/architecture.md. Summary:

**Background** — Neutral (13 slots incl. quartiary), brand-like (11 slots)
  ⚠ Light-mode `primary` / `primary hover` / `pressed` are set PER HUE from
  measured contrast, not one global step (see Scale conventions below):
    Brand   700 → 800 → 900   (pale ink)
    Error   700 → 800 → 900   (pale ink)
    Accent  600 → 700 → 800   (pale ink)
    Info    600 → 700 → 800   (pale ink)
    Success 500 → 400 → 300   (dark ink)
    Warning 500 → 400 → 300   (dark ink)
  Dark-mode for every brand-like role: 400 → 300 → 200 (dark ink).
  Brand-like `tertiary` = deep surface (900 L / 100 D); `inverse` = palest
  tint (50 L / 950 D).
**Text** — Neutral + brand-like (8 slots each)
  Brand-like `primary` = 700 L / 400 D (700 is the lightest step that clears
  4.5:1 against the neutral surface for all six roles).
  Brand-like `tertiary` = 950 L / 50 D (max-contrast tinted ink);
  `inverse` = 50 L / 950 D.
**Border** — Neutral + brand-like (7 slots each)
**Icon** — mirrors Text exactly
**Chart** — 5 series, each with Light → Alias/Chart/series-N/light mode
                              Dark  → Alias/Chart/series-N/dark mode
**Overlay** — 5 scrim steps aliasing the mode-appropriate Alpha wash:
```
Overlay/sm    Light → Alias/Alpha/light mode/100   Dark → Alias/Alpha/dark mode/100
Overlay/md    Light → Alias/Alpha/light mode/200   Dark → Alias/Alpha/dark mode/200
Overlay/lg    Light → Alias/Alpha/light mode/400   Dark → Alias/Alpha/dark mode/400
Overlay/xl    Light → Alias/Alpha/light mode/600   Dark → Alias/Alpha/dark mode/600
Overlay/xxl   Light → Alias/Alpha/light mode/800   Dark → Alias/Alpha/dark mode/800
```

---

## Step 4 — Create text styles in Figma via MCP

After all variables are created, create the 25 text styles via `figma_execute`
using `figma.createTextStyle()`. Load each font with
`await figma.loadFontAsync({ family, style })` before assigning it, then bind
each property with `style.setBoundVariable(field, variable)`.

**Critical**: Every property must be bound to the Typography variable
we just created — including fontWeight. Do NOT hardcode any values.

### Variable binding for each property:
```
fontFamily    → 2. Typography / family/Body    (body styles)
              → 2. Typography / family/Title   (heading styles)
fontSize      → 2. Typography / size/[token]
fontWeight    → 2. Typography / weight/[token]   ← MUST be a variable ref
lineHeight    → 2. Typography / lh/[token]
letterSpacing → 2. Typography / ls/[token]
```

### The 25 text styles:

Body styles (fontFamily → family/Body, letterSpacing → ls/relaxed):
```
Name          size token    weight token       lh token
body xs       size/body xs  weight/regular     lh/body xs
body xs-M     size/body xs  weight/medium      lh/body xs
body sm       size/body sm  weight/regular     lh/body sm
body sm-M     size/body sm  weight/medium      lh/body sm
body md       size/body md  weight/regular     lh/body md
body md-M     size/body md  weight/medium      lh/body md
body md-SB    size/body md  weight/semibold    lh/body md
body rg       size/body rg  weight/regular     lh/body rg
body rg-M     size/body rg  weight/medium      lh/body rg
body rg-SB    size/body rg  weight/semibold    lh/body rg
body lg       size/body lg  weight/regular     lh/body lg
body lg-M     size/body lg  weight/medium      lh/body lg
body lg-SB    size/body lg  weight/semibold    lh/body lg
```

Heading styles (fontFamily → family/Title):
```
Name    size token  weight token     lh token   ls token
h6      size/h6     weight/medium    lh/h6      ls/normal
h6-SB   size/h6     weight/semibold  lh/h6      ls/normal
h5      size/h5     weight/medium    lh/h5      ls/normal
h5-SB   size/h5     weight/semibold  lh/h5      ls/normal
h4      size/h4     weight/medium    lh/h4      ls/tight
h4-SB   size/h4     weight/semibold  lh/h4      ls/tight
h3      size/h3     weight/medium    lh/h3      ls/tight
h3-B    size/h3     weight/bold      lh/h3      ls/tight
h2      size/h2     weight/medium    lh/h2      ls/tight
h2-B    size/h2     weight/bold      lh/h2      ls/tight
h1      size/h1     weight/medium    lh/h1      ls/tight
h1-B    size/h1     weight/bold      lh/h1      ls/tight
```

---

## Step 5 — Create effect styles via MCP (12 total)

After the Alias `Drop shadow` and `Background blur` variables exist,
create 12 EFFECT styles. Every numeric/color property must be bound to a
variable — never hardcoded.

### 8 drop shadow styles (DROP_SHADOW type)

Named with a direction group and arrow suffix:
```
Drop shadow/sm ↓   Drop shadow/md ↓   Drop shadow/lg ↓   Drop shadow/xl ↓
Drop shadow/sm ↑   Drop shadow/md ↑   Drop shadow/lg ↑   Drop shadow/xl ↑
```

**Binding pattern** — every field binds to the matching Alias-tier token
for that direction and size (the color binds THROUGH the Alias
`Drop shadow/.../Color` token, which itself aliases `Alpha/dark mode/200`
or `/400` — do NOT bind color straight to a raw alpha variable):

```
color    → Alias / Drop shadow/{Down|Up}/{size} {↓|↑}/Color
offsetX  → Alias / Drop shadow/{Down|Up}/{size} {↓|↑}/X
offsetY  → Alias / Drop shadow/{Down|Up}/{size} {↓|↑}/Y
radius   → Alias / Drop shadow/{Down|Up}/{size} {↓|↑}/Blur   (Figma's
           effect field name for blur is "radius")
spread   → Alias / Drop shadow/{Down|Up}/{size} {↓|↑}/Spread
```

⚠ Down styles must bind ONLY to `Drop shadow/Down/...` tokens and Up
styles ONLY to `Drop shadow/Up/...` tokens — never mix directions across
the five fields of one style.

Use the Plugin API's `figma.variables.setBoundVariableForEffect(effect, field, variable)`
— it returns a new effect object per call, so reassign after each bind:

```js
let effect = {
  type: 'DROP_SHADOW',
  color: { r, g, b, a },   // seed values only; overwritten by the bound variable
  offset: { x: 0, y: 8 },  // y: -8 for Up styles
  radius: 8,
  spread: -6,
  visible: true,
  blendMode: 'NORMAL'
};
effect = figma.variables.setBoundVariableForEffect(effect, 'color', colorVar);
effect = figma.variables.setBoundVariableForEffect(effect, 'offsetX', xVar);
effect = figma.variables.setBoundVariableForEffect(effect, 'offsetY', yVar);
effect = figma.variables.setBoundVariableForEffect(effect, 'radius', blurVar);
effect = figma.variables.setBoundVariableForEffect(effect, 'spread', spreadVar);

const style = figma.createEffectStyle();
style.name = 'Drop shadow/sm ↓'; // etc.
style.effects = [effect];
```

Seed values per size (used only as the initial unbound value — the bound
variable drives the real value). offset.x is 0 for all sizes; offset.y is
+8 for ↓ styles and -8 for ↑ styles:

| Style | radius (blur) | spread | color alpha |
|---|---|---|---|
| sm | 8  | -6  | 20% |
| md | 16 | -6  | 20% |
| lg | 32 | -6  | 20% |
| xl | 48 | -12 | 40% |

### 4 background blur styles (BACKGROUND_BLUR type)

Named `Background blur/sm`, `Background blur/md`, `Background blur/lg`,
`Background blur/xl`. Single effect each; the radius binds to the Alias
`Background blur/{size}` token:

```js
let effect = {
  type: 'BACKGROUND_BLUR',
  radius: 5,        // seed only — 5/10/30/100 per size
  visible: true
};
effect = figma.variables.setBoundVariableForEffect(effect, 'radius', blurVar);

const style = figma.createEffectStyle();
style.name = 'Background blur/sm'; // etc.
style.effects = [effect];
```

---

## Step 6 — Confirm completion

Once everything is created, tell the user:

```
✅ Your design system is ready in Figma!

Created:
  • 4 variable collections (~662 variables)
    - 1. Base     — Colours/ (19 hues × 11 scales) + Spacing + radius
    - 2. Typography — font, weight, size, line-height, spacing, style
    - 3. Alias    — semantic roles (Brand → [hue], Accent → [hue], etc.)
                    + Alpha washes (light/dark) + Drop shadow (Down ↓ / Up ↑)
                    + Background blur tokens
    - 4. Map      — light/dark UI tokens for Background, Text, Border, Icon,
                    Chart, Overlay
  • 25 text styles — body xs through h1-B, all properties bound to variables
  • 12 effect styles — 8 drop shadows (sm–xl, ↓ and ↑) + 4 background blurs,
    all properties bound to variables

Open Figma's Variables panel (right-click canvas → Edit Variables) to see
all four collections. Text styles and effect styles appear in the Styles panel.
```

---

## What the system contains

### Collections and modes
| Collection    | Mode(s)              | Purpose                           |
|---------------|----------------------|-----------------------------------|
| 1. Base       | Value (1 mode)       | Raw Tailwind v4 primitives        |
| 2. Typography | Value (1 mode)       | Raw text primitives               |
| 3. Alias      | Theme 1 (Default)    | Semantic role → Base hue mapping  |
| 4. Map        | Light + Dark         | UI token → Alias resolution       |

### Scale conventions (contrast-measured against WCAG AA 4.5:1)

Every hue ramp has a **dead zone** — the step where the pale ink and the dark
ink both fall below 4.5:1. It sits at the ink crossover and moves per hue:

| Role | Hue | Dead zone |
|---|---|---|
| Brand | Emerald | 600 |
| Accent | Violet | 500 |
| Error | Red | 500–600 |
| Info | Blue | 500 |
| Success | Green | none |
| Warning | Amber | none |

Success and Warning have no dead zone: they are high-luminance hues, so the
crossover lands where both inks still clear 4.5:1. That is why they can sit at
500 with dark ink and still measure best in the set.

Because the dead zone moves, light-mode filled surfaces are set per hue rather
than on one global step:

- Background brand-like primary (light): Brand 700 · Error 700 · Accent 600 ·
  Info 600 with pale ink; Success 500 · Warning 500 with dark ink
- Background brand-like hover/pressed (light): pale-ink roles step one and two
  darker; dark-ink roles step lighter (400 / 300) to keep dark ink legible
- Background brand-like (dark): 400 → hover 300 → pressed 200, dark ink
  (hover must NOT be 500 — that is inside the Accent and Info dead zone)
- Text/Icon neutral primary: 950 light / 50 dark
- Text/Icon brand-like primary: 700 light / 400 dark — uniform, since 700 is
  the lightest step clearing 4.5:1 on the neutral surface for all six roles
- Text/Icon brand-like tertiary: 950 light / 50 dark; inverse: 50 light / 950 dark
- Chart colors: colorblind-safe (deuteranopia validated)

Measured worst cases across 36 surface states + 12 colored-text pairings:
Info light primary **4.75:1**, Success light text **4.80:1**. Zero failures.

⚠ Filled surfaces do not all take the same ink token. Pale-ink roles
(Brand/Accent/Error/Info) pair with `Text/{role}/inverse`; dark-ink roles
(Success/Warning) pair with `Text/{role}/tertiary`.

### Effect styles
Drop shadows come in two directions: ↓ (default, elevation below) and
↑ (shadow cast upward — bottom sheets, docked toolbars, footers).

| Size | Purpose | Blur | Spread | Color alpha |
|---|---|---|---|---|
| sm | subtle elevation (cards, chips) | 8  | -6  | 20% |
| md | default elevation (dropdowns, popovers) | 16 | -6  | 20% |
| lg | high elevation (modals) | 32 | -6  | 20% |
| xl | maximum elevation (dialogs, spotlights) | 48 | -12 | 40% |

Background blurs (glassmorphism / frosted panels):

| Style | Radius |
|---|---|
| Background blur/sm | 5 |
| Background blur/md | 10 |
| Background blur/lg | 30 |
| Background blur/xl | 100 |

For full slot-level details → references/architecture.md

---

## APPENDIX: JSON Fallback

If the user doesn't have Figma MCP, fall back to the generator script:

```bash
node [skill-dir]/scripts/generate.js \
  --brand Emerald --accent Violet --neutral Gray \
  --success Green --warning Amber --error Red --info Blue \
  --font "Inter" --mono "Roboto Mono" \
  --name "project-name" --out ./
```

Then import with the Variables Import/Export plugin:
https://www.figma.com/community/plugin/1253571037276775

**Note on font weight in JSON fallback**: Figma's REST API does not support
binding fontWeight to a variable reference in text styles. The weight is
stored as a variable ref in the JSON, and the plugin will resolve it to the
numeric value (400/500/600/700) on import. The variable itself (weight/regular
etc.) exists in the Typography collection and can be used for variable bindings
in components — it just can't drive text style fontWeight directly.

