@jabworks/condux 0.14.2 → 0.15.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jabworks/condux",
3
- "version": "0.14.2",
3
+ "version": "0.15.0",
4
4
  "description": "OpenCode plugin for the condux workflow toolkit — bundles the condux skills and injects the specialist agents (coder, explorer, planner, researcher) plus an opt-in plan-review listener.",
5
5
  "type": "module",
6
6
  "publishConfig": {
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: blueprint
3
- description: "Produce dependency-free visual clarity artifacts at design time — grayscale HTML wireframes for UI screens and flows, and inline-SVG system diagrams (data models, flows, architecture, state machines) for backend work. During /discovery when the feature has a UI surface or a data model, from /draft-plan task cards, or standalone on \"mock this up\", \"wireframe this screen\", \"visualize the data model\", \"sketch the architecture\", \"diagram the flow\". Not for aesthetic or brand direction, editable design canvases or Figma, charts from real data, or generating code from a mockup."
3
+ description: "Produce dependency-free visual clarity artifacts at design time — HTML wireframes and full renders for UI screens and flows in the house design language (surface-kit tokens), and inline-SVG system diagrams (data models, flows, architecture, state machines) for backend work. During /discovery when the feature has a UI surface or a data model, from /draft-plan task cards, or standalone on \"mock this up\", \"wireframe this screen\", \"visualize the data model\", \"sketch the architecture\", \"diagram the flow\". Not for aesthetic or brand direction, editable design canvases or Figma, charts from real data, or generating code from a mockup."
4
4
  argument-hint: "[surface or model to visualize — optional; defaults to the current design context]"
5
5
  ---
6
6
 
@@ -8,7 +8,9 @@ argument-hint: "[surface or model to visualize — optional; defaults to the cur
8
8
 
9
9
  Make the design visible before it's built. Wireframes tell a frontend dev what
10
10
  goes where and why; system diagrams tell a backend dev what talks to what.
11
- Structure, never style.
11
+ Structure first — and everything speaks the house design language (the
12
+ surface-kit token core), so a mockup already looks like it belongs to the
13
+ product family.
12
14
 
13
15
  ## Usage
14
16
 
@@ -33,9 +35,11 @@ Structure, never style.
33
35
  │ │
34
36
  │ Step 2: PRODUCE │
35
37
  │ One self-contained HTML file per screen / flow state / diagram. │
36
- │ Wireframes follow references/wireframe-kit.md. │
37
- │ Diagrams follow references/diagram-kit.md. │
38
- │ No external assets, no CDN, no fonts beyond the system stack. │
38
+ │ Wireframes follow references/wireframe-kit.md — wireframe mode │
39
+ │ by default; render mode when structure is signed off or the │
40
+ │ user asks for fidelity. Diagrams follow references/ │
41
+ │ diagram-kit.md. All styling from references/token-core.css. │
42
+ │ No external assets, no CDN, no font files. │
39
43
  │ │
40
44
  │ Step 3: DELIVER │
41
45
  │ Open in the browser (xdg-open / open). If neither works │
@@ -50,11 +54,15 @@ Structure, never style.
50
54
 
51
55
  ## The Two Families
52
56
 
53
- **Wireframes (UI clarity).** Grayscale boxes with real content hierarchy and
54
- annotation callouts. A wireframe answers: what elements exist, how they group,
55
- what order they read in, what happens on each state (empty, loading, error,
56
- populated). Multiple states of one flow are separate files, named for the
57
- state. The full discipline — hard rules plus a copyable base-CSS block — is in
57
+ **Wireframes and renders (UI clarity).** Two modes over one shared skeleton,
58
+ both in the house tokens. *Wireframe mode* (default) is schematic — dashed
59
+ grouping, neutral roles only, annotation callouts — and answers: what elements
60
+ exist, how they group, what order they read in, what happens on each state
61
+ (empty, loading, error, populated). *Render mode* unlocks the full language
62
+ (accent, semantic and categorical colour, elevation, motion) to show how the
63
+ settled structure will look; promotion is a style-block swap, the skeleton
64
+ never changes. Multiple states of one flow are separate files, named for the
65
+ state. The full discipline — hard rules plus copyable mode CSS blocks — is in
58
66
  `references/wireframe-kit.md`.
59
67
 
60
68
  **System diagrams (BE clarity).** Hand-authored inline SVG for four shapes:
@@ -94,8 +102,9 @@ mockup into the spec directory first and cite the committed copy.
94
102
  ## What Does NOT Happen
95
103
 
96
104
  ```
97
- ✗ Brand styling, palettes, typography choices, premium polish — structure only
98
- ✗ Colors beyond grayscale (one muted annotation accent is the ceiling)
105
+ ✗ Palettes or typography outside the shared token core — the house language
106
+ is the ceiling, render mode included; blueprint is not a brand playground
107
+ ✗ Chromatic colour in wireframe mode (neutral roles + the annotation accent)
99
108
  ✗ External dependencies — no Mermaid CDN, no image generation, no Figma
100
109
  ✗ Code generation from the mockup (that's implementation's job, later)
101
110
  ✗ Charts of real data (that's a dataviz concern, not a design mockup)
@@ -2,28 +2,33 @@
2
2
 
3
3
  Reference for `/blueprint`. Hand-authored inline SVG — no Mermaid, no CDN, no
4
4
  renderer dependency. Every diagram is a self-contained HTML file that renders
5
- from `file://`.
5
+ from `file://`. Diagrams have one look — no wireframe/render split — and it is
6
+ the house language: paste `token-core.css` (sibling of this file) at the top
7
+ of the `<style>` block, verbatim.
6
8
 
7
9
  ## Shared Conventions
8
10
 
9
11
  - Canvas: `<svg viewBox="0 0 W H" style="max-width:100%">` sized to content;
10
- the page wraps it in the same `.frame` shell as the wireframe kit.
11
- - Palette mirrors the wireframe discipline: fills `#fff`/`#f0f0f0`, strokes
12
- `#777`, text `#222`, the `#5b7c99` accent for the one thing the diagram is
13
- about (the new entity, the changed edge) — never more than one accent use.
14
- - Text: `font-family: -apple-system, "Segoe UI", Roboto, sans-serif`, 13–14px
15
- labels, 11px annotations. If a label doesn't fit its box, the box grows —
16
- never shrink the font below 11px.
12
+ the page wraps it in the wireframe kit's `.frame` shell (either mode's).
13
+ - Palette is token roles, referenced with `var(--…)` (CSS variables work in
14
+ inline SVG attributes): fills `var(--card)` / `var(--muted)`, strokes
15
+ `var(--border)`, edges `var(--subtle)`, text `var(--foreground)`. The one
16
+ accent is the `--primary` family — for the one thing the diagram is about
17
+ (the new entity, the changed edge) — never more than one accent use.
18
+ - Text: `--sans` for titles, `--mono` for everything that is data — field
19
+ rows, cardinalities, edge labels (D2). 13–14px labels, 11px annotations
20
+ in `var(--muted-foreground)`. If a label doesn't fit its box, the box
21
+ grows — never shrink the font below 11px.
17
22
  - Arrowheads via one shared `<marker>`:
18
23
 
19
24
  ```html
20
25
  <defs>
21
26
  <marker id="arrow" viewBox="0 0 10 10" refX="9" refY="5"
22
27
  markerWidth="7" markerHeight="7" orient="auto-start-reverse">
23
- <path d="M0,0 L10,5 L0,10 z" fill="#777"/>
28
+ <path d="M0,0 L10,5 L0,10 z" fill="var(--subtle)"/>
24
29
  </marker>
25
30
  </defs>
26
- <!-- usage: <line ... stroke="#777" marker-end="url(#arrow)"/> -->
31
+ <!-- usage: <line ... stroke="var(--subtle)" marker-end="url(#arrow)"/> -->
27
32
  ```
28
33
 
29
34
  - Every relationship line gets a label. An unlabeled arrow is a guess the
@@ -36,18 +41,22 @@ labels carry cardinality (`1..*`, `0..1`).
36
41
 
37
42
  ```html
38
43
  <g transform="translate(40,40)">
39
- <rect width="200" height="24" fill="#f0f0f0" stroke="#777"/>
44
+ <rect width="200" height="24" fill="var(--muted)" stroke="var(--border)" rx="3"/>
40
45
  <text x="100" y="17" text-anchor="middle" font-weight="600">orders</text>
41
- <rect y="24" width="200" height="72" fill="#fff" stroke="#777"/>
46
+ <rect y="24" width="200" height="72" fill="var(--card)" stroke="var(--border)"/>
42
47
  <text x="8" y="41">id PK</text>
43
48
  <text x="8" y="61">user_id FK</text>
44
49
  <text x="8" y="81">status</text>
45
50
  </g>
46
51
  <!-- edge: users 1..* orders -->
47
- <line x1="240" y1="80" x2="340" y2="80" stroke="#777" marker-end="url(#arrow)"/>
48
- <text x="290" y="72" text-anchor="middle" font-size="11">1..*</text>
52
+ <line x1="240" y1="80" x2="340" y2="80" stroke="var(--subtle)" marker-end="url(#arrow)"/>
53
+ <text x="290" y="72" text-anchor="middle" font-size="11" fill="var(--muted-foreground)">1..*</text>
49
54
  ```
50
55
 
56
+ An accented entity (the diagram's one accent) swaps its title-bar fill to
57
+ `var(--primary-muted)`, its strokes to `var(--primary)`, and its title text to
58
+ `var(--primary-text)`.
59
+
51
60
  ## 2. Request / Data Flow
52
61
 
53
62
  Actors and stores as boxes on one horizontal band; numbered edges show
@@ -0,0 +1,173 @@
1
+ /* Shared design core — do not hand-edit; edit scripts/tokens/core.css. */
2
+ :root {
3
+ --background: #111110;
4
+ --card: #191918;
5
+ --card-foreground: #eeeeec;
6
+ --popover: #222221;
7
+ --foreground: #eeeeec;
8
+ --muted: #222221;
9
+ --muted-foreground: #b5b3ad;
10
+ --border: #3b3a37;
11
+ --input: #3b3a37;
12
+ --primary: #978365;
13
+ --primary-foreground: #ffffff;
14
+ --primary-hover: #a39073;
15
+ --primary-muted: #24231f;
16
+ --primary-text: #cbb99f;
17
+ --ring: #978365;
18
+ --accent: #2a2a28;
19
+ --success: #71d083;
20
+ --success-muted: #1b2a1e;
21
+ --success-border: #2d5736;
22
+ --warning: #ffca16;
23
+ --warning-muted: #302008;
24
+ --warning-border: #5c3d05;
25
+ --destructive: #ff977d;
26
+ --destructive-muted: #391714;
27
+ --destructive-border: #6e2920;
28
+ --info: #70b8ff;
29
+ --info-muted: #0d2847;
30
+ --info-border: #104d87;
31
+ /* categorical — series identity; neither the accent nor the semantics */
32
+ --cat-1: #cf686e;
33
+ --cat-2: #897ed6;
34
+ --cat-3: #41a265;
35
+ --cat-4: #3694d4;
36
+ --cat-5: #94911b;
37
+ --cat-6: #ba6cae;
38
+ --cat-7: #c37827;
39
+ --cat-8: #00a0a4;
40
+ --cat-other: #686560;
41
+ --outline: rgba(237, 237, 236, 0.08);
42
+ --subtle: #686560;
43
+ --shadow-sm: 0 1px 2px rgba(6, 6, 5, 0.5);
44
+ --shadow-md: 0 4px 14px rgba(6, 6, 5, 0.55);
45
+ --shadow-lg: 0 20px 60px rgba(6, 6, 5, 0.62);
46
+ --mono: "Geist Mono", "JetBrains Mono", ui-monospace, "SF Mono", Menlo, Monaco, "Cascadia Code", monospace;
47
+ --sans: "Geist", "Inter Tight", ui-sans-serif, system-ui, -apple-system, "Segoe UI Variable Text", "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
48
+ --text-2xs: 0.6875rem;
49
+ --text-xs: 0.75rem;
50
+ --text-sm: 0.8125rem;
51
+ --text-base: 0.875rem;
52
+ --text-md: 1rem;
53
+ --text-lg: 1.125rem;
54
+ --text-xl: 1.375rem;
55
+ --text-2xl: 1.75rem;
56
+ --text-3xl: 2.5rem;
57
+ --text-4xl: 3.5rem;
58
+ --leading-tight: 1.15;
59
+ --leading-snug: 1.35;
60
+ --leading-normal: 1.55;
61
+ --leading-relaxed: 1.7;
62
+ --tracking-tight: -0.022em;
63
+ --tracking-normal: 0em;
64
+ --tracking-wide: 0.06em;
65
+ --space-1: 0.25rem;
66
+ --space-2: 0.5rem;
67
+ --space-3: 0.75rem;
68
+ --space-4: 1rem;
69
+ --space-5: 1.5rem;
70
+ --space-6: 2rem;
71
+ --space-8: 3rem;
72
+ --space-12: 4rem;
73
+ --radius-sm: 0.1875rem;
74
+ --radius: 0.25rem;
75
+ --radius-md: 0.5rem;
76
+ --radius-lg: 0.75rem;
77
+ --radius-full: 9999px;
78
+ --dur-fast: 120ms;
79
+ --dur: 200ms;
80
+ --dur-slow: 320ms;
81
+ --ease-out: cubic-bezier(0.22, 1, 0.36, 1);
82
+ --ease-spring: cubic-bezier(0.34, 1.56, 0.64, 1);
83
+ }
84
+ @media (prefers-color-scheme: light) {
85
+ :root:not([data-theme="dark"]) {
86
+ --background: #f6f5ef;
87
+ --card: #fcfbf6;
88
+ --card-foreground: #36302a;
89
+ --popover: #fcfbf6;
90
+ --foreground: #36302a;
91
+ --muted: #f0efe3;
92
+ --muted-foreground: #726c5e;
93
+ --border: #ddd6c6;
94
+ --input: #ddd6c6;
95
+ --primary: #967e60;
96
+ --primary-foreground: #ffffff;
97
+ --primary-hover: #897254;
98
+ --primary-muted: #efece0;
99
+ --primary-text: #6f5e44;
100
+ --ring: #967e60;
101
+ --accent: #eae7da;
102
+ --success: #3f7a34;
103
+ --success-muted: #e6f5e2;
104
+ --success-border: #c2e1b3;
105
+ --warning: #93761d;
106
+ --warning-muted: #fbf4c4;
107
+ --warning-border: #ebd87f;
108
+ --destructive: #bf4f3b;
109
+ --destructive-muted: #fbe8e2;
110
+ --destructive-border: #f0c9ba;
111
+ --info: #3f6fa6;
112
+ --info-muted: #e6f1fc;
113
+ --info-border: #bed7ef;
114
+ --cat-1: #b04d54;
115
+ --cat-2: #6f63b8;
116
+ --cat-3: #1e874b;
117
+ --cat-4: #0a78b7;
118
+ --cat-5: #797600;
119
+ --cat-6: #9d5192;
120
+ --cat-7: #a45e00;
121
+ --cat-8: #008f93;
122
+ --cat-other: #a8a294;
123
+ --outline: rgba(54, 48, 42, 0.08);
124
+ --subtle: #a8a294;
125
+ --shadow-sm: 0 1px 2px rgba(54, 48, 42, 0.1);
126
+ --shadow-md: 0 4px 14px rgba(54, 48, 42, 0.13);
127
+ --shadow-lg: 0 20px 60px rgba(54, 48, 42, 0.18);
128
+ }
129
+ }
130
+ :root[data-theme="light"] {
131
+ --background: #f6f5ef;
132
+ --card: #fcfbf6;
133
+ --card-foreground: #36302a;
134
+ --popover: #fcfbf6;
135
+ --foreground: #36302a;
136
+ --muted: #f0efe3;
137
+ --muted-foreground: #726c5e;
138
+ --border: #ddd6c6;
139
+ --input: #ddd6c6;
140
+ --primary: #967e60;
141
+ --primary-foreground: #ffffff;
142
+ --primary-hover: #897254;
143
+ --primary-muted: #efece0;
144
+ --primary-text: #6f5e44;
145
+ --ring: #967e60;
146
+ --accent: #eae7da;
147
+ --success: #3f7a34;
148
+ --success-muted: #e6f5e2;
149
+ --success-border: #c2e1b3;
150
+ --warning: #93761d;
151
+ --warning-muted: #fbf4c4;
152
+ --warning-border: #ebd87f;
153
+ --destructive: #bf4f3b;
154
+ --destructive-muted: #fbe8e2;
155
+ --destructive-border: #f0c9ba;
156
+ --info: #3f6fa6;
157
+ --info-muted: #e6f1fc;
158
+ --info-border: #bed7ef;
159
+ --cat-1: #b04d54;
160
+ --cat-2: #6f63b8;
161
+ --cat-3: #1e874b;
162
+ --cat-4: #0a78b7;
163
+ --cat-5: #797600;
164
+ --cat-6: #9d5192;
165
+ --cat-7: #a45e00;
166
+ --cat-8: #008f93;
167
+ --cat-other: #a8a294;
168
+ --outline: rgba(54, 48, 42, 0.08);
169
+ --subtle: #a8a294;
170
+ --shadow-sm: 0 1px 2px rgba(54, 48, 42, 0.1);
171
+ --shadow-md: 0 4px 14px rgba(54, 48, 42, 0.13);
172
+ --shadow-lg: 0 20px 60px rgba(54, 48, 42, 0.18);
173
+ }
@@ -1,88 +1,295 @@
1
1
  # Wireframe Kit
2
2
 
3
- Reference for `/blueprint`. The discipline is what keeps a wireframe
4
- unambiguous: the moment brand styling creeps in, reviewers debate taste
5
- instead of structure.
3
+ Reference for `/blueprint`. Every mockup speaks the house design language —
4
+ the surface-kit token core in `token-core.css` beside this file — in one of
5
+ two modes. The discipline is what keeps a mockup unambiguous: in wireframe
6
+ mode the schematic look keeps reviewers debating structure instead of taste;
7
+ in render mode the full language shows how the approved structure will
8
+ actually look.
9
+
10
+ ## The Two Modes
11
+
12
+ | | `wireframe` | `render` |
13
+ |---|---|---|
14
+ | When | design time — structure is the open question | sign-off / presentation — structure is settled |
15
+ | Colour roles | neutrals only; semantics stay silent | full palette: accent, semantic, categorical |
16
+ | Grouping | dashed borders, flat corners | solid borders, radius + elevation |
17
+ | Buttons | transparent outlines, emphasis by border weight | filled `--primary`, hover, motion |
18
+ | Overall read | "schematic under discussion" | "this is how it'll look" |
19
+
20
+ **Same skeleton, two skins.** Both modes share identical HTML structure and
21
+ class names; only the component CSS block differs. Promoting a signed-off
22
+ wireframe to a render is a style-block swap — nothing may move. Declare the
23
+ mode on the body: `<body data-blueprint-mode="wireframe">` (or `"render"`).
24
+
25
+ Default to wireframe mode. Produce a render when the structure is already
26
+ signed off, when the user asks for fidelity ("make it look real", "mock this
27
+ up properly"), or when discovery offers promotion at sign-off.
6
28
 
7
29
  ## Hard Rules
8
30
 
9
- 1. **Grayscale only.** Backgrounds `#fff`–`#f5f5f5`, borders `#ccc`,
10
- text `#222`/`#777`. One muted accent (`#5b7c99`) is allowed for
11
- annotation callouts only — never for UI elements.
12
- 2. **System font stack.** `-apple-system, "Segoe UI", Roboto, sans-serif`.
13
- No webfonts, no font files.
14
- 3. **No imagery.** Photos and illustrations render as a crossed box with a
31
+ 1. **Tokens only.** Every colour, size, radius, and duration comes from a
32
+ `var(--…)` defined in the token core. No raw hex, no ad-hoc px values
33
+ where a ramp token exists. Paste `token-core.css` (sibling of this file)
34
+ at the top of every `<style>` block, verbatim.
35
+ 2. **Wireframe mode is neutral.** Its component CSS may reference only:
36
+ `--background`, `--card`, `--foreground`, `--muted`, `--muted-foreground`,
37
+ `--border`, `--input`, `--accent`, `--subtle`, the `--primary*` family
38
+ (annotation callouts only), and every type / space / radius / motion /
39
+ font token. Semantic (`--success*`, `--warning*`, `--destructive*`,
40
+ `--info*`), categorical (`--cat-*`), and elevation (`--shadow-*`) tokens
41
+ are render-mode vocabulary.
42
+ 3. **Fonts per D2.** `--sans` for the UI's own copy; `--mono` for everything
43
+ meta — labels, badges, annotations, data. The stacks are fallbacks; never
44
+ load font files.
45
+ 4. **No imagery.** Photos and illustrations render as a crossed box with a
15
46
  label (`.img-box`). Icons render as their name in brackets, e.g. `[gear]`.
16
- 4. **Real hierarchy, placeholder content.** Headings, labels, and CTAs carry
47
+ 5. **Real hierarchy, placeholder content.** Headings, labels, and CTAs carry
17
48
  their actual intended text; body copy may be greeked with `▓▓▓` bars.
18
- 5. **Annotate decisions, not furniture.** A callout explains *why this is
49
+ 6. **Annotate decisions, not furniture.** A callout explains *why this is
19
50
  here* or *what happens on interaction* — not "this is a button".
20
- 6. **One file per screen or flow state.** Empty, loading, error, and populated
51
+ 7. **One file per screen or flow state.** Empty, loading, error, and populated
21
52
  are different files named for the state:
22
53
  `settings-page.html`, `settings-page-empty.html`, `settings-page-error.html`.
23
- 7. **Self-contained.** All CSS inline in a `<style>` block. No external
54
+ 8. **Self-contained.** All CSS inline in a `<style>` block. No external
24
55
  requests of any kind. The file must render identically from `file://`.
56
+ The token core carries dark and light themes; the page follows the OS.
25
57
 
26
- ## Base CSS
58
+ ## Page Skeleton
59
+
60
+ ```html
61
+ <title>settings-page — wireframe</title>
62
+ <style>
63
+ /* 1. token-core.css pasted verbatim */
64
+ /* 2. ONE mode block from below */
65
+ </style>
66
+ <body data-blueprint-mode="wireframe">
67
+ <div class="frame">
68
+ <div class="box"><strong>Header</strong> · [logo] · nav: Account / Billing / Team</div>
69
+ <div class="row">
70
+ <div class="box"><!-- sidebar --></div>
71
+ <div class="box" style="flex:3"><!-- main content --></div>
72
+ </div>
73
+ <div class="note">Sidebar collapses below 768px — Billing moves into the header nav.</div>
74
+ </div>
75
+ </body>
76
+ ```
27
77
 
28
- Copy this block into every wireframe's `<style>` and build on it.
78
+ ## Wireframe Mode CSS
29
79
 
30
80
  ```css
81
+ /* wireframe mode — surface-kit neutrals only, schematic look.
82
+ Emphasis by value and weight, never hue. */
31
83
  * { margin: 0; box-sizing: border-box; }
32
84
  body {
33
- font-family: -apple-system, "Segoe UI", Roboto, sans-serif;
34
- background: #f5f5f5; color: #222; padding: 24px;
85
+ font-family: var(--sans);
86
+ font-size: var(--text-base);
87
+ line-height: var(--leading-normal);
88
+ background: var(--background);
89
+ color: var(--foreground);
90
+ padding: var(--space-6);
35
91
  }
36
- .frame { /* the device/viewport boundary */
37
- background: #fff; border: 2px solid #ccc; border-radius: 6px;
38
- max-width: 1100px; margin: 0 auto; padding: 24px;
92
+ .frame {
93
+ background: var(--card);
94
+ border: 1px dashed var(--muted-foreground);
95
+ border-radius: var(--radius-sm);
96
+ max-width: 1100px; margin: 0 auto; padding: var(--space-6);
39
97
  }
40
- .box { /* generic grouping region */
41
- border: 1px dashed #bbb; border-radius: 4px;
42
- padding: 16px; margin-bottom: 16px;
98
+ .topbar {
99
+ display: flex; justify-content: space-between; align-items: baseline;
100
+ padding-bottom: var(--space-4); border-bottom: 1px solid var(--border);
101
+ margin-bottom: var(--space-5);
43
102
  }
44
- .row { display: flex; gap: 16px; }
103
+ .nav { display: flex; gap: var(--space-4); font-size: var(--text-sm); }
104
+ .nav a { color: var(--muted-foreground); }
105
+ .nav a.active { color: var(--foreground); border-bottom: 2px solid var(--foreground); padding-bottom: 2px; }
106
+ .row { display: flex; gap: var(--space-4); }
45
107
  .row > * { flex: 1; }
46
- .img-box { /* rule 3: imagery placeholder */
47
- border: 1px solid #ccc; background:
48
- linear-gradient(45deg, transparent 49.5%, #ccc 49.5%, #ccc 50.5%, transparent 50.5%),
49
- linear-gradient(-45deg, transparent 49.5%, #ccc 49.5%, #ccc 50.5%, transparent 50.5%);
108
+ .box {
109
+ background: var(--card); border: 1px dashed var(--border);
110
+ border-radius: var(--radius-sm); padding: var(--space-4); margin-bottom: var(--space-4);
111
+ }
112
+ h2 { font-size: var(--text-md); letter-spacing: var(--tracking-tight); margin-bottom: var(--space-3); }
113
+ .side-item {
114
+ padding: var(--space-2) var(--space-3); border-radius: var(--radius-sm);
115
+ color: var(--muted-foreground); font-size: var(--text-sm);
116
+ }
117
+ .side-item.active { background: var(--accent); color: var(--foreground); }
118
+ .field { margin-bottom: var(--space-3); }
119
+ label {
120
+ display: block; font-family: var(--mono); font-size: var(--text-2xs);
121
+ text-transform: uppercase; letter-spacing: var(--tracking-wide);
122
+ color: var(--muted-foreground); margin-bottom: var(--space-1);
123
+ }
124
+ input {
125
+ width: 100%; background: transparent; color: var(--foreground);
126
+ border: 1px solid var(--input); border-radius: var(--radius);
127
+ padding: var(--space-2) var(--space-3); font: inherit; font-size: var(--text-sm);
128
+ }
129
+ .btn {
130
+ display: inline-block; border: 1px solid var(--muted-foreground); border-radius: var(--radius-sm);
131
+ padding: var(--space-2) var(--space-4); background: transparent;
132
+ color: var(--foreground); font-size: var(--text-sm);
133
+ }
134
+ .btn.primary { border-width: 2px; font-weight: 600; }
135
+ .btn.danger { color: var(--muted-foreground); } /* semantics stay silent in wireframe */
136
+ .greek { color: var(--border); letter-spacing: 2px; overflow: hidden; white-space: nowrap; }
137
+ .img-box {
138
+ border: 1px solid var(--border); background:
139
+ linear-gradient(45deg, transparent 49.5%, var(--border) 49.5%, var(--border) 50.5%, transparent 50.5%),
140
+ linear-gradient(-45deg, transparent 49.5%, var(--border) 49.5%, var(--border) 50.5%, transparent 50.5%)
141
+ var(--muted);
50
142
  display: flex; align-items: center; justify-content: center;
51
- color: #777; min-height: 120px;
143
+ color: var(--muted-foreground); font-family: var(--mono); font-size: var(--text-xs);
144
+ min-height: 120px; border-radius: var(--radius);
52
145
  }
53
- .btn { /* any actionable element */
54
- display: inline-block; border: 1px solid #777; border-radius: 4px;
55
- padding: 8px 20px; background: #eee; color: #222;
146
+ table { width: 100%; border-collapse: collapse; font-size: var(--text-sm); }
147
+ th {
148
+ font-family: var(--mono); font-size: var(--text-2xs); text-transform: uppercase;
149
+ letter-spacing: var(--tracking-wide); color: var(--muted-foreground);
150
+ text-align: left; padding: var(--space-2); border-bottom: 1px solid var(--border);
56
151
  }
57
- .greek { /* rule 4: body-copy placeholder */
58
- color: #ccc; letter-spacing: 2px; overflow: hidden; white-space: nowrap;
152
+ td { padding: var(--space-2); border-bottom: 1px solid var(--border); }
153
+ .badge {
154
+ display: inline-block; font-family: var(--mono); font-size: var(--text-2xs);
155
+ padding: 2px var(--space-2); border-radius: var(--radius-full);
156
+ border: 1px solid var(--border); color: var(--muted-foreground);
59
157
  }
60
- .note { /* rule 5: annotation callout — the only accent use */
61
- border-left: 3px solid #5b7c99; background: #eef2f6; color: #33475b;
62
- padding: 8px 12px; font-size: 13px; margin: 8px 0;
158
+ .note::before { content: "\25B8 note "; font-weight: 600; letter-spacing: var(--tracking-wide); }
159
+ .note {
160
+ border-left: 3px solid var(--primary); background: var(--primary-muted);
161
+ color: var(--primary-text); border-radius: 0 var(--radius) var(--radius) 0;
162
+ padding: var(--space-2) var(--space-3); margin: var(--space-3) 0;
163
+ font-family: var(--mono); font-size: var(--text-xs); line-height: var(--leading-snug);
63
164
  }
165
+ .actions { display: flex; gap: var(--space-2); margin-top: var(--space-3); }
166
+ .choice { display: flex; gap: var(--space-2); }
167
+ .empty { text-align: center; padding: var(--space-8); border-style: dashed; }
168
+ .muted { color: var(--muted-foreground); }
64
169
  ```
65
170
 
66
171
  Greeked copy: `<div class="greek">▓▓▓▓▓▓▓▓ ▓▓▓▓ ▓▓▓▓▓▓</div>` at whatever
67
172
  width the real copy would occupy.
68
173
 
69
- ## Page Skeleton
174
+ ## Render Mode CSS
70
175
 
71
- ```html
72
- <title>settings-page — wireframe</title>
73
- <style>/* base CSS above */</style>
74
- <div class="frame">
75
- <div class="box"><strong>Header</strong> · [logo] · nav: Account / Billing / Team</div>
76
- <div class="row">
77
- <div class="box"><!-- sidebar --></div>
78
- <div class="box" style="flex:3"><!-- main content --></div>
79
- </div>
80
- <div class="note">Sidebar collapses below 768px — Billing moves into the header nav.</div>
81
- </div>
176
+ ```css
177
+ /* render mode — the full house language. Same skeleton, colour unlocked:
178
+ accent on primary actions, semantic status colours, categorical chips,
179
+ elevation, motion. */
180
+ * { margin: 0; box-sizing: border-box; }
181
+ body {
182
+ font-family: var(--sans);
183
+ font-size: var(--text-base);
184
+ line-height: var(--leading-normal);
185
+ background: var(--background);
186
+ color: var(--foreground);
187
+ padding: var(--space-6);
188
+ }
189
+ .frame {
190
+ background: var(--card);
191
+ border: 1px solid var(--border);
192
+ border-radius: var(--radius-lg);
193
+ box-shadow: var(--shadow-md);
194
+ max-width: 1100px; margin: 0 auto; padding: var(--space-6);
195
+ }
196
+ .topbar {
197
+ display: flex; justify-content: space-between; align-items: baseline;
198
+ padding-bottom: var(--space-4); border-bottom: 1px solid var(--border);
199
+ margin-bottom: var(--space-5);
200
+ }
201
+ .topbar strong { font-size: var(--text-lg); letter-spacing: var(--tracking-tight); }
202
+ .nav { display: flex; gap: var(--space-4); font-size: var(--text-sm); }
203
+ .nav a { color: var(--muted-foreground); transition: color var(--dur-fast) var(--ease-out); }
204
+ .nav a.active { color: var(--primary-text); border-bottom: 2px solid var(--primary); padding-bottom: 2px; }
205
+ .row { display: flex; gap: var(--space-4); }
206
+ .row > * { flex: 1; }
207
+ .box {
208
+ background: var(--card); border: 1px solid var(--border);
209
+ border-radius: var(--radius-md); padding: var(--space-4); margin-bottom: var(--space-4);
210
+ box-shadow: var(--shadow-sm);
211
+ }
212
+ h2 { font-size: var(--text-md); letter-spacing: var(--tracking-tight); margin-bottom: var(--space-3); }
213
+ .side-item {
214
+ padding: var(--space-2) var(--space-3); border-radius: var(--radius);
215
+ color: var(--muted-foreground); font-size: var(--text-sm);
216
+ transition: background var(--dur-fast) var(--ease-out);
217
+ }
218
+ .side-item.active { background: var(--primary-muted); color: var(--primary-text); }
219
+ .field { margin-bottom: var(--space-3); }
220
+ label {
221
+ display: block; font-family: var(--mono); font-size: var(--text-2xs);
222
+ text-transform: uppercase; letter-spacing: var(--tracking-wide);
223
+ color: var(--muted-foreground); margin-bottom: var(--space-1);
224
+ }
225
+ input {
226
+ width: 100%; background: var(--muted); color: var(--foreground);
227
+ border: 1px solid var(--input); border-radius: var(--radius);
228
+ padding: var(--space-2) var(--space-3); font: inherit; font-size: var(--text-sm);
229
+ transition: border-color var(--dur-fast) var(--ease-out);
230
+ }
231
+ input:focus { outline: none; border-color: var(--ring); }
232
+ .btn {
233
+ display: inline-block; border: 1px solid var(--border); border-radius: var(--radius);
234
+ padding: var(--space-2) var(--space-4); background: var(--accent);
235
+ color: var(--foreground); font-size: var(--text-sm); cursor: pointer;
236
+ transition: background var(--dur-fast) var(--ease-out);
237
+ }
238
+ .btn.primary { background: var(--primary); color: var(--primary-foreground); border-color: transparent; }
239
+ .btn.primary:hover { background: var(--primary-hover); }
240
+ .btn.danger {
241
+ background: var(--destructive-muted); color: var(--destructive);
242
+ border-color: var(--destructive-border);
243
+ }
244
+ .greek { color: var(--border); letter-spacing: 2px; overflow: hidden; white-space: nowrap; }
245
+ .img-box {
246
+ border: 1px solid var(--border); background:
247
+ linear-gradient(45deg, transparent 49.5%, var(--border) 49.5%, var(--border) 50.5%, transparent 50.5%),
248
+ linear-gradient(-45deg, transparent 49.5%, var(--border) 49.5%, var(--border) 50.5%, transparent 50.5%)
249
+ var(--muted);
250
+ display: flex; align-items: center; justify-content: center;
251
+ color: var(--muted-foreground); font-family: var(--mono); font-size: var(--text-xs);
252
+ min-height: 120px; border-radius: var(--radius);
253
+ }
254
+ table { width: 100%; border-collapse: collapse; font-size: var(--text-sm); }
255
+ th {
256
+ font-family: var(--mono); font-size: var(--text-2xs); text-transform: uppercase;
257
+ letter-spacing: var(--tracking-wide); color: var(--muted-foreground);
258
+ text-align: left; padding: var(--space-2); border-bottom: 1px solid var(--border);
259
+ }
260
+ td { padding: var(--space-2); border-bottom: 1px solid var(--border); }
261
+ .badge {
262
+ display: inline-block; font-family: var(--mono); font-size: var(--text-2xs);
263
+ padding: 2px var(--space-2); border-radius: var(--radius-full);
264
+ border: 1px solid var(--border); color: var(--muted-foreground);
265
+ }
266
+ .badge.ok { color: var(--success); background: var(--success-muted); border-color: var(--success-border); }
267
+ .badge.warn { color: var(--warning); background: var(--warning-muted); border-color: var(--warning-border); }
268
+ .badge.err { color: var(--destructive); background: var(--destructive-muted); border-color: var(--destructive-border); }
269
+ .badge.role-1 { color: var(--cat-2); border-color: var(--cat-2); background: transparent; }
270
+ .badge.role-2 { color: var(--cat-4); border-color: var(--cat-4); background: transparent; }
271
+ .badge.role-3 { color: var(--cat-other); border-color: var(--cat-other); background: transparent; }
272
+ .note {
273
+ border-left: 3px solid var(--primary); background: var(--primary-muted);
274
+ color: var(--primary-text); border-radius: 0 var(--radius) var(--radius) 0;
275
+ padding: var(--space-2) var(--space-3); margin: var(--space-3) 0;
276
+ font-family: var(--mono); font-size: var(--text-xs); line-height: var(--leading-snug);
277
+ }
278
+ .actions { display: flex; gap: var(--space-2); margin-top: var(--space-3); }
279
+ .choice { display: flex; gap: var(--space-2); }
280
+ .empty { text-align: center; padding: var(--space-8); border-style: dashed; box-shadow: none; }
281
+ .muted { color: var(--muted-foreground); }
82
282
  ```
83
283
 
284
+ The `.badge.role-*` classes are categorical-colour examples — rename them for
285
+ the domain at hand (`.badge.plan-pro`, `.badge.env-staging`, …); the pattern
286
+ to keep is one `--cat-N` per identity, `--cat-other` for the long tail.
287
+
84
288
  ## Review Posture
85
289
 
86
290
  Present a wireframe as a question, not an answer: "this is the structure I
87
291
  understood — what's wrong with it?" When two structures genuinely compete,
88
- produce both files and let discovery's mockup-picker run the choice.
292
+ produce both files and let discovery's mockup-picker run the choice. A render
293
+ is the opposite posture — it presents the settled structure in the house
294
+ language, so changes at render stage should be taste-level, not structural;
295
+ structural feedback at that point reopens the wireframe.
@@ -171,10 +171,12 @@ design that lives only in conversation doesn't count as signed off.
171
171
  ignored — see the bootstrap step there. Honour an `AGENTS.md` path override
172
172
  if the project defines one.
173
173
 
174
- For full design mockups — grayscale UI wireframes, data-model / flow /
175
- architecture diagrams — load the `blueprint` skill; the design doc links the
176
- files it produces. For *picking between* side-by-side options in the browser,
177
- see `references/mockup-picker.md` (it can point at blueprint's files).
174
+ For full design mockups — UI wireframes and renders in the house token
175
+ language, data-model / flow / architecture diagrams — load the `blueprint`
176
+ skill; the design doc links the files it produces. At sign-off, offer to
177
+ promote the chosen wireframes to render mode (a style-block swap). For
178
+ *picking between* side-by-side options in the browser, see
179
+ `references/mockup-picker.md` (it can point at blueprint's files).
178
180
 
179
181
  ## Design Review Loop
180
182