htmlboard 0.1.0 → 0.2.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.
@@ -1,703 +1,372 @@
1
- /* HtmlBoard Explorer Theme */
2
- :root {
3
- --bg-app: #090a0f;
4
- --bg-topbar: rgba(14, 16, 24, 0.85);
5
- --bg-sidebar: #0e111a;
6
- --bg-canvas: #090b12;
7
- --bg-card: #131722;
8
- --bg-card-header: #171b29;
9
- --bg-btn: rgba(255, 255, 255, 0.05);
10
- --bg-btn-hover: rgba(255, 255, 255, 0.1);
11
- --border-subtle: #1c2132;
12
- --border-card: #282e44;
13
- --border-focus: #6366f1;
14
- --text-primary: #f8fafc;
15
- --text-secondary: #94a3b8;
16
- --text-muted: #64748b;
17
- --accent: #6366f1;
18
- --accent-glow: rgba(99, 102, 241, 0.35);
19
- --accent-light: #818cf8;
20
- --emerald: #10b981;
21
- --amber: #f59e0b;
22
- --rose: #f43f5e;
23
- --purple: #a855f7;
24
- --font-sans: 'Inter', -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
25
- --font-mono: 'JetBrains Mono', ui-monospace, SFMono-Regular, monospace;
26
- }
27
-
28
- * {
29
- box-sizing: border-box;
30
- margin: 0;
31
- padding: 0;
32
- user-select: none;
33
- -webkit-font-smoothing: antialiased;
34
- }
1
+ /* HtmlBoard explorer. Its own dark chrome, so the designs stand out on the canvas. */
35
2
 
36
- body {
37
- font-family: var(--font-sans);
38
- background: var(--bg-app);
39
- color: var(--text-primary);
40
- overflow: hidden;
41
- height: 100vh;
42
- width: 100vw;
3
+ @font-face {
4
+ font-family: 'Inter';
5
+ font-style: normal;
6
+ font-weight: 400 700;
7
+ font-display: swap;
8
+ src: url(fonts/inter.woff2) format('woff2');
43
9
  }
44
10
 
45
- #app {
46
- display: flex;
47
- flex-direction: column;
48
- height: 100vh;
49
- width: 100vw;
50
- }
51
-
52
- /* Topbar */
53
- .topbar {
54
- height: 52px;
55
- background: var(--bg-topbar);
56
- backdrop-filter: blur(16px);
57
- border-bottom: 1px solid var(--border-subtle);
58
- display: flex;
59
- align-items: center;
60
- justify-content: space-between;
61
- padding: 0 16px;
62
- z-index: 50;
63
- flex-shrink: 0;
64
- }
65
-
66
- .topbar-left, .topbar-center, .topbar-right {
67
- display: flex;
68
- align-items: center;
69
- gap: 12px;
11
+ @font-face {
12
+ font-family: 'Bricolage Grotesque';
13
+ font-style: normal;
14
+ font-weight: 500 800;
15
+ font-display: swap;
16
+ src: url(fonts/bricolage-grotesque.woff2) format('woff2');
70
17
  }
71
18
 
72
- .brand {
73
- display: flex;
74
- align-items: center;
75
- gap: 8px;
76
- cursor: pointer;
77
- }
78
-
79
- .brand-logo {
80
- display: flex;
81
- align-items: center;
82
- justify-content: center;
83
- }
84
-
85
- .brand-name {
86
- font-weight: 700;
87
- font-size: 15px;
88
- letter-spacing: -0.02em;
89
- background: linear-gradient(135deg, #fff 0%, #cbd5e1 100%);
90
- -webkit-background-clip: text;
91
- -webkit-text-fill-color: transparent;
19
+ :root {
20
+ --x-canvas: #1C1C1E;
21
+ --x-dot: rgb(255 255 255 / 0.09);
22
+ --x-panel: #252527;
23
+ --x-raised: #2E2E31;
24
+ --x-line: #3A3A3E;
25
+ --x-text: #EDEDEB;
26
+ --x-text-soft: #9D9DA3;
27
+ --x-accent: #3D9DFF;
28
+ --x-wash: rgb(255 255 255 / 0.07);
29
+ --x-live: #3DD68C;
30
+ --font-ui: 'Inter', system-ui, sans-serif;
31
+ --font-display: 'Bricolage Grotesque', 'Inter', system-ui, sans-serif;
32
+ color-scheme: dark;
92
33
  }
93
34
 
94
- .project-pill {
95
- background: rgba(255, 255, 255, 0.04);
96
- border: 1px solid var(--border-subtle);
97
- padding: 4px 10px;
98
- border-radius: 6px;
99
- font-size: 12px;
100
- color: var(--text-secondary);
101
- font-weight: 500;
102
- max-width: 220px;
103
- white-space: nowrap;
104
- overflow: hidden;
105
- text-overflow: ellipsis;
106
- }
35
+ *, ::before, ::after { box-sizing: border-box; }
107
36
 
108
- /* Category Filters */
109
- .filter-tabs {
110
- display: flex;
111
- background: rgba(0, 0, 0, 0.3);
112
- padding: 3px;
113
- border-radius: 8px;
114
- border: 1px solid var(--border-subtle);
115
- }
37
+ html, body { height: 100%; margin: 0; overflow: hidden; }
116
38
 
117
- .filter-tab {
118
- background: transparent;
119
- border: none;
120
- color: var(--text-muted);
121
- font-size: 12px;
39
+ body {
40
+ font-family: var(--font-ui);
122
41
  font-weight: 500;
123
- padding: 5px 12px;
124
- border-radius: 6px;
125
- cursor: pointer;
126
- transition: all 0.15s ease;
42
+ color: var(--x-text);
43
+ background: var(--x-canvas);
127
44
  }
128
45
 
129
- .filter-tab:hover {
130
- color: var(--text-primary);
131
- }
46
+ :focus-visible { outline: 2px solid var(--x-accent); outline-offset: 2px; }
132
47
 
133
- .filter-tab.active {
134
- background: var(--accent);
135
- color: #fff;
136
- font-weight: 600;
137
- box-shadow: 0 2px 8px var(--accent-glow);
138
- }
48
+ [hidden] { display: none !important; }
139
49
 
140
- /* Search Box */
141
- .search-box {
142
- display: flex;
143
- align-items: center;
144
- gap: 8px;
145
- background: rgba(0, 0, 0, 0.35);
146
- border: 1px solid var(--border-subtle);
147
- border-radius: 8px;
148
- padding: 5px 10px;
149
- position: relative;
150
- transition: border-color 0.15s ease;
151
- }
152
-
153
- .search-box:focus-within {
154
- border-color: var(--border-focus);
155
- }
156
-
157
- .search-icon {
158
- color: var(--text-muted);
159
- }
160
-
161
- .search-box input {
162
- background: transparent;
163
- border: none;
164
- outline: none;
165
- color: var(--text-primary);
166
- font-size: 12px;
167
- width: 140px;
168
- font-family: var(--font-sans);
169
- user-select: text;
170
- }
171
-
172
- .search-box input::placeholder {
173
- color: var(--text-muted);
174
- }
175
-
176
- .search-kbd {
177
- font-size: 10px;
178
- font-family: var(--font-mono);
179
- background: rgba(255, 255, 255, 0.08);
180
- border: 1px solid var(--border-subtle);
50
+ kbd {
51
+ display: inline-block;
52
+ min-width: 1.6em;
53
+ padding: 0 4px;
54
+ border: 1px solid var(--x-line);
181
55
  border-radius: 4px;
182
- padding: 2px 5px;
183
- color: var(--text-muted);
184
- }
185
-
186
- /* Zoom Controls */
187
- .zoom-controls {
188
- display: flex;
189
- align-items: center;
190
- gap: 4px;
191
- background: rgba(0, 0, 0, 0.35);
192
- border: 1px solid var(--border-subtle);
193
- border-radius: 8px;
194
- padding: 2px 6px;
195
- }
196
-
197
- .zoom-level-text {
198
- font-size: 12px;
199
- font-family: var(--font-mono);
200
- color: var(--text-secondary);
201
- min-width: 44px;
56
+ background: var(--x-raised);
57
+ font: inherit;
58
+ font-size: 0.92em;
59
+ line-height: 1.5;
202
60
  text-align: center;
203
- cursor: pointer;
204
- padding: 2px 4px;
205
- border-radius: 4px;
206
61
  }
207
62
 
208
- .zoom-level-text:hover {
209
- background: var(--bg-btn-hover);
210
- color: var(--text-primary);
211
- }
63
+ .app { display: flex; height: 100%; }
212
64
 
213
- /* Buttons */
214
- .btn-icon {
215
- width: 32px;
216
- height: 32px;
217
- border-radius: 7px;
218
- border: 1px solid transparent;
219
- background: transparent;
220
- color: var(--text-secondary);
221
- display: flex;
222
- align-items: center;
223
- justify-content: center;
224
- cursor: pointer;
225
- transition: all 0.15s ease;
226
- }
227
-
228
- .btn-icon:hover {
229
- background: var(--bg-btn-hover);
230
- color: var(--text-primary);
231
- }
232
-
233
- .btn-text {
234
- background: transparent;
235
- border: none;
236
- color: var(--text-secondary);
237
- font-size: 12px;
238
- font-weight: 500;
239
- padding: 5px 8px;
240
- border-radius: 6px;
241
- cursor: pointer;
242
- transition: all 0.15s ease;
243
- }
65
+ /* ---------- The list ---------- */
244
66
 
245
- .btn-text:hover {
246
- background: var(--bg-btn-hover);
247
- color: var(--text-primary);
248
- }
249
-
250
- /* Live Indicator */
251
- .live-indicator {
67
+ .sidebar {
252
68
  display: flex;
253
- align-items: center;
254
- gap: 6px;
255
- background: rgba(16, 185, 129, 0.1);
256
- border: 1px solid rgba(16, 185, 129, 0.25);
257
- padding: 4px 10px;
258
- border-radius: 20px;
259
- font-size: 11px;
260
- font-weight: 600;
261
- color: var(--emerald);
69
+ flex-direction: column;
70
+ flex: none;
71
+ width: 272px;
72
+ border-right: 1px solid var(--x-line);
73
+ background: var(--x-panel);
262
74
  }
263
75
 
264
- .live-dot {
265
- width: 7px;
266
- height: 7px;
267
- border-radius: 50%;
268
- background: var(--emerald);
269
- box-shadow: 0 0 8px var(--emerald);
270
- animation: pulse-live 2s infinite ease-in-out;
271
- }
76
+ .app.is-collapsed .sidebar { display: none; }
272
77
 
273
- .live-indicator.disconnected {
274
- background: rgba(244, 63, 94, 0.1);
275
- border-color: rgba(244, 63, 94, 0.25);
276
- color: var(--rose);
277
- }
78
+ /* htmlboard's own row: the logo (a link to the project) and the version */
79
+ .brand { display: flex; align-items: center; justify-content: space-between; gap: 8px; padding: 14px 16px 12px; border-bottom: 1px solid var(--x-line); }
80
+ .brand-logo { display: block; border-radius: 4px; }
81
+ .brand-logo img { display: block; width: auto; height: 18px; }
82
+ .version { font-size: 11px; color: var(--x-text-soft); font-variant-numeric: tabular-nums; }
278
83
 
279
- .live-indicator.disconnected .live-dot {
280
- background: var(--rose);
281
- box-shadow: 0 0 8px var(--rose);
282
- animation: none;
283
- }
84
+ .sidebar-head { display: flex; align-items: baseline; gap: 8px; padding: 16px 16px 10px; }
85
+ .sidebar-head h1 { min-width: 0; margin: 0; font: 800 24px/1.1 var(--font-display); overflow-wrap: anywhere; }
86
+ .count { flex: none; font-size: 13px; color: var(--x-text-soft); font-variant-numeric: tabular-nums; }
284
87
 
285
- @keyframes pulse-live {
286
- 0% { transform: scale(0.95); opacity: 0.8; }
287
- 50% { transform: scale(1.3); opacity: 1; }
288
- 100% { transform: scale(0.95); opacity: 0.8; }
289
- }
88
+ .search { position: relative; margin: 0 12px 4px; }
290
89
 
291
- /* Workspace Layout */
292
- .workspace {
293
- display: flex;
294
- flex: 1;
295
- position: relative;
296
- overflow: hidden;
297
- }
298
-
299
- /* Sidebar */
300
- .sidebar {
301
- width: 260px;
302
- background: var(--bg-sidebar);
303
- border-right: 1px solid var(--border-subtle);
304
- display: flex;
305
- flex-direction: column;
306
- flex-shrink: 0;
307
- transition: margin-left 0.2s cubic-bezier(0.16, 1, 0.3, 1);
308
- z-index: 40;
90
+ .search svg {
91
+ position: absolute;
92
+ left: 9px;
93
+ top: 50%;
94
+ width: 15px;
95
+ height: 15px;
96
+ fill: none;
97
+ stroke: var(--x-text-soft);
98
+ stroke-width: 2;
99
+ stroke-linecap: round;
100
+ transform: translateY(-50%);
101
+ pointer-events: none;
309
102
  }
310
103
 
311
- .sidebar.collapsed {
312
- margin-left: -260px;
104
+ .search input {
105
+ width: 100%;
106
+ height: 32px;
107
+ padding: 0 30px;
108
+ border: 1px solid var(--x-line);
109
+ border-radius: 6px;
110
+ background: var(--x-canvas);
111
+ color: var(--x-text);
112
+ font: inherit;
113
+ font-size: 13px;
313
114
  }
314
115
 
315
- .sidebar-header {
316
- height: 42px;
317
- border-bottom: 1px solid var(--border-subtle);
318
- display: flex;
319
- align-items: center;
320
- justify-content: space-between;
321
- padding: 0 16px;
322
- }
116
+ .search input::placeholder { color: var(--x-text-soft); opacity: 1; }
117
+ .search input:focus { border-color: var(--x-accent); outline: none; }
118
+ .search input::-webkit-search-cancel-button { appearance: none; }
323
119
 
324
- .sidebar-heading {
120
+ .search kbd {
121
+ position: absolute;
122
+ right: 7px;
123
+ top: 50%;
325
124
  font-size: 11px;
326
- text-transform: uppercase;
327
- letter-spacing: 0.08em;
328
- font-weight: 700;
329
- color: var(--text-muted);
125
+ color: var(--x-text-soft);
126
+ transform: translateY(-50%);
127
+ pointer-events: none;
330
128
  }
331
129
 
332
- .sidebar-count {
333
- font-size: 11px;
334
- color: var(--text-muted);
335
- font-family: var(--font-mono);
336
- }
130
+ .search input:focus ~ kbd, .search input:not(:placeholder-shown) ~ kbd { display: none; }
337
131
 
338
- .sidebar-tree {
339
- flex: 1;
340
- overflow-y: auto;
341
- padding: 12px 8px;
342
- display: flex;
343
- flex-direction: column;
344
- gap: 16px;
345
- }
132
+ .list { flex: 1; overflow-y: auto; padding: 0 8px 16px; }
346
133
 
347
- .sidebar-section-title {
348
- font-size: 11px;
349
- font-weight: 600;
350
- color: var(--text-muted);
351
- padding: 4px 8px;
134
+ .list h2 {
135
+ margin: 18px 8px 4px;
136
+ font-size: 12px;
137
+ font-weight: 700;
138
+ letter-spacing: 0.06em;
352
139
  text-transform: uppercase;
353
- letter-spacing: 0.05em;
354
- display: flex;
355
- align-items: center;
356
- justify-content: space-between;
140
+ color: var(--x-text-soft);
357
141
  }
358
142
 
359
- .sidebar-items {
360
- display: flex;
361
- flex-direction: column;
362
- gap: 2px;
363
- margin-top: 4px;
364
- }
143
+ .list .section-desc { margin: -2px 8px 6px; font-size: 12px; line-height: 1.45; color: var(--x-text-soft); }
144
+
145
+ .list ul { margin: 0; padding: 0; list-style: none; }
365
146
 
366
- .sidebar-item {
147
+ .item {
367
148
  display: flex;
368
- align-items: center;
149
+ align-items: baseline;
369
150
  justify-content: space-between;
370
- padding: 8px 10px;
371
- border-radius: 6px;
372
- font-size: 13px;
373
- color: var(--text-secondary);
151
+ gap: 12px;
152
+ width: 100%;
153
+ padding: 6px 8px;
154
+ border: 0;
155
+ border-radius: 5px;
156
+ background: none;
157
+ color: inherit;
158
+ font: inherit;
159
+ font-size: 14px;
160
+ line-height: 20px;
161
+ text-align: left;
374
162
  cursor: pointer;
375
- transition: all 0.12s ease;
376
163
  }
377
164
 
378
- .sidebar-item:hover {
379
- background: var(--bg-btn-hover);
380
- color: var(--text-primary);
381
- }
165
+ .item:hover { background: var(--x-wash); }
166
+ .item[aria-current='true'] { background: color-mix(in srgb, var(--x-accent) 24%, transparent); color: #fff; }
167
+ .item .dims { flex: none; font-size: 12px; color: var(--x-text-soft); font-variant-numeric: tabular-nums; }
382
168
 
383
- .sidebar-item.active {
384
- background: rgba(99, 102, 241, 0.15);
385
- color: var(--accent-light);
386
- font-weight: 500;
387
- }
169
+ .no-match { margin: 0; padding: 12px 16px 0; font-size: 13px; color: var(--x-text-soft); }
388
170
 
389
- .sidebar-item-badge {
390
- font-size: 10px;
391
- font-family: var(--font-mono);
392
- padding: 2px 6px;
393
- border-radius: 4px;
394
- background: rgba(255, 255, 255, 0.05);
395
- color: var(--text-muted);
171
+ .sidebar-hint {
172
+ margin: 0;
173
+ padding: 12px 16px 16px;
174
+ border-top: 1px solid var(--x-line);
175
+ font-size: 12px;
176
+ line-height: 1.6;
177
+ color: var(--x-text-soft);
396
178
  }
397
179
 
398
- /* Canvas Viewport */
399
- .canvas-viewport {
400
- flex: 1;
180
+ /* ---------- The canvas ---------- */
181
+
182
+ .viewport {
401
183
  position: relative;
184
+ flex: 1;
402
185
  overflow: hidden;
403
- background: var(--bg-canvas);
404
- cursor: grab;
186
+ touch-action: none;
187
+ background-color: var(--x-canvas);
188
+ background-image: radial-gradient(circle at 1px 1px, var(--x-dot) 1px, transparent 0);
189
+ background-size: var(--grid, 32px) var(--grid, 32px);
190
+ outline: none;
405
191
  }
406
192
 
407
- .canvas-viewport.panning {
408
- cursor: grabbing;
409
- }
193
+ .viewport.is-panning, .viewport.is-panning * { cursor: grabbing; }
194
+ .viewport.is-space { cursor: grab; }
410
195
 
411
- .canvas-stage {
412
- position: absolute;
413
- top: 0;
414
- left: 0;
415
- width: 100%;
416
- height: 100%;
417
- transform-origin: 0 0;
418
- will-change: transform;
419
- }
420
-
421
- /* Infinite Dot Grid */
422
- .canvas-grid {
423
- position: absolute;
424
- inset: -50000px;
425
- background-image: radial-gradient(circle, #22283a 1.2px, transparent 1.2px);
426
- background-size: 28px 28px;
427
- pointer-events: none;
428
- }
196
+ .world { position: absolute; left: 0; top: 0; transform-origin: 0 0; }
429
197
 
430
- /* Canvas Content Layout */
431
- .canvas-content {
198
+ .frame {
432
199
  position: absolute;
433
- top: 0;
434
- left: 0;
435
- /* Grow with the artboards instead of the viewport: each section is one row */
436
- width: max-content;
437
- padding: 80px;
438
- display: flex;
439
- flex-direction: column;
440
- gap: 64px;
441
- }
442
-
443
- .canvas-section {
444
- display: flex;
445
- flex-direction: column;
446
- gap: 24px;
447
- }
448
-
449
- .canvas-section-header {
450
- display: flex;
451
- flex-direction: column;
452
- gap: 4px;
453
- }
454
-
455
- .canvas-section-title {
456
- font-size: 22px;
457
- font-weight: 700;
458
- letter-spacing: -0.02em;
459
- color: var(--text-primary);
200
+ background: #FFFFFF;
201
+ box-shadow: 0 1px 3px rgb(0 0 0 / 0.45), 0 10px 40px rgb(0 0 0 / 0.35);
460
202
  }
461
203
 
462
- .canvas-section-desc {
463
- font-size: 13px;
464
- color: var(--text-muted);
465
- }
204
+ /* The canvas takes every pointer event (wheel included, so Ctrl + scroll never zooms the page):
205
+ designs are pictures here, and Open shows one on its own. */
206
+ .frame iframe { display: block; width: 100%; height: 100%; border: 0; pointer-events: none; }
466
207
 
467
- .artboards-flow {
468
- display: flex;
469
- flex-wrap: nowrap;
470
- align-items: flex-start;
471
- gap: 48px;
472
- }
208
+ /* Designs the search leaves out stay in place, faded. */
209
+ .frame.is-dimmed { opacity: 0.2; }
473
210
 
474
- /* Artboard Frame */
475
- .artboard-frame {
476
- flex: none;
477
- background: var(--bg-card);
478
- border: 1px solid var(--border-card);
479
- border-radius: 14px;
480
- box-shadow: 0 20px 40px -15px rgba(0, 0, 0, 0.6), 0 0 0 1px rgba(255, 255, 255, 0.03);
481
- display: flex;
482
- flex-direction: column;
483
- overflow: hidden;
484
- transition: box-shadow 0.2s ease, border-color 0.2s ease;
485
- }
211
+ .overlay { position: absolute; inset: 0; overflow: hidden; pointer-events: none; }
486
212
 
487
- .artboard-frame:hover {
488
- border-color: #3b4260;
489
- box-shadow: 0 24px 50px -12px rgba(0, 0, 0, 0.7), 0 0 20px var(--accent-glow);
490
- }
213
+ .label, .section-title, .outline, .size { position: absolute; left: 0; top: 0; }
491
214
 
492
- .artboard-frame.focused {
493
- border-color: var(--accent);
494
- box-shadow: 0 0 0 2px var(--accent), 0 24px 50px -12px rgba(99, 102, 241, 0.4);
495
- }
496
-
497
- /* Artboard Header */
498
- .artboard-header {
499
- height: 42px;
500
- background: var(--bg-card-header);
501
- border-bottom: 1px solid var(--border-subtle);
502
- display: flex;
503
- align-items: center;
504
- justify-content: space-between;
505
- padding: 0 14px;
506
- gap: 12px;
507
- }
508
-
509
- .artboard-title-group {
510
- display: flex;
511
- align-items: center;
512
- gap: 8px;
215
+ .label {
513
216
  overflow: hidden;
514
- }
515
-
516
- .artboard-title {
517
- font-size: 13px;
217
+ font-size: 12px;
518
218
  font-weight: 600;
219
+ line-height: 16px;
519
220
  white-space: nowrap;
520
- overflow: hidden;
521
221
  text-overflow: ellipsis;
522
- color: var(--text-primary);
222
+ color: var(--x-text-soft);
523
223
  }
524
224
 
525
- .artboard-badge {
526
- font-size: 10px;
527
- font-weight: 600;
528
- text-transform: uppercase;
225
+ .label.is-hover { color: var(--x-text); }
226
+ .label.is-selected { color: var(--x-accent); }
227
+ .label.is-dimmed { opacity: 0.35; }
228
+
229
+ .section-title { font: 700 20px/24px var(--font-display); letter-spacing: 0.01em; white-space: nowrap; color: var(--x-text); }
230
+
231
+ .outline--hover { box-shadow: 0 0 0 1px var(--x-accent); }
232
+ .outline--selected { box-shadow: 0 0 0 2px var(--x-accent); }
233
+
234
+ .size {
529
235
  padding: 2px 6px;
530
236
  border-radius: 4px;
531
- letter-spacing: 0.04em;
237
+ background: var(--x-accent);
238
+ color: #FFFFFF;
239
+ font-size: 11px;
240
+ font-weight: 600;
241
+ line-height: 14px;
242
+ white-space: nowrap;
243
+ font-variant-numeric: tabular-nums;
532
244
  }
533
245
 
534
- .badge-mobile { background: rgba(168, 85, 247, 0.18); color: #c084fc; border: 1px solid rgba(168, 85, 247, 0.3); }
535
- .badge-desktop { background: rgba(59, 130, 246, 0.18); color: #60a5fa; border: 1px solid rgba(59, 130, 246, 0.3); }
536
- .badge-tablet { background: rgba(16, 185, 129, 0.18); color: #34d399; border: 1px solid rgba(16, 185, 129, 0.3); }
537
- .badge-components { background: rgba(245, 158, 11, 0.18); color: #fbbf24; border: 1px solid rgba(245, 158, 11, 0.3); }
538
- .badge-responsive { background: rgba(99, 102, 241, 0.18); color: #a5b4fc; border: 1px solid rgba(99, 102, 241, 0.3); }
246
+ /* ---------- Toolbar, shortcuts, messages ---------- */
539
247
 
540
- .artboard-actions {
248
+ .toolbar {
249
+ position: absolute;
250
+ bottom: 16px;
251
+ left: 50%;
541
252
  display: flex;
542
253
  align-items: center;
543
- gap: 6px;
544
- }
545
-
546
- .artboard-dimensions {
547
- font-size: 11px;
548
- font-family: var(--font-mono);
549
- color: var(--text-muted);
550
- margin-right: 4px;
254
+ gap: 2px;
255
+ padding: 4px;
256
+ border: 1px solid var(--x-line);
257
+ border-radius: 10px;
258
+ background: var(--x-raised);
259
+ box-shadow: 0 8px 28px rgb(0 0 0 / 0.4);
260
+ transform: translateX(-50%);
551
261
  }
552
262
 
553
- .artboard-btn {
554
- width: 26px;
555
- height: 26px;
556
- border-radius: 6px;
557
- border: 1px solid transparent;
558
- background: transparent;
559
- color: var(--text-muted);
560
- display: flex;
263
+ .tool {
264
+ display: inline-flex;
561
265
  align-items: center;
562
266
  justify-content: center;
267
+ gap: 6px;
268
+ min-width: 34px;
269
+ height: 34px;
270
+ padding: 0 8px;
271
+ border: 0;
272
+ border-radius: 6px;
273
+ background: none;
274
+ color: var(--x-text);
275
+ font: inherit;
276
+ font-size: 13px;
277
+ text-decoration: none;
563
278
  cursor: pointer;
564
- transition: all 0.15s ease;
565
279
  }
566
280
 
567
- .artboard-btn:hover {
568
- background: var(--bg-btn-hover);
569
- color: var(--text-primary);
570
- }
281
+ .tool:hover { background: var(--x-wash); }
282
+ .tool[aria-pressed='true'] { color: var(--x-accent); }
283
+ .tool[aria-disabled='true'] { opacity: 0.4; pointer-events: none; }
571
284
 
572
- /* Artboard Iframe */
573
- .artboard-body {
574
- position: relative;
575
- background: #000;
576
- overflow: hidden;
577
- display: flex;
285
+ .tool svg {
286
+ width: 17px;
287
+ height: 17px;
288
+ fill: none;
289
+ stroke: currentColor;
290
+ stroke-width: 2;
291
+ stroke-linecap: round;
292
+ stroke-linejoin: round;
578
293
  }
579
294
 
580
- .artboard-iframe {
581
- border: none;
582
- background: #fff;
583
- display: block;
584
- }
295
+ .zoom { min-width: 58px; font-variant-numeric: tabular-nums; }
585
296
 
586
- /* Shield to prevent iframes capturing pointer events during canvas pan/drag */
587
- .pointer-shield {
588
- position: absolute;
589
- inset: 0;
590
- z-index: 30;
591
- display: none;
592
- cursor: inherit;
593
- }
297
+ .sep { width: 1px; height: 20px; margin: 0 4px; background: var(--x-line); }
594
298
 
595
- .pointer-shield.active {
596
- display: block;
597
- }
299
+ .live { display: inline-flex; align-items: center; gap: 6px; padding: 0 8px; font-size: 12px; color: var(--x-text-soft); }
300
+ .live::before { content: ''; width: 7px; height: 7px; border-radius: 50%; background: var(--x-live); }
301
+ .live.is-off::before { background: var(--x-text-soft); }
598
302
 
599
- /* Mini HUD */
600
- .canvas-hud {
303
+ .help {
601
304
  position: absolute;
602
- bottom: 16px;
603
- left: 50%;
604
- transform: translateX(-50%);
605
- background: rgba(14, 17, 26, 0.85);
606
- backdrop-filter: blur(12px);
607
- border: 1px solid var(--border-subtle);
608
- border-radius: 20px;
609
- padding: 6px 16px;
610
- display: flex;
611
- align-items: center;
612
- gap: 10px;
613
- font-size: 11px;
614
- color: var(--text-muted);
615
- pointer-events: none;
616
- z-index: 40;
617
- }
618
-
619
- .canvas-hud kbd {
620
- font-family: var(--font-mono);
621
- background: rgba(255, 255, 255, 0.1);
622
- padding: 2px 5px;
623
- border-radius: 4px;
624
- color: var(--text-secondary);
305
+ right: 16px;
306
+ bottom: 72px;
307
+ width: min(340px, calc(100% - 32px));
308
+ padding: 14px 16px 10px;
309
+ border: 1px solid var(--x-line);
310
+ border-radius: 10px;
311
+ background: var(--x-raised);
312
+ box-shadow: 0 8px 28px rgb(0 0 0 / 0.4);
313
+ font-size: 13px;
625
314
  }
626
315
 
627
- .hud-sep {
628
- opacity: 0.4;
629
- }
316
+ .help h2 { margin: 0 0 8px; font: 700 18px/1.2 var(--font-display); }
317
+ .help dl { margin: 0; }
318
+ .help dl > div { display: flex; justify-content: space-between; gap: 12px; padding: 5px 0; border-top: 1px solid var(--x-line); }
319
+ .help dt { color: var(--x-text-soft); }
320
+ .help dd { margin: 0; text-align: right; }
630
321
 
631
- /* Modal */
632
- .modal-backdrop {
633
- position: fixed;
634
- inset: 0;
635
- background: rgba(0, 0, 0, 0.7);
636
- backdrop-filter: blur(8px);
637
- display: flex;
638
- align-items: center;
639
- justify-content: center;
640
- z-index: 100;
322
+ .toast {
323
+ position: absolute;
324
+ top: 16px;
325
+ left: 50%;
326
+ max-width: calc(100% - 32px);
327
+ padding: 8px 14px;
328
+ border: 1px solid var(--x-line);
329
+ border-radius: 8px;
330
+ background: var(--x-raised);
331
+ font-size: 13px;
332
+ white-space: nowrap;
333
+ overflow: hidden;
334
+ text-overflow: ellipsis;
641
335
  opacity: 0;
642
336
  pointer-events: none;
643
- transition: opacity 0.2s ease;
644
- }
645
-
646
- .modal-backdrop.open {
647
- opacity: 1;
648
- pointer-events: auto;
649
- }
650
-
651
- .modal-card {
652
- width: 90%;
653
- max-width: 520px;
654
- background: var(--bg-card);
655
- border: 1px solid var(--border-card);
656
- border-radius: 16px;
657
- padding: 24px;
658
- box-shadow: 0 30px 60px -12px rgba(0, 0, 0, 0.8);
659
- }
660
-
661
- .modal-header {
662
- display: flex;
663
- align-items: center;
664
- justify-content: space-between;
665
- margin-bottom: 20px;
666
- border-bottom: 1px solid var(--border-subtle);
667
- padding-bottom: 12px;
337
+ transform: translateX(-50%);
338
+ transition: opacity 0.2s;
668
339
  }
669
340
 
670
- .modal-header h2 {
671
- font-size: 18px;
672
- font-weight: 700;
673
- }
341
+ .toast.is-on { opacity: 1; }
674
342
 
675
- .shortcuts-grid {
676
- display: flex;
677
- flex-direction: column;
678
- gap: 12px;
343
+ .notice {
344
+ position: absolute;
345
+ inset: 0;
346
+ display: grid;
347
+ place-content: center;
348
+ gap: 8px;
349
+ padding: 32px;
350
+ background: var(--x-canvas);
351
+ font-size: 15px;
352
+ line-height: 1.6;
353
+ text-align: center;
679
354
  }
680
355
 
681
- .shortcut-item {
682
- display: flex;
683
- align-items: center;
684
- justify-content: space-between;
685
- font-size: 13px;
686
- color: var(--text-secondary);
687
- }
356
+ .notice-mark { justify-self: center; width: auto; height: 72px; margin-bottom: 8px; }
357
+ .notice strong { font: 800 24px/1.2 var(--font-display); }
358
+ .notice p { max-width: 34em; margin: 0; color: var(--x-text-soft); }
359
+ .notice code { padding: 2px 6px; border-radius: 4px; background: var(--x-raised); color: var(--x-text); font-size: 14px; }
688
360
 
689
- .shortcut-keys {
690
- display: flex;
691
- align-items: center;
692
- gap: 6px;
361
+ /* Phones: the toolbar keeps its icons only. */
362
+ @media (max-width: 520px) {
363
+ .toolbar { bottom: 10px; }
364
+ .tool span { display: none; }
365
+ .zoom { min-width: 48px; }
366
+ .live { padding: 0 6px; font-size: 0; }
367
+ .help { bottom: 64px; }
693
368
  }
694
369
 
695
- .shortcut-keys kbd {
696
- font-family: var(--font-mono);
697
- background: rgba(255, 255, 255, 0.08);
698
- border: 1px solid var(--border-subtle);
699
- padding: 3px 7px;
700
- border-radius: 6px;
701
- font-size: 11px;
702
- color: var(--text-primary);
370
+ @media (prefers-reduced-motion: reduce) {
371
+ .toast { transition: none; }
703
372
  }