---
name: design-prototype
description: Generate standalone SDTK-DESIGN prototype HTML from a generation manifest, design system, design tokens, and per-screen briefs. Use the optional greybox fidelity path only when the user explicitly asks for a greybox, blueprint, or lo-fi HTML wireframe.
sdtk:
  preview:
    entry: sdtk-design preview
  parameters:
    - { name: --accent, type: color }
    - { name: --primary, type: color }
    - { name: --surface, type: color }
    - { name: --text, type: color }
    - { name: --radius-card, type: spacing, min: 0, max: 24 }
    - { name: --space-section, type: spacing, min: 8, max: 96 }
    - { name: --motion-intensity, type: number, min: 0, max: 1.5 }
  capabilities_required: [surgical_edit]
---

# Design Prototype

Use this skill when the user asks you to generate, regenerate, or polish SDTK-DESIGN prototype screen HTML from `docs/design/prototype/.manifest.json`.

## Inputs

Read these files before writing any screen HTML:

1. `docs/design/prototype/.manifest.json`
2. This skill's `references/designer-charter.md`
3. This skill's `references/craft.md`
4. `docs/design/DESIGN_SYSTEM.md`
5. `docs/design/DESIGN_TOKENS.json`
6. Each screen brief named by the manifest entry's `briefPath`
7. This skill's `references/effects/EFFECTS.md` — **only** when a screen entry carries a `signature` block (see "Signature moments" below).

The manifest contract is:

```json
{
  "screens": [
    {
      "screenId": "home",
      "title": "Home",
      "role": "home",
      "briefPath": "docs/design/screens/home_DESIGN_BRIEF.md",
      "outPath": "docs/design/prototype/screens/home.html",
      "signature": {
        "type": "shader-aurora",
        "tier": "T2",
        "intensity": 1.0,
        "fallbackPoster": "inline",
        "recipe": "aurora-flow"
      }
    }
  ]
}
```

`signature` is **optional**. Screens without it render as normal high-fidelity prototypes. Screens with it get exactly one art-directed motion moment — see "Signature moments".

## Fidelity selection (BK-339)

The high-fidelity path remains the default. Do not infer greybox fidelity from a generic request to generate or polish a prototype.

When the user explicitly asks for a `greybox`, `blueprint`, or `lo-fi HTML wireframe`:

1. Read `references/wireframe-greybox.md` and use its structural fidelity contract.
2. Treat `references/wireframe-greybox-example.html` as a pattern reference only; do not copy it or replace brief-sourced structure with its sample composition.
3. Keep the normal manifest `outPath` contract. Write standalone screen HTML directly; do not emit open-design `<artifact>` wrappers.
4. Use system fonts and inline CSS/SVG only. No CDN fonts, external images, external CSS, or external JavaScript.
5. Preserve brief-sourced actions, states, routes, facts, and `NEEDS_*` honesty while expressing them as neutral structural placeholders.

This fidelity path is different from `sdtk-design wireframe`, which continues to generate Markdown screen-role specifications. If a request says only “wireframe” and the intended output is unclear, distinguish the two outputs before writing.

## Signature moments (BK-357)

When — and only when — a manifest screen entry carries a `signature` block, that screen gets one art-directed motion moment. This is what separates a flat template from a screen that stops the scroll.

**Read `references/effects/EFFECTS.md` first** (once per run, only if any screen has a signature). It is the binding recipe contract. `references/effects/signature-hero-example.html` is a complete self-contained reference of the whole contract in one file — study it, then adapt to the brief; never copy it verbatim or reuse its demo copy.

Rules that override nothing else in this skill but apply on top for a signature screen:

1. **One spectacle per screen.** Build exactly the effect named by `signature.type` using the matching recipe in EFFECTS.md. Everything else on the screen stays calm (entrance reveals at most). `signature.type: "none"` means no motion effect — do not add one.
2. **Poster-first + reduced-motion + JS-off.** The first paint is an inline CSS/SVG poster; the effect fades in after it initialises and is also the permanent fallback. Under `prefers-reduced-motion` or with JS off, the poster carries the screen. This is mandatory — a signature screen must still be complete and readable with no motion.
3. **Token-driven.** The effect's colours come from the design tokens (`--accent`, `--glow`, surface tokens) and re-read them on `data-theme` change. Respect `--motion-intensity` (0–1.5) for amplitude.
4. **Stay self-contained.** Inline CSS + inline effect JS in the one screen file — the same no-CDN / no-external-file rule as the rest of this skill. The single exception is a **T3** signature (`tier: "T3"`, three.js-class): it loads one bundled IIFE named by `signature.bundle`, which must sit beside the screen file. Follow the "T3 rule" in EFFECTS.md exactly (browsers block ES modules from `file://`, so the engine must be a pre-bundled classic script).
5. **Honour the QA rules** in EFFECTS.md before emitting — especially `--on-accent` contrast, never `filter` + `background-clip:text`, no timer-raced style mutations, and don't let a parent `max-width` clamp children.
6. **Honest performance.** Keep the self-contained (T0/T1/T2) budgets so Lighthouse stays ≥ 90; a T3 screen is heavier by design and its real performance is measured, never assumed. Do not claim "zero-touch" or an unmeasured score.

If a signature screen also has data/interactive slots, the BK-227/229/231 slot and density rules still apply to the screen's content — the signature governs the hero moment, not the whole page.

## Workflow

1. Validate that the manifest exists and that every screen entry has `screenId`, `title`, `role`, `briefPath`, and `outPath`.
2. Read the charter and craft references once for the whole run.
3. Read `DESIGN_SYSTEM.md` and `DESIGN_TOKENS.json` as the only brand and visual-direction authority.
4. For each screen, read its `briefPath`, plan the page structure, then write exactly one complete standalone `<!doctype html>` document to its `outPath`.
5. Keep CSS inline in the file. Do not create external CSS, JavaScript, image, or font files.
6. Keep each generated HTML file under roughly 1000 lines.
7. Use real brief-sourced content, data slots, states, actions, and screen purpose. Do not add filler sections to make the page feel dense.
8. Verify each file after writing: complete doctype, `<html>`, `<head>`, `<body>`, non-empty `<title>`, one `<h1>`, visible state coverage, token usage, no raw debug JSON, no placeholder/filler copy.

## NEEDS_* slot rendering convention (BK-227)

When emitting NEEDS_* placeholders in screen HTML, distinguish two slot classes by checking the brief's per-section `interactive_data_slots` array (sidecar JSON) or the `interactive=` detail in the brief markdown:

**Interactive slots** — markers listed in `interactive_data_slots`. These sit inside repeated card / row / list structures (product cards, order rows, search results, category cards, nav items). Emit each as:

    <a href="#" data-needs="NEEDS_PRODUCT_NAME">NEEDS_PRODUCT_NAME</a>

**Static slots** — every other NEEDS_* marker (brand name in header, footer URLs, hero imagery, single-occurrence content). Emit as:

    <span data-needs="NEEDS_BRAND_NAME">NEEDS_BRAND_NAME</span>

Rules:
- `href="#"` is the ONLY permitted destination for skeleton anchors. Never invent URLs.
- The visible marker text and the `data-needs` attribute value are identical across both classes — only the wrapper element changes.
- If a section mixes interactive and static slots, look up class per marker via set membership on `interactive_data_slots`.
- Skeleton anchors preserve BK-225 honesty (the `data-needs` attribute marks the gap) and BK-217 no-invented-content (`#` is not a real destination).

### Density rule for repeated structures (BK-231)

When a section's `interactive_data_slots` is non-empty (BK-227 interactive) OR the section's `components` include a card / row / list-item / nav-item pattern, render **3–4 sample instances** rather than 1. Each instance reuses the same skeleton anchor + marker set from BK-227.

Cap at 4 instances per section to keep file size bounded (per-screen HTML must stay under ~1000 lines). Single-occurrence interactive slots (e.g. one cart-summary panel, one add-to-cart button on PDP) are unaffected — apply density only to repeated structures.

Composition with BK-229 facts:
- If `tokens.brand.categories[]` has N entries → render N category instances (use supplied labels per BK-229).
- For repeated structures NOT bound to factual data (product cards, order rows, search results, generic list items) → render exactly 4 instances, all carrying the same `NEEDS_*` marker set.

#### Examples

Product cards in a category screen — render 4 instances per BK-231 density rule (section.interactive_data_slots contains NEEDS_PRODUCT_NAME, NEEDS_PRODUCT_IMAGE, NEEDS_SKU, NEEDS_PRICE):
```
<div class="product-grid">
  <a href="#" data-needs="NEEDS_PRODUCT_NAME" class="product-card">
    <span data-needs="NEEDS_PRODUCT_IMAGE" class="product-thumb">NEEDS_PRODUCT_IMAGE</span>
    <span class="product-name">NEEDS_PRODUCT_NAME</span>
    <span class="product-sku" data-needs="NEEDS_SKU">NEEDS_SKU</span>
    <span class="product-price" data-needs="NEEDS_PRICE">NEEDS_PRICE</span>
  </a>
  <a href="#" data-needs="NEEDS_PRODUCT_NAME" class="product-card">
    <span data-needs="NEEDS_PRODUCT_IMAGE" class="product-thumb">NEEDS_PRODUCT_IMAGE</span>
    <span class="product-name">NEEDS_PRODUCT_NAME</span>
    <span class="product-sku" data-needs="NEEDS_SKU">NEEDS_SKU</span>
    <span class="product-price" data-needs="NEEDS_PRICE">NEEDS_PRICE</span>
  </a>
  <a href="#" data-needs="NEEDS_PRODUCT_NAME" class="product-card">
    <span data-needs="NEEDS_PRODUCT_IMAGE" class="product-thumb">NEEDS_PRODUCT_IMAGE</span>
    <span class="product-name">NEEDS_PRODUCT_NAME</span>
    <span class="product-sku" data-needs="NEEDS_SKU">NEEDS_SKU</span>
    <span class="product-price" data-needs="NEEDS_PRICE">NEEDS_PRICE</span>
  </a>
  <a href="#" data-needs="NEEDS_PRODUCT_NAME" class="product-card">
    <span data-needs="NEEDS_PRODUCT_IMAGE" class="product-thumb">NEEDS_PRODUCT_IMAGE</span>
    <span class="product-name">NEEDS_PRODUCT_NAME</span>
    <span class="product-sku" data-needs="NEEDS_SKU">NEEDS_SKU</span>
    <span class="product-price" data-needs="NEEDS_PRICE">NEEDS_PRICE</span>
  </a>
</div>
```

Brand logo in a header — single occurrence, density rule does NOT apply (section.interactive_data_slots empty — static slot):
```
<a href="/" class="logo">
  <span data-needs="NEEDS_BRAND_NAME">NEEDS_BRAND_NAME</span>
</a>
```

Order row in order-history — pattern shape shown once; renderer applies BK-231 density to emit 4 such rows (section.interactive_data_slots contains NEEDS_ORDER_ID, NEEDS_DATE, NEEDS_TOTAL):
```
<a href="#" data-needs="NEEDS_ORDER_ID" class="order-row">
  <span class="order-id">NEEDS_ORDER_ID</span>
  <span class="order-date" data-needs="NEEDS_DATE">NEEDS_DATE</span>
  <span class="order-total" data-needs="NEEDS_TOTAL">NEEDS_TOTAL</span>
</a>
```

## Factual content from project-facts (BK-229)

Before emitting any NEEDS_* marker, check `tokens.brand` in `DESIGN_TOKENS.json` for a matching factual value. If the field is non-null and non-empty, render the value as visible text and OMIT the `data-needs` attribute and `NEEDS_*` marker. If the field is null or empty, fall back to the BK-227 wrapper emit rule.

Marker → token field mapping:

| NEEDS_* marker | tokens.brand field |
|---|---|
| NEEDS_BRAND_NAME | brand.name |
| NEEDS_COMPANY_NAME | brand.company |
| NEEDS_CONTACT_URL | brand.contactUrl |
| NEEDS_PRIVACY_URL | brand.privacyUrl |
| NEEDS_TERMS_URL | brand.termsUrl |
| NEEDS_CATEGORY_LABEL | brand.categories[i].label (keyed by element's `data-key` attribute) |

For NEEDS_CATEGORY_LABEL specifically — when a slot is also classified interactive (BK-227), the result combines both rules:
- BK-227 wraps as `<a href="#" data-needs="NEEDS_CATEGORY_LABEL" data-key="cable">`
- BK-229 fills label from `brand.categories` if `{ key: "cable", label: "..." }` present
- Combined output: `<a href="#" data-key="cable">...label...</a>`

### Examples (BK-229)

Header brand (BK-227 static + BK-229 fact):
- `tokens.brand.name = "Esteam"`: `<a href="/" class="logo">Esteam</a>`
- `tokens.brand.name = null`: `<a href="/" class="logo"><span data-needs="NEEDS_BRAND_NAME">NEEDS_BRAND_NAME</span></a>`

Footer contact URL (BK-227 static + BK-229 fact):
- `tokens.brand.contactUrl = "https://example.com/contact"`: `<a href="https://example.com/contact">Contact</a>`
- null: `<a href="#" data-needs="NEEDS_CONTACT_URL">Contact</a>`

Category nav (BK-227 interactive + BK-229 fact, keyed by `data-key`):
- `tokens.brand.categories[0] = { key: "cable", label: "Cable" }`: `<a href="#" data-key="cable">Cable</a>`
- absent: `<a href="#" data-needs="NEEDS_CATEGORY_LABEL" data-key="cable">NEEDS_CATEGORY_LABEL</a>`

Boundary: do NOT derive `name`, `company`, `*Url`, or `categories` from requirement text, screen names, or any other source. The only source of factual content is the `tokens.brand` block populated by `--project-facts`.

## Inter-screen navigation (BK-232)

The MVP prototype is a click-through demo across 10 sibling HTML files in `docs/design/prototype/screens/`. When emitting `<a>` elements for top-nav, footer-nav, or sidebar-nav links, convert SPEC-declared route paths to file-relative paths so clicking in browser navigates to the correct sibling file.

### Canonical route → file mapping

| Route prefix (from brief / SPEC) | Target `href` value |
|---|---|
| `/` | `home.html` |
| `/category` or `/category/*` | `category.html` |
| `/product` or `/product/*` | `product-detail.html` |
| `/search` | `search.html` |
| `/cart` | `cart.html` |
| `/checkout` or `/checkout/*` | `checkout.html` |
| `/account` or `/account/info` | `account-info.html` |
| `/account/orders` (exact) | `order-history.html` |
| `/account/orders/*` (any order id) | `order-detail.html` |
| `/configure` or `/configure/*` | `mode-b-configurator.html` |

### Fallback rule

Routes NOT in the mapping (`/account/quotes`, `/account/addresses`, `/logout`, `/shipping`, `/faq`, `/about`, `/help`, `/admin`, `/api/*`, etc.) → emit `href="#"` (BK-227 skeleton anchor). The placeholder is honest: no rendered file exists for the route.

### Factual URL priority (BK-229)

When `tokens.brand.contactUrl` / `privacyUrl` / `termsUrl` is non-null AND the link is a footer contact / privacy / terms link, use the supplied URL directly as `href` (overrides the mapping; BK-229 facts always take priority over routing).

### Current-page marker

When the rendered file IS the current screen (e.g. `order-history.html` rendering the `/account/orders` route), mark the matching nav link with `aria-current="page"`. Keep the `href` value pointing to the same file (self-link is fine).

### Example

In `home.html` top nav:
```
<nav aria-label="Main navigation">
  <a href="category.html">高圧ケーブル</a>
  <a href="category.html">開閉器（PAS）</a>
  <a href="category.html">金具・支持材</a>
  <a href="category.html">碍子・絶縁材</a>
  <a href="search.html">検索</a>
  <a href="mode-b-configurator.html">Mode B</a>
  <a href="account-info.html" class="btn btn-secondary">アカウント</a>
  <a href="cart.html" class="btn btn-primary">カート</a>
</nav>
```

In `order-history.html` sidebar (current page = order-history):
```
<nav class="account-nav" aria-label="アカウントナビゲーション">
  <h2>マイアカウント</h2>
  <ul>
    <li><a href="account-info.html">ダッシュボード</a></li>
    <li><a href="order-history.html" aria-current="page">注文履歴</a></li>
    <li><a href="#">見積一覧</a></li>
    <li><a href="account-info.html">アカウント情報</a></li>
    <li><a href="#">配送先一覧</a></li>
    <li><a href="#">ログアウト</a></li>
  </ul>
</nav>
```

## CSS scope checklist for nav elements (BK-233)

When a screen contains multiple `<nav>` elements (e.g. header nav + sidebar account nav + footer nav), generic `nav ul { ... }` rules cascade into ALL nav contexts and break nested layouts. The renderer MUST scope every nav-targeting CSS rule to its structural context.

### Required scoping per nav context

1. **Header nav** — use `header nav ul { display: flex; ... }` (NEVER bare `nav ul`).
2. **Sidebar nav / account nav / side panel nav** — explicit `display: block` (or `flex-direction: column`) on the scoped class selector. Example: `.account-nav ul { display: block; }`.
3. **Footer nav** — same discipline: `footer nav ul { display: flex; ... }` if horizontal, OR explicit `display: block` if vertical.

Rule: if a `<nav>` element appears in more than one structural context within the same screen, scope EVERY nav-targeting rule with a parent selector. Never rely on cascade defaults for nested nav.

### Negative example (DON'T)

```
/* Generic nav ul cascades into ALL nav children — breaks sidebar */
nav ul { list-style: none; display: flex; gap: 1.5rem; }
.account-nav ul { list-style: none; }  /* missing display reset! cascade wins */
```

Result: sidebar `<li>` items render in a horizontal row, each becoming a narrow column where Japanese/CJK characters wrap one-per-line.

### Positive example (DO)

```
/* Scope header explicitly */
header nav ul { list-style: none; display: flex; gap: 1.5rem; }
header nav li { margin: 0; }

/* Sidebar explicitly declares display: block */
.account-nav ul { list-style: none; display: block; margin: 0; padding: 0; }
.account-nav li { display: block; margin-bottom: 0.25rem; }
.account-nav a { display: block; padding: 0.5rem 0.75rem; }
```

Result: header nav horizontal, sidebar nav proper vertical menu list.

### Sanity check during rendering

For each screen with multiple `<nav>` elements, verify before output:
- Does every `nav`-targeting rule have a parent selector (`header nav`, `footer nav`) OR a class scope (`.account-nav`)?
- Do nested nav class rules explicitly set `display`?
- Are there any bare `nav ul` or `nav li` rules without a parent / class scope?

If any check fails, fix the CSS before emitting the HTML file.

## Consume design feedback (BK-275)

Use this when the user asks you to apply Preview Studio feedback (the `sdtk-design preview` annotate→send loop).

1. Read the **newest** `docs/design/feedback/DESIGN_FEEDBACK_*.md` (sort by filename timestamp; the name is `DESIGN_FEEDBACK_<YYYYMMDDThhmmss>.md`). Its front-matter is `schema: sdtk.design.feedback.v1`.
2. Parse the `<attached-preview-comments>` block. Each numbered entry names a `targetKind` (`element`, `pod`, or `token`), and — for element/pod — a `screen` (with its `file:` path), a `selector`, a `stable-id`, a `position`, and a `comment`. Pod entries list `member.N` sub-targets. **Token entries** instead name a `token` (a CSS custom property such as `--accent`), an `oldValue`, a `newValue`, a `scope: global`, and a `comment`.
3. **Hard scope — obey it literally.** For `element`/`pod` marks, change ONLY the elements named by selector / stable-id / position, in ONLY the named screen file(s) under `docs/design/prototype/screens/`. Do NOT modify sibling screens, parent layout, global CSS, `DESIGN_SYSTEM.md`, or `DESIGN_TOKENS.json` — even if you notice issues there. Surface any out-of-scope observation as a short note in your reply instead of editing it. If a request cannot be satisfied without touching outside the scope, ask the user first.
   - **`token` marks are the one deliberate exception** to "do not touch tokens": apply the named `token` change globally to its source of truth — update the value in `docs/design/DESIGN_TOKENS.json` if the token maps to a token field there, and/or the `:root { --token: … }` declaration shared by the screens. Change ONLY the named token(s) to the given `newValue`; do not retune other tokens, palettes, or unmarked screens. If a token has no clear source of truth, ask before editing.
4. When you (re)write a screen, **stamp `data-sdtk-id="<stable id>"` on the stable structural elements you touch** (headers, cards, sections, nav, primary CTAs). This is best-effort and never required, but it lets future Preview Studio marks re-anchor by id instead of by DOM-path.
5. After editing, keep each screen a complete standalone `<!doctype html>` document under ~1000 lines, exactly as elsewhere in this skill. Do not delete the feedback file.

## Client Loop (BK-358 — Pro)

Use this when the user asks you to work client review comments from the Review Room (`sdtk-design room start`). The ledger at `docs/design/reviews/R<n>/review-ledger.json` (`sdtk.design.review-ledger.v1`) is the contract; the CLI is your only write path to it.

1. `sdtk-design review-loop next --json` gives the next unworked comment: `screen`, `viewportWidth`, an `anchor` (`xPct`/`yPct` are **document** percentages; `cssPath` is a best-effort hint), the client's `text`, and `author`. Work ONE comment at a time.
2. Locate the target in the named screen file using the anchor + cssPath + the comment text together. The text outranks the coordinates — if the comment says "the CTA" and the anchor is slightly off, the CTA is the target. Check the fix at the comment's `viewportWidth` first; keep the other viewports sane.
3. **Hard scope, same spirit as BK-275:** change only what the comment asks, in only the named screen. Out-of-scope observations go into your reply, not into edits. When a comment is ambiguous, resolve it as `question` instead of guessing:
   `sdtk-design review-loop resolve <id> --status question --note "<the specific question, client-readable>"`.
4. After applying: `sdtk-design review-loop resolve <id> --status applied --note "<what you changed, one client-readable sentence>"`. Declines are allowed (`--status declined`) when a request conflicts with the design system or accessibility — the note must say why, kindly. **The note is read by the client verbatim — write it for them, not for the repo.**
5. Repeat until `review-loop status` exits 0 (no open/question comments), then tell the user the round is ready to close: `sdtk-design round close` snapshots every screen (375/768/1440), freezes the round, and opens the next; `sdtk-design round diff` renders the "what changed" report at `docs/design/reviews/R<n>/diff/report.html`.
6. Round-1 tip you should apply proactively: right after the FIRST `room start` of a project, run `round close` once — that baseline is what every later diff compares against.
7. Sign-off is the client's/owner's act, not yours: never run `round signoff` yourself; suggest it when a round's diff is clean and the client is happy.
8. Screens stay complete standalone documents per this skill; the ledger and rounds files are CLI-owned — never edit them by hand.

## Direction Round (BK-358 P4 — Pro)

Use this when the user runs `sdtk-design direction start` (or asks for "direction candidates" / "stylescapes"). The manifest at `docs/design/directions/directions.json` (`sdtk.design.directions.v1`) lists candidate stubs; you author the pages and fill each candidate's four axes.

1. Author each candidate as ONE full self-contained page of the manifest's representative `screen` (default: the landing/hero), written to its `outPath`, following every rule in this skill (standalone `<!doctype html>`, tokens, signature contract, poster-first).
2. **The divergence rule is binding:** every candidate pair must differ on at least 2 of the 4 axes — `stylePreset`, `paletteHint`, `typePair`, `signatureType`. Fill those fields honestly in the manifest (plus a short `label` and one-sentence `rationale` per candidate); `sdtk-design direction lint` enforces the recordable part. Three shades of one idea is a failed round — pick genuinely different families (e.g. calm-editorial vs dark-spectacle vs warm-craft).
3. Run `sdtk-design direction lint` and fix findings until PASS, then tell the user the room is ready: the client compares candidates and picks in the Review Room (`sdtk-design room start`).
4. Client comments on candidates arrive in the review ledger with `screen: "direction:<id>"` — work them with the normal Client Loop contract. Refining a candidate is allowed for the chosen one only, budget ~2 passes (guidance): the direction round must not become the whole project.
5. **The pick and the lock are not yours:** the client picks; the user runs `sdtk-design direction lock`. After lock, `DESIGN_TOKENS.json` carries a `direction` block — treat it as a binding input: every screen you generate afterwards inherits its `stylePreset`/`paletteHint`/`typePair`/`signatureType` unless the user explicitly reopens the round.

## Brand-Match (BK-359 — Pro)

Use this when the user runs `sdtk-design brand ingest <url>` (or asks to "match the client's brand"). The CLI does the deterministic extraction; **you do the taste** — curate the raw extraction into a brand profile the Direction Round can start from.

1. Read `docs/design/brand/raw-extraction.json` (`sdtk.design.brand-extraction.v1`): ranked `colorCandidates` (usage × saturation), `typeStacks`, a `logo` pointer, and a `confidence` (`ok`|`low`) with `notes`. **If `confidence: low`, say so to the user and lean on the live site** — the extraction is a starting point, not truth.
2. Curate into `docs/design/brand/brand-profile.json` (`sdtk.design.brand-profile.v1`):
   ```
   { schema, source, confidence,
     tokens: { accent, accentHover, glow, onAccent, surface, text, textMuted, border },
     palettes: [6 × { name, accent, glow, onAccent }],
     typography: { display, body },
     logo?, notes: [] }
   ```
   - **accent** = the true brand hue (usually the top saturated candidate — sanity-check against the live site, not blindly the #1 rank). Pick `onAccent` for AA contrast on that accent.
   - **Palette derivation rule (binding):** palette #1 is the brand hue; #2–#6 are **curated complements** around it (analogous / complementary / triadic families) — **NOT six shades of the same colour.** Six near-identical hues is a failed derivation, same spirit as the Direction Round divergence rule.
   - **typography** maps the extracted `typeStacks` to a display/body pairing; keep safe system fallbacks in the stack.
3. **Guard before you ship:** run `sdtk-design brand check` — it recomputes WCAG AA for every `onAccent`/text pair and fails loud. Fix any violation in the profile before generating a screen; a bad `onAccent` caught here never becomes a client review comment.
4. Feed it forward: `sdtk-design direction start --brand docs/design/brand/brand-profile.json` seeds the candidates from the brand palette family and type pairing, so the Direction Round opens with three directions that already look like the client — then the normal Direction Round contract applies.
5. **Honesty (BR-03):** the profile carries `confidence` + `notes`; describe the result as "a starting point from the client's real brand, reviewed by you", never "a perfect automatic brand match". Every quality claim comes from the dogfood, not the tool.

## Boundaries

- Brand, palette, typography, spacing, mood, and component direction come only from `docs/design/DESIGN_SYSTEM.md` and `docs/design/DESIGN_TOKENS.json`.
- Do not infer brand direction from requirements, source quotes, screen names, or sample file names.
- Do not read `docs/ui/**` before generation completes.
- Do not copy or hash-match sample HTML, PNG, or other reference files.
- Do not hardcode Esteam screen names, routes, palette, copy, or layouts.
- Do not call a network service, start a daemon, spawn a subprocess, or require an API key.
- Do not create `.sdtk/atlas`.
