Design System — Onboarding + Shared Brand Tokens
Captures the user's brand identity once via a 10-question onboarding wizard (primary/accent HEX + heading + body Google Fonts + design style editorial/technical/minimal/playful + default output directory + syntax theme + TOC behavior + optional logo/company), validates body-text and link contrast against WCAG 2.2 AA, derives 12 CSS custom properties in HSL space, and stores the result for every markdown-html converter to consume.
How to use it
Claude Code
- Run the line below. It pulls the whole folder into
~/.claude/skills/design-system, including the files SKILL.md points to. - Describe your job in plain words. Claude Code follows the skill from there.
npx degit alirezarezvani/claude-skills/markdown-html/skills/design-system#main ~/.claude/skills/design-systemFor one project only, change the path to .claude/skills/design-system. This skill also uses config_loader.py, onboard.py, brand_palette_validator.py, output_path_resolver.py — copying SKILL.md alone won't be enough. See the folder on GitHub.
Claude (web or desktop app)
- On this page open ⋯ → Download .md.
- Save it as SKILL.md in a folder, zip the folder, then Customize → Skills → + → Create skill → Upload a skill.
- Pick the file and Save. Claude shows the name and description and runs a security scan.
- Check the skill is switched on.
- Start a new chat and describe your job in plain words. The AI follows the skill from there.
ChatGPT or another app
- ChatGPT: make a Project and paste it into Instructions.
- Neither? Paste it at the top of a new chat — it works for that chat.
Not working?
- Check which app you pasted it into — the steps above name the right one.
- Some skills need the paid tier of Claude or ChatGPT.
Paste into Claude, ChatGPT or Cursor.
Source of Design System — Onboarding + Shared Brand Tokens
Show the full text157 lines
| name | description | version | author | license | tags | compatible_tools |
|---|---|---|---|---|---|---|
| design-system | Captures the user's brand identity once via a 10-question onboarding wizard (primary/accent HEX + heading + body Google Fonts + design style editorial/technical/minimal/playful + default output directory + syntax theme + TOC behavior + optional logo/company), validates body-text and link contrast against WCAG 2.2 AA, derives 12 CSS custom properties in HSL space, and stores the result for every markdown-html converter to consume. Use before any markdown-html conversion. Triggers on first-run onboarding ("set up the brand", "configure markdown-html", "run onboarding"), on explicit reset ("reset the design system", "re-onboard"), and is checked by every converter via config_loader.py before rendering. Refuses to save if body-text contrast fails AA 4.5:1 or the output dir isn't writable. Precedence is project (./.markdown-html/) > global (~/.config/markdown-html/) > built-in defaults; MARKDOWN_HTML_NO_CONFIG=1 bypasses. | 2.10.0 | Alireza Rezvani | MIT | [design-system, brand-palette, wcag, onboarding, customization, markdown-html, css-variables, typography] | [claude-code, codex-cli, cursor, antigravity, opencode, gemini-cli] |
Design System — Onboarding + Shared Brand Tokens
The design-system skill is the shared brand owner for the markdown-html plugin. Run its onboarding once. Every converter (md-document, md-review, md-slides) reads the resulting config via config_loader.py and applies the same 12 CSS custom properties to its output. Without this, conversions render with placeholder defaults — technically functional but unbranded.
This skill ships exactly three Python tools:
onboard.py— interactive (or--defaults/--set/--show/--reset) wizard.config_loader.py— importable customization loader with project > global > defaults precedence andMARKDOWN_HTML_NO_CONFIG=1bypass.brand_palette_validator.py— WCAG-AA contrast checker + HSL palette deriver.
All three are stdlib-only and contain no LLM calls (deterministic per Path-B discipline).
When to invoke
| Symptom | Action |
|---|---|
| User says "convert this markdown to HTML" for the first time in this workspace | Run python3 markdown-html/skills/design-system/scripts/onboard.py |
~/.config/markdown-html/design-system.json doesn't exist OR setup_completed_at is null |
Refuse conversion, surface onboarding |
| User wants per-repo brand override | python3 .../onboard.py --scope project |
| User wants to change a single field non-interactively | python3 .../onboard.py --set brand.primary=#FF6B35 |
| User wants to reset and re-onboard | python3 .../onboard.py --reset then re-run |
| User wants zero-touch defaults (CI, ephemeral session) | python3 .../onboard.py --defaults |
| Headless / containerized run that should ignore saved config | MARKDOWN_HTML_NO_CONFIG=1 ... |
Onboarding question set (10 questions)
| # | Key | Choices / Validator | Default |
|---|---|---|---|
| 1 | default_output_dir |
path; os.access(parent, os.W_OK) |
./markdown-html-out/ |
| 2 | brand.primary |
HEX ^#?[0-9a-fA-F]{6}$ |
#0A1628 |
| 3 | brand.accent |
HEX or blank (auto-derive) | derive from primary |
| 4 | typography.heading_font |
Google Font name (12 safe defaults) | Inter |
| 5 | typography.body_font |
Google Font name | Inter |
| 6 | design_style |
editorial / technical / minimal / playful |
technical |
| 7 | code_theme |
light / dark / auto |
auto |
| 8 | toc.behavior |
sticky-sidebar / collapsible-top / inline / none |
sticky-sidebar |
| 9 | company_name |
string (may be empty) | "" |
| 10 | logo_url |
URL or empty (base64-embedded at render) | "" |
Hard rules
- WCAG AA body-text contrast must pass.
brand_palette_validator.validate()runs after every change. Body text on bg must reach 4.5:1; link on bg must reach 4.5:1. If either fails,onboard.pyrefuses to save (exit code 4) and tells the user to pick a darker primary, blankbrand.bg/brand.textto let derivation pick a safe pair, or overridebrand.textdirectly. Canon: WCAG 2.2 §1.4.3. - Output directory must be writable.
onboard.pywalks up the path to find an existing ancestor and checksos.W_OK. Empty or unwritable path → exit code 3. The orchestrator'soutput_path_resolver.pyhonors the same rule per-conversion. - Customization must change behavior, not sit as decoration. Every consumer (md-document, md-review, md-slides) must read the config and render differently when the user changes
design_style,brand.primary,code_theme, ortoc.behavior. Decorative-only fields fail the design discipline. - Precedence is fixed. Project > global > defaults. The deep-merge preserves nested keys (e.g. you can override
brand.primaryin a project config without losingtypography.heading_fontfrom global). - Bypass env exists for a reason.
MARKDOWN_HTML_NO_CONFIG=1is for headless CI, ephemeral test containers, and the autoresearch-style evaluator loops. Never set it silently for an interactive user.
Derived 12-token palette
Once the user's brand is captured, brand_palette_validator.derive_palette() produces 12 CSS custom properties stored under derived_palette in the same config file. Every converter inlines these into its <style> block.
| Token | Purpose | Derivation |
|---|---|---|
--md-bg |
Document background | Primary if dark, near-neutral if vibrant |
--md-surface |
Card / callout / blockquote background | Bg ± 4-6% luminance |
--md-border |
Hairline dividers, table borders | Bg ± 8-12% luminance |
--md-text |
Body text | Off-white on dark bg, near-black on light bg |
--md-text-muted |
Captions, metadata, footers | rgba(text, 0.68) |
--md-accent |
Primary CTA, callout headers, link emphasis | Primary if vibrant, hue-shifted lighter if dark |
--md-accent-soft |
Accent backgrounds, hover states | rgba(accent, 0.14) |
--md-code-bg |
Inline code, fenced block bg | Bg ± 4-5% luminance |
--md-link |
Hyperlinks | Iteratively walked to reach 4.5:1 contrast on bg |
--md-link-hover |
Hover state | Link ± 6-8% luminance |
--md-success |
OK / approved / passed | Green anchored, luminance-matched |
--md-warn |
Caution / nit / TODO | Amber anchored, luminance-matched |
Forcing-question library (Matt Pocock grill-with-docs pattern)
One question per turn, recommended answer, canon citation.
- What's your brand primary color? Recommended: a HEX you already use in your product or docs — not a stock blue. Canon: Aarron Walter, Designing for Emotion (color carries brand affect).
- Should accent be derived or set? Recommended: derive on first run (hue-shift + lighten produces a coherent companion); set explicitly only if your brand kit specifies one. Canon: Adobe Spectrum, Color Foundations.
- Editorial, technical, minimal, or playful? Recommended:
technicalfor engineering specs/reports,editorialfor long-read narratives,minimalfor sparse reference docs,playfulfor marketing/landing content. Canon: Ellen Lupton, Thinking with Type (style serves the rhetorical purpose). - Sticky-sidebar TOC, or inline? Recommended:
sticky-sidebarfor documents over 800 words,inlinefor short reads. Canon: Nielsen-Norman, Table of Contents Best Practices (2023). - Save to global or per-project? Recommended: global by default (consistent across your work); use
--scope projectonly when this repo has a different brand. Canon: research-ops onboarding pattern,research-ops/CLAUDE.md§8.
Customization in use (worked example)
# First-run onboarding (interactive, walks all 10 questions)
python3 markdown-html/skills/design-system/scripts/onboard.py
# Zero-touch defaults for CI / first-test
python3 .../onboard.py --defaults
# Change just the primary color and design style
python3 .../onboard.py --set brand.primary=#FF6B35 --set design_style=editorial
# Per-repo override
python3 .../onboard.py --scope project --set design_style=minimal
# Reset and re-onboard
python3 .../onboard.py --reset
python3 .../onboard.py
# Inspect the effective config (project > global > defaults)
python3 .../config_loader.py --show
python3 .../config_loader.py --status
# Bypass saved config (returns DEFAULTS only)
MARKDOWN_HTML_NO_CONFIG=1 python3 .../config_loader.py --show
# Spot-check WCAG contrast before committing to a brand
python3 .../brand_palette_validator.py --primary "#FF6B35" --accent "#00D4AA"
Assumptions
- User has at least one brand HEX they want consistent across their HTML conversions.
- User accepts a 1-2 minute one-time setup.
- User is OK with Google Fonts as the typography source (CDN, no local font hosting).
- WCAG 2.2 AA is the accessibility floor (4.5:1 body, 3:1 large/UI). AAA (7:1) is out of scope.
Non-goals
- Not a full design-token system (Style Dictionary, Theo). Twelve tokens, not a hundred.
- Not a custom-font hosting solution. Google Fonts only.
- Not a dark/light mode switcher in the converters.
code_theme: autohandles the prefers-color-scheme case for syntax highlighting; layout palette is single-mode per onboarding. - Not an accessibility audit suite (use axe-core / pa11y for that). We enforce contrast only.
- Does not transform existing CSS — the derived palette is injected into freshly generated HTML.
Distinct from
marketing/landing/skills/landing/scripts/brand_palette_validator.py— that script'sderive_palette()produces 8 tokens shaped for hero-page rendering (--navy,--teal,--card-bg,--card-border). This script produces 12 tokens shaped for document rendering (sticky surface, hairline border, code bg, link, link-hover, success, warn). Same WCAG + HSL math, different token taxonomy.research-ops/skills/clinical-research/scripts/onboard.py— same pattern (interactive +--defaults/--set/--show/--reset/--scope), different question set (clinical alpha/power/dropout vs. brand palette/typography/layout).
Output artifact
~/.config/markdown-html/design-system.json (global) or ./.markdown-html/design-system.json (project). JSON schema lives at assets/design_system_schema.json.
Anti-patterns (do not)
- ❌ Skip onboarding and run a converter with placeholder defaults — output looks unbranded.
- ❌ Pick a vibrant brand primary as
brand.bgdirectly (low text contrast). Use it as accent instead. - ❌ Set
MARKDOWN_HTML_NO_CONFIG=1silently for an interactive user — they'll wonder why their tokens disappeared. - ❌ Encode brand semantics in
derived_paletteoutside the 12-token taxonomy. Add a new token only with a deliberate name + purpose + derivation rule.
References
- WCAG 2.2 — §1.4.3 (contrast), §1.4.4 (resize), §1.4.11 (non-text contrast)
- Aarron Walter — Designing for Emotion (A Book Apart)
- Ellen Lupton — Thinking with Type
- Adobe Spectrum — Color Foundations
- Nielsen-Norman — Table of Contents Best Practices (2023)
- research-ops onboarding pattern:
research-ops/CLAUDE.md§8 - Brand palette math source:
marketing/landing/skills/landing/scripts/brand_palette_validator.py
| 1 | |
| 2 | name design-system |
| 3 | description Captures the user's brand identity once via a 10-question onboarding wizard (primary/accent HEX + heading + body Google Fonts + design style editorial/technical/minimal/playful + default output directory + syntax theme + TOC behavior + optional logo/company), validates body-text and link contrast against WCAG 2.2 AA, derives 12 CSS custom properties in HSL space, and stores the result for every markdown-html converter to consume. Use before any markdown-html conversion. Triggers on first-run onboarding ("set up the brand", "configure markdown-html", "run onboarding"), on explicit reset ("reset the design system", "re-onboard"), and is checked by every converter via config_loader.py before rendering. Refuses to save if body-text contrast fails AA 4.5:1 or the output dir isn't writable. Precedence is project (./.markdown-html/) > global (~/.config/markdown-html/) > built-in defaults; MARKDOWN_HTML_NO_CONFIG=1 bypasses. |
| 4 | version 2.10.0 |
| 5 | author Alireza Rezvani |
| 6 | license MIT |
| 7 | tags [design-system, brand-palette, wcag, onboarding, customization, markdown-html, css-variables, typography] |
| 8 | compatible_tools [claude-code, codex-cli, cursor, antigravity, opencode, gemini-cli] |
| 9 | |
| 10 | |
| 11 | # Design System — Onboarding + Shared Brand Tokens |
| 12 | |
| 13 | The design-system skill is the **shared brand owner** for the markdown-html plugin. Run its onboarding once. Every converter (`md-document`, `md-review`, `md-slides`) reads the resulting config via `config_loader.py` and applies the same 12 CSS custom properties to its output. Without this, conversions render with placeholder defaults — technically functional but unbranded. |
| 14 | |
| 15 | This skill ships exactly three Python tools: |
| 16 | |
| 17 | **`onboard.py`** — interactive (or `--defaults` / `--set` / `--show` / `--reset`) wizard. |
| 18 | **`config_loader.py`** — importable customization loader with project > global > defaults precedence and `MARKDOWN_HTML_NO_CONFIG=1` bypass. |
| 19 | **`brand_palette_validator.py`** — WCAG-AA contrast checker + HSL palette deriver. |
| 20 | |
| 21 | All three are stdlib-only and contain no LLM calls (deterministic per Path-B discipline). |
| 22 | |
| 23 | ## When to invoke |
| 24 | |
| 25 | | Symptom | Action | |
| 26 | |---|---| |
| 27 | | User says "convert this markdown to HTML" for the first time in this workspace | Run `python3 markdown-html/skills/design-system/scripts/onboard.py` | |
| 28 | | `~/.config/markdown-html/design-system.json` doesn't exist OR `setup_completed_at` is null | Refuse conversion, surface onboarding | |
| 29 | | User wants per-repo brand override | `python3 .../onboard.py --scope project` | |
| 30 | | User wants to change a single field non-interactively | `python3 .../onboard.py --set brand.primary=#FF6B35` | |
| 31 | | User wants to reset and re-onboard | `python3 .../onboard.py --reset` then re-run | |
| 32 | | User wants zero-touch defaults (CI, ephemeral session) | `python3 .../onboard.py --defaults` | |
| 33 | | Headless / containerized run that should ignore saved config | `MARKDOWN_HTML_NO_CONFIG=1 ...` | |
| 34 | |
| 35 | ## Onboarding question set (10 questions) |
| 36 | |
| 37 | | # | Key | Choices / Validator | Default | |
| 38 | |---|---|---|---| |
| 39 | | 1 | `default_output_dir` | path; `os.access(parent, os.W_OK)` | `./markdown-html-out/` | |
| 40 | | 2 | `brand.primary` | HEX `^#?[0-9a-fA-F]{6}$` | `#0A1628` | |
| 41 | | 3 | `brand.accent` | HEX or blank (auto-derive) | derive from primary | |
| 42 | | 4 | `typography.heading_font` | Google Font name (12 safe defaults) | `Inter` | |
| 43 | | 5 | `typography.body_font` | Google Font name | `Inter` | |
| 44 | | 6 | `design_style` | `editorial / technical / minimal / playful` | `technical` | |
| 45 | | 7 | `code_theme` | `light / dark / auto` | `auto` | |
| 46 | | 8 | `toc.behavior` | `sticky-sidebar / collapsible-top / inline / none` | `sticky-sidebar` | |
| 47 | | 9 | `company_name` | string (may be empty) | `""` | |
| 48 | | 10 | `logo_url` | URL or empty (base64-embedded at render) | `""` | |
| 49 | |
| 50 | ## Hard rules |
| 51 | |
| 52 | **WCAG AA body-text contrast must pass.** `brand_palette_validator.validate()` runs after every change. Body text on bg must reach 4.5:1; link on bg must reach 4.5:1. If either fails, `onboard.py` refuses to save (exit code 4) and tells the user to pick a darker primary, blank `brand.bg`/`brand.text` to let derivation pick a safe pair, or override `brand.text` directly. Canon: WCAG 2.2 §1.4.3. |
| 53 | **Output directory must be writable.** `onboard.py` walks up the path to find an existing ancestor and checks `os.W_OK`. Empty or unwritable path → exit code 3. The orchestrator's `output_path_resolver.py` honors the same rule per-conversion. |
| 54 | **Customization must change behavior, not sit as decoration.** Every consumer (md-document, md-review, md-slides) must read the config and render differently when the user changes `design_style`, `brand.primary`, `code_theme`, or `toc.behavior`. Decorative-only fields fail the design discipline. |
| 55 | **Precedence is fixed.** Project > global > defaults. The deep-merge preserves nested keys (e.g. you can override `brand.primary` in a project config without losing `typography.heading_font` from global). |
| 56 | **Bypass env exists for a reason.** `MARKDOWN_HTML_NO_CONFIG=1` is for headless CI, ephemeral test containers, and the autoresearch-style evaluator loops. Never set it silently for an interactive user. |
| 57 | |
| 58 | ## Derived 12-token palette |
| 59 | |
| 60 | Once the user's brand is captured, `brand_palette_validator.derive_palette()` produces 12 CSS custom properties stored under `derived_palette` in the same config file. Every converter inlines these into its `<style>` block. |
| 61 | |
| 62 | | Token | Purpose | Derivation | |
| 63 | |---|---|---| |
| 64 | | `--md-bg` | Document background | Primary if dark, near-neutral if vibrant | |
| 65 | | `--md-surface` | Card / callout / blockquote background | Bg ± 4-6% luminance | |
| 66 | | `--md-border` | Hairline dividers, table borders | Bg ± 8-12% luminance | |
| 67 | | `--md-text` | Body text | Off-white on dark bg, near-black on light bg | |
| 68 | | `--md-text-muted` | Captions, metadata, footers | `rgba(text, 0.68)` | |
| 69 | | `--md-accent` | Primary CTA, callout headers, link emphasis | Primary if vibrant, hue-shifted lighter if dark | |
| 70 | | `--md-accent-soft` | Accent backgrounds, hover states | `rgba(accent, 0.14)` | |
| 71 | | `--md-code-bg` | Inline code, fenced block bg | Bg ± 4-5% luminance | |
| 72 | | `--md-link` | Hyperlinks | Iteratively walked to reach 4.5:1 contrast on bg | |
| 73 | | `--md-link-hover` | Hover state | Link ± 6-8% luminance | |
| 74 | | `--md-success` | OK / approved / passed | Green anchored, luminance-matched | |
| 75 | | `--md-warn` | Caution / nit / TODO | Amber anchored, luminance-matched | |
| 76 | |
| 77 | ## Forcing-question library (Matt Pocock grill-with-docs pattern) |
| 78 | |
| 79 | One question per turn, recommended answer, canon citation. |
| 80 | |
| 81 | **What's your brand primary color?** Recommended: a HEX you already use in your product or docs — not a stock blue. Canon: Aarron Walter, *Designing for Emotion* (color carries brand affect). |
| 82 | **Should accent be derived or set?** Recommended: derive on first run (hue-shift + lighten produces a coherent companion); set explicitly only if your brand kit specifies one. Canon: Adobe Spectrum, *Color Foundations*. |
| 83 | **Editorial, technical, minimal, or playful?** Recommended: `technical` for engineering specs/reports, `editorial` for long-read narratives, `minimal` for sparse reference docs, `playful` for marketing/landing content. Canon: Ellen Lupton, *Thinking with Type* (style serves the rhetorical purpose). |
| 84 | **Sticky-sidebar TOC, or inline?** Recommended: `sticky-sidebar` for documents over 800 words, `inline` for short reads. Canon: Nielsen-Norman, *Table of Contents Best Practices* (2023). |
| 85 | **Save to global or per-project?** Recommended: global by default (consistent across your work); use `--scope project` only when this repo has a different brand. Canon: research-ops onboarding pattern, `research-ops/CLAUDE.md` §8. |
| 86 | |
| 87 | ## Customization in use (worked example) |
| 88 | |
| 89 | |
| 90 | # First-run onboarding (interactive, walks all 10 questions) |
| 91 | python3 markdown-html/skills/design-system/scripts/onboard.py |
| 92 | |
| 93 | # Zero-touch defaults for CI / first-test |
| 94 | python3 .../onboard.py --defaults |
| 95 | |
| 96 | # Change just the primary color and design style |
| 97 | python3 .../onboard.py --set brand.primary=#FF6B35 --set design_style=editorial |
| 98 | |
| 99 | # Per-repo override |
| 100 | python3 .../onboard.py --scope project --set design_style=minimal |
| 101 | |
| 102 | # Reset and re-onboard |
| 103 | python3 .../onboard.py --reset |
| 104 | python3 .../onboard.py |
| 105 | |
| 106 | # Inspect the effective config (project > global > defaults) |
| 107 | python3 .../config_loader.py --show |
| 108 | python3 .../config_loader.py --status |
| 109 | |
| 110 | # Bypass saved config (returns DEFAULTS only) |
| 111 | MARKDOWN_HTML_NO_CONFIG=1 python3 .../config_loader.py --show |
| 112 | |
| 113 | # Spot-check WCAG contrast before committing to a brand |
| 114 | python3 .../brand_palette_validator.py --primary "#FF6B35" --accent "#00D4AA" |
| 115 | |
| 116 | |
| 117 | ## Assumptions |
| 118 | |
| 119 | User has at least one brand HEX they want consistent across their HTML conversions. |
| 120 | User accepts a 1-2 minute one-time setup. |
| 121 | User is OK with Google Fonts as the typography source (CDN, no local font hosting). |
| 122 | WCAG 2.2 AA is the accessibility floor (4.5:1 body, 3:1 large/UI). AAA (7:1) is out of scope. |
| 123 | |
| 124 | ## Non-goals |
| 125 | |
| 126 | Not a full design-token system (Style Dictionary, Theo). Twelve tokens, not a hundred. |
| 127 | Not a custom-font hosting solution. Google Fonts only. |
| 128 | Not a dark/light mode switcher in the converters. `code_theme: auto` handles the prefers-color-scheme case for syntax highlighting; layout palette is single-mode per onboarding. |
| 129 | Not an accessibility audit suite (use axe-core / pa11y for that). We enforce contrast only. |
| 130 | Does not transform existing CSS — the derived palette is injected into freshly generated HTML. |
| 131 | |
| 132 | ## Distinct from |
| 133 | |
| 134 | **`marketing/landing/skills/landing/scripts/brand_palette_validator.py`** — that script's `derive_palette()` produces 8 tokens shaped for hero-page rendering (`--navy`, `--teal`, `--card-bg`, `--card-border`). This script produces 12 tokens shaped for document rendering (sticky surface, hairline border, code bg, link, link-hover, success, warn). Same WCAG + HSL math, different token taxonomy. |
| 135 | **`research-ops/skills/clinical-research/scripts/onboard.py`** — same pattern (interactive + `--defaults`/`--set`/`--show`/`--reset`/`--scope`), different question set (clinical alpha/power/dropout vs. brand palette/typography/layout). |
| 136 | |
| 137 | ## Output artifact |
| 138 | |
| 139 | `~/.config/markdown-html/design-system.json` (global) or `./.markdown-html/design-system.json` (project). JSON schema lives at `assets/design_system_schema.json`. |
| 140 | |
| 141 | ## Anti-patterns (do not) |
| 142 | |
| 143 | ❌ Skip onboarding and run a converter with placeholder defaults — output looks unbranded. |
| 144 | ❌ Pick a vibrant brand primary as `brand.bg` directly (low text contrast). Use it as accent instead. |
| 145 | ❌ Set `MARKDOWN_HTML_NO_CONFIG=1` silently for an interactive user — they'll wonder why their tokens disappeared. |
| 146 | ❌ Encode brand semantics in `derived_palette` outside the 12-token taxonomy. Add a new token only with a deliberate name + purpose + derivation rule. |
| 147 | |
| 148 | ## References |
| 149 | |
| 150 | WCAG 2.2 — §1.4.3 (contrast), §1.4.4 (resize), §1.4.11 (non-text contrast) |
| 151 | Aarron Walter — *Designing for Emotion* (A Book Apart) |
| 152 | Ellen Lupton — *Thinking with Type* |
| 153 | Adobe Spectrum — *Color Foundations* |
| 154 | Nielsen-Norman — *Table of Contents Best Practices* (2023) |
| 155 | research-ops onboarding pattern: `research-ops/CLAUDE.md` §8 |
| 156 | Brand palette math source: `marketing/landing/skills/landing/scripts/brand_palette_validator.py` |
| 157 |
Discussion
Browse more free Claude skills or everything in Design.