@1agh/maude 0.43.0 → 0.44.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.
Files changed (122) hide show
  1. package/apps/studio/acp/bridge.ts +44 -10
  2. package/apps/studio/acp/env.ts +23 -0
  3. package/apps/studio/acp/login-state.ts +263 -0
  4. package/apps/studio/acp/plugin-bootstrap.ts +31 -25
  5. package/apps/studio/acp/probe.ts +152 -1
  6. package/apps/studio/annotations-layer.tsx +396 -46
  7. package/apps/studio/api.ts +395 -2
  8. package/apps/studio/bin/_audio-search.mjs +140 -0
  9. package/apps/studio/bin/_import-asset-pdf-worker.mjs +34 -0
  10. package/apps/studio/bin/_import-asset.mjs +815 -0
  11. package/apps/studio/bin/_import-brand.mjs +635 -0
  12. package/apps/studio/bin/_import-tokens-alias-resolver.mjs +95 -0
  13. package/apps/studio/bin/_import-tokens.mjs +1201 -0
  14. package/apps/studio/bin/_transcribe.mjs +419 -0
  15. package/apps/studio/bin/_transcribe.test.mjs +80 -0
  16. package/apps/studio/bin/audio-search.sh +28 -0
  17. package/apps/studio/bin/generate.sh +154 -0
  18. package/apps/studio/bin/import-asset.sh +34 -0
  19. package/apps/studio/bin/import-brand.sh +29 -0
  20. package/apps/studio/bin/import-tokens.sh +33 -0
  21. package/apps/studio/bin/photo-bg-remove.sh +119 -21
  22. package/apps/studio/bin/transcribe.sh +39 -0
  23. package/apps/studio/canvas-edit.ts +197 -2
  24. package/apps/studio/canvas-lib.tsx +115 -6
  25. package/apps/studio/client/app.jsx +1954 -685
  26. package/apps/studio/client/generate-dialog.jsx +352 -0
  27. package/apps/studio/client/github.js +14 -0
  28. package/apps/studio/client/inspector-controls.jsx +781 -0
  29. package/apps/studio/client/panels/BrandUploadPanel.jsx +233 -0
  30. package/apps/studio/client/panels/ChatPanel.jsx +15 -33
  31. package/apps/studio/client/panels/IntroVideoDialog.jsx +44 -0
  32. package/apps/studio/client/panels/OnboardingWizard.jsx +12 -0
  33. package/apps/studio/client/panels/ReadinessList.jsx +227 -7
  34. package/apps/studio/client/panels/SettingsPanel.jsx +828 -0
  35. package/apps/studio/client/panels/SetupChecklist.jsx +223 -0
  36. package/apps/studio/client/photo-knobs.jsx +167 -172
  37. package/apps/studio/client/styles/3-shell-maude.css +334 -28
  38. package/apps/studio/client/styles/4-components.css +223 -0
  39. package/apps/studio/client/styles/6-acp-chat.css +86 -0
  40. package/apps/studio/client/tour/quick-setup-tour.js +39 -0
  41. package/apps/studio/commands/annotation-strokes-command.ts +13 -3
  42. package/apps/studio/config.schema.json +70 -0
  43. package/apps/studio/context-menu.tsx +11 -2
  44. package/apps/studio/context.ts +16 -0
  45. package/apps/studio/design-setup-readiness.ts +115 -0
  46. package/apps/studio/dist/client.bundle.js +2097 -2088
  47. package/apps/studio/dist/styles.css +1 -1
  48. package/apps/studio/draw/palette.ts +34 -0
  49. package/apps/studio/footage/schema.test.ts +92 -0
  50. package/apps/studio/footage/schema.ts +179 -1
  51. package/apps/studio/generation/adapters/elevenlabs.ts +370 -0
  52. package/apps/studio/generation/adapters/gemini.ts +542 -0
  53. package/apps/studio/generation/adapters/groq.test.ts +80 -0
  54. package/apps/studio/generation/adapters/groq.ts +247 -0
  55. package/apps/studio/generation/audio-library.test.ts +95 -0
  56. package/apps/studio/generation/audio-library.ts +156 -0
  57. package/apps/studio/generation/captions.test.ts +78 -0
  58. package/apps/studio/generation/captions.ts +132 -0
  59. package/apps/studio/generation/download.ts +76 -0
  60. package/apps/studio/generation/elevenlabs.test.ts +223 -0
  61. package/apps/studio/generation/gemini.test.ts +350 -0
  62. package/apps/studio/generation/jobs.test.ts +128 -0
  63. package/apps/studio/generation/jobs.ts +243 -0
  64. package/apps/studio/generation/keys.test.ts +75 -0
  65. package/apps/studio/generation/keys.ts +162 -0
  66. package/apps/studio/generation/prefs.test.ts +95 -0
  67. package/apps/studio/generation/prefs.ts +82 -0
  68. package/apps/studio/generation/registry.ts +88 -0
  69. package/apps/studio/generation/types.test.ts +123 -0
  70. package/apps/studio/generation/types.ts +266 -0
  71. package/apps/studio/generation/whisper-models.test.ts +152 -0
  72. package/apps/studio/generation/whisper-models.ts +257 -0
  73. package/apps/studio/generation/whisper-spike-results.md +61 -0
  74. package/apps/studio/git/service.ts +3 -1
  75. package/apps/studio/http.ts +867 -9
  76. package/apps/studio/media/intro.mp4 +0 -0
  77. package/apps/studio/media-commit-chain.ts +119 -0
  78. package/apps/studio/paths.ts +10 -0
  79. package/apps/studio/readiness.ts +108 -20
  80. package/apps/studio/scaffold-design.ts +1145 -0
  81. package/apps/studio/server.ts +13 -1
  82. package/apps/studio/test/_helpers.ts +15 -2
  83. package/apps/studio/test/acp-bridge.test.ts +34 -1
  84. package/apps/studio/test/acp-env.test.ts +30 -0
  85. package/apps/studio/test/acp-plugin-bootstrap.test.ts +23 -57
  86. package/apps/studio/test/acp-session-plugins.test.ts +72 -1
  87. package/apps/studio/test/annotation-strokes-command.test.ts +17 -0
  88. package/apps/studio/test/annotations-layer.test.ts +174 -0
  89. package/apps/studio/test/canvas-origin-gate.test.ts +37 -0
  90. package/apps/studio/test/csp-canvas-shell.test.ts +11 -0
  91. package/apps/studio/test/csrf-write-guard.test.ts +23 -1
  92. package/apps/studio/test/design-setup-readiness.test.ts +155 -0
  93. package/apps/studio/test/element-structural-edit.test.ts +108 -0
  94. package/apps/studio/test/fixtures/fake-claude-auth.mjs +13 -0
  95. package/apps/studio/test/generate-route.test.ts +106 -0
  96. package/apps/studio/test/import-asset-browser.test.ts +64 -0
  97. package/apps/studio/test/import-asset-route.test.ts +71 -0
  98. package/apps/studio/test/import-asset.test.ts +399 -0
  99. package/apps/studio/test/import-brand-browser.test.ts +88 -0
  100. package/apps/studio/test/import-brand-route.test.ts +120 -0
  101. package/apps/studio/test/import-brand.test.ts +206 -0
  102. package/apps/studio/test/import-tokens.test.ts +722 -0
  103. package/apps/studio/test/media-commit-chain.test.ts +210 -0
  104. package/apps/studio/test/photo-bg-remove-validation.test.ts +71 -0
  105. package/apps/studio/test/readiness.test.ts +13 -11
  106. package/apps/studio/test/scaffold-design.test.ts +122 -0
  107. package/apps/studio/test/tour-overlay.test.tsx +16 -0
  108. package/apps/studio/tool-palette.tsx +11 -6
  109. package/apps/studio/ui-prefs.ts +130 -0
  110. package/apps/studio/use-canvas-media-drop.tsx +4 -2
  111. package/apps/studio/use-chrome-visibility.tsx +8 -2
  112. package/apps/studio/whats-new.json +96 -0
  113. package/apps/studio/ws.ts +5 -0
  114. package/cli/bin/maude.mjs +6 -6
  115. package/cli/commands/design.mjs +33 -0
  116. package/cli/lib/gitignore-block.mjs +1 -0
  117. package/cli/lib/pkg-root.mjs +107 -0
  118. package/cli/lib/pkg-root.test.mjs +79 -0
  119. package/cli/lib/reconstruct-toolset.test.mjs +194 -0
  120. package/cli/lib/update-check.mjs +8 -0
  121. package/package.json +12 -10
  122. package/plugins/design/dependencies.json +18 -0
@@ -212,6 +212,20 @@
212
212
  .st-body > .main { flex: 1; min-width: 0; }
213
213
  .st-body > .st-rpanel { flex: 0 0 304px; }
214
214
 
215
+ /* ─── Dock slot (feature-configurable-panel-docking) ──────────────────────────
216
+ * A left/right slot: an optional tab strip over the active panel, which fills the
217
+ * remaining height. The wrapper owns the resizable width; the inner panel fills
218
+ * it (width:100% wins over the panel's own inline width, which we no longer set). */
219
+ .st-dockslot { display: flex; flex-direction: column; min-height: 0; min-width: 0; overflow: hidden; flex: none; }
220
+ .st-dockslot.is-collapsed { width: 0 !important; flex-basis: 0 !important; }
221
+ .st-dockslot > .st-rpanel,
222
+ .st-dockslot > .st-sidebar { flex: 1 1 auto; width: 100%; min-height: 0; }
223
+ .st-docktabs { display: flex; gap: 2px; padding: var(--space-2) var(--space-2) 0; border-bottom: 1px solid var(--border-subtle); background: var(--bg-1); flex: none; }
224
+ .st-docktab { appearance: none; border: 0; background: transparent; cursor: pointer; padding: var(--space-1) var(--space-3); border-radius: var(--radius-sm) var(--radius-sm) 0 0; color: var(--fg-3); font-family: var(--font-mono); font-size: var(--type-xs); letter-spacing: var(--tracking-wide); transition: color var(--dur-soft) var(--ease-out), background var(--dur-soft) var(--ease-out); }
225
+ .st-docktab:hover { color: var(--fg-1); background: var(--bg-2); }
226
+ .st-docktab.is-active { color: var(--fg-0); background: var(--bg-2); box-shadow: inset 0 -2px 0 var(--accent); }
227
+ .st-docktab:focus-visible { outline: 2px solid var(--accent); outline-offset: -2px; }
228
+
215
229
  /* ─── Left sidebar — file tree ────────────────────────────────────────────── */
216
230
  .st-sidebar {
217
231
  width: 252px; flex: 0 0 252px;
@@ -292,6 +306,20 @@
292
306
  min-width: 16px; height: 16px; padding: 0 4px; display: inline-flex; align-items: center; justify-content: center;
293
307
  border-radius: var(--radius-pill); background: var(--accent); color: var(--accent-fg); flex: none;
294
308
  }
309
+ /* DDR-174 (T15) — "reconstructed from an image, experimental" marker. Sits left
310
+ of the git/open-count badges (which already claim margin-left:auto), so this
311
+ one gets an explicit left margin instead of fighting for the auto slot.
312
+ `--status-warn` stays on the border only (a UI-component outline needs just
313
+ 3:1, which it clears) — a11y-auditor caught it also being used as 9px TEXT
314
+ color failing WCAG AA in light theme (~3.46:1 vs the required 4.5:1); the
315
+ sibling `.st-git-badge[data-kind="M"]` avoids this by using the warn token
316
+ as a fill with a fixed dark foreground instead. Text uses `--fg-2` (the
317
+ DS's own documented AA-clearing muted-text token) so both themes pass. */
318
+ .st-row-exp-badge {
319
+ margin-left: 6px; font-family: var(--font-mono); font-size: 9px; font-weight: 700; letter-spacing: 0.02em;
320
+ line-height: 1; padding: 2px 4px; display: inline-flex; align-items: center; justify-content: center;
321
+ border-radius: var(--radius-xs); border: 1px dashed var(--status-warn); color: var(--fg-2); flex: none;
322
+ }
295
323
  /* delete affordance — sibling of the row button (can't nest buttons). */
296
324
  .st-row-wrap { position: relative; display: flex; align-items: center; }
297
325
  .st-row-wrap .st-row { flex: 1; }
@@ -352,6 +380,10 @@
352
380
  .st-empty-body { max-width: 540px; font-size: var(--type-sm); line-height: 1.7; color: var(--fg-2); }
353
381
  .st-empty-body code { font-family: var(--font-mono); font-size: var(--type-xs); background: var(--bg-2); color: var(--accent); padding: 1px 5px; border-radius: var(--radius-xs); }
354
382
  .st-empty-body strong { color: var(--fg-0); font-weight: 600; }
383
+ /* DDR-166 plan, Phase 2 (T7) — persistent "Setup" affordance, shown only while
384
+ the project's own setup (design system / first canvas / brand assets) is
385
+ incomplete; auto-hides once probeSetupReadiness() reports ready. */
386
+ .st-empty-quick-setup { pointer-events: auto; margin-top: var(--space-2); }
355
387
 
356
388
  /* ═══ Task 6 — right panel (Inspector / Comments) + palette + toast ═══════════ */
357
389
  .st-rpanel {
@@ -495,6 +527,44 @@
495
527
  .st-dialog-lbl { font-family: var(--font-mono); font-size: var(--type-xs); color: var(--fg-2); text-transform: uppercase; letter-spacing: var(--tracking-wide); }
496
528
  .st-select { flex: 1; appearance: none; background: var(--bg-2); color: var(--fg-0); border: 1px solid var(--border-default); border-radius: var(--radius-sm); padding: var(--space-2) var(--space-3); font-family: var(--font-body); font-size: var(--type-sm); cursor: pointer; }
497
529
  .st-dialog-ft { display: flex; align-items: center; gap: var(--space-3); justify-content: flex-end; padding: var(--space-4) var(--space-5); border-top: 1px solid var(--border-subtle); }
530
+
531
+ /* ── Unified Settings modal (feature-unified-settings-modal) ────────────────
532
+ * One modal for every Maude preference: a vertical tab rail + an internally
533
+ * scrolling pane, so no category can push the dialog off-screen. Extends the
534
+ * shared .st-dialog shell (which already clips + pops). */
535
+ .st-dialog.is-settings { width: 760px; }
536
+ .st-settings-tabs { display: grid; grid-template-columns: 184px 1fr; min-height: 0; }
537
+ .st-settings-rail { display: flex; flex-direction: column; gap: 2px; padding: var(--space-4); border-right: 1px solid var(--border-subtle); background: var(--bg-0); }
538
+ .st-settings-tab { appearance: none; border: 0; background: transparent; text-align: left; cursor: pointer; padding: var(--space-2) var(--space-3); border-radius: var(--radius-sm); color: var(--fg-2); font-family: var(--font-body); font-size: var(--type-sm); transition: background var(--dur-soft) var(--ease-out), color var(--dur-soft) var(--ease-out); }
539
+ .st-settings-tab:hover { background: var(--bg-3); color: var(--fg-0); }
540
+ .st-settings-tab.is-active { background: var(--accent-tint); color: var(--fg-0); font-weight: 600; }
541
+ .st-settings-tab:focus-visible { outline: 2px solid var(--accent); outline-offset: -2px; }
542
+ /* The scrolling pane — this is the fix for the AI-generation section overflowing
543
+ * the viewport; the pane scrolls, the page never does. */
544
+ .st-settings-pane { max-height: min(72vh, 620px); overflow-y: auto; padding: var(--space-5); }
545
+ .st-settings-pane .st-rp-hd { margin-bottom: var(--space-3); }
546
+ .st-pref-row { display: flex; align-items: flex-start; gap: var(--space-4); justify-content: space-between; padding: var(--space-3) 0; border-bottom: 1px solid var(--border-subtle); cursor: pointer; }
547
+ .st-pref-row:last-child { border-bottom: 0; }
548
+ .st-pref-row.is-disabled { cursor: default; opacity: 0.6; }
549
+ .st-pref-body { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
550
+ .st-pref-label { font-size: var(--type-sm); color: var(--fg-0); font-weight: 500; }
551
+ .st-pref-note { font-size: var(--type-xs); color: var(--fg-3); line-height: 1.45; }
552
+ /* Switch — styled checkbox; compositor-only transition (transform/background). */
553
+ .st-switch { appearance: none; flex: none; position: relative; width: 34px; height: 20px; border-radius: 999px; background: var(--bg-4); border: 1px solid var(--border-default); cursor: pointer; transition: background var(--dur-soft) var(--ease-out); margin-top: 2px; }
554
+ .st-switch::after { content: ''; position: absolute; top: 2px; left: 2px; width: 14px; height: 14px; border-radius: 50%; background: var(--fg-2); transition: transform var(--dur-soft) var(--ease-out), background var(--dur-soft) var(--ease-out); }
555
+ .st-switch:checked { background: var(--accent); border-color: var(--accent); }
556
+ .st-switch:checked::after { transform: translateX(14px); background: var(--accent-fg); }
557
+ .st-switch:disabled { cursor: default; }
558
+ .st-switch:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
559
+ @media (prefers-reduced-motion: reduce) { .st-switch, .st-switch::after, .st-settings-tab { transition-duration: 1ms; } }
560
+ /* Layout tab — left/right segmented control per panel. */
561
+ .st-sidetoggle { display: inline-flex; flex: none; border: 1px solid var(--border-default); border-radius: var(--radius-sm); overflow: hidden; }
562
+ .st-sidebtn { appearance: none; border: 0; background: var(--bg-2); color: var(--fg-2); cursor: pointer; font-family: var(--font-mono); font-size: var(--type-xs); padding: var(--space-1) var(--space-3); min-width: 46px; transition: background var(--dur-soft) var(--ease-out), color var(--dur-soft) var(--ease-out); }
563
+ .st-sidebtn + .st-sidebtn { border-left: 1px solid var(--border-default); }
564
+ .st-sidebtn:hover:not(:disabled) { background: var(--bg-3); color: var(--fg-0); }
565
+ .st-sidebtn.is-active { background: var(--accent); color: var(--accent-fg); }
566
+ .st-sidebtn:disabled { opacity: 0.5; cursor: default; }
567
+ .st-sidebtn:focus-visible { outline: 2px solid var(--accent); outline-offset: -2px; }
498
568
  .st-export-recent { display: flex; flex-direction: column; gap: 2px; max-height: 132px; overflow-y: auto; }
499
569
  .st-export-recent-row { display: flex; align-items: center; justify-content: space-between; gap: var(--space-3); padding: var(--space-2) var(--space-3); border-radius: var(--radius-sm); font-size: var(--type-xs); color: var(--fg-2); }
500
570
  .st-export-recent-row:hover { background: var(--bg-2); }
@@ -509,11 +579,25 @@
509
579
  .st-ap-err { color: var(--danger, #e5484d); font-family: var(--font-mono); font-size: var(--type-xs); }
510
580
  .st-ap-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(112px, 1fr)); gap: var(--space-3); max-height: 52vh; overflow-y: auto; padding: 2px; }
511
581
  .st-ap-empty { grid-column: 1 / -1; color: var(--fg-2); font-family: var(--font-mono); font-size: var(--type-xs); padding: var(--space-6) 0; text-align: center; }
512
- .st-ap-cell { appearance: none; cursor: pointer; display: flex; flex-direction: column; gap: 4px; padding: 6px; border: 1px solid var(--border-subtle); border-radius: var(--radius-sm); background: var(--bg-2); text-align: left; transition: border-color var(--dur-soft) var(--ease-out), background var(--dur-soft) var(--ease-out); }
582
+ .st-ap-cell { position: relative; appearance: none; cursor: pointer; display: flex; flex-direction: column; gap: 4px; padding: 6px; border: 1px solid var(--border-subtle); border-radius: var(--radius-sm); background: var(--bg-2); text-align: left; transition: border-color var(--dur-soft) var(--ease-out), background var(--dur-soft) var(--ease-out); }
513
583
  .st-ap-cell:hover { border-color: var(--accent, var(--border-strong, var(--border-default))); background: var(--bg-3); }
514
584
  .st-ap-thumb { width: 100%; aspect-ratio: 1; object-fit: cover; border-radius: var(--radius-xs); background: var(--bg-4, var(--bg-3)); display: block; }
515
585
  .st-ap-name { font-family: var(--font-mono); font-size: 10px; color: var(--fg-2); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
516
586
 
587
+ /* feature-bulk-media-insert — multi-select grid state + destination toggle + confirm bar */
588
+ .st-ap-cell[data-selected="true"] { border-color: var(--accent); background: var(--bg-3); }
589
+ .st-ap-check { position: absolute; top: 6px; right: 6px; width: 18px; height: 18px; border-radius: var(--radius-pill); border: 1px solid var(--border-default); background: var(--bg-1); color: var(--accent-fg, #fff); display: grid; place-items: center; }
590
+ .st-ap-cell[data-selected="true"] .st-ap-check { background: var(--accent); border-color: var(--accent); }
591
+ .st-ap-confirm { flex-wrap: wrap; }
592
+ .st-ap-count { font-family: var(--font-mono); font-size: var(--type-xs); color: var(--fg-2); }
593
+ .st-ap-seg { display: inline-flex; border: 1px solid var(--border-default); border-radius: var(--radius-sm); overflow: hidden; background: var(--bg-2); }
594
+ .st-ap-seg-btn { appearance: none; border: 0; background: transparent; color: var(--fg-2); font-size: var(--type-xs); font-family: var(--font-mono); padding: var(--space-2) var(--space-3); cursor: pointer; }
595
+ .st-ap-seg-btn[aria-pressed="true"] { background: var(--bg-4); color: var(--fg-0); }
596
+ .st-ap-seg-btn:disabled { opacity: 0.45; cursor: default; }
597
+ .st-ap-seg-btn + .st-ap-seg-btn { border-left: 1px solid var(--border-subtle); }
598
+ .st-ap-dest-note { font-family: var(--font-mono); font-size: var(--type-xs); color: var(--fg-2); }
599
+ .st-ap-confirm-spacer { flex: 1; }
600
+
517
601
  /* ─── StickerPicker (feature-whiteboard-annotation-improvements Phase 4) ──── */
518
602
  .st-sticker-picker { width: 640px; }
519
603
  .st-sticker-picker .input {
@@ -637,11 +721,68 @@
637
721
  * rail; 24px+ targets (bind / seg / box-model inputs); legible box-model. */
638
722
  .st-cp { display: flex; flex-direction: column; gap: var(--space-4); }
639
723
 
640
- /* element identity — Phase 12.3 (W2.3) hairline under the header for structure (Figma-ish) */
641
- .st-cp-id { display: flex; align-items: baseline; justify-content: space-between; gap: var(--space-2); padding-bottom: var(--space-3); border-bottom: 1px solid var(--border-subtle); }
724
+ /* element identity — Phase 12.3 (W2.3) hairline under the header for structure
725
+ * (Figma-ish). DDR-171 critic pass this is the panel's own top-level
726
+ * boundary (vs. a section's internal divider below), so it gets the stronger
727
+ * of the two border tokens; otherwise the id-row rule and the first section's
728
+ * `.st-cp-sechd` rule read as identical weight stacked ~40px apart. */
729
+ .st-cp-id { display: flex; align-items: baseline; justify-content: space-between; gap: var(--space-2); padding-bottom: var(--space-3); border-bottom: 1px solid var(--border-strong); }
642
730
  .st-cp-idtag { font-family: var(--font-mono); font-size: var(--type-sm); color: var(--fg-0); }
643
731
  .st-cp-idcls { color: var(--accent); }
644
- .st-cp-idmeta { font-family: var(--font-mono); font-size: 10px; color: var(--fg-2); text-transform: uppercase; letter-spacing: var(--tracking-wide); }
732
+ /* DDR-171 the Advanced/Designer vocabulary toggle lives in the `.st-cp-id`
733
+ * row's corner slot as a plain `IconButtonGroup` (`.st-cp-iconseg`, styled
734
+ * below) — no extra wrapper class needed, `.st-cp-id`'s own flex/space-between
735
+ * places it. Deliberately NOT a full-width `Segmented` row (too heavy for a
736
+ * mode switch this minor — every other toggle in this panel is icon-sized).
737
+ * The active glyph gets the stronger accent-tint treatment (normally reserved
738
+ * for `aria-pressed` toggles) rather than the neutral `.is-active` fill every
739
+ * OTHER icon-seg in this panel uses — this one is a mode switch, not a value
740
+ * picker, so "which mode am I in" needs to read at a glance, not just on
741
+ * close inspection. Scoped to `.st-cp-idmode` so it doesn't touch direction /
742
+ * align / overflow etc. */
743
+ .st-cp-idmode .st-cp-iconseg button.is-active { background: var(--accent-tint); color: var(--accent); }
744
+
745
+ /* ── DDR-171 Designer-mode layout refinement ─────────────────────────────────
746
+ * Why Figma's panel reads cleaner than our raw-CSS panel, and what we borrow
747
+ * for Designer mode ONLY (Advanced mode stays byte-identical — it's the
748
+ * DDR-104-critic-gated developer surface where mono labels + provenance dots
749
+ * ARE the point). Three root causes, three scoped fixes:
750
+ *
751
+ * 1. Figma has NO per-row status dot — our provenance dot on every row builds
752
+ * a "punch-card" rail down the left edge. In Designer mode we hide the dot
753
+ * for INHERITED/unset rows (the common case) and keep it only where a value
754
+ * is genuinely token-bound or overridden — that's a useful "this is
755
+ * customized" marker even for a designer, and rare enough not to form a
756
+ * rail. The 14px grid column stays reserved so labels never shift.
757
+ * 2. Figma section headers are quiet title-case ("Auto layout"), not code
758
+ * labels ("AUTO LAYOUT"). We drop the mono/uppercase/tracking for the body
759
+ * font, sentence case, one step brighter — reads as a group heading, not a
760
+ * token name.
761
+ * 3. Figma row labels are soft sans, not monospace — we switch the label font
762
+ * to the body face so the column reads as prose, not a code editor. */
763
+ .st-cp--designer .st-cp-prov--inherit { visibility: hidden; }
764
+ .st-cp--designer .st-cp-sechd {
765
+ font-family: var(--font-body);
766
+ font-size: var(--type-sm);
767
+ font-weight: 600;
768
+ text-transform: none;
769
+ letter-spacing: normal;
770
+ color: var(--fg-1);
771
+ padding-bottom: var(--space-2);
772
+ }
773
+ .st-cp--designer .st-cp-sechd:hover, .st-cp--designer .st-cp-sechd:hover svg { color: var(--fg-0); }
774
+ .st-cp--designer .st-cp-label { font-family: var(--font-body); font-size: var(--type-sm); color: var(--fg-1); }
775
+ .st-cp--designer .st-cp-modelabel { font-family: var(--font-body); font-size: var(--type-sm); }
776
+ /* a touch more air between clusters — Figma's sections breathe. */
777
+ .st-cp--designer .st-cp-sec { gap: var(--space-3); }
778
+
779
+ /* a Designer cluster's "···" overflow disclosure — same visual weight as the
780
+ * section reset glyph (`.st-cp-secreset`), right-aligned under the cluster's
781
+ * common rows. */
782
+ .st-cp-clustermore-row { display: flex; justify-content: flex-end; }
783
+ .st-cp-clustermore { appearance: none; cursor: pointer; background: transparent; border: 0; color: var(--fg-3); font-family: var(--font-mono); font-size: var(--type-xs); letter-spacing: var(--tracking-wide); padding: var(--space-1) var(--space-2); border-radius: var(--radius-xs); }
784
+ .st-cp-clustermore:hover { color: var(--accent); background: var(--accent-tint); }
785
+ .st-cp-clustermore:focus-visible { outline: none; color: var(--accent); box-shadow: 0 0 0 2px var(--accent-tint); }
645
786
 
646
787
  /* sections */
647
788
  .st-cp-sec { display: flex; flex-direction: column; gap: var(--space-2); }
@@ -660,13 +801,19 @@
660
801
  .st-cp-reset { width: 16px; height: 16px; }
661
802
  .st-cp-reset:hover, .st-cp-secreset:hover { color: var(--accent); background: var(--accent-tint); }
662
803
  .st-cp-reset:focus-visible, .st-cp-secreset:focus-visible { outline: none; color: var(--accent); box-shadow: 0 0 0 2px var(--accent-tint); }
663
- .st-cp-secreset { align-self: center; }
804
+ .st-cp-secreset { align-self: center; display: inline-grid; place-items: center; }
805
+ .st-cp-secreset.is-quiet { color: var(--fg-3); opacity: 0.4; cursor: default; }
806
+ .st-cp-secreset.is-quiet:hover { color: var(--fg-3); background: transparent; }
664
807
  /* read-only name field for an existing custom CSS prop / HTML attr row */
665
808
  .st-cp-fin--ro { flex: 0 0 38%; background: var(--bg-2); color: var(--fg-2); cursor: default; }
666
809
  .st-cp-fin--ro:focus { outline: none; border-color: var(--border-strong); box-shadow: none; }
667
810
 
668
- /* a labelled row: [provenance] [css property] [control] */
669
- .st-cp-row { display: grid; grid-template-columns: 10px 92px 1fr; align-items: center; gap: var(--space-2); min-height: 28px; }
811
+ /* a labelled row: [provenance] [css property] [control]. DDR-171 critic pass —
812
+ * the dot column widened 10px→14px (was) so the provenance dot reads as a
813
+ * detached status signal instead of looking glued to the label when several
814
+ * rows stack (dot's own size is unchanged — this only adds breathing room,
815
+ * doesn't shrink an already-small interactive/focusable target). */
816
+ .st-cp-row { display: grid; grid-template-columns: 14px 92px 1fr; align-items: center; column-gap: var(--space-3); min-height: 32px; padding: 3px 0; }
670
817
  /* #1 bigger-bet — unset rows recede so the overridden ones pop; full opacity on
671
818
  * hover/focus so they're still editable. The panel reads as a diff of overrides. */
672
819
  .st-cp-row.is-unset { opacity: 0.5; transition: opacity var(--dur-soft) var(--ease-out); }
@@ -679,7 +826,7 @@
679
826
  /* provenance — SHAPE-coded so token/override/inherited survive small size +
680
827
  * colour-blindness: token = filled accent circle · override = filled neutral
681
828
  * square · inherited = hollow ring. Each carries role=img + aria-label. */
682
- .st-cp-prov { width: 8px; height: 8px; display: inline-block; flex: none; padding: 0; }
829
+ .st-cp-prov { width: 9px; height: 9px; display: inline-block; flex: none; padding: 0; }
683
830
  /* Phase 12.3 (#4) — the row's leading dot is a button: provenance + save status
684
831
  * (glow) + double-click reset. No appearance chrome; the variant fills it. */
685
832
  /* reset native button chrome; the variants own the FILL (a transparent bg here
@@ -692,13 +839,12 @@ button.st-cp-prov { appearance: none; border: 0; cursor: default; }
692
839
  .st-cp-prov.is-saved { box-shadow: 0 0 0 3px color-mix(in oklab, var(--status-success) 45%, transparent); }
693
840
  .st-cp-prov.is-saving { box-shadow: 0 0 0 3px color-mix(in oklab, var(--fg-2) 35%, transparent); }
694
841
  .st-cp-prov.is-err { background: var(--status-error); border-color: var(--status-error); box-shadow: 0 0 0 3px color-mix(in oklab, var(--status-error) 40%, transparent); }
695
- /* Phase 12.3 — provenance is SHAPE-coded (token=circle · override=square ·
696
- * inherited=ring) on NEUTRAL fills. Indigo is reserved for its one job on this
697
- * surface (the bound-token ◇ button + the focus ring), so the token dot must NOT
698
- * reuse the accent (design-critic 1.4/1.5). */
699
- .st-cp-prov--bound { background: var(--fg-0); border-radius: 50%; }
700
- .st-cp-prov--raw { background: var(--fg-2); border-radius: 1px; }
701
- .st-cp-prov--inherit { background: transparent; box-shadow: inset 0 0 0 1.5px var(--fg-3); border-radius: 50%; }
842
+ /* handoff — provenance dots match the design specimen (supersedes the older
843
+ * shape-coded/neutral scheme): token-bound = accent · raw override = fg-1 ·
844
+ * inherited = hollow ring. All circles. */
845
+ .st-cp-prov--bound { background: var(--accent); border-radius: 50%; }
846
+ .st-cp-prov--raw { background: var(--fg-1); border-radius: 50%; }
847
+ .st-cp-prov--inherit { background: transparent; box-shadow: inset 0 0 0 1.5px var(--border-strong); border-radius: 50%; }
702
848
 
703
849
  /* colour swatch — standalone (border cluster) + inline (inside the token field) */
704
850
  .st-cp-swatch { flex: none; width: 22px; height: 22px; border-radius: var(--radius-xs); border: 1px solid var(--border-default); }
@@ -739,6 +885,128 @@ body.st-scrubbing, body.st-scrubbing * { cursor: ew-resize !important; user-sele
739
885
  .st-cp-bind:hover::before { border-color: var(--accent); }
740
886
  .st-cp-numin--mini { flex: none; width: 38px; background: var(--bg-3); border: 1px solid var(--border-default); border-radius: var(--radius-xs); }
741
887
 
888
+ /* feature-inspector-controls-redesign — shared control library (inspector-controls.jsx).
889
+ * The drag-to-scrub affordance now lives on the LEADING handle, not the input,
890
+ * so click-to-type + select-all work; the input keeps a plain text caret. */
891
+ .st-cp-handle { cursor: ew-resize; touch-action: none; }
892
+ .st-cp-handle:hover { color: var(--fg-1); background: var(--bg-3); }
893
+ .st-cp-grip { display: inline-block; width: 7px; height: 12px; color: var(--fg-2); background-image: radial-gradient(currentColor 0.8px, transparent 0.8px); background-size: 3px 4px; background-position: center; opacity: 0.7; }
894
+ .st-cp-handle:hover .st-cp-grip { opacity: 1; }
895
+ /* static unit suffix inside a number field (e.g. a SliderField's compact numeric) */
896
+ .st-cp-numsuffix { flex: none; display: inline-flex; align-items: center; padding: 0 6px; color: var(--fg-2); font-family: var(--font-mono); font-size: 10px; border-left: 1px solid var(--border-subtle); background: var(--bg-2); }
897
+ /* compact numeric — the exact-value box paired with a Slider */
898
+ .st-cp-num--compact { flex: 0 0 auto; width: 64px; }
899
+ .st-cp-num--compact .st-cp-numin { text-align: right; }
900
+ /* SliderField row: real slider (flex) + compact numeric (fixed) */
901
+ .st-cp-sfield { flex: 1 1 auto; display: flex; align-items: center; gap: var(--space-2); min-width: 0; }
902
+ /* Toggle (immediate-effect boolean) */
903
+ .st-cp-toggle { display: inline-flex; align-items: center; gap: 6px; font-size: 11px; cursor: pointer; color: var(--fg-1); }
904
+ .st-cp-toggle-lbl { color: var(--fg-1); }
905
+ /* handoff — Toggle is a real switch (not a checkbox), matching the DS .switch. */
906
+ .st-cp-switch { appearance: none; -webkit-appearance: none; position: relative; flex: none; width: 34px; height: 18px; border-radius: var(--radius-pill); background: var(--bg-4); border: 1px solid var(--border-default); cursor: pointer; transition: background var(--dur-flip) var(--ease-out), border-color var(--dur-flip) var(--ease-out); }
907
+ .st-cp-switch::after { content: ""; position: absolute; top: 1px; left: 1px; width: 14px; height: 14px; border-radius: var(--radius-pill); background: var(--fg-1); transition: transform var(--dur-flip) var(--ease-out), background var(--dur-flip) var(--ease-out); }
908
+ .st-cp-switch:checked { background: var(--accent); border-color: var(--accent); }
909
+ .st-cp-switch:checked::after { transform: translateX(16px); background: var(--accent-fg); }
910
+ .st-cp-switch:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
911
+ /* inline help text under a Field control; wrapping a wide row keeps 3 controls fitting */
912
+ .st-cp-help { flex-basis: 100%; font-size: 10px; color: var(--fg-2); margin-top: 2px; }
913
+ .st-cp-row--wide { flex-wrap: wrap; }
914
+
915
+ /* ════ feature-inspector-controls-redesign — ported design controls ══════════
916
+ * The design-specimen control set promoted into the shared library
917
+ * (inspector-controls.jsx). lucide icons; `.st-cp-*` to match the shell. */
918
+
919
+ /* bipolar slider zero-tick */
920
+ .st-cp-zero { position: absolute; top: -3px; bottom: -3px; width: 1px; background: var(--border-strong); }
921
+ .st-cp-dial--scrub, body.st-scrubbing--dial, body.st-scrubbing--dial * { cursor: grabbing !important; }
922
+
923
+ /* icon button group (flex-direction / justify / align / text-align / overflow) */
924
+ .st-cp-iconseg { display: inline-flex; border: 1px solid var(--border-default); border-radius: var(--radius-sm); overflow: hidden; background: var(--bg-2); }
925
+ .st-cp-iconseg button { appearance: none; border: 0; background: transparent; color: var(--fg-2); min-width: 30px; height: 26px; display: grid; place-items: center; cursor: pointer; transition: background var(--dur-soft) var(--ease-out), color var(--dur-soft) var(--ease-out); }
926
+ .st-cp-iconseg button + button { border-left: 1px solid var(--border-subtle); }
927
+ .st-cp-iconseg button:hover:not(.is-active) { color: var(--fg-0); background: var(--bg-3); }
928
+ .st-cp-iconseg button.is-active { background: var(--bg-4); color: var(--fg-0); }
929
+ .st-cp-iconseg button[aria-pressed="true"] { background: var(--accent-tint); color: var(--accent); }
930
+
931
+ /* DS checkbox */
932
+ .st-cp-check { display: inline-flex; align-items: center; gap: var(--space-2); font-size: 11px; color: var(--fg-1); cursor: pointer; }
933
+ .st-cp-check input { position: absolute; opacity: 0; width: 0; height: 0; }
934
+ .st-cp-check-box { flex: none; width: 15px; height: 15px; border-radius: var(--radius-xs); border: 1px solid var(--border-strong); background: var(--bg-3); display: grid; place-items: center; color: transparent; transition: background var(--dur-soft) var(--ease-out), border-color var(--dur-soft) var(--ease-out); }
935
+ .st-cp-check input:checked + .st-cp-check-box { background: var(--accent); border-color: var(--accent); color: var(--accent-fg); }
936
+ .st-cp-check input:focus-visible + .st-cp-check-box { box-shadow: 0 0 0 3px var(--accent-tint); }
937
+
938
+ /* 9-point alignment pad */
939
+ .st-cp-alignpad { width: 68px; height: 68px; display: grid; grid-template: repeat(3, 1fr) / repeat(3, 1fr); border: 1px solid var(--border-default); border-radius: var(--radius-xs); background: var(--bg-3); flex: none; }
940
+ .st-cp-alignpad button { appearance: none; border: 0; background: transparent; display: grid; place-items: center; cursor: pointer; }
941
+ .st-cp-alignpad button::before { content: ""; width: 5px; height: 5px; border-radius: 50%; background: var(--fg-3); transition: background var(--dur-soft) var(--ease-out); }
942
+ .st-cp-alignpad button:hover::before { background: var(--fg-1); }
943
+ .st-cp-alignpad button.is-active::before { background: var(--accent); box-shadow: 0 0 0 3px var(--accent-tint); }
944
+
945
+ /* angle dial */
946
+ .st-cp-dial { flex: none; width: 28px; height: 28px; border-radius: 50%; border: 1px solid var(--border-default); background: var(--bg-3); position: relative; cursor: grab; touch-action: none; padding: 0; }
947
+ .st-cp-dial:active { cursor: grabbing; }
948
+ .st-cp-dial:hover { border-color: var(--border-strong); }
949
+ .st-cp-dial:focus-visible { outline: none; border-color: var(--accent); box-shadow: 0 0 0 3px var(--accent-tint); }
950
+ .st-cp-dial-needle { position: absolute; top: 50%; left: 50%; width: 11px; height: 1.5px; background: var(--accent); border-radius: 1px; transform-origin: left center; transform: rotate(var(--angle, 0deg)); }
951
+ .st-cp-dial::after { content: ""; position: absolute; top: 50%; left: 50%; width: 4px; height: 4px; border-radius: 50%; background: var(--fg-1); transform: translate(-50%, -50%); }
952
+
953
+ /* collapsable section — height animation + caret rotation (on top of .st-cp-sec) */
954
+ .st-cp-sechd[aria-expanded="false"] .st-cp-caret { transform: rotate(-90deg); }
955
+ .st-cp-caret { transition: transform var(--dur-flip) var(--ease-out); display: inline-grid; place-items: center; }
956
+ .st-cp-sec-anim { display: grid; grid-template-rows: 0fr; transition: grid-template-rows var(--dur-panel) var(--ease-in-out); }
957
+ .st-cp-sec-anim.is-open { grid-template-rows: 1fr; }
958
+ .st-cp-sec-inner { overflow: hidden; min-height: 0; }
959
+ .st-cp-sec-anim.is-open .st-cp-sec-inner { padding-top: var(--space-1); }
960
+
961
+ /* compact composite colour field — swatch flush prefix + divider, value [+alpha+eye] */
962
+ .st-cp-cf { display: flex; align-items: stretch; min-height: 26px; min-width: 0; flex: 1 1 auto; border: 1px solid var(--border-default); border-radius: var(--radius-xs); background: var(--bg-3); transition: border-color var(--dur-soft) var(--ease-out), box-shadow var(--dur-soft) var(--ease-out); }
963
+ .st-cp-cf:hover { border-color: var(--border-strong); }
964
+ /* handoff — accent frame ONLY when editing the value input, not when the swatch
965
+ * (popover trigger) has focus — clicking the swatch left a persistent blue frame. */
966
+ .st-cp-cf:has(.st-cp-cf-in:focus) { border-color: var(--accent); box-shadow: 0 0 0 3px var(--accent-tint); }
967
+ .st-cp-cf .st-cp-tokwrap { display: flex; align-items: stretch; }
968
+ .st-cp-cf > *:last-child { border-top-right-radius: 2px; border-bottom-right-radius: 2px; }
969
+ .st-cp-cf-sw { flex: none; width: 26px; border: 0; border-right: 1px solid var(--border-default); border-radius: 2px 0 0 2px; padding: 0; cursor: pointer; position: relative; overflow: hidden; }
970
+ .st-cp-cf-in { flex: 1 1 auto; min-width: 0; width: 100%; border: 0; background: transparent; color: var(--fg-0); font-family: var(--font-mono); font-variant-numeric: tabular-nums; font-size: var(--type-xs); text-transform: uppercase; padding: 0 var(--space-2); }
971
+ .st-cp-cf-in.is-bound { color: var(--accent); text-transform: none; }
972
+ .st-cp-cf-in:focus { outline: none; }
973
+ .st-cp-cf-alpha { flex: none; width: 42px; border: 0; border-left: 1px solid var(--border-default); background: transparent; color: var(--fg-1); font-family: var(--font-mono); font-variant-numeric: tabular-nums; font-size: var(--type-xs); text-align: right; padding: 0 6px; }
974
+ .st-cp-cf-alpha:focus { outline: none; }
975
+ .st-cp-cf-eye { flex: none; width: 26px; border: 0; border-left: 1px solid var(--border-default); background: transparent; color: var(--fg-2); cursor: pointer; display: grid; place-items: center; }
976
+ .st-cp-cf-eye:hover { color: var(--fg-0); background: var(--bg-2); }
977
+ .st-cp-cf-eye.is-off { color: var(--fg-3); }
978
+
979
+ /* value-token binding (◇ + bound chip) */
980
+ .st-cp-tokfield { display: flex; align-items: center; gap: var(--space-2); flex: 1 1 auto; min-width: 0; }
981
+ .st-cp-tokfield > .st-cp-num, .st-cp-tokfield > .st-cp-boundchip { flex: 1 1 auto; min-width: 0; }
982
+ .st-cp-tokbtn { flex: none; width: 24px; height: 24px; display: grid; place-items: center; border: 1px solid var(--border-default); border-radius: var(--radius-xs); background: var(--bg-2); color: var(--fg-2); cursor: pointer; position: relative; }
983
+ .st-cp-tokbtn:hover { border-color: var(--border-strong); color: var(--fg-0); }
984
+ .st-cp-tokbtn.is-bound { border-color: var(--accent); color: var(--accent); background: var(--accent-tint); }
985
+ .st-cp-boundchip { display: flex; align-items: center; gap: var(--space-2); min-height: 26px; border: 1px solid var(--accent-muted); border-radius: var(--radius-xs); background: var(--accent-tint); padding: 0 var(--space-2); }
986
+ .st-cp-boundchip-lead { display: inline-grid; place-items: center; color: var(--accent); }
987
+ .st-cp-boundchip-name { flex: 1 1 auto; min-width: 0; font-family: var(--font-mono); font-size: var(--type-xs); color: var(--accent); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
988
+ .st-cp-boundchip-x { flex: none; appearance: none; border: 0; background: transparent; color: var(--accent); cursor: pointer; display: grid; place-items: center; padding: 0 2px; }
989
+ .st-cp-boundchip-x:hover { color: var(--fg-0); }
990
+
991
+ /* corner-radius control — uniform field + detach quad with per-corner glyphs */
992
+ .st-cp-radius { display: grid; gap: var(--space-2); flex: 1 1 auto; min-width: 0; }
993
+ .st-cp-radius-main { display: flex; align-items: center; gap: var(--space-2); min-width: 0; }
994
+ .st-cp-radius-main > .st-cp-num { flex: 1 1 auto; min-width: 0; }
995
+ .st-cp-splitbtn { flex: none; width: 24px; height: 24px; display: grid; place-items: center; border: 1px solid transparent; border-radius: var(--radius-xs); background: transparent; color: var(--fg-2); cursor: pointer; }
996
+ .st-cp-splitbtn:hover { color: var(--fg-0); background: var(--bg-3); }
997
+ .st-cp-splitbtn.is-on { color: var(--accent); border-color: var(--accent-muted); background: var(--accent-tint); }
998
+ .st-cp-corners { display: grid; grid-template-columns: 1fr 1fr; gap: var(--space-2); }
999
+ .st-cp-corner { display: flex; align-items: center; gap: 6px; min-height: 26px; background: var(--bg-3); border: 1px solid var(--border-default); border-radius: var(--radius-xs); padding: 0 8px; }
1000
+ .st-cp-corner:hover { border-color: var(--border-strong); }
1001
+ .st-cp-corner:focus-within { border-color: var(--accent); box-shadow: 0 0 0 3px var(--accent-tint); }
1002
+ .st-cp-corner input { flex: 1; min-width: 0; width: 100%; appearance: none; border: 0; background: transparent; color: var(--fg-0); font-family: var(--font-mono); font-variant-numeric: tabular-nums; font-size: 11px; padding: 0; }
1003
+ .st-cp-corner input:focus { outline: none; }
1004
+ .st-cp-cnr { flex: none; width: 11px; height: 11px; border: 1.5px solid var(--fg-2); box-sizing: border-box; }
1005
+ .st-cp-cnr--tl { border-right: 0; border-bottom: 0; border-top-left-radius: 4px; }
1006
+ .st-cp-cnr--tr { border-left: 0; border-bottom: 0; border-top-right-radius: 4px; }
1007
+ .st-cp-cnr--bl { border-right: 0; border-top: 0; border-bottom-left-radius: 4px; }
1008
+ .st-cp-cnr--br { border-left: 0; border-top: 0; border-bottom-right-radius: 4px; }
1009
+
742
1010
  /* select (font-weight, border-style) */
743
1011
  .st-cp-select { flex: 1 1 auto; min-width: 0; display: inline-flex; align-items: center; justify-content: space-between; gap: var(--space-2); appearance: none; cursor: pointer; font-family: var(--font-body); font-size: var(--type-xs); color: var(--fg-0); background: var(--bg-3); border: 1px solid var(--border-default); border-radius: var(--radius-xs); padding: 4px var(--space-2); min-height: 26px; }
744
1012
  .st-cp-select span { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
@@ -768,9 +1036,12 @@ body.st-scrubbing, body.st-scrubbing * { cursor: ew-resize !important; user-sele
768
1036
  .st-cp-bars--just i { width: 100%; }
769
1037
 
770
1038
  /* nested box-model widget (Webflow-style): margin outer · padding inner */
771
- .st-cp-box { position: relative; margin-top: var(--space-1); padding: 26px; border: 1px dashed var(--border-default); border-radius: var(--radius-sm); background: var(--bg-2); display: grid; place-items: center; }
772
- .st-cp-boxpad { position: relative; width: 100%; padding: 26px; border: 1px solid var(--border-default); border-radius: var(--radius-xs); background: var(--bg-3); display: grid; place-items: center; }
773
- .st-cp-boxcore { min-width: 72px; padding: 7px 12px; border-radius: var(--radius-xs); background: var(--bg-4); border: 1px solid var(--accent); color: var(--fg-0); font-family: var(--font-mono); font-variant-numeric: tabular-nums; font-size: 11px; text-align: center; }
1039
+ .st-cp-box { position: relative; margin-top: var(--space-2); padding: 34px 30px; border: 1px dashed var(--border-default); border-radius: var(--radius-sm); background: var(--bg-2); display: grid; place-items: center; }
1040
+ .st-cp-boxpad { position: relative; width: 100%; padding: 30px 26px; border: 1px dashed var(--border-subtle); border-radius: var(--radius-xs); background: var(--bg-1); display: grid; place-items: center; }
1041
+ /* handoff spacing size core is PLAIN mono text (no box/border), 1:1 with the
1042
+ * design's .icp-box-core. Only the position core (--pos, below) is an accent bar. */
1043
+ .st-cp-boxcore { min-width: 72px; padding: 10px 16px; background: transparent; border: 0; color: var(--fg-2); font-family: var(--font-mono); font-variant-numeric: tabular-nums; font-size: 10px; text-align: center; }
1044
+ .st-cp-boxcore--pos { padding: 7px 12px; border-radius: var(--radius-xs); font-size: 11px; }
774
1045
  .st-cp-boxtag { position: absolute; top: 4px; left: 6px; display: inline-flex; align-items: center; gap: 4px; font-family: var(--font-mono); font-size: 10px; letter-spacing: var(--tracking-wide); text-transform: uppercase; color: var(--fg-2); pointer-events: none; }
775
1046
  .st-cp-boxtag .st-cp-prov { width: 6px; height: 6px; }
776
1047
  .st-cp-boxv { position: absolute; width: 36px; height: 24px; border: 1px solid transparent; border-radius: var(--radius-xs); background: transparent; color: var(--fg-0); font-family: var(--font-mono); font-variant-numeric: tabular-nums; font-size: 11px; text-align: center; padding: 0; }
@@ -788,27 +1059,33 @@ body.st-scrubbing, body.st-scrubbing * { cursor: ew-resize !important; user-sele
788
1059
  .st-cp-boxv--il { left: 0; top: 50%; transform: translateY(-50%); }
789
1060
  .st-cp-boxv--ir { right: 0; top: 50%; transform: translateY(-50%); }
790
1061
  .st-cp-boxtag--i { color: var(--accent); }
791
- .st-cp-boxcore--pos { text-transform: none; letter-spacing: 0; }
1062
+ /* handoff position core IS an accent bar (design); spacing core is plain text */
1063
+ .st-cp-boxcore--pos { text-transform: none; letter-spacing: 0; background: var(--accent-tint); border: 1px solid var(--accent); color: var(--accent); }
792
1064
  .st-cp-boxhint { display: flex; flex-wrap: wrap; gap: var(--space-1); }
793
1065
  .st-cp-boxhint + .st-cp-row { margin-top: var(--space-1); }
794
1066
  .st-cp-chip { font-family: var(--font-mono); font-size: 10px; color: var(--fg-2); background: var(--bg-2); border: 1px solid var(--border-default); border-radius: var(--radius-xs); padding: 1px 6px; }
795
1067
 
796
1068
  /* opacity slider — role=slider, focusable */
797
1069
  .st-cp-slider { flex: 1 1 auto; display: flex; align-items: center; gap: var(--space-2); min-width: 0; }
798
- .st-cp-track { position: relative; flex: 1 1 auto; height: 6px; border-radius: 3px; background: var(--bg-4); border: 1px solid var(--border-default); cursor: pointer; }
1070
+ .st-cp-track { position: relative; flex: 1 1 auto; height: 6px; border-radius: 3px; background: var(--bg-2); border: 1px solid var(--border-default); cursor: pointer; }
799
1071
  .st-cp-track:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
800
1072
  .st-cp-fill { position: absolute; left: 0; top: 0; bottom: 0; border-radius: 3px; background: var(--accent); }
801
1073
  .st-cp-thumb { position: absolute; top: 50%; width: 12px; height: 12px; border-radius: 50%; background: var(--fg-0); border: 2px solid var(--accent); transform: translate(-50%, -50%); }
802
1074
  .st-cp-slval { flex: none; font-family: var(--font-mono); font-variant-numeric: tabular-nums; font-size: var(--type-xs); color: var(--fg-1); width: 34px; text-align: right; }
803
1075
 
804
1076
  /* border cluster — fills to the right control rail */
805
- .st-cp-border { flex: 1 1 auto; display: flex; align-items: center; gap: var(--space-2); min-width: 0; }
1077
+ .st-cp-border { flex: 1 1 auto; display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-2); min-width: 0; }
806
1078
  .st-cp-border .st-cp-swatch--mini { margin-left: 0; }
807
1079
  /* design-critic 1.1 — the border row was cramming width+style+swatch; the
808
1080
  * width field was eating the flex and clipping the style select to "styl▾".
809
- * Fix the width field, let the style select take the rest. */
1081
+ * Fix the width field, let the style select take the rest. Task 5 (feature-
1082
+ * inspector-controls-redesign) — border-width now skips its unit-select
1083
+ * (px-only, opts.fixedUnit) so the cluster is narrower to start with;
1084
+ * flex-wrap is the fallback so [width][style][swatch] never clips at the
1085
+ * panel's 260px minimum — the style select wraps to its own line rather than
1086
+ * shrinking to an illegible sliver. */
810
1087
  .st-cp-border .st-cp-num { flex: 0 0 58px; }
811
- .st-cp-border .st-cp-nsel { flex: 1 1 auto; max-width: none; }
1088
+ .st-cp-border .st-cp-nsel { flex: 1 1 96px; max-width: none; min-width: 64px; }
812
1089
 
813
1090
  /* per-field save state */
814
1091
  /* #5 — error-only now (idle/saved status moved into each row's leading dot). */
@@ -837,11 +1114,26 @@ body.st-scrubbing, body.st-scrubbing * { cursor: ew-resize !important; user-sele
837
1114
 
838
1115
  /* Stage M — Fixed / Hug / Fill sizing-mode segmented control (per axis). */
839
1116
  .st-cp-modes { display: flex; flex-direction: column; gap: var(--space-1); margin-bottom: var(--space-1); }
840
- .st-cp-modeseg { display: flex; align-items: stretch; gap: var(--space-1); }
841
- .st-cp-modeax { display: inline-flex; align-items: center; justify-content: center; min-width: 18px; font-family: var(--font-mono); font-size: 10px; color: var(--fg-2); }
842
- .st-cp-modebtn { flex: 1; appearance: none; cursor: pointer; border: 1px solid var(--border-default); background: var(--bg-3); color: var(--fg-1); font-family: var(--font-mono); font-size: 10px; min-height: 22px; border-radius: var(--radius-xs); padding: 0 var(--space-1); }
843
- .st-cp-modebtn:hover:not(.is-active):not(:disabled) { background: var(--bg-4); color: var(--fg-0); }
844
- .st-cp-modebtn.is-active { background: var(--accent-tint); border-color: var(--accent); color: var(--accent); }
1117
+ /* handoff Fixed/Hug/Fill uses the shared Segmented (.st-cp-seg) component,
1118
+ * stretched full-width, with a leading W/H axis label. */
1119
+ .st-cp-modeseg { display: flex; align-items: center; gap: var(--space-2); }
1120
+ .st-cp-modeax { display: inline-flex; align-items: center; justify-content: center; min-width: 14px; font-family: var(--font-mono); font-size: 10px; color: var(--fg-2); }
1121
+ /* handoff — Size mode row: grid-aligned with the other rows (label column +
1122
+ * control column), the compact Segmented right-aligned to match the number
1123
+ * inputs below, at the same 26px input height. Neutral active, mono lowercase. */
1124
+ .st-cp-moderow { display: grid; grid-template-columns: 14px 92px 1fr; align-items: center; column-gap: var(--space-3); min-height: 32px; padding: 3px 0; }
1125
+ .st-cp-modelabel { grid-column: 2; font-size: var(--type-xs); color: var(--fg-1); }
1126
+ .st-cp-modeseg { grid-column: 3; display: flex; justify-content: flex-end; }
1127
+ .st-cp-modeseg .st-cp-seg { flex: none; display: inline-flex; height: 26px; background: var(--bg-2); border-radius: var(--radius-sm); }
1128
+ .st-cp-modeseg .st-cp-segbtn { flex: none; display: inline-flex; align-items: center; font-family: var(--font-mono); font-size: var(--type-xs); text-transform: lowercase; color: var(--fg-2); min-width: 0; min-height: 0; padding: 0 var(--space-4); }
1129
+ .st-cp-modeseg .st-cp-segbtn.is-active { background: var(--bg-4); color: var(--fg-0); }
1130
+ .st-cp-modeseg .st-cp-segbtn:hover:not(.is-active) { background: var(--bg-3); color: var(--fg-0); }
1131
+ /* .st-cp-modebtn — still used by the artboard height-sizing control (not CssKnobs). */
1132
+ .st-cp-modebtn { flex: 1; appearance: none; cursor: pointer; border: 1px solid var(--border-default); border-left-width: 0; background: var(--bg-2); color: var(--fg-2); font-family: var(--font-mono); font-size: 10px; text-transform: lowercase; min-height: 24px; padding: 0 var(--space-2); }
1133
+ .st-cp-modebtn:first-of-type { border-left-width: 1px; border-radius: var(--radius-sm) 0 0 var(--radius-sm); }
1134
+ .st-cp-modebtn:last-child { border-radius: 0 var(--radius-sm) var(--radius-sm) 0; }
1135
+ .st-cp-modebtn:hover:not(.is-active):not(:disabled) { background: var(--bg-3); color: var(--fg-0); }
1136
+ .st-cp-modebtn.is-active { background: var(--bg-4); color: var(--fg-0); }
845
1137
  .st-cp-modebtn:disabled { opacity: 0.5; cursor: default; }
846
1138
  /* Stage M — sub-header for the flex-child row group + the make-flex CTA. */
847
1139
  .st-cp-subhd { font-family: var(--font-mono); font-size: 10px; color: var(--fg-2); text-transform: uppercase; letter-spacing: 0.04em; margin-top: var(--space-2); }
@@ -919,6 +1211,17 @@ body.st-scrubbing, body.st-scrubbing * { cursor: ew-resize !important; user-sele
919
1211
  * hue slider + eyedropper + hex field. The swatch on the colour row is the only
920
1212
  * trigger (no separate native picker). */
921
1213
  .st-cp-cpick { display: flex; flex-direction: column; gap: var(--space-2); padding: var(--space-1); }
1214
+ /* handoff — hex row on top + preview circle + RGB fields (design parity) */
1215
+ .st-cp-cpick-hexrow { display: flex; align-items: center; gap: var(--space-2); }
1216
+ .st-cp-cpick-hexsw { flex: none; width: 34px; height: 26px; border-radius: var(--radius-xs); border: 1px solid var(--border-default); }
1217
+ .st-cp-cpick-hex { flex: 1 1 auto; min-width: 0; appearance: none; border: 1px solid var(--border-default); border-radius: var(--radius-xs); background: var(--bg-3); color: var(--fg-0); font-family: var(--font-mono); font-size: var(--type-xs); padding: 4px var(--space-2); }
1218
+ .st-cp-cpick-hex:focus { outline: none; border-color: var(--accent); box-shadow: 0 0 0 3px var(--accent-tint); }
1219
+ .st-cp-cpick-preview { flex: none; width: 20px; height: 20px; border-radius: 50%; border: 1px solid var(--border-default); }
1220
+ .st-cp-cpick-rgb { display: grid; grid-template-columns: repeat(3, 1fr); gap: var(--space-2); }
1221
+ .st-cp-cpick-rgbf { display: grid; gap: 2px; justify-items: center; }
1222
+ .st-cp-cpick-rgbf input { width: 100%; text-align: center; appearance: none; border: 1px solid var(--border-default); border-radius: var(--radius-xs); background: var(--bg-3); color: var(--fg-0); font-family: var(--font-mono); font-variant-numeric: tabular-nums; font-size: var(--type-xs); padding: 3px 2px; }
1223
+ .st-cp-cpick-rgbf input:focus { outline: none; border-color: var(--accent); box-shadow: 0 0 0 3px var(--accent-tint); }
1224
+ .st-cp-cpick-rgbf span { font-family: var(--font-mono); font-size: 9px; color: var(--fg-3); }
922
1225
  .st-cp-swatch--trigger { position: relative; overflow: hidden; cursor: pointer; appearance: none; padding: 0; }
923
1226
  .st-cp-swatch--trigger.is-bound { border-color: var(--accent); box-shadow: 0 0 0 2px var(--accent-tint); }
924
1227
  .st-cp-cpick-sv { position: relative; display: block; width: 100%; height: 120px; border-radius: var(--radius-sm); border: 1px solid var(--border-default); overflow: hidden; cursor: crosshair; padding: 0; touch-action: none; }
@@ -1806,6 +2109,9 @@ body.st-scrubbing, body.st-scrubbing * { cursor: ew-resize !important; user-sele
1806
2109
  .ob-eyebrow { font-family: var(--font-mono); font-size: var(--type-xs); letter-spacing: var(--tracking-wide); text-transform: uppercase; color: var(--accent); }
1807
2110
  .ob-head h1 { margin: 0; font-family: var(--font-display); font-size: var(--type-3xl); line-height: var(--lh-2xl); font-weight: 600; letter-spacing: var(--tracking-tight); }
1808
2111
  .ob-head p { margin: 0; max-width: 56ch; color: var(--fg-2); font-size: var(--type-md); line-height: var(--lh-lg); }
2112
+ .ob-watch-intro { align-self: flex-start; display: inline-flex; align-items: center; gap: var(--space-2); margin-top: var(--space-1); padding: var(--space-2) var(--space-3); border: 1px solid var(--border-default); border-radius: var(--radius-pill); background: var(--bg-1); color: var(--fg-1); font-size: var(--type-sm); cursor: pointer; }
2113
+ .ob-watch-intro:hover { border-color: var(--border-strong); color: var(--fg-0); background: var(--bg-2); }
2114
+ .ob-watch-intro:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
1809
2115
 
1810
2116
  .ob-doors { display: flex; flex-direction: column; gap: var(--space-4); max-width: 720px; }
1811
2117
  .ob-door { position: relative; display: grid; grid-template-columns: auto 1fr auto; align-items: center; gap: var(--space-4); width: 100%; text-align: left; padding: var(--space-5); border: 1px solid var(--border-default); border-radius: var(--radius-lg); background: var(--bg-1); color: inherit; cursor: pointer; transition: border-color var(--dur-soft) var(--ease-out), background var(--dur-soft) var(--ease-out), transform var(--dur-soft) var(--ease-out); }