bedrock-flows 0.7.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (85) hide show
  1. package/auth-schema.sql +8 -0
  2. package/bin/bedrock-flows.mjs +127 -0
  3. package/lib/setup.mjs +262 -0
  4. package/package.json +11 -0
  5. package/template/.storybook/main.js +46 -0
  6. package/template/.storybook/manager-head.html +963 -0
  7. package/template/.storybook/preview-head.html +35 -0
  8. package/template/.storybook/preview.js +23 -0
  9. package/template/CHANGELOG.md +236 -0
  10. package/template/README.md +26 -0
  11. package/template/apps/dashboard/index.html +15 -0
  12. package/template/apps/dashboard/package.json +22 -0
  13. package/template/apps/dashboard/src/App.module.css +1318 -0
  14. package/template/apps/dashboard/src/App.tsx +2716 -0
  15. package/template/apps/dashboard/src/auth-client.ts +17 -0
  16. package/template/apps/dashboard/src/changelog.tsx +92 -0
  17. package/template/apps/dashboard/src/index.css +86 -0
  18. package/template/apps/dashboard/src/main.tsx +15 -0
  19. package/template/apps/dashboard/src/theme.ts +31 -0
  20. package/template/apps/dashboard/src/vite-env.d.ts +4 -0
  21. package/template/apps/dashboard/vite.config.ts +48 -0
  22. package/template/apps/worker/.dev.vars.example +50 -0
  23. package/template/apps/worker/package.json +19 -0
  24. package/template/apps/worker/src/index.ts +295 -0
  25. package/template/apps/worker/tsconfig.json +11 -0
  26. package/template/apps/worker/wrangler.jsonc +29 -0
  27. package/template/bedrock.config.ts +16 -0
  28. package/template/design-system/README.md +97 -0
  29. package/template/design-system/starter-v1/components/button/component.css +42 -0
  30. package/template/design-system/starter-v1/components/button/danger.html +21 -0
  31. package/template/design-system/starter-v1/components/button/default.html +21 -0
  32. package/template/design-system/starter-v1/components/button/disabled.html +21 -0
  33. package/template/design-system/starter-v1/components/button/ghost.html +21 -0
  34. package/template/design-system/starter-v1/components/button/macro.njk +14 -0
  35. package/template/design-system/starter-v1/components/button/primary.html +21 -0
  36. package/template/design-system/starter-v1/components/button/variants.json +30 -0
  37. package/template/design-system/starter-v1/ds.json +3 -0
  38. package/template/design-system/starter-v1/global.css +52 -0
  39. package/template/design-system/starter-v1/style.css +107 -0
  40. package/template/gitignore +8 -0
  41. package/template/package.json +41 -0
  42. package/template/prototypes/F-001-hello/1-welcome.njk +30 -0
  43. package/template/prototypes/F-001-hello/2-form.njk +46 -0
  44. package/template/prototypes/F-001-hello/3-done.njk +29 -0
  45. package/template/prototypes/F-001-hello/meta.json +6 -0
  46. package/template/prototypes/_shared/_auth-gate.njk +54 -0
  47. package/template/prototypes/_shared/delivery.njk +43 -0
  48. package/template/prototypes/_shared/layout.njk +15 -0
  49. package/template/prototypes/_shared/screen.njk +1818 -0
  50. package/template/prototypes/_shared/wireflow.njk +4731 -0
  51. package/template/public/auth-gate.css +150 -0
  52. package/template/public/bedrock/color-inspector.js +284 -0
  53. package/template/public/bedrock/component-overlay.js +219 -0
  54. package/template/public/bedrock/data/bedrock-config.js +45 -0
  55. package/template/public/bedrock/font-size-overlay.js +590 -0
  56. package/template/public/bedrock/grid-overlay.js +379 -0
  57. package/template/public/bedrock/prototype-navigation.js +974 -0
  58. package/template/public/cmdk.js +146 -0
  59. package/template/public/ds-xray.css +112 -0
  60. package/template/public/ds-xray.js +271 -0
  61. package/template/public/favicon.svg +4 -0
  62. package/template/public/icons/bolt-fill.svg +3 -0
  63. package/template/public/icons/bolt.svg +3 -0
  64. package/template/public/icons/caret-down-fill.svg +3 -0
  65. package/template/public/icons/check-double.svg +4 -0
  66. package/template/public/icons/check.svg +3 -0
  67. package/template/public/icons/chevron-left.svg +3 -0
  68. package/template/public/icons/chevron-right.svg +3 -0
  69. package/template/public/icons/circle-info.svg +6 -0
  70. package/template/public/icons/grid.svg +6 -0
  71. package/template/public/icons/message-square-1.svg +3 -0
  72. package/template/public/icons/message-square.svg +3 -0
  73. package/template/public/icons/messages.svg +4 -0
  74. package/template/public/icons/options-horizontal.svg +5 -0
  75. package/template/public/icons/swatches.svg +6 -0
  76. package/template/public/icons/workflow.svg +6 -0
  77. package/template/public/lightbox.js +87 -0
  78. package/template/public/proto-chrome.css +596 -0
  79. package/template/public/screen-comments.css +723 -0
  80. package/template/public/wireflow-client.js +26 -0
  81. package/template/scripts/build-storybooks.mjs +8 -0
  82. package/template/scripts/dev-setup.mjs +15 -0
  83. package/template/scripts/generate-stories.mjs +12 -0
  84. package/template/scripts/generate-variants.mjs +22 -0
  85. package/template/tsconfig.base.json +19 -0
@@ -0,0 +1,723 @@
1
+ /* Comments UI shown on individual prototype screens (screen.njk).
2
+ Hidden when the page is rendered inside a wireflow iframe via the
3
+ .is-embedded class set by the inline script in screen.njk. */
4
+
5
+ /* Tokens: chrome-only — they don't bleed into the prototype's own
6
+ surface (which uses --ds-color-*). Light defaults; dark overrides
7
+ below via prefers-color-scheme. */
8
+ :root {
9
+ --sc-surface: #ffffff;
10
+ --sc-surface-alt: #fafbfc;
11
+ --sc-border: rgba(15, 23, 42, 0.15);
12
+ --sc-border-soft: rgba(15, 23, 42, 0.08);
13
+ --sc-text: #0f172a;
14
+ --sc-text-muted: #64748b;
15
+ --sc-text-faint: #94a3b8;
16
+ --sc-accent: #0f172a;
17
+ --sc-accent-fg: #ffffff;
18
+ --sc-danger: #dc2626;
19
+ --sc-shadow: 0 6px 18px rgba(15, 23, 42, 0.18);
20
+ --sc-shadow-lg: 0 20px 60px rgba(15, 23, 42, 0.4);
21
+ --sc-overlay: rgba(15, 23, 42, 0.6);
22
+ }
23
+ /* Honors the shared manual theme override (data-theme on <html>) and
24
+ falls back to the OS preference. */
25
+ @media (prefers-color-scheme: dark) {
26
+ :root:not([data-theme='light']) {
27
+ --sc-surface: #0f172a;
28
+ --sc-surface-alt: #111c33;
29
+ --sc-border: rgba(255, 255, 255, 0.10);
30
+ --sc-border-soft: rgba(255, 255, 255, 0.06);
31
+ --sc-text: #f1f5f9;
32
+ --sc-text-muted: #94a3b8;
33
+ --sc-text-faint: #64748b;
34
+ --sc-accent: #f1f5f9;
35
+ --sc-accent-fg: #0f172a;
36
+ --sc-overlay: rgba(0, 0, 0, 0.7);
37
+ }
38
+ }
39
+ :root[data-theme='dark'] {
40
+ --sc-surface: #0f172a;
41
+ --sc-surface-alt: #111c33;
42
+ --sc-border: rgba(255, 255, 255, 0.10);
43
+ --sc-border-soft: rgba(255, 255, 255, 0.06);
44
+ --sc-text: #f1f5f9;
45
+ --sc-text-muted: #94a3b8;
46
+ --sc-text-faint: #64748b;
47
+ --sc-accent: #f1f5f9;
48
+ --sc-accent-fg: #0f172a;
49
+ --sc-overlay: rgba(0, 0, 0, 0.7);
50
+ }
51
+
52
+ .is-embedded .screen-comments-fab,
53
+ .is-embedded .screen-comments-panel,
54
+ .is-embedded .bf-auth-gate { display: none !important; }
55
+
56
+ .screen-comments-fab {
57
+ position: fixed; right: 16px; bottom: 72px;
58
+ width: 44px; height: 44px;
59
+ border-radius: 999px;
60
+ border: 1px solid var(--sc-border);
61
+ background: var(--sc-surface);
62
+ color: var(--sc-text);
63
+ cursor: pointer;
64
+ display: flex; align-items: center; justify-content: center;
65
+ box-shadow: var(--sc-shadow);
66
+ z-index: 100;
67
+ transition: right 120ms ease;
68
+ }
69
+ /* When the comments sidebar is open, shift the FAB left so it stays
70
+ visible on the canvas. The toggle adds .is-active to the FAB itself. */
71
+ .screen-comments-fab.is-active { right: 336px; }
72
+ @media (max-width: 800px) {
73
+ .screen-comments-fab.is-active {
74
+ right: 16px;
75
+ bottom: calc(60vh + 72px);
76
+ }
77
+ }
78
+ .screen-comments-fab:hover {
79
+ background: var(--sc-surface-alt);
80
+ border-color: var(--sc-text-muted);
81
+ }
82
+ .screen-comments-fab.is-active {
83
+ background: var(--sc-accent);
84
+ color: var(--sc-accent-fg);
85
+ border-color: var(--sc-accent);
86
+ }
87
+ .screen-comments-fab__count {
88
+ position: absolute; top: -4px; right: -4px;
89
+ min-width: 18px; height: 18px;
90
+ padding: 0 5px;
91
+ border-radius: 999px;
92
+ background: #f97316;
93
+ color: white;
94
+ font-size: 10px; font-weight: 600;
95
+ display: flex; align-items: center; justify-content: center;
96
+ }
97
+
98
+ .screen-comments-panel {
99
+ /* Full viewport height, sitting ABOVE the chrome bars (z-index 1000)
100
+ rather than inset by guessed bar heights — guessed insets left
101
+ white gaps top/bottom when the guess didn't match the real bar
102
+ height. The panel's 320px column has no Back/Continue/state
103
+ controls under it (those are left/centre), so covering the bars
104
+ here is fine and the compose box + Post stay fully visible. */
105
+ position: fixed; right: 0;
106
+ top: 0;
107
+ bottom: 0;
108
+ width: 320px;
109
+ display: none; flex-direction: column;
110
+ background: var(--sc-surface);
111
+ color: var(--sc-text);
112
+ border-left: 1px solid var(--sc-border);
113
+ z-index: 1001;
114
+ overflow: hidden;
115
+ /* Harness chrome font — pinned because the panel shares the document with
116
+ the prototype, whose DS styles would otherwise cascade in. */
117
+ font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
118
+ }
119
+ .screen-comments-panel.is-open { display: flex; }
120
+
121
+ /* The panel shares the document with the prototype, so a design system that
122
+ styles bare h1–h6 (display font, heading color) hits the panel's headings
123
+ directly — element-level rules beat inheritance. Reset headings inside the
124
+ harness panel back to the panel's own font/color. */
125
+ .screen-comments-panel h1,
126
+ .screen-comments-panel h2,
127
+ .screen-comments-panel h3,
128
+ .screen-comments-panel h4,
129
+ .screen-comments-panel h5,
130
+ .screen-comments-panel h6 {
131
+ font-family: inherit;
132
+ color: inherit;
133
+ }
134
+
135
+ /* Inline toggle in the proto-bottombar — replaces the prior bottom-right
136
+ FAB. The bottom-right corner is too easily covered by product UI
137
+ (chat widgets, native FABs, mobile bottom bars), so the comments
138
+ entry sits in the harness chrome where it's always reachable. */
139
+ .screen-comments-toggle {
140
+ display: inline-flex;
141
+ align-items: center;
142
+ gap: 6px;
143
+ height: 28px;
144
+ padding: 0 12px;
145
+ background: var(--proto-chrome-nav-bg);
146
+ color: var(--proto-chrome-text);
147
+ border: 1px solid var(--proto-chrome-border);
148
+ border-radius: 6px;
149
+ font: inherit;
150
+ font-size: 12px;
151
+ cursor: pointer;
152
+ }
153
+ .screen-comments-toggle:hover { background: var(--proto-chrome-pill-bg); }
154
+ /* On touch devices chrome competes with a small screen — icon + count only. */
155
+ @media (pointer: coarse) {
156
+ .screen-comments-toggle__label { display: none; }
157
+ }
158
+
159
+ /* Compose: the side-note opt-out. Comments are agent-actionable by default;
160
+ checking this marks one as reference-only so automated agents skip it. */
161
+ .screen-comments-panel__note-toggle {
162
+ display: flex;
163
+ align-items: center;
164
+ gap: 6px;
165
+ margin: 6px 0 8px;
166
+ font-size: 11.5px;
167
+ color: var(--sc-text-muted);
168
+ cursor: pointer;
169
+ user-select: none;
170
+ }
171
+ .screen-comments-panel__note-toggle input {
172
+ margin: 0;
173
+ accent-color: var(--sc-text);
174
+ }
175
+ /* Manager compose hint — replaces the side-note toggle for managers, whose
176
+ comments always wait on designer approval before agents act. */
177
+ .screen-comments-panel__manager-hint {
178
+ margin: 6px 0 8px;
179
+ font-size: 11.5px;
180
+ color: var(--sc-text-muted);
181
+ }
182
+ /* Designer approval of a manager comment: context textarea + buttons. */
183
+ .screen-comment-card__approve-row {
184
+ display: flex;
185
+ flex-direction: column;
186
+ gap: 6px;
187
+ margin-top: 6px;
188
+ }
189
+ /* Designer-added context on an approved manager comment — what the agent
190
+ should actually do with the feedback. */
191
+ .screen-comment-card__designer-note {
192
+ margin-top: 6px;
193
+ padding: 6px 8px;
194
+ border-left: 3px solid var(--sc-border);
195
+ background: var(--sc-surface-alt);
196
+ border-radius: 0 6px 6px 0;
197
+ font-size: 12px;
198
+ color: var(--sc-text);
199
+ white-space: pre-wrap;
200
+ }
201
+ .screen-comment-card__designer-note b { font-weight: 600; }
202
+ /* Manager comment still waiting on a designer — amber chip. */
203
+ .screen-comment-card__chip--pending {
204
+ border-color: #f59e0b;
205
+ color: #b45309;
206
+ }
207
+ @media (prefers-color-scheme: dark) {
208
+ :root:not([data-theme='light']) .screen-comment-card__chip--pending {
209
+ color: #fcd34d;
210
+ border-color: #b45309;
211
+ }
212
+ }
213
+ :root[data-theme='dark'] .screen-comment-card__chip--pending {
214
+ color: #fcd34d;
215
+ border-color: #b45309;
216
+ }
217
+ /* Agent considered this but it needs a human decision — a soft-blue pill in
218
+ the same treatment as the green Resolved badge (an attention badge, not a
219
+ quiet metadata chip). Mirrors .screen-comment-card__resolved. */
220
+ .screen-comment-card__needs-human {
221
+ display: inline-flex; align-items: center; gap: 4px;
222
+ margin-bottom: 6px;
223
+ padding: 1px 7px; border-radius: 999px;
224
+ font-size: 10.5px; font-weight: 600;
225
+ background: #dbeafe; color: #1e40af;
226
+ }
227
+
228
+ /* Small metadata chips on a comment card (side-note marker, viewport). */
229
+ .screen-comment-card__chips {
230
+ display: flex;
231
+ flex-wrap: wrap;
232
+ align-items: center;
233
+ gap: 6px;
234
+ margin-top: 8px;
235
+ }
236
+ .screen-comment-card__byline {
237
+ color: var(--sc-text-faint);
238
+ font-size: 11px;
239
+ }
240
+ .screen-comment-card__chip {
241
+ display: inline-block;
242
+ margin-left: 0;
243
+ padding: 1px 6px;
244
+ border: 1px solid var(--sc-border-soft);
245
+ border-radius: 999px;
246
+ font-size: 10px;
247
+ line-height: 1.5;
248
+ color: var(--sc-text-muted);
249
+ white-space: nowrap;
250
+ }
251
+ /* "View local" — desktop-only, deployed-only jump to the dev server. */
252
+ .screen-viewlocal {
253
+ display: inline-flex; align-items: center;
254
+ height: 28px; padding: 0 12px;
255
+ background: var(--proto-chrome-nav-bg);
256
+ color: var(--proto-chrome-text-muted);
257
+ border: 1px solid var(--proto-chrome-border);
258
+ border-radius: 6px;
259
+ font: inherit; font-size: 12px; text-decoration: none;
260
+ }
261
+ .screen-viewlocal:hover { background: var(--proto-chrome-pill-bg); color: var(--proto-chrome-text); }
262
+ .screen-viewlocal[hidden] { display: none; }
263
+ @media (max-width: 720px) { .screen-viewlocal { display: none !important; } }
264
+ .screen-comments-toggle.is-active {
265
+ background: var(--proto-chrome-text);
266
+ color: var(--proto-chrome-bg);
267
+ border-color: var(--proto-chrome-text);
268
+ }
269
+ .screen-comments-toggle__count {
270
+ display: inline-flex;
271
+ align-items: center;
272
+ justify-content: center;
273
+ min-width: 16px;
274
+ height: 16px;
275
+ padding: 0 5px;
276
+ background: var(--sc-accent, #f97316);
277
+ /* Paired with the accent so it stays legible in dark mode (where
278
+ --sc-accent is near-white and a hardcoded #fff vanished). */
279
+ color: var(--sc-accent-fg, #fff);
280
+ border-radius: 999px;
281
+ font-size: 10px;
282
+ font-weight: 600;
283
+ }
284
+ /* When the sidebar is open we want the whole prototype to remain
285
+ visible — no overlap with the panel. The screen content is wrapped
286
+ in `.proto-stage` (see screen.njk). Shrinking the stage's width
287
+ lets the page reflow into the remaining viewport. */
288
+ /* Desktop full-bleed pages reflow into the remaining width. Phone-frame
289
+ prototypes must NOT — their body is clamped to a fixed device height
290
+ (.is-phone-frame body { height: 874px }); forcing width/min-height here
291
+ stretches the phone content. Instead, reserve the panel's width by
292
+ padding the html flex-centerer so the phone stays centered beside it. */
293
+ .has-comments-open:not(.is-phone-frame) .proto-stage {
294
+ /* `100%` (not `100vw`) excludes the scrollbar — with `100vw` the
295
+ stage is scrollbar-width wider than the area left of the fixed
296
+ 320px panel, leaving a sliver where neither covers. */
297
+ width: calc(100% - 320px);
298
+ min-height: 100vh;
299
+ }
300
+ .has-comments-open.is-phone-frame { padding-right: 320px; }
301
+ .has-comments-open { overflow-x: hidden; }
302
+ @media (max-width: 800px) {
303
+ /* On narrow screens the panel becomes a bottom drawer (60vh).
304
+ Shrink the stage vertically instead of horizontally so it stays
305
+ usable above the drawer. */
306
+ .has-comments-open:not(.is-phone-frame) .proto-stage {
307
+ width: 100vw;
308
+ min-height: 0;
309
+ height: 40vh;
310
+ overflow: auto;
311
+ }
312
+ }
313
+ @media (max-width: 800px) {
314
+ .screen-comments-panel {
315
+ top: auto; left: 0; right: 0;
316
+ bottom: var(--proto-bottombar-h, 0px);
317
+ width: 100%; height: 60vh;
318
+ border-left: 0; border-top: 1px solid var(--sc-border);
319
+ }
320
+ }
321
+ .screen-comments-panel__header {
322
+ display: flex; align-items: center; gap: 8px;
323
+ padding: 12px 14px;
324
+ border-bottom: 1px solid var(--sc-border-soft);
325
+ }
326
+ .screen-comments-panel__title {
327
+ margin: 0; font-size: 13px; font-weight: 600;
328
+ color: var(--sc-text);
329
+ flex: 1;
330
+ }
331
+ .screen-comments-panel__close {
332
+ background: transparent; border: 0;
333
+ border-radius: 6px;
334
+ color: var(--sc-text-muted);
335
+ padding: 6px;
336
+ font: inherit;
337
+ cursor: pointer;
338
+ display: inline-flex; align-items: center; justify-content: center;
339
+ width: 28px; height: 28px;
340
+ }
341
+ .screen-comments-panel__close:hover { background: var(--sc-surface-alt); color: var(--sc-text); }
342
+ .screen-comments-panel__list {
343
+ flex: 1;
344
+ overflow-y: auto;
345
+ padding: 8px 12px;
346
+ display: flex; flex-direction: column; gap: 8px;
347
+ min-height: 60px;
348
+ }
349
+ .screen-comments-panel__empty {
350
+ color: var(--sc-text-faint); font-size: 12px; padding: 16px 0;
351
+ text-align: center;
352
+ }
353
+ .screen-comment-card {
354
+ border: 1px solid var(--sc-border-soft);
355
+ border-radius: 8px;
356
+ padding: 8px 10px;
357
+ background: var(--sc-surface-alt);
358
+ }
359
+ .screen-comment-card.is-editing { padding: 8px; }
360
+ .screen-comment-card.is-resolved { opacity: 0.62; }
361
+ .screen-comment-card__link {
362
+ color: var(--sc-accent, #2563eb);
363
+ text-decoration: underline;
364
+ text-underline-offset: 2px;
365
+ word-break: break-all;
366
+ }
367
+ .screen-comment-card__resolved {
368
+ display: inline-flex; align-items: center; gap: 4px;
369
+ margin-bottom: 6px;
370
+ padding: 1px 7px; border-radius: 999px;
371
+ font-size: 10.5px; font-weight: 600;
372
+ background: #dcfce7; color: #166534;
373
+ }
374
+ .screen-comment-card__code {
375
+ font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
376
+ font-size: 10.5px; font-weight: 600; letter-spacing: 0.06em;
377
+ color: var(--sc-text-muted);
378
+ background: var(--sc-surface); border: 1px solid var(--sc-border-soft);
379
+ padding: 0 5px; border-radius: 4px; margin-right: 6px;
380
+ }
381
+ .screen-comment-card__resolve {
382
+ background: transparent; border: 0; padding: 0;
383
+ font: inherit; font-size: 11px; font-weight: 500;
384
+ color: var(--sc-text-muted); cursor: pointer;
385
+ }
386
+ .screen-comment-card__resolve:hover { color: #166534; }
387
+ .screen-comment-card__text {
388
+ font-size: 13px; line-height: 1.4;
389
+ color: var(--sc-text);
390
+ white-space: pre-wrap;
391
+ }
392
+ .screen-comment-card__meta {
393
+ display: flex; align-items: center; justify-content: space-between;
394
+ gap: 8px;
395
+ margin-top: 6px;
396
+ font-size: 11px;
397
+ color: var(--sc-text-faint);
398
+ }
399
+ .screen-comment-card.is-editing .screen-comment-card__meta { display: none; }
400
+ .screen-comment-card__actions {
401
+ display: inline-flex; align-items: center; gap: 2px;
402
+ }
403
+ /* Icon affordances in the meta row: Resolve (checkmark) and the
404
+ "⋯" more trigger. Subtle until hovered; checkmark goes green
405
+ once the comment is resolved. */
406
+ .screen-comment-card__icon-btn {
407
+ display: inline-flex; align-items: center; justify-content: center;
408
+ width: 24px; height: 24px;
409
+ padding: 0; border: 0; border-radius: 5px;
410
+ background: transparent;
411
+ color: var(--sc-text-muted);
412
+ font-size: 14px; line-height: 1;
413
+ cursor: pointer;
414
+ }
415
+ .screen-comment-card__icon-btn:hover {
416
+ background: var(--sc-surface-alt);
417
+ color: var(--sc-text);
418
+ }
419
+ .screen-comment-card__icon-btn.is-resolved { color: #16a34a; }
420
+ .screen-comment-card__icon-btn.is-resolved:hover { color: #15803d; }
421
+ /* More-menu: anchored dropdown under the "⋯" trigger. */
422
+ .screen-comment-card__more { position: relative; display: inline-flex; }
423
+ .screen-comment-card__menu {
424
+ position: absolute; top: calc(100% + 4px); right: 0;
425
+ display: none; flex-direction: column;
426
+ min-width: 132px;
427
+ padding: 4px;
428
+ background: var(--sc-surface);
429
+ border: 1px solid var(--sc-border);
430
+ border-radius: 8px;
431
+ box-shadow: 0 6px 20px rgba(0, 0, 0, 0.28);
432
+ z-index: 10;
433
+ }
434
+ .screen-comment-card__more.is-open .screen-comment-card__menu {
435
+ display: flex;
436
+ }
437
+ .screen-comment-card__menu-item {
438
+ display: flex; align-items: center;
439
+ padding: 7px 10px;
440
+ background: transparent; border: 0; border-radius: 5px;
441
+ font: inherit; font-size: 12px; font-weight: 500;
442
+ color: var(--sc-text);
443
+ text-align: left; cursor: pointer;
444
+ }
445
+ .screen-comment-card__menu-item:hover { background: var(--sc-surface-alt); }
446
+ .screen-comment-card__menu-item--danger { color: var(--sc-danger); }
447
+ .screen-comment-card__menu-item--danger:hover {
448
+ background: rgba(220, 38, 38, 0.12);
449
+ color: var(--sc-danger);
450
+ }
451
+ /* Edit + Delete + Cancel — same look (subtle text-only buttons),
452
+ distinguished only by hover color. */
453
+ .screen-comment-card__edit,
454
+ .screen-comment-card__delete {
455
+ background: transparent; border: 0; padding: 0;
456
+ font: inherit; font-size: 11px; font-weight: 500;
457
+ color: var(--sc-text-muted);
458
+ cursor: pointer;
459
+ }
460
+ .screen-comment-card__edit:hover { color: var(--sc-text); }
461
+ .screen-comment-card__delete:hover { color: var(--sc-danger); }
462
+ /* Inline delete confirmation row — replaces native confirm(). */
463
+ .screen-comment-card__delete-confirm {
464
+ display: flex; align-items: center; gap: 8px;
465
+ margin-top: 6px; padding: 6px 8px;
466
+ background: var(--sc-surface-alt);
467
+ border: 1px solid var(--sc-border);
468
+ border-radius: 6px;
469
+ }
470
+ .screen-comment-card__delete-confirm-msg {
471
+ flex: 1;
472
+ font-size: 11px; font-weight: 500;
473
+ color: var(--sc-text-muted);
474
+ }
475
+ /* Inline editor: textarea + Save/Cancel row. */
476
+ .screen-comment-card__editor {
477
+ width: 100%; box-sizing: border-box;
478
+ padding: 8px;
479
+ border: 1px solid var(--sc-border);
480
+ border-radius: 6px;
481
+ font: inherit; font-size: 13px; line-height: 1.4;
482
+ background: var(--sc-surface);
483
+ color: var(--sc-text);
484
+ resize: vertical;
485
+ min-height: 60px;
486
+ }
487
+ .screen-comment-card__editor:focus {
488
+ outline: 2px solid var(--sc-text); outline-offset: -1px;
489
+ }
490
+ .screen-comment-card__edit-row {
491
+ display: flex; align-items: center; gap: 6px;
492
+ margin-top: 6px;
493
+ }
494
+ .screen-comment-card__edit-row .screen-comments-panel__post {
495
+ align-self: auto;
496
+ }
497
+ .screen-comments-panel__compose {
498
+ display: flex; flex-direction: column; gap: 6px;
499
+ padding: 10px 12px;
500
+ border-top: 1px solid var(--sc-border-soft);
501
+ }
502
+ .screen-comments-panel__compose[hidden] { display: none !important; }
503
+ .screen-mention-wrap { position: relative; }
504
+ .screen-mention {
505
+ display: inline;
506
+ padding: 1px 6px; border-radius: 999px;
507
+ background: rgba(59, 130, 246, 0.32);
508
+ color: var(--sc-text-strong, #f1f5f9); font-weight: 600;
509
+ }
510
+ .screen-mention-menu {
511
+ position: absolute; left: 0; right: 0; bottom: calc(100% + 4px);
512
+ background: var(--sc-surface); border: 1px solid var(--sc-border);
513
+ border-radius: 8px; box-shadow: var(--sc-shadow); padding: 4px;
514
+ z-index: 10; max-height: 180px; overflow-y: auto;
515
+ }
516
+ .screen-mention-menu[hidden] { display: none; }
517
+ .screen-mention-menu__item {
518
+ display: flex; align-items: center; gap: 8px;
519
+ padding: 6px 8px; border-radius: 6px; cursor: pointer;
520
+ font-size: 13px; color: var(--sc-text);
521
+ }
522
+ .screen-mention-menu__item:hover,
523
+ .screen-mention-menu__item.is-active { background: var(--sc-surface-alt); }
524
+ .screen-mention-menu__handle { color: var(--sc-text-muted); font-size: 12px; }
525
+ .screen-comments-panel__readonly {
526
+ margin: 10px 12px;
527
+ padding: 8px 10px 8px 12px;
528
+ border-left: 2px solid var(--sc-text-faint);
529
+ border-radius: 0 6px 6px 0;
530
+ background: var(--sc-surface-alt);
531
+ color: var(--sc-text-muted);
532
+ font-size: 12px; font-weight: 500;
533
+ display: flex; flex-direction: column; gap: 2px;
534
+ }
535
+ .screen-comments-panel__readonly[hidden] { display: none !important; }
536
+ .screen-comments-panel__readonly a { color: var(--sc-text); font-weight: 600; text-decoration: underline; }
537
+ .screen-comments-panel__compose textarea {
538
+ width: 100%; padding: 10px 12px; box-sizing: border-box;
539
+ border: 1px solid var(--sc-border);
540
+ border-radius: 6px;
541
+ font: inherit; font-size: 13px; line-height: 1.5;
542
+ background: var(--sc-surface-alt);
543
+ color: var(--sc-text);
544
+ resize: vertical;
545
+ min-height: 70px;
546
+ }
547
+ .screen-comments-panel__post {
548
+ padding: 6px 12px; border: 0; border-radius: 6px;
549
+ background: var(--sc-accent);
550
+ color: var(--sc-accent-fg);
551
+ font: inherit; font-size: 12px; font-weight: 500;
552
+ cursor: pointer;
553
+ align-self: flex-end;
554
+ }
555
+ .screen-comments-panel__post:disabled { opacity: 0.5; cursor: not-allowed; }
556
+ /* Compose footer: attach-image affordance left, Post right. */
557
+ .screen-comments-panel__compose-row {
558
+ display: flex; align-items: center; justify-content: space-between; gap: 8px;
559
+ }
560
+ .screen-comments-panel__compose-row .screen-comments-panel__post { align-self: auto; }
561
+ .screen-comments-panel__attach {
562
+ display: inline-flex; align-items: center; justify-content: center;
563
+ width: 26px; height: 26px;
564
+ padding: 0; border: 0; border-radius: 5px;
565
+ background: transparent;
566
+ color: var(--sc-text-muted);
567
+ cursor: pointer;
568
+ }
569
+ .screen-comments-panel__attach:hover {
570
+ background: var(--sc-surface-alt);
571
+ color: var(--sc-text);
572
+ }
573
+ /* Staged (not yet posted) image thumbnails with a remove control. */
574
+ .screen-comments-panel__attachments {
575
+ display: flex; flex-wrap: wrap; gap: 6px;
576
+ }
577
+ .screen-comments-panel__attachments[hidden] { display: none !important; }
578
+ .screen-comments-panel__attach-thumb {
579
+ position: relative; display: inline-flex;
580
+ }
581
+ .screen-comments-panel__attach-thumb img {
582
+ display: block;
583
+ max-height: 56px; max-width: 96px;
584
+ border: 1px solid var(--sc-border);
585
+ border-radius: 6px;
586
+ object-fit: cover;
587
+ }
588
+ .screen-comments-panel__attach-remove {
589
+ position: absolute; top: -6px; right: -6px;
590
+ display: inline-flex; align-items: center; justify-content: center;
591
+ width: 16px; height: 16px;
592
+ padding: 0; border: 1px solid var(--sc-border);
593
+ border-radius: 999px;
594
+ background: var(--sc-surface);
595
+ color: var(--sc-text-muted);
596
+ font-size: 11px; line-height: 1;
597
+ cursor: pointer;
598
+ }
599
+ .screen-comments-panel__attach-remove:hover { color: var(--sc-danger); }
600
+ .screen-comments-panel__attach-error {
601
+ margin: 0;
602
+ font-size: 11px; font-weight: 500;
603
+ color: var(--sc-danger);
604
+ }
605
+ .screen-comments-panel__attach-error[hidden] { display: none !important; }
606
+ /* Image attachments on a posted comment — small thumbnails, click = full image. */
607
+ .screen-comment-card__attachments {
608
+ display: flex; flex-wrap: wrap; gap: 6px;
609
+ margin-top: 6px;
610
+ }
611
+ .screen-comment-card__attachments img {
612
+ display: block;
613
+ max-height: 120px; max-width: 100%;
614
+ border: 1px solid var(--sc-border-soft);
615
+ border-radius: 6px;
616
+ }
617
+
618
+ /* Auth gate (shown when the user hits the Comments FAB without a session) —
619
+ markup from _auth-gate.njk, styling from the shared /auth-gate.css. */
620
+
621
+ /* ── Node-anchored comments (EXPERIMENTAL) ──────────────────────────────
622
+ Pin-to-element pick mode, the staged anchor chip in the compose area,
623
+ the anchor chip on posted cards, and the in-page highlight overlays.
624
+ Overlay elements may be appended to the preview iframe's document —
625
+ that document loads this same stylesheet, so the classes resolve there
626
+ too. Fixed accent colors (not --sc-*) so the highlight reads the same
627
+ over any prototype surface, light or dark. */
628
+ .screen-comments-panel__compose-tools {
629
+ display: inline-flex; align-items: center; gap: 2px;
630
+ }
631
+ .screen-comments-panel__attach.is-picking {
632
+ background: var(--sc-accent);
633
+ color: var(--sc-accent-fg);
634
+ }
635
+ /* Staged (not yet posted) element anchor — one removable chip. */
636
+ .screen-comments-panel__anchor-row { display: flex; }
637
+ .screen-comments-panel__anchor-row[hidden] { display: none !important; }
638
+ .screen-comments-panel__anchor-chip {
639
+ display: inline-flex; align-items: center; gap: 4px;
640
+ max-width: 100%;
641
+ padding: 2px 4px 2px 8px;
642
+ border: 1px solid var(--sc-border-soft);
643
+ border-radius: 999px;
644
+ font-size: 11px; line-height: 1.6;
645
+ color: var(--sc-text-muted);
646
+ background: var(--sc-surface-alt);
647
+ }
648
+ .screen-comments-panel__anchor-chip-label {
649
+ overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
650
+ }
651
+ .screen-comments-panel__anchor-remove {
652
+ display: inline-flex; align-items: center; justify-content: center;
653
+ width: 16px; height: 16px; flex: 0 0 auto;
654
+ padding: 0; border: 0; border-radius: 999px;
655
+ background: transparent;
656
+ color: var(--sc-text-muted);
657
+ font-size: 12px; line-height: 1;
658
+ cursor: pointer;
659
+ }
660
+ .screen-comments-panel__anchor-remove:hover { color: var(--sc-danger); }
661
+ /* Anchor chip on a posted card — clickable (re-highlights the element). */
662
+ .screen-comment-card__chip--anchor {
663
+ display: inline-flex; align-items: center; gap: 3px;
664
+ max-width: 180px; overflow: hidden; text-overflow: ellipsis;
665
+ padding: 1px 6px;
666
+ background: transparent;
667
+ font: inherit; font-size: 10px; line-height: 1.5;
668
+ cursor: pointer;
669
+ }
670
+ .screen-comment-card__chip--anchor svg { flex: 0 0 auto; }
671
+ .screen-comment-card__chip--anchor {
672
+ max-width: 100%;
673
+ overflow: hidden;
674
+ text-overflow: ellipsis;
675
+ white-space: nowrap;
676
+ }
677
+ .screen-comment-card__chip--anchor:hover {
678
+ color: var(--sc-text);
679
+ border-color: var(--sc-border);
680
+ }
681
+ .screen-comment-card__chip--anchor.is-missing {
682
+ color: var(--sc-danger);
683
+ border-color: var(--sc-danger);
684
+ animation: sc-anchor-flash 0.4s ease 2;
685
+ }
686
+ @keyframes sc-anchor-flash {
687
+ 50% { opacity: 0.35; }
688
+ }
689
+ /* Pick-mode overlays — absolutely positioned in document coordinates;
690
+ pointer-events:none so hover/click reach the elements underneath. */
691
+ .screen-anchor-pick-box {
692
+ position: absolute; z-index: 2147483600;
693
+ display: none;
694
+ pointer-events: none;
695
+ border: 1.5px solid #38bdf8;
696
+ border-radius: 2px;
697
+ background: rgba(56, 189, 248, 0.14);
698
+ }
699
+ .screen-anchor-pick-tag {
700
+ position: absolute; z-index: 2147483601;
701
+ display: none;
702
+ pointer-events: none;
703
+ max-width: 360px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
704
+ padding: 2px 7px;
705
+ border-radius: 4px;
706
+ background: #0c4a6e; color: #e0f2fe;
707
+ font-family: ui-monospace, Menlo, monospace;
708
+ font-size: 10.5px; line-height: 1.6;
709
+ }
710
+ .is-anchor-picking .proto-content,
711
+ .is-anchor-picking .proto-content * { cursor: crosshair !important; }
712
+ /* Re-highlight pulse when a card's anchor chip is clicked (~2s). */
713
+ .screen-anchor-pulse {
714
+ position: absolute; z-index: 2147483600;
715
+ pointer-events: none;
716
+ border: 2px solid #38bdf8;
717
+ border-radius: 4px;
718
+ animation: sc-anchor-pulse 1s ease-in-out 2;
719
+ }
720
+ @keyframes sc-anchor-pulse {
721
+ 0%, 100% { box-shadow: 0 0 0 0 rgba(56, 189, 248, 0.55); opacity: 1; }
722
+ 50% { box-shadow: 0 0 0 8px rgba(56, 189, 248, 0); opacity: 0.55; }
723
+ }