DESIGN.md@brand/showcase/app-screens/02-sleep-meditation · alpha · 2026-10-14 · sha256 506e27322d48cd50

DESIGN.md@brand/showcase/app-screens/02-sleep-meditation alphaA

Immutable. This exact content never changes and is served at /api/v1/blob/506e27322d48cd50.

---
version: alpha
name: "Lullwater"
description: "Design system generated by OpenDesigner"
colors:
  primary: "#e8a48a"
  on-primary: "#242428"
  surface: "#fcfdff"
  on-surface: "#242428"
  error: "#c0534a"
typography:
  body-md: { fontFamily: "Instrument Sans", fontSize: 17px, lineHeight: 24px }
rounded:
  control: 9999px
  container: 20px
spacing:
  unit: 4px
---

# Lullwater

**Lullwater** is a design system; what it is for is not recorded yet (Q-scope-01).

- **For:** people who use it often, as an everyday app
- **Screens:** not asked yet
- **Runs on:** ios
- **Feel:** calm, gentle (deferential, minimal, friendly; picked for you)
- **Brand color:** Picked for you, not chosen by you: an orange (#E8A48A) on buttons, links and focus, with dark text on it.
- **Decided:** 15 picked for you; everything else uses sourced defaults
- **Standards:** 339 house standards followed (locked, house standards v2); see the Standards section
- **Next:** zoom into Colors, Layout, Shapes, or stop here: each level works
- **Licence risks:** none found

> Generated by the OpenDesigner engine 1.0.0 from `opendesigner/state.json` and `opendesigner/decisions.md`; `opendesigner/tokens/` is the source of truth. Change the system with `engine.py set ...` and `engine.py build`, not by editing this file (notes inside `<!-- od:keep -->` blocks survive). Each section opens with one plain sentence; open **More** for the designer and engineer detail.

## Overview

> Zoom: sketch (0 of 3), 5 decisions in this area. To zoom in, answer Q-dir-01, Q-dir-02.
<!-- od:zoom area=overview level=0 -->

**Lullwater feels deferential, minimal and friendly. Screens are roomy, in a flat style.**
Designers: visual style: flat, tonal, glass · Code: `preset in state.json`

<details><summary>More</summary>

**Intent.** A design system generated from eight dials and a few raw inputs.

- Audience: people who use it often, as an everyday app
- The memorable thing: not recorded yet (Q-brand-02)
- Surfaces: not recorded yet (Q-scope-06)
- Platforms: ios; inputs: pointer, touch
- Direction: preset flat2 (the default until Q-dir-01 is answered); feel deferential, minimal, friendly (words picked for you: calm, gentle)

**Principles (ranked).**
No principles recorded yet (Q-brand-07). Until they are, the dials act as the tie-breakers below.

**Dial positions.** Three posture dials set the overall stance. Five character dials fine-tune it.

- **Expression 75/100** (productive to expressive: expressive): type ratio 1.333, hero moments: 1-2-per-product, expressive motion: throughout, brand color role: brand-chrome-allowed, containment: visible-containers.
- **Brand presence 65/100** (native to brand-led: leaning brand-led): typeface suggestion: open-custom-face, brand color placement: accent+signature-surface, native component share about 56%, voice guidance: short.
- **Density 15/100** (spacious to compact: spacious): body 16px on the web, default control 48px, density mode spacious, icons 24px; hit areas never shrink.
- **Energy 5/100** (calm to energetic: calm): standard easing [0.77, 0, 0.175, 1], duration multiplier 0.82, spring damping 1.0, heading weight 600, navigation: recessive.
- **Roundness 95/100** (sharp to soft: soft): control radius full, icon corners rounded, caps round.
- **Depth 90/100** (flat to deep: deep): depth model: materials.
- **Colorfulness 60/100** (monochrome to vivid: leaning vivid): scheme tonalSpot, accent chroma 39.6 (HCT), 3 accent(s), surfaces: tinted-containers.
- **Warmth 75/100** (cool/formal to warm/friendly: warm/friendly): neutral tint chroma 0.013 at hue 58, borders: soft, sentence-case, contractions encouraged.

**Zoom by area** (sketch, broad, defined, detailed). You can stop at any level; each one works.

| Area | Zoom | Next questions |
|---|---|---|
| Colors | sketch | Q-color-02 |
| Typography | broad | Q-type-03, Q-type-04, Q-type-17 |
| Layout | sketch | Q-space-01, Q-space-02, Q-space-03 |
| Elevation & Depth | defined | Q-depth-02, Q-depth-03, Q-depth-05 |
| Shapes | sketch | Q-shape-01 |
| Components | sketch | Q-comp-01, Q-comp-02, Q-state-01 |
| Motion | broad | Q-motion-07, Q-motion-08 |
| Modes and Themes | sketch | Q-theme-03 |
| Iconography and Imagery | sketch | Q-icon-01, Q-icon-02, Q-icon-06 |
| Content and Voice | sketch | Q-voice-01, Q-voice-02, Q-voice-03 |
| Accessibility | sketch | Q-aud-02, Q-aud-03, Q-aud-04 |
| Platforms and Devices | sketch | Q-plat-05, Q-plat-10, Q-plat-08 |

The tokens in `opendesigner/tokens/` (DTCG 2025.10 with `opendesigner.resolver.json`) are the source of truth. This file is a generated view.

Decisions: D-0002 (answers.Q-aud-01), D-0007 (macros), D-0023 (dials.expression), D-0024 (dials.brandPresence), D-0025 (dials.density).

</details>

## Colors

> Zoom: sketch (0 of 3), 9 decisions in this area. To zoom in, answer Q-color-02.
<!-- od:zoom area=color level=0 -->

**Three accent colors: an orange picked for you (`#E8A48A`) marks buttons, links and focus; `#c67ea8`, `#7a67c4` add highlights.** Everything else stays neutral.
Designers: primary or brand accent · Code: `color.bg.accent`

<details><summary>More</summary>

**Your answers here** (each one either sets tokens or is a rule for this section):
- Do you have fixed brand colors, or should I build the palette from one color? **Keep your exact brand colors and tune the shades by hand (Carbon, Primer, Atlassian, GOV.UK)** (delegated; tokens; Q-color-01)
- How many accent colors does the product need? **One accent with nearby hues for backgrounds and drawings** (delegated; tokens; Q-color-04)
- How dark should dark mode be: pure black, near-black, or charcoal? **Near-black #0D1117 to #161616** (delegated; tokens; Q-color-21)

**Intent.** Brand color `#E8A48A` drives the accent ramp's hue; the Colorfulness dial (60) sets its chroma (scheme tonalSpot, peak HCT chroma 39.6). The brand's role is **brand-chrome-allowed** and it sits closest to accent step 9. Picked for you, not chosen by you: an orange (#E8A48A) on buttons, links and focus, with dark text on it.

**How ramps are built.** Each hue gets twelve steps in OKLCH, placed by contrast. Step 8 reaches at least 3:1 (edges and focus). Steps 10 and 11 reach the text minimum on backgrounds 1-4. Step 12 reaches at least 7:1. Steps 2-6 are spaced evenly in lightness between step 1 and step 7. Light and dark ramps are solved separately. Dark solids are lighter and carry dark text (dark mode is a separate mapping, never an inversion). Text minimum: 4.5:1 (WCAG 2.2 AA).

| Ramp | Light steps 1-12 | Solid carries |
|---|---|---|
| `accent` | `#fffcfb` `#faf3f0` `#f8e8e3` `#f6ded5` `#f4d4c7` `#f2c9ba` `#f0bfac` `#b37861` `#e8a48a` `#e09274` `#93533b` `#4a2c21` | dark |
| `accent2` | `#fffcfd` `#f9f3f6` `#f6e8ef` `#f3dde9` `#f0d3e2` `#edc8dc` `#e9bdd5` `#ab7694` `#c67ea8` `#d38db5` `#8b5273` `#472b3b` | dark |
| `accent3` | `#fdfcff` `#f4f3fc` `#eceafb` `#e3e0fc` `#dbd6fc` `#d2cdfc` `#cac3fc` `#887dc3` `#7a67c4` `#6e5cb3` `#5b4c97` `#352f53` | light |
| `danger` | `#fffcfc` `#fcf2f1` `#fde7e4` `#fedbd7` `#fed0ca` `#fec4bd` `#feb9b0` `#c26f66` `#c0534a` `#b04941` `#933a34` `#522723` | light |
| `info` | `#fbfdff` `#edf5fc` `#dceefc` `#cae7fc` `#b8e0fd` `#a5d8fd` `#92d1fd` `#348dc4` `#007cb7` `#0070a6` `#005c8a` `#043753` | light |
| `neutral` | `#fcfdff` `#f3f3fe` `#eaeaf9` `#e1e1f4` `#d8d9ef` `#cfd0e9` `#c7c7e4` `#8383a2` `#737293` `#616181` `#555470` `#242428` | light |
| `success` | `#fafefb` `#eef6ef` `#e0efe2` `#d0e9d4` `#c0e3c6` `#b1dcb8` `#a1d6ab` `#4e945f` `#158740` `#0b7a38` `#01652c` `#163b20` | light |
| `warning` | `#fffcf9` `#f8f4ec` `#f4eadb` `#f0e1c9` `#ecd8b7` `#e8cfa5` `#e4c592` `#a6803a` `#eab34f` `#d8a446` `#845d00` `#44300a` | dark |

**Step-distance guarantee** (neutral, light; WCAG contrast of a foreground step on background steps 1-5):

| Foreground | on 1 | on 2 | on 3 | on 4 | on 5 |
|---|---|---|---|---|---|
| neutral 8 | 3.60 | 3.32 | 3.08 | 2.84 | 2.63 |
| neutral 9 | 4.53 | 4.18 | 3.87 | 3.57 | 3.31 |
| neutral 10 | 5.84 | 5.39 | 4.99 | 4.60 | 4.27 |
| neutral 11 | 7.14 | 6.60 | 6.11 | 5.64 | 5.22 |
| neutral 12 | 15.19 | 14.04 | 12.99 | 11.99 | 11.11 |

**States.** Hover is at least 1.15:1 from its fill and pressed at least 1.3:1, as shade steps (DC-L01-17). Where a color is unknown at design time, use the state opacities in `opacity.state.*`.

| Fill | Base | Hover | Pressed |
|---|---|---|---|
| `color.bg.action.primary` | `#e8a48a` | `#e09274` (1.18:1) | `#d5886a` (1.34:1) |
| `color.bg.accent.bold` | `#e8a48a` | `#e09274` (1.18:1) | `#d5886a` (1.34:1) |

**Semantic roles** (use these, never the ramps):

| Token | Light | Dark | Use |
|---|---|---|---|
| `color.bg.accent.bold` | `#e8a48a` | `#e8a48a` | Solid accent fill. |
| `color.bg.accent.bold-hover` | `#e09274` | `#f8b499` | Hover: one step, at least 1.15:1 from the solid (DC-L01-17). |
| `color.bg.accent.bold-pressed` | `#d5886a` | `#ffc2ab` | Pressed: at least 1.3:1 from the solid. |
| `color.bg.accent.subtle` | `#f8e8e3` | `#312520` | Selected rows, accent badges. |
| `color.bg.accent.subtle-hover` | `#f6ded5` | `#3d2c25` | Hover on accent subtle fills. |
| `color.bg.accent.subtle-pressed` | `#f4d4c7` | `#4a3229` | Pressed accent subtle fills. |
| `color.bg.accent2.bold` | `#c67ea8` | `#be83a5` | accent2 solid fill. |
| `color.bg.accent2.bold-hover` | `#d38db5` | `#cc91b3` | Hover: one step, at least 1.15:1 from the solid (DC-L01-17). |
| `color.bg.accent2.bold-pressed` | `#de97c0` | `#d89bbd` | Pressed: at least 1.3:1 from the solid. |
| `color.bg.accent2.subtle` | `#f6e8ef` | `#30252b` | accent2 subtle fill. |
| `color.bg.accent3.bold` | `#7a67c4` | `#867ac6` | accent3 solid fill. |
| `color.bg.accent3.bold-hover` | `#6e5cb3` | `#9387d4` | Hover: one step, at least 1.15:1 from the solid (DC-L01-17). |
| `color.bg.accent3.bold-pressed` | `#6654aa` | `#9d91df` | Pressed: at least 1.3:1 from the solid. |
| `color.bg.accent3.subtle` | `#eceafb` | `#282634` | accent3 subtle fill. |
| `color.bg.action.primary` | `#e8a48a` | `#e8a48a` | Primary action. One per view (DC-L15-03, L15 P08). |
| `color.bg.action.primary-hover` | `#e09274` | `#f8b499` | Hover: one step, at least 1.15:1 from the solid (DC-L01-17). |
| `color.bg.action.primary-pressed` | `#d5886a` | `#ffc2ab` | Pressed: at least 1.3:1 from the solid. |
| `color.bg.brand` | `#e8a48a` | `#e8a48a` | Brand fill for signature surfaces; carries text.on-brand (brandAnchor rule, DC-L01-09). |
| `color.bg.danger.bold` | `#c0534a` | `#c56a61` | Danger solid fill. |
| `color.bg.danger.bold-hover` | `#b04941` | `#d3776e` | Hover: one step, at least 1.15:1 from the solid (DC-L01-17). |
| `color.bg.danger.bold-pressed` | `#a64039` | `#de8177` | Pressed: at least 1.3:1 from the solid. |
| `color.bg.danger.subtle` | `#fde7e4` | `#352421` | Danger banner and badge background. |
| `color.bg.disabled` | `#eaeaf9` | `#2c2c3a` | Disabled control fill. |
| `color.bg.field` | `#ffffff` | `#24242f` | Text field fill: outlined fields sit on the raised surface (Q-form-01). |
| `color.bg.info.bold` | `#007cb7` | `#248cc7` | Info solid fill. |
| `color.bg.info.bold-hover` | `#0070a6` | `#3699d6` | Hover: one step, at least 1.15:1 from the solid (DC-L01-17). |
| `color.bg.info.bold-pressed` | `#006799` | `#42a3e0` | Pressed: at least 1.3:1 from the solid. |
| `color.bg.info.subtle` | `#dceefc` | `#1a2934` | Info banner and badge background. |
| `color.bg.inverse` | `#242428` | `#e8e9ef` | Tooltips and toasts: the inverted surface. |
| `color.bg.neutral.subtle` | `#eaeaf9` | `#353546` | Secondary buttons, chips, hovered rows. |
| `color.bg.neutral.subtle-hover` | `#e1e1f4` | `#3e3d52` | Hover: +1 step (DC-L01-17). |
| `color.bg.neutral.subtle-pressed` | `#d8d9ef` | `#46465e` | Pressed or selected: +2 steps (DC-L01-17). |
| `color.bg.success.bold` | `#158740` | `#46935a` | Success solid fill. |
| `color.bg.success.bold-hover` | `#0b7a38` | `#53a066` | Hover: one step, at least 1.15:1 from the solid (DC-L01-17). |
| `color.bg.success.bold-pressed` | `#007131` | `#5daa6f` | Pressed: at least 1.3:1 from the solid. |
| `color.bg.success.subtle` | `#e0efe2` | `#1d2b20` | Success banner and badge background. |
| `color.bg.warning.bold` | `#eab34f` | `#e2b66a` | Warning solid fill. |
| `color.bg.warning.bold-hover` | `#d8a446` | `#f3c67a` | Hover: one step, at least 1.15:1 from the solid (DC-L01-17). |
| `color.bg.warning.bold-pressed` | `#cd9a3a` | `#ffd388` | Pressed: at least 1.3:1 from the solid. |
| `color.bg.warning.subtle` | `#f4eadb` | `#2e271a` | Warning banner and badge background. |
| `color.border.accent` | `#b37861` | `#ac755f` | Selected card or accent outline. |
| `color.border.danger` | `#c26f66` | `#bb6c64` | Danger boundary, for example an invalid field (3:1). |
| `color.border.default` | `#cfd0e9` | `#3e3d52` | Outlines (soft borders). |
| `color.border.focus` | `#93533b` | `#ffbea6` | Focus ring (3:1 against every surface, DC-L04-09). |
| `color.border.info` | `#348dc4` | `#3789bc` | Info boundary, for example an invalid field (3:1). |
| `color.border.input` | `#8383a2` | `#7e7e9c` | Text field and select borders (3:1, DC-L01-16). |
| `color.border.strong` | `#8383a2` | `#7e7e9c` | Boundaries that are the only cue: inputs, checkboxes, switches (3:1, WCAG 1.4.11). |
| `color.border.subtle` | `#d8d9ef` | `#353546` | Dividers (soft borders: Warmth 67+, Linear 2026 S-L06-067). |
| `color.border.success` | `#4e945f` | `#4e8f5d` | Success boundary, for example an invalid field (3:1). |
| `color.border.warning` | `#a6803a` | `#a07c3c` | Warning boundary, for example an invalid field (3:1). |
| `color.icon.accent` | `#93533b` | `#ffbea6` | Selected and interactive icons. |
| `color.icon.default` | `#555470` | `#a8a9c8` | Icons beside text; same color as secondary text (DC-L05-08). |
| `color.icon.on-accent` | `#242428` | `#151519` | Icons on solid accent fills. |
| `color.icon.subtle` | `#616181` | `#9292b4` | Decorative icons. |
| `color.overlay.scrim` | `#242428 @0.45` | `#000000` | Modal backdrop (DC-L04-18; Q-depth-06). |
| `color.surface.base` | `#fcfdff` | `#1c1c24` | The page background. |
| `color.surface.glass` | `#ffffff @0.72` | `#24242f` | Glass for controls and navigation only, never content (DC-L04-15). |
| `color.surface.glass-dimming` | `#000000 @0.35` | `#000000` | 35% dimming under clear glass over bright content (S-L15-073). |
| `color.surface.glass-fallback` | `#ffffff` | `#2c2c3a` | Solid twin under Reduce Transparency and Increase Contrast (DC-L04-16). |
| `color.surface.nav` | `#f3f3fe` | `#151519` | Recessive navigation, dimmer than content (Linear 2026, S-L06-067). |
| `color.surface.overlay` | `#ffffff` | `#2c2c3a` | Menus, popovers, dialogs; always with elevation.floating or elevation.overlay. |
| `color.surface.raised` | `#ffffff` | `#24242f` | Cards and panels on the page. |
| `color.surface.sunken` | `#f3f3fe` | `#151519` | Wells, code blocks, page gutters. |
| `color.surface.tinted` | `#faf3f0` | `#251f1c` | Tinted container (Colorfulness 50+, L09 X rubric; Q-color-05). |
| `color.text.accent` | `#93533b` | `#ffbea6` | Accent text and selected labels. |
| `color.text.accent2` | `#8b5273` | `#d49cbc` | accent2 text. |
| `color.text.accent3` | `#5b4c97` | `#aea3ed` | accent3 text. |
| `color.text.danger` | `#933a34` | `#ed958b` | Danger text and icons; pair with an icon or label (DC-L01-15). |
| `color.text.disabled` | `#8383a2` | `#7e7e9c` | Disabled labels; exempt from contrast minimums (WCAG 1.4.3 exception). |
| `color.text.info` | `#005c8a` | `#5eb5ee` | Info text and icons; pair with an icon or label (DC-L01-15). |
| `color.text.inverse` | `#ffffff` | `#151519` | Text on color.bg.inverse (tooltips, toasts). |
| `color.text.link` | `#93533b` | `#ffbea6` | Links. Underline them in running text so color is not the only cue. |
| `color.text.on-accent` | `#242428` | `#151519` | Text and icons on color.bg.accent.bold* (auto-picked light or dark, S-L06-094). |
| `color.text.on-accent2` | `#242428` | `#151519` | Text on accent2 solid. |
| `color.text.on-accent3` | `#ffffff` | `#151519` | Text on accent3 solid. |
| `color.text.on-action` | `#242428` | `#151519` | Text on the primary action fill. |
| `color.text.on-brand` | `#242428` | `#151519` | Text on color.bg.brand. |
| `color.text.on-danger` | `#ffffff` | `#151519` | Text on bg.danger.bold. |
| `color.text.on-info` | `#ffffff` | `#151519` | Text on bg.info.bold. |
| `color.text.on-success` | `#ffffff` | `#151519` | Text on bg.success.bold. |
| `color.text.on-warning` | `#242428` | `#151519` | Text on bg.warning.bold. |
| `color.text.primary` | `#242428` | `#e8e9ef` | Body copy, headings, labels (guaranteed >= 7:1 on steps 1-5). |
| `color.text.secondary` | `#555470` | `#a8a9c8` | Supporting text (guaranteed >= the text minimum on surfaces and neutral fills 1-4). |
| `color.text.success` | `#01652c` | `#74bc84` | Success text and icons; pair with an icon or label (DC-L01-15). |
| `color.text.tertiary` | `#616181` | `#9292b4` | Captions and placeholders (still meets the text minimum on surfaces 1-4). |
| `color.text.warning` | `#845d00` | `#fad08a` | Warning text and icons; pair with an icon or label (DC-L01-15). |

**Use / avoid.**
- Use one solid accent fill per view for the primary action; spend chroma on small, meaningful elements.
- Avoid gray text on colored fills; use the matching `text.on-*` role.
- Avoid color as the only signal: pair status colors with an icon or label.
- Charts: no chart palette yet (Q-color-19). Take chart colors from the status and accent hues, and check them separately.

**Tailwind classes:** `bg-action-primary`, `hover:bg-action-primary-hover`, `active:bg-action-primary-pressed`, `text-on-action`, `bg-surface-base`, `bg-surface-raised`, `text-fg-primary`, `text-fg-secondary`, `text-fg-link`, `border-line-subtle`, `border-line-input`, `outline-line-focus`, `bg-danger-bold`.

Decisions: D-0009 (answers.Q-theme-01), D-0011 (answers.Q-color-01), D-0012 (raw.brandColor), D-0013 (raw.neutralBase), D-0014 (answers.Q-color-21), D-0029 (dials.colorfulness), D-0030 (dials.warmth), D-0033 (answers.Q-color-04), D-0034 (raw.secondaryColors).

</details>

## Typography

> Zoom: broad (1 of 3), 8 decisions in this area. To zoom in, answer Q-type-03, Q-type-04, Q-type-17.
<!-- od:zoom area=typography level=1 -->

**Body text is 17px, and each larger size is about 1.333 times the one below.**
Designers: type scale: base size and ratio · Code: `font.size.14`

<details><summary>More</summary>

**Your answers here** (each one either sets tokens or is a rule for this section):
- Should it use the device's built-in font, a free plain font like Inter, or your brand font? **Brand font for headlines, system font for body (Apple's advice)** (delegated; tokens; Q-type-01)
- Do you have the brand font files? **Yes** (delegated; asset status; Q-type-02)
- What size should body text be? **17pt (iOS Body)** (delegated; tokens; Q-type-08)
- How much bigger should each text size be than the one below it? **Hand-tuned list (11-15 named styles in 12 systems; only Carbon and Ant use a formula)** (delegated; a rule here; Q-type-09)
- How many text styles, and how should they be named? **Named semantic styles (Apple's 11** (delegated; a rule here; Q-type-10)

**Intent.** Body text is 17px; sizes follow `round(17 x 1.333^n)` for n from -2 to 6, reaching about 6.0x body (product surfaces only). Sizes: 13, 17, 23, 30, 40, 54, 72, 95px.

- Text face: Instrument Sans, system-ui, -apple-system, Segoe UI, Roboto, Helvetica Neue, Arial, sans-serif. Licence status (hook H-type): **have**.
- Licence by platform: text: Instrument Sans (open licence or system font: web, apps and self-hosting); display: Instrument Serif: licensed for web, apps, self-hosting.
- On iOS the Swift file uses Dynamic Type text styles (body 17 pt), so text follows the person's text size setting; Compose uses sp, which follows the Android font scale.
- Weights: body 400, label 500, heading 600, display 700 (two or three distinct weights per view).
- Emphasized variants (Expression 75, on from 67): 11 styles under `text.emphasized.*`, the same size one weight heavier, for the selected item, key actions and headlines (DC-L02-11).
- Line heights snap to a 4px grid: 1.5 up to 17px, 1.4 to 26px, 1.25 to 44px, 1.12 above.
- Letter spacing: +0.02em at 11-12px, -0.01em from 32px, -0.02em from 48px.
- Text scaling: CSS sizes are rem, line heights unitless, so text scales to 200% (WCAG 1.4.4); containers must grow with it.
- Scripts: Latin only; add scripts in raw.scripts to get per-script line heights (DC-L02-25).

| Style | Size/line (px) | Weight | Tracking | Use |
|---|---|---|---|---|
| `text.body.lg` | 20/32 | 400 | 0em | Long-form reading, onboarding copy. |
| `text.body.md` | 17/24 | 400 | 0em | Default UI text: forms, tables, descriptions. |
| `text.body.sm` | 15/20 | 400 | 0em | Helper text, timestamps, captions. |
| `text.code.md` | 17/24 | 400 | 0em | Code blocks, token names. |
| `text.code.sm` | 13/20 | 400 | 0em | Inline values, dense code rows. |
| `text.display.sm` | 95/108 | 700 | -0.02em | One hero line per page: marketing, empty states. |
| `text.headline.lg` | 72/80 | 600 | -0.02em | Page and section titles. |
| `text.headline.md` | 34/60 | 600 | -0.02em | Page and section titles. |
| `text.headline.sm` | 28/48 | 600 | -0.01em | Page and section titles. |
| `text.label.lg` | 17/24 | 500 | 0em | Button and control labels. |
| `text.label.md` | 13/20 | 500 | 0em | Small control labels, badges, dense tabs. |
| `text.label.sm` | 11/20 | 500 | 0.05em caps | Overlines in capitals with wide tracking (DC-L02-18). |
| `text.title.lg` | 22/36 | 600 | 0em | Card, panel and group titles. |
| `text.title.md` | 20/32 | 600 | 0em | Card, panel and group titles. |
| `text.title.sm` | 17/24 | 600 | 0em | Table headers, field-group titles. |

**Use / avoid.**
- Use at most three sizes and two weights in one view; let color and weight carry hierarchy before size.
- Avoid all caps for sentences and in scripts without case; use weight for emphasis there.

**Tailwind classes:** `text-body-md`, `text-label-lg`, `text-title-md`, `text-headline-md`.

Decisions: D-0017 (answers.Q-type-01), D-0018 (raw.displayFace), D-0019 (raw.textFace), D-0020 (answers.Q-type-02), D-0021 (answers.Q-type-08), D-0022 (overrides.type.displayReach), D-0035 (answers.Q-type-10), D-0036 (answers.Q-type-09).

</details>

## Layout

> Zoom: sketch (0 of 3), 1 decision in this area. To zoom in, answer Q-space-01, Q-space-02, Q-space-03.
<!-- od:zoom area=layout level=0 -->

**Spacing comes in steps of 4px, and screens use spacious spacing by default.**
Designers: spacing scale, 0 to 96 · Code: `space.0 to space.96`

<details><summary>More</summary>

**Intent.** Everything sits on a 4px unit: ladder 0, 2, 4, 6, 8, 12, 16, 20, 24, 32, 40, 48, 64, 80, 96. Density is a mode on the semantic layer (default **spacious**). Primitives and minimum tap areas never change.

| Density | inset xs/sm/md/lg/xl | section sm/md/lg | control sm/md/lg | outer:inner |
|---|---|---|---|---|
| spacious (default) | 6 / 12 / 16 / 20 / 32 | 64 / 80 / 96 | 40 / 48 / 56 | 3.5 |
| comfortable | 4 / 8 / 12 / 16 / 24 | 32 / 40 / 64 | 32 / 40 / 48 | 2.5 |
| compact | 2 / 6 / 8 / 12 / 20 | 16 / 24 / 40 | 24 / 32 / 40 | 2.0 |

- Target sizes: pointer 24px, touch 44px; `size.target.min` is the floor for the primary input, and `space.target.gap` separates adjacent targets.
- Inner gaps stay below outer gaps (at least half), so grouping reads without borders (L15 P16).
- Breakpoints and grid: not generated yet; use the platform defaults and keep layout spacing independent of density (DC-L03-17).

**Use / avoid.**
- Parents own spacing (padding and gap); children never set outer margins.
- Avoid values off the ladder; if one is needed, add it as a decision.

Decisions: D-0025 (dials.density).

</details>

## Elevation & Depth

> Zoom: defined (2 of 3), 3 decisions in this area. To zoom in, answer Q-depth-02, Q-depth-03, Q-depth-05.
<!-- od:zoom area=elevation level=2 -->

**Controls and bars can be see-through glass, with solid fallbacks.**
Designers: flat, shadowed, tonal or glass · Code: `$extensions.opendesigner.model`

<details><summary>More</summary>

**Your answers here** (each one either sets tokens or is a rule for this section):
- How should cards and panels stand out from the page: shadows, color steps, lines, or glass? **Materials and glass** (delegated; tokens; Q-depth-01)
- Should menus, bars and pop-ups be see-through glass, or stay solid? **Glass on navigation and controls only, never on content (Apple Liquid Glass** (delegated; tokens; Q-depth-04)

**Intent.** Depth 90/100 selects the **materials** model. Shadow alpha in light mode is 0.221; dark mode doubles it and lifts surfaces by lightness instead (sunken, base, raised, overlay).

| Token | Layers (x y blur spread) | Use |
|---|---|---|
| `elevation.raised` | 0 0 2 0, 0 1 2 0 | Cards that lift on hover, sticky headers, dragged rows. |
| `elevation.floating` | 0 0 2 0, 0 4 8 0 | Menus, popovers, dropdowns. |
| `elevation.overlay` | 0 0 2 0, 0 14 28 0 | Dialogs and sheets (with color.overlay.scrim). |

- Borders: 1px default, 2px selected and focus, 4px emphasis; width changes use an inset shadow so layout does not jump.
- Stacking: page < raised < floating (menus) < overlay (dialogs with `color.overlay.scrim`).
- Glass is for controls and navigation only, with `color.surface.glass-fallback` under Reduce Transparency.

Decisions: D-0015 (answers.Q-depth-01), D-0031 (dials.depth), D-0032 (answers.Q-depth-04).

</details>

## Shapes

> Zoom: sketch (0 of 3), 1 decision in this area. To zoom in, answer Q-shape-01.
<!-- od:zoom area=shape level=0 -->

**Buttons and fields have fully round corners; cards have 20px corners.**
Designers: corner radius, sharp to pill · Code: `radius.control, CSS border-radius`

<details><summary>More</summary>

**Intent.** Roundness 95/100 gives controls a **full** radius; details 4px, containers 20px, overlays 28px, people full. Controls under 32px tall use `radius.control-sm` (full).

- Nested radius: inner = max(outer - padding, smallest step). Here it is 2px inside a container with `space.inset.lg` padding. Equal radii on nested shapes look uneven (DC-L04-05).
- Focus ring: 2px, 2px offset, radius = control radius + offset (full).
- Icons: rounded corners, round caps. On iOS, use continuous corners (DC-L04-04).
- Signature shapes: none generated; a brand shape library is a designer asset (hook H-motif).

Decisions: D-0027 (dials.roundness).

</details>

## Components

> Zoom: sketch (0 of 3), 0 decisions in this area. To zoom in, answer Q-comp-01, Q-comp-02, Q-state-01.
<!-- od:zoom area=components level=0 -->

**Version 1 plans 25 components, all built from these tokens.**
Designers: core set of about 25 components · Code: `button.* (proposed), APG pattern`

<details><summary>More</summary>

**Intent.** v1 components use the semantic tokens only. Base: not chosen yet (Q-comp-01). Buttons are 48px tall (spacious), full radius, `text.label.lg`; one primary action per view.

| Component | Status |
|---|---|
| button | planned (tokens ready) |
| text-field | planned (tokens ready) |
| textarea | planned (tokens ready) |
| select | planned (tokens ready) |
| checkbox | planned (tokens ready) |
| radio | planned (tokens ready) |
| switch | planned (tokens ready) |
| slider | planned (tokens ready) |
| tabs | planned (tokens ready) |
| tooltip | planned (tokens ready) |
| popover | planned (tokens ready) |
| dialog | planned (tokens ready) |
| menu | planned (tokens ready) |
| progress-bar | planned (tokens ready) |
| spinner | planned (tokens ready) |
| banner | planned (tokens ready) |
| badge | planned (tokens ready) |
| avatar | planned (tokens ready) |
| card | planned (tokens ready) |
| list | planned (tokens ready) |
| table | planned (tokens ready) |
| link | planned (tokens ready) |
| breadcrumbs | planned (tokens ready) |
| side-navigation | planned (tokens ready) |
| accordion | planned (tokens ready) |

**Contested policies:** Validation timing and disabled submit: pending; Field style: pending; Toasts: pending; Undo versus confirm: pending; Danger actions: pending; Button emphasis levels: pending.

**Use / avoid.**
- Every interactive component shows hover, pressed, focus-visible and disabled states from the tokens.
- Inputs keep a 3:1 boundary (`color.border.input`); signifier strength: minimal-allowed.
- Component docs belong in `opendesigner/components/<name>.md` (spec 7.8).

Decisions: none recorded yet; values are defaults from references/levers.json.

</details>

## Do's and Don'ts

**These rules keep screens clear and easy to read.** The engine checks the ones it can.
Designers: guardrails and design linting · Code: `engine.py validate, engine.py review`

<details><summary>More</summary>

**Enforced by construction.** The generator cannot break these:
- text contrast 4.5:1, and 3:1 for edges, in every mode
- text on colored fills picked automatically
- tap areas pointer 24px, touch 44px
- a 2px focus ring with a 2px offset
- a reduced-motion mode
- inner spacing smaller than outer spacing, three text colors, and nested radii

**Do**
- Use semantic tokens; never raw hex, px or ms values in components.
- Keep one primary action per view and at most three type sizes per view.
- Pair every status color with an icon or label; underline links in running text.

**Don't**
- Don't shrink hit areas in dense layouts; shrink visuals and extend the hit area.
- Don't use motion as the only signal, or flash more than three times a second.
- Don't copy another brand's identity from a reference (colors, typeface, logo, imagery, copy).

**Current validation findings:** warn: light: color.bg.action.primary (#e8a48a) on color.surface.base (#fcfdff) is 2.04:1, needs 3.0:1, warn: light: color.bg.action.primary (#e8a48a) on color.surface.raised (#ffffff) is 2.08:1, needs 3.0:1, warn: 14 text sizes; 8 to 10 is the usual range

**Waivers:** none.

</details>

## Standards

**Follow these rules when you build.** They come from sources marked non-negotiable, their values are locked, and `engine.py review` checks the ones it can.

House standards v2: 339 rules followed in this project.

**Don't break these:**
- No motion on 100+ times-a-day actions (STD-when-to-animate-05).
- Never use ease-in on UI (STD-easing-duration-03).
- Never enter from scale(0) (STD-enter-exit-origin-01).
- Never block input during transitions (STD-springs-gestures-13).
- Never rely on haptics alone (STD-accessibility-motion-20).

<details><summary>Every theme (185 rules)</summary>

- **When to animate** (15 rules, 13 must): Decide whether to animate first; Name a valid purpose for every animation; Scale motion down as frequency rises; No motion on 100+ times-a-day actions; Never animate keyboard-initiated actions; Remove or shrink motion seen tens-of-times daily; Spend delight only on rare moments; Explanatory motion only in marketing, onboarding; and 5 more must rules. Locks `motion.duration.instant` 0ms.
- **Easing and duration** (12 rules, 10 must): Pick easing by the motion's job; Strong custom curves, not built-in keywords; Never use ease-in on UI; UI motion under 300ms unless justified; Duration budget for each element; Nothing over 1s unless illustrative; Duration grows with size and distance; Slow deliberate phase, snappy response; and 2 more must rules. Locks `motion.easing.linear` [0, 0, 1, 1], `motion.easing.hover` [0.25, 0.1, 0.25, 1], `motion.easing.enter` [0.23, 1, 0.32, 1], `motion.easing.exit` [0.23, 1, 0.32, 1], `motion.easing.standard` [0.77, 0, 0.175, 1], `motion.duration.micro` 100ms, `motion.duration.short` 150ms, `motion.duration.medium` 200ms, `motion.duration.long` 250ms.
- **Enter, exit and origin** (10 rules, 7 must): Never enter from scale(0); No opacity-only fade entrances; Exit the way it entered; Stagger group entrances 30–80ms; Measure heights, never animate to auto; React Native: never animate header height; No entering on virtualized rows. Locks `motion.scale.enter` 0.95, `motion.duration.stagger` 50ms.
- **Springs and gestures** (28 rules, 19 must): Springs for anything a finger drives; Default springs are critically damped; Bounce only after a momentum gesture; Keep bounce subtle, 0.1 to 0.3; Sheet and drawer spring values; Every animation can be grabbed mid-flight; Never block input during transitions; Start from the on-screen value; and 11 more must rules. Locks `motion.spring.spatial.dampingRatio` 1.0, `motion.spring.spatial.stiffness` 246.7, `motion.spring.momentum` a composite value (see standards.md), `motion.spring.sheet` a composite value (see standards.md), `motion.spring.rotation` a composite value (see standards.md), `motion.gesture.deceleration-rate` 0.998, `motion.gesture.dismiss-velocity` 0.11, `motion.gesture.rubberband-constant` 0.55, `motion.gesture.direction-threshold` 10px.
- **Performance and properties** (9 rules, 7 must): Animate only transform and opacity; Only clip-path, accordion height, childless width; Keep per-frame values out of React state; Pick the cheapest animation tool; Treat dropped frames as a regression; Keep React Native motion on the UI thread; Crossfade static layers, not elevation or blur.
- **Accessibility in motion** (9 rules, 5 must): Ship reduced motion with the animation; Reduced motion is gentler, never zero; Scale layout with the user's text size; Never rely on haptics alone; Never trap the user in an overlay. Locks `raw.reducedMotion` "replace", `motion.duration.reduced-fade` 200ms, `reduced:motion.transition.enter` a composite value (see standards.md), `reduced:motion.transition.exit` a composite value (see standards.md), `reduced:motion.transition.expand` a composite value (see standards.md).
- **Toasts, drawers and overlays** (10 rules, 4 must): React Native toasts: 300ms in, 250ms out; Drawer curve: cubic-bezier(0.32, 0.72, 0, 1); React Native: form sheets on both platforms; Feedback on press, commit on release. Locks `component.toast.duration` 4000ms, `motion.easing.drawer` [0.32, 0.72, 0, 1], `motion.gesture.drag-lock-after-scroll` 100ms.
- **Mobile and touch** (22 rules, 18 must): Press feedback scales to 0.97, briefly; Touch targets 44pt on iOS, 48dp on Android; Paint edge to edge, pad the safe areas; Ignore extra fingers during a drag; Redesign hover affordances for touch; Use Gesture Handler, never PanResponder; Use scheduleOnRN, not runOnJS; Cross to the JS thread only at thresholds; and 10 more must rules. Locks `motion.scale.press` 0.97, `motion.duration.micro` 100ms (STD-easing-duration-07 wins), `size.target.touch` 44px, `size.target.min` 44px, `motion.spring.spatial.dampingRatio` 1.0 (STD-springs-gestures-04 wins).
- **Visual details** (41 rules, 13 must): Tabular digits for changing numbers; Use the ellipsis character; Loosen tracking on uppercase labels; Make letter-spacing specific to size; Reserve underlines for links; Never stack light translucent surfaces; Restrained look with no project; Use and extend existing tokens; and 5 more must rules.
- **Process, review and taste** (14 rules, 8 must): Motion that merely runs is not done; Self-check motion before finishing; Report review findings as one table; Close every motion review with Block or Approve; Make the motion call yourself; Keep the motion note to a few lines; Say when feel can't be judged from code; Judge feel on real hardware.
- **Swift** (15 rules, 11 must): Check the Swift toolchain first; Simplest, most static thing first; Value types by default; Make invalid states unrepresentable; Main actor first, then step down; Enable Approachable Concurrency everywhere; MainActor default isolation for app modules; Libraries ship nonisolated APIs; and 3 more must rules.

</details>

Every rule, with its values, reasons and sources: `opendesigner/standards.md` (it also has the 154 rules this file leaves out). Read the themes you touch before you build.

## Motion

> Zoom: broad (1 of 3), 2 decisions in this area. To zoom in, answer Q-motion-07, Q-motion-08.
<!-- od:zoom area=motion level=1 -->

**Motion is off: things change in place without moving.**
Designers: motion system: duration, easing, springs · Code: `motion.duration.*, motion.easing.*`

<details><summary>More</summary>

**Your answers here** (each one either sets tokens or is a rule for this section):
- Should motion be quick and barely seen, calm with a few bold moments, or physical and bouncy? **Minimal motion (GOV.UK)** (delegated; tokens; Q-motion-01)

**Intent.** Energy 5/100: the duration multiplier x0.82 scales the extra step (standards fix medium, long). Standard easing `cubic-bezier(0.77, 0, 0.175, 1)`, enter `cubic-bezier(0.23, 1, 0.32, 1)`, exit `cubic-bezier(0.23, 1, 0.32, 1)`. Spatial spring: damping 1.0, stiffness 246.7 (Apple duration 0.4s, bounce 0.0; web `linear()` sample over 590ms). Motion is off (flags.motionOff): standard equals reduced.

| Token | Value | Note |
|---|---|---|
| `motion.duration.instant` | 0ms | set by house standard STD-when-to-animate-05 |
| `motion.duration.micro` | 100ms | set by house standard STD-easing-duration-07 |
| `motion.duration.short` | 150ms | set by house standard STD-easing-duration-07 |
| `motion.duration.medium` | 200ms | set by house standard STD-easing-duration-07 |
| `motion.duration.long` | 250ms | set by house standard STD-easing-duration-07 |
| `motion.duration.extra` | 570ms | illustrative and marketing motion only, never UI (STD-easing-duration-06) |
| `motion.duration.medium-exit` | 160ms | derived: about 0.8 x medium |
| `motion.duration.long-exit` | 200ms | derived: about 0.8 x long |
| `motion.duration.reduced-fade` | 200ms | set by house standard STD-accessibility-motion-02 |
| `motion.duration.stagger` | 50ms | set by house standard STD-enter-exit-origin-13 |

- Exits are derived, not set on their own: each is about 20% shorter than the entrance in force (medium-exit 160ms from medium 200ms, long-exit 200ms from long 250ms; STD-easing-duration-11). Change an entrance and its exit follows. Linear easing only for spinners and progress.
- Reduced motion (`prefers-reduced-motion` or `data-motion="reduced"`): travel becomes opacity, feedback stays, `motion.transition.move` is 0ms.
- Springs are stored as damping and stiffness in `$extensions.opendesigner.spring` because DTCG 2025.10 has no spring type.
- Haptics: light intensity where the platform has them; sound: hook H-sound is pending.

Decisions: D-0010 (25 values, standards), D-0016 (answers.Q-motion-01), D-0026 (dials.energy).

</details>

## Modes and Themes

> Zoom: sketch (0 of 3), 1 decision in this area. To zoom in, answer Q-theme-03.
<!-- od:zoom area=modes level=0 -->

**The system has light and dark color modes, three spacing densities and a reduced-motion mode.**
Designers: modes: light, dark, density, motion · Code: `resolver modifiers, Figma collection modes`

<details><summary>More</summary>

**Your answers here** (each one either sets tokens or is a rule for this section):
- Should the app have light and dark modes that follow the device, or just one mode? **Light and dark, matching the device setting** (delegated; tokens; Q-theme-01)

**Intent.** Modes live in the DTCG resolver (`opendesigner/tokens/opendesigner.resolver.json`); modifiers are orthogonal, so no two set the same token.

| Modifier | Contexts | Default |
|---|---|---|
| theme | light, dark | light |
| density | spacious, comfortable, compact | spacious |
| motion | standard, reduced | reduced |

- Web: `prefers-color-scheme` with a `[data-theme]` override; `[data-density]`; `prefers-reduced-motion` with `[data-motion]` (see `opendesigner/build/css/tokens.css`).
- High-contrast themes are not generated; set `raw.contrastTarget` to AAA for 7:1 text everywhere.
- A second brand or a client re-skin may override the color primitives and `color.bg.brand`; semantic names never change.

Decisions: D-0009 (answers.Q-theme-01).

</details>

## Iconography and Imagery

> Zoom: sketch (0 of 3), 0 decisions in this area. To zoom in, answer Q-icon-01, Q-icon-02, Q-icon-06.
<!-- od:zoom area=iconography level=0 -->

**Icons are 24px by default.** The logo, photos and custom icons come from a person, not from the engine.
Designers: icon system: style, sizes, color · Code: `size.icon.*, icon.stroke.*, color.icon.*`

<details><summary>More</summary>

**Intent.** Default icon size 24px; sizes 16/20/24 pair with 14/16/20px text. Stroke follows the label weight: 1.5px at 16, 2.0px at 20, 2.5px at 24. Rest style: outline.

| Asset | Hook | Status |
|---|---|---|
| Logo and marks | H-logo | pending |
| Favicon set | H-favicon | pending |
| App icon | H-appicon | pending |
| Custom icons | H-icons | pending |
| Illustration | H-illus | pending |
| Photography | H-photo | pending |
| Motifs and brand shapes | H-motif | pending |

- Placeholders are labelled as placeholders. A generated stand-in is never shown as a finished brand asset.
- Icon-only buttons need an accessible name and a hit area of `size.target.min`.

Decisions: none recorded yet; values are defaults from references/levers.json.

</details>

## Content and Voice

> Zoom: sketch (0 of 3), 0 decisions in this area. To zoom in, answer Q-voice-01, Q-voice-02, Q-voice-03.
<!-- od:zoom area=content level=0 -->

**Words stay plain and short, and every button says what it does.**
Designers: content: voice, tone, microcopy · Code: `DESIGN.md Content and Voice section`

<details><summary>More</summary>

**Intent.** Draft: voice guidance level **short** (Brand presence 65); **sentence-case**; contractions **encouraged** (Warmth 75). Voice guide hook H-voice: pending.

- Buttons say what they do in two to four words; errors say what happened and how to fix it.
- Reading level: plain language; avoid jargon in UI copy.
- Word list: not recorded yet (Q-voice-03).

Decisions: none recorded yet; values are defaults from references/levers.json.

</details>

## Accessibility

> Zoom: sketch (0 of 3), 0 decisions in this area. To zoom in, answer Q-aud-02, Q-aud-03, Q-aud-04.
<!-- od:zoom area=accessibility level=0 -->

**Text passes WCAG 2.2 AA contrast in every mode, and focus is always visible.**
Designers: WCAG 2.2 AA target · Code: `raw.contrastTarget`

<details><summary>More</summary>

**Your answers here** (each one either sets tokens or is a rule for this section):
- Who uses it, and how often: all day for work, often, or now and then on the go? **Often, in an everyday app** (delegated; tokens; Q-aud-01)

**Intent.** Standard: WCAG 2.2 AA. APCA is reported as advice only.

**The system guarantees:**
- text and edge contrast in every mode
- visible focus (2px ring, 2px offset, 3:1)
- minimum target sizes for each kind of input
- a reduced-motion mode
- rem-based type, so text scales to 200%
- text on colored fills chosen automatically

**Product teams own:** accessible names and labels, alt text, reading and focus order, and never using color alone. Also: clear error messages, dialogs that can be closed, no pre-checked consent boxes, and captions for media.

**Test on each platform:**
- keyboard only
- a screen reader (VoiceOver, NVDA or TalkBack)
- 200% zoom
- forced colors (Windows High Contrast)
- reduced motion
- touch on a phone, for every surface that allows touch

Decisions: none recorded yet; values are defaults from references/levers.json.

</details>

## Platforms and Devices

> Zoom: sketch (0 of 3), 1 decision in this area. To zoom in, answer Q-plat-05, Q-plat-10, Q-plat-08.
<!-- od:zoom area=platforms level=0 -->

**It runs on ios, and each platform keeps its own navigation.**
Designers: target platforms · Code: `raw.platforms; size.target.min`

<details><summary>More</summary>

**Your answers here** (each one either sets tokens or is a rule for this section):
- Where will it run first: web, iOS, Android or desktop? **iOS/iPadOS** (delegated; tokens; Q-plat-01)

**Intent.** Platforms: ios. Inputs: pointer, touch. Brand presence 65: each platform keeps its own shapes and materials: no; each platform keeps its own body text size: no.

- Navigation, back, sheets and pickers stay native on every platform (DC-L10-02).
- Swift and Compose files in `opendesigner/build/` use the same names as the CSS variables (Figma code syntax matches them).
- Fonts by platform: text: Instrument Sans (open licence or system font: web, apps and self-hosting); display: Instrument Serif: licensed for web, apps, self-hosting.

Decisions: D-0006 (answers.Q-plat-01).

</details>

## Decisions

**55 decisions so far.** Each one says who set it and why.
Designers: decision history with reasons · Code: `opendesigner/decisions.md`

<details><summary>More</summary>

Your own decisions first (the newest value per path), then your changes to standards, then one row per standards batch. Full log: [opendesigner/decisions.md](opendesigner/decisions.md).

| Id | Path | Value | Set by | Reason |
|---|---|---|---|---|
| D-0002 | `answers.Q-aud-01` | "regular" | delegated | sketch: picked for them |
| D-0003 | `context.audience` | "people who use it often, as an everyday app" | delegated | sketch: plain words for Q-aud-01, picked for them |
| D-0006 | `answers.Q-plat-01` | ["ios"] | delegated | sketch: picked for them |
| D-0007 | `macros` | ["deferential", "minimal", "friendly"] | delegated | sketch: picked for them (feel words: calm, gentle) |
| D-0008 | `taste.feelWords` | ["calm", "gentle"] | delegated | sketch: feel words picked for them |
| D-0009 | `answers.Q-theme-01` | "system-light-dark" | delegated | sketch: picked for them |
| D-0011 | `answers.Q-color-01` | "keep-hex" | delegated | dusk peach is the brand; keep it exact |
| D-0012 | `raw.brandColor` | "#E8A48A" | delegated | restore the dusk peach the sketch turned into a brown; dark text passes on it |
| D-0013 | `raw.neutralBase` | "#231E4A" | delegated | night-indigo grays: the app lives after dark |
| D-0014 | `answers.Q-color-21` | "near-black" | delegated | deep night, not pure black (OLED smear on the slow orb) |
| D-0015 | `answers.Q-depth-01` | "glass" | delegated | frosted controls float over the living gradient |
| D-0016 | `answers.Q-motion-01` | "none" | delegated | a sleep screen should barely move; only the orb breathes |
| D-0017 | `answers.Q-type-01` | "brand-display" | delegated | a calm serif for the timer and title, a soft sans for controls |
| D-0018 | `raw.displayFace` | "Instrument Serif" | delegated | light, calm, condensed serif with a lovely italic (OFL) |
| D-0019 | `raw.textFace` | "Instrument Sans" | delegated | the serif's companion sans (OFL) |
| D-0020 | `answers.Q-type-02` | "yes" | delegated | both are SIL OFL from Google Fonts |
| D-0021 | `answers.Q-type-08` | 17 | delegated | iOS body 17pt |
| D-0022 | `type.displayReach` | 6 | delegated | the timer is the hero; it needs a step near 100px |
| D-0023 | `dials.expression` | 75 | delegated | an immersive player: the orb and the timer perform |
| D-0024 | `dials.brandPresence` | 65 | delegated | the dusk palette and serif are the brand |
| D-0025 | `dials.density` | 15 | delegated | very spacious; one thing at a time |
| D-0026 | `dials.energy` | 5 | delegated | the calmest possible; slow, soft |
| D-0027 | `dials.roundness` | 95 | delegated | circles and pills only; nothing sharp at bedtime |
| D-0029 | `dials.colorfulness` | 60 | delegated | dusk gradients carry color |
| D-0030 | `dials.warmth` | 75 | delegated | warm peach light against indigo |
| D-0031 | `dials.depth` | 90 | delegated | glass, as answered in Q-depth-01 (my earlier depth 45 had silently undone it) |
| D-0032 | `answers.Q-depth-04` | "control-layer" | delegated | frosted controls over the gradient |
| D-0033 | `answers.Q-color-04` | "analogous" | delegated | dusk needs neighbouring hues for the sky: peach, rose, lavender |
| D-0034 | `raw.secondaryColors` | ["#C77DA8", "#7E6CC9"] | delegated | dusk rose and evening lavender, the two hues either side of the peach horizon |
| D-0035 | `answers.Q-type-10` | "named" | delegated | owner rule: Apple HIG Dynamic Type roles |
| D-0036 | `answers.Q-type-09` | "hand-tuned" | delegated | HIG sizes are hand-tuned, not a ratio |
| D-0037 | `font.size.11` | {"value": 11, "unit": "px"} | delegated | HIG Dynamic Type step |
| D-0038 | `font.size.13` | {"value": 13, "unit": "px"} | delegated | HIG Dynamic Type step |
| D-0039 | `font.size.15` | {"value": 15, "unit": "px"} | delegated | HIG Dynamic Type step |
| D-0040 | `font.size.17` | {"value": 17, "unit": "px"} | delegated | HIG Dynamic Type step |
| D-0041 | `font.size.20` | {"value": 20, "unit": "px"} | delegated | HIG Dynamic Type step |
| D-0042 | `font.size.22` | {"value": 22, "unit": "px"} | delegated | HIG Dynamic Type step |
| D-0043 | `font.size.28` | {"value": 28, "unit": "px"} | delegated | HIG Dynamic Type step |
| D-0044 | `font.size.34` | {"value": 34, "unit": "px"} | delegated | HIG Dynamic Type step |
| D-0045 | `text.label.sm` | {"fontFamily": "{font.family.text}", "fontSize": "{font.size.11}", "fontWeight": "{font.weight.label}", "letterSpacing": {"value": 0.06, "unit": "em"}, "lineHeight": 1.1818} | delegated | HIG Caption 2 (11/13), used as the overline |

11 more in the full log.

</details>

## Open Items

**These parts are still defaults, guesses, or waiting for a person.**

- Still defaults (zoom 0, sketch): Colors, Layout, Shapes, Components, Modes and Themes, Iconography and Imagery, Content and Voice, Accessibility, Platforms and Devices
- Assets not final: Logo, wordmark, symbol, lockups (H-logo): pending; App icon (H-appicon): pending; Favicon set (H-favicon): pending; Custom icons, pictograms, spot icons (H-icons): pending; Illustration, characters, empty-state art (H-illus): pending; Photography and art direction (H-photo): pending; Fixed brand colors (H-color): pending; Motion signature and rich media (H-motion): pending; Graphic devices, patterns, textures, brand gradients, signature shape (H-motif): pending; UI sounds and sonic logo (H-sound): pending; Custom haptic patterns (H-haptic): pending; Voice and tone guide (H-voice): pending; Brand guidelines PDF (H-brandbook): pending
- Answers taken on assumption or delegated: answers.Q-aud-01 (delegated), context.audience (delegated), raw.brandColor (delegated), answers.Q-plat-01 (delegated), macros (delegated), taste.feelWords (delegated), answers.Q-theme-01 (delegated), answers.Q-color-01 (delegated), raw.neutralBase (delegated), answers.Q-color-21 (delegated), answers.Q-depth-01 (delegated), answers.Q-motion-01 (delegated), answers.Q-type-01 (delegated), raw.displayFace (delegated), raw.textFace (delegated), answers.Q-type-02 (delegated), answers.Q-type-08 (delegated), overrides.type.displayReach (delegated), dials.expression (delegated), dials.brandPresence (delegated), dials.density (delegated), dials.energy (delegated), dials.roundness (delegated), dials.depth (delegated), dials.colorfulness (delegated), dials.warmth (delegated), answers.Q-depth-04 (delegated), answers.Q-color-04 (delegated), raw.secondaryColors (delegated), answers.Q-type-10 (delegated), answers.Q-type-09 (delegated), overrides.font.size.11 (delegated), overrides.font.size.13 (delegated), overrides.font.size.15 (delegated), overrides.font.size.17 (delegated), overrides.font.size.20 (delegated), overrides.font.size.22 (delegated), overrides.font.size.28 (delegated), overrides.font.size.34 (delegated), overrides.text.label.sm (delegated), overrides.text.label.md (delegated), overrides.text.label.lg (delegated), overrides.text.body.sm (delegated), overrides.text.body.md (delegated), overrides.text.body.lg (delegated), overrides.text.title.sm (delegated), overrides.text.title.md (delegated), overrides.text.title.lg (delegated), overrides.text.headline.sm (delegated), overrides.text.headline.md (delegated)
- Waivers: none.
- Licence risks: none found.
- Validation: 0 errors, 3 warnings.

## For Agents

**AI agents: read this file and the tokens before you change any screen.**

1. Before any visual work, read this file, PRODUCT.md and `opendesigner/tokens/` (start at `opendesigner/tokens/opendesigner.resolver.json`).
2. Use tokens, never raw values: CSS `var(--ds-...)`, Tailwind classes from `opendesigner/build/tailwind/theme.css`, `DS.*` in Swift, `DsTheme` in Compose.
3. Do not change a locked decision without asking the owner.
4. To change the system: `engine.py set <path> <value> --why "..."`, then `engine.py generate`, `engine.py validate`, `engine.py design-md`.
5. To extend: add a decision (never hand-edit tokens or this file). Keep semantic names the same across modes. Deprecate instead of deleting.
6. After any implementation, run `engine.py review` and re-read this file.
7. Follow the Standards section. Change a standard only when the person explicitly asks: `engine.py standard override <id> --why "<their words>"`.

**Tailwind v4 classes** (one import: `@import "tailwindcss"; @import "<path>/opendesigner/build/tailwind/theme.css";`; Tailwind's default colors, text sizes, radii and shadows are switched off, so only these exist):

| Area | Classes |
|---|---|
| Color | `bg-action-primary`, `hover:bg-action-primary-hover`, `active:bg-action-primary-pressed`, `text-on-action`, `bg-surface-base`, `bg-surface-raised`, `text-fg-primary`, `text-fg-secondary`, `text-fg-link`, `border-line-subtle`, `border-line-input`, `outline-line-focus`, `bg-danger-bold` |
| Layout | `p-inset-md`, `gap-stack-md`, `gap-inline-sm`, `h-control-md`, `size-icon-md`, `min-h-target-min` |
| Shape | `rounded-control`, `rounded-container`, `rounded-overlay`, `rounded-full` |
| Elevation | `shadow-raised`, `shadow-floating`, `shadow-overlay` |
| Type | `text-body-md`, `text-label-lg`, `text-title-md`, `text-headline-md` |
| Motion | `transition-feedback`, `ease-enter`, `ease-exit`, `ease-hover` |