htmlboard 0.1.0 → 0.3.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,407 @@
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
- }
35
-
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;
43
- }
44
-
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;
70
- }
1
+ /* HtmlBoard explorer. Its own dark chrome, so the designs stand out on the canvas. */
71
2
 
72
- .brand {
73
- display: flex;
74
- align-items: center;
75
- gap: 8px;
76
- cursor: pointer;
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');
77
9
  }
78
10
 
79
- .brand-logo {
80
- display: flex;
81
- align-items: center;
82
- justify-content: center;
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');
83
17
  }
84
18
 
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;
92
- }
19
+ /* One cool family of greys at the accent's hue (oklch 258, barely tinted), so the chrome sits with
20
+ the logo's blue and keeps out of the designs' way. Text colours pass WCAG AA on every surface. */
21
+ :root {
22
+ --x-canvas: #15171B; /* oklch(0.205 0.008 258) */
23
+ --x-panel: #1E2126; /* oklch(0.248 0.009 258) */
24
+ --x-raised: #282C30; /* oklch(0.29 0.01 258) */
25
+ --x-line: #36393F; /* oklch(0.345 0.011 258) */
26
+ --x-line-soft: #2B2E33; /* oklch(0.3 0.01 258): dividers inside a panel */
27
+ --x-text: #EDEEF1; /* 13.9:1 on the panel */
28
+ --x-text-soft: #A2A8B1; /* 6.7:1 */
29
+ --x-text-faint: #878D95; /* 4.8:1 */
30
+ --x-accent: #3D9DFF; /* the logo's pegs */
31
+ --x-accent-text: #8BC2FF; /* the accent as text: 8.7:1 */
32
+ --x-accent-wash: rgb(61 157 255 / 0.16);
33
+ --x-on-accent: #15171B; /* text on the accent: 6.4:1 (white would be 2.8:1) */
34
+ --x-wash: rgb(255 255 255 / 0.06);
35
+ --x-dot: rgb(255 255 255 / 0.1);
36
+ --x-live: #3DD68C;
37
+ --x-glass: color-mix(in srgb, var(--x-raised) 84%, transparent);
38
+ --x-float: inset 0 1px 0 rgb(255 255 255 / 0.05), 0 10px 32px rgb(0 0 0 / 0.5);
39
+ --font-ui: 'Inter', system-ui, sans-serif;
40
+ --font-display: 'Bricolage Grotesque', 'Inter', system-ui, sans-serif;
41
+ color-scheme: dark;
42
+ }
43
+
44
+ *, ::before, ::after { box-sizing: border-box; }
45
+
46
+ html, body { height: 100%; margin: 0; overflow: hidden; }
93
47
 
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);
48
+ body {
49
+ font-family: var(--font-ui);
101
50
  font-weight: 500;
102
- max-width: 220px;
103
- white-space: nowrap;
104
- overflow: hidden;
105
- text-overflow: ellipsis;
51
+ color: var(--x-text);
52
+ background: var(--x-canvas);
106
53
  }
107
54
 
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
- }
55
+ :focus-visible { outline: 2px solid var(--x-accent); outline-offset: 2px; }
116
56
 
117
- .filter-tab {
118
- background: transparent;
119
- border: none;
120
- color: var(--text-muted);
121
- font-size: 12px;
122
- font-weight: 500;
123
- padding: 5px 12px;
124
- border-radius: 6px;
125
- cursor: pointer;
126
- transition: all 0.15s ease;
127
- }
57
+ [hidden] { display: none !important; }
128
58
 
129
- .filter-tab:hover {
130
- color: var(--text-primary);
59
+ kbd {
60
+ display: inline-block;
61
+ min-width: 1.6em;
62
+ padding: 0 4px;
63
+ border: 1px solid var(--x-line);
64
+ border-radius: 4px;
65
+ background: var(--x-raised);
66
+ font: inherit;
67
+ font-size: 0.92em;
68
+ line-height: 1.5;
69
+ text-align: center;
131
70
  }
132
71
 
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
- }
72
+ .app { display: flex; height: 100%; }
139
73
 
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
- }
74
+ /* ---------- The list ---------- */
156
75
 
157
- .search-icon {
158
- color: var(--text-muted);
76
+ .sidebar {
77
+ display: flex;
78
+ flex-direction: column;
79
+ flex: none;
80
+ width: 272px;
81
+ border-right: 1px solid var(--x-line-soft);
82
+ background: var(--x-panel);
159
83
  }
160
84
 
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
- }
85
+ .app.is-collapsed .sidebar { display: none; }
171
86
 
172
- .search-box input::placeholder {
173
- color: var(--text-muted);
174
- }
87
+ /* htmlboard's own row: the logo (a link to the project) and the version */
88
+ .brand { display: flex; align-items: center; justify-content: space-between; gap: 8px; padding: 14px 16px 12px; border-bottom: 1px solid var(--x-line-soft); }
89
+ .brand-logo { display: block; border-radius: 4px; }
90
+ .brand-logo img { display: block; width: auto; height: 18px; }
91
+ .version { font-size: 11px; color: var(--x-text-faint); font-variant-numeric: tabular-nums; }
175
92
 
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);
181
- border-radius: 4px;
182
- padding: 2px 5px;
183
- color: var(--text-muted);
184
- }
93
+ /* The project's title, the count running on after its last word */
94
+ .sidebar-head { padding: 16px 16px 10px; }
95
+ .sidebar-head h1 { display: inline; margin: 0; font: 800 24px/1.1 var(--font-display); overflow-wrap: anywhere; }
96
+ .count { margin-left: 8px; font-size: 13px; color: var(--x-text-soft); white-space: nowrap; font-variant-numeric: tabular-nums; }
185
97
 
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
- }
98
+ .search { position: relative; margin: 0 12px 4px; }
196
99
 
197
- .zoom-level-text {
198
- font-size: 12px;
199
- font-family: var(--font-mono);
200
- color: var(--text-secondary);
201
- min-width: 44px;
202
- text-align: center;
203
- cursor: pointer;
204
- padding: 2px 4px;
205
- border-radius: 4px;
206
- }
207
-
208
- .zoom-level-text:hover {
209
- background: var(--bg-btn-hover);
210
- color: var(--text-primary);
100
+ .search svg {
101
+ position: absolute;
102
+ left: 9px;
103
+ top: 50%;
104
+ width: 15px;
105
+ height: 15px;
106
+ fill: none;
107
+ stroke: var(--x-text-faint);
108
+ stroke-width: 2;
109
+ stroke-linecap: round;
110
+ transform: translateY(-50%);
111
+ pointer-events: none;
211
112
  }
212
113
 
213
- /* Buttons */
214
- .btn-icon {
215
- width: 32px;
114
+ .search input {
115
+ width: 100%;
216
116
  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;
117
+ padding: 0 30px;
118
+ border: 1px solid var(--x-line-soft);
240
119
  border-radius: 6px;
241
- cursor: pointer;
242
- transition: all 0.15s ease;
120
+ background: var(--x-canvas);
121
+ color: var(--x-text);
122
+ font: inherit;
123
+ font-size: 13px;
243
124
  }
244
125
 
245
- .btn-text:hover {
246
- background: var(--bg-btn-hover);
247
- color: var(--text-primary);
248
- }
126
+ .search input::placeholder { color: var(--x-text-faint); opacity: 1; }
127
+ .search input:focus { border-color: var(--x-accent); outline: none; box-shadow: 0 0 0 3px var(--x-accent-wash); }
128
+ .search input::-webkit-search-cancel-button { appearance: none; }
249
129
 
250
- /* Live Indicator */
251
- .live-indicator {
252
- 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;
130
+ .search kbd {
131
+ position: absolute;
132
+ right: 7px;
133
+ top: 50%;
259
134
  font-size: 11px;
260
- font-weight: 600;
261
- color: var(--emerald);
262
- }
263
-
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
- }
272
-
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
- }
278
-
279
- .live-indicator.disconnected .live-dot {
280
- background: var(--rose);
281
- box-shadow: 0 0 8px var(--rose);
282
- animation: none;
135
+ color: var(--x-text-faint);
136
+ transform: translateY(-50%);
137
+ pointer-events: none;
283
138
  }
284
139
 
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
- }
140
+ /* The filters: all, the devices (and any other category), as chips that wrap */
141
+ .filters { display: flex; flex-wrap: wrap; gap: 4px; margin: 8px 12px 0; }
290
142
 
291
- /* Workspace Layout */
292
- .workspace {
293
- display: flex;
294
- flex: 1;
295
- position: relative;
296
- overflow: hidden;
143
+ .filter {
144
+ height: 26px;
145
+ padding: 0 10px;
146
+ border: 1px solid var(--x-line-soft);
147
+ border-radius: 13px;
148
+ background: none;
149
+ color: var(--x-text-soft);
150
+ font: inherit;
151
+ font-size: 12px;
152
+ cursor: pointer;
297
153
  }
298
154
 
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;
309
- }
155
+ .filter:hover:not(:disabled) { background: var(--x-wash); color: var(--x-text); }
156
+ .filter[aria-pressed='true'] { border-color: transparent; background: var(--x-accent-wash); color: var(--x-accent-text); }
157
+ .filter:disabled { color: var(--x-text-faint); border-style: dashed; cursor: default; }
310
158
 
311
- .sidebar.collapsed {
312
- margin-left: -260px;
313
- }
159
+ .search input:focus ~ kbd, .search input:not(:placeholder-shown) ~ kbd { display: none; }
314
160
 
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
- }
161
+ .list { flex: 1; overflow-y: auto; padding: 0 8px 16px; scrollbar-width: thin; scrollbar-color: var(--x-line) transparent; }
323
162
 
324
- .sidebar-heading {
325
- font-size: 11px;
326
- text-transform: uppercase;
327
- letter-spacing: 0.08em;
163
+ .list h2 {
164
+ margin: 18px 8px 4px;
165
+ font-size: 12px;
328
166
  font-weight: 700;
329
- color: var(--text-muted);
167
+ letter-spacing: 0.06em;
168
+ text-transform: uppercase;
169
+ color: var(--x-text-soft);
330
170
  }
331
171
 
332
- .sidebar-count {
333
- font-size: 11px;
334
- color: var(--text-muted);
335
- font-family: var(--font-mono);
336
- }
172
+ .list .section-desc { margin: -2px 8px 6px; font-size: 12px; line-height: 1.45; color: var(--x-text-soft); }
337
173
 
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
- }
174
+ .list ul { margin: 0; padding: 0; list-style: none; }
175
+ .list section > ul:first-child { margin-top: 12px; } /* a section without a title (the files at the top) */
346
176
 
347
- .sidebar-section-title {
348
- font-size: 11px;
349
- font-weight: 600;
350
- color: var(--text-muted);
351
- padding: 4px 8px;
352
- text-transform: uppercase;
353
- letter-spacing: 0.05em;
177
+ .item {
354
178
  display: flex;
355
- align-items: center;
179
+ align-items: baseline;
356
180
  justify-content: space-between;
357
- }
358
-
359
- .sidebar-items {
360
- display: flex;
361
- flex-direction: column;
362
- gap: 2px;
363
- margin-top: 4px;
364
- }
365
-
366
- .sidebar-item {
367
- display: flex;
368
- align-items: center;
369
- justify-content: space-between;
370
- padding: 8px 10px;
371
- border-radius: 6px;
372
- font-size: 13px;
373
- color: var(--text-secondary);
181
+ gap: 12px;
182
+ width: 100%;
183
+ padding: 6px 8px;
184
+ border: 0;
185
+ border-radius: 5px;
186
+ background: none;
187
+ color: inherit;
188
+ font: inherit;
189
+ font-size: 14px;
190
+ line-height: 20px;
191
+ text-align: left;
374
192
  cursor: pointer;
375
- transition: all 0.12s ease;
376
193
  }
377
194
 
378
- .sidebar-item:hover {
379
- background: var(--bg-btn-hover);
380
- color: var(--text-primary);
381
- }
195
+ .item:hover { background: var(--x-wash); }
196
+ .item[aria-current='true'] { background: var(--x-accent-wash); color: var(--x-text); }
197
+ .item .dims { flex: none; font-size: 12px; color: var(--x-text-faint); font-variant-numeric: tabular-nums; }
198
+ .item[aria-current='true'] .dims { color: var(--x-accent-text); }
382
199
 
383
- .sidebar-item.active {
384
- background: rgba(99, 102, 241, 0.15);
385
- color: var(--accent-light);
386
- font-weight: 500;
387
- }
200
+ .no-match { margin: 0; padding: 12px 16px 0; font-size: 13px; color: var(--x-text-soft); }
388
201
 
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);
202
+ .sidebar-hint {
203
+ margin: 0;
204
+ padding: 12px 16px 16px;
205
+ border-top: 1px solid var(--x-line-soft);
206
+ font-size: 12px;
207
+ line-height: 1.6;
208
+ color: var(--x-text-soft);
396
209
  }
397
210
 
398
- /* Canvas Viewport */
399
- .canvas-viewport {
400
- flex: 1;
211
+ /* ---------- The canvas ---------- */
212
+
213
+ .viewport {
401
214
  position: relative;
215
+ flex: 1;
402
216
  overflow: hidden;
403
- background: var(--bg-canvas);
404
- cursor: grab;
217
+ touch-action: none;
218
+ background-color: var(--x-canvas);
219
+ background-image: radial-gradient(circle at 1px 1px, var(--x-dot) 1px, transparent 0);
220
+ background-size: var(--grid, 32px) var(--grid, 32px);
221
+ outline: none;
405
222
  }
406
223
 
407
- .canvas-viewport.panning {
408
- cursor: grabbing;
409
- }
224
+ .viewport.is-panning, .viewport.is-panning * { cursor: grabbing; }
225
+ .viewport.is-space { cursor: grab; }
410
226
 
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
- }
227
+ .world { position: absolute; left: 0; top: 0; transform-origin: 0 0; }
429
228
 
430
- /* Canvas Content Layout */
431
- .canvas-content {
229
+ .frame {
432
230
  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);
231
+ background: #FFFFFF;
232
+ box-shadow: 0 1px 3px rgb(0 0 0 / 0.5), 0 12px 40px rgb(0 0 0 / 0.4);
460
233
  }
461
234
 
462
- .canvas-section-desc {
463
- font-size: 13px;
464
- color: var(--text-muted);
465
- }
235
+ /* The canvas takes every pointer event (wheel included, so Ctrl + scroll never zooms the page):
236
+ designs are pictures here, and Open shows one on its own. */
237
+ .frame iframe { display: block; width: 100%; height: 100%; border: 0; pointer-events: none; }
466
238
 
467
- .artboards-flow {
468
- display: flex;
469
- flex-wrap: nowrap;
470
- align-items: flex-start;
471
- gap: 48px;
472
- }
239
+ /* Designs the search leaves out stay in place, faded. */
240
+ .frame.is-dimmed { opacity: 0.2; }
473
241
 
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
- }
242
+ .overlay { position: absolute; inset: 0; overflow: hidden; pointer-events: none; }
486
243
 
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
- }
244
+ .label, .section-title, .outline, .size { position: absolute; left: 0; top: 0; }
491
245
 
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;
246
+ .label {
513
247
  overflow: hidden;
514
- }
515
-
516
- .artboard-title {
517
- font-size: 13px;
248
+ font-size: 12px;
518
249
  font-weight: 600;
250
+ line-height: 16px;
519
251
  white-space: nowrap;
520
- overflow: hidden;
521
252
  text-overflow: ellipsis;
522
- color: var(--text-primary);
253
+ color: var(--x-text-soft);
523
254
  }
524
255
 
525
- .artboard-badge {
526
- font-size: 10px;
527
- font-weight: 600;
528
- text-transform: uppercase;
256
+ .label.is-hover { color: var(--x-text); }
257
+ .label.is-selected { color: var(--x-accent); }
258
+ .label.is-dimmed { opacity: 0.35; }
259
+
260
+ .section-title { font: 700 20px/24px var(--font-display); letter-spacing: 0.01em; white-space: nowrap; color: var(--x-text); }
261
+
262
+ .outline--hover { box-shadow: 0 0 0 1px var(--x-accent); }
263
+ .outline--selected { box-shadow: 0 0 0 2px var(--x-accent); }
264
+
265
+ .size {
529
266
  padding: 2px 6px;
530
267
  border-radius: 4px;
531
- letter-spacing: 0.04em;
268
+ background: var(--x-accent);
269
+ color: var(--x-on-accent);
270
+ font-size: 11px;
271
+ font-weight: 600;
272
+ line-height: 14px;
273
+ white-space: nowrap;
274
+ font-variant-numeric: tabular-nums;
532
275
  }
533
276
 
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); }
277
+ /* ---------- Toolbar, shortcuts, messages ---------- */
539
278
 
540
- .artboard-actions {
279
+ .toolbar {
280
+ position: absolute;
281
+ bottom: 16px;
282
+ left: 50%;
541
283
  display: flex;
542
284
  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;
285
+ gap: 2px;
286
+ padding: 4px;
287
+ border: 1px solid var(--x-line);
288
+ border-radius: 10px;
289
+ background: var(--x-glass);
290
+ backdrop-filter: blur(16px) saturate(1.4);
291
+ box-shadow: var(--x-float);
292
+ transform: translateX(-50%);
551
293
  }
552
294
 
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;
295
+ .tool {
296
+ display: inline-flex;
561
297
  align-items: center;
562
298
  justify-content: center;
299
+ gap: 6px;
300
+ min-width: 34px;
301
+ height: 34px;
302
+ padding: 0 8px;
303
+ border: 0;
304
+ border-radius: 6px;
305
+ background: none;
306
+ color: var(--x-text);
307
+ font: inherit;
308
+ font-size: 13px;
309
+ text-decoration: none;
563
310
  cursor: pointer;
564
- transition: all 0.15s ease;
565
311
  }
566
312
 
567
- .artboard-btn:hover {
568
- background: var(--bg-btn-hover);
569
- color: var(--text-primary);
570
- }
313
+ .tool:hover { background: var(--x-wash); }
314
+ .tool[aria-pressed='true'] { color: var(--x-accent-text); }
315
+ .tool[aria-disabled='true'] { opacity: 0.4; pointer-events: none; }
571
316
 
572
- /* Artboard Iframe */
573
- .artboard-body {
574
- position: relative;
575
- background: #000;
576
- overflow: hidden;
577
- display: flex;
317
+ .tool svg {
318
+ width: 17px;
319
+ height: 17px;
320
+ fill: none;
321
+ stroke: currentColor;
322
+ stroke-width: 2;
323
+ stroke-linecap: round;
324
+ stroke-linejoin: round;
578
325
  }
579
326
 
580
- .artboard-iframe {
581
- border: none;
582
- background: #fff;
583
- display: block;
584
- }
327
+ .zoom { min-width: 58px; font-variant-numeric: tabular-nums; }
585
328
 
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
- }
329
+ .sep { width: 1px; height: 20px; margin: 0 4px; background: var(--x-line); }
594
330
 
595
- .pointer-shield.active {
596
- display: block;
597
- }
331
+ .live { display: inline-flex; align-items: center; gap: 6px; padding: 0 8px; font-size: 12px; color: var(--x-text-soft); }
332
+ .live::before { content: ''; width: 7px; height: 7px; border-radius: 50%; background: var(--x-live); }
333
+ .live.is-off::before { background: var(--x-text-faint); }
598
334
 
599
- /* Mini HUD */
600
- .canvas-hud {
335
+ .help {
601
336
  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);
337
+ right: 16px;
338
+ bottom: 72px;
339
+ width: min(340px, calc(100% - 32px));
340
+ padding: 14px 16px 10px;
341
+ border: 1px solid var(--x-line);
342
+ border-radius: 10px;
343
+ background: var(--x-glass);
344
+ backdrop-filter: blur(16px) saturate(1.4);
345
+ box-shadow: var(--x-float);
346
+ font-size: 13px;
625
347
  }
626
348
 
627
- .hud-sep {
628
- opacity: 0.4;
629
- }
349
+ .help h2 { margin: 0 0 8px; font: 700 18px/1.2 var(--font-display); }
350
+ .help dl { margin: 0; }
351
+ .help dl > div { display: flex; justify-content: space-between; gap: 12px; padding: 5px 0; border-top: 1px solid var(--x-line-soft); }
352
+ .help dt { color: var(--x-text-soft); }
353
+ .help dd { margin: 0; text-align: right; }
630
354
 
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;
355
+ .toast {
356
+ position: absolute;
357
+ top: 16px;
358
+ left: 50%;
359
+ max-width: calc(100% - 32px);
360
+ padding: 8px 14px;
361
+ border: 1px solid var(--x-line);
362
+ border-radius: 8px;
363
+ background: var(--x-glass);
364
+ backdrop-filter: blur(16px) saturate(1.4);
365
+ box-shadow: var(--x-float);
366
+ font-size: 13px;
367
+ white-space: nowrap;
368
+ overflow: hidden;
369
+ text-overflow: ellipsis;
641
370
  opacity: 0;
642
371
  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;
372
+ transform: translateX(-50%);
373
+ transition: opacity 0.2s;
668
374
  }
669
375
 
670
- .modal-header h2 {
671
- font-size: 18px;
672
- font-weight: 700;
673
- }
376
+ .toast.is-on { opacity: 1; }
674
377
 
675
- .shortcuts-grid {
676
- display: flex;
677
- flex-direction: column;
678
- gap: 12px;
378
+ .notice {
379
+ position: absolute;
380
+ inset: 0;
381
+ display: grid;
382
+ place-content: center;
383
+ gap: 8px;
384
+ padding: 32px;
385
+ background: var(--x-canvas);
386
+ font-size: 15px;
387
+ line-height: 1.6;
388
+ text-align: center;
679
389
  }
680
390
 
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
- }
391
+ .notice-mark { justify-self: center; width: auto; height: 72px; margin-bottom: 8px; }
392
+ .notice strong { font: 800 24px/1.2 var(--font-display); }
393
+ .notice p { max-width: 34em; margin: 0; color: var(--x-text-soft); }
394
+ .notice code { padding: 2px 6px; border-radius: 4px; background: var(--x-raised); color: var(--x-text); font-size: 14px; }
688
395
 
689
- .shortcut-keys {
690
- display: flex;
691
- align-items: center;
692
- gap: 6px;
396
+ /* Phones: the toolbar keeps its icons only. */
397
+ @media (max-width: 520px) {
398
+ .toolbar { bottom: 10px; }
399
+ .tool span { display: none; }
400
+ .zoom { min-width: 48px; }
401
+ .live { padding: 0 6px; font-size: 0; }
402
+ .help { bottom: 64px; }
693
403
  }
694
404
 
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);
405
+ @media (prefers-reduced-motion: reduce) {
406
+ .toast { transition: none; }
703
407
  }