- Design system
- Agent prompt
11 — Agent prompt
Agent prompt
Paste this into a new repo's CLAUDE.md, AGENTS.md or system prompt. It is written to be enough on its own — an agent that has only this file should produce on-system markup without seeing the CSS.
/llms.txt is the entire system — tokens, layout,
every class, the known traps — as one plain-text file. One fetch, no crawling, and it
stays accurate because it is maintained alongside the CSS. Use the prompt below when
you want the rules pinned inside the repo rather than fetched from a URL.
How to use it
Copy
assets/css/into the new repoAll eight files except
docs.css, which styles this reference site only.Paste the prompt below into
CLAUDE.mdat the repo rootUnder a heading like
## Design system. It is read on every session.Add the project's own exceptions underneath
A different accent, an extra component. Keep them below the pasted block so it stays diffable against this page.
tokens.css and its component layers, not a second source of truth — if you change a token, update the block below in the same commit.
The prompt
Copy the whole block. It is about 90 lines and deliberately written as rules an agent can check its own output against, not as prose about design values.
# Design system — tanghoong.com
All UI in this repo follows the shared system at https://design.tanghoong.com.
The stylesheets in `assets/css/` are the source of truth. This file describes
them so you can write correct markup without reading all of the CSS.
## Non-negotiables
1. Never write a literal colour, font size, radius, shadow or duration in a
component. Every value comes from a CSS custom property in `tokens.css`.
If the value you need does not exist, add it to `tokens.css` — do not inline it.
2. Never remove a focus outline without replacing it. Focus is `:focus-visible`,
2px `var(--focus)`, 2px offset.
3. Every interactive control clears a 44px touch target.
4. Every form field has a real `<label for>`. A placeholder is not a label.
5. Colour never carries meaning alone. Pair every status colour with a word.
6. Reach for the native element first: `<dialog>` for modals and drawers,
`<details>` for menus, accordions and the mobile nav, real `<button>`
and `<a>`. Do not rebuild what the platform gives you.
## Tokens
Surfaces --bg (page) · --bg-sunken (bands, wells) · --bg-elevated (cards,
menus, modals) · --bg-glass (sticky header only)
Ink --text (content) · --text-2 (supporting) · --text-3 (labels, meta)
Lines --hairline (separators, inputs) · --hairline-soft (card outlines)
Accent --accent · --accent-ink (text on filled) · --accent-wash (12% tint)
Status --ok --warn --danger --info, each with a matching -wash
Type --font-sans (system stack) · --font-mono
--fs-h1 --fs-h2 --fs-h3 --fs-lead --fs-stat
--fs-body (17px) --fs-sm (15px) --fs-xs (13px)
Space --s-1 (4px) through --s-32 (128px) on a 4px scale
Measure --container (1120) --container-prose (720) --container-mid (940)
--container-wide (1320) · --gutter · --section-y · --nav-h (56px)
Radius --r-sm (10) --r-md (16) --r-lg (20) --r-xl (28) --r-chip (pill)
Shadow --sh-sm --sh-md --sh-lg — all resolve to none in dark theme
Motion --dur-fast (.15s) --dur (.26s) --dur-slow (.42s) · --ease
Themes: every colour is declared once with `light-dark()`. An explicit choice
sets `data-theme="light"|"dark"` on `<html>`; no attribute means follow the OS.
Never define a colour only inside a media query.
## Layout
- Page = a stack of `<section class="section s-page|s-sunken">`, alternating
surfaces. Inside each, one `.container` (add `--prose|--mid|--wide`).
- The section owns vertical rhythm; the grid owns gaps. Components carry no
outer margin. Never put `margin-bottom` on a component.
- Grids are mobile-first single column with `minmax(0, 1fr)` tracks.
`.grid--2 --3 --4`, `.cards --2 --3`.
- Two-column reading layout: `.with-aside` + `aside.rail`.
- Breakpoints (range syntax only): 640, 720, 900, 960.
## Components — the class vocabulary
Buttons .btn + .btn--filled|--tinted|--quiet|--outline|--danger
sizes .btn--sm|--lg|--icon|--block · .iconbtn for bordered icon
buttons · .link-more for an inline arrow link
Exactly one --filled per view.
Labels .chip (passive: a topic, a tag) vs .badge (state: --ok --warn
--danger --info --solid). A chip has no meaning; a badge does.
Surfaces .card (elevated, lifts on hover only when it is an <a>)
.panel (sunken well, no hover) · .band (centred CTA)
.note + --ok|--warn|--danger|--info (inline message)
Data .stats/.stat__fig · .rows/.row · .facts (dl) · .empty · .meter
.table inside .table-wrap (the wrapper scrolls, never the body)
Nav .site-head/.head-nav · .site-foot/.foot-grid · .crumb · .tabs
.navsheet (mobile, a details element)
Forms .field > .label + .input|.textarea|.select + .hint|.error
.check (checkbox/radio row) · .check--boxed · .switch
.input-group with .input-group__addon · .fieldset + .fieldset__legend
.form-grid --2 with .span-2 · .form-actions
Errors use aria-invalid="true" plus aria-describedby — not a class.
Overlays .modal and .drawer (both <dialog>, opened with .showModal())
.menu (<details>) · .accordion__item (<details>) · .toast · .tip
Prose .prose on the wrapper, then unclassed HTML inside it.
.lede · .eyebrow · .quote · .steps · .codeblock · .kbd
Utility .t2 .t3 .sm .xs .mono .nums .measure .cluster .stack .vh
.mt-2 .mt-4 .mt-6 .mt-8 .mt-12 .mt-16 (top margin only)
## Writing markup
- Build the page from the classes above before writing any new CSS. If a new
component is genuinely needed, add it to the right layer file and give it a
comment saying what it is for and when not to use it.
- Prefer `inline-size`/`block-size` and `inset-*`/`margin-inline` over the
physical properties — the layout is direction-agnostic and the CV site
ships in English and Chinese.
- SVG icons: 16–20px, `fill="none" stroke="currentColor" stroke-width="1.8–2"`,
always `aria-hidden="true"`. An icon-only control needs `aria-label`.
- Wrap every table in `.table-wrap`. The page body must never scroll sideways.
- Long-form copy caps at 68ch. Leads and quotes cap at 56–60ch.
## What to avoid
- A second primary button in the same view.
- A shadow in dark theme (they resolve to `none`; use `--bg-elevated`).
- A tooltip carrying information not available anywhere else.
- Validating a field on every keystroke — validate on blur and on submit.
- A fifth breakpoint. Try `clamp()`, `minmax()` or `auto-fill` first.
- Any animation that ignores `prefers-reduced-motion`.
The < escapes above are for this page only — the copy button gives you the plain text with real angle brackets.
Token quick reference
The same values as a table, for when you need to check one without loading the stylesheet.
| Token | Light | Dark | Use |
|---|---|---|---|
--bg | #fbfbfd | #000000 | Page ground |
--bg-sunken | #f5f5f7 | #0a0a0c | Bands, wells, chips |
--bg-elevated | #ffffff | #1c1c1e | Cards, menus, modals |
--text | #1d1d1f | #f5f5f7 | Body and headings |
--text-2 | #515154 | #a1a1a6 | Supporting copy |
--text-3 | #6e6e73 | #86868b | Labels, metadata |
--hairline | #0000001a | #ffffff21 | Separators, inputs |
--hairline-soft | #0000000f | #ffffff14 | Card outlines |
--accent | #03744e | #4dff9b | Primary action, current item |
--accent-ink | #ffffff | #04140b | Text on a filled accent |
--ok | #03744e | #4dff9b | Success |
--warn | #8a5a00 | #f5c451 | Caution |
--danger | #b3261e | #ff6b62 | Error, destructive |
--info | #0a5ec2 | #6bb6ff | Neutral notice |
Review checklist
Run this against any new page before it ships. It catches almost everything that makes a page look off-system.
- No literal hex, px font size, radius or duration outside
tokens.css - Both themes checked, including the toggle in both directions
- Tabbed the whole page — every control shows the focus ring, nothing is skipped or trapped
- Every field has a label; every error has
aria-invalidandaria-describedby - Every icon-only control has an
aria-label; every decorative SVG hasaria-hidden - Exactly one
.btn--filledper view - No horizontal scroll at 320 px; tables scroll inside their wrapper
- Headings run h1 → h2 → h3 with no level skipped
- Checked with
prefers-reduced-motion: reduceforced on - Print preview is clean — no chrome, nothing cut off
Short version
For a tool with a tight context budget, or a commit-message-length reminder.
Follow https://design.tanghoong.com. Values come from tokens.css custom properties only — never literal colours, sizes, radii or durations. Surfaces: --bg, --bg-sunken, --bg-elevated. Ink: --text, --text-2, --text-3. One accent, one .btn--filled per view. Space on the --s-* 4px scale. Sections own vertical rhythm; components carry no outer margin. Native elements first: dialog for modals, details for menus and accordions, real labels on every field. 44px touch targets, visible :focus-visible ring, colour never alone. Light and dark from one light-dark() token set.