@1agh/maude 0.29.0 → 0.31.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 (162) hide show
  1. package/README.md +6 -6
  2. package/apps/studio/acp/bridge.ts +285 -0
  3. package/apps/studio/acp/env.ts +48 -0
  4. package/apps/studio/acp/index.ts +132 -0
  5. package/apps/studio/acp/probe.ts +112 -0
  6. package/apps/studio/acp/transcript.ts +149 -0
  7. package/apps/studio/ai-banner.tsx +0 -1
  8. package/apps/studio/annotations-align.ts +149 -0
  9. package/apps/studio/annotations-bindings.ts +197 -0
  10. package/apps/studio/annotations-context-toolbar.tsx +436 -186
  11. package/apps/studio/annotations-groups.ts +270 -0
  12. package/apps/studio/annotations-layer.tsx +1714 -1661
  13. package/apps/studio/annotations-model.ts +2077 -0
  14. package/apps/studio/annotations-snap.ts +125 -0
  15. package/apps/studio/api.ts +433 -182
  16. package/apps/studio/bin/_png-playwright.mjs +1 -1
  17. package/apps/studio/bin/annotate.mjs +732 -0
  18. package/apps/studio/bin/annotate.sh +17 -0
  19. package/apps/studio/bin/chat-open.sh +44 -0
  20. package/apps/studio/bin/read-annotations.mjs +152 -17
  21. package/apps/studio/build.ts +1 -1
  22. package/apps/studio/canvas-arrowheads.ts +78 -9
  23. package/apps/studio/canvas-cursors.ts +2 -0
  24. package/apps/studio/canvas-edit.ts +257 -7
  25. package/apps/studio/canvas-icons.tsx +105 -0
  26. package/apps/studio/canvas-lib.tsx +112 -19
  27. package/apps/studio/canvas-list-watch.ts +177 -0
  28. package/apps/studio/canvas-shell.tsx +326 -9
  29. package/apps/studio/client/app.jsx +3579 -250
  30. package/apps/studio/client/canvas-url.js +5 -0
  31. package/apps/studio/client/github.js +99 -0
  32. package/apps/studio/client/index.html +1 -1
  33. package/apps/studio/client/panels/ChatPanel.jsx +770 -0
  34. package/apps/studio/client/panels/CollabModelInfographic.jsx +71 -0
  35. package/apps/studio/client/panels/CreateProject.jsx +334 -0
  36. package/apps/studio/client/panels/DiffView.jsx +590 -0
  37. package/apps/studio/client/panels/GitPanel.jsx +767 -0
  38. package/apps/studio/client/panels/IdentityBar.jsx +294 -0
  39. package/apps/studio/client/panels/OnboardingWizard.jsx +563 -0
  40. package/apps/studio/client/panels/RepoBranchSwitcher.jsx +349 -0
  41. package/apps/studio/client/panels/acp-runtime.js +286 -0
  42. package/apps/studio/client/panels/chat-markdown.jsx +138 -0
  43. package/apps/studio/client/panels/git-grouping.js +86 -0
  44. package/apps/studio/client/styles/0-reset.css +4 -0
  45. package/apps/studio/client/styles/3-shell-maude.css +1326 -14
  46. package/apps/studio/client/styles/4-components.css +39 -0
  47. package/apps/studio/client/styles/5-maude-overrides.css +41 -2
  48. package/apps/studio/client/styles/6-acp-chat.css +771 -0
  49. package/apps/studio/client/styles/_index.css +2 -0
  50. package/apps/studio/client/tour/collab-tour.js +61 -0
  51. package/apps/studio/client/tour/overlay.jsx +116 -18
  52. package/apps/studio/client/tour/usage-tour.js +23 -10
  53. package/apps/studio/client/whats-new.jsx +25 -10
  54. package/apps/studio/collab/registry.ts +13 -0
  55. package/apps/studio/collab/room.ts +36 -0
  56. package/apps/studio/commands/annotation-strokes-command.ts +1 -1
  57. package/apps/studio/commands/move-artboards-command.ts +1 -1
  58. package/apps/studio/comments-overlay.tsx +7 -5
  59. package/apps/studio/context-menu.tsx +4 -3
  60. package/apps/studio/contextual-toolbar.tsx +14 -0
  61. package/apps/studio/cursors-overlay.tsx +37 -21
  62. package/apps/studio/dist/client.bundle.js +31795 -1829
  63. package/apps/studio/dist/comment-mount.js +97 -9
  64. package/apps/studio/dist/styles.css +7938 -1599
  65. package/apps/studio/dom-selection.ts +115 -0
  66. package/apps/studio/export-dialog.tsx +3 -3
  67. package/apps/studio/git/endpoints.ts +338 -0
  68. package/apps/studio/git/service.ts +1334 -0
  69. package/apps/studio/git/watch.ts +97 -0
  70. package/apps/studio/github/endpoints.ts +358 -0
  71. package/apps/studio/github/service.ts +231 -0
  72. package/apps/studio/github/token.ts +53 -0
  73. package/apps/studio/history.ts +20 -3
  74. package/apps/studio/hmr-broadcast.ts +9 -2
  75. package/apps/studio/http.ts +508 -6
  76. package/apps/studio/input-router.tsx +7 -0
  77. package/apps/studio/inspect.ts +37 -8
  78. package/apps/studio/participants-chrome.tsx +70 -16
  79. package/apps/studio/paths.ts +12 -0
  80. package/apps/studio/scaffold-design.ts +57 -0
  81. package/apps/studio/server.ts +70 -4
  82. package/apps/studio/sync/agent.ts +311 -57
  83. package/apps/studio/sync/codec.ts +69 -0
  84. package/apps/studio/sync/cold-start.ts +198 -0
  85. package/apps/studio/sync/connection-state.ts +58 -2
  86. package/apps/studio/sync/hub-link.ts +137 -0
  87. package/apps/studio/sync/index.ts +563 -221
  88. package/apps/studio/sync/journal.ts +190 -0
  89. package/apps/studio/sync/migrate-seed.ts +202 -44
  90. package/apps/studio/sync/projection.ts +22 -3
  91. package/apps/studio/sync/status.ts +15 -4
  92. package/apps/studio/test/acp-bridge.test.ts +127 -0
  93. package/apps/studio/test/acp-env.test.ts +65 -0
  94. package/apps/studio/test/acp-origin-gate.test.ts +78 -0
  95. package/apps/studio/test/acp-transcript.test.ts +112 -0
  96. package/apps/studio/test/activity.test.ts +1 -7
  97. package/apps/studio/test/annotate-write.test.ts +184 -0
  98. package/apps/studio/test/annotations-align.test.ts +88 -0
  99. package/apps/studio/test/annotations-bindings.test.ts +124 -0
  100. package/apps/studio/test/annotations-groups.test.ts +231 -0
  101. package/apps/studio/test/annotations-snap.test.ts +79 -0
  102. package/apps/studio/test/canvas-create-api.test.ts +72 -0
  103. package/apps/studio/test/canvas-edit.test.ts +181 -1
  104. package/apps/studio/test/canvas-list-watch.test.ts +322 -0
  105. package/apps/studio/test/canvas-meta-api.test.ts +161 -27
  106. package/apps/studio/test/canvas-origin-gate.test.ts +43 -0
  107. package/apps/studio/test/chat-markdown.test.tsx +58 -0
  108. package/apps/studio/test/collab-bridge.test.ts +0 -2
  109. package/apps/studio/test/collab-room.test.ts +2 -7
  110. package/apps/studio/test/collab-session-survival.test.tsx +176 -0
  111. package/apps/studio/test/csp-canvas-shell.test.ts +5 -0
  112. package/apps/studio/test/csrf-write-guard.test.ts +78 -0
  113. package/apps/studio/test/editing-presence.test.ts +103 -0
  114. package/apps/studio/test/figjam-v3-model.test.ts +342 -0
  115. package/apps/studio/test/fixtures/figjam-v3-groups-bindings.svg +1 -0
  116. package/apps/studio/test/fixtures/mock-acp-agent.mjs +45 -0
  117. package/apps/studio/test/git-api.test.ts +0 -0
  118. package/apps/studio/test/git-branches.test.ts +106 -0
  119. package/apps/studio/test/git-grouping.test.ts +106 -0
  120. package/apps/studio/test/git-watch.test.ts +97 -0
  121. package/apps/studio/test/github-api.test.ts +465 -0
  122. package/apps/studio/test/hub-link.test.ts +69 -0
  123. package/apps/studio/test/participants-chrome.test.ts +36 -1
  124. package/apps/studio/test/shared-doc-migrate.test.ts +224 -14
  125. package/apps/studio/test/sync-agent.test.ts +272 -2
  126. package/apps/studio/test/sync-codec.test.ts +65 -0
  127. package/apps/studio/test/sync-cold-seed-dedup.test.ts +187 -0
  128. package/apps/studio/test/sync-cold-start.test.ts +304 -0
  129. package/apps/studio/test/sync-connection-state.test.ts +68 -0
  130. package/apps/studio/test/sync-hardening.test.ts +0 -8
  131. package/apps/studio/test/sync-hubs-config.test.ts +0 -1
  132. package/apps/studio/test/sync-incident-replay.test.ts +211 -0
  133. package/apps/studio/test/sync-journal.test.ts +176 -0
  134. package/apps/studio/test/sync-runtime.test.ts +360 -5
  135. package/apps/studio/test/sync-status.test.ts +66 -0
  136. package/apps/studio/test/tour-overlay.test.tsx +18 -0
  137. package/apps/studio/test/use-annotation-resize.test.ts +159 -0
  138. package/apps/studio/test/use-artboard-drag.test.ts +0 -1
  139. package/apps/studio/test/use-collab.test.ts +0 -0
  140. package/apps/studio/test/use-tool-mode.test.tsx +5 -2
  141. package/apps/studio/tool-palette.tsx +30 -11
  142. package/apps/studio/undo-hud.tsx +0 -1
  143. package/apps/studio/use-agent-presence.tsx +4 -2
  144. package/apps/studio/use-annotation-resize.tsx +484 -54
  145. package/apps/studio/use-annotation-selection.tsx +16 -4
  146. package/apps/studio/use-canvas-activity.tsx +2 -2
  147. package/apps/studio/use-chrome-visibility.tsx +66 -0
  148. package/apps/studio/use-collab.tsx +434 -202
  149. package/apps/studio/use-selection-set.tsx +9 -0
  150. package/apps/studio/use-tool-mode.tsx +5 -1
  151. package/apps/studio/whats-new.json +208 -10
  152. package/apps/studio/whats-new.schema.json +18 -2
  153. package/apps/studio/ws.ts +44 -1
  154. package/cli/commands/design-link.test.mjs +84 -0
  155. package/cli/commands/design.mjs +3 -1
  156. package/cli/commands/design.test.mjs +5 -1
  157. package/cli/lib/design-link.mjs +51 -1
  158. package/cli/lib/gitignore-block.mjs +16 -3
  159. package/cli/lib/gitignore-block.test.mjs +13 -1
  160. package/package.json +11 -9
  161. package/plugins/design/dependencies.json +17 -0
  162. package/plugins/design/templates/_shell.html +58 -12
@@ -60,7 +60,7 @@
60
60
  .st-menu:hover { background: var(--bg-3); color: var(--fg-0); }
61
61
  .st-menu[aria-expanded="true"] { background: var(--bg-3); color: var(--fg-0); }
62
62
  .st-menu[aria-disabled="true"] { color: var(--fg-3); cursor: default; }
63
- .st-menu:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; }
63
+ /* keyboard ring: the shared `.maude :is(button…):focus-visible` recipe */
64
64
 
65
65
  .st-mb-right { margin-left: auto; display: flex; align-items: center; gap: var(--space-3); }
66
66
  .st-stamp {
@@ -91,7 +91,9 @@
91
91
  position: absolute; top: 38px; min-width: 230px;
92
92
  background: var(--bg-2); border: 1px solid var(--border-default);
93
93
  border-radius: var(--radius-md); box-shadow: var(--shadow-lg);
94
- padding: var(--space-2); z-index: 60;
94
+ /* above the floating st-banner (9100) an open menu must never sit under
95
+ a transient notice */
96
+ padding: var(--space-2); z-index: 9150;
95
97
  animation: st-pop var(--dur-panel) var(--ease-out);
96
98
  transform-origin: top left;
97
99
  }
@@ -123,12 +125,23 @@
123
125
  transition: background var(--dur-soft) var(--ease-out), color var(--dur-soft) var(--ease-out);
124
126
  }
125
127
  .st-iconbtn:hover { background: var(--bg-3); color: var(--fg-0); }
126
- .st-iconbtn:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; }
127
128
 
128
129
  /* ─── Presence avatars (menubar) ──────────────────────────────────────────── */
129
130
  .st-presence { display: flex; align-items: center; }
130
- .st-avatar { width: 22px; height: 22px; border-radius: var(--radius-pill); display: grid; place-items: center; font-family: var(--font-mono); font-size: 10px; line-height: 1; letter-spacing: 0.02em; text-transform: uppercase; color: #fff; font-weight: 600; }
131
- .st-presence .st-avatar { margin-left: -6px; border: 1.5px solid var(--bg-1); }
131
+ /* DS avatar recipe (ui_kits showcase `.sc-avatar`): hue-TINTED surface + hue
132
+ * border + fg-0 text. A solid hue fill with white text broke the accent-fg
133
+ * contrast rule on dark and washed out entirely in light theme. */
134
+ .st-avatar {
135
+ --av-hue: var(--accent);
136
+ width: 22px; height: 22px; border-radius: var(--radius-pill);
137
+ display: grid; place-items: center;
138
+ font-family: var(--font-mono); font-size: 10px; line-height: 1;
139
+ letter-spacing: 0.02em; text-transform: uppercase; font-weight: 600;
140
+ background: color-mix(in oklab, var(--av-hue) 22%, var(--bg-3));
141
+ border: 1px solid var(--av-hue);
142
+ color: var(--fg-0);
143
+ }
144
+ .st-presence .st-avatar { margin-left: -6px; box-shadow: 0 0 0 1.5px var(--bg-1); }
132
145
  .st-presence .st-avatar:first-child { margin-left: 0; }
133
146
 
134
147
  /* ─── Status bar (bottom — context) ───────────────────────────────────────── */
@@ -151,13 +164,21 @@
151
164
  .st-sb-spacer { flex: 1; }
152
165
  .st-sb-theme { display: inline-flex; align-items: center; gap: var(--space-2); cursor: pointer; appearance: none; color: var(--fg-0); font-family: var(--font-mono); font-size: var(--type-xs); padding: 3px var(--space-3); border-radius: var(--radius-sm); border: 1px solid var(--border-default); background: var(--bg-3); }
153
166
  .st-sb-theme:hover { background: var(--bg-4); border-color: var(--border-strong); }
154
- .st-sb-theme:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; }
155
167
  .st-dot { width: 7px; height: 7px; border-radius: var(--radius-pill); display: inline-block; flex: none; }
156
168
  .st-live-dot { width: 7px; height: 7px; border-radius: var(--radius-pill); background: var(--presence-offline); flex: none; }
157
169
  .st-live-dot.is-connected { background: var(--presence-online); }
158
170
  .st-sb-sync-dot { width: 7px; height: 7px; border-radius: var(--radius-pill); background: var(--status-warn); flex: none; }
159
171
  .st-sb-sync-dot.is-online { background: var(--presence-online); }
160
172
 
173
+ /* Phase 28 — clickable "changes" slot (opens the Changes panel). Button reset; the
174
+ .st-sb-slot + .st-sb-slot rule still supplies the divider + left padding. */
175
+ .st-sb-changes { appearance: none; border: 0; padding: 0; border-radius: 0; background: transparent; font: inherit; cursor: pointer; }
176
+ .st-sb-changes:hover .val, .st-sb-changes.is-open .val { color: var(--accent); }
177
+ .st-sb-changes:focus-visible { outline: 2px solid var(--accent); outline-offset: -2px; }
178
+ .st-sb-changes-dot { width: 7px; height: 7px; border-radius: var(--radius-pill); background: var(--border-strong); flex: none; }
179
+ .st-sb-changes.has-changes .st-sb-changes-dot { background: var(--status-warn); }
180
+ .st-sb-changes.has-unpushed .st-sb-changes-dot { background: var(--accent); }
181
+
161
182
  /* ═══ Task 4 — body row · sidebar · tree · rail ═══════════════════════════════ */
162
183
 
163
184
  /* The body flex row replaces the legacy `.app` grid: rail | sidebar | main | rpanel. */
@@ -205,7 +226,6 @@
205
226
  border-radius: var(--radius-sm); color: var(--fg-0); font-family: var(--font-body); font-size: var(--type-sm);
206
227
  padding: var(--space-2) var(--space-3);
207
228
  }
208
- .st-newboard input:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; }
209
229
  .st-newboard-go {
210
230
  appearance: none; border: 1px solid var(--accent); background: var(--accent); color: var(--accent-fg);
211
231
  border-radius: var(--radius-sm); cursor: pointer; padding: 0 var(--space-3); font-family: var(--font-mono); font-size: var(--type-sm);
@@ -257,10 +277,13 @@
257
277
  }
258
278
  /* Kept in the a11y tree (opacity, not display:none) so keyboard users reach it. */
259
279
  .st-row-wrap:hover .st-row-del, .st-row-del:focus-visible { opacity: 1; }
260
- /* Shift the open-comments badge left of the delete button on hover so they
261
- don't overlap (the delete is absolute at the row's right edge). */
280
+ /* Shift the open-comments badge AND the M/A/D/U git badge left of the delete
281
+ button on hover/focus so they don't overlap (the delete is absolute at the
282
+ row's right edge). */
262
283
  .st-row-wrap:hover .st-row-badge,
263
- .st-row-wrap:focus-within .st-row-badge { margin-right: 24px; }
284
+ .st-row-wrap:focus-within .st-row-badge,
285
+ .st-row-wrap:hover .st-git-badge,
286
+ .st-row-wrap:focus-within .st-git-badge { margin-right: 24px; }
264
287
  .st-row-del:hover { color: var(--status-error); background: color-mix(in oklab, var(--status-error) 14%, transparent); }
265
288
 
266
289
  /* DS-folder row — chevron toggles disclosure, name opens the system view. */
@@ -359,7 +382,8 @@
359
382
 
360
383
  /* ─── Floating status banners (sync / git-lifecycle) ──────────────────────── */
361
384
  .st-banner {
362
- position: fixed; top: 12px; left: 50%; transform: translateX(-50%); z-index: 9100;
385
+ /* below the 40px menubar — at top:12px the banner covered the menus + file slot */
386
+ position: fixed; top: 48px; left: 50%; transform: translateX(-50%); z-index: 9100;
363
387
  display: flex; align-items: center; gap: var(--space-3);
364
388
  padding: var(--space-2) var(--space-4); border-radius: var(--radius-pill);
365
389
  border: 1px solid var(--border-default); background: var(--bg-2); color: var(--fg-0);
@@ -384,7 +408,7 @@
384
408
  /* ─── Command palette (⌘K) ───────────────────────────────────────────────── */
385
409
  .st-scrim { position: fixed; inset: 0; background: color-mix(in oklab, var(--bg-0) 62%, transparent); z-index: 9000; display: grid; place-items: start center; padding-top: 12vh; }
386
410
  .st-palette {
387
- width: 560px; max-width: 92vw; background: var(--bg-2); border: 1px solid var(--border-strong);
411
+ width: 560px; max-width: 92vw; background: var(--bg-2); border: 1px solid var(--border-default);
388
412
  border-radius: var(--radius-lg); box-shadow: var(--shadow-lg); overflow: hidden;
389
413
  animation: st-pop var(--dur-route) var(--ease-out);
390
414
  }
@@ -424,7 +448,7 @@
424
448
 
425
449
  /* ─── Export & handoff dialog (Plan C P9/P10) ──────────────────────────────
426
450
  * Lifted from Studio.css `.st-dialog*` / `.st-fmt*`. Rendered inside `.st-scrim`. */
427
- .st-dialog { width: 540px; max-width: 92vw; background: var(--bg-1); border: 1px solid var(--border-strong); border-radius: var(--radius-lg); box-shadow: var(--shadow-lg); overflow: hidden; animation: st-pop var(--dur-route) var(--ease-out); }
451
+ .st-dialog { width: 540px; max-width: 92vw; background: var(--bg-1); border: 1px solid var(--border-default); border-radius: var(--radius-lg); box-shadow: var(--shadow-lg); overflow: hidden; animation: st-pop var(--dur-route) var(--ease-out); }
428
452
  .st-dialog-hd { display: flex; align-items: center; justify-content: space-between; padding: var(--space-4) var(--space-5); border-bottom: 1px solid var(--border-subtle); }
429
453
  .st-dialog-title { font-family: var(--font-display); font-size: var(--type-lg); font-weight: 600; color: var(--fg-0); }
430
454
  .st-dialog-bd { padding: var(--space-5); display: flex; flex-direction: column; gap: var(--space-4); }
@@ -450,10 +474,1298 @@
450
474
  .st-field { font-family: var(--font-mono); font-variant-numeric: tabular-nums; 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: var(--space-1) var(--space-2); width: 58px; text-align: right; }
451
475
  .st-field-lead { display: inline-flex; align-items: center; gap: var(--space-1); }
452
476
  .st-field-lead .k { font-family: var(--font-mono); font-size: 9px; color: var(--fg-3); }
477
+ /* Phase 12.3 — maude DS coordinate cell (components-inputs `.fld-mini`): a mono
478
+ * axis tag glued to the tabular field, the tag a left segment of one bordered
479
+ * group. focus-within rings the whole cell (border-accent + 3px tint halo). */
480
+ .st-fmini { display: inline-flex; align-items: stretch; min-width: 0; flex: 1 1 0; border: 1px solid var(--border-default); border-radius: var(--radius-xs); overflow: hidden; background: var(--bg-3); transition: border-color var(--dur-soft) var(--ease-out), box-shadow var(--dur-soft) var(--ease-out); }
481
+ .st-fmini .st-mtag { flex: none; display: flex; align-items: center; justify-content: center; width: 20px; font-family: var(--font-mono); font-size: var(--type-xs); color: var(--fg-2); background: var(--bg-2); border-right: 1px solid var(--border-default); }
482
+ .st-fmini input, .st-fmini .st-fminival { flex: 1 1 auto; min-width: 0; width: 100%; box-sizing: border-box; appearance: none; border: 0; border-radius: 0; background: transparent; color: var(--fg-0); font-family: var(--font-mono); font-variant-numeric: tabular-nums; font-size: var(--type-xs); text-align: right; padding: 3px var(--space-2); }
483
+ .st-fmini input:focus { outline: none; }
484
+ .st-fmini:focus-within { border-color: var(--accent); box-shadow: 0 0 0 3px var(--accent-tint); }
485
+ .st-insp-unit { align-self: center; font-family: var(--font-mono); font-size: 10px; color: var(--fg-2); letter-spacing: var(--tracking-wide); }
486
+ /* design-critic 1.2 — the Inspect FILL/TEXT chip was collapsing to a thin sliver
487
+ * (read as a text caret) because its container `.st-swatch-row` had no flex rule,
488
+ * so the inline swatch span ignored its width/height. Define the row + make the
489
+ * chip a block so the resolved colour reads as a real swatch. */
490
+ .st-swatch-row { display: flex; align-items: center; gap: var(--space-2); min-width: 0; }
491
+ .st-insp-swatch { display: block; width: 18px; height: 18px; border-radius: var(--radius-xs); border: 1px solid var(--border-default); flex: none; }
453
492
  .st-layer { display: flex; align-items: center; gap: var(--space-2); padding: var(--space-2); border-radius: var(--radius-xs); font-size: var(--type-sm); color: var(--fg-1); font-family: var(--font-mono); }
454
493
  .st-layer:hover { background: var(--bg-2); }
455
- .st-layer.is-sel { background: var(--accent-tint); color: var(--fg-0); }
494
+ /* maude signature — selection is an accent-tint wash + an inset 2px accent bar,
495
+ * never a solid fill (DS hard rule). */
496
+ .st-layer.is-sel { background: var(--accent-tint); color: var(--fg-0); box-shadow: inset 2px 0 0 var(--accent); }
497
+ /* Phase 12 Task 4 — browsable layers tree rows */
498
+ .st-layer--row { cursor: pointer; padding: 3px var(--space-2); gap: 4px; white-space: nowrap; }
499
+ .st-layer--row:focus-visible { outline: 2px solid var(--accent); outline-offset: -2px; }
500
+ .st-layer-caret { flex: none; width: 14px; height: 14px; display: inline-flex; align-items: center; justify-content: center; background: transparent; border: 0; color: var(--fg-3); font-size: 9px; line-height: 1; cursor: pointer; padding: 0; }
501
+ .st-layer-label { flex: 1 1 auto; overflow: hidden; text-overflow: ellipsis; }
502
+ .st-layer-type { flex: none; font-size: 9px; color: var(--fg-3); text-transform: uppercase; letter-spacing: var(--tracking-wide); }
503
+ /* Phase 12.3 (W3.1) — type icon tint + per-row visibility (eye) toggle. */
504
+ .st-layer-ticon { flex: none; color: var(--fg-3); }
505
+ .st-layer.is-sel .st-layer-ticon { color: var(--accent); }
506
+ .st-layer-eye { flex: none; width: 18px; height: 18px; display: inline-flex; align-items: center; justify-content: center; background: transparent; border: 0; color: var(--fg-3); cursor: pointer; padding: 0; border-radius: var(--radius-xs); opacity: 0; }
507
+ .st-layer--row:hover .st-layer-eye, .st-layer--row:focus-within .st-layer-eye { opacity: 1; }
508
+ .st-layer-eye:hover { color: var(--fg-0); background: var(--bg-3); }
509
+ .st-layer-eye:focus-visible { outline: none; color: var(--accent); box-shadow: 0 0 0 2px var(--accent-tint); }
510
+ /* a hidden layer stays dim + keeps its eye visible (so it can be re-shown) */
511
+ .st-layer.is-hidden { opacity: 0.45; }
512
+ .st-layer.is-hidden .st-layer-eye { opacity: 1; color: var(--fg-2); }
456
513
  .st-css { font-family: var(--font-mono); font-size: var(--type-xs); background: var(--bg-0); border: 1px solid var(--border-subtle); border-radius: var(--radius-sm); padding: var(--space-3); line-height: 1.7; color: var(--fg-1); }
457
514
  .st-css .comment { color: var(--fg-3); }
458
515
 
516
+ /* Phase 12.2 — in-canvas CSS editor knobs. Full-width value fields (NOT the 58px
517
+ read-only inspect fields), grouped sections, color swatch, per-field feedback. */
518
+ .st-css-panel { display: flex; flex-direction: column; gap: var(--space-2); }
519
+ .st-css-title { font-family: var(--font-mono); font-size: var(--type-xs); color: var(--fg-1); word-break: break-word; }
520
+ .st-css-group { font-family: var(--font-mono); font-size: 10px; letter-spacing: var(--tracking-wide); text-transform: uppercase; color: var(--fg-3); margin-top: var(--space-3); }
521
+ .st-css-row { display: grid; grid-template-columns: 72px 1fr; align-items: center; gap: var(--space-2); }
522
+ .st-css-label { font-family: var(--font-mono); font-size: var(--type-xs); color: var(--fg-2); }
523
+ .st-css-control { display: flex; align-items: center; gap: var(--space-2); min-width: 0; }
524
+ .st-css-input { flex: 1 1 auto; min-width: 0; width: 100%; box-sizing: border-box; font-family: var(--font-mono); font-variant-numeric: tabular-nums; 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: var(--space-1) var(--space-2); text-align: left; }
525
+ .st-css-input::placeholder { color: var(--fg-3); }
526
+ .st-css-input:focus { outline: none; border-color: var(--accent); box-shadow: 0 0 0 2px var(--accent-tint); }
527
+ .st-css-swatch { position: relative; flex: none; width: 22px; height: 22px; border-radius: var(--radius-xs); border: 1px solid var(--border-default); padding: 0; cursor: pointer; overflow: hidden; background-image: linear-gradient(45deg, var(--bg-2) 25%, transparent 25%), linear-gradient(-45deg, var(--bg-2) 25%, transparent 25%), linear-gradient(45deg, transparent 75%, var(--bg-2) 75%), linear-gradient(-45deg, transparent 75%, var(--bg-2) 75%); background-size: 8px 8px; background-position: 0 0, 0 4px, 4px -4px, -4px 0; }
528
+ .st-css-swatch > span { position: absolute; inset: 0; }
529
+ .st-css-swatch input[type="color"] { position: absolute; inset: -4px; width: calc(100% + 8px); height: calc(100% + 8px); opacity: 0; cursor: pointer; border: 0; padding: 0; }
530
+ .st-css-status { font-family: var(--font-mono); font-size: 10px; min-height: 12px; }
531
+ .st-css-status.is-error { color: oklch(0.62 0.2 25); }
532
+ .st-css-status.is-saved { color: var(--fg-3); }
533
+ .st-css-help { font-size: var(--type-xs); color: var(--fg-3); line-height: 1.5; margin-top: var(--space-2); }
534
+ .st-css-help code { font-family: var(--font-mono); color: var(--fg-2); background: var(--bg-3); padding: 0 3px; border-radius: 3px; }
535
+ .st-css-disabled { color: var(--fg-2); font-size: var(--type-sm); line-height: 1.6; }
536
+ .st-css-disabled code { font-family: var(--font-mono); color: var(--accent); background: var(--bg-2); padding: 1px 5px; border-radius: var(--radius-xs); }
537
+
538
+
539
+ /* Phase 12.2 port — interactive CSS panel knobs (DDR-104). Ported from the
540
+ critic-approved + user-iterated Studio.css spec. Tokens resolve from the
541
+ shell .maude[data-theme] root (1-tokens-maude.css). */
542
+ /* ─── CSS panel · Phase 12.2 spec (DDR-104) ──────────────────────────────────
543
+ * Hybrid vocabulary (friendly section headers + CSS-named rows), per-field
544
+ * token dropdowns, nested box-model widget, per-row provenance, two-hatch
545
+ * Advanced section. Scoped `.st-cp-*` (never reuses the cramped `.st-field`).
546
+ * Critic iter-1 fixes: live text off the disabled --fg-3 token → --fg-2 (WCAG
547
+ * AA ≥4.5:1); SHAPE-coded provenance (circle/square/ring, not colour alone);
548
+ * colour swatch lives INSIDE the token field so every control shares one left
549
+ * rail; 24px+ targets (bind / seg / box-model inputs); legible box-model. */
550
+ .st-cp { display: flex; flex-direction: column; gap: var(--space-4); }
551
+
552
+ /* element identity — Phase 12.3 (W2.3) hairline under the header for structure (Figma-ish) */
553
+ .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); }
554
+ .st-cp-idtag { font-family: var(--font-mono); font-size: var(--type-sm); color: var(--fg-0); }
555
+ .st-cp-idcls { color: var(--accent); }
556
+ .st-cp-idmeta { font-family: var(--font-mono); font-size: 10px; color: var(--fg-2); text-transform: uppercase; letter-spacing: var(--tracking-wide); }
557
+
558
+ /* sections */
559
+ .st-cp-sec { display: flex; flex-direction: column; gap: var(--space-2); }
560
+ /* section header — collapsible disclosure button */
561
+ .st-cp-sechd { width: 100%; appearance: none; cursor: pointer; display: flex; align-items: center; gap: var(--space-2); background: transparent; border: 0; border-bottom: 1px solid var(--border-subtle); text-align: left; font-family: var(--font-mono); font-size: var(--type-xs); text-transform: uppercase; letter-spacing: var(--tracking-wide); color: var(--fg-2); padding: 0 0 var(--space-1); }
562
+ .st-cp-sechd svg { color: var(--fg-2); }
563
+ .st-cp-sechd:hover, .st-cp-sechd:hover svg { color: var(--fg-0); }
564
+ /* Phase 12.3 — section header row carries the shared underline so the toggle
565
+ * button + the per-section reset sit on one baseline. */
566
+ .st-cp-sechd-row { display: flex; align-items: stretch; gap: var(--space-1); border-bottom: 1px solid var(--border-subtle); }
567
+ .st-cp-sechd-row .st-cp-sechd { border-bottom: 0; flex: 1 1 auto; }
568
+ /* reset affordances — a subtle revert glyph (⟲). Muted by default, brightens on
569
+ * hover/focus. The per-row variant lives in .st-cp-ctl / .st-cp-kv; the
570
+ * per-section variant sits at the end of the header row. */
571
+ .st-cp-reset, .st-cp-secreset { flex: none; appearance: none; cursor: pointer; background: transparent; border: 0; color: var(--fg-3); font-size: 12px; line-height: 1; padding: 2px; border-radius: var(--radius-xs); }
572
+ .st-cp-reset { width: 16px; height: 16px; }
573
+ .st-cp-reset:hover, .st-cp-secreset:hover { color: var(--accent); background: var(--accent-tint); }
574
+ .st-cp-reset:focus-visible, .st-cp-secreset:focus-visible { outline: none; color: var(--accent); box-shadow: 0 0 0 2px var(--accent-tint); }
575
+ .st-cp-secreset { align-self: center; }
576
+ /* read-only name field for an existing custom CSS prop / HTML attr row */
577
+ .st-cp-fin--ro { flex: 0 0 38%; background: var(--bg-2); color: var(--fg-2); cursor: default; }
578
+ .st-cp-fin--ro:focus { outline: none; border-color: var(--border-strong); box-shadow: none; }
579
+
580
+ /* a labelled row: [provenance] [css property] [control] */
581
+ .st-cp-row { display: grid; grid-template-columns: 10px 92px 1fr; align-items: center; gap: var(--space-2); min-height: 28px; }
582
+ /* #1 bigger-bet — unset rows recede so the overridden ones pop; full opacity on
583
+ * hover/focus so they're still editable. The panel reads as a diff of overrides. */
584
+ .st-cp-row.is-unset { opacity: 0.5; transition: opacity var(--dur-soft) var(--ease-out); }
585
+ .st-cp-row.is-unset:hover, .st-cp-row.is-unset:focus-within { opacity: 1; }
586
+ /* one-line labels keep the row rhythm uniform; the full property name is in the
587
+ * row's title tooltip (design-critic 4.1 — uneven wrap was the top craft nit). */
588
+ .st-cp-label { font-family: var(--font-mono); font-size: var(--type-xs); color: var(--fg-1); line-height: 1.15; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
589
+ .st-cp-ctl { display: flex; align-items: center; gap: var(--space-2); min-width: 0; }
590
+
591
+ /* provenance — SHAPE-coded so token/override/inherited survive small size +
592
+ * colour-blindness: token = filled accent circle · override = filled neutral
593
+ * square · inherited = hollow ring. Each carries role=img + aria-label. */
594
+ .st-cp-prov { width: 8px; height: 8px; display: inline-block; flex: none; padding: 0; }
595
+ /* Phase 12.3 (#4) — the row's leading dot is a button: provenance + save status
596
+ * (glow) + double-click reset. No appearance chrome; the variant fills it. */
597
+ /* reset native button chrome; the variants own the FILL (a transparent bg here
598
+ * would out-specify them and hollow the dot — that was the bug). */
599
+ button.st-cp-prov { appearance: none; border: 0; cursor: default; }
600
+ .st-cp-prov.is-resettable { cursor: pointer; }
601
+ .st-cp-prov.is-resettable:hover { box-shadow: 0 0 0 3px var(--bg-4); }
602
+ .st-cp-prov:focus-visible { outline: none; box-shadow: 0 0 0 2px var(--accent-tint); }
603
+ /* save-status glows (replaces the trailing ✓/! markers) */
604
+ .st-cp-prov.is-saved { box-shadow: 0 0 0 3px color-mix(in oklab, var(--status-success) 45%, transparent); }
605
+ .st-cp-prov.is-saving { box-shadow: 0 0 0 3px color-mix(in oklab, var(--fg-2) 35%, transparent); }
606
+ .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); }
607
+ /* Phase 12.3 — provenance is SHAPE-coded (token=circle · override=square ·
608
+ * inherited=ring) on NEUTRAL fills. Indigo is reserved for its one job on this
609
+ * surface (the bound-token ◇ button + the focus ring), so the token dot must NOT
610
+ * reuse the accent (design-critic 1.4/1.5). */
611
+ .st-cp-prov--bound { background: var(--fg-0); border-radius: 50%; }
612
+ .st-cp-prov--raw { background: var(--fg-2); border-radius: 1px; }
613
+ .st-cp-prov--inherit { background: transparent; box-shadow: inset 0 0 0 1.5px var(--fg-3); border-radius: 50%; }
614
+
615
+ /* colour swatch — standalone (border cluster) + inline (inside the token field) */
616
+ .st-cp-swatch { flex: none; width: 22px; height: 22px; border-radius: var(--radius-xs); border: 1px solid var(--border-default); }
617
+ .st-cp-swatch--mini { width: 18px; height: 18px; }
618
+ .st-cp-tokswatch { flex: none; width: 14px; height: 14px; border-radius: 3px; border: 1px solid var(--border-default); }
619
+
620
+ /* token field (per-field DS-token dropdown) */
621
+ .st-cp-token { flex: 1 1 auto; min-width: 0; display: inline-flex; align-items: center; gap: var(--space-2); appearance: none; cursor: pointer; font-family: var(--font-mono); 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); }
622
+ .st-cp-token:hover { border-color: var(--accent); }
623
+ .st-cp-tokdot { flex: none; width: 8px; height: 8px; border-radius: 50%; background: var(--accent); }
624
+ .st-cp-tokname { flex: 1 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
625
+ .st-cp-token svg { flex: none; color: var(--fg-2); }
626
+
627
+ /* number field: input + steppers + unit-select + bind-to-token */
628
+ .st-cp-num { flex: 1 1 auto; min-width: 0; display: inline-flex; align-items: stretch; background: var(--bg-3); border: 1px solid var(--border-default); border-radius: var(--radius-xs); overflow: hidden; min-height: 26px; }
629
+ /* #2 — Figma-style property prefix segment inside the numeric field. */
630
+ .st-cp-numlead { flex: none; display: inline-flex; align-items: center; justify-content: center; width: 20px; color: var(--fg-2); font-family: var(--font-mono); font-size: var(--type-xs); border-right: 1px solid var(--border-subtle); background: var(--bg-2); }
631
+ .st-cp-num:focus-within .st-cp-numlead { color: var(--fg-1); }
632
+ .st-cp-num:hover { border-color: var(--border-strong); }
633
+ .st-cp-num:focus-within { border-color: var(--accent); box-shadow: 0 0 0 3px var(--accent-tint); }
634
+ .st-cp-numin { flex: 1 1 auto; 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: var(--type-xs); padding: 3px var(--space-2); }
635
+ .st-cp-numin::placeholder { color: var(--fg-2); }
636
+ .st-cp-numin:focus { outline: none; }
637
+ /* Phase 12.3 (W2.2) — scrub affordance: a number field signals it's draggable
638
+ * (ew-resize), reverts to a text caret when focused for typing. While a scrub is
639
+ * active the whole document holds the resize cursor + suppresses selection. */
640
+ .st-cp-scrub { cursor: ew-resize; }
641
+ .st-cp-scrub:focus { cursor: text; }
642
+ body.st-scrubbing, body.st-scrubbing * { cursor: ew-resize !important; user-select: none !important; }
643
+ .st-cp-step { flex: none; display: flex; flex-direction: column; border-left: 1px solid var(--border-subtle); }
644
+ .st-cp-stepb { flex: 1; appearance: none; cursor: pointer; border: 0; background: var(--bg-2); color: var(--fg-2); font-size: 7px; line-height: 1; padding: 0 5px; }
645
+ .st-cp-stepb:first-child { border-bottom: 1px solid var(--border-subtle); }
646
+ .st-cp-stepb:hover { color: var(--accent); }
647
+ .st-cp-unit { flex: none; appearance: none; cursor: pointer; display: inline-flex; align-items: center; gap: 2px; border: 0; border-left: 1px solid var(--border-subtle); background: var(--bg-2); color: var(--fg-2); font-family: var(--font-mono); font-size: 10px; padding: 0 var(--space-2); }
648
+ .st-cp-unit svg { color: var(--fg-2); }
649
+ .st-cp-bind { flex: none; width: 24px; appearance: none; cursor: pointer; border: 0; border-left: 1px solid var(--border-subtle); background: var(--bg-2); position: relative; }
650
+ .st-cp-bind::before { content: ""; position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); width: 7px; height: 7px; border-radius: 50%; border: 1.5px solid var(--fg-2); }
651
+ .st-cp-bind:hover::before { border-color: var(--accent); }
652
+ .st-cp-numin--mini { flex: none; width: 38px; background: var(--bg-3); border: 1px solid var(--border-default); border-radius: var(--radius-xs); }
653
+
654
+ /* select (font-weight, border-style) */
655
+ .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; }
656
+ .st-cp-select span { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
657
+ .st-cp-select svg { flex: none; color: var(--fg-2); }
658
+ .st-cp-select--mini { flex: 0 1 auto; }
659
+
660
+ /* segmented control (text-align) with drawn align glyphs — 26px tall targets */
661
+ .st-cp-seg { display: inline-flex; background: var(--bg-3); border: 1px solid var(--border-default); border-radius: var(--radius-xs); overflow: hidden; }
662
+ .st-cp-segbtn { appearance: none; cursor: pointer; border: 0; background: transparent; min-width: 26px; min-height: 26px; padding: 0 7px; display: inline-flex; align-items: center; justify-content: center; border-right: 1px solid var(--border-subtle); }
663
+ .st-cp-segbtn:last-child { border-right: 0; }
664
+ .st-cp-segbtn.is-active { background: var(--accent-tint); }
665
+ .st-cp-segbtn:hover:not(.is-active) { background: var(--bg-4); }
666
+ .st-cp-bars { display: flex; flex-direction: column; gap: 2px; width: 13px; color: var(--fg-1); }
667
+ .st-cp-segbtn.is-active .st-cp-bars { color: var(--accent); }
668
+ .st-cp-bars i { height: 2px; border-radius: 1px; background: currentColor; }
669
+ .st-cp-bars--left i:nth-child(1) { width: 100%; }
670
+ .st-cp-bars--left i:nth-child(2) { width: 60%; }
671
+ .st-cp-bars--left i:nth-child(3) { width: 80%; }
672
+ .st-cp-bars--center i { margin: 0 auto; }
673
+ .st-cp-bars--center i:nth-child(1) { width: 100%; }
674
+ .st-cp-bars--center i:nth-child(2) { width: 55%; }
675
+ .st-cp-bars--center i:nth-child(3) { width: 75%; }
676
+ .st-cp-bars--right i { margin-left: auto; }
677
+ .st-cp-bars--right i:nth-child(1) { width: 100%; }
678
+ .st-cp-bars--right i:nth-child(2) { width: 60%; }
679
+ .st-cp-bars--right i:nth-child(3) { width: 80%; }
680
+ .st-cp-bars--just i { width: 100%; }
681
+
682
+ /* nested box-model widget (Webflow-style): margin outer · padding inner */
683
+ .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; }
684
+ .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; }
685
+ .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; }
686
+ .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; }
687
+ .st-cp-boxtag .st-cp-prov { width: 6px; height: 6px; }
688
+ .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; }
689
+ .st-cp-boxv.is-zero { color: var(--fg-2); }
690
+ .st-cp-boxv:hover, .st-cp-boxv:focus { border-color: var(--border-strong); background: var(--bg-1); outline: none; color: var(--fg-0); }
691
+ .st-cp-boxv--mt, .st-cp-boxv--pt { top: 1px; left: 50%; transform: translateX(-50%); }
692
+ .st-cp-boxv--mb, .st-cp-boxv--pb { bottom: 1px; left: 50%; transform: translateX(-50%); }
693
+ .st-cp-boxv--ml, .st-cp-boxv--pl { left: 0; top: 50%; transform: translateY(-50%); }
694
+ .st-cp-boxv--mr, .st-cp-boxv--pr { right: 0; top: 50%; transform: translateY(-50%); }
695
+ .st-cp-boxhint { display: flex; flex-wrap: wrap; gap: var(--space-1); }
696
+ .st-cp-boxhint + .st-cp-row { margin-top: var(--space-1); }
697
+ .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; }
698
+
699
+ /* opacity slider — role=slider, focusable */
700
+ .st-cp-slider { flex: 1 1 auto; display: flex; align-items: center; gap: var(--space-2); min-width: 0; }
701
+ .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; }
702
+ .st-cp-track:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
703
+ .st-cp-fill { position: absolute; left: 0; top: 0; bottom: 0; border-radius: 3px; background: var(--accent); }
704
+ .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%); }
705
+ .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; }
706
+
707
+ /* border cluster — fills to the right control rail */
708
+ .st-cp-border { flex: 1 1 auto; display: flex; align-items: center; gap: var(--space-2); min-width: 0; }
709
+ .st-cp-border .st-cp-swatch--mini { margin-left: 0; }
710
+ /* design-critic 1.1 — the border row was cramming width+style+swatch; the
711
+ * width field was eating the flex and clipping the style select to "styl▾".
712
+ * Fix the width field, let the style select take the rest. */
713
+ .st-cp-border .st-cp-num { flex: 0 0 58px; }
714
+ .st-cp-border .st-cp-nsel { flex: 1 1 auto; max-width: none; }
715
+
716
+ /* per-field save state */
717
+ /* #5 — error-only now (idle/saved status moved into each row's leading dot). */
718
+ .st-cp-save { display: inline-flex; align-items: center; gap: var(--space-2); align-self: flex-start; font-size: var(--type-xs); font-family: var(--font-mono); padding: 4px var(--space-2); border-radius: var(--radius-xs); background: color-mix(in oklab, var(--status-error) 14%, var(--bg-2)); border: 1px solid var(--status-error); color: var(--status-error); }
719
+ .st-cp-save.is-saved { color: var(--status-success); }
720
+ .st-cp-save.is-saved svg { color: var(--status-success); }
721
+
722
+ /* Advanced — the two-hatch escape (custom CSS property + custom HTML attribute) */
723
+ .st-cp-adv { border: 1px solid var(--border-default); border-radius: var(--radius-sm); background: var(--bg-0); overflow: hidden; }
724
+ .st-cp-advhd { width: 100%; appearance: none; cursor: pointer; display: flex; align-items: center; gap: var(--space-2); border: 0; background: transparent; color: var(--fg-2); font-family: var(--font-mono); font-size: var(--type-xs); text-transform: uppercase; letter-spacing: var(--tracking-wide); padding: var(--space-2) var(--space-3); }
725
+ .st-cp-advhd svg { color: var(--fg-2); }
726
+ .st-cp-advbody { display: flex; flex-direction: column; gap: var(--space-2); padding: 0 var(--space-3) var(--space-3); }
727
+ .st-cp-advgrp { font-family: var(--font-mono); font-size: 10px; text-transform: uppercase; letter-spacing: var(--tracking-wide); color: var(--fg-2); margin-top: var(--space-1); }
728
+ /* #3 — custom prop/attr rows are ONE line: [name] [value] [×]. The reset glyph
729
+ * used to wrap to a second line; a trailing × close button keeps it on one row. */
730
+ .st-cp-kv { display: grid; grid-template-columns: 1fr 1fr auto; gap: var(--space-2); align-items: center; }
731
+ .st-cp-kvx { flex: none; width: 18px; height: 18px; display: inline-flex; align-items: center; justify-content: center; appearance: none; cursor: pointer; background: transparent; border: 0; color: var(--fg-3); padding: 0; border-radius: var(--radius-xs); }
732
+ .st-cp-kvx:hover { color: var(--status-error); background: var(--bg-3); }
733
+ .st-cp-kvx:focus-visible { outline: none; color: var(--status-error); box-shadow: 0 0 0 2px var(--accent-tint); }
734
+ .st-cp-kv .st-cp-numin { background: var(--bg-3); border: 1px solid var(--border-default); border-radius: var(--radius-xs); }
735
+ .st-cp-kv.has-warn .st-cp-numin { border-color: var(--status-warn); }
736
+ .st-cp-warn { font-size: 10px; color: var(--status-warn); font-family: var(--font-mono); }
737
+ .st-cp-add { align-self: flex-start; appearance: none; cursor: pointer; border: 1px dashed var(--border-default); background: transparent; color: var(--fg-1); font-family: var(--font-mono); font-size: var(--type-xs); border-radius: var(--radius-xs); padding: 4px var(--space-2); }
738
+ .st-cp-add:hover { border-color: var(--accent); color: var(--fg-0); }
739
+ .st-cp-note { font-size: 10px; color: var(--fg-2); font-style: italic; }
740
+
741
+ /* provenance legend */
742
+ .st-cp-legend { display: flex; flex-wrap: wrap; gap: var(--space-3); padding-top: var(--space-1); border-top: 1px solid var(--border-subtle); }
743
+ .st-cp-legend span { display: inline-flex; align-items: center; gap: var(--space-1); font-family: var(--font-mono); font-size: 10px; color: var(--fg-2); }
744
+
745
+ /* box-model link-all-sides toggle (replaces the cryptic modifier-key chips) */
746
+ .st-cp-boxlink { display: flex; align-items: center; gap: var(--space-2); flex-wrap: wrap; }
747
+ .st-cp-linkbtn { appearance: none; cursor: pointer; display: inline-flex; align-items: center; gap: 5px; min-height: 24px; border: 1px solid var(--border-default); border-radius: var(--radius-xs); background: var(--bg-3); color: var(--fg-1); font-family: var(--font-mono); font-size: 10px; padding: 0 8px; }
748
+ .st-cp-linkbtn.is-on { border-color: var(--accent); color: var(--fg-0); background: var(--accent-tint); }
749
+ .st-cp-linkglyph { width: 13px; height: 9px; border: 1.5px solid currentColor; border-radius: 4px; }
750
+ .st-cp-linkhint { font-family: var(--font-mono); font-size: 10px; color: var(--fg-2); }
751
+
752
+ /* per-corner border-radius: split toggle + 4-corner inputs (TL/TR/BL/BR) */
753
+ .st-cp-split { flex: none; width: 24px; height: 24px; appearance: none; cursor: pointer; border: 1px solid var(--border-default); border-radius: var(--radius-xs); background: var(--bg-3); position: relative; }
754
+ .st-cp-split.is-on { border-color: var(--accent); background: var(--accent-tint); }
755
+ .st-cp-split::before { content: ""; position: absolute; inset: 6px; border: 1.5px solid var(--fg-1); border-radius: 3px; }
756
+ .st-cp-split.is-on::before { border-color: var(--accent); border-style: dashed; }
757
+ .st-cp-corners { display: grid; grid-template-columns: 1fr 1fr; gap: var(--space-1); margin: 0 0 var(--space-1) 18px; }
758
+ .st-cp-cornerf { display: flex; align-items: center; gap: 6px; min-height: 24px; background: var(--bg-3); border: 1px solid var(--border-default); border-radius: var(--radius-xs); padding: 0 8px; }
759
+ .st-cp-cornerf span { font-family: var(--font-mono); font-size: 10px; color: var(--fg-2); }
760
+ .st-cp-cornerf 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; }
761
+ .st-cp-cornerf input:focus { outline: none; }
762
+
763
+ /* Phase 12.2 PORT-only controls — the live panel uses native <select>/<input>
764
+ for real interactivity + a11y where the Studio.tsx spec used styled buttons. */
765
+ /* The port mounts an absolute `inset:0` fill span + a hidden color <input>
766
+ INSIDE the swatch (the spec's swatch was decorative-only, so the ported rule
767
+ has no `position`). Without `relative` the fill anchored to `.maude` and
768
+ painted the element's computed colour across the ENTIRE window (dark element
769
+ → black screen, light → white), and the invisible input swallowed every
770
+ click. The old `.st-css-swatch` had `position:relative` for exactly this. */
771
+ .st-cp-swatch { position: relative; overflow: hidden; }
772
+ .st-cp-caret { flex: none; color: var(--fg-2); font-size: 9px; width: 9px; text-align: center; }
773
+ .st-cp-fin { flex: 1 1 auto; min-width: 0; width: 100%; box-sizing: border-box; appearance: none; background: var(--bg-3); border: 1px solid var(--border-default); border-radius: var(--radius-xs); color: var(--fg-0); font-family: var(--font-mono); font-variant-numeric: tabular-nums; font-size: var(--type-xs); padding: 4px var(--space-2); min-height: 26px; transition: border-color var(--dur-soft) var(--ease-out), box-shadow var(--dur-soft) var(--ease-out); }
774
+ .st-cp-fin::placeholder { color: var(--fg-2); }
775
+ .st-cp-fin:hover { border-color: var(--border-strong); }
776
+ /* maude signature focus — border goes accent + a 3px tint halo (DS focus spec). */
777
+ .st-cp-fin:focus { outline: none; border-color: var(--accent); box-shadow: 0 0 0 3px var(--accent-tint); }
778
+ .st-cp-nsel { flex: 1 1 auto; min-width: 0; box-sizing: border-box; cursor: pointer; background: var(--bg-3); border: 1px solid var(--border-default); border-radius: var(--radius-xs); color: var(--fg-0); font-family: var(--font-body); font-size: var(--type-xs); padding: 3px var(--space-2); min-height: 26px; transition: border-color var(--dur-soft) var(--ease-out), box-shadow var(--dur-soft) var(--ease-out); }
779
+ .st-cp-nsel:hover { border-color: var(--border-strong); }
780
+ .st-cp-nsel:focus, .st-cp-nsel:focus-visible { outline: none; border-color: var(--accent); box-shadow: 0 0 0 3px var(--accent-tint); }
781
+ .st-cp-nsel--tok { flex: 0 1 auto; max-width: 108px; font-family: var(--font-mono); color: var(--fg-2); background: var(--bg-2); }
782
+ .st-cp-nsel--mini { flex: 0 1 auto; max-width: 92px; }
783
+ .st-cp-unitsel { flex: none; cursor: pointer; appearance: none; border: 0; border-left: 1px solid var(--border-subtle); background: var(--bg-2); color: var(--fg-2); font-family: var(--font-mono); font-size: 10px; padding: 0 4px; }
784
+ /* Phase 12.3 (W2.1) — token picker as a popover. The trigger is a compact
785
+ * variables button (◇ glyph); bound state tints it accent. */
786
+ .st-cp-tokbtn { flex: none; width: 24px; height: 26px; display: inline-flex; align-items: center; justify-content: center; cursor: pointer; appearance: none; background: var(--bg-2); border: 1px solid var(--border-default); border-radius: var(--radius-xs); color: var(--fg-2); padding: 0; }
787
+ .st-cp-tokbtn:hover { color: var(--fg-0); border-color: var(--border-strong); }
788
+ .st-cp-tokbtn:focus-visible { outline: none; border-color: var(--accent); box-shadow: 0 0 0 2px var(--accent-tint); }
789
+ .st-cp-tokbtn.is-bound { color: var(--accent); border-color: var(--accent-muted); background: var(--accent-tint); }
790
+ /* the glyph — a small rotated square (variable diamond, Figma-ish) */
791
+ .st-cp-tokbtn-glyph { width: 8px; height: 8px; border: 1.5px solid currentColor; border-radius: 1px; transform: rotate(45deg); }
792
+ .st-cp-tokbtn.is-bound .st-cp-tokbtn-glyph { background: currentColor; }
793
+ /* the floating popover (portalled to body, fixed-positioned) */
794
+ .st-cp-pop { position: fixed; z-index: 1000; overflow-y: auto; background: var(--bg-2); border: 1px solid var(--border-default); border-radius: var(--radius-md); box-shadow: var(--shadow-md); padding: var(--space-2); }
795
+ .st-cp-pop-empty { font-family: var(--font-mono); font-size: var(--type-xs); color: var(--fg-2); padding: var(--space-2); }
796
+ /* sticky search over the token list */
797
+ .st-cp-pop-search { position: sticky; top: 0; z-index: 2; display: flex; align-items: center; gap: var(--space-2); padding: 0 0 var(--space-2); margin: calc(-1 * var(--space-2)) 0 0; background: var(--bg-2); color: var(--fg-2); }
798
+ .st-cp-pop-search svg { flex: none; margin-left: var(--space-1); }
799
+ .st-cp-pop-search input { flex: 1 1 auto; min-width: 0; appearance: none; background: var(--bg-3); border: 1px solid var(--border-default); border-radius: var(--radius-xs); color: var(--fg-0); font-family: var(--font-body); font-size: var(--type-xs); padding: 4px var(--space-2); }
800
+ .st-cp-pop-search input::placeholder { color: var(--fg-3); }
801
+ .st-cp-pop-search input:focus { outline: none; border-color: var(--accent); box-shadow: 0 0 0 2px var(--accent-tint); }
802
+ /* #4 — colour popover tabs (Custom picker · Variables list) */
803
+ .st-cp-poptabs { display: flex; border-bottom: 1px solid var(--border-subtle); margin: calc(-1 * var(--space-2)) calc(-1 * var(--space-2)) var(--space-2); }
804
+ .st-cp-poptab { flex: 1; appearance: none; border: 0; background: transparent; cursor: pointer; font-family: var(--font-body); font-size: var(--type-xs); color: var(--fg-2); padding: var(--space-3); border-bottom: 2px solid transparent; }
805
+ .st-cp-poptab.is-active { color: var(--fg-0); border-bottom-color: var(--accent); }
806
+ .st-cp-poptab:hover:not(.is-active) { color: var(--fg-1); }
807
+ /* #6 — the unified HSV colour picker (Custom tab): saturation/value square +
808
+ * hue slider + eyedropper + hex field. The swatch on the colour row is the only
809
+ * trigger (no separate native picker). */
810
+ .st-cp-cpick { display: flex; flex-direction: column; gap: var(--space-2); padding: var(--space-1); }
811
+ .st-cp-swatch--trigger { position: relative; overflow: hidden; cursor: pointer; appearance: none; padding: 0; }
812
+ .st-cp-swatch--trigger.is-bound { border-color: var(--accent); box-shadow: 0 0 0 2px var(--accent-tint); }
813
+ .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; }
814
+ .st-cp-cpick-svwhite { position: absolute; inset: 0; background: linear-gradient(to right, #fff, transparent); }
815
+ .st-cp-cpick-svblack { position: absolute; inset: 0; background: linear-gradient(to top, #000, transparent); }
816
+ .st-cp-cpick-knob { position: absolute; width: 12px; height: 12px; border-radius: 50%; border: 2px solid #fff; box-shadow: 0 0 0 1px rgba(0,0,0,0.5); transform: translate(-50%, -50%); pointer-events: none; }
817
+ .st-cp-cpick-controls { display: flex; align-items: center; gap: var(--space-2); }
818
+ .st-cp-cpick-eye { flex: none; width: 26px; height: 16px; display: inline-flex; align-items: center; justify-content: center; appearance: none; cursor: pointer; background: transparent; border: 0; color: var(--fg-2); padding: 0; border-radius: var(--radius-xs); }
819
+ .st-cp-cpick-eye:hover { color: var(--fg-0); }
820
+ .st-cp-cpick-hue { position: relative; flex: 1 1 auto; height: 12px; border-radius: var(--radius-pill); border: 1px solid var(--border-default); cursor: pointer; padding: 0; touch-action: none; background: linear-gradient(to right, #f00 0%, #ff0 17%, #0f0 33%, #0ff 50%, #00f 67%, #f0f 83%, #f00 100%); }
821
+ .st-cp-cpick-huethumb { position: absolute; top: 50%; width: 12px; height: 12px; border-radius: 50%; background: #fff; border: 1px solid rgba(0,0,0,0.4); box-shadow: 0 1px 3px rgba(0,0,0,0.4); transform: translate(-50%, -50%); pointer-events: none; }
822
+ /* W3 — per-design-system grouping. The DS name labels each group when >1 DS. */
823
+ .st-cp-pop-group + .st-cp-pop-group { margin-top: var(--space-2); }
824
+ .st-cp-pop-ds { font-family: var(--font-mono); font-size: 10px; text-transform: uppercase; letter-spacing: var(--tracking-wide); color: var(--fg-2); padding: 2px var(--space-1) 4px; position: sticky; top: 30px; background: var(--bg-2); z-index: 1; }
825
+ /* color: swatch grid */
826
+ .st-cp-pop-grid { display: grid; grid-template-columns: repeat(6, 1fr); gap: 6px; }
827
+ .st-cp-pop-sw { aspect-ratio: 1; min-height: 26px; cursor: pointer; appearance: none; border: 1px solid var(--border-subtle); border-radius: var(--radius-xs); padding: 0; }
828
+ .st-cp-pop-sw:hover { border-color: var(--fg-2); transform: scale(1.06); }
829
+ .st-cp-pop-sw.is-on { border-color: var(--accent); box-shadow: 0 0 0 2px var(--accent-tint); }
830
+ .st-cp-pop-sw:focus-visible { outline: none; border-color: var(--accent); box-shadow: 0 0 0 2px var(--accent-tint); }
831
+ /* value: variable list (name + resolved value) */
832
+ .st-cp-pop-list { display: flex; flex-direction: column; gap: 1px; }
833
+ .st-cp-pop-row { display: flex; align-items: center; justify-content: space-between; gap: var(--space-2); cursor: pointer; appearance: none; background: transparent; border: 0; border-radius: var(--radius-xs); padding: 5px var(--space-2); text-align: left; }
834
+ .st-cp-pop-row:hover { background: var(--bg-3); }
835
+ .st-cp-pop-row.is-on { background: var(--accent-tint); }
836
+ .st-cp-pop-row:focus-visible { outline: none; box-shadow: 0 0 0 2px var(--accent-tint); }
837
+ .st-cp-pop-name { font-family: var(--font-mono); font-size: var(--type-xs); color: var(--fg-0); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
838
+ /* #2 — colour Variables as a list row: [swatch] [name] [value] */
839
+ .st-cp-pop-crow { justify-content: flex-start; }
840
+ .st-cp-pop-crow .st-cp-pop-name { flex: 1 1 auto; min-width: 0; }
841
+ .st-cp-pop-cswatch { flex: none; width: 16px; height: 16px; border-radius: var(--radius-xs); border: 1px solid var(--border-default); }
842
+ .st-cp-pop-val { flex: none; font-family: var(--font-mono); font-variant-numeric: tabular-nums; font-size: 10px; color: var(--fg-2); }
843
+ .st-cp-pop-row.is-on .st-cp-pop-name { color: var(--accent); }
844
+ .st-cp-fs { flex: none; width: 14px; text-align: center; font-family: var(--font-mono); font-size: 11px; }
845
+ .st-cp-fs.is-saving { color: var(--fg-3); }
846
+ .st-cp-fs.is-saved { color: var(--status-success); }
847
+ .st-cp-fs.is-err { color: var(--status-warn); cursor: help; }
848
+
849
+ /* shared focus ring for the panel's interactive controls (incl. native selects) */
850
+ .st-cp button:focus-visible, .st-cp input:focus-visible, .st-cp select:focus-visible, .st-cp-token:focus-visible, .st-cp-track:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; }
851
+ /* ═══ DS-parity polish (specimen sweep) ═══════════════════════════════════════
852
+ * Gaps found auditing the shell against `.design/system/maude/preview/*`:
853
+ * focus-visible coverage, the DS input focus ring, select chevron, unified
854
+ * thin scrollbars, tooltip bubbles. */
855
+
856
+ /* Catch-all keyboard focus — the DS focus specimen's ONE ring: 2px accent
857
+ * outline at 2px offset wrapped in a 5px --accent-tint halo (`focus.css`
858
+ * .fo-chip). :focus-visible only — mouse clicks never paint it. Inputs are
859
+ * NOT here — they take the DS input recipe (accent border + 3px tint ring). */
860
+ .maude :is(button, [role="tab"], select, summary, a):focus-visible {
861
+ outline: 2px solid var(--accent);
862
+ outline-offset: 2px;
863
+ box-shadow: 0 0 0 5px var(--accent-tint);
864
+ }
865
+ /* tight rows inside scrollers — the inset variant so the ring never clips
866
+ * (focus.css .fo-tree .tree-row recipe). */
867
+ .maude :is(.st-row, .st-dd-item, .st-pal-item, .st-layer, .st-tree-sec-hd, .st-cm-group-hd):focus-visible {
868
+ outline-offset: -2px;
869
+ box-shadow: inset 0 0 0 5px var(--accent-tint);
870
+ }
871
+
872
+ /* DS input recipe (`_components.css` .input:focus) — accent hairline + 3px tint
873
+ * ring, never the default UA outline. */
874
+ .st-search-box:focus-within {
875
+ border-color: var(--accent);
876
+ box-shadow: 0 0 0 3px var(--accent-tint);
877
+ color: var(--fg-2);
878
+ }
879
+ .st-search-box input:focus { outline: none; }
880
+ .st-newboard input:focus,
881
+ .st-newboard input:focus-visible {
882
+ outline: none;
883
+ border-color: var(--accent);
884
+ box-shadow: 0 0 0 3px var(--accent-tint);
885
+ }
886
+ .st-field:focus {
887
+ outline: none;
888
+ border-color: var(--accent);
889
+ box-shadow: 0 0 0 3px var(--accent-tint);
890
+ }
891
+ .st-select:hover { border-color: var(--border-strong); background-color: var(--bg-3); }
892
+ .st-select:focus-visible {
893
+ outline: none;
894
+ border-color: var(--accent);
895
+ box-shadow: 0 0 0 3px var(--accent-tint);
896
+ }
897
+ /* palette search — the container is the field; the inner input stays naked */
898
+ .st-pal-search input:focus { outline: none; }
899
+ .st-pal-search:focus-within { border-bottom-color: var(--accent-muted); }
900
+
901
+ /* select chevron — `appearance:none` dropped the UA arrow and left the control
902
+ * affordance-less. Data-URIs can't read tokens, so the stroke is the resolved
903
+ * --fg-1 per theme (dark ≈ #c0c4cf, light ≈ #4f5563). */
904
+ .st-select {
905
+ padding-right: 30px;
906
+ background-repeat: no-repeat;
907
+ background-position: right 10px center;
908
+ background-size: 12px;
909
+ background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='none' stroke='%23c0c4cf' stroke-width='1.4' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='3.5 6 8 10.5 12.5 6'/%3E%3C/svg%3E");
910
+ }
911
+ .maude[data-theme="light"] .st-select {
912
+ background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='none' stroke='%234f5563' stroke-width='1.4' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='3.5 6 8 10.5 12.5 6'/%3E%3C/svg%3E");
913
+ }
914
+
915
+ /* unified thin scrollbars — one material everywhere (tree, panels, palette,
916
+ * system view, modals). Hairline thumb, transparent track. */
917
+ .maude * {
918
+ scrollbar-width: thin;
919
+ scrollbar-color: var(--border-default) transparent;
920
+ }
921
+ .maude ::-webkit-scrollbar { width: 8px; height: 8px; }
922
+ .maude ::-webkit-scrollbar-track { background: transparent; }
923
+ .maude ::-webkit-scrollbar-thumb {
924
+ background: var(--border-default);
925
+ border-radius: var(--radius-pill);
926
+ border: 2px solid transparent;
927
+ background-clip: padding-box;
928
+ }
929
+ .maude ::-webkit-scrollbar-thumb:hover { background-color: var(--border-strong); }
930
+
931
+ /* tooltip bubble — DS `components-tooltips` recipe (bg-2 hairline bubble), CSS
932
+ * attr-driven so chrome controls opt in via `data-tip` without a JS layer.
933
+ * 500ms reveal delay ≈ native tooltip timing; reduced-motion shows instantly. */
934
+ .maude [data-tip] { position: relative; }
935
+ .maude [data-tip]::after {
936
+ content: attr(data-tip);
937
+ position: absolute;
938
+ top: calc(100% + 7px);
939
+ left: 50%;
940
+ transform: translateX(-50%);
941
+ z-index: 9200;
942
+ white-space: nowrap;
943
+ padding: var(--space-2) var(--space-3);
944
+ background: var(--bg-2);
945
+ color: var(--fg-0);
946
+ font-family: var(--font-body);
947
+ font-size: var(--type-xs);
948
+ font-weight: 400;
949
+ letter-spacing: normal;
950
+ text-transform: none;
951
+ line-height: 1;
952
+ border: 1px solid var(--border-default);
953
+ border-radius: var(--radius-sm);
954
+ box-shadow: var(--shadow-md);
955
+ pointer-events: none;
956
+ opacity: 0;
957
+ transition: opacity var(--dur-soft) var(--ease-out);
958
+ }
959
+ .maude [data-tip]:hover::after,
960
+ .maude [data-tip]:focus-visible::after {
961
+ opacity: 1;
962
+ transition-delay: 500ms;
963
+ }
964
+ /* bottom-bar + right-edge hosts flip/clamp so the bubble stays on screen */
965
+ .maude [data-tip][data-tip-pos="top"]::after { top: auto; bottom: calc(100% + 7px); }
966
+ .maude [data-tip][data-tip-pos="left"]::after { top: 50%; left: auto; right: calc(100% + 7px); transform: translateY(-50%); }
967
+
968
+ /* ═══ Behavioral polish (specimen sweep, round 2) ═════════════════════════════ */
969
+
970
+ /* ─── Panel grip — DS components-resize-panels recipe ──────────────────────
971
+ * 8px hit area; the panel's own border is the at-rest hairline, the grip seam
972
+ * surfaces accent + grip dots on hover/focus/drag. col-resize everywhere
973
+ * while dragging; iframes drop pointer events so they can't eat the stream. */
974
+ .st-grip {
975
+ flex: 0 0 8px;
976
+ width: 8px;
977
+ position: relative;
978
+ cursor: col-resize;
979
+ display: grid;
980
+ place-items: center;
981
+ background: transparent;
982
+ /* sit over the adjacent panel borders so the accent seam reads centered */
983
+ margin: 0 -4px;
984
+ z-index: 25;
985
+ }
986
+ .st-grip::before {
987
+ content: "";
988
+ position: absolute;
989
+ top: 0; bottom: 0; left: 50%;
990
+ width: 1px;
991
+ transform: translateX(-50%);
992
+ background: transparent;
993
+ transition: background var(--dur-flip) var(--ease-out), width var(--dur-flip) var(--ease-out);
994
+ }
995
+ .st-grip:hover::before,
996
+ .st-grip:focus-visible::before,
997
+ .st-grip.is-active::before { background: var(--accent); width: 2px; }
998
+ .st-grip-dots {
999
+ width: 6px; height: 18px;
1000
+ color: var(--accent);
1001
+ opacity: 0;
1002
+ position: relative;
1003
+ transition: opacity var(--dur-flip) var(--ease-out);
1004
+ }
1005
+ .st-grip:hover .st-grip-dots,
1006
+ .st-grip:focus-visible .st-grip-dots,
1007
+ .st-grip.is-active .st-grip-dots { opacity: 1; }
1008
+ /* specimen recipe — inset ring on the narrow hit area (the seam + dots already
1009
+ * surface accent, this keeps a proper outline for WCAG focus visibility) */
1010
+ .st-grip:focus-visible { outline: 2px solid var(--accent); outline-offset: -3px; }
1011
+ .st-body.is-resizing { cursor: col-resize; user-select: none; }
1012
+ .st-body.is-resizing iframe { pointer-events: none; }
1013
+ .st-sidebar.is-resizing, .st-rpanel.is-resizing { transition: none; }
1014
+
1015
+ /* ─── Canvas-compile skeleton — DS skeletons recipe (.skel pulse) ──────────── */
1016
+ .st-canvas-loading {
1017
+ position: absolute; inset: 0;
1018
+ display: grid; place-items: center;
1019
+ pointer-events: none;
1020
+ z-index: 5;
1021
+ /* 180ms appearance delay — warm canvases mount in <150ms and never flash it */
1022
+ opacity: 0;
1023
+ animation: st-loading-in var(--dur-soft) var(--ease-out) 180ms forwards;
1024
+ }
1025
+ @keyframes st-loading-in { to { opacity: 1; } }
1026
+ .st-skel-card {
1027
+ width: 300px;
1028
+ display: flex; flex-direction: column; gap: var(--space-3);
1029
+ padding: var(--space-5);
1030
+ background: var(--bg-1);
1031
+ border: 1px solid var(--border-default);
1032
+ border-radius: var(--radius-md);
1033
+ box-shadow: var(--shadow-md);
1034
+ animation: st-pop var(--dur-panel) var(--ease-out);
1035
+ }
1036
+ .st-skel-cap {
1037
+ font-size: var(--type-xs); letter-spacing: var(--tracking-wide);
1038
+ text-transform: uppercase; color: var(--fg-3);
1039
+ }
1040
+ .skel {
1041
+ display: block;
1042
+ background: var(--bg-3);
1043
+ border-radius: var(--radius-xs);
1044
+ animation: sk-pulse calc(var(--dur-route) * 3) var(--ease-in-out) infinite alternate;
1045
+ }
1046
+ @keyframes sk-pulse { from { opacity: 0.45; } to { opacity: 0.95; } }
1047
+ @media (prefers-reduced-motion: reduce) { .skel { animation: none; opacity: 0.7; } }
1048
+ .st-skel-thumb { height: 96px; border-radius: var(--radius-sm); }
1049
+ .st-skel-line { height: 10px; }
1050
+
1051
+ /* ─── Micro-motion — hover/disclosure transitions on the dense surfaces ───── */
1052
+ .st-row,
1053
+ .st-comment,
1054
+ .st-fmt,
1055
+ .st-cm-filter,
1056
+ .st-rp-tab,
1057
+ .st-dd-item,
1058
+ .st-pal-item,
1059
+ .st-layer,
1060
+ .st-export-recent-row {
1061
+ transition: background var(--dur-soft) var(--ease-out),
1062
+ border-color var(--dur-soft) var(--ease-out),
1063
+ color var(--dur-soft) var(--ease-out);
1064
+ }
1065
+ /* tree disclosure chevron — one glyph, rotated (animatable) */
1066
+ .st-chev { transition: transform var(--dur-flip) var(--ease-out); }
1067
+ .st-chev.is-open { transform: rotate(90deg); }
1068
+ /* right dock slides in as a panel (DS motion role: panel) */
1069
+ .st-rpanel { animation: st-panel-in var(--dur-panel) var(--ease-out); }
1070
+ @keyframes st-panel-in { from { opacity: 0; transform: translateX(10px); } to { opacity: 1; transform: none; } }
1071
+
1072
+ /* ─── Keyboard-shortcuts overlay — DS components-shortcuts-overlay recipe ──── */
1073
+ .so-overlay {
1074
+ position: relative;
1075
+ width: 100%;
1076
+ max-width: 720px;
1077
+ background: var(--bg-1);
1078
+ border: 1px solid var(--border-default);
1079
+ border-radius: var(--radius-lg);
1080
+ box-shadow: var(--shadow-lg);
1081
+ padding: var(--space-6);
1082
+ margin-top: -4vh;
1083
+ animation: so-enter var(--dur-panel) var(--ease-out) both;
1084
+ }
1085
+ @keyframes so-enter {
1086
+ 0% { opacity: 0; transform: translateY(-6px) scale(0.99); }
1087
+ 100% { opacity: 1; transform: none; }
1088
+ }
1089
+ .so-overlay-hd {
1090
+ display: flex;
1091
+ align-items: baseline;
1092
+ justify-content: space-between;
1093
+ gap: var(--space-4);
1094
+ margin: 0 0 var(--space-5);
1095
+ padding-bottom: var(--space-4);
1096
+ border-bottom: 1px solid var(--border-subtle);
1097
+ }
1098
+ .so-title {
1099
+ font-family: var(--font-display);
1100
+ font-size: var(--type-lg);
1101
+ line-height: var(--lh-lg);
1102
+ font-weight: 600;
1103
+ letter-spacing: var(--tracking-tight);
1104
+ color: var(--fg-0);
1105
+ }
1106
+ .so-trigger { font-size: var(--type-xs); color: var(--fg-2); }
1107
+ .so-columns {
1108
+ display: grid;
1109
+ grid-template-columns: repeat(2, 1fr);
1110
+ gap: var(--space-6) var(--space-7);
1111
+ }
1112
+ .so-section-hd {
1113
+ margin: 0 0 var(--space-3);
1114
+ font-family: var(--font-mono);
1115
+ font-size: var(--type-xs);
1116
+ font-weight: 500;
1117
+ letter-spacing: var(--tracking-wide);
1118
+ text-transform: uppercase;
1119
+ color: var(--fg-2);
1120
+ padding-bottom: var(--space-2);
1121
+ border-bottom: 1px solid var(--border-subtle);
1122
+ }
1123
+ /* the canvas-tools column reads as the in-canvas scope — accent-muted header */
1124
+ .so-section--tools .so-section-hd {
1125
+ color: var(--accent);
1126
+ border-bottom-color: color-mix(in oklab, var(--accent) 40%, var(--border-subtle));
1127
+ }
1128
+ .so-list { display: flex; flex-direction: column; gap: var(--space-1); margin: 0; }
1129
+ .so-pair {
1130
+ display: grid;
1131
+ grid-template-columns: 1fr auto;
1132
+ align-items: center;
1133
+ gap: var(--space-4);
1134
+ padding: var(--space-1) var(--space-1);
1135
+ border-radius: var(--radius-xs);
1136
+ }
1137
+ .so-pair:hover { background: var(--bg-2); }
1138
+ .so-pair dt { font-size: var(--type-sm); color: var(--fg-1); }
1139
+ .so-pair dd { margin: 0; justify-self: end; }
1140
+ .so-combos { display: inline-flex; align-items: center; gap: var(--space-2); }
1141
+ .so-combo { display: inline-flex; align-items: center; gap: var(--space-1); }
1142
+ .so-or { font-family: var(--font-mono); font-size: var(--type-xs); color: var(--fg-3); padding: 0 1px; }
1143
+ .so-overlay-ft {
1144
+ display: flex;
1145
+ align-items: center;
1146
+ justify-content: space-between;
1147
+ gap: var(--space-4);
1148
+ margin-top: var(--space-5);
1149
+ padding-top: var(--space-4);
1150
+ border-top: 1px solid var(--border-subtle);
1151
+ font-size: var(--type-xs);
1152
+ color: var(--fg-2);
1153
+ }
1154
+ @media (max-width: 640px) { .so-columns { grid-template-columns: 1fr; } }
1155
+
1156
+ /* ─── Agent presence pulse — DS motion-presence role (scale+opacity ring) ──── */
1157
+ .st-avatar.is-pulsing::after {
1158
+ content: "";
1159
+ position: absolute;
1160
+ inset: -1px;
1161
+ border-radius: var(--radius-pill);
1162
+ border: 1px solid var(--av-hue);
1163
+ animation: st-presence-ring 1600ms var(--ease-out) infinite;
1164
+ pointer-events: none;
1165
+ }
1166
+ .st-avatar { position: relative; }
1167
+ @keyframes st-presence-ring {
1168
+ 0% { opacity: 0.9; transform: scale(1); }
1169
+ 70%, 100% { opacity: 0; transform: scale(1.45); }
1170
+ }
1171
+ @media (prefers-reduced-motion: reduce) { .st-avatar.is-pulsing::after { animation: none; opacity: 0; } }
1172
+
1173
+ /* ── Phase 27 (E2) — GitPanel (Changes / History), mockup-faithful ────────────
1174
+ * Ported 1:1 from `.design/ui/GitPanel.css`. The DS treatments the mock LIFTS
1175
+ * (.panel/.tabbar/.tab/.textarea/.callout/.check) are folded into the gp-* names
1176
+ * so they don't collide with the existing shell classes. Every value a token. */
1177
+ .gp-panel { display: flex; flex-direction: column; min-height: 0; background: var(--bg-1); }
1178
+
1179
+ /* header: title + "N unsaved" pill + close, then the Changes/History tabbar */
1180
+ .gp-head { flex: none; }
1181
+ .gp-panel-hd { display: flex; align-items: center; gap: var(--space-2); height: 40px; padding: 0 var(--space-2) 0 var(--space-4); border-bottom: 1px solid var(--border-default); }
1182
+ .gp-panel-title { font-family: var(--font-display); font-weight: 600; font-size: var(--type-md); color: var(--fg-0); flex: none; }
1183
+ .gp-count { font-family: var(--font-mono); font-size: var(--type-xs); font-weight: 600; padding: 1px var(--space-2); border-radius: var(--radius-pill); background: var(--accent-tint); color: var(--accent); border: 1px solid var(--accent-muted); white-space: nowrap; flex: none; }
1184
+ .gp-spacer { flex: 1; min-width: var(--space-2); }
1185
+ .gp-draft { font-family: var(--font-mono); font-size: var(--type-xs); color: var(--fg-2); display: inline-flex; align-items: center; gap: var(--space-1); padding: 1px var(--space-2); border: 1px solid var(--border-default); border-radius: var(--radius-sm); background: var(--bg-2); white-space: nowrap; min-width: 0; flex: 0 1 auto; }
1186
+ .gp-draft b { color: var(--fg-0); font-weight: 600; overflow: hidden; text-overflow: ellipsis; max-width: 90px; }
1187
+ .gp-draft .gp-sep { color: var(--fg-3); }
1188
+ .gp-x { appearance: none; border: none; background: transparent; color: var(--fg-2); font-size: 16px; line-height: 1; cursor: pointer; padding: 2px 5px; border-radius: var(--radius-xs); }
1189
+ .gp-x:hover { color: var(--fg-1); background: var(--bg-3); }
1190
+ /* tabbar/tab — DS treatment folded in */
1191
+ .gp-tabs { display: flex; gap: var(--space-1); padding: var(--space-2) var(--space-3) 0; border-bottom: 1px solid var(--border-subtle); }
1192
+ .gp-tab { appearance: none; border: 0; background: transparent; font-size: var(--type-sm); color: var(--fg-2); font-family: var(--font-body); padding: var(--space-3) var(--space-4); cursor: pointer; border-bottom: 2px solid transparent; }
1193
+ .gp-tab:hover { color: var(--fg-1); }
1194
+ .gp-tab.is-active { color: var(--fg-0); border-bottom-color: var(--accent); }
1195
+
1196
+ /* the changed-file list */
1197
+ .gp-list { flex: 1; overflow-y: auto; padding: var(--space-2) 0; min-height: 0; }
1198
+ .gp-group-hd { display: flex; align-items: center; gap: var(--space-2); padding: var(--space-3) var(--space-4) var(--space-2); font-family: var(--font-mono); font-size: var(--type-xs); letter-spacing: var(--tracking-wide); text-transform: uppercase; color: var(--fg-2); }
1199
+ .gp-group-count { color: var(--fg-2); }
1200
+ .gp-file { display: flex; align-items: center; gap: var(--space-3); padding: var(--space-2) var(--space-3) var(--space-2) var(--space-4); border-radius: var(--radius-sm); margin: 0 var(--space-2); }
1201
+ .gp-file:hover { background: var(--bg-2); }
1202
+ .gp-file.is-checked { background: color-mix(in oklab, var(--accent-tint) 60%, transparent); }
1203
+ .gp-check { flex: 0 0 auto; width: 15px; height: 15px; accent-color: var(--accent); cursor: pointer; }
1204
+ .gp-file-text { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 1px; cursor: pointer; appearance: none; background: none; border: none; padding: 0; text-align: left; }
1205
+ .gp-file-name { color: var(--fg-0); font-size: var(--type-sm); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
1206
+ .gp-file-path { color: var(--fg-2); font-family: var(--font-mono); font-size: var(--type-xs); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
1207
+ .gp-file.is-checked .gp-file-path { color: var(--fg-1); }
1208
+ .gp-file-text:hover .gp-file-name { color: var(--accent); }
1209
+ .gp-discard { flex: 0 0 auto; opacity: 0; color: var(--fg-2); background: none; border: none; padding: var(--space-1); border-radius: var(--radius-xs); cursor: pointer; transition: opacity var(--dur-soft) var(--ease-out), color var(--dur-soft) var(--ease-out); }
1210
+ .gp-file:hover .gp-discard, .gp-file:focus-within .gp-discard { opacity: 1; }
1211
+ .gp-discard:hover { color: var(--status-error); background: var(--bg-3); }
1212
+ .gp-discard:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; border-radius: var(--radius-xs); opacity: 1; }
1213
+
1214
+ /* DDR-115 follow-up — canvas-grouped changes: a canvas + its collapsed
1215
+ supporting files (Layout & settings, Annotations) as one logical unit. */
1216
+ .gp-unit { display: flex; flex-direction: column; }
1217
+ .gp-unit-hd .gp-file-name { font-weight: 500; }
1218
+ .gp-disclose { flex: 0 0 auto; display: grid; place-items: center; color: var(--fg-2); background: none; border: none; padding: var(--space-1); border-radius: var(--radius-xs); cursor: pointer; transition: transform var(--dur-soft) var(--ease-out), color var(--dur-soft) var(--ease-out); }
1219
+ .gp-disclose.is-open { transform: rotate(90deg); }
1220
+ .gp-disclose:hover { color: var(--fg-0); }
1221
+ .gp-disclose:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
1222
+ .gp-support { margin: 0 var(--space-2) var(--space-1) var(--space-6); border-left: 1px solid var(--border-default); padding-left: var(--space-2); }
1223
+ .gp-support-row { display: flex; align-items: center; gap: var(--space-3); padding: var(--space-1) var(--space-2); min-width: 0; }
1224
+ .gp-support-text { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 1px; }
1225
+ .gp-support-row .gp-file-name { color: var(--fg-1); font-size: var(--type-sm); }
1226
+
1227
+ /* M / A / D / U dirty badge — solid for M/A/D, dashed outline for U (untracked) */
1228
+ .gp-badge { flex: 0 0 auto; width: 16px; height: 16px; border-radius: var(--radius-xs); display: grid; place-items: center; font-family: var(--font-mono); font-size: 10px; font-weight: 600; line-height: 1; color: oklch(0.11 0.012 260); }
1229
+ .gp-badge[data-kind="M"] { background: var(--status-warn); }
1230
+ .gp-badge[data-kind="A"] { background: var(--status-success); }
1231
+ .gp-badge[data-kind="D"] { background: var(--status-error); }
1232
+ .gp-badge[data-kind="U"] { background: transparent; border: 1px dashed var(--border-strong); color: var(--fg-2); }
1233
+
1234
+ /* composer footer: select-all · message · Save version / Save all · hint */
1235
+ .gp-compose { flex: none; border-top: 1px solid var(--border-default); padding: var(--space-3) var(--space-4) var(--space-4); display: flex; flex-direction: column; gap: var(--space-3); background: var(--bg-1); }
1236
+ .gp-selectall { display: inline-flex; align-items: center; gap: var(--space-2); align-self: flex-start; appearance: none; background: none; border: none; padding: 0; font-family: var(--font-body); font-size: var(--type-sm); color: var(--fg-1); cursor: pointer; }
1237
+ .gp-msg { font-family: var(--font-body); font-size: var(--type-sm); color: var(--fg-0); background: var(--bg-3); border: 1px solid var(--border-default); border-radius: var(--radius-sm); padding: var(--space-3) var(--space-4); width: 100%; resize: none; min-height: 64px; transition: border-color var(--dur-soft) var(--ease-out), box-shadow var(--dur-soft) var(--ease-out); }
1238
+ .gp-msg::placeholder { color: var(--fg-2); }
1239
+ .gp-msg:focus { outline: none; border-color: var(--accent); box-shadow: 0 0 0 3px var(--accent-tint); }
1240
+ .gp-compose-actions { display: flex; align-items: center; gap: var(--space-3); }
1241
+ .gp-save { flex: 1; justify-content: center; }
1242
+ .gp-save:disabled, .gp-save[aria-disabled="true"], .gp-publish:disabled, .gp-publish[aria-disabled="true"] { background: var(--bg-3); color: var(--fg-3); border-color: var(--border-default); cursor: not-allowed; }
1243
+ .gp-hint { font-size: var(--type-xs); color: var(--fg-2); }
1244
+
1245
+ /* publish / get-latest bar */
1246
+ .gp-publishbar { flex: none; border-top: 1px solid var(--border-default); padding: var(--space-4); display: flex; flex-direction: column; gap: var(--space-4); background: var(--bg-1); }
1247
+ .gp-publish { width: 100%; justify-content: center; }
1248
+ .gp-nudge { display: flex; align-items: center; gap: var(--space-3); padding: var(--space-3); border-radius: var(--radius-sm); }
1249
+ .gp-nudge-text { flex: 1; font-size: var(--type-sm); }
1250
+ .gp-nudge-text b { color: var(--fg-0); font-weight: 600; }
1251
+ .gp-nudge-text span { color: var(--fg-1); }
1252
+ .gp-dot-pulse { width: 7px; height: 7px; border-radius: var(--radius-pill); background: var(--status-info); flex: 0 0 auto; box-shadow: 0 0 0 0 color-mix(in oklab, var(--status-info) 60%, transparent); animation: gp-pulse 2.4s var(--ease-out) infinite; }
1253
+ @keyframes gp-pulse { 0% { box-shadow: 0 0 0 0 color-mix(in oklab, var(--status-info) 55%, transparent); } 70% { box-shadow: 0 0 0 7px transparent; } 100% { box-shadow: 0 0 0 0 transparent; } }
1254
+ @media (prefers-reduced-motion: reduce) { .gp-dot-pulse { animation: none; } }
1255
+
1256
+ /* callout (banner / conflict) — uses the client .callout, gp- adds layout */
1257
+ .gp-callout-col { display: flex; flex-direction: column; gap: var(--space-2); flex: 1; }
1258
+ .gp-callout-actions { display: flex; gap: var(--space-3); margin-top: var(--space-2); }
1259
+ .gp-pad { padding: var(--space-4) var(--space-4) 0; }
1260
+ .gp-sect-label { font-family: var(--font-mono); font-size: var(--type-xs); letter-spacing: var(--tracking-wide); text-transform: uppercase; color: var(--fg-2); padding: var(--space-4) var(--space-4) var(--space-2); }
1261
+
1262
+ /* History timeline with rail */
1263
+ .gp-history { padding: var(--space-2) var(--space-3); display: flex; flex-direction: column; gap: 0; overflow-y: auto; min-height: 0; }
1264
+ .gp-version { display: grid; grid-template-columns: 18px 1fr auto; gap: var(--space-3); padding: var(--space-3) var(--space-2); align-items: start; position: relative; }
1265
+ .gp-version-rail { display: grid; place-items: center; position: relative; }
1266
+ .gp-version-node { width: 8px; height: 8px; border-radius: var(--radius-pill); background: var(--accent); margin-top: 4px; z-index: 1; }
1267
+ .gp-version:not(:last-child) .gp-version-rail::after { content: ""; position: absolute; top: 12px; bottom: -12px; width: 1px; background: var(--border-default); }
1268
+ .gp-version-body { display: flex; flex-direction: column; min-width: 0; }
1269
+ .gp-version-msg { color: var(--fg-0); font-size: var(--type-sm); overflow: hidden; text-overflow: ellipsis; }
1270
+ .gp-version-meta { color: var(--fg-2); font-family: var(--font-mono); font-size: var(--type-xs); margin-top: 2px; }
1271
+ .gp-version-when { color: var(--fg-2); font-family: var(--font-mono); font-size: var(--type-xs); white-space: nowrap; transition: opacity var(--dur-soft) ease; }
1272
+
1273
+ /* phase-27.1 — per-file History rows are click-to-preview when a canvas is open */
1274
+ .gp-history-scope { color: var(--fg-1); font-size: var(--type-xs); padding: var(--space-1) var(--space-2) var(--space-2); margin: 0; }
1275
+ .gp-history-scope b { color: var(--fg-0); }
1276
+ .gp-history-hint { color: var(--fg-2); font-size: var(--type-xs); text-align: center; padding: var(--space-3) var(--space-2); margin: 0; }
1277
+ .gp-version--clickable { width: 100%; text-align: left; font: inherit; color: inherit; background: none; border: 0; border-radius: var(--radius-sm); cursor: pointer; appearance: none; transition: background var(--dur-soft) ease; }
1278
+ .gp-version--clickable:hover { background: var(--bg-2); }
1279
+ .gp-version--clickable:focus-visible { outline: 2px solid var(--accent); outline-offset: -2px; }
1280
+ .gp-version-cue { position: absolute; top: var(--space-2); right: var(--space-2); display: inline-flex; align-items: center; gap: 4px; padding: 2px 7px; border-radius: var(--radius-pill); background: var(--accent-tint); color: var(--accent); font-size: var(--type-xs); font-weight: 600; opacity: 0; pointer-events: none; transition: opacity var(--dur-soft) ease; }
1281
+ .gp-version--clickable:hover .gp-version-cue,
1282
+ .gp-version--clickable:focus-visible .gp-version-cue { opacity: 1; }
1283
+ .gp-version--clickable:hover .gp-version-when,
1284
+ .gp-version--clickable:focus-visible .gp-version-when { opacity: 0; }
1285
+
1286
+ /* empty state — "Nothing to save" */
1287
+ .gp-empty { flex: 1; display: flex; flex-direction: column; align-items: center; justify-content: center; gap: var(--space-4); padding: var(--space-8) var(--space-6); text-align: center; }
1288
+ .gp-empty-glyph { width: 52px; height: 52px; border-radius: var(--radius-pill); display: grid; place-items: center; background: color-mix(in oklab, var(--status-success) 16%, transparent); color: var(--status-success); }
1289
+ .gp-empty-glyph--publish { background: var(--accent-tint); color: var(--accent); }
1290
+ .gp-empty h3 { font-family: var(--font-display); font-size: var(--type-lg); color: var(--fg-0); margin: 0; font-weight: 600; }
1291
+ .gp-empty p { color: var(--fg-1); font-size: var(--type-sm); max-width: 30ch; margin: 0; }
1292
+
1293
+ /* tree dirty badge — mirrors the activity-overlay badge style (DDR-075) */
1294
+ .st-git-badge { display: inline-flex; align-items: center; justify-content: center; width: 15px; height: 15px; margin-left: auto; border-radius: var(--radius-xs); font-family: var(--font-mono); font-size: 9px; font-weight: 700; line-height: 1; color: oklch(0.11 0.012 260); flex: none; }
1295
+ .st-git-badge[data-kind="M"] { background: var(--status-warn); }
1296
+ .st-git-badge[data-kind="A"] { background: var(--status-success); }
1297
+ .st-git-badge[data-kind="D"] { background: var(--status-error); }
1298
+ .st-git-badge[data-kind="U"] { background: transparent; border: 1px dashed var(--border-strong); color: var(--fg-2); }
1299
+
1300
+ /* ── Phase 27 (E2) — DiffView: clean rendered before/after, SYNCED zoom/pan ────
1301
+ * Ported from `.design/ui/DiffView.css`. Each pane renders a CLEAN canvas
1302
+ * (hide-chrome: no toolbar/minimap/devtools) inside a zoom/pan viewport. Both
1303
+ * panes share ONE view transform (locked): scroll to zoom, drag to pan, both
1304
+ * track the same region. Header reuses the app brand (.st-brand). */
1305
+ /* The shared .st-scrim top-anchors short dialogs (place-items:start center + 12vh
1306
+ * pad). The DiffView sheet is tall (92vh), so top-anchoring overflows the bottom
1307
+ * (12vh + 92vh > 100vh — the footer got cut off). Center it instead. */
1308
+ .dv-scrim { place-items: center; padding-top: 0; }
1309
+ .dv-sheet { width: min(1280px, 96vw); height: min(900px, 92vh); display: flex; flex-direction: column; background: var(--bg-1); border: 1px solid var(--border-default); border-radius: var(--radius-lg); box-shadow: var(--shadow-lg); overflow: hidden; }
1310
+ .dv-hd { display: flex; align-items: center; gap: var(--space-3); padding: var(--space-4) var(--space-5); border-bottom: 1px solid var(--border-default); flex: none; }
1311
+ .dv-hd .st-brand { padding-right: var(--space-3); border-right: 1px solid var(--border-default); }
1312
+ .dv-title { font-family: var(--font-display); font-weight: 600; font-size: var(--type-lg); color: var(--fg-0); }
1313
+ .dv-file { display: inline-flex; align-items: center; gap: var(--space-2); padding: var(--space-1) var(--space-3); border: 1px solid var(--border-default); border-radius: var(--radius-sm); background: var(--bg-2); font-family: var(--font-mono); font-size: var(--type-sm); color: var(--fg-1); }
1314
+ .dv-spacer { flex: 1; }
1315
+ .dv-close { appearance: none; border: none; background: transparent; color: var(--fg-2); cursor: pointer; padding: var(--space-2); border-radius: var(--radius-xs); display: grid; place-items: center; }
1316
+ .dv-close:hover { color: var(--fg-0); background: var(--bg-3); }
1317
+ /* segmented mode toggle (DS .seg) */
1318
+ .dv-seg { display: inline-flex; border: 1px solid var(--border-default); border-radius: var(--radius-sm); overflow: hidden; background: var(--bg-2); }
1319
+ .dv-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-4); cursor: pointer; }
1320
+ .dv-seg-btn[aria-pressed="true"] { background: var(--bg-4); color: var(--fg-0); }
1321
+ .dv-seg-btn + .dv-seg-btn { border-left: 1px solid var(--border-subtle); }
1322
+
1323
+ /* phase-27.1 — "Saved version" picker: pick which past version the before pane shows */
1324
+ .dv-verpick { display: inline-flex; align-items: center; gap: var(--space-2); }
1325
+ .dv-verpick-lbl { color: var(--fg-2); font-size: var(--type-xs); }
1326
+ .dv-verpick-sel { appearance: none; border: 1px solid var(--border-default); border-radius: var(--radius-sm); background: var(--bg-2); color: var(--fg-0); font-size: var(--type-xs); font-family: var(--font-mono); padding: var(--space-2) var(--space-5) var(--space-2) var(--space-3); max-width: 22ch; cursor: pointer; background-image: linear-gradient(45deg, transparent 50%, var(--fg-2) 50%), linear-gradient(135deg, var(--fg-2) 50%, transparent 50%); background-position: right 12px center, right 7px center; background-size: 5px 5px, 5px 5px; background-repeat: no-repeat; }
1327
+ .dv-verpick-sel:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; border-color: var(--accent); }
1328
+
1329
+ .dv-stage { padding: var(--space-4) var(--space-5) var(--space-5); display: flex; flex-direction: column; gap: var(--space-3); flex: 1; min-height: 0; }
1330
+ .dv-pair { display: grid; grid-template-columns: 1fr 1fr; gap: var(--space-4); align-items: stretch; flex: 1; min-height: 0; }
1331
+ .dv-col { display: flex; flex-direction: column; gap: var(--space-2); min-width: 0; min-height: 0; }
1332
+ .dv-col-hd { display: flex; align-items: center; gap: var(--space-2); flex: none; }
1333
+ .dv-col-tag { font-family: var(--font-mono); font-size: var(--type-xs); letter-spacing: var(--tracking-wide); text-transform: uppercase; color: var(--fg-2); display: inline-flex; align-items: center; gap: var(--space-1); }
1334
+ .dv-col-tag.is-after { color: var(--accent); }
1335
+ .dv-col-who { color: var(--fg-2); font-size: var(--type-xs); margin-left: auto; }
1336
+
1337
+ /* the rendered-canvas thumbnail = a zoom/pan viewport over a clean iframe */
1338
+ .dv-thumb { position: relative; flex: 1; min-height: 0; background: var(--bg-0); border: 1px solid var(--border-default); border-radius: var(--radius-md); overflow: hidden; }
1339
+ .dv-thumb.is-after { border-color: var(--accent-muted); }
1340
+ .dv-thumb.ring-mine { box-shadow: 0 0 0 2px var(--accent); border-color: var(--accent); }
1341
+ .dv-thumb.ring-theirs { box-shadow: 0 0 0 2px var(--status-info); border-color: var(--status-info); }
1342
+ .dv-viewport { position: absolute; inset: 0; overflow: hidden; cursor: grab; touch-action: none; }
1343
+ .dv-viewport.is-panning { cursor: grabbing; }
1344
+ .dv-frame-wrap { position: absolute; top: 0; left: 0; width: 100%; height: 100%; transform-origin: 0 0; will-change: transform; }
1345
+ .dv-frame { position: absolute; inset: 0; width: 100%; height: 100%; border: 0; background: var(--bg-0); display: block; pointer-events: none; }
1346
+ .dv-thumb-note { position: absolute; inset: 0; display: grid; place-items: center; padding: var(--space-4); text-align: center; font-size: var(--type-xs); color: var(--fg-3); background: repeating-linear-gradient(45deg, var(--bg-1), var(--bg-1) 8px, var(--bg-2) 8px, var(--bg-2) 16px); }
1347
+
1348
+ /* shared zoom toolbar — drives the locked view for both panes */
1349
+ .dv-zoombar { display: inline-flex; align-items: center; gap: var(--space-1); align-self: center; background: var(--bg-2); border: 1px solid var(--border-default); border-radius: var(--radius-pill); padding: 2px; flex: none; }
1350
+ .dv-zoom-btn { appearance: none; border: none; background: transparent; color: var(--fg-1); cursor: pointer; width: 26px; height: 22px; border-radius: var(--radius-pill); font-size: var(--type-sm); line-height: 1; display: grid; place-items: center; }
1351
+ .dv-zoom-btn:hover { background: var(--bg-3); color: var(--fg-0); }
1352
+ .dv-zoom-val { font-family: var(--font-mono); font-size: var(--type-xs); color: var(--fg-2); min-width: 44px; text-align: center; cursor: pointer; appearance: none; border: none; background: transparent; }
1353
+ .dv-zoom-val:hover { color: var(--fg-0); }
1354
+ .dv-zoom-sync { font-family: var(--font-mono); font-size: var(--type-xs); color: var(--fg-3); padding-left: var(--space-2); border-left: 1px solid var(--border-subtle); margin-left: var(--space-1); }
1355
+
1356
+ /* overlay / slider compare (shares the locked view; frozen layers for the wipe) */
1357
+ .dv-overlay { --dv-split: 52%; position: relative; flex: 1; min-height: 0; margin: 0 auto; width: 100%; max-width: 900px; background: var(--bg-0); border: 1px solid var(--border-default); border-radius: var(--radius-md); overflow: hidden; }
1358
+ .dv-overlay-layer { position: absolute; inset: 0; }
1359
+ .dv-overlay-after { position: absolute; inset: 0; clip-path: inset(0 0 0 var(--dv-split)); }
1360
+ .dv-split { position: absolute; top: 0; bottom: 0; left: var(--dv-split); width: 2px; background: var(--accent); z-index: 3; }
1361
+ .dv-split-handle { position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); width: 26px; height: 26px; border-radius: var(--radius-pill); background: var(--accent); color: var(--accent-fg); display: grid; place-items: center; box-shadow: var(--shadow-md); cursor: ew-resize; }
1362
+ .dv-split-handle:focus-visible { outline: 2px solid var(--fg-0); outline-offset: 2px; }
1363
+ .dv-overlay-tag { position: absolute; bottom: var(--space-3); font-family: var(--font-mono); font-size: var(--type-xs); padding: 2px var(--space-3); border-radius: var(--radius-sm); background: color-mix(in oklab, var(--bg-0) 70%, transparent); color: var(--fg-1); z-index: 4; }
1364
+ .dv-overlay-tag.l { left: var(--space-3); }
1365
+ .dv-overlay-tag.r { right: var(--space-3); color: var(--accent); }
1366
+
1367
+ /* conflict picker */
1368
+ .dv-pick-intro { padding: var(--space-4) var(--space-6) 0; flex: none; }
1369
+ .dv-picker { display: grid; grid-template-columns: repeat(3, 1fr); gap: var(--space-4); padding: var(--space-4) var(--space-6) var(--space-2); flex: none; }
1370
+ .dv-pick { text-align: left; appearance: none; cursor: pointer; background: var(--bg-2); border: 1px solid var(--border-default); border-radius: var(--radius-md); padding: var(--space-4); display: flex; flex-direction: column; gap: var(--space-2); color: var(--fg-1); }
1371
+ .dv-pick:hover { border-color: var(--border-strong); background: var(--bg-3); }
1372
+ .dv-pick.is-rec { border-color: var(--accent); box-shadow: 0 0 0 1px var(--accent); background: var(--accent-tint); }
1373
+ .dv-pick:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
1374
+ .dv-pick.is-rec .dv-pick-desc { color: var(--fg-1); }
1375
+ .dv-pick-hd { display: flex; align-items: center; gap: var(--space-2); }
1376
+ .dv-pick-title { font-weight: 600; color: var(--fg-0); font-size: var(--type-sm); }
1377
+ .dv-pick-rec { margin-left: auto; font-family: var(--font-mono); font-size: var(--type-xs); letter-spacing: var(--tracking-wide); text-transform: uppercase; color: var(--accent-fg); background: var(--accent); border-radius: var(--radius-pill); padding: 1px var(--space-2); }
1378
+ .dv-pick-desc { font-size: var(--type-xs); color: var(--fg-2); line-height: var(--lh-xs); }
1379
+
1380
+ /* footer */
1381
+ .dv-ft { display: flex; align-items: center; gap: var(--space-3); padding: var(--space-4) var(--space-6); border-top: 1px solid var(--border-default); flex: none; }
1382
+ .dv-note { color: var(--fg-2); font-size: var(--type-xs); flex: 1; }
1383
+
1384
+ /* ── Phase 28 (E3) — GitHub identity rail + create/pull/share dialogs.
1385
+ * All chrome is the SHELL maude DS: solid surfaces (var(--bg-1)/2) and the
1386
+ * .st-dialog scrim+card treatment — NEVER the canvas-side `.panel` (it isn't in
1387
+ * the client bundle, which made the cards transparent). The identity rail docks
1388
+ * at the BOTTOM of the sidebar as a compact avatar; the menu opens upward. */
1389
+
1390
+ /* text inputs — the maude DS .input/.textarea recipe (lifted from the canvas-side
1391
+ * _components.css, which isn't in the client bundle → my fields fell back to native).
1392
+ * Scoped to the github dialogs so it can't collide with the shell's .st-search/.st-field. */
1393
+ .gi-dialog .input, .cp-dialog .input, .gi-dialog .textarea, .cp-dialog .textarea {
1394
+ font-family: var(--font-body); font-size: var(--type-sm); color: var(--fg-0);
1395
+ background: var(--bg-3); border: 1px solid var(--border-default); border-radius: var(--radius-sm);
1396
+ padding: var(--space-3) var(--space-4); width: 100%;
1397
+ transition: border-color var(--dur-soft) var(--ease-out), box-shadow var(--dur-soft) var(--ease-out);
1398
+ }
1399
+ .gi-dialog .input::placeholder, .cp-dialog .input::placeholder,
1400
+ .gi-dialog .textarea::placeholder, .cp-dialog .textarea::placeholder { color: var(--fg-3); }
1401
+ .gi-dialog .input:focus, .cp-dialog .input:focus, .gi-dialog .textarea:focus, .cp-dialog .textarea:focus {
1402
+ outline: none; border-color: var(--accent); box-shadow: 0 0 0 3px var(--accent-tint);
1403
+ }
1404
+ .cp-dialog .textarea { resize: vertical; min-height: 76px; }
1405
+
1406
+ /* identity rail — sidebar footer */
1407
+ .gi-rail { position: relative; flex: 0 0 auto; margin-top: auto; padding: var(--space-2) var(--space-3); border-top: 1px solid var(--border-default); display: flex; flex-direction: column; gap: var(--space-2); }
1408
+ .gi-rail-hint { font-size: var(--type-xs); color: var(--fg-2); padding: var(--space-1) var(--space-1); }
1409
+ .gi-rail-signin { width: 100%; justify-content: center; }
1410
+ .gi-rail-err { font-size: var(--type-xs); color: var(--status-error); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
1411
+ .gi-avatar { border-radius: var(--radius-pill); display: grid; place-items: center; font-family: var(--font-mono); font-size: 10px; font-weight: 600; color: var(--accent-fg); background: var(--accent); flex: 0 0 auto; }
1412
+ .gi-rail-account { display: flex; align-items: center; gap: var(--space-2); width: 100%; padding: var(--space-1) var(--space-2); border: 1px solid transparent; border-radius: var(--radius-md); background: transparent; color: var(--fg-0); cursor: pointer; text-align: left; }
1413
+ .gi-rail-account:hover { background: var(--bg-2); }
1414
+ .gi-rail-account.is-open { background: var(--bg-2); border-color: var(--border-default); }
1415
+ .gi-rail-account:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
1416
+ .gi-rail-login { flex: 1; min-width: 0; font-family: var(--font-mono); font-size: var(--type-sm); color: var(--fg-1); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
1417
+ .gi-rail-caret { color: var(--fg-2); flex: 0 0 auto; display: inline-flex; }
1418
+
1419
+ /* account menu — opens UPWARD, solid surface */
1420
+ .gi-menu { position: absolute; bottom: calc(100% + var(--space-1)); left: var(--space-3); right: var(--space-3); z-index: 9500; background: var(--bg-1); border: 1px solid var(--border-default); border-radius: var(--radius-lg); box-shadow: var(--shadow-lg); padding: var(--space-2); }
1421
+ .gi-menu-hd { display: flex; align-items: center; gap: var(--space-3); padding: var(--space-2) var(--space-2) var(--space-3); border-bottom: 1px solid var(--border-subtle); margin-bottom: var(--space-1); }
1422
+ .gi-menu-id { display: flex; flex-direction: column; min-width: 0; }
1423
+ .gi-menu-name { font-weight: 600; color: var(--fg-0); font-size: var(--type-sm); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
1424
+ .gi-menu-login { font-family: var(--font-mono); font-size: var(--type-xs); color: var(--fg-2); }
1425
+ .gi-menu-item { display: flex; align-items: center; gap: var(--space-3); width: 100%; padding: var(--space-2) var(--space-3); border: 0; border-radius: var(--radius-sm); background: transparent; color: var(--fg-1); font-size: var(--type-sm); cursor: pointer; text-align: left; }
1426
+ .gi-menu-item svg { color: var(--fg-2); }
1427
+ .gi-menu-item:hover { background: var(--bg-2); color: var(--fg-0); }
1428
+ .gi-menu-item:hover svg { color: var(--fg-1); }
1429
+ .gi-menu-item:focus-visible { outline: 2px solid var(--accent); outline-offset: -2px; }
1430
+ .gi-menu-item--danger, .gi-menu-item--danger svg { color: var(--status-error); }
1431
+ .gi-menu-item--danger:hover { background: color-mix(in oklab, var(--status-error) 14%, transparent); color: var(--status-error); }
1432
+ .gi-menu-sep { height: 1px; background: var(--border-subtle); margin: var(--space-1) 0; }
1433
+
1434
+ /* shared dialog shell (device-code + create/pull/share) — lifts .st-scrim/.st-dialog */
1435
+ .gi-modal, .cp-modal { position: fixed; inset: 0; display: grid; place-items: center; z-index: 9600; padding: var(--space-6); }
1436
+ .gi-scrim, .cp-scrim { position: fixed; inset: 0; background: color-mix(in oklab, var(--bg-0) 72%, transparent); }
1437
+ .gi-dialog, .cp-dialog { position: relative; background: var(--bg-1); border: 1px solid var(--border-default); border-radius: var(--radius-lg); box-shadow: var(--shadow-lg); display: flex; flex-direction: column; overflow: hidden; animation: st-pop var(--dur-route) var(--ease-out); }
1438
+
1439
+ /* device-code dialog */
1440
+ .gi-dialog--code { width: min(460px, 92vw); padding: var(--space-6); gap: var(--space-5); }
1441
+ .gi-dc-head { display: flex; flex-direction: column; align-items: center; text-align: center; gap: var(--space-3); }
1442
+ .gi-dc-head h2 { margin: 0; font-family: var(--font-display); font-size: var(--type-lg); font-weight: 600; color: var(--fg-0); }
1443
+ .gi-dc-marks { display: grid; place-items: center; width: 52px; height: 52px; border-radius: var(--radius-lg); background: var(--bg-2); border: 1px solid var(--border-default); color: var(--fg-0); }
1444
+ .gi-dc-head p { margin: 0; color: var(--fg-2); font-size: var(--type-sm); line-height: var(--lh-base); max-width: 38ch; }
1445
+ .gi-dc-steps { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: var(--space-3); }
1446
+ .gi-dc-steps li { display: flex; align-items: flex-start; gap: var(--space-3); }
1447
+ .gi-dc-step-n { flex: 0 0 auto; width: 22px; height: 22px; display: grid; place-items: center; border-radius: var(--radius-pill); background: var(--accent-tint); border: 1px solid var(--accent-muted); color: var(--accent); font-family: var(--font-mono); font-size: var(--type-xs); font-weight: 600; }
1448
+ .gi-dc-step-tx { font-size: var(--type-sm); color: var(--fg-1); line-height: var(--lh-base); display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-2); }
1449
+ .gi-dc-url { font-family: var(--font-mono); color: var(--fg-0); background: var(--bg-2); border: 1px solid var(--border-subtle); border-radius: var(--radius-xs); padding: 1px var(--space-2); }
1450
+ .gi-code { display: flex; align-items: center; justify-content: space-between; gap: var(--space-3); padding: var(--space-4) var(--space-5); border: 1px solid var(--border-strong); border-radius: var(--radius-md); background: var(--bg-2); }
1451
+ .gi-code-val { font-family: var(--font-mono); font-size: var(--type-2xl); font-weight: 600; letter-spacing: 0.16em; color: var(--fg-0); }
1452
+ .gi-code-copy { flex: 0 0 auto; }
1453
+ .gi-dc-status { display: flex; align-items: center; gap: var(--space-3); font-size: var(--type-sm); color: var(--fg-2); }
1454
+ .gi-pulse { width: 9px; height: 9px; flex: 0 0 auto; border-radius: var(--radius-pill); background: var(--status-info); animation: gi-pulse 1.8s var(--ease-out) infinite; }
1455
+ @keyframes gi-pulse { 0% { box-shadow: 0 0 0 0 color-mix(in oklch, var(--status-info) 55%, transparent); } 70% { box-shadow: 0 0 0 7px transparent; } 100% { box-shadow: 0 0 0 0 transparent; } }
1456
+ .gi-dc-foot { display: flex; align-items: center; gap: var(--space-3); }
1457
+ .gi-dc-foot-note { font-size: var(--type-xs); color: var(--fg-2); line-height: var(--lh-sm); }
1458
+
1459
+ /* create / pull / share dialog */
1460
+ .cp-dialog { width: min(560px, 94vw); max-height: 88vh; }
1461
+ .cp-dialog-hd { display: flex; align-items: flex-start; gap: var(--space-3); padding: var(--space-5) var(--space-5) var(--space-4); border-bottom: 1px solid var(--border-subtle); flex: none; }
1462
+ .cp-dialog-titles { flex: 1; min-width: 0; }
1463
+ .cp-dialog-hd h2 { margin: 0; font-family: var(--font-display); font-size: var(--type-lg); font-weight: 600; color: var(--fg-0); }
1464
+ .cp-dialog-hd p { margin: var(--space-1) 0 0; font-size: var(--type-sm); color: var(--fg-2); line-height: var(--lh-base); }
1465
+ .cp-body { padding: var(--space-5); display: flex; flex-direction: column; gap: var(--space-5); overflow: auto; }
1466
+ .cp-body--list { gap: var(--space-3); }
1467
+ .cp-ft { display: flex; align-items: center; gap: var(--space-3); padding: var(--space-4) var(--space-5); border-top: 1px solid var(--border-subtle); background: var(--bg-1); flex: none; }
1468
+ .cp-spacer { flex: 1; }
1469
+ .cp-cl-glyph { flex: 0 0 auto; display: inline-flex; }
1470
+ .cp-field { display: flex; flex-direction: column; gap: var(--space-2); }
1471
+ .cp-field-label { font-size: var(--type-sm); font-weight: 600; color: var(--fg-0); display: flex; align-items: center; gap: var(--space-2); }
1472
+ .cp-optional { font-weight: 400; font-size: var(--type-xs); color: var(--fg-2); text-transform: lowercase; }
1473
+ .cp-field-help { font-size: var(--type-xs); color: var(--fg-2); line-height: var(--lh-base); }
1474
+ .cp-field-help b { color: var(--fg-1); font-family: var(--font-mono); font-weight: 500; }
1475
+ .cp-input, .cp-textarea { width: 100%; }
1476
+ .cp-textarea { resize: none; }
1477
+ .cp-seg { width: 100%; }
1478
+ .cp-seg button { flex: 1; justify-content: center; gap: var(--space-2); }
1479
+ .cp-seg button:focus-visible { outline: 2px solid var(--accent); outline-offset: -2px; }
1480
+ .cp-invite { display: flex; align-items: center; gap: var(--space-2); position: relative; }
1481
+ .cp-invite-at { position: absolute; left: var(--space-3); font-family: var(--font-mono); color: var(--fg-2); pointer-events: none; }
1482
+ .cp-dialog .cp-invite-input { flex: 1; padding-left: calc(var(--space-3) + 0.9em); font-family: var(--font-mono); }
1483
+ .cp-invite-btn { flex: 0 0 auto; }
1484
+ .cp-repolist { display: flex; flex-direction: column; gap: var(--space-1); max-height: 360px; overflow: auto; }
1485
+ .cp-repo { display: flex; align-items: center; gap: var(--space-3); width: 100%; padding: var(--space-3); border: 1px solid var(--border-subtle); border-radius: var(--radius-md); background: var(--bg-2); color: var(--fg-0); cursor: pointer; text-align: left; }
1486
+ .cp-repo:hover:not(:disabled) { border-color: var(--accent); background: var(--bg-3); }
1487
+ .cp-repo:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
1488
+ .cp-repo:disabled { cursor: default; opacity: 0.6; }
1489
+ .cp-repo.is-busy { opacity: 1; border-color: var(--accent); }
1490
+ .cp-repo > svg:first-child { color: var(--fg-2); flex: 0 0 auto; }
1491
+ .cp-repo-tx { flex: 1; min-width: 0; display: flex; flex-direction: column; }
1492
+ .cp-repo-name { font-weight: 600; font-size: var(--type-sm); color: var(--fg-0); }
1493
+ .cp-repo-meta { font-family: var(--font-mono); font-size: var(--type-xs); color: var(--fg-2); }
1494
+ .cp-repo-go { color: var(--fg-3); flex: 0 0 auto; display: inline-flex; }
1495
+ .cp-repo:hover:not(:disabled) .cp-repo-go { color: var(--accent); }
1496
+ .cp-repo.is-busy .cp-repo-go { color: var(--accent); }
1497
+ .cp-spin { animation: cp-spin 0.9s linear infinite; transform-origin: center; }
1498
+ @keyframes cp-spin { to { transform: rotate(360deg); } }
1499
+
1500
+ @media (prefers-reduced-motion: reduce) { .gi-pulse, .cp-spin { animation: none; } .gi-dialog, .cp-dialog { animation: none; } }
1501
+
1502
+ /* ─── Presentation Mode ────────────────────────────────────────────────────
1503
+ View ▸ Presentation Mode — a non-destructive "artboards only" overlay. Hides
1504
+ every piece of shell chrome while leaving the canvas viewport (.main) mounted
1505
+ so its pan/zoom + open tabs survive an exit. The two structural rules below
1506
+ hide (a) the menubar + status bar — the .st-shell children that aren't the
1507
+ body — and (b) the sidebar / collapsed rail / resize grips / side panels —
1508
+ the .st-body children that aren't the viewport. The canvas iframe hides its
1509
+ OWN floating chrome (minimap, zoom pill, tool palette, annotations, comment
1510
+ pins) via the dgn:'view-chrome' bridge. Escape hatch: Esc or the pill. */
1511
+ .maude.is-present .st-shell > :not(.st-body) { display: none !important; }
1512
+ .maude.is-present .st-body > :not(.main) { display: none !important; }
1513
+ /* Top-level banners (.st-banner — SyncBanner + the "repo state changed" notice)
1514
+ are DELIBERATELY left visible in present mode: they're the DDR-102 fail-closed
1515
+ sync/divergence warnings, and an untrusted canvas (DDR-054) must not be able to
1516
+ silence a security-relevant notice by entering Presentation Mode (phase-28
1517
+ audit F-1). They're transient + rare, so they don't clutter a clean view. */
1518
+
1519
+ /* Floating escape-hatch pill — the only chrome visible while presenting.
1520
+ Deliberately understated (55% opacity) so it doesn't intrude on a clean
1521
+ screenshot, brightening to full on hover/focus. */
1522
+ .st-present-exit {
1523
+ position: fixed; top: var(--space-4); right: var(--space-4); z-index: 200;
1524
+ display: inline-flex; align-items: center; gap: var(--space-2);
1525
+ padding: var(--space-2) var(--space-3);
1526
+ appearance: none; cursor: pointer;
1527
+ font-family: var(--font-body); font-size: var(--type-sm); color: var(--fg-1);
1528
+ background: var(--bg-1); border: 1px solid var(--border-default);
1529
+ border-radius: var(--radius-pill);
1530
+ box-shadow: 0 4px 16px rgb(0 0 0 / 0.18);
1531
+ opacity: 0.72;
1532
+ transition: opacity var(--dur-soft) var(--ease-out),
1533
+ background var(--dur-soft) var(--ease-out), color var(--dur-soft) var(--ease-out);
1534
+ }
1535
+ .st-present-exit:hover,
1536
+ .st-present-exit:focus-visible { opacity: 1; background: var(--bg-3); color: var(--fg-0); }
1537
+ .st-present-exit > svg { color: var(--fg-2); flex: 0 0 auto; }
1538
+ .st-present-exit:hover > svg,
1539
+ .st-present-exit:focus-visible > svg { color: var(--accent); }
1540
+ .st-present-exit-kbd {
1541
+ font-family: var(--font-mono); font-size: var(--type-xs);
1542
+ color: var(--fg-3); border: 1px solid var(--border-subtle);
1543
+ border-radius: var(--radius-xs); padding: 1px 5px; line-height: 1.4;
1544
+ }
1545
+ @media (prefers-reduced-motion: reduce) { .st-present-exit { transition: none; } }
1546
+
1547
+ /* ── Phase 29 (E4) — OnboardingWizard (first-run). Ported from the approved
1548
+ `.design/ui/Onboarding.tsx` mockup (≥4.5/5); ob-* classes, every value a token. ── */
1549
+ .ob-overlay {
1550
+ position: fixed; inset: 0; z-index: 100;
1551
+ background: var(--bg-0);
1552
+ display: flex;
1553
+ }
1554
+ .ob-shell {
1555
+ position: absolute; inset: 0;
1556
+ display: flex;
1557
+ background: var(--bg-0); color: var(--fg-0);
1558
+ font-family: var(--font-body); font-size: var(--type-base); line-height: var(--lh-base);
1559
+ overflow: hidden;
1560
+ }
1561
+ .ob-rail {
1562
+ flex: 0 0 372px; display: flex; flex-direction: column; gap: var(--space-7);
1563
+ padding: var(--space-8) var(--space-7);
1564
+ background: radial-gradient(120% 90% at 0% 0%, var(--accent-tint) 0%, transparent 55%), var(--bg-1);
1565
+ border-right: 1px solid var(--border-default);
1566
+ }
1567
+ .ob-rail-brand { display: inline-flex; align-items: center; gap: var(--space-3); }
1568
+ /* maude mark tile — lifted from system/maude/preview/logo.css `.lg-mark`: spark in
1569
+ * --accent-fg on the indigo, bottom-right corner squared (bubble), accent-tint halo. */
1570
+ .ob-mark { display: grid; place-items: center; flex: 0 0 auto; background: var(--accent); color: var(--accent-fg); border-radius: 24% 24% 0 24%; box-shadow: 0 0 0 3px var(--accent-tint); }
1571
+ .ob-mark svg { width: 100%; height: 100%; display: block; }
1572
+ .ob-rail-wordmark { font-family: var(--font-display); font-size: var(--type-xl); font-weight: 600; letter-spacing: var(--tracking-tight); }
1573
+ .ob-rail-h { margin: 0 0 var(--space-3); font-family: var(--font-display); font-size: var(--type-2xl); line-height: var(--lh-xl); font-weight: 600; letter-spacing: var(--tracking-tight); color: var(--fg-0); }
1574
+ .ob-rail-lede p { margin: 0; max-width: 30ch; color: var(--fg-2); font-size: var(--type-md); line-height: var(--lh-lg); }
1575
+ .ob-rail-reassure { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: var(--space-3); }
1576
+ .ob-rail-reassure li { display: flex; align-items: center; gap: var(--space-3); color: var(--fg-1); font-size: var(--type-sm); }
1577
+ .ob-rail-tick { flex: 0 0 auto; width: 20px; height: 20px; display: grid; place-items: center; border-radius: var(--radius-pill); background: var(--accent-tint); color: var(--accent); }
1578
+ .ob-rail-signed { display: inline-flex; align-items: center; gap: var(--space-3); align-self: flex-start; padding: var(--space-2) var(--space-4); border: 1px solid var(--border-default); border-radius: var(--radius-pill); background: var(--bg-2); font-size: var(--type-sm); color: var(--fg-1); }
1579
+ .ob-rail-signed b { color: var(--fg-0); font-weight: 600; }
1580
+ .ob-rail-signed-dot { width: 7px; height: 7px; border-radius: var(--radius-pill); background: var(--presence-online); box-shadow: 0 0 0 3px color-mix(in oklab, var(--presence-online) 28%, transparent); }
1581
+ .ob-rail-foot { margin-top: auto; color: var(--fg-2); font-size: var(--type-xs); font-family: var(--font-mono); }
1582
+
1583
+ .ob-main { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: var(--space-6); padding: var(--space-8) clamp(var(--space-7), 6vw, 96px); overflow: auto; }
1584
+ .ob-back { align-self: flex-start; display: inline-flex; align-items: center; gap: var(--space-2); padding: var(--space-1) var(--space-3) var(--space-1) var(--space-2); 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; }
1585
+ .ob-back:hover { border-color: var(--border-strong); color: var(--fg-0); }
1586
+ .ob-back:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
1587
+ .ob-head { display: flex; flex-direction: column; gap: var(--space-2); }
1588
+ .ob-eyebrow { font-family: var(--font-mono); font-size: var(--type-xs); letter-spacing: var(--tracking-wide); text-transform: uppercase; color: var(--accent); }
1589
+ .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); }
1590
+ .ob-head p { margin: 0; max-width: 56ch; color: var(--fg-2); font-size: var(--type-md); line-height: var(--lh-lg); }
1591
+
1592
+ .ob-doors { display: flex; flex-direction: column; gap: var(--space-4); max-width: 720px; }
1593
+ .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); }
1594
+ .ob-door:hover { border-color: var(--border-strong); background: var(--bg-2); transform: translateY(-1px); }
1595
+ .ob-door:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
1596
+ .ob-door:disabled { opacity: 0.6; cursor: default; }
1597
+ .ob-door--primary { padding: var(--space-6); border-color: color-mix(in oklab, var(--accent) 55%, transparent); background: linear-gradient(180deg, var(--accent-tint) 0%, transparent 70%), var(--bg-1); box-shadow: var(--shadow-md); }
1598
+ .ob-door--primary:hover { border-color: var(--accent); }
1599
+ .ob-door--advanced { background: var(--bg-1); border-style: dashed; border-color: var(--border-strong); }
1600
+ .ob-door--advanced:hover { background: var(--bg-2); }
1601
+ .ob-door-icon { width: 48px; height: 48px; display: grid; place-items: center; border-radius: var(--radius-md); background: var(--bg-3); color: var(--fg-1); border: 1px solid var(--border-subtle); }
1602
+ .ob-door-icon--gh { background: var(--fg-0); color: var(--bg-0); border-color: transparent; }
1603
+ .ob-door-icon--quiet { width: 40px; height: 40px; background: var(--bg-2); color: var(--fg-2); }
1604
+ .ob-door-tx { display: flex; flex-direction: column; gap: 3px; min-width: 0; }
1605
+ .ob-door-title { display: inline-flex; align-items: center; gap: var(--space-3); font-family: var(--font-display); font-size: var(--type-lg); font-weight: 600; color: var(--fg-0); }
1606
+ .ob-door--primary .ob-door-title { font-size: var(--type-xl); }
1607
+ .ob-door-sub { color: var(--fg-2); font-size: var(--type-sm); line-height: var(--lh-md); }
1608
+ .ob-door-tag { font-family: var(--font-mono); font-size: var(--type-xs); letter-spacing: var(--tracking-wide); text-transform: uppercase; color: var(--accent); padding: 2px var(--space-2); border-radius: var(--radius-pill); background: var(--accent-tint); }
1609
+ .ob-door-adv { font-family: var(--font-mono); font-size: var(--type-xs); letter-spacing: var(--tracking-wide); text-transform: uppercase; color: var(--fg-2); padding: 1px var(--space-2); border: 1px solid var(--border-default); border-radius: var(--radius-sm); }
1610
+ .ob-door-cta { display: flex; }
1611
+ .ob-door-btn { pointer-events: none; white-space: nowrap; }
1612
+ .ob-door-go { color: var(--fg-3); display: grid; place-items: center; }
1613
+ .ob-door:hover .ob-door-go { color: var(--fg-1); }
1614
+ .ob-foot-note { margin: 0; color: var(--fg-2); font-size: var(--type-xs); }
1615
+
1616
+ /* Opt-in crash reporting checkbox (Phase 32 / Task 4) — quiet footer affordance. */
1617
+ .ob-crash-optin { display: flex; align-items: flex-start; gap: var(--space-2); max-width: 560px; margin: var(--space-3) 0 0; color: var(--fg-2); font-size: var(--type-xs); line-height: var(--lh-md); cursor: pointer; text-align: left; }
1618
+ .ob-crash-optin input { margin-top: 2px; flex: 0 0 auto; accent-color: var(--accent); cursor: pointer; }
1619
+
1620
+ .ob-create { display: grid; grid-template-columns: auto 1fr auto; align-items: center; gap: var(--space-4); width: 100%; max-width: 720px; text-align: left; padding: var(--space-5); border: 1px solid color-mix(in oklab, var(--accent) 45%, transparent); border-radius: var(--radius-lg); background: linear-gradient(180deg, var(--accent-tint) 0%, transparent 80%), var(--bg-1); cursor: pointer; color: inherit; transition: border-color var(--dur-soft) var(--ease-out); }
1621
+ .ob-create:hover { border-color: var(--accent); }
1622
+ .ob-create:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
1623
+ .ob-create-icon { width: 44px; height: 44px; display: grid; place-items: center; border-radius: var(--radius-md); background: var(--accent); color: var(--accent-fg); }
1624
+ .ob-create-tx { display: flex; flex-direction: column; gap: 2px; }
1625
+ .ob-create-title { font-family: var(--font-display); font-size: var(--type-lg); font-weight: 600; color: var(--fg-0); }
1626
+ .ob-create-sub { color: var(--fg-2); font-size: var(--type-sm); }
1627
+ .ob-create-btn { pointer-events: none; }
1628
+ .ob-section-label { font-family: var(--font-mono); font-size: var(--type-xs); letter-spacing: var(--tracking-wide); text-transform: uppercase; color: var(--fg-2); margin-top: var(--space-2); }
1629
+ .ob-repolist { display: flex; flex-direction: column; gap: var(--space-2); max-width: 720px; }
1630
+ .ob-repo { display: grid; grid-template-columns: auto 1fr auto; align-items: center; gap: var(--space-4); width: 100%; text-align: left; padding: var(--space-4); border: 1px solid var(--border-default); border-radius: var(--radius-md); background: var(--bg-1); color: inherit; cursor: pointer; transition: border-color var(--dur-soft) var(--ease-out), background var(--dur-soft) var(--ease-out); }
1631
+ .ob-repo:hover { border-color: var(--border-strong); background: var(--bg-2); }
1632
+ .ob-repo:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
1633
+ .ob-repo:disabled { opacity: 0.6; cursor: default; }
1634
+ .ob-repo-icon { color: var(--fg-2); display: grid; place-items: center; }
1635
+ .ob-repo-tx { display: flex; flex-direction: column; gap: 1px; min-width: 0; }
1636
+ .ob-repo-name { font-weight: 600; color: var(--fg-0); }
1637
+ .ob-repo-meta { color: var(--fg-2); font-size: var(--type-xs); font-family: var(--font-mono); }
1638
+ .ob-repo-go { display: inline-flex; align-items: center; gap: var(--space-2); color: var(--fg-2); font-size: var(--type-sm); white-space: nowrap; padding: var(--space-1) var(--space-3); border-radius: var(--radius-sm); }
1639
+ .ob-repo:hover .ob-repo-go { color: var(--accent); background: var(--accent-tint); }
1640
+
1641
+ .ob-drop { display: flex; flex-direction: column; align-items: center; justify-content: center; gap: var(--space-3); width: 100%; max-width: 720px; padding: var(--space-8) var(--space-6); border: 1.5px dashed var(--border-strong); border-radius: var(--radius-lg); background: var(--bg-1); text-align: center; color: inherit; cursor: pointer; }
1642
+ .ob-drop:hover { border-color: var(--accent); }
1643
+ .ob-drop:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
1644
+ .ob-drop:disabled { opacity: 0.6; cursor: default; }
1645
+ .ob-drop-glyph { width: 64px; height: 64px; display: grid; place-items: center; border-radius: var(--radius-lg); background: var(--bg-3); color: var(--accent); margin-bottom: var(--space-2); }
1646
+ .ob-drop-title { font-family: var(--font-display); font-size: var(--type-lg); font-weight: 600; color: var(--fg-0); }
1647
+ .ob-drop-or { color: var(--fg-2); font-size: var(--type-sm); }
1648
+ .ob-callout { max-width: 720px; }
1649
+ .ob-callout-glyph { flex: 0 0 auto; display: grid; place-items: center; }
1650
+
1651
+ .ob-form { display: flex; flex-direction: column; gap: var(--space-4); max-width: 560px; }
1652
+ .ob-field { display: flex; flex-direction: column; gap: var(--space-2); }
1653
+ .ob-field-label { font-size: var(--type-sm); font-weight: 600; color: var(--fg-1); }
1654
+ .ob-field-wrap { position: relative; display: flex; align-items: center; }
1655
+ .ob-field-pre { position: absolute; left: var(--space-3); color: var(--fg-3); pointer-events: none; }
1656
+ .ob-input { width: 100%; }
1657
+ .ob-field-wrap .ob-input { padding-left: calc(var(--space-3) * 2 + 16px); font-family: var(--font-mono); }
1658
+ .ob-form-actions { display: flex; gap: var(--space-3); margin-top: var(--space-1); }
1659
+
1660
+ .ob-toast { position: fixed; bottom: var(--space-5); left: 50%; transform: translateX(-50%); max-width: 480px; z-index: 101; box-shadow: var(--shadow-lg); }
1661
+ .ob-spin { animation: ob-spin 0.8s linear infinite; }
1662
+ @keyframes ob-spin { to { transform: rotate(360deg); } }
1663
+ @media (prefers-reduced-motion: reduce) {
1664
+ .ob-door, .ob-create, .ob-repo, .ob-back { transition-duration: 1ms; }
1665
+ .ob-door:hover { transform: none; }
1666
+ .ob-spin { animation-duration: 1ms; }
1667
+ }
1668
+
1669
+ /* ── Phase 29 (E4) — RepoBranchSwitcher. REDESIGNED to the approved mockup
1670
+ (.design/ui/RepoBranchSwitcher.tsx): a compact ONE-LINE dock at the BOTTOM of the
1671
+ sidebar (above the IdentityBar avatar) that opens ONE popup UPWARD. Mirrors the
1672
+ gi-rail/gi-menu anatomy so the two bottom surfaces read as one dock. ── */
1673
+ .rb-dock-wrap {
1674
+ flex: 0 0 auto;
1675
+ display: flex; flex-direction: column; gap: var(--space-1);
1676
+ padding: var(--space-3);
1677
+ border-top: 1px solid var(--border-default);
1678
+ background: var(--bg-1);
1679
+ box-shadow: 0 -10px 18px -12px color-mix(in oklab, var(--bg-0) 80%, transparent);
1680
+ }
1681
+ .rb-dock { position: relative; }
1682
+ /* The compact one-line trigger — "📁 <project> · ◐ <version> ⌃" */
1683
+ .rb-trigger {
1684
+ display: flex; align-items: center; gap: var(--space-2);
1685
+ width: 100%; text-align: left;
1686
+ padding: var(--space-2) var(--space-3);
1687
+ border: 1px solid var(--border-default); border-radius: var(--radius-md);
1688
+ background: var(--bg-2); color: var(--fg-1); cursor: pointer; font-size: var(--type-sm);
1689
+ transition: border-color var(--dur-soft) var(--ease-out), background var(--dur-soft) var(--ease-out);
1690
+ }
1691
+ .rb-trigger:hover, .rb-trigger.is-open { border-color: var(--border-strong); background: var(--bg-3); }
1692
+ .rb-trigger:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
1693
+ .rb-trigger-icon { color: var(--accent); flex: 0 0 auto; display: grid; place-items: center; }
1694
+ .rb-trigger-proj { font-weight: 600; color: var(--fg-0); flex: 0 1 auto; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
1695
+ .rb-trigger-sep { color: var(--fg-3); flex: 0 0 auto; }
1696
+ .rb-trigger-ver { display: inline-flex; align-items: center; gap: var(--space-1); min-width: 0; flex: 1 1 auto; color: var(--presence-online); }
1697
+ .rb-trigger-ver.is-draft { color: var(--status-warn); }
1698
+ .rb-trigger-ver-name { color: var(--fg-1); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
1699
+ .rb-trigger-caret { color: var(--fg-2); flex: 0 0 auto; }
1700
+ /* Web studio: the switcher degrades to a read-only awareness badge (DDR-119).
1701
+ Git vocab ("branch: X"), no hover affordance, no actions — the dev switches
1702
+ from their terminal. Neutral colour distinguishes it from the native dock's
1703
+ green "Shared version" / amber draft. */
1704
+ .rb-trigger--ro { cursor: default; }
1705
+ .rb-trigger--ro:hover { border-color: var(--border-default); background: var(--bg-2); }
1706
+ .rb-trigger-ver--ro { color: var(--fg-2); flex: 0 1 auto; }
1707
+ .rb-trigger-ver--ro .rb-trigger-ver-name { color: var(--fg-1); font-family: var(--font-mono); font-size: var(--type-xs); }
1708
+ /* GitPanel read-only footer hint (web studio — actions live in the terminal). */
1709
+ .gp-ro-hint { padding: var(--space-3) var(--space-4); color: var(--fg-2); }
1710
+ /* The popup — opens UPWARD from the dock (gi-menu anatomy). SOLID opaque menu
1711
+ * surface + border here (NOT the canvas `.panel`, which isn't in the client bundle
1712
+ * — phase-28 lesson; the tree must never bleed through). */
1713
+ .rb-pop { padding: var(--space-2); display: flex; flex-direction: column; gap: 1px; background: var(--bg-2); border: 1px solid var(--border-strong); border-radius: var(--radius-md); box-shadow: var(--shadow-lg); }
1714
+ .rb-pop--up { position: absolute; left: 0; right: 0; bottom: calc(100% + var(--space-1)); z-index: 30; max-height: 600px; overflow-y: auto; }
1715
+ .rb-pop-hd, .rb-pop-grouplabel { font-family: var(--font-mono); font-size: var(--type-xs); letter-spacing: var(--tracking-wide); text-transform: uppercase; color: var(--fg-2); padding: var(--space-2) var(--space-3) var(--space-1); }
1716
+ .rb-pop-grouplabel { padding-top: var(--space-3); }
1717
+ .rb-pop-item { display: flex; align-items: center; gap: var(--space-3); width: 100%; text-align: left; padding: var(--space-2) var(--space-3); border: 0; border-radius: var(--radius-sm); background: transparent; color: var(--fg-1); cursor: pointer; transition: background var(--dur-soft) var(--ease-out); }
1718
+ .rb-pop-item:hover { background: var(--bg-2); }
1719
+ .rb-pop-item:focus-visible { outline: 2px solid var(--accent); outline-offset: -2px; }
1720
+ .rb-pop-item.is-current { background: var(--accent-tint); }
1721
+ .rb-pop-item--action { color: var(--accent); }
1722
+ .rb-pop-icon { flex: 0 0 auto; color: var(--fg-2); display: grid; place-items: center; }
1723
+ .rb-pop-item--action .rb-pop-icon { color: var(--accent); }
1724
+ .rb-pop-icon--shared { color: var(--presence-online); }
1725
+ .rb-pop-icon--draft { color: var(--status-warn); }
1726
+ .rb-pop-tx { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 0; }
1727
+ .rb-pop-name { font-weight: 600; font-size: var(--type-sm); color: var(--fg-0); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
1728
+ .rb-pop-item--action .rb-pop-name { color: var(--accent); }
1729
+ .rb-pop-sub { font-family: var(--font-mono); font-size: var(--type-xs); color: var(--fg-2); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
1730
+ .rb-pop-item.is-current .rb-pop-sub { color: var(--fg-1); }
1731
+ .rb-pop-check { color: var(--accent); flex: 0 0 auto; }
1732
+ .rb-pop-sep { height: 1px; background: var(--border-default); margin: var(--space-2); }
1733
+ /* fold-back CTA (Task 7) — the one filled action in the Version section. Compact:
1734
+ * type-sm title + type-xs sub + tight padding, so it reads as a strong row, not a
1735
+ * giant banner. */
1736
+ .rb-fold { display: flex; align-items: center; gap: var(--space-2); width: 100%; text-align: left; margin: var(--space-2) 0; padding: var(--space-2) var(--space-3); border: 0; border-radius: var(--radius-sm); background: var(--accent); color: var(--accent-fg); cursor: pointer; transition: background var(--dur-soft) var(--ease-out); }
1737
+ .rb-fold:hover { background: var(--accent-hover); }
1738
+ .rb-fold:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
1739
+ .rb-fold-icon { flex: 0 0 auto; display: grid; place-items: center; color: var(--accent-fg); }
1740
+ .rb-fold-tx { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 1px; }
1741
+ .rb-fold-title { font-weight: 600; font-size: var(--type-sm); line-height: var(--lh-sm); color: var(--accent-fg); }
1742
+ .rb-fold-sub { font-size: var(--type-xs); line-height: var(--lh-sm); color: var(--accent-fg); }
1743
+ /* new-draft inline form (anchored upward above the dock). Solid bg (not `.panel`). */
1744
+ .rb-newdraft { display: flex; flex-direction: column; gap: var(--space-3); padding: var(--space-4); }
1745
+ .rb-newdraft--up { position: absolute; left: 0; right: 0; bottom: calc(100% + var(--space-1)); z-index: 30; background: var(--bg-1); border: 1px solid var(--border-strong); border-radius: var(--radius-md); box-shadow: var(--shadow-lg); }
1746
+ .rb-newdraft-field { display: flex; flex-direction: column; gap: var(--space-2); }
1747
+ .rb-newdraft-label { font-size: var(--type-sm); font-weight: 600; color: var(--fg-1); }
1748
+ .rb-newdraft-input { width: 100%; }
1749
+ .rb-newdraft-actions { display: flex; gap: var(--space-2); justify-content: flex-end; }
1750
+ .rb-newdraft-err, .rb-switcher-err { color: var(--status-error); font-size: var(--type-xs); }
1751
+ .rb-newdraft-hint { margin: 0; color: var(--fg-2); font-size: var(--type-xs); line-height: var(--lh-md); }
1752
+ /* switching state (compact, in the dock). */
1753
+ .rb-switching { display: flex; align-items: center; gap: var(--space-2); padding: var(--space-2) var(--space-3); border: 1px solid var(--border-default); border-radius: var(--radius-md); background: var(--bg-2); color: var(--fg-1); font-size: var(--type-sm); }
1754
+ .rb-switching b { color: var(--fg-0); }
1755
+ .rb-spin { color: var(--accent); animation: rb-spin 0.8s linear infinite; flex: 0 0 auto; }
1756
+ @keyframes rb-spin { to { transform: rotate(360deg); } }
1757
+ /* fold-back confirm sheet (modal over the shell). */
1758
+ .rb-scrim { position: fixed; inset: 0; z-index: 200; display: grid; place-items: center; padding: var(--space-6); background: color-mix(in oklab, var(--bg-0) 64%, transparent); backdrop-filter: blur(2px); }
1759
+ .rb-sheet { width: min(440px, 100%); display: flex; flex-direction: column; gap: var(--space-3); padding: var(--space-6); background: var(--bg-1); border: 1px solid var(--border-strong); border-radius: var(--radius-lg); box-shadow: var(--shadow-lg); text-align: left; }
1760
+ .rb-sheet-icon { width: 38px; height: 38px; border-radius: var(--radius-md); display: grid; place-items: center; color: var(--accent); background: var(--accent-tint); margin-bottom: var(--space-1); }
1761
+ .rb-sheet-title { margin: 0; font-family: var(--font-display); font-size: var(--type-lg); font-weight: 600; color: var(--fg-0); letter-spacing: var(--tracking-tight); }
1762
+ .rb-sheet-body { margin: 0; color: var(--fg-1); font-size: var(--type-md); line-height: var(--lh-md); }
1763
+ .rb-sheet-body b { color: var(--fg-0); font-weight: 600; }
1764
+ .rb-sheet-meta { margin: 0; color: var(--fg-2); font-size: var(--type-sm); line-height: var(--lh-md); }
1765
+ .rb-sheet-actions { display: flex; gap: var(--space-2); justify-content: flex-end; margin-top: var(--space-2); }
1766
+ @media (prefers-reduced-motion: reduce) {
1767
+ .rb-spin { animation-duration: 1ms; }
1768
+ .rb-trigger, .rb-pop-item, .rb-fold, .rb-identity-account { transition-duration: 1ms; }
1769
+ }
1770
+
459
1771
  }