design-playbook 0.21.0 → 0.21.1

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.
Files changed (36) hide show
  1. package/README.md +11 -0
  2. package/codex/AGENTS.md +1 -0
  3. package/commands/run-review.md +1 -1
  4. package/lib/cli.js +46 -0
  5. package/mcp/evidence/README.md +2 -2
  6. package/mcp/evidence/static_handoff_page.html +1 -1
  7. package/mcp/preview/control.css +204 -35
  8. package/mcp/preview/control.html +28 -1
  9. package/mcp/preview/control.js +367 -24
  10. package/mcp/preview/control.py +92 -1
  11. package/mcp/preview/control.review.js +37 -7
  12. package/mcp/preview/i18n.py +27 -6
  13. package/mcp/preview/pin_bridge.py +129 -4
  14. package/mcp/preview/review_session.py +47 -1
  15. package/mcp/preview/test_browser_control.py +450 -0
  16. package/mcp/preview/test_i18n_labels.py +20 -2
  17. package/mcp/preview/test_transaction.py +103 -9
  18. package/mcp/preview/transaction.py +71 -4
  19. package/package.json +4 -1
  20. package/scripts/adapter_matrix.py +192 -0
  21. package/scripts/adapter_templates/codex-agents.md +86 -0
  22. package/scripts/adapter_templates/cursor-mcp-note.mdc +27 -0
  23. package/scripts/adapter_templates/windsurf-mcp-guide.md +45 -0
  24. package/scripts/generate_adapter.py +753 -0
  25. package/skills/craft-guard/SKILL.md +1 -1
  26. package/skills/craft-guard/references/craft.md +18 -18
  27. package/skills/design-playbook/SKILL.md +5 -5
  28. package/skills/reference-intake/SKILL.md +1 -1
  29. package/skills/ui-evaluator/SKILL.md +1 -1
  30. package/skills/ui-evaluator/references/rubric.md +22 -22
  31. package/skills/ui-picker/SKILL.md +1 -1
  32. package/skills/ui-picker/references/components.md +13 -13
  33. package/skills/ui-picker/references/design.md +14 -14
  34. package/skills/ui-picker/references/domain.md +14 -14
  35. package/skills/ui-picker/references/template.md +16 -16
  36. package/skills/ux-spec/references/spec-template.md +29 -29
package/README.md CHANGED
@@ -101,6 +101,17 @@ pi install npm:pi-mcp-adapter
101
101
 
102
102
  `<pkg>` is the installed package root — `~/.pi/agent/npm/node_modules/design-playbook` for a user install, `.pi/npm/node_modules/design-playbook` for a project install. Evidence also needs `pip install playwright && playwright install chromium`.
103
103
 
104
+ ## Install on other agents
105
+
106
+ Generate adapter files for Cursor, Gemini CLI, OpenCode, Windsurf, GitHub Copilot, or any of 22 Tier-3 agents:
107
+
108
+ ```bash
109
+ npx design-playbook init <agent> # e.g. cursor, gemini-cli, windsurf
110
+ npx design-playbook --list # all 29 agents, shows which have renderers
111
+ ```
112
+
113
+ See the root [README](../../README.md#install-on-other-agents) for the tier table and capability notes.
114
+
104
115
  ## Stack with other skills
105
116
 
106
117
  | Package | Use for |
package/codex/AGENTS.md CHANGED
@@ -1,3 +1,4 @@
1
+ <!-- generated-by design-playbook v0.21.1 -->
1
2
  # design-playbook for Codex
2
3
 
3
4
  ## Install (path of record)
@@ -20,7 +20,7 @@ Scan user-side `.scratch/<run>/` (not monorepo `dogfood/*` globs). **Include** o
20
20
  Ledger row shape: **ui-evaluator** step 2 (do not restate).
21
21
 
22
22
  ```
23
- 禁止:
23
+ Prohibited:
24
24
  - no new run ledger
25
25
  - no prose lessons / narrative "learning"
26
26
  - no auto-writeback to baseline
package/lib/cli.js ADDED
@@ -0,0 +1,46 @@
1
+ #!/usr/bin/env node
2
+ 'use strict'
3
+ /**
4
+ * design-playbook CLI shim (ADR-0042).
5
+ *
6
+ * Locates python3/python and delegates to
7
+ * packages/design-playbook/scripts/generate_adapter.py with passthrough args.
8
+ *
9
+ * npx design-playbook --list
10
+ * npx design-playbook init <agent>
11
+ * npx design-playbook <agent> --dry-run
12
+ */
13
+ const { execFileSync } = require('node:child_process')
14
+ const path = require('node:path')
15
+
16
+ const SCRIPT = path.join(__dirname, '..', 'scripts', 'generate_adapter.py')
17
+
18
+ function findPython() {
19
+ for (const bin of ['python3', 'python']) {
20
+ try {
21
+ const out = execFileSync(bin, ['--version'], { encoding: 'utf8', stdio: ['ignore', 'pipe', 'pipe'] })
22
+ if (/python\s+3\./i.test(out)) return bin
23
+ } catch {}
24
+ }
25
+ return null
26
+ }
27
+
28
+ const python = findPython()
29
+ if (!python) {
30
+ process.stderr.write(
31
+ 'error: design-playbook requires Python 3 (python3 or python).\n' +
32
+ 'Install Python 3 from https://python.org and re-run.\n'
33
+ )
34
+ process.exit(1)
35
+ }
36
+
37
+ // Strip leading "init" if invoked as `design-playbook init <agent>` so both
38
+ // forms are equivalent: `design-playbook init codex` == `design-playbook codex`
39
+ const rawArgs = process.argv.slice(2)
40
+ const args = rawArgs[0] === 'init' ? rawArgs.slice(1) : rawArgs
41
+
42
+ try {
43
+ execFileSync(python, [SCRIPT, ...args], { stdio: 'inherit' })
44
+ } catch (err) {
45
+ process.exit(err.status ?? 1)
46
+ }
@@ -8,7 +8,7 @@ Runtime for the optional **observe\*** step. Writes capture artifacts only — *
8
8
  | --- | --- |
9
9
  | Unset | Artifact paths resolve under the **MCP process cwd** |
10
10
  | `"."` (default in package `.mcp.json`) | Same — relative to process cwd, **not** the chat workspace root |
11
- | Absolute path | Preferred for cross-repo dogfood: set to the run root (e.g. `D:/…/nmg_bup_h5/.scratch/playbook-smoke/<run>`) so `evidence/L6.*.png` lands next to `manifest.jsonl` |
11
+ | Absolute path | Preferred for cross-repo dogfood: set to the run root (e.g. `/path/to/host-app/.scratch/playbook-smoke/<run>`) so `evidence/L6.*.png` lands next to `manifest.jsonl` |
12
12
 
13
13
  Relative values are resolved with `Path(value).resolve()` at process start semantics (cwd-relative). If captures appear under the plugin monorepo instead of the host run, check cwd and this env — the tool also returns **`written_path`** (absolute) so mis-roots are obvious without a filesystem search.
14
14
 
@@ -16,7 +16,7 @@ Example (host run):
16
16
 
17
17
  ```json
18
18
  "env": {
19
- "DESIGN_PLAYBOOK_RUN_ROOT": "D:/code_space/app/.scratch/my-run"
19
+ "DESIGN_PLAYBOOK_RUN_ROOT": "/path/to/app/.scratch/my-run"
20
20
  }
21
21
  ```
22
22
 
@@ -12,7 +12,7 @@
12
12
  *{box-sizing:border-box}
13
13
  body{margin:0;background:var(--bg);color:var(--ink);
14
14
  font:14px/1.6 -apple-system,BlinkMacSystemFont,"Segoe UI","PingFang SC",
15
- "Hiragino Sans GB","Microsoft YaHei",sans-serif;}
15
+ "Hiragino Sans GB","Microsoft YaHei","Noto Sans SC",sans-serif;}
16
16
  .wrap{max-width:960px;margin:0 auto;padding:32px 20px 64px;}
17
17
  header{border-bottom:2px solid var(--primary);padding-bottom:16px;margin-bottom:24px;}
18
18
  h1{margin:0;font-size:22px;letter-spacing:-.01em;}
@@ -40,9 +40,14 @@
40
40
  --dpb-shadow-pin: 0 3px 8px rgba(37,99,235,.35), 0 1px 2px rgba(0,0,0,.1);
41
41
  --dpb-ring-accent: rgba(37,99,235,.25);
42
42
  --dpb-ring-danger: rgba(225,29,72,.25);
43
+ --dpb-ease-spring: cubic-bezier(.16,1,.3,1);
44
+ --dpb-ease-pulse: cubic-bezier(0,0,.2,1);
45
+ --dpb-duration-spring: 200ms;
46
+ --dpb-duration-quick: 120ms;
43
47
  --dpb-radius: 8px;
44
48
  --dpb-topbar-h: 48px;
45
49
  --dpb-rail-w: 352px;
50
+ --dpb-spec-rail-w: 320px;
46
51
  }
47
52
  #dpb-root[data-theme="dark"],
48
53
  #dpb-float-root[data-theme="dark"],
@@ -109,7 +114,7 @@ body.dpb-shell { overflow: hidden; height: 100vh; }
109
114
  background: var(--dpb-surface); color: var(--dpb-soft);
110
115
  border: 1px solid var(--dpb-line-strong); border-bottom-width: 2px;
111
116
  }
112
- .i18n { transition: opacity .15s ease; }
117
+ .i18n { transition: opacity var(--dpb-duration-spring) var(--dpb-ease-spring); }
113
118
 
114
119
  /* ---- header ---- */
115
120
  .dpb-header {
@@ -138,8 +143,7 @@ body.dpb-shell { overflow: hidden; height: 100vh; }
138
143
  background: var(--dpb-surface); border: 1px solid var(--dpb-line); white-space: nowrap;
139
144
  }
140
145
  .dpb-header-center {
141
- position: absolute; left: 50%; transform: translateX(-50%);
142
- display: flex; align-items: center; gap: 12px;
146
+ display: flex; align-items: center; gap: 12px; flex: 0 1 auto; min-width: 0;
143
147
  }
144
148
  .dpb-header-div { width: 1px; height: 16px; background: var(--dpb-line); flex: 0 0 auto; }
145
149
  .dpb-seg {
@@ -150,7 +154,7 @@ body.dpb-shell { overflow: hidden; height: 100vh; }
150
154
  appearance: none; cursor: pointer; border: 0; background: transparent;
151
155
  display: inline-flex; align-items: center; gap: 6px;
152
156
  height: 26px; padding: 0 9px; border-radius: 6px;
153
- color: var(--dpb-soft); font: 500 12px/1 inherit; transition: all .15s ease;
157
+ color: var(--dpb-soft); font: 500 12px/1 inherit; transition: all var(--dpb-duration-spring) var(--dpb-ease-spring);
154
158
  }
155
159
  .dpb-seg button:hover { color: var(--dpb-ink); }
156
160
  .dpb-seg button[aria-pressed="true"] {
@@ -158,13 +162,13 @@ body.dpb-shell { overflow: hidden; height: 100vh; }
158
162
  font-weight: 600; box-shadow: var(--dpb-shadow-tool);
159
163
  }
160
164
  .dpb-seg button:focus-visible { outline: 2px solid var(--dpb-accent); outline-offset: 1px; }
161
- .dpb-header-right { display: flex; align-items: center; gap: 4px; }
165
+ .dpb-header-right { display: flex; align-items: center; gap: 4px; position: relative; z-index: 2; }
162
166
  .dpb-header-right > button {
163
167
  appearance: none; cursor: pointer; border: 0;
164
168
  display: inline-flex; align-items: center; gap: 6px;
165
169
  height: 32px; padding: 0 10px; border-radius: 8px;
166
170
  background: transparent; color: var(--dpb-soft); font: 500 12px/1 inherit;
167
- transition: all .15s ease;
171
+ transition: all var(--dpb-duration-spring) var(--dpb-ease-spring);
168
172
  }
169
173
  .dpb-header-right > button:hover { background: var(--dpb-surface); color: var(--dpb-ink); }
170
174
  .dpb-header-right > button:focus-visible { outline: 2px solid var(--dpb-accent); outline-offset: 1px; }
@@ -174,14 +178,31 @@ body.dpb-shell { overflow: hidden; height: 100vh; }
174
178
  background: var(--dpb-accent); color: var(--dpb-accent-ink);
175
179
  font-weight: 600; padding: 0 14px;
176
180
  }
177
- .dpb-approve-btn:hover { background: var(--dpb-accent-deep); box-shadow: var(--dpb-shadow-glow); color: var(--dpb-accent-ink); }
178
- .dpb-approve-btn:active { transform: scale(.96); }
181
+ .dpb-approve-btn:hover { background: var(--dpb-accent-deep); box-shadow: var(--dpb-shadow-glow); color: var(--dpb-accent-ink); transform: translateY(-1px); }
182
+ .dpb-approve-btn:active { transform: translateY(.5px) scale(.97); }
183
+ .dpb-header-right > button:active,
184
+ .dpb-header-right .dpb-btn-secondary:active,
185
+ .dpb-seg button:active,
186
+ .dpb-toolbar button:active,
187
+ .dpb-filter-tabs button:active,
188
+ .dpb-anchor:active,
189
+ .dpb-anchor-rm:active,
190
+ .dpb-anchor-resolve:active,
191
+ .dpb-spec-check-row:active,
192
+ .dpb-status-approve:active,
193
+ .dpb-btn:active,
194
+ .dpb-tag:active,
195
+ .dpb-comment-box button:active,
196
+ .dpb-modal-head button:active,
197
+ .dpb-reopen-tab:active {
198
+ transform: translateY(.5px) scale(.97);
199
+ }
179
200
  .dpb-approve-btn kbd { background: var(--dpb-highlight); color: var(--dpb-accent-ink); border-color: transparent; border-bottom-width: 1px; }
180
201
  .dpb-header-right .dpb-btn-secondary {
181
202
  appearance: none; cursor: pointer; display: inline-flex; align-items: center; gap: 6px;
182
203
  height: 32px; padding: 0 10px; border-radius: 8px;
183
204
  background: transparent; border: 1px solid var(--dpb-line-strong); color: var(--dpb-soft);
184
- font: 500 12px/1 inherit; transition: all .15s ease;
205
+ font: 500 12px/1 inherit; transition: all var(--dpb-duration-spring) var(--dpb-ease-spring);
185
206
  }
186
207
  .dpb-header-right .dpb-btn-secondary:hover { background: var(--dpb-surface); color: var(--dpb-ink); }
187
208
 
@@ -199,6 +220,74 @@ body.dpb-shell { overflow: hidden; height: 100vh; }
199
220
 
200
221
  /* ---- workspace ---- */
201
222
  .dpb-workspace { flex: 1 1 auto; display: flex; min-width: 0; position: relative; overflow: hidden; }
223
+ .dpb-spec-panel {
224
+ width: var(--dpb-spec-rail-w); flex: 0 0 auto; min-width: 0;
225
+ display: flex; flex-direction: column; overflow: hidden;
226
+ background: color-mix(in srgb, var(--dpb-elev) 96%, transparent);
227
+ border-right: 1px solid var(--dpb-line); z-index: 35;
228
+ box-shadow: 6px 0 28px -8px rgba(15,23,42,.08);
229
+ transition: margin-left .3s var(--dpb-ease-spring), opacity var(--dpb-duration-spring) var(--dpb-ease-spring);
230
+ }
231
+ #dpb-root[data-theme="dark"] .dpb-spec-panel { box-shadow: 6px 0 28px rgba(0,0,0,.28); }
232
+ .dpb-spec-panel.dpb-collapsed { margin-left: calc(-1 * var(--dpb-spec-rail-w)); opacity: 0; pointer-events: none; }
233
+ .dpb-spec-head {
234
+ height: 48px; flex: 0 0 auto; padding: 0 14px;
235
+ display: flex; align-items: center; justify-content: space-between;
236
+ border-bottom: 1px solid var(--dpb-line);
237
+ }
238
+ .dpb-spec-title-row { display: flex; align-items: center; gap: 8px; min-width: 0; }
239
+ .dpb-spec-title-row svg { color: var(--dpb-accent); flex: 0 0 auto; }
240
+ .dpb-spec-title-row h2 { margin: 0; font-size: 13.5px; font-weight: 700; letter-spacing: -.01em; }
241
+ .dpb-spec-list {
242
+ flex: 1 1 auto; min-height: 0; overflow-y: auto;
243
+ display: flex; flex-direction: column; gap: 10px; padding: 12px;
244
+ }
245
+ .dpb-spec-card {
246
+ padding: 12px; border-radius: 10px;
247
+ background: var(--dpb-bg); border: 1px solid var(--dpb-line);
248
+ transition: border-color var(--dpb-duration-spring) var(--dpb-ease-spring), background var(--dpb-duration-spring) var(--dpb-ease-spring), box-shadow var(--dpb-duration-spring) var(--dpb-ease-spring), transform var(--dpb-duration-spring) var(--dpb-ease-spring);
249
+ }
250
+ .dpb-spec-card:hover { border-color: var(--dpb-line-strong); background: var(--dpb-surface); transform: translateY(-1px); }
251
+ .dpb-spec-card.dpb-checked {
252
+ border-color: var(--dpb-accent-chip-border);
253
+ background: color-mix(in srgb, var(--dpb-accent-wash) 72%, var(--dpb-bg));
254
+ }
255
+ .dpb-spec-check-row {
256
+ display: grid; grid-template-columns: auto 1fr; gap: 8px; align-items: start;
257
+ color: var(--dpb-ink); font: 650 12px/1.45 inherit; cursor: pointer;
258
+ transition: transform var(--dpb-duration-quick) var(--dpb-ease-spring);
259
+ }
260
+ .dpb-spec-check-row input {
261
+ appearance: none; width: 14px; height: 14px; margin: 2px 0 0;
262
+ border-radius: 4px; border: 1px solid var(--dpb-line-strong);
263
+ background: var(--dpb-elev); display: grid; place-items: center;
264
+ }
265
+ .dpb-spec-check-row input::after {
266
+ content: ""; width: 7px; height: 4px; border-left: 2px solid var(--dpb-accent-ink);
267
+ border-bottom: 2px solid var(--dpb-accent-ink); transform: rotate(-45deg) scale(0);
268
+ transition: transform var(--dpb-duration-quick) var(--dpb-ease-spring);
269
+ }
270
+ .dpb-spec-check-row input:checked { background: var(--dpb-accent); border-color: var(--dpb-accent); }
271
+ .dpb-spec-check-row input:checked::after { transform: rotate(-45deg) scale(1); }
272
+ .dpb-spec-check-row input:focus-visible { outline: 2px solid var(--dpb-accent); outline-offset: 2px; }
273
+ .dpb-spec-card p { margin: 6px 0 0 22px; color: var(--dpb-soft); font-size: 11.5px; line-height: 1.5; }
274
+ .dpb-spec-empty {
275
+ margin: 0; padding: 14px; border-radius: 10px;
276
+ background: var(--dpb-bg); border: 1px dashed var(--dpb-line-strong);
277
+ color: var(--dpb-soft); font-size: 12px; text-align: center;
278
+ }
279
+ #dpb-criteria-toggle[hidden] { display: none !important; }
280
+ #dpb-criteria-toggle[aria-expanded="true"] {
281
+ background: var(--dpb-accent-wash);
282
+ color: var(--dpb-accent);
283
+ box-shadow: var(--dpb-shadow-tool);
284
+ }
285
+ #dpb-criteria-count { font: 600 11px/1 ui-monospace, Consolas, monospace; }
286
+ #dpb-theme-icon {
287
+ width: 16px; height: 16px;
288
+ display: inline-flex; align-items: center; justify-content: center;
289
+ }
290
+ #dpb-theme-icon svg { width: 16px; height: 16px; display: block; }
202
291
  .dpb-canvas {
203
292
  flex: 1 1 auto; position: relative; overflow: auto;
204
293
  display: flex; align-items: center; justify-content: center; padding: 48px;
@@ -206,7 +295,7 @@ body.dpb-shell { overflow: hidden; height: 100vh; }
206
295
  background-image: radial-gradient(var(--dpb-line-strong) 1.2px, transparent 1.2px);
207
296
  background-size: 24px 24px;
208
297
  }
209
- .dpb-artboard-wrap { position: relative; flex: 0 0 auto; transition: transform .25s cubic-bezier(.16,1,.3,1); }
298
+ .dpb-artboard-wrap { position: relative; flex: 0 0 auto; transition: transform var(--dpb-duration-spring) var(--dpb-ease-spring); }
210
299
  .dpb-artboard-wrap.dpb-no-anim { transition: none; }
211
300
  .dpb-artboard {
212
301
  position: relative; width: 1024px; height: 720px;
@@ -221,7 +310,9 @@ body.dpb-shell { overflow: hidden; height: 100vh; }
221
310
  .dpb-draw-layer {
222
311
  position: absolute; inset: 0; z-index: 30; pointer-events: none; overflow: visible;
223
312
  }
224
- body.dpb-tool-draw .dpb-draw-layer { pointer-events: auto; cursor: crosshair; }
313
+ body.dpb-tool-draw .dpb-draw-layer,
314
+ body.dpb-tool-box .dpb-draw-layer,
315
+ body.dpb-tool-ruler .dpb-draw-layer { pointer-events: auto; cursor: crosshair; }
225
316
  .dpb-draw-layer .dpb-draw-path {
226
317
  fill: none; stroke: var(--dpb-draw-stroke); stroke-width: 2.4;
227
318
  stroke-dasharray: 8 4; stroke-linecap: round; stroke-linejoin: round; opacity: .92;
@@ -231,34 +322,63 @@ body.dpb-tool-draw .dpb-draw-layer { pointer-events: auto; cursor: crosshair; }
231
322
  .dpb-draw-layer .dpb-draw-badge text {
232
323
  fill: var(--dpb-draw-ink); font: 700 11px/1 system-ui, sans-serif;
233
324
  }
325
+ .dpb-draw-layer .dpb-box-rect {
326
+ fill: var(--dpb-accent-wash); stroke: var(--dpb-accent); stroke-width: 2;
327
+ stroke-dasharray: 6 4; opacity: .9;
328
+ }
329
+ .dpb-draw-layer .dpb-box-live { opacity: .65; }
330
+ .dpb-draw-layer .dpb-box-badge rect,
331
+ .dpb-draw-layer .dpb-ruler-badge rect {
332
+ fill: var(--dpb-accent); stroke: var(--dpb-highlight); stroke-width: 1;
333
+ }
334
+ .dpb-draw-layer .dpb-box-badge text,
335
+ .dpb-draw-layer .dpb-ruler-badge text {
336
+ fill: var(--dpb-accent-ink); font: 700 11px/1 ui-monospace, Consolas, monospace;
337
+ }
338
+ .dpb-draw-layer .dpb-ruler-hover {
339
+ fill: var(--dpb-accent-wash); stroke: var(--dpb-accent); stroke-width: 1.5;
340
+ stroke-dasharray: 4 3; pointer-events: none;
341
+ }
342
+ .dpb-draw-layer .dpb-ruler-line {
343
+ stroke: var(--dpb-accent); stroke-width: 2; stroke-linecap: round; pointer-events: none;
344
+ }
345
+ .dpb-draw-layer .dpb-ruler-point { fill: var(--dpb-accent); stroke: var(--dpb-elev); stroke-width: 2; pointer-events: none; }
234
346
  .dpb-pins-layer { position: absolute; inset: 0; z-index: 20; pointer-events: none; }
235
347
  .dpb-free-pin {
236
348
  position: absolute; width: 28px; height: 28px; margin: -14px 0 0 -14px;
237
349
  border-radius: 999px; background: var(--dpb-accent); color: var(--dpb-accent-ink);
238
350
  display: flex; align-items: center; justify-content: center;
239
351
  font: 700 12px/1 system-ui, sans-serif; box-shadow: var(--dpb-shadow-pin);
240
- pointer-events: auto; cursor: pointer; transition: transform .15s ease;
241
- animation: dpb-toast-in .25s cubic-bezier(.16,1,.3,1);
352
+ pointer-events: auto; cursor: pointer;
353
+ transition: transform var(--dpb-duration-spring) var(--dpb-ease-spring), box-shadow var(--dpb-duration-spring) var(--dpb-ease-spring);
242
354
  }
243
- .dpb-free-pin:hover { transform: scale(1.12); }
355
+ .dpb-free-pin:hover { transform: translateY(-1px) scale(1.08); }
356
+ .dpb-free-pin:active { transform: translateY(.5px) scale(.97); }
244
357
  .dpb-free-pin.dpb-resolved { background: var(--dpb-success); opacity: .65; }
358
+ .dpb-free-pin.dpb-pin-drop { animation: dpb-pin-drop 380ms var(--dpb-ease-spring) both; }
359
+ .dpb-free-pin.dpb-active::after {
360
+ content: ""; position: absolute; inset: -4px; border-radius: inherit;
361
+ border: 2px solid var(--dpb-ring-accent); animation: dpb-pulse-ring 1.8s var(--dpb-ease-pulse) infinite;
362
+ }
245
363
 
246
364
  /* ---- left toolbar ---- */
247
365
  .dpb-toolbar {
248
- position: fixed; left: 16px; top: 64px; z-index: 40;
366
+ position: fixed; left: calc(var(--dpb-spec-rail-w) + 16px); top: 64px; z-index: 40;
249
367
  width: 48px; padding: 10px 0; border-radius: 12px;
250
368
  display: flex; flex-direction: column; align-items: center; gap: 6px;
251
369
  background: color-mix(in srgb, var(--dpb-elev) 95%, transparent);
252
370
  backdrop-filter: blur(8px);
253
371
  border: 1px solid var(--dpb-line); box-shadow: var(--dpb-shadow-tool);
372
+ transition: left .3s var(--dpb-ease-spring);
254
373
  }
374
+ #dpb-root.dpb-spec-collapsed .dpb-toolbar { left: 16px; }
255
375
  .dpb-toolbar button {
256
376
  appearance: none; cursor: pointer; border: 0; background: transparent;
257
377
  width: 32px; height: 32px; border-radius: 8px;
258
378
  display: flex; align-items: center; justify-content: center;
259
- color: var(--dpb-soft); transition: all .15s ease;
379
+ color: var(--dpb-soft); transition: all var(--dpb-duration-spring) var(--dpb-ease-spring);
260
380
  }
261
- .dpb-toolbar button:hover { background: var(--dpb-surface); color: var(--dpb-ink); }
381
+ .dpb-toolbar button:hover { background: var(--dpb-surface); color: var(--dpb-ink); transform: translateY(-1px); }
262
382
  .dpb-toolbar button[aria-pressed="true"] { background: var(--dpb-accent-wash); color: var(--dpb-accent); }
263
383
  .dpb-toolbar button:focus-visible { outline: 2px solid var(--dpb-accent); outline-offset: 1px; }
264
384
  .dpb-toolbar-div { width: 20px; height: 1px; background: var(--dpb-line); margin: 2px 0; }
@@ -275,8 +395,9 @@ body.dpb-tool-draw .dpb-draw-layer { pointer-events: auto; cursor: crosshair; }
275
395
  background: color-mix(in srgb, var(--dpb-ink) 92%, transparent);
276
396
  color: var(--dpb-elev); backdrop-filter: blur(8px);
277
397
  border: 1px solid var(--dpb-highlight); box-shadow: var(--dpb-shadow-pill);
278
- transition: opacity .2s ease;
398
+ transition: opacity var(--dpb-duration-spring) var(--dpb-ease-spring), transform var(--dpb-duration-spring) var(--dpb-ease-spring), box-shadow var(--dpb-duration-spring) var(--dpb-ease-spring);
279
399
  }
400
+ .dpb-status-pill:hover { transform: translate(-50%, -1px); box-shadow: var(--dpb-shadow-pop); }
280
401
  .dpb-status-dot {
281
402
  position: relative; width: 8px; height: 8px; border-radius: 999px; flex: 0 0 auto;
282
403
  background: var(--dpb-muted);
@@ -284,7 +405,7 @@ body.dpb-tool-draw .dpb-draw-layer { pointer-events: auto; cursor: crosshair; }
284
405
  .dpb-status-pill.dpb-is-ready .dpb-status-dot { background: var(--dpb-success); }
285
406
  .dpb-status-dot::after {
286
407
  content: ""; position: absolute; inset: 0; border-radius: 999px;
287
- background: inherit; animation: dpb-ping 1.8s cubic-bezier(0,0,.2,1) infinite;
408
+ background: inherit; animation: dpb-ping 1.8s var(--dpb-ease-pulse) infinite;
288
409
  }
289
410
  .dpb-status-pill:not(.dpb-is-ready) .dpb-status-dot::after { animation: none; }
290
411
  .dpb-status-text { font-size: 12px; font-weight: 500; letter-spacing: .01em; white-space: nowrap; }
@@ -293,6 +414,7 @@ body.dpb-tool-draw .dpb-draw-layer { pointer-events: auto; cursor: crosshair; }
293
414
  appearance: none; cursor: pointer; border: 0; background: transparent;
294
415
  display: inline-flex; align-items: center; gap: 5px;
295
416
  color: var(--dpb-accent-soft); font: 600 12px/1 inherit;
417
+ transition: color var(--dpb-duration-spring) var(--dpb-ease-spring), transform var(--dpb-duration-quick) var(--dpb-ease-spring);
296
418
  }
297
419
  .dpb-status-approve:hover { color: var(--dpb-elev); }
298
420
  .dpb-status-approve kbd { background: var(--dpb-highlight); color: var(--dpb-elev); border-color: transparent; border-bottom-width: 1px; }
@@ -304,7 +426,7 @@ body.dpb-tool-draw .dpb-draw-layer { pointer-events: auto; cursor: crosshair; }
304
426
  width: var(--dpb-rail-w); flex: 0 0 auto; display: flex; flex-direction: column;
305
427
  background: var(--dpb-elev); border-left: 1px solid var(--dpb-line);
306
428
  box-shadow: var(--dpb-shadow-drawer); z-index: 40;
307
- transition: margin-right .3s cubic-bezier(.16,1,.3,1), opacity .2s ease;
429
+ transition: margin-right .3s var(--dpb-ease-spring), opacity var(--dpb-duration-spring) var(--dpb-ease-spring);
308
430
  }
309
431
  .dpb-inspector.dpb-collapsed { margin-right: calc(-1 * var(--dpb-rail-w)); opacity: 0; pointer-events: none; }
310
432
  .dpb-inspector-head {
@@ -326,7 +448,7 @@ body.dpb-tool-draw .dpb-draw-layer { pointer-events: auto; cursor: crosshair; }
326
448
  appearance: none; cursor: pointer; border: 0; background: transparent;
327
449
  width: 26px; height: 26px; border-radius: 6px;
328
450
  display: flex; align-items: center; justify-content: center;
329
- color: var(--dpb-soft); transition: all .15s ease;
451
+ color: var(--dpb-soft); transition: all var(--dpb-duration-spring) var(--dpb-ease-spring);
330
452
  }
331
453
  .dpb-inspector-nav button:hover { background: var(--dpb-surface); color: var(--dpb-ink); }
332
454
  .dpb-inspector-nav .dpb-header-div { height: 14px; }
@@ -340,7 +462,7 @@ body.dpb-tool-draw .dpb-draw-layer { pointer-events: auto; cursor: crosshair; }
340
462
  display: inline-flex; align-items: center; gap: 5px;
341
463
  height: 24px; padding: 0 10px; border-radius: 6px;
342
464
  background: transparent; color: var(--dpb-soft); font: 500 11.5px/1 inherit;
343
- transition: all .15s ease;
465
+ transition: all var(--dpb-duration-spring) var(--dpb-ease-spring);
344
466
  }
345
467
  .dpb-filter-tabs button:hover { color: var(--dpb-ink); }
346
468
  .dpb-filter-tabs button[aria-pressed="true"] {
@@ -351,12 +473,21 @@ body.dpb-tool-draw .dpb-draw-layer { pointer-events: auto; cursor: crosshair; }
351
473
 
352
474
  .dpb-anchor-list { flex: 1 1 auto; min-height: 0; overflow-y: auto; padding: 12px; display: flex; flex-direction: column; gap: 10px; }
353
475
  .dpb-anchor-list:not(.has-items) + .dpb-comment-form { border-top: 1px solid var(--dpb-line); }
476
+ .dpb-anchor-empty {
477
+ margin: auto 0; padding: 22px 18px; border-radius: 14px;
478
+ border: 1px dashed var(--dpb-line-strong); background: var(--dpb-bg);
479
+ display: grid; justify-items: center; gap: 7px; text-align: center;
480
+ }
481
+ .dpb-anchor-empty svg { color: var(--dpb-accent); opacity: .88; }
482
+ .dpb-anchor-empty-title { font: 700 13px/1.3 inherit; color: var(--dpb-ink); }
483
+ .dpb-anchor-empty-desc { margin: 0; max-width: 260px; color: var(--dpb-soft); font-size: 11.5px; line-height: 1.45; }
354
484
  .dpb-anchor {
355
485
  position: relative; padding: 12px; border-radius: 10px; cursor: pointer;
356
486
  background: var(--dpb-bg); border: 1px solid transparent;
357
- transition: all .18s ease;
487
+ transition: background var(--dpb-duration-spring) var(--dpb-ease-spring), border-color var(--dpb-duration-spring) var(--dpb-ease-spring), box-shadow var(--dpb-duration-spring) var(--dpb-ease-spring), transform var(--dpb-duration-spring) var(--dpb-ease-spring);
358
488
  }
359
489
  .dpb-anchor:hover { background: var(--dpb-surface); border-color: var(--dpb-line); }
490
+ .dpb-anchor.dpb-anchor-enter { animation: dpb-anchor-enter var(--dpb-duration-spring) var(--dpb-ease-spring) both; }
360
491
  .dpb-anchor.dpb-active { background: var(--dpb-accent-wash); border-color: var(--dpb-accent-chip-border); box-shadow: var(--dpb-shadow-tool); }
361
492
  .dpb-anchor.dpb-active::before {
362
493
  content: ""; position: absolute; left: 0; top: 0; bottom: 0; width: 3px;
@@ -387,7 +518,7 @@ body.dpb-tool-draw .dpb-draw-layer { pointer-events: auto; cursor: crosshair; }
387
518
  flex: 1 1 auto; min-width: 0; height: 28px; padding: 4px 8px;
388
519
  border: 1px solid transparent; border-radius: 6px; background: transparent;
389
520
  color: var(--dpb-ink); font: 400 12px/1.4 inherit; outline: none;
390
- transition: border-color .15s ease, background .15s ease;
521
+ transition: border-color var(--dpb-duration-spring) var(--dpb-ease-spring), background var(--dpb-duration-spring) var(--dpb-ease-spring);
391
522
  }
392
523
  .dpb-anchor-row input:focus { border-color: var(--dpb-accent); background: var(--dpb-elev); }
393
524
  .dpb-anchor-row input::placeholder { color: var(--dpb-muted); }
@@ -395,6 +526,7 @@ body.dpb-tool-draw .dpb-draw-layer { pointer-events: auto; cursor: crosshair; }
395
526
  appearance: none; cursor: pointer; border: 0; background: transparent;
396
527
  color: var(--dpb-muted); font: 500 10px/1 inherit; padding: 4px 6px; border-radius: 6px;
397
528
  flex: 0 0 auto;
529
+ transition: color var(--dpb-duration-spring) var(--dpb-ease-spring), background var(--dpb-duration-spring) var(--dpb-ease-spring), transform var(--dpb-duration-quick) var(--dpb-ease-spring);
398
530
  }
399
531
  .dpb-anchor-rm:hover { color: var(--dpb-danger); background: var(--dpb-danger-wash); }
400
532
  .dpb-anchor-foot { display: flex; align-items: center; justify-content: space-between; margin: 6px 0 0 28px; }
@@ -402,6 +534,7 @@ body.dpb-tool-draw .dpb-draw-layer { pointer-events: auto; cursor: crosshair; }
402
534
  appearance: none; cursor: pointer; border: 0; background: transparent;
403
535
  display: inline-flex; align-items: center; gap: 4px;
404
536
  color: var(--dpb-soft); font: 500 10.5px/1 inherit; padding: 3px 6px; border-radius: 6px;
537
+ transition: color var(--dpb-duration-spring) var(--dpb-ease-spring), background var(--dpb-duration-spring) var(--dpb-ease-spring), transform var(--dpb-duration-quick) var(--dpb-ease-spring);
405
538
  }
406
539
  .dpb-anchor-resolve:hover { color: var(--dpb-success); background: var(--dpb-success-wash); }
407
540
  .dpb-anchor-id { font: 500 9px/1 ui-monospace, Consolas, monospace; color: var(--dpb-muted); }
@@ -416,7 +549,7 @@ body.dpb-tool-draw .dpb-draw-layer { pointer-events: auto; cursor: crosshair; }
416
549
  .dpb-tag {
417
550
  appearance: none; cursor: pointer; height: 22px; padding: 0 9px; border-radius: 6px;
418
551
  border: 1px solid var(--dpb-line); background: var(--dpb-bg); color: var(--dpb-soft);
419
- font: 500 10.5px/1 inherit; transition: all .15s ease;
552
+ font: 500 10.5px/1 inherit; transition: all var(--dpb-duration-spring) var(--dpb-ease-spring);
420
553
  }
421
554
  .dpb-tag:hover { color: var(--dpb-ink); border-color: var(--dpb-line-strong); }
422
555
  .dpb-tag.is-on { background: var(--dpb-accent-wash); color: var(--dpb-accent); border-color: var(--dpb-accent-chip-border); }
@@ -426,7 +559,7 @@ body.dpb-tool-draw .dpb-draw-layer { pointer-events: auto; cursor: crosshair; }
426
559
  width: 100%; display: block; resize: none; padding: 8px 34px 8px 10px;
427
560
  background: var(--dpb-bg); border: 1px solid var(--dpb-line); border-radius: 8px;
428
561
  color: var(--dpb-ink); font: 400 12px/1.5 inherit; outline: none;
429
- transition: border-color .15s ease, box-shadow .15s ease;
562
+ transition: border-color var(--dpb-duration-spring) var(--dpb-ease-spring), box-shadow var(--dpb-duration-spring) var(--dpb-ease-spring);
430
563
  }
431
564
  .dpb-comment-box textarea:focus { border-color: var(--dpb-accent); box-shadow: 0 0 0 2px var(--dpb-ring-accent); }
432
565
  .dpb-comment-box textarea::placeholder { color: var(--dpb-muted); }
@@ -434,7 +567,7 @@ body.dpb-tool-draw .dpb-draw-layer { pointer-events: auto; cursor: crosshair; }
434
567
  position: absolute; right: 6px; bottom: 6px; width: 26px; height: 26px;
435
568
  appearance: none; cursor: pointer; border: 0; border-radius: 6px;
436
569
  background: transparent; color: var(--dpb-muted);
437
- display: flex; align-items: center; justify-content: center; transition: all .15s ease;
570
+ display: flex; align-items: center; justify-content: center; transition: all var(--dpb-duration-spring) var(--dpb-ease-spring);
438
571
  }
439
572
  .dpb-comment-box button:hover { color: var(--dpb-accent); background: var(--dpb-surface); }
440
573
  .dpb-field { display: flex; flex-direction: column; gap: 4px; }
@@ -446,7 +579,7 @@ body.dpb-tool-draw .dpb-draw-layer { pointer-events: auto; cursor: crosshair; }
446
579
  width: 100%; display: block; resize: vertical; min-height: 64px; max-height: 140px;
447
580
  padding: 8px 10px; background: var(--dpb-bg); border: 1px solid var(--dpb-line);
448
581
  border-radius: 8px; color: var(--dpb-ink); font: 400 12px/1.5 inherit; outline: none;
449
- transition: border-color .15s ease, box-shadow .15s ease;
582
+ transition: border-color var(--dpb-duration-spring) var(--dpb-ease-spring), box-shadow var(--dpb-duration-spring) var(--dpb-ease-spring);
450
583
  }
451
584
  .dpb-field textarea[name="feedback"]:focus { border-color: var(--dpb-accent); box-shadow: 0 0 0 2px var(--dpb-ring-accent); }
452
585
  .dpb-field textarea[name="feedback"]::placeholder { color: var(--dpb-muted); }
@@ -460,7 +593,7 @@ body.dpb-tool-draw .dpb-draw-layer { pointer-events: auto; cursor: crosshair; }
460
593
  appearance: none; cursor: pointer; height: 32px; padding: 0 14px; border-radius: 8px;
461
594
  display: inline-flex; align-items: center; justify-content: center; gap: 6px;
462
595
  border: 1px solid var(--dpb-line-strong); background: transparent; color: var(--dpb-soft);
463
- font: 600 12px/1 inherit; transition: all .15s ease;
596
+ font: 600 12px/1 inherit; transition: all var(--dpb-duration-spring) var(--dpb-ease-spring);
464
597
  }
465
598
  .dpb-btn:hover { background: var(--dpb-surface); color: var(--dpb-ink); }
466
599
  .dpb-btn-quiet { border-color: transparent; }
@@ -477,7 +610,7 @@ body.dpb-tool-draw .dpb-draw-layer { pointer-events: auto; cursor: crosshair; }
477
610
  background: color-mix(in srgb, var(--dpb-elev) 95%, transparent);
478
611
  box-shadow: var(--dpb-shadow-tool);
479
612
  display: flex; flex-direction: column; align-items: center; gap: 8px;
480
- color: var(--dpb-soft); cursor: pointer; transition: all .2s ease;
613
+ color: var(--dpb-soft); cursor: pointer; transition: all var(--dpb-duration-spring) var(--dpb-ease-spring);
481
614
  }
482
615
  .dpb-reopen-tab:hover { color: var(--dpb-accent); }
483
616
  .dpb-reopen-tab[hidden] { display: none !important; }
@@ -546,7 +679,8 @@ body.dpb-tool-draw .dpb-draw-layer { pointer-events: auto; cursor: crosshair; }
546
679
  .dpb-toasts {
547
680
  position: fixed; top: 60px; right: 24px; z-index: 2147483200;
548
681
  display: flex; flex-direction: column; gap: 8px; pointer-events: none;
549
- font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "PingFang SC", sans-serif;
682
+ font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "PingFang SC",
683
+ "Hiragino Sans GB", "Microsoft YaHei", "Noto Sans SC", sans-serif;
550
684
  }
551
685
  .dpb-toast {
552
686
  display: flex; align-items: center; gap: 8px; max-width: 320px;
@@ -555,8 +689,8 @@ body.dpb-tool-draw .dpb-draw-layer { pointer-events: auto; cursor: crosshair; }
555
689
  color: var(--dpb-elev); border: 1px solid var(--dpb-highlight);
556
690
  box-shadow: var(--dpb-shadow-pill); backdrop-filter: blur(8px);
557
691
  font-size: 12px; font-weight: 500;
558
- animation: dpb-toast-in .25s cubic-bezier(.16,1,.3,1);
559
- transition: opacity .2s ease, transform .2s ease;
692
+ animation: dpb-toast-in var(--dpb-duration-spring) var(--dpb-ease-spring);
693
+ transition: opacity var(--dpb-duration-spring) var(--dpb-ease-spring), transform var(--dpb-duration-spring) var(--dpb-ease-spring);
560
694
  }
561
695
  .dpb-toast.dpb-out { opacity: 0; transform: translateY(-10px); }
562
696
 
@@ -573,6 +707,11 @@ body.dpb-tool-draw .dpb-draw-layer { pointer-events: auto; cursor: crosshair; }
573
707
  display: flex; align-items: center; justify-content: center;
574
708
  background: var(--dpb-accent); color: var(--dpb-accent-ink);
575
709
  font: 700 10px/1 system-ui, sans-serif;
710
+ position: relative;
711
+ }
712
+ .dpb-float.dpb-active .dpb-float-n::after {
713
+ content: ""; position: absolute; inset: -4px; border-radius: inherit;
714
+ border: 2px solid var(--dpb-ring-accent); animation: dpb-pulse-ring 1.8s var(--dpb-ease-pulse) infinite;
576
715
  }
577
716
  .dpb-float-note {
578
717
  font-size: 11px; line-height: 1.4; color: var(--dpb-ink);
@@ -589,6 +728,20 @@ body.dpb-tool-draw .dpb-draw-layer { pointer-events: auto; cursor: crosshair; }
589
728
  .dpb-pin-hover { outline: 1px dashed var(--dpb-ring-accent) !important; outline-offset: 1px !important; }
590
729
  .dpb-pin-flash { animation: dpb-flash 900ms ease-out 1; }
591
730
 
731
+ @keyframes dpb-pin-drop {
732
+ 0% { transform: translateY(-16px) scale(1.3); opacity: 0; }
733
+ 60% { transform: translateY(2px) scale(.95); opacity: 1; }
734
+ 80% { transform: translateY(-1px) scale(1.02); }
735
+ 100% { transform: translateY(0) scale(1); opacity: 1; }
736
+ }
737
+ @keyframes dpb-anchor-enter {
738
+ from { transform: translateY(6px); opacity: 0; }
739
+ to { transform: translateY(0); opacity: 1; }
740
+ }
741
+ @keyframes dpb-pulse-ring {
742
+ 0% { transform: scale(.9); opacity: .72; }
743
+ 100% { transform: scale(1.9); opacity: 0; }
744
+ }
592
745
  @keyframes dpb-flash {
593
746
  0% { box-shadow: 0 0 0 0 var(--dpb-ring-accent); outline-color: var(--dpb-accent) !important; }
594
747
  50% { box-shadow: 0 0 0 6px var(--dpb-ring-accent); }
@@ -607,7 +760,23 @@ body.dpb-tool-draw .dpb-draw-layer { pointer-events: auto; cursor: crosshair; }
607
760
  75%, 100% { transform: scale(2.2); opacity: 0; }
608
761
  }
609
762
  @media (prefers-reduced-motion: reduce) {
610
- .dpb-free-pin, .dpb-toast { animation: none; }
611
- .dpb-status-dot::after { animation: none; }
763
+ #dpb-root *, #dpb-root *::before, #dpb-root *::after,
764
+ #dpb-float-root *, #dpb-float-root *::before, #dpb-float-root *::after,
765
+ .dpb-toasts *, .dpb-toasts *::before, .dpb-toasts *::after {
766
+ scroll-behavior: auto !important;
767
+ transition-duration: 1ms !important;
768
+ transition-delay: 0ms !important;
769
+ }
770
+ .dpb-free-pin,
771
+ .dpb-free-pin.dpb-pin-drop,
772
+ .dpb-free-pin.dpb-active::after,
773
+ .dpb-float.dpb-active .dpb-float-n::after,
774
+ .dpb-anchor.dpb-anchor-enter,
775
+ .dpb-toast,
776
+ .dpb-status-dot::after,
777
+ .dpb-pin-flash,
778
+ .dpb-field textarea[name="feedback"].is-shaking {
779
+ animation: none !important;
780
+ }
612
781
  .dpb-artboard-wrap { transition: none; }
613
782
  }