@ldlework/feedback 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/styles.css ADDED
@@ -0,0 +1,478 @@
1
+ /*
2
+ * @ldlework/feedback — the one stylesheet.
3
+ *
4
+ * Every class is prefixed `fb-` and every colour reads from a `--fb-*`
5
+ * custom property, so the whole overlay re-skins from one knob: set
6
+ * `--fb-hue` (0–360) to shift the accent and the warm-neutral chrome
7
+ * together, or override any individual token. Defaults are a dark,
8
+ * "lit display" amber that floats cleanly over light or dark pages.
9
+ *
10
+ * Scope: the variables live on `.fb-root`, which the library puts on
11
+ * every portal root (overlay, dock, popover), so nothing here leaks into
12
+ * or out of the host page.
13
+ */
14
+
15
+ .fb-root {
16
+ /* One knob. */
17
+ --fb-hue: 65;
18
+
19
+ /* Accent — the lit pixel. */
20
+ --fb-accent: oklch(0.78 0.16 var(--fb-hue));
21
+ --fb-accent-hover: oklch(0.86 0.16 var(--fb-hue));
22
+ --fb-accent-contrast: oklch(0.18 0.05 var(--fb-hue));
23
+ --fb-accent-subtle: oklch(0.78 0.16 var(--fb-hue) / 0.2);
24
+
25
+ /* Surfaces — unlit material, hue-aware. */
26
+ --fb-surface: oklch(0.17 0.012 var(--fb-hue));
27
+ --fb-surface-raised: oklch(0.21 0.014 var(--fb-hue));
28
+ --fb-surface-overlay: oklch(0.26 0.016 var(--fb-hue));
29
+ --fb-surface-sunken: oklch(0.13 0.01 var(--fb-hue));
30
+ --fb-border: oklch(0.33 0.02 var(--fb-hue));
31
+ --fb-border-strong: oklch(0.43 0.03 var(--fb-hue));
32
+
33
+ /* Text. */
34
+ --fb-text: oklch(0.95 0.008 var(--fb-hue));
35
+ --fb-text-secondary: oklch(0.78 0.015 var(--fb-hue));
36
+ --fb-text-muted: oklch(0.6 0.02 var(--fb-hue));
37
+
38
+ /* Semantic — hue-fixed so right/wrong never drifts. */
39
+ --fb-success: oklch(0.78 0.14 165);
40
+ --fb-danger: oklch(0.7 0.17 15);
41
+
42
+ /* Shape. */
43
+ --fb-radius-sm: 0.375rem;
44
+ --fb-radius: 0.5rem;
45
+ --fb-radius-lg: 0.75rem;
46
+ --fb-radius-full: 9999px;
47
+
48
+ /* Elevation. */
49
+ --fb-shadow-sm: 0 4px 12px rgba(0, 0, 0, 0.35);
50
+ --fb-shadow: 0 12px 32px rgba(0, 0, 0, 0.45);
51
+
52
+ /* Type. */
53
+ --fb-font: 'Inter', system-ui, -apple-system, BlinkMacSystemFont, sans-serif;
54
+ --fb-font-mono: 'JetBrains Mono', ui-monospace, SFMono-Regular, monospace;
55
+
56
+ /* Stacking. High base so the overlay clears app chrome; layers offset up. */
57
+ --fb-z: 2147483000;
58
+
59
+ --fb-dur: 150ms;
60
+ --fb-ease: cubic-bezier(0.16, 1, 0.3, 1);
61
+
62
+ font-family: var(--fb-font);
63
+ line-height: 1.5;
64
+ color: var(--fb-text);
65
+ }
66
+
67
+ .fb-root *,
68
+ .fb-root *::before,
69
+ .fb-root *::after {
70
+ box-sizing: border-box;
71
+ }
72
+
73
+ /* ---------------------------------------------------------------- overlay */
74
+
75
+ .fb-overlay {
76
+ position: absolute;
77
+ left: 0;
78
+ top: 0;
79
+ pointer-events: none;
80
+ z-index: var(--fb-z);
81
+ }
82
+
83
+ /* ------------------------------------------------------------------- note */
84
+
85
+ .fb-note {
86
+ position: absolute;
87
+ pointer-events: auto;
88
+ display: flex;
89
+ flex-direction: column;
90
+ overflow: hidden;
91
+ border-radius: var(--fb-radius);
92
+ border: 1px solid var(--fb-border-strong);
93
+ background: var(--fb-surface-overlay);
94
+ box-shadow: var(--fb-shadow);
95
+ color: var(--fb-text);
96
+ transition: opacity var(--fb-dur), box-shadow var(--fb-dur);
97
+ }
98
+
99
+ .fb-note--current {
100
+ border-color: var(--fb-accent);
101
+ box-shadow: 0 0 0 2px var(--fb-accent), var(--fb-shadow);
102
+ }
103
+
104
+ .fb-note--resolved {
105
+ opacity: 0.6;
106
+ }
107
+
108
+ .fb-note__header {
109
+ display: flex;
110
+ align-items: center;
111
+ justify-content: space-between;
112
+ gap: 0.25rem;
113
+ padding: 0.25rem 0.5rem;
114
+ background: var(--fb-surface-sunken);
115
+ color: var(--fb-text-muted);
116
+ cursor: grab;
117
+ touch-action: none;
118
+ user-select: none;
119
+ }
120
+
121
+ .fb-note__header:active {
122
+ cursor: grabbing;
123
+ }
124
+
125
+ .fb-note__actions {
126
+ display: flex;
127
+ align-items: center;
128
+ gap: 0.125rem;
129
+ }
130
+
131
+ .fb-note__body {
132
+ resize: none;
133
+ border: 0;
134
+ background: transparent;
135
+ padding: 0.5rem 0.75rem;
136
+ font-family: var(--fb-font);
137
+ font-size: 0.875rem;
138
+ line-height: 1.375;
139
+ color: var(--fb-text);
140
+ outline: none;
141
+ }
142
+
143
+ .fb-note__body::placeholder {
144
+ color: var(--fb-text-muted);
145
+ }
146
+
147
+ /* ------------------------------------------------------------------- knob */
148
+
149
+ .fb-knob {
150
+ position: absolute;
151
+ width: 0.75rem;
152
+ height: 0.75rem;
153
+ transform: translate(-50%, -50%);
154
+ border-radius: var(--fb-radius-full);
155
+ border: 1px solid var(--fb-accent);
156
+ background: var(--fb-surface-overlay);
157
+ cursor: crosshair;
158
+ touch-action: none;
159
+ pointer-events: auto;
160
+ transition: background-color var(--fb-dur);
161
+ }
162
+
163
+ .fb-knob:hover {
164
+ background: var(--fb-accent);
165
+ }
166
+
167
+ /* ------------------------------------------------------------------ ghost */
168
+
169
+ .fb-ghost {
170
+ position: fixed;
171
+ pointer-events: none;
172
+ z-index: calc(var(--fb-z) + 5);
173
+ border-radius: var(--fb-radius);
174
+ border: 2px dashed var(--fb-accent);
175
+ background: var(--fb-accent-subtle);
176
+ }
177
+
178
+ /* ------------------------------------------------------------------ arrow */
179
+
180
+ .fb-arrow {
181
+ position: absolute;
182
+ overflow: visible;
183
+ pointer-events: none;
184
+ }
185
+
186
+ .fb-edge__hit {
187
+ pointer-events: auto;
188
+ cursor: pointer;
189
+ }
190
+
191
+ .fb-edge__head {
192
+ pointer-events: auto;
193
+ cursor: grab;
194
+ touch-action: none;
195
+ }
196
+
197
+ .fb-edge__head:active {
198
+ cursor: grabbing;
199
+ }
200
+
201
+ /* --------------------------------------------------------------- buttons */
202
+
203
+ .fb-btn {
204
+ display: inline-flex;
205
+ align-items: center;
206
+ justify-content: center;
207
+ margin: 0;
208
+ padding: 0;
209
+ border: 0;
210
+ background: transparent;
211
+ color: var(--fb-text-secondary);
212
+ border-radius: var(--fb-radius-full);
213
+ cursor: pointer;
214
+ -webkit-tap-highlight-color: transparent;
215
+ transition: color var(--fb-dur), background-color var(--fb-dur), border-color var(--fb-dur);
216
+ }
217
+
218
+ .fb-btn:disabled {
219
+ cursor: not-allowed;
220
+ opacity: 0.4;
221
+ }
222
+
223
+ .fb-btn--sm {
224
+ width: 1.5rem;
225
+ height: 1.5rem;
226
+ }
227
+ .fb-btn--md {
228
+ width: 2rem;
229
+ height: 2rem;
230
+ }
231
+ .fb-btn--lg {
232
+ width: 3rem;
233
+ height: 3rem;
234
+ }
235
+
236
+ /* Ghost: bare glyph that brightens on hover, tints when active. */
237
+ .fb-btn--ghost:not(:disabled):hover {
238
+ color: var(--fb-text);
239
+ }
240
+ .fb-btn--ghost.fb-btn--success:not(:disabled):hover {
241
+ color: var(--fb-success);
242
+ }
243
+ .fb-btn--ghost.fb-btn--danger:not(:disabled):hover {
244
+ color: var(--fb-danger);
245
+ }
246
+ .fb-btn.is-active.fb-btn--accent {
247
+ color: var(--fb-accent);
248
+ }
249
+ .fb-btn.is-active.fb-btn--success {
250
+ color: var(--fb-success);
251
+ }
252
+ .fb-btn.is-active.fb-btn--danger {
253
+ color: var(--fb-danger);
254
+ }
255
+
256
+ /* Solid: a standalone chip with a border and fill. */
257
+ .fb-btn--solid {
258
+ border: 1px solid var(--fb-border);
259
+ background: var(--fb-surface-overlay);
260
+ color: var(--fb-text-secondary);
261
+ box-shadow: var(--fb-shadow-sm);
262
+ }
263
+ .fb-btn--solid:not(:disabled):hover {
264
+ border-color: var(--fb-border-strong);
265
+ color: var(--fb-accent);
266
+ }
267
+ .fb-btn--solid.is-active {
268
+ border-color: var(--fb-accent);
269
+ background: var(--fb-accent);
270
+ color: var(--fb-accent-contrast);
271
+ }
272
+ .fb-btn--solid.is-active.fb-btn--success {
273
+ border-color: var(--fb-success);
274
+ background: var(--fb-success);
275
+ }
276
+ .fb-btn--solid.is-active.fb-btn--danger {
277
+ border-color: var(--fb-danger);
278
+ background: var(--fb-danger);
279
+ }
280
+
281
+ .fb-btn-wrap {
282
+ position: relative;
283
+ display: inline-flex;
284
+ }
285
+
286
+ .fb-btn__badge {
287
+ position: absolute;
288
+ top: -0.25rem;
289
+ right: -0.25rem;
290
+ display: flex;
291
+ align-items: center;
292
+ justify-content: center;
293
+ height: 1.25rem;
294
+ min-width: 1.25rem;
295
+ padding: 0 0.25rem;
296
+ border-radius: var(--fb-radius-full);
297
+ background: var(--fb-accent);
298
+ color: var(--fb-accent-contrast);
299
+ font-size: 10px;
300
+ font-weight: 600;
301
+ pointer-events: none;
302
+ }
303
+
304
+ /* ------------------------------------------------------------------- dock */
305
+
306
+ .fb-dock {
307
+ position: fixed;
308
+ right: 1.25rem;
309
+ bottom: 1.25rem;
310
+ z-index: calc(var(--fb-z) + 10);
311
+ display: flex;
312
+ align-items: center;
313
+ gap: 0.5rem;
314
+ }
315
+
316
+ .fb-dock__launcher {
317
+ cursor: grab;
318
+ touch-action: none;
319
+ }
320
+ .fb-dock__launcher:active {
321
+ cursor: grabbing;
322
+ }
323
+
324
+ /* The send button breathes while its request is in flight. */
325
+ .fb-dock__send.is-sending svg {
326
+ animation: fb-send-pulse 0.9s ease-in-out infinite;
327
+ }
328
+ @keyframes fb-send-pulse {
329
+ 50% {
330
+ opacity: 0.3;
331
+ }
332
+ }
333
+
334
+ /* ---------------------------------------------------------------- toolbar */
335
+
336
+ .fb-toolbar {
337
+ display: flex;
338
+ align-items: center;
339
+ gap: 0.25rem;
340
+ padding: 0.375rem 0.5rem;
341
+ border-radius: var(--fb-radius-full);
342
+ border: 1px solid var(--fb-border);
343
+ background: color-mix(in oklab, var(--fb-surface-overlay) 95%, transparent);
344
+ box-shadow: var(--fb-shadow);
345
+ backdrop-filter: blur(12px);
346
+ }
347
+
348
+ .fb-toolbar__divider {
349
+ width: 1px;
350
+ height: 1.25rem;
351
+ margin: 0 0.25rem;
352
+ background: var(--fb-border);
353
+ }
354
+
355
+ /* --------------------------------------------------------------- review */
356
+
357
+ .fb-reviewbar {
358
+ position: fixed;
359
+ top: 1rem;
360
+ left: 50%;
361
+ transform: translateX(-50%);
362
+ z-index: calc(var(--fb-z) + 10);
363
+ }
364
+
365
+ .fb-reviewbar__count {
366
+ min-width: 4rem;
367
+ text-align: center;
368
+ font-family: var(--fb-font-mono);
369
+ font-size: 0.75rem;
370
+ font-variant-numeric: tabular-nums;
371
+ color: var(--fb-text-secondary);
372
+ }
373
+
374
+ /* --------------------------------------------------------------- popover */
375
+
376
+ .fb-popover {
377
+ position: fixed;
378
+ z-index: calc(var(--fb-z) + 20);
379
+ width: 20rem;
380
+ max-width: calc(100vw - 24px);
381
+ padding: 1rem;
382
+ border-radius: var(--fb-radius-lg);
383
+ border: 1px solid var(--fb-border);
384
+ background: var(--fb-surface-raised);
385
+ box-shadow: var(--fb-shadow);
386
+ font-size: 0.875rem;
387
+ color: var(--fb-text-secondary);
388
+ }
389
+
390
+ /* ----------------------------------------------------------------- guide */
391
+
392
+ .fb-guide__header {
393
+ display: flex;
394
+ align-items: center;
395
+ justify-content: space-between;
396
+ margin-bottom: 0.5rem;
397
+ }
398
+
399
+ .fb-guide__title {
400
+ margin: 0;
401
+ font-size: 1rem;
402
+ font-weight: 600;
403
+ color: var(--fb-text);
404
+ }
405
+
406
+ .fb-guide__close {
407
+ display: inline-flex;
408
+ padding: 0.125rem;
409
+ border: 0;
410
+ background: transparent;
411
+ color: var(--fb-text-muted);
412
+ border-radius: var(--fb-radius-sm);
413
+ cursor: pointer;
414
+ transition: color var(--fb-dur);
415
+ }
416
+ .fb-guide__close:hover {
417
+ color: var(--fb-text);
418
+ }
419
+
420
+ .fb-guide__lead {
421
+ margin: 0 0 0.75rem;
422
+ color: var(--fb-text-secondary);
423
+ }
424
+
425
+ .fb-guide__steps {
426
+ display: flex;
427
+ flex-direction: column;
428
+ gap: 0.75rem;
429
+ margin: 0;
430
+ padding: 0;
431
+ list-style: none;
432
+ }
433
+
434
+ .fb-guide__step {
435
+ display: flex;
436
+ gap: 0.75rem;
437
+ }
438
+
439
+ .fb-guide__step-icon {
440
+ flex-shrink: 0;
441
+ margin-top: 0.125rem;
442
+ color: var(--fb-accent);
443
+ }
444
+
445
+ .fb-guide__step-text {
446
+ color: var(--fb-text-secondary);
447
+ }
448
+ .fb-guide__step-text b {
449
+ color: var(--fb-text);
450
+ }
451
+
452
+ .fb-guide__inline-icon {
453
+ display: inline-flex;
454
+ align-items: center;
455
+ justify-content: center;
456
+ vertical-align: middle;
457
+ width: 1.25rem;
458
+ height: 1.25rem;
459
+ margin: 0 0.125rem;
460
+ border-radius: var(--fb-radius-full);
461
+ border: 1px solid var(--fb-border);
462
+ background: var(--fb-surface-overlay);
463
+ color: var(--fb-text);
464
+ }
465
+ .fb-guide__inline-icon svg {
466
+ width: 0.875rem;
467
+ height: 0.875rem;
468
+ }
469
+
470
+ .fb-guide__knob {
471
+ display: block;
472
+ margin-top: 0.25rem;
473
+ width: 0.75rem;
474
+ height: 0.75rem;
475
+ border-radius: var(--fb-radius-full);
476
+ border: 1px solid var(--fb-accent);
477
+ background: var(--fb-surface-overlay);
478
+ }