DESIGN.md@brand · diff
alpha to alpha
205 added, 201 removed. Audit A to A.
---
version: alpha
name: "OpenDesigner brand"
- description: "Design system generated by OpenDesigner"
+ description: "Marketing site, Docs or content site"
colors:
primary: "#2338ff"
on-primary: "#ffffff"
surface: "#fcfdff"
on-surface: "#222428"
error: "#d93834"
typography:
body-md: { fontFamily: "Hanken Grotesk", fontSize: 16px, lineHeight: 24px }
rounded:
- control: 6px
- container: 8px
+ control: 12px
+ container: 16px
spacing:
unit: 4px
---
# OpenDesigner brand
- **OpenDesigner brand** is a design system; what it is for is not recorded yet (Q-scope-01).
+ **OpenDesigner brand**: Marketing site, Docs or content site.
- - **For:** people who use it now and then, often on a phone
- - **Screens:** social cards (a page that shows off and invites people in); readme (pages people read)
+ - **For:** design-system teams, product designers and engineers, mostly at work on a desktop, including enterprise and B2B teams
+ - **Screens:** landing page (a page that shows off and invites people in); documentation (pages people read); social cards (a page that shows off and invites people in); readme (pages people read)
- **Runs on:** web, secondary
- - **Feel:** bold, premium, warm (bold, premium, friendly; picked for you)
+ - **Feel:** technical, premium, calm, precise, friendly (modern, serious, premium, minimal, friendly)
- **Brand color:** Your brand color (#2338FF) is on the buttons exactly, with white text that reads clearly on it.
- - **Decided:** 3 answers you gave, 5 picked for you; everything else uses sourced defaults
- - **Standards:** 289 house standards followed (locked, house standards v2); see the Standards section
+ - **Decided:** 7 answers you gave, 4 picked for you; everything else uses sourced defaults
+ - **Standards:** 288 house standards followed (locked, house standards v3), 1 overridden by you; see the Standards section
- **Next:** zoom into Colors, Layout, Elevation & Depth, or stop here: each level works
- - **Licence risks:** none found
+ - **Licence risks:** Custom icons, pictograms, spot icons: check the terms of the set you use. Recraft vector output with its plan terms. Photography and art direction: check the terms of the set you use. Stock: Unsplash (free, irrevocable, commercial; no competing service) or Pexels (no implied endorsement, no use as a trademark).
> 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), 6 decisions in this area. To zoom in, answer Q-dir-01, Q-dir-02.
+ > Zoom: sketch (0 of 3), 7 decisions in this area. To zoom in, answer Q-dir-01, Q-dir-02.
<!-- od:zoom area=overview level=0 -->
- **OpenDesigner brand feels bold, premium and friendly. Screens are roomy, in a flat style.**
+ **OpenDesigner brand feels modern, serious, premium, minimal and friendly. Screens are comfortable, in a flat style.**
Designers: visual style: flat, tonal, glass · Code: `preset in state.json`
<details><summary>More</summary>
**Your answers here** (each one either sets tokens or is a rule for this section):
- - What are these screens mostly for: selling, getting work done, reading, or enjoying an experience? **social cards (Persuade), readme (Read)** (delegated; tokens; Q-scope-06)
+ - Is this only for your app, or also your marketing site, docs, emails or in-house tools? **Marketing site, Docs or content site** (delegated; owner input; Q-scope-01)
+ - What are these screens mostly for: selling, getting work done, reading, or enjoying an experience? **landing page (Persuade), documentation (Read), social cards (Persuade), readme (Read)** (delegated; tokens; Q-scope-06)
- **Intent.** A design system generated from eight dials and a few raw inputs.
+ **Intent.** Marketing site, Docs or content site
- - Audience: people who use it now and then, often on a phone
+ - Audience: design-system teams, product designers and engineers, mostly at work on a desktop, including enterprise and B2B teams
- The memorable thing: not recorded yet (Q-brand-02)
- - Surfaces: social cards (Persuade: density spacious; one hero line per page; sections, not card grids); readme (Read: density comfortable; no hero; `text.body.lg` for long text; no cards around running text)
+ - Surfaces: landing page (Persuade: density spacious; one hero line per page; sections, not card grids); documentation (Read: density comfortable; no hero; `text.body.lg` for long text; no cards around running text); social cards (Persuade: density spacious; one hero line per page; sections, not card grids); readme (Read: density comfortable; no hero; `text.body.lg` for long text; no cards around running text)
- Platforms: web, secondary; inputs: pointer, touch
- - Direction: preset flat2 (the default until Q-dir-01 is answered); feel bold, premium, friendly (words picked for you: bold, premium, warm)
+ - Direction: preset flat2 (the default until Q-dir-01 is answered); feel modern, serious, premium, minimal, friendly (your words: technical, premium, calm, precise, friendly)
**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 68/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 80/100** (native to brand-led: brand-led): typeface suggestion: proprietary-brand-face, brand color placement: large-surfaces+custom-components, native component share about 32%, voice guidance: full.
- - **Density 30/100** (spacious to compact: spacious): body 16px on the web, default control 48px, density mode spacious, icons 24px; hit areas never shrink.
- - **Energy 40/100** (calm to energetic: leaning calm): standard easing [0.77, 0, 0.175, 1], duration multiplier 0.96, spring damping 1.0, heading weight 400, navigation: neutral.
- - **Roundness 40/100** (sharp to soft: leaning sharp): control radius 6, icon corners default, caps square.
- - **Depth 30/100** (flat to deep: flat): depth model: ring+faint-shadow.
- - **Colorfulness 62/100** (monochrome to vivid: leaning vivid): scheme tonalSpot, accent chroma 83.2 (HCT), 3 accent(s), surfaces: tinted-containers.
+ - **Expression 40/100** (productive to expressive: leaning productive): type ratio 1.25, hero moments: significant-moments, expressive motion: significant-moments, brand color role: accent+signature-surface, containment: mixed.
+ - **Brand presence 55/100** (native to brand-led: balanced): typeface suggestion: open-custom-face, brand color placement: accent+signature-surface, native component share about 72%, voice guidance: short.
+ - **Density 45/100** (spacious to compact: balanced): body 16px on the web, default control 40px, density mode comfortable, icons 20px; hit areas never shrink.
+ - **Energy 30/100** (calm to energetic: calm): standard easing [0.77, 0, 0.175, 1], duration multiplier 0.92, spring damping 1.0, heading weight 400, navigation: recessive.
+ - **Roundness 75/100** (sharp to soft: soft): control radius 12, icon corners rounded, caps round.
+ - **Depth 15/100** (flat to deep: flat): depth model: borders.
+ - **Colorfulness 35/100** (monochrome to vivid: leaning monochrome): scheme neutral, accent chroma 83.2 (HCT), 1 accent(s), surfaces: neutral+one-accent.
- **Warmth 30/100** (cool/formal to warm/friendly: cool/formal): neutral tint chroma 0.022 at hue 264, borders: strong-rules, sentence-case, contractions allowed.
**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-02, Q-type-03, Q-type-04 |
| Layout | sketch | Q-space-01, Q-space-02, Q-space-03 |
| Elevation & Depth | sketch | Q-depth-01 |
| Shapes | sketch | Q-shape-01 |
| Components | sketch | Q-comp-01, Q-comp-02, Q-state-01 |
| Motion | sketch | Q-motion-01 |
- | Modes and Themes | sketch | Q-theme-03 |
+ | Modes and Themes | defined | Q-theme-02, Q-theme-04 |
| 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-0010 (answers.Q-scope-06), D-0012 (dials.expression), D-0014 (dials.density), D-0021 (dials.brandPresence).
+ Decisions: D-0035 (answers.Q-aud-01), D-0037 (answers.Q-scope-01), D-0038 (answers.Q-scope-06), D-0050 (macros), D-0051 (dials.expression), D-0052 (dials.brandPresence), D-0053 (dials.density).
</details>
## Colors
> Zoom: sketch (0 of 3), 4 decisions in this area. To zoom in, answer Q-color-02.
<!-- od:zoom area=color level=0 -->
- **Three accent colors: your brand color `#2338FF` (exactly) marks buttons, links and focus; `#a856a9`, `#00828f` add highlights.** Everything else stays neutral.
+ **One accent color: your brand color `#2338FF` (exactly) marks buttons, links and focus.** Everything else stays neutral.
Designers: primary or brand accent · Code: `color.bg.accent`
<details><summary>More</summary>
- **Intent.** Brand color `#2338FF` drives the accent ramp's hue; the Colorfulness dial (62) sets its chroma (scheme tonalSpot, peak HCT chroma 83.23). The brand's role is **brand-chrome-allowed** and it sits closest to accent step 9. Your brand color #2338FF is on the buttons exactly (white text on it reads at 6.82:1).
+ **Intent.** Brand color `#2338FF` drives the accent ramp's hue; the Colorfulness dial (35) sets its chroma (scheme neutral, peak HCT chroma 83.23). The brand's role is **accent+signature-surface** and it sits closest to accent step 9. Your brand color #2338FF is on the buttons exactly (white text on it reads at 6.82:1).
**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` | `#fcfdff` `#eff4ff` `#e3ecff` `#d7e3ff` `#cbdbff` `#bfd2ff` `#b3c9ff` `#537eff` `#2338ff` `#1e2fe6` `#1c31ce` `#192e75` | light |
- | `accent2` | `#fffcff` `#faf2f9` `#f7e7f6` `#f4dcf3` `#f2d0f1` `#efc5ee` `#ecb9eb` `#af71ae` `#a856a9` `#994c9a` `#803d81` `#482848` | light |
- | `accent3` | `#f8feff` `#ebf6f8` `#d7f0f3` `#c3eaef` `#ade4eb` `#97dde7` `#7ed7e3` `#0094a3` `#00828f` `#007581` `#00616b` `#003a40` | light |
| `danger` | `#fffcfc` `#fff1ef` `#ffe6e3` `#ffdbd6` `#ffcfc9` `#ffc4bc` `#ffb8af` `#d76258` `#d93834` `#c72f2c` `#a82321` `#5c201c` | light |
| `info` | `#fbfdff` `#eaf6ff` `#d9efff` `#c7e7ff` `#b5e0ff` `#a3d8ff` `#8fd1ff` `#008ed1` `#007cb7` `#0070a6` `#005c8a` `#003755` | light |
| `neutral` | `#fcfdff` `#f2f4f9` `#e8ecf1` `#dfe3ea` `#d6dbe3` `#cdd2dc` `#c4cad5` `#808793` `#6f7683` `#5e6471` `#515762` `#222428` | light |
| `success` | `#f9fef9` `#ebf7ed` `#d9f1dd` `#c6eccc` `#b2e7bc` `#9de2ab` `#87dc9a` `#089a47` `#00883d` `#007b36` `#00652c` `#003d17` | light |
| `warning` | `#fffcf8` `#f8f4ec` `#f5ead9` `#f1e1c6` `#eed8b3` `#ebce9f` `#e7c58b` `#aa7f2c` `#efb239` `#dda331` `#845d00` `#463001` | 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.55 | 3.29 | 3.05 | 2.81 | 2.60 |
| neutral 9 | 4.49 | 4.15 | 3.85 | 3.55 | 3.29 |
| neutral 10 | 5.83 | 5.40 | 5.00 | 4.61 | 4.27 |
| neutral 11 | 7.14 | 6.60 | 6.13 | 5.65 | 5.23 |
| neutral 12 | 15.27 | 14.13 | 13.10 | 12.07 | 11.18 |
**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` | `#2338ff` | `#1e2fe6` (1.18:1) | `#1a21dc` (1.34:1) |
| `color.bg.accent.bold` | `#2338ff` | `#1e2fe6` (1.18:1) | `#1a21dc` (1.34:1) |
**Semantic roles** (use these, never the ramps):
| Token | Light | Dark | Use |
|---|---|---|---|
- | `color.bg.accent.bold` | `#2338ff` | `#517cff` | Solid accent fill. |
- | `color.bg.accent.bold-hover` | `#1e2fe6` | `#638cff` | Hover: one step, at least 1.15:1 from the solid (DC-L01-17). |
- | `color.bg.accent.bold-pressed` | `#1a21dc` | `#7197ff` | Pressed: at least 1.3:1 from the solid. |
- | `color.bg.accent.subtle` | `#e3ecff` | `#1c2742` | Selected rows, accent badges. |
- | `color.bg.accent.subtle-hover` | `#d7e3ff` | `#1f2e56` | Hover on accent subtle fills. |
- | `color.bg.accent.subtle-pressed` | `#cbdbff` | `#22356b` | Pressed accent subtle fills. |
- | `color.bg.accent2.bold` | `#a856a9` | `#b06db0` | accent2 solid fill. |
- | `color.bg.accent2.bold-hover` | `#994c9a` | `#be7abe` | Hover: one step, at least 1.15:1 from the solid (DC-L01-17). |
- | `color.bg.accent2.bold-pressed` | `#904391` | `#c884c8` | Pressed: at least 1.3:1 from the solid. |
- | `color.bg.accent2.subtle` | `#f7e7f6` | `#302330` | accent2 subtle fill. |
- | `color.bg.accent3.bold` | `#00828f` | `#0093a1` | accent3 solid fill. |
- | `color.bg.accent3.bold-hover` | `#007581` | `#00a1b1` | Hover: one step, at least 1.15:1 from the solid (DC-L01-17). |
- | `color.bg.accent3.bold-pressed` | `#006c77` | `#00acbc` | Pressed: at least 1.3:1 from the solid. |
- | `color.bg.accent3.subtle` | `#d7f0f3` | `#152b2e` | accent3 subtle fill. |
- | `color.bg.action.primary` | `#2338ff` | `#517cff` | Primary action. One per view (DC-L15-03, L15 P08). |
- | `color.bg.action.primary-hover` | `#1e2fe6` | `#638cff` | Hover: one step, at least 1.15:1 from the solid (DC-L01-17). |
- | `color.bg.action.primary-pressed` | `#1a21dc` | `#7197ff` | Pressed: at least 1.3:1 from the solid. |
- | `color.bg.brand` | `#2338ff` | `#517cff` | Brand fill for signature surfaces; carries text.on-brand (brandAnchor rule, DC-L01-09). |
- | `color.bg.danger.bold` | `#d93834` | `#da5b51` | Danger solid fill. |
- | `color.bg.danger.bold-hover` | `#c72f2c` | `#e9695e` | Hover: one step, at least 1.15:1 from the solid (DC-L01-17). |
- | `color.bg.danger.bold-pressed` | `#bc2323` | `#f47367` | Pressed: at least 1.3:1 from the solid. |
- | `color.bg.danger.subtle` | `#ffe6e3` | `#39211f` | Danger banner and badge background. |
- | `color.bg.disabled` | `#e8ecf1` | `#2b2e33` | Disabled control fill. |
- | `color.bg.field` | `#ffffff` | `#232529` | Text field fill: outlined fields sit on the raised surface (Q-form-01). |
- | `color.bg.info.bold` | `#007cb7` | `#008bcd` | Info solid fill. |
- | `color.bg.info.bold-hover` | `#0070a6` | `#0099e0` | Hover: one step, at least 1.15:1 from the solid (DC-L01-17). |
- | `color.bg.info.bold-pressed` | `#006799` | `#00a3ee` | Pressed: at least 1.3:1 from the solid. |
- | `color.bg.info.subtle` | `#d9efff` | `#062a3f` | Info banner and badge background. |
- | `color.bg.inverse` | `#222428` | `#e6e9ee` | Tooltips and toasts: the inverted surface. |
- | `color.bg.neutral.subtle` | `#e8ecf1` | `#33363d` | Secondary buttons, chips, hovered rows. |
- | `color.bg.neutral.subtle-hover` | `#dfe3ea` | `#3b3f47` | Hover: +1 step (DC-L01-17). |
- | `color.bg.neutral.subtle-pressed` | `#d6dbe3` | `#434852` | Pressed or selected: +2 steps (DC-L01-17). |
- | `color.bg.success.bold` | `#00883d` | `#009845` | Success solid fill. |
- | `color.bg.success.bold-hover` | `#007b36` | `#00a74c` | Hover: one step, at least 1.15:1 from the solid (DC-L01-17). |
- | `color.bg.success.bold-pressed` | `#007132` | `#19b155` | Pressed: at least 1.3:1 from the solid. |
- | `color.bg.success.subtle` | `#d9f1dd` | `#172c1b` | Success banner and badge background. |
- | `color.bg.warning.bold` | `#efb239` | `#e6b55d` | Warning solid fill. |
- | `color.bg.warning.bold-hover` | `#dda331` | `#f7c56e` | Hover: one step, at least 1.15:1 from the solid (DC-L01-17). |
- | `color.bg.warning.bold-pressed` | `#d29921` | `#ffd388` | Pressed: at least 1.3:1 from the solid. |
- | `color.bg.warning.subtle` | `#f5ead9` | `#2f2618` | Warning banner and badge background. |
- | `color.border.accent` | `#537eff` | `#507af9` | Selected card or accent outline. |
- | `color.border.danger` | `#d76258` | `#cd6057` | Danger boundary, for example an invalid field (3:1). |
- | `color.border.default` | `#808793` | `#7a808c` | Outlines (strong rules). |
- | `color.border.focus` | `#2338ff` | `#89aaff` | Focus ring (3:1 against every surface, DC-L04-09). |
- | `color.border.info` | `#008ed1` | `#0089c9` | Info boundary, for example an invalid field (3:1). |
- | `color.border.input` | `#808793` | `#7a808c` | Text field and select borders (3:1, DC-L01-16). |
- | `color.border.strong` | `#808793` | `#7a808c` | Boundaries that are the only cue: inputs, checkboxes, switches (3:1, WCAG 1.4.11). |
- | `color.border.subtle` | `#c4cad5` | `#434852` | Dividers (strong rules: Warmth 0-33, S-L06-067 inverse). |
- | `color.border.success` | `#089a47` | `#199547` | Success boundary, for example an invalid field (3:1). |
- | `color.border.warning` | `#aa7f2c` | `#a47b2f` | Warning boundary, for example an invalid field (3:1). |
- | `color.icon.accent` | `#1c31ce` | `#89aaff` | Selected and interactive icons. |
- | `color.icon.default` | `#515762` | `#a5abb8` | Icons beside text; same color as secondary text (DC-L05-08). |
- | `color.icon.on-accent` | `#ffffff` | `#141517` | Icons on solid accent fills. |
- | `color.icon.subtle` | `#5e6471` | `#8f96a4` | Decorative icons. |
- | `color.overlay.scrim` | `#222428 @0.45` | `#000000` | Modal backdrop (DC-L04-18; Q-depth-06). |
- | `color.surface.base` | `#fcfdff` | `#1b1d20` | The page background. |
- | `color.surface.nav` | `#fcfdff` | `#1b1d20` | Navigation on the page background. |
- | `color.surface.overlay` | `#ffffff` | `#2b2e33` | Menus, popovers, dialogs; always with elevation.floating or elevation.overlay. |
- | `color.surface.raised` | `#ffffff` | `#232529` | Cards and panels on the page. |
- | `color.surface.sunken` | `#f2f4f9` | `#141517` | Wells, code blocks, page gutters. |
- | `color.surface.tinted` | `#eff4ff` | `#1a202d` | Tinted container (Colorfulness 50+, L09 X rubric; Q-color-05). |
- | `color.text.accent` | `#1c31ce` | `#89aaff` | Accent text and selected labels. |
- | `color.text.accent2` | `#803d81` | `#d796d7` | accent2 text. |
- | `color.text.accent3` | `#00616b` | `#31bccd` | accent3 text. |
- | `color.text.danger` | `#a82321` | `#ff8c80` | Danger text and icons; pair with an icon or label (DC-L01-15). |
- | `color.text.disabled` | `#808793` | `#7a808c` | Disabled labels; exempt from contrast minimums (WCAG 1.4.3 exception). |
- | `color.text.info` | `#005c8a` | `#3ab6ff` | Info text and icons; pair with an icon or label (DC-L01-15). |
- | `color.text.inverse` | `#ffffff` | `#141517` | Text on color.bg.inverse (tooltips, toasts). |
- | `color.text.link` | `#1c31ce` | `#89aaff` | Links. Underline them in running text so color is not the only cue. |
- | `color.text.on-accent` | `#ffffff` | `#141517` | Text and icons on color.bg.accent.bold* (auto-picked light or dark, S-L06-094). |
- | `color.text.on-accent2` | `#ffffff` | `#141517` | Text on accent2 solid. |
- | `color.text.on-accent3` | `#ffffff` | `#141517` | Text on accent3 solid. |
- | `color.text.on-action` | `#ffffff` | `#141517` | Text on the primary action fill. |
- | `color.text.on-brand` | `#ffffff` | `#141517` | Text on color.bg.brand. |
- | `color.text.on-danger` | `#ffffff` | `#141517` | Text on bg.danger.bold. |
- | `color.text.on-info` | `#ffffff` | `#141517` | Text on bg.info.bold. |
- | `color.text.on-success` | `#ffffff` | `#141517` | Text on bg.success.bold. |
- | `color.text.on-warning` | `#222428` | `#141517` | Text on bg.warning.bold. |
- | `color.text.primary` | `#222428` | `#e6e9ee` | Body copy, headings, labels (guaranteed >= 7:1 on steps 1-5). |
- | `color.text.secondary` | `#515762` | `#a5abb8` | Supporting text (guaranteed >= the text minimum on surfaces and neutral fills 1-4). |
- | `color.text.success` | `#00652c` | `#47c26c` | Success text and icons; pair with an icon or label (DC-L01-15). |
- | `color.text.tertiary` | `#5e6471` | `#8f96a4` | Captions and placeholders (still meets the text minimum on surfaces 1-4). |
- | `color.text.warning` | `#845d00` | `#fecf7f` | Warning text and icons; pair with an icon or label (DC-L01-15). |
+ | `color.bg.accent.bold` | `#2338ff` | `same` | Solid accent fill. |
+ | `color.bg.accent.bold-hover` | `#1e2fe6` | `same` | Hover: one step, at least 1.15:1 from the solid (DC-L01-17). |
+ | `color.bg.accent.bold-pressed` | `#1a21dc` | `same` | Pressed: at least 1.3:1 from the solid. |
+ | `color.bg.accent.subtle` | `#e3ecff` | `same` | Selected rows, accent badges. |
+ | `color.bg.accent.subtle-hover` | `#d7e3ff` | `same` | Hover on accent subtle fills. |
+ | `color.bg.accent.subtle-pressed` | `#cbdbff` | `same` | Pressed accent subtle fills. |
+ | `color.bg.action.primary` | `#2338ff` | `same` | Primary action. One per view (DC-L15-03, L15 P08). |
+ | `color.bg.action.primary-hover` | `#1e2fe6` | `same` | Hover: one step, at least 1.15:1 from the solid (DC-L01-17). |
+ | `color.bg.action.primary-pressed` | `#1a21dc` | `same` | Pressed: at least 1.3:1 from the solid. |
+ | `color.bg.brand` | `#2338ff` | `same` | Brand fill for signature surfaces; carries text.on-brand (brandAnchor rule, DC-L01-09). |
+ | `color.bg.danger.bold` | `#d93834` | `same` | Danger solid fill. |
+ | `color.bg.danger.bold-hover` | `#c72f2c` | `same` | Hover: one step, at least 1.15:1 from the solid (DC-L01-17). |
+ | `color.bg.danger.bold-pressed` | `#bc2323` | `same` | Pressed: at least 1.3:1 from the solid. |
+ | `color.bg.danger.subtle` | `#ffe6e3` | `same` | Danger banner and badge background. |
+ | `color.bg.disabled` | `#e8ecf1` | `same` | Disabled control fill. |
+ | `color.bg.field` | `#ffffff` | `same` | Text field fill: outlined fields sit on the raised surface (Q-form-01). |
+ | `color.bg.info.bold` | `#007cb7` | `same` | Info solid fill. |
+ | `color.bg.info.bold-hover` | `#0070a6` | `same` | Hover: one step, at least 1.15:1 from the solid (DC-L01-17). |
+ | `color.bg.info.bold-pressed` | `#006799` | `same` | Pressed: at least 1.3:1 from the solid. |
+ | `color.bg.info.subtle` | `#d9efff` | `same` | Info banner and badge background. |
+ | `color.bg.inverse` | `#222428` | `same` | Tooltips and toasts: the inverted surface. |
+ | `color.bg.neutral.subtle` | `#e8ecf1` | `same` | Secondary buttons, chips, hovered rows. |
+ | `color.bg.neutral.subtle-hover` | `#dfe3ea` | `same` | Hover: +1 step (DC-L01-17). |
+ | `color.bg.neutral.subtle-pressed` | `#d6dbe3` | `same` | Pressed or selected: +2 steps (DC-L01-17). |
+ | `color.bg.success.bold` | `#00883d` | `same` | Success solid fill. |
+ | `color.bg.success.bold-hover` | `#007b36` | `same` | Hover: one step, at least 1.15:1 from the solid (DC-L01-17). |
+ | `color.bg.success.bold-pressed` | `#007132` | `same` | Pressed: at least 1.3:1 from the solid. |
+ | `color.bg.success.subtle` | `#d9f1dd` | `same` | Success banner and badge background. |
+ | `color.bg.warning.bold` | `#efb239` | `same` | Warning solid fill. |
+ | `color.bg.warning.bold-hover` | `#dda331` | `same` | Hover: one step, at least 1.15:1 from the solid (DC-L01-17). |
+ | `color.bg.warning.bold-pressed` | `#d29921` | `same` | Pressed: at least 1.3:1 from the solid. |
+ | `color.bg.warning.subtle` | `#f5ead9` | `same` | Warning banner and badge background. |
+ | `color.border.accent` | `#537eff` | `same` | Selected card or accent outline. |
+ | `color.border.danger` | `#d76258` | `same` | Danger boundary, for example an invalid field (3:1). |
+ | `color.border.default` | `#808793` | `same` | Outlines (strong rules). |
+ | `color.border.focus` | `#2338ff` | `same` | Focus ring (3:1 against every surface, DC-L04-09). |
+ | `color.border.info` | `#008ed1` | `same` | Info boundary, for example an invalid field (3:1). |
+ | `color.border.input` | `#808793` | `same` | Text field and select borders (3:1, DC-L01-16). |
+ | `color.border.separator` | `#d6dbe3` | `same` | Hairlines between table rows and list items, lighter than border.subtle; decorative, so never the only cue (DC-L23-05). |
+ | `color.border.strong` | `#808793` | `same` | Boundaries that are the only cue: inputs, checkboxes, switches (3:1, WCAG 1.4.11). |
+ | `color.border.subtle` | `#c4cad5` | `same` | Dividers (strong rules: Warmth 0-33, S-L06-067 inverse). |
+ | `color.border.success` | `#089a47` | `same` | Success boundary, for example an invalid field (3:1). |
+ | `color.border.warning` | `#aa7f2c` | `same` | Warning boundary, for example an invalid field (3:1). |
+ | `color.icon.accent` | `#1c31ce` | `same` | Selected and interactive icons. |
+ | `color.icon.default` | `#515762` | `same` | Icons beside text; same color as secondary text (DC-L05-08). |
+ | `color.icon.on-accent` | `#ffffff` | `same` | Icons on solid accent fills. |
+ | `color.icon.subtle` | `#5e6471` | `same` | Decorative icons. |
+ | `color.overlay.scrim` | `#222428 @0.45` | `same` | Modal backdrop (DC-L04-18; Q-depth-06). |
+ | `color.surface.base` | `#fcfdff` | `same` | The page background. |
+ | `color.surface.nav` | `#f2f4f9` | `same` | Recessive navigation, dimmer than content (Linear 2026, S-L06-067). |
+ | `color.surface.overlay` | `#ffffff` | `same` | Menus, popovers, dialogs; always with elevation.floating or elevation.overlay. |
+ | `color.surface.raised` | `#ffffff` | `same` | Cards and panels on the page. |
+ | `color.surface.sunken` | `#f2f4f9` | `same` | Wells, code blocks, page gutters. |
+ | `color.text.accent` | `#1c31ce` | `same` | Accent text and selected labels. |
+ | `color.text.danger` | `#a82321` | `same` | Danger text and icons; pair with an icon or label (DC-L01-15). |
+ | `color.text.disabled` | `#808793` | `same` | Disabled labels; exempt from contrast minimums (WCAG 1.4.3 exception). |
+ | `color.text.info` | `#005c8a` | `same` | Info text and icons; pair with an icon or label (DC-L01-15). |
+ | `color.text.inverse` | `#ffffff` | `same` | Text on color.bg.inverse (tooltips, toasts). |
+ | `color.text.link` | `#1c31ce` | `same` | Links. Underline them in running text so color is not the only cue. |
+ | `color.text.on-accent` | `#ffffff` | `same` | Text and icons on color.bg.accent.bold* (auto-picked light or dark, S-L06-094). |
+ | `color.text.on-action` | `#ffffff` | `same` | Text on the primary action fill. |
+ | `color.text.on-brand` | `#ffffff` | `same` | Text on color.bg.brand. |
+ | `color.text.on-danger` | `#ffffff` | `same` | Text on bg.danger.bold. |
+ | `color.text.on-info` | `#ffffff` | `same` | Text on bg.info.bold. |
+ | `color.text.on-success` | `#ffffff` | `same` | Text on bg.success.bold. |
+ | `color.text.on-warning` | `#222428` | `same` | Text on bg.warning.bold. |
+ | `color.text.primary` | `#222428` | `same` | Body copy, headings, labels (guaranteed >= 7:1 on steps 1-5). |
+ | `color.text.secondary` | `#515762` | `same` | Supporting text (guaranteed >= the text minimum on surfaces and neutral fills 1-4). |
+ | `color.text.success` | `#00652c` | `same` | Success text and icons; pair with an icon or label (DC-L01-15). |
+ | `color.text.tertiary` | `#5e6471` | `same` | Captions and placeholders (still meets the text minimum on surfaces 1-4). |
+ | `color.text.warning` | `#845d00` | `same` | 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-0020 (dials.colorfulness), D-0025 (raw.brandColor), D-0026 (dials.warmth).
+ Decisions: D-0026 (dials.warmth), D-0039 (raw.brandColor), D-0048 (answers.Q-theme-01), D-0055 (dials.colorfulness).
</details>
## Typography
- > Zoom: broad (1 of 3), 3 decisions in this area. To zoom in, answer Q-type-02, Q-type-03, Q-type-04.
+ > Zoom: broad (1 of 3), 4 decisions in this area. To zoom in, answer Q-type-02, Q-type-03, Q-type-04.
<!-- od:zoom area=typography level=1 -->
- **Body text is 16px, and each larger size is about 1.333 times the one below.**
+ **Body text is 16px, and each larger size is about 1.25 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? **A free font with character** (chosen; tokens; Q-type-01)
+ - Should letter spacing change with text size, or stay as the font sets it? **A size-specific table (SF Pro** (chosen; tokens; Q-type-13)
- **Intent.** Body text is 16px; sizes follow `round(16 x 1.333^n)` for n from -2 to 6, reaching about 5.5x body (marketing surfaces in scope). Sizes: 12, 16, 21, 28, 38, 51, 67, 90px.
+ **Intent.** Body text is 16px; sizes follow `round(16 x 1.25^n)` for n from -2 to 8, reaching about 5.5x body (marketing surfaces in scope). Sizes: 13, 16, 20, 25, 39, 49, 76, 95px.
- Text face: Hanken Grotesk, system-ui, -apple-system, Segoe UI, Roboto, Helvetica Neue, Arial, sans-serif. Licence status (hook H-type): **open-library**.
- Licence by platform: text: Hanken Grotesk (open licence or system font: web, apps and 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 400, display 500 (two or three distinct weights per view).
- - Emphasized variants (Expression 68, on from 67): 9 styles under `text.emphasized.*`, the same size one weight heavier, for the selected item, key actions and headlines (DC-L02-11).
+ - Weights: body 400, label 500, heading 400 (two or three distinct weights per view).
+ - Emphasized variants: off (they turn on at Expression 67 and up, 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` | 21/28 | 400 | 0em | Long-form reading, onboarding copy. |
+ | `text.body.lg` | 20/28 | 400 | 0em | Long-form reading, onboarding copy. |
| `text.body.md` | 16/24 | 400 | 0em | Default UI text: forms, tables, descriptions. |
- | `text.body.sm` | 12/16 | 400 | 0.02em | Helper text, timestamps, captions. |
+ | `text.body.sm` | 13/20 | 400 | 0em | Helper text, timestamps, captions. |
| `text.code.md` | 16/24 | 400 | 0em | Code blocks, token names. |
- | `text.code.sm` | 12/16 | 400 | 0.02em | Inline values, dense code rows. |
- | `text.display.sm` | 90/100 | 500 | -0.02em | One hero line per page: marketing, empty states. |
- | `text.headline.lg` | 67/76 | 400 | -0.02em | Page and section titles. |
- | `text.headline.md` | 51/56 | 400 | -0.02em | Page and section titles. |
- | `text.headline.sm` | 38/48 | 400 | -0.01em | Page and section titles. |
+ | `text.code.sm` | 13/20 | 400 | 0em | Inline values, dense code rows. |
+ | `text.display.lg` | 95/108 | 400 | -0.02em | One hero line per page: marketing, empty states. |
+ | `text.display.md` | 76/84 | 400 | -0.02em | One hero line per page: marketing, empty states. |
+ | `text.headline.lg` | 49/56 | 400 | -0.02em | Page and section titles. |
+ | `text.headline.sm` | 39/48 | 400 | -0.01em | Page and section titles. |
| `text.label.lg` | 16/24 | 500 | 0em | Button and control labels. |
- | `text.label.md` | 12/16 | 500 | 0.02em | Small control labels, badges, dense tabs. |
- | `text.label.sm` | 12/16 | 500 | 0.05em caps | Overlines in capitals with wide tracking (DC-L02-18). |
- | `text.title.lg` | 28/36 | 400 | 0em | Card, panel and group titles. |
- | `text.title.md` | 21/28 | 400 | 0em | Card, panel and group titles. |
+ | `text.label.md` | 13/20 | 500 | 0em | Small control labels, badges, dense tabs. |
+ | `text.label.sm` | 13/20 | 500 | 0.05em caps | Overlines in capitals with wide tracking (DC-L02-18). |
+ | `text.title.lg` | 25/36 | 400 | 0em | Card, panel and group titles. |
+ | `text.title.md` | 20/28 | 400 | 0em | Card, panel and group titles. |
| `text.title.sm` | 16/24 | 400 | 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`.
+ **Tailwind classes:** `text-body-md`, `text-label-lg`, `text-title-md`.
- Decisions: D-0023 (answers.Q-type-01), D-0024 (raw.textFace), D-0028 (overrides.type.headingWeight).
+ Decisions: D-0023 (answers.Q-type-01), D-0024 (raw.textFace), D-0028 (overrides.type.headingWeight), D-0058 (answers.Q-type-13).
</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.**
+ **Spacing comes in steps of 4px, and screens use comfortable 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.
+ **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 **comfortable**). 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 |
+ | Density | inset xs/sm/md/lg/xl | section sm/md/lg | control sm/md/lg | row sm/md/lg/two-line | outer:inner |
+ |---|---|---|---|---|---|
+ | spacious | 6 / 12 / 16 / 20 / 32 | 64 / 80 / 96 | 40 / 48 / 56 | 52 / 56 / 64 / 80 | 3.5 |
+ | comfortable (default) | 4 / 8 / 12 / 16 / 24 | 32 / 40 / 64 | 32 / 40 / 48 | 44 / 48 / 56 / 72 | 2.5 |
+ | compact | 2 / 6 / 8 / 12 / 20 | 16 / 24 / 40 | 24 / 32 / 40 | 36 / 40 / 48 / 64 | 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-0014 (dials.density).
+ Decisions: D-0053 (dials.density).
</details>
## Elevation & Depth
> Zoom: sketch (0 of 3), 1 decision in this area. To zoom in, answer Q-depth-01.
<!-- od:zoom area=elevation level=0 -->
- **Cards get a faint outline and a very soft shadow.**
+ **Surfaces are separated by thin borders, with no shadows.**
Designers: flat, shadowed, tonal or glass · Code: `$extensions.opendesigner.model`
<details><summary>More</summary>
- **Intent.** Depth 30/100 selects the **ring+faint-shadow** model. Shadow alpha in light mode is 0.107; dark mode doubles it and lifts surfaces by lightness instead (sunken, base, raised, overlay).
+ **Intent.** Depth 15/100 selects the **borders** model. Shadow alpha in light mode is 0.0; 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 0 1, 0 1 2 0 | Cards that lift on hover, sticky headers, dragged rows. |
- | `elevation.floating` | 0 0 0 1, 0 1 2 0, 0 4 12 0 | Menus, popovers, dropdowns. |
- | `elevation.overlay` | 0 0 0 1, 0 1 2 0, 0 12 32 0 | Dialogs and sheets (with color.overlay.scrim). |
+ | `elevation.raised` | none | Cards that lift on hover, sticky headers, dragged rows. |
+ | `elevation.floating` | none | Menus, popovers, dropdowns. |
+ | `elevation.overlay` | none | 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`).
- No materials or glass in this system.
- Decisions: D-0017 (dials.depth).
+ Decisions: D-0034 (dials.depth).
</details>
## Shapes
- > Zoom: sketch (0 of 3), 1 decision in this area. To zoom in, answer Q-shape-01.
+ > Zoom: sketch (0 of 3), 2 decisions in this area. To zoom in, answer Q-shape-01.
<!-- od:zoom area=shape level=0 -->
- **Buttons and fields have 6px corners; cards have 8px corners.**
+ **Buttons and fields have 12px corners; cards have 16px corners.**
Designers: corner radius, sharp to pill · Code: `radius.control, CSS border-radius`
<details><summary>More</summary>
- **Intent.** Roundness 40/100 gives controls a **6** radius; details 2px, containers 8px, overlays 12px, people full. Controls under 32px tall use `radius.control-sm` (4).
+ **Your answers here** (each one either sets tokens or is a rule for this section):
+ - Use standard round corners, or smooth Apple-style squircle corners where they work? **Continuous curvature** (chosen; a rule here; Q-shape-04)
+ **Intent.** Roundness 75/100 gives controls a **12** radius; details 6px, containers 16px, overlays 24px, people full. Controls under 32px tall use `radius.control-sm` (8).
+
- 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 (8).
- - Icons: default corners, square caps. On iOS, use continuous corners (DC-L04-04).
+ - Focus ring: 2px, 2px offset, radius = control radius + offset (14).
+ - 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-0016 (dials.roundness).
+ Decisions: D-0056 (dials.roundness), D-0057 (answers.Q-shape-04).
</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), 6 radius, `text.label.lg`; one primary action per view.
+ **Intent.** v1 components use the semantic tokens only. Base: not chosen yet (Q-comp-01). Buttons are 40px tall (comfortable), 12 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.
+ - Inputs keep a 3:1 boundary (`color.border.input`); signifier strength: balanced.
- 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:** none (errors 0, warnings 0).
**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: 289 rules followed in this project.
+ House standards v3: 288 rules followed in this project; 1 overridden.
**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 use transition: all (STD-performance-properties-06).
- Never disable pinch zoom (STD-accessibility-motion-27).
- <details><summary>Every theme (225 rules)</summary>
+ **Overridden in this project**
+ - ~~Colors adapt to light and dark~~ Overridden in this project: "Kunal 2026-10-14: keep the website only in light mode, do not keep it in dark mode" (D-0047). The house rule: Make interface colors adapt to light and dark mode: give each color role a light value and a dark value. (STD-visual-details-24).
+ <details><summary>Every theme (224 rules)</summary>
+
- **When to animate** (14 rules, 12 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 4 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** (29 rules, 16 must): Never enter from scale(0); No opacity-only fade entrances; Scale popovers from their trigger; Keep modals scaling from center; Exit the way it entered; Dropdowns and popovers: scale 0.95, 200ms; Tooltips: scale 0.97, 125ms; Delay only the first tooltip; and 8 more must rules. Locks `motion.scale.enter` 0.95, `motion.duration.medium` 200ms (STD-easing-duration-07 wins), `motion.duration.tooltip` 125ms, `motion.scale.enter-tooltip` 0.97, `motion.duration.instant` 0ms (STD-when-to-animate-05 wins), `motion.duration.modal` 250ms, `motion.scale.enter-modal` 0.96, `motion.duration.stagger` 50ms, `motion.duration.reveal` 600ms, `motion.blur.crossfade` 2px, `motion.easing.drawer` [0.32, 0.72, 0, 1], `motion.duration.drawer` 500ms.
- **Springs and gestures** (32 rules, 21 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 13 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** (14 rules, 9 must): Animate only transform and opacity; Only clip-path, accordion height, childless width; Never use transition: all; Motion: animate the full transform string; Keep per-frame values out of React state; Set drag transforms on the moving element; Pick the cheapest animation tool; Treat dropped frames as a regression; and 1 more must rule.
- **Accessibility in motion** (18 rules, 11 must): Ship reduced motion with the animation; Reduced motion is gentler, never zero; Check reduced motion by toggling it; Reduced transparency makes surfaces solid; Increased contrast gets solid, bordered surfaces; Scale layout with the user's text size; Gate hover motion to fine pointers; Build overlays on accessible primitives; and 3 more must rules. 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** (23 rules, 7 must): Fill gaps between toasts for hover; Pause toast timers in a hidden tab; Toast classNames need !important; Copy Sonner styles into shadow DOM; Drawer curve: cubic-bezier(0.32, 0.72, 0, 1); Feedback on press, commit on release; Hold to confirm: slow press, fast release. Locks `motion.duration.toast` 400ms, `motion.easing.toast` [0.25, 0.1, 0.25, 1], `component.toast.gap` 14px, `component.toast.visible` 3, `component.toast.duration` 4000ms, `component.toast.offset.desktop` 32px, `component.toast.offset.mobile` 16px, `motion.easing.drawer` [0.32, 0.72, 0, 1] (STD-enter-exit-origin-41 wins), `motion.gesture.drag-lock-after-scroll` 100ms.
- **Mobile and touch** (20 rules, 16 must): Detect touch by capability, never by device; Remove the tap highlight flash globally; Press feedback scales to 0.97, briefly; Remove the tap delay on tappables; Touch targets 44pt on iOS, 48dp on Android; Size full-height layouts with dvh and svh; Form inputs at 16px or larger; Contain overscroll in app layouts; and 8 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, `font.size.input` 16px.
- - **Visual details** (49 rules, 19 must): Cap body text near 65ch; Tabular digits for changing numbers; Use the ellipsis character; Loosen tracking on uppercase labels; Make letter-spacing specific to size; Reserve underlines for links; Metric-matched fallback font stack; Never stack light translucent surfaces; and 11 more must rules.
+ - **Visual details** (48 rules, 19 must): Cap body text near 65ch; Tabular digits for changing numbers; Use the ellipsis character; Loosen tracking on uppercase labels; Make letter-spacing specific to size; Reserve underlines for links; Metric-matched fallback font stack; Never stack light translucent surfaces; and 11 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.
</details>
Every rule, with its values, reasons and sources: `opendesigner/standards.md` (it also has the 64 rules this file leaves out). Read the themes you touch before you build.
## Motion
> Zoom: sketch (0 of 3), 1 decision in this area. To zoom in, answer Q-motion-01.
<!-- od:zoom area=motion level=0 -->
**Most movements take 200ms.** They turn into fades when a person asks for less motion.
Designers: motion system: duration, easing, springs · Code: `motion.duration.*, motion.easing.*`
<details><summary>More</summary>
- **Intent.** Energy 40/100: the duration multiplier x0.96 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).
+ **Intent.** Energy 30/100: the duration multiplier x0.92 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).
| 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` | 670ms | illustrative and marketing motion only, never UI (STD-easing-duration-06) |
+ | `motion.duration.extra` | 640ms | 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.drawer` | 500ms | set by house standard STD-enter-exit-origin-41 |
| `motion.duration.modal` | 250ms | set by house standard STD-enter-exit-origin-11 |
| `motion.duration.reduced-fade` | 200ms | set by house standard STD-accessibility-motion-02 |
| `motion.duration.reveal` | 600ms | set by house standard STD-enter-exit-origin-26 |
| `motion.duration.stagger` | 50ms | set by house standard STD-enter-exit-origin-13 |
| `motion.duration.toast` | 400ms | set by house standard STD-components-toasts-drawers-07 |
| `motion.duration.tooltip` | 125ms | set by house standard STD-enter-exit-origin-09 |
- 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: medium intensity where the platform has them; sound: hook H-sound is pending.
+ - Haptics: light intensity where the platform has them; sound: hook H-sound is not-needed.
- Decisions: D-0011 (34 values, standards), D-0027 (dials.energy).
+ Decisions: D-0011 (34 values, standards), D-0054 (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 -->
+ > Zoom: defined (2 of 3), 1 decision in this area. To zoom in, answer Q-theme-02, Q-theme-04.
+ <!-- od:zoom area=modes level=2 -->
- **The system has light and dark color modes, three spacing densities and a reduced-motion mode.**
+ **The system has one color mode, 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, plus a switch in the app** (delegated; tokens; Q-theme-01)
+ - Should the app have light and dark modes that follow the device, or just one mode? **Light only** (chosen; 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 |
+ | density | spacious, comfortable, compact | comfortable |
| motion | standard, reduced | standard |
- 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).
+ Decisions: D-0048 (answers.Q-theme-01).
</details>
## Iconography and Imagery
- > Zoom: sketch (0 of 3), 2 decisions in this area. To zoom in, answer Q-icon-01, Q-icon-02, Q-icon-06.
+ > Zoom: sketch (0 of 3), 7 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.
+ **Icons are 20px 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.
+ **Intent.** Default icon size 20px; 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 | have |
- | Favicon set | H-favicon | pending |
- | App icon | H-appicon | pending |
- | Custom icons | H-icons | pending |
- | Illustration | H-illus | pending |
- | Photography | H-photo | pending |
+ | Favicon set | H-favicon | have |
+ | App icon | H-appicon | not-needed |
+ | Custom icons | H-icons | open-library |
+ | Illustration | H-illus | not-needed |
+ | Photography | H-photo | open-library |
| 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: D-0029 (hooks.H-logo.status), D-0032 (hooks.H-logo.files).
+ Decisions: D-0029 (hooks.H-logo.status), D-0032 (hooks.H-logo.files), D-0040 (hooks.H-appicon.status), D-0043 (hooks.H-favicon.status), D-0044 (hooks.H-photo.status), D-0045 (hooks.H-illus.status), D-0046 (hooks.H-icons.status).
</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 **full** (Brand presence 80); **sentence-case**; contractions **allowed** (Warmth 30). Voice guide hook H-voice: pending.
+ **Intent.** Draft: voice guidance level **short** (Brand presence 55); **sentence-case**; contractions **allowed** (Warmth 30). 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? **Now and then, on a phone or in public** (delegated; tokens; Q-aud-01)
+ - 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 web, secondary, 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? **Web, Watch, TV, car or headset** (delegated; tokens; Q-plat-01)
- **Intent.** Platforms: web, secondary. Inputs: pointer, touch. Brand presence 80: each platform keeps its own shapes and materials: no; each platform keeps its own body text size: no.
+ **Intent.** Platforms: web, secondary. Inputs: pointer, touch. Brand presence 55: 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: Hanken Grotesk (open licence or system font: web, apps and self-hosting).
Decisions: D-0006 (answers.Q-plat-01).
</details>
## Decisions
- **32 decisions so far.** Each one says who set it and why.
+ **58 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` | "large" | delegated | sketch: picked for them |
- | D-0003 | `context.audience` | "people who use it now and then, often on a phone" | delegated | sketch: plain words for Q-aud-01, picked for them |
| D-0006 | `answers.Q-plat-01` | ["web", "secondary"] | delegated | sketch: picked for them |
- | D-0007 | `macros` | ["bold", "premium", "friendly"] | delegated | sketch: picked for them (feel words: bold, premium, warm) |
- | D-0008 | `taste.feelWords` | ["bold", "premium", "warm"] | delegated | sketch: feel words picked for them |
- | D-0009 | `answers.Q-theme-01` | "light-dark-toggle" | delegated | sketch: picked for them |
- | D-0010 | `answers.Q-scope-06` | ["social cards:persuade", "readme:read"] | delegated | sketch: picked for them |
- | D-0012 | `dials.expression` | 68 | delegated | Kunal's taste-poll profile, nudged toward bold brand marketing |
| D-0013 | `dials.brand` | 80 | delegated | Kunal's taste-poll profile, nudged toward bold brand marketing |
- | D-0014 | `dials.density` | 30 | delegated | Kunal's taste-poll profile, nudged toward bold brand marketing |
- | D-0016 | `dials.roundness` | 40 | delegated | Kunal's taste-poll profile, nudged toward bold brand marketing |
- | D-0017 | `dials.depth` | 30 | delegated | Kunal's taste-poll profile, nudged toward bold brand marketing |
| D-0018 | `dials.colour` | 62 | delegated | Kunal's taste-poll profile, nudged toward bold brand marketing |
- | D-0020 | `dials.colorfulness` | 62 | delegated | taste-poll profile; earlier set under the wrong id 'colour' |
- | D-0021 | `dials.brandPresence` | 80 | delegated | taste-poll profile; earlier set under the wrong id 'brand' |
| D-0022 | `dials.notADial` | 5 | chosen | test |
| D-0023 | `answers.Q-type-01` | "open-custom" | chosen | owner wants a real typeface; Hanken Grotesk, light display + bold highlight, picked by eye from a specimen |
| D-0024 | `raw.textFace` | "Hanken Grotesk" | chosen | specimen test: calm, premium at light weights, not tied to another company |
- | D-0025 | `raw.brandColor` | "#2338FF" | chosen | owner feedback 2026-10-14: hated brown background + orange + cream; wants striking color with clear tonal contrast |
| D-0026 | `dials.warmth` | 30 | chosen | owner feedback 2026-10-14: hated brown background + orange + cream; wants striking color with clear tonal contrast; warmth 68 made the neutrals brown |
- | D-0027 | `dials.energy` | 40 | delegated | calm, Palantir-like restraint |
| D-0028 | `type.headingWeight` | 400 | chosen | owner: titles need not be bold; light/regular titles like Palantir's; bold is kept for the highlighted phrase |
| D-0029 | `hooks.H-logo.status` | "have" | asset | mark (square-to-circle tiles) and lockup in Hanken Grotesk, outlined; brand/design-system |
| D-0031 | `hooks.H-type.status` | "open-library" | chosen | Hanken Grotesk (SIL OFL) from Google Fonts |
| D-0032 | `hooks.H-logo.files` | ["design-system/project/assets/Logos/lockup-light.svg", "design-system/project/assets/Logos/mark-light.svg"] | asset | logo files, paths relative to the project root |
+ | D-0034 | `dials.depth` | 15 | chosen | owner 2026-10-14: no drop shadows, hairline borders instead |
+ | D-0035 | `answers.Q-aud-01` | "regular" | delegated | judgment 2026-10-14 after Kunal: top customers are B2B and enterprise; readers are design-system teams, designers and engineers who read the docs at work,... |
+ | D-0036 | `context.audience` | "design-system teams, product designers and engineers, mostly at work on a desktop, including enterprise and B2B teams" | delegated | judgment 2026-10-14 after Kunal: top customers are B2B and enterprise |
+ | D-0037 | `answers.Q-scope-01` | ["marketing", "docs-content"] | delegated | judgment 2026-10-14 after Kunal: top customers are B2B and enterprise; the system styles opendesigner.vercel.app (landing and docs), social cards and the... |
+ | D-0038 | `answers.Q-scope-06` | ["landing page:persuade", "documentation:read", "social cards:persuade", "readme:read"] | delegated | judgment 2026-10-14 after Kunal: top customers are B2B and enterprise; the docs site is now the main surface |
+ | D-0039 | `raw.brandColor` | "#2338FF" | chosen (locked) | Kunal chose cobalt over the AI's red; locked so later sessions cannot drift it |
+ | D-0040 | `hooks.H-appicon.status` | "not-needed" | delegated | judgment 2026-10-14 after Kunal: top customers are B2B and enterprise; there is no app, only a site, docs and social cards |
+ | D-0041 | `hooks.H-sound.status` | "not-needed" | delegated | no app and no sound on the site |
+ | D-0042 | `hooks.H-haptic.status` | "not-needed" | delegated | no app |
+ | D-0043 | `hooks.H-favicon.status` | "have" | asset | the favicon set is made from the mark (site/build.py images()) |
+ | D-0044 | `hooks.H-photo.status` | "open-library" | delegated | judgment 2026-10-14 after Kunal: top customers are B2B and enterprise; free Unsplash photos (abstract blurs, workspaces) in a cobalt duotone or as a grainy... |
+ | D-0045 | `hooks.H-illus.status` | "not-needed" | delegated | judgment 2026-10-14 after Kunal: top customers are B2B and enterprise; enterprise buyers need to see the product, so figures are drawn from real UI and data... |
+ | D-0046 | `hooks.H-icons.status` | "open-library" | delegated | a few line arrows and the GitHub mark only; if more are needed, one open library at one stroke weight |
+ | D-0048 | `answers.Q-theme-01` | "light-only" | chosen | Kunal 2026-10-14: keep the website only in light mode, no dark mode |
+ | D-0049 | `taste.feelWords` | ["technical", "premium", "calm", "precise", "friendly"] | chosen | Kunal 2026-10-14 for B2B and enterprise buyers: technical, premium, calm, precise, friendly |
+ | D-0050 | `macros` | ["modern", "serious", "premium", "minimal", "friendly"] | chosen | Kunal 2026-10-14 for B2B and enterprise buyers: technical, premium, calm, precise, friendly (engine reading: technical = modern + serious, calm = minimal,... |
+ | D-0051 | `dials.expression` | 40 | delegated | Kunal 2026-10-14 for B2B and enterprise buyers: technical, premium, calm, precise, friendly: calm and precise means modest type contrast; real UI and... |
+ | D-0052 | `dials.brandPresence` | 55 | delegated | Kunal 2026-10-14 for B2B and enterprise buyers: technical, premium, calm, precise, friendly: cobalt marks actions and one highlight per view, the rest stays... |
+ | D-0053 | `dials.density` | 45 | delegated | Kunal 2026-10-14 for B2B and enterprise buyers: technical, premium, calm, precise, friendly: technical readers at a desk; tighter than a marketing page,... |
+ | D-0054 | `dials.energy` | 30 | delegated | Kunal 2026-10-14 for B2B and enterprise buyers: technical, premium, calm, precise, friendly: calm; short, quiet motion |
+ | D-0055 | `dials.colorfulness` | 35 | delegated | Kunal 2026-10-14 for B2B and enterprise buyers: technical, premium, calm, precise, friendly: one accent plus status colors, as premium B2B tools do |
+ | D-0056 | `dials.roundness` | 75 | chosen | Kunal 2026-10-14: use iOS style rounded edges with iOS kerning everywhere instead of sharp corners |
+ | D-0057 | `answers.Q-shape-04` | "continuous" | chosen | Kunal 2026-10-14: use iOS style rounded edges with iOS kerning everywhere instead of sharp corners (Apple-style continuous corners) |
+ | D-0058 | `answers.Q-type-13` | "size-table" | chosen | Kunal 2026-10-14: use iOS style rounded edges with iOS kerning everywhere instead of sharp corners (Apple's SF Pro tracking table by size, HIG Typography,... |
+ | D-0047 | standards | override STD-visual-details-24 (house standard) | chosen, overrides STD-visual-details-24 | Kunal 2026-10-14: keep the website only in light mode, do not keep it in dark mode |
| D-0011 | standards | House standards v2: 289 applied | standard (locked) | OpenDesigner's house standards (sources marked non-negotiable) are applied without asking and locked. Change one only when the person asks: engine.py... |
</details>
## Open Items
**These parts are still defaults, guesses, or waiting for a person.**
- - Still defaults (zoom 0, sketch): Colors, Layout, Elevation & Depth, Shapes, Components, Motion, Modes and Themes, Iconography and Imagery, Content and Voice, Accessibility, Platforms and Devices
- - Assets not final: 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), answers.Q-plat-01 (delegated), macros (delegated), taste.feelWords (delegated), answers.Q-theme-01 (delegated), answers.Q-scope-06 (delegated), dials.expression (delegated), dials.brand (delegated), dials.density (delegated), dials.energy (delegated), dials.roundness (delegated), dials.depth (delegated), dials.colour (delegated), dials.colorfulness (delegated), dials.brandPresence (delegated)
+ - Still defaults (zoom 0, sketch): Colors, Layout, Elevation & Depth, Shapes, Components, Motion, Iconography and Imagery, Content and Voice, Accessibility, Platforms and Devices
+ - Assets not final: 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; 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), answers.Q-plat-01 (delegated), answers.Q-scope-06 (delegated), dials.expression (delegated), dials.brand (delegated), dials.density (delegated), dials.energy (delegated), dials.colour (delegated), dials.colorfulness (delegated), dials.brandPresence (delegated), answers.Q-scope-01 (delegated), hooks.H-appicon.status (delegated), hooks.H-sound.status (delegated), hooks.H-haptic.status (delegated), hooks.H-photo.status (delegated), hooks.H-illus.status (delegated), hooks.H-icons.status (delegated)
- Waivers: none.
- - Licence risks: none found.
+ - Licence risks: Custom icons, pictograms, spot icons: check the terms of the set you use. Recraft vector output with its plan terms. Photography and art direction: check the terms of the set you use. Stock: Unsplash (free, irrevocable, commercial; no competing service) or Pexels (no implied endorsement, no use as a trademark).
- Validation: 0 errors, 0 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.
+ 2. Use tokens, never raw values: CSS `var(--ds-...)`, Tailwind classes from `opendesigner/build/tailwind/theme.css`, `DS.*` in Swift. In Compose: colors from `LocalDsColors.current` (provide `DsLightColors` or `DsDarkColors`), then `DsSpace`, `DsType` and `DsMotion`.
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` |
+ | Type | `text-body-md`, `text-label-lg`, `text-title-md` |
| Motion | `transition-feedback`, `ease-enter`, `ease-exit`, `ease-hover` |