tui-cap 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/LICENSE +21 -0
- package/README.md +213 -0
- package/dist/anim.js +104 -0
- package/dist/animation.js +96 -0
- package/dist/asciinema.js +125 -0
- package/dist/cli.js +648 -0
- package/dist/edits.js +527 -0
- package/dist/fonts.js +87 -0
- package/dist/input.js +136 -0
- package/dist/meta.js +58 -0
- package/dist/palette.js +111 -0
- package/dist/parse.js +659 -0
- package/dist/paths.js +100 -0
- package/dist/record-pty.js +148 -0
- package/dist/record.js +100 -0
- package/dist/server.js +978 -0
- package/dist/svg.js +767 -0
- package/dist/timing.js +112 -0
- package/dist/types.js +2 -0
- package/dist/version.js +232 -0
- package/dist/web/app.js +3312 -0
- package/dist/web/fonts/MonaSansMonoVF-wght.woff2 +0 -0
- package/dist/web/fonts/MonaSansVF-wdth-wght-opsz.woff2 +0 -0
- package/dist/web/fonts/README.md +13 -0
- package/dist/web/index.html +382 -0
- package/dist/web/logo.svg +11 -0
- package/dist/web/styles.css +925 -0
- package/dist/web/timing-model.js +115 -0
- package/dist/web/vendor/mp4-muxer.LICENSE +21 -0
- package/dist/web/vendor/mp4-muxer.js +1885 -0
- package/package.json +61 -0
|
@@ -0,0 +1,925 @@
|
|
|
1
|
+
/* GitHub's Primer Brand typeface, bundled locally (see fonts/README.md) so the
|
|
2
|
+
GUI matches primer.style/brand offline without a runtime package dependency.
|
|
3
|
+
It upgrades the system font stack progressively — fallbacks render until the
|
|
4
|
+
variable font loads. */
|
|
5
|
+
@font-face {
|
|
6
|
+
font-family: "Mona Sans";
|
|
7
|
+
src: url("fonts/MonaSansVF-wdth-wght-opsz.woff2") format("woff2 supports variations"),
|
|
8
|
+
url("fonts/MonaSansVF-wdth-wght-opsz.woff2") format("woff2-variations");
|
|
9
|
+
font-weight: 200 900;
|
|
10
|
+
font-stretch: 75% 125%;
|
|
11
|
+
font-display: swap;
|
|
12
|
+
font-synthesis: none;
|
|
13
|
+
font-feature-settings: "liga" 0;
|
|
14
|
+
}
|
|
15
|
+
@font-face {
|
|
16
|
+
font-family: "Mona Sans Mono";
|
|
17
|
+
src: url("fonts/MonaSansMonoVF-wght.woff2") format("woff2 supports variations"),
|
|
18
|
+
url("fonts/MonaSansMonoVF-wght.woff2") format("woff2-variations");
|
|
19
|
+
font-weight: 200 900;
|
|
20
|
+
font-display: swap;
|
|
21
|
+
font-synthesis: none;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/* ============================================================================
|
|
25
|
+
Primer Brand design tokens (dark) — inlined from @primer/primitives and
|
|
26
|
+
@primer/react-brand so the GUI follows primer.style/brand without adding any
|
|
27
|
+
runtime package dependency. These mirror the look of the sibling
|
|
28
|
+
asset-generator and OctoCap projects.
|
|
29
|
+
========================================================================== */
|
|
30
|
+
:root {
|
|
31
|
+
/* Spacing scale — Primer base-size primitives (1rem = 16px) */
|
|
32
|
+
--space-1: 0.125rem; /* 2px */
|
|
33
|
+
--space-2: 0.25rem; /* 4px */
|
|
34
|
+
--space-3: 0.375rem; /* 6px */
|
|
35
|
+
--space-4: 0.5rem; /* 8px */
|
|
36
|
+
--space-5: 0.75rem; /* 12px */
|
|
37
|
+
--space-6: 1rem; /* 16px */
|
|
38
|
+
--space-7: 1.25rem; /* 20px */
|
|
39
|
+
--space-8: 1.5rem; /* 24px */
|
|
40
|
+
|
|
41
|
+
/* Neutral scale (dark) — Primer product functional greys (cool, no tint).
|
|
42
|
+
Brand green is reserved as an accent so chrome reads neutral, not washed. */
|
|
43
|
+
--scale-gray-2: #9198a1; /* fgColor-muted */
|
|
44
|
+
--scale-gray-5: #3d444d; /* borderColor-default */
|
|
45
|
+
--scale-gray-6: #262c36; /* control-bgColor-hover */
|
|
46
|
+
--scale-gray-7: #212830; /* control-bgColor-rest */
|
|
47
|
+
--scale-gray-8: #151b23; /* bgColor-muted (raised) */
|
|
48
|
+
--scale-gray-9: #0d1117; /* bgColor-default */
|
|
49
|
+
|
|
50
|
+
/* Surfaces — pure-black brand canvas; raised surfaces are neutral grey */
|
|
51
|
+
--bg: #000000; /* brand color-canvas-default */
|
|
52
|
+
--panel: #000000; /* chrome panels */
|
|
53
|
+
--panel-2: #212830; /* raised surface: default buttons / cards */
|
|
54
|
+
--input-bg: #0d1117; /* text fields / selects (neutral well) */
|
|
55
|
+
--elevated: #151b23; /* menus / floating popovers */
|
|
56
|
+
--inset: #010409; /* deep wells: previews, tracks */
|
|
57
|
+
--hover: #262c36; /* hover background (control hover) */
|
|
58
|
+
--active: #2a313c; /* pressed / active background (control active) */
|
|
59
|
+
--border: #3d444d; /* borderColor-default */
|
|
60
|
+
--border-muted: #2a313c;/* subtle divider */
|
|
61
|
+
|
|
62
|
+
/* Text */
|
|
63
|
+
--text: #f0f6fc; /* fgColor-default */
|
|
64
|
+
--muted: #9198a1; /* fgColor-muted */
|
|
65
|
+
|
|
66
|
+
/* Brand green accent — the signature Primer Brand color, used sparingly for
|
|
67
|
+
primary actions, the live "now" frame, progress and success. */
|
|
68
|
+
--accent: #2ea043; /* vibrant green: current / progress / spinner */
|
|
69
|
+
--accent-emphasis: #238636; /* primary action rest */
|
|
70
|
+
--accent-emphasis-hover: #2ea043;
|
|
71
|
+
--accent-fg: #ffffff;
|
|
72
|
+
--accent-bright: #5fed83; /* brand color-accent-primary highlight */
|
|
73
|
+
|
|
74
|
+
/* Blue — Primer interactive: toggles, sliders, active/selected, focus.
|
|
75
|
+
This is the product-Primer accent (matches the sibling asset-generator). */
|
|
76
|
+
--accent-blue: #1f6feb; /* control-checked / filled active */
|
|
77
|
+
--accent-blue-fg: #4493f8; /* fgColor-accent */
|
|
78
|
+
--knob: #262c36; /* toggle knob (off) */
|
|
79
|
+
--focus: #4493f8; /* focus ring */
|
|
80
|
+
--select: #4493f8; /* content-selection overlays */
|
|
81
|
+
|
|
82
|
+
/* Semantic */
|
|
83
|
+
--green: #3fb950;
|
|
84
|
+
--red: #fa383d; /* brand danger */
|
|
85
|
+
--gold: #db9d00; /* brand color-accent-secondary */
|
|
86
|
+
|
|
87
|
+
/* Radius / border width — brand primitives */
|
|
88
|
+
--radius: 0.5rem; /* brand borderRadius-medium (8px) */
|
|
89
|
+
--radius-sm: 0.25rem; /* brand borderRadius-small (4px) */
|
|
90
|
+
--radius-lg: 1rem; /* brand borderRadius-large (16px) */
|
|
91
|
+
--border-thin: max(1px, 0.0625rem);
|
|
92
|
+
|
|
93
|
+
/* Typography — Mona Sans with graceful system fallbacks */
|
|
94
|
+
--sans: "Mona Sans", "MonaSansFallback", -apple-system, BlinkMacSystemFont, "Segoe UI", "Noto Sans", Helvetica, Arial, sans-serif;
|
|
95
|
+
--mono: "Mona Sans Mono", ui-monospace, "SFMono-Regular", "SF Mono", Menlo, Consolas, "Liberation Mono", monospace;
|
|
96
|
+
|
|
97
|
+
/* Render native UI (scrollbars, form controls) in dark mode so every
|
|
98
|
+
scrollbar — including the timeline's horizontal one — matches the theme. */
|
|
99
|
+
color-scheme: dark;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
/* Consistent brand focus ring (blue) for keyboard navigation across controls. */
|
|
103
|
+
:where(button, input, select, textarea, a, [tabindex]):focus-visible {
|
|
104
|
+
outline: 2px solid var(--focus);
|
|
105
|
+
outline-offset: 1px;
|
|
106
|
+
border-radius: var(--radius-sm);
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
* { box-sizing: border-box; }
|
|
110
|
+
|
|
111
|
+
/* Range sliders use the Primer blue interactive accent. */
|
|
112
|
+
input[type="range"] { accent-color: var(--accent-blue); }
|
|
113
|
+
|
|
114
|
+
/* Checkboxes are restyled as Primer ToggleSwitch-style toggles (blue when on).
|
|
115
|
+
Pure CSS over the native <input type="checkbox"> — no markup or JS changes. */
|
|
116
|
+
input[type="checkbox"] {
|
|
117
|
+
appearance: none;
|
|
118
|
+
-webkit-appearance: none;
|
|
119
|
+
flex: none;
|
|
120
|
+
position: relative;
|
|
121
|
+
width: 28px;
|
|
122
|
+
height: 16px;
|
|
123
|
+
margin: 0;
|
|
124
|
+
border-radius: 999px;
|
|
125
|
+
background: var(--scale-gray-7);
|
|
126
|
+
border: var(--border-thin) solid var(--border);
|
|
127
|
+
cursor: pointer;
|
|
128
|
+
transition: background 0.15s ease, border-color 0.15s ease;
|
|
129
|
+
}
|
|
130
|
+
input[type="checkbox"]::before {
|
|
131
|
+
content: "";
|
|
132
|
+
position: absolute;
|
|
133
|
+
top: 50%;
|
|
134
|
+
left: 2px;
|
|
135
|
+
width: 10px;
|
|
136
|
+
height: 10px;
|
|
137
|
+
border-radius: 50%;
|
|
138
|
+
background: var(--knob);
|
|
139
|
+
transform: translateY(-50%);
|
|
140
|
+
transition: transform 0.15s ease, background 0.15s ease;
|
|
141
|
+
}
|
|
142
|
+
input[type="checkbox"]:hover { border-color: color-mix(in srgb, #ffffff 22%, var(--border)); }
|
|
143
|
+
input[type="checkbox"]:checked {
|
|
144
|
+
background: var(--accent-blue);
|
|
145
|
+
border-color: var(--accent-blue);
|
|
146
|
+
}
|
|
147
|
+
input[type="checkbox"]:checked::before {
|
|
148
|
+
background: #ffffff;
|
|
149
|
+
transform: translate(12px, -50%);
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
/* The app is a fixed shell: the page itself never scrolls. Panels and the
|
|
153
|
+
canvas own their overflow so content stays anchored around them. */
|
|
154
|
+
html, body { height: 100%; overflow: hidden; }
|
|
155
|
+
|
|
156
|
+
body {
|
|
157
|
+
margin: 0;
|
|
158
|
+
background: var(--bg);
|
|
159
|
+
color: var(--text);
|
|
160
|
+
font-family: var(--sans);
|
|
161
|
+
font-size: 14px;
|
|
162
|
+
-webkit-font-smoothing: antialiased;
|
|
163
|
+
-moz-osx-font-smoothing: grayscale;
|
|
164
|
+
text-rendering: optimizeLegibility;
|
|
165
|
+
display: flex;
|
|
166
|
+
flex-direction: column;
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
h1, h2 { margin: 0; font-weight: 600; }
|
|
170
|
+
h1 { font-size: 15px; letter-spacing: -0.01em; }
|
|
171
|
+
h2 { font-size: 12px; text-transform: uppercase; letter-spacing: 0.06em; color: var(--muted); }
|
|
172
|
+
|
|
173
|
+
.muted { color: var(--muted); }
|
|
174
|
+
.small { font-size: 12px; }
|
|
175
|
+
.hidden { display: none !important; }
|
|
176
|
+
|
|
177
|
+
/* Top bar */
|
|
178
|
+
.topbar {
|
|
179
|
+
display: grid;
|
|
180
|
+
grid-template-columns: 1fr auto 1fr;
|
|
181
|
+
align-items: center;
|
|
182
|
+
gap: var(--space-5);
|
|
183
|
+
padding: var(--space-5) var(--space-6);
|
|
184
|
+
border-bottom: var(--border-thin) solid var(--border);
|
|
185
|
+
background: var(--panel);
|
|
186
|
+
}
|
|
187
|
+
.brand { display: flex; align-items: center; gap: 10px; min-width: 0; }
|
|
188
|
+
.brand h1 { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
|
189
|
+
.brand .logo { width: 28px; height: 28px; display: block; flex: none; }
|
|
190
|
+
|
|
191
|
+
/* Canvas scale controls — stay centered in the header across viewport sizes. */
|
|
192
|
+
.view-scale { justify-self: center; display: flex; align-items: center; gap: 8px; }
|
|
193
|
+
.view-scale .zoom-range { width: 120px; }
|
|
194
|
+
.view-scale .zoom-pct {
|
|
195
|
+
min-width: 40px;
|
|
196
|
+
text-align: right;
|
|
197
|
+
font-variant-numeric: tabular-nums;
|
|
198
|
+
}
|
|
199
|
+
.view-scale .zoom-range:disabled { opacity: 0.45; }
|
|
200
|
+
.view-scale:has(.zoom-range:disabled) .zoom-pct { opacity: 0.45; }
|
|
201
|
+
.topbar > .btn-primary { justify-self: end; }
|
|
202
|
+
|
|
203
|
+
/* Update notice — a slim accent bar under the header when a newer release ships */
|
|
204
|
+
.update-banner {
|
|
205
|
+
display: flex;
|
|
206
|
+
align-items: center;
|
|
207
|
+
gap: var(--space-5);
|
|
208
|
+
padding: var(--space-4) var(--space-6);
|
|
209
|
+
border-bottom: var(--border-thin) solid var(--border);
|
|
210
|
+
background: color-mix(in srgb, var(--accent) 12%, var(--panel));
|
|
211
|
+
font-size: 13px;
|
|
212
|
+
}
|
|
213
|
+
.update-banner .ub-icon {
|
|
214
|
+
color: var(--accent-bright);
|
|
215
|
+
font-weight: 700;
|
|
216
|
+
flex: none;
|
|
217
|
+
}
|
|
218
|
+
.update-banner .ub-msg { flex: 1; min-width: 0; }
|
|
219
|
+
.update-banner .ub-actions { display: flex; align-items: center; gap: var(--space-4); flex: none; }
|
|
220
|
+
|
|
221
|
+
/* Layout */
|
|
222
|
+
.layout {
|
|
223
|
+
flex: 1;
|
|
224
|
+
display: grid;
|
|
225
|
+
grid-template-columns: 260px minmax(0, 1fr) 290px;
|
|
226
|
+
/* Bound the single row to the viewport so the row can't grow with its
|
|
227
|
+
content (a CSS-grid auto row would, forcing the whole page to scroll).
|
|
228
|
+
With the row clamped, each region scrolls within itself instead. */
|
|
229
|
+
grid-template-rows: minmax(0, 1fr);
|
|
230
|
+
min-height: 0;
|
|
231
|
+
}
|
|
232
|
+
.panel { border-right: var(--border-thin) solid var(--border); overflow-y: auto; min-height: 0; padding: var(--space-6); }
|
|
233
|
+
.settings { border-right: none; border-left: var(--border-thin) solid var(--border); }
|
|
234
|
+
.panel-head { display: flex; align-items: center; justify-content: space-between; gap: 8px; margin-bottom: var(--space-5); }
|
|
235
|
+
.panel-head-actions { display: flex; align-items: center; gap: 6px; flex: none; }
|
|
236
|
+
.lib-folder { color: var(--muted); }
|
|
237
|
+
.lib-folder:hover { background: var(--bg); color: var(--text); }
|
|
238
|
+
|
|
239
|
+
/* Library list */
|
|
240
|
+
.rec-list { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 4px; }
|
|
241
|
+
.rec-item {
|
|
242
|
+
border: 1px solid transparent;
|
|
243
|
+
border-radius: var(--radius);
|
|
244
|
+
padding: 8px 10px;
|
|
245
|
+
cursor: pointer;
|
|
246
|
+
display: flex;
|
|
247
|
+
align-items: center;
|
|
248
|
+
gap: 8px;
|
|
249
|
+
}
|
|
250
|
+
.rec-item:hover { background: var(--panel-2); }
|
|
251
|
+
.rec-item.active { background: color-mix(in srgb, var(--accent-blue) 14%, var(--panel-2)); border-color: var(--accent-blue); }
|
|
252
|
+
.rec-main { display: flex; flex-direction: column; gap: 2px; min-width: 0; flex: 1; }
|
|
253
|
+
.rec-item .name { font-family: var(--mono); font-size: 12.5px; word-break: break-all; }
|
|
254
|
+
.rec-item .meta { font-size: 11.5px; color: var(--muted); display: flex; gap: 8px; }
|
|
255
|
+
|
|
256
|
+
.rec-actions {
|
|
257
|
+
display: flex;
|
|
258
|
+
gap: 2px;
|
|
259
|
+
flex: none;
|
|
260
|
+
opacity: 0;
|
|
261
|
+
pointer-events: none;
|
|
262
|
+
transition: opacity 0.12s ease;
|
|
263
|
+
}
|
|
264
|
+
.rec-item:hover .rec-actions,
|
|
265
|
+
.rec-item.active .rec-actions,
|
|
266
|
+
.rec-actions:focus-within { opacity: 1; pointer-events: auto; }
|
|
267
|
+
.rec-act {
|
|
268
|
+
appearance: none;
|
|
269
|
+
border: none;
|
|
270
|
+
background: transparent;
|
|
271
|
+
color: var(--muted);
|
|
272
|
+
border-radius: 5px;
|
|
273
|
+
padding: 4px;
|
|
274
|
+
cursor: pointer;
|
|
275
|
+
display: inline-flex;
|
|
276
|
+
align-items: center;
|
|
277
|
+
justify-content: center;
|
|
278
|
+
line-height: 0;
|
|
279
|
+
}
|
|
280
|
+
.rec-act svg { width: 15px; height: 15px; display: block; }
|
|
281
|
+
.rec-act:hover { background: var(--bg); color: var(--text); }
|
|
282
|
+
.rec-act.danger:hover { background: color-mix(in srgb, var(--red) 22%, var(--bg)); color: var(--red); }
|
|
283
|
+
.empty { padding: 8px 2px; font-size: 12.5px; }
|
|
284
|
+
|
|
285
|
+
/* First-load library spinner so a slow scan of many captures doesn't look frozen. */
|
|
286
|
+
.lib-loading { display: flex; align-items: center; gap: 8px; padding: 10px 2px; font-size: 12.5px; }
|
|
287
|
+
.spinner {
|
|
288
|
+
flex: none;
|
|
289
|
+
width: 13px; height: 13px;
|
|
290
|
+
border: 2px solid var(--border);
|
|
291
|
+
border-top-color: var(--accent);
|
|
292
|
+
border-radius: 50%;
|
|
293
|
+
animation: spin 0.7s linear infinite;
|
|
294
|
+
}
|
|
295
|
+
@keyframes spin { to { transform: rotate(360deg); } }
|
|
296
|
+
@media (prefers-reduced-motion: reduce) { .spinner { animation: none; } }
|
|
297
|
+
|
|
298
|
+
/* Stage */
|
|
299
|
+
.stage { display: flex; flex-direction: column; min-width: 0; min-height: 0; padding: 14px; gap: 12px; }
|
|
300
|
+
.preview-wrap {
|
|
301
|
+
flex: 1;
|
|
302
|
+
min-height: 0;
|
|
303
|
+
display: flex;
|
|
304
|
+
align-items: center;
|
|
305
|
+
justify-content: center;
|
|
306
|
+
border: var(--border-thin) solid var(--border);
|
|
307
|
+
border-radius: var(--radius);
|
|
308
|
+
background-color: var(--inset);
|
|
309
|
+
background-image:
|
|
310
|
+
linear-gradient(45deg, var(--scale-gray-9) 25%, transparent 25%),
|
|
311
|
+
linear-gradient(-45deg, var(--scale-gray-9) 25%, transparent 25%),
|
|
312
|
+
linear-gradient(45deg, transparent 75%, var(--scale-gray-9) 75%),
|
|
313
|
+
linear-gradient(-45deg, transparent 75%, var(--scale-gray-9) 75%);
|
|
314
|
+
background-size: 20px 20px;
|
|
315
|
+
background-position: 0 0, 0 10px, 10px -10px, -10px 0;
|
|
316
|
+
overflow: auto;
|
|
317
|
+
padding: 24px;
|
|
318
|
+
}
|
|
319
|
+
.preview { max-width: 100%; max-height: 100%; object-fit: contain; }
|
|
320
|
+
.preview-wrap .empty { margin: auto; }
|
|
321
|
+
|
|
322
|
+
/* Scaled view (100% or any slider zoom): render the canvas at an explicit size
|
|
323
|
+
and let the wrap pan via scroll. margin:auto keeps it centered when it fits and
|
|
324
|
+
scroll-from-origin when it overflows. */
|
|
325
|
+
.preview-wrap.scaled { align-items: flex-start; justify-content: flex-start; }
|
|
326
|
+
.preview-wrap.scaled .preview { max-width: none; max-height: none; margin: auto; }
|
|
327
|
+
|
|
328
|
+
.frame-label { font-variant-numeric: tabular-nums; white-space: nowrap; }
|
|
329
|
+
|
|
330
|
+
/* Timeline — pinned to the bottom of the stage; the preview above it flexes and
|
|
331
|
+
scrolls, so the timeline stays anchored to the bottom of the viewport. */
|
|
332
|
+
.timeline { display: flex; flex-direction: column; gap: 8px; flex: 0 0 auto; }
|
|
333
|
+
.timeline-toolbar {
|
|
334
|
+
display: flex;
|
|
335
|
+
align-items: center;
|
|
336
|
+
gap: 8px;
|
|
337
|
+
flex-wrap: wrap;
|
|
338
|
+
}
|
|
339
|
+
.tl-group { display: flex; align-items: center; gap: 4px; }
|
|
340
|
+
.tl-spacer { flex: 1 1 auto; min-width: 8px; }
|
|
341
|
+
.tl-group.zoom { gap: 6px; }
|
|
342
|
+
.tl-group.zoom input[type="range"] { width: 120px; }
|
|
343
|
+
.tl-len { display: flex; align-items: center; gap: 4px; }
|
|
344
|
+
.tl-len input[type="number"] {
|
|
345
|
+
width: 68px;
|
|
346
|
+
background: var(--input-bg);
|
|
347
|
+
border: 1px solid var(--border);
|
|
348
|
+
color: var(--text);
|
|
349
|
+
border-radius: 5px;
|
|
350
|
+
padding: 4px 6px;
|
|
351
|
+
font: inherit;
|
|
352
|
+
font-size: 12px;
|
|
353
|
+
text-align: right;
|
|
354
|
+
font-variant-numeric: tabular-nums;
|
|
355
|
+
-moz-appearance: textfield;
|
|
356
|
+
}
|
|
357
|
+
.tl-len input::-webkit-outer-spin-button,
|
|
358
|
+
.tl-len input::-webkit-inner-spin-button { -webkit-appearance: none; margin: 0; }
|
|
359
|
+
.tl-group.selection { gap: 6px; }
|
|
360
|
+
.btn.small.danger { color: var(--red); border-color: color-mix(in srgb, var(--red) 35%, var(--border)); }
|
|
361
|
+
.btn.small.danger:hover { background: color-mix(in srgb, var(--red) 18%, var(--bg)); border-color: var(--red); }
|
|
362
|
+
|
|
363
|
+
.timeline-scroll {
|
|
364
|
+
position: relative;
|
|
365
|
+
overflow-x: auto;
|
|
366
|
+
overflow-y: hidden;
|
|
367
|
+
border: 1px solid var(--border);
|
|
368
|
+
border-radius: var(--radius);
|
|
369
|
+
background: var(--panel);
|
|
370
|
+
user-select: none;
|
|
371
|
+
}
|
|
372
|
+
.timeline-scroll.dragging { cursor: ew-resize; }
|
|
373
|
+
/* Shift-held / active brush selection: edges stop reading as resize handles. */
|
|
374
|
+
.timeline-scroll.selecting .timeline-track,
|
|
375
|
+
.timeline-scroll.selecting .tl-frame,
|
|
376
|
+
.timeline-scroll.selecting .tl-handle,
|
|
377
|
+
.timeline-scroll.shift-select .timeline-track,
|
|
378
|
+
.timeline-scroll.shift-select .tl-frame,
|
|
379
|
+
.timeline-scroll.shift-select .tl-handle { cursor: crosshair; }
|
|
380
|
+
.timeline-empty { position: absolute; inset: 0; margin: auto; height: max-content; text-align: center; }
|
|
381
|
+
|
|
382
|
+
/* Ruler — doubles as the scrubber: click or drag anywhere to seek. */
|
|
383
|
+
.timeline-ruler { position: relative; height: 18px; border-bottom: 1px solid var(--border); background: var(--panel-2); cursor: pointer; }
|
|
384
|
+
.timeline-ruler:hover { background: var(--hover); }
|
|
385
|
+
.tl-tick { position: absolute; top: 0; bottom: 0; border-left: 1px solid var(--border); pointer-events: none; }
|
|
386
|
+
.tl-tick > span { position: absolute; top: 1px; left: 3px; font-size: 9px; color: var(--muted); font-variant-numeric: tabular-nums; }
|
|
387
|
+
|
|
388
|
+
/* Track + frame blocks */
|
|
389
|
+
.timeline-track { position: relative; height: 76px; }
|
|
390
|
+
.tl-frame {
|
|
391
|
+
position: absolute;
|
|
392
|
+
top: 0;
|
|
393
|
+
bottom: 0;
|
|
394
|
+
overflow: hidden;
|
|
395
|
+
background: var(--panel);
|
|
396
|
+
border-right: 1px solid var(--border);
|
|
397
|
+
cursor: pointer;
|
|
398
|
+
}
|
|
399
|
+
.tl-frame:hover { background: var(--panel-2); }
|
|
400
|
+
/* Frames containing user typing are tinted green so typing is easy to scan.
|
|
401
|
+
When zoomed out each frame is only a pixel or two wide, so the 1px right-edge
|
|
402
|
+
divider dominates what's visible — tint that green (not just the background)
|
|
403
|
+
so typing sections read as solid green bands at any zoom. */
|
|
404
|
+
.tl-frame.is-typing {
|
|
405
|
+
background-color: color-mix(in srgb, var(--green) 30%, var(--panel));
|
|
406
|
+
border-right-color: var(--green);
|
|
407
|
+
}
|
|
408
|
+
.tl-frame.is-typing .tl-head {
|
|
409
|
+
background-color: color-mix(in srgb, var(--green) 28%, var(--panel-2));
|
|
410
|
+
color: color-mix(in srgb, var(--green) 45%, var(--text));
|
|
411
|
+
}
|
|
412
|
+
.tl-frame .tl-head {
|
|
413
|
+
height: 15px;
|
|
414
|
+
display: flex;
|
|
415
|
+
align-items: center;
|
|
416
|
+
gap: 4px;
|
|
417
|
+
padding: 0 4px;
|
|
418
|
+
font-size: 10px;
|
|
419
|
+
color: var(--muted);
|
|
420
|
+
background: var(--panel-2);
|
|
421
|
+
white-space: nowrap;
|
|
422
|
+
overflow: hidden;
|
|
423
|
+
}
|
|
424
|
+
.tl-frame .tl-prev {
|
|
425
|
+
display: block;
|
|
426
|
+
width: 100%;
|
|
427
|
+
height: calc(100% - 15px);
|
|
428
|
+
object-fit: contain;
|
|
429
|
+
object-position: top left;
|
|
430
|
+
background: var(--bg);
|
|
431
|
+
}
|
|
432
|
+
.tl-frame.current { z-index: 3; }
|
|
433
|
+
.tl-frame.selected { background: color-mix(in srgb, var(--select) 18%, var(--panel)); }
|
|
434
|
+
.tl-frame.selected .tl-head { color: var(--text); }
|
|
435
|
+
/* Selection / current outline is an overlay drawn above the preview image so the
|
|
436
|
+
accent border stays visible on wide frames that show a thumbnail (an inset
|
|
437
|
+
box-shadow on the frame itself paints below the opaque .tl-prev child). */
|
|
438
|
+
.tl-frame.selected::after,
|
|
439
|
+
.tl-frame.current::after {
|
|
440
|
+
content: "";
|
|
441
|
+
position: absolute;
|
|
442
|
+
inset: 0;
|
|
443
|
+
pointer-events: none;
|
|
444
|
+
}
|
|
445
|
+
.tl-frame.selected::after { box-shadow: inset 0 0 0 1px var(--select); }
|
|
446
|
+
.tl-frame.current::after,
|
|
447
|
+
.tl-frame.current.selected::after { box-shadow: inset 0 0 0 2px var(--accent); }
|
|
448
|
+
.tl-frame.overridden .tl-head { color: var(--accent); }
|
|
449
|
+
.tl-frame.overridden .tl-head::after { content: "•"; color: var(--accent); }
|
|
450
|
+
.tl-frame.excluded { opacity: 0.4; }
|
|
451
|
+
.tl-frame.excluded .tl-prev { filter: grayscale(0.6); }
|
|
452
|
+
.tl-frame.skipped {
|
|
453
|
+
opacity: 0.5;
|
|
454
|
+
background-image: repeating-linear-gradient(
|
|
455
|
+
-45deg,
|
|
456
|
+
transparent 0 5px,
|
|
457
|
+
color-mix(in srgb, var(--red) 30%, transparent) 5px 6px
|
|
458
|
+
);
|
|
459
|
+
}
|
|
460
|
+
.tl-frame.skipped .tl-head { color: var(--red); text-decoration: line-through; }
|
|
461
|
+
|
|
462
|
+
/* Resize handle sits on each block's right edge (the boundary you drag). */
|
|
463
|
+
.tl-handle { position: absolute; top: 0; bottom: 0; right: 0; width: 8px; cursor: ew-resize; z-index: 4; }
|
|
464
|
+
.tl-handle::after {
|
|
465
|
+
content: "";
|
|
466
|
+
position: absolute;
|
|
467
|
+
top: 0; bottom: 0; right: 0;
|
|
468
|
+
width: 1px;
|
|
469
|
+
background: transparent;
|
|
470
|
+
}
|
|
471
|
+
.tl-handle:hover::after { background: var(--accent); right: 0; width: 2px; }
|
|
472
|
+
|
|
473
|
+
/* Playhead */
|
|
474
|
+
.tl-playhead { position: absolute; top: 0; bottom: 0; width: 2px; background: var(--text); pointer-events: none; z-index: 5; }
|
|
475
|
+
.tl-playhead::before {
|
|
476
|
+
content: "";
|
|
477
|
+
position: absolute;
|
|
478
|
+
top: 0;
|
|
479
|
+
left: -3px;
|
|
480
|
+
border-left: 4px solid transparent;
|
|
481
|
+
border-right: 4px solid transparent;
|
|
482
|
+
border-top: 5px solid var(--text);
|
|
483
|
+
}
|
|
484
|
+
|
|
485
|
+
/* Fields */
|
|
486
|
+
.field { display: flex; flex-direction: column; gap: 5px; margin-bottom: 12px; font-size: 12.5px; }
|
|
487
|
+
.field > span { color: var(--muted); }
|
|
488
|
+
.field input[type="text"], .field input[type="number"], .field select {
|
|
489
|
+
background: var(--input-bg);
|
|
490
|
+
border: var(--border-thin) solid var(--border);
|
|
491
|
+
color: var(--text);
|
|
492
|
+
border-radius: 6px;
|
|
493
|
+
padding: var(--space-3) var(--space-4);
|
|
494
|
+
font: inherit;
|
|
495
|
+
transition: border-color 0.15s ease;
|
|
496
|
+
}
|
|
497
|
+
.field input[type="text"]:hover, .field input[type="number"]:hover, .field select:hover {
|
|
498
|
+
border-color: color-mix(in srgb, #ffffff 18%, var(--border));
|
|
499
|
+
}
|
|
500
|
+
.field input[type="text"]:focus, .field input[type="number"]:focus, .field select:focus {
|
|
501
|
+
border-color: var(--focus);
|
|
502
|
+
}
|
|
503
|
+
.field input[type="range"] { width: 100%; }
|
|
504
|
+
.field.checkbox { flex-direction: row; align-items: center; justify-content: flex-start; gap: 10px; }
|
|
505
|
+
.field.checkbox > span { color: var(--text); }
|
|
506
|
+
.field-row { display: grid; grid-template-columns: 1fr 1fr; gap: 10px; }
|
|
507
|
+
.reset-row { margin: -2px 0 14px; }
|
|
508
|
+
.recorded-size {
|
|
509
|
+
align-self: flex-start;
|
|
510
|
+
color: var(--text);
|
|
511
|
+
font: inherit;
|
|
512
|
+
font-variant-numeric: tabular-nums;
|
|
513
|
+
padding: 2px 0;
|
|
514
|
+
}
|
|
515
|
+
|
|
516
|
+
/* Buttons */
|
|
517
|
+
.btn {
|
|
518
|
+
appearance: none;
|
|
519
|
+
border: var(--border-thin) solid var(--border);
|
|
520
|
+
background: var(--panel-2);
|
|
521
|
+
color: var(--text);
|
|
522
|
+
border-radius: 6px;
|
|
523
|
+
padding: var(--space-3) var(--space-5);
|
|
524
|
+
font: inherit;
|
|
525
|
+
font-size: 13px;
|
|
526
|
+
font-weight: 600;
|
|
527
|
+
cursor: pointer;
|
|
528
|
+
text-decoration: none;
|
|
529
|
+
display: inline-flex;
|
|
530
|
+
align-items: center;
|
|
531
|
+
justify-content: center;
|
|
532
|
+
gap: var(--space-3);
|
|
533
|
+
transition: background 0.15s ease, border-color 0.15s ease;
|
|
534
|
+
}
|
|
535
|
+
.btn:hover { background: var(--hover); border-color: color-mix(in srgb, #ffffff 22%, var(--border)); }
|
|
536
|
+
.btn.small { padding: var(--space-2) var(--space-4); font-size: 12px; }
|
|
537
|
+
.btn.icon { padding: var(--space-3) var(--space-4); }
|
|
538
|
+
.btn.icon svg { width: 15px; height: 15px; display: block; }
|
|
539
|
+
.btn.block { width: 100%; }
|
|
540
|
+
.btn-primary { background: var(--accent-emphasis); border-color: var(--accent-emphasis); color: var(--accent-fg); }
|
|
541
|
+
.btn-primary:hover { background: var(--accent-emphasis-hover); border-color: var(--accent-emphasis-hover); }
|
|
542
|
+
.btn.active { background: var(--accent-blue); border-color: var(--accent-blue); color: #ffffff; }
|
|
543
|
+
.btn.active:hover { background: color-mix(in srgb, #ffffff 10%, var(--accent-blue)); border-color: var(--accent-blue); }
|
|
544
|
+
.btn:disabled, .btn.disabled { opacity: 0.45; pointer-events: none; }
|
|
545
|
+
|
|
546
|
+
.export { margin-top: 18px; display: flex; flex-direction: column; gap: 8px; }
|
|
547
|
+
.export-png { display: grid; grid-template-columns: 1fr auto; gap: 8px; }
|
|
548
|
+
.export-png .btn { width: 100%; }
|
|
549
|
+
.png-scale {
|
|
550
|
+
background: var(--input-bg);
|
|
551
|
+
border: 1px solid var(--border);
|
|
552
|
+
color: var(--text);
|
|
553
|
+
border-radius: 6px;
|
|
554
|
+
padding: 0 8px;
|
|
555
|
+
font: inherit;
|
|
556
|
+
font-size: 13px;
|
|
557
|
+
cursor: pointer;
|
|
558
|
+
}
|
|
559
|
+
.png-scale:disabled { opacity: 0.45; pointer-events: none; }
|
|
560
|
+
|
|
561
|
+
/* Dialog */
|
|
562
|
+
.dialog {
|
|
563
|
+
border: 1px solid var(--border);
|
|
564
|
+
border-radius: 12px;
|
|
565
|
+
background: var(--panel);
|
|
566
|
+
color: var(--text);
|
|
567
|
+
width: min(520px, 92vw);
|
|
568
|
+
padding: 20px;
|
|
569
|
+
}
|
|
570
|
+
.dialog::backdrop { background: rgba(0, 0, 0, 0.7); }
|
|
571
|
+
.dialog h2 { color: var(--text); text-transform: none; letter-spacing: 0; font-size: 16px; margin-bottom: 6px; }
|
|
572
|
+
.cmd-box {
|
|
573
|
+
display: flex;
|
|
574
|
+
align-items: center;
|
|
575
|
+
gap: 8px;
|
|
576
|
+
background: var(--bg);
|
|
577
|
+
border: 1px solid var(--border);
|
|
578
|
+
border-radius: 6px;
|
|
579
|
+
padding: 8px 10px;
|
|
580
|
+
margin: 12px 0;
|
|
581
|
+
}
|
|
582
|
+
.cmd-box code { font-family: var(--mono); font-size: 12.5px; flex: 1; word-break: break-all; color: var(--green); }
|
|
583
|
+
.dialog-actions { display: flex; justify-content: flex-end; gap: 8px; }
|
|
584
|
+
|
|
585
|
+
/* Animation panel */
|
|
586
|
+
.anim-head { margin-top: 22px; border-top: 1px solid var(--border); padding-top: 16px; }
|
|
587
|
+
.anim-note { margin: -2px 0 10px; }
|
|
588
|
+
.anim-meta { display: flex; align-items: center; justify-content: space-between; gap: 8px; margin: -2px 0 4px; min-height: 24px; }
|
|
589
|
+
#animLen { font-variant-numeric: tabular-nums; }
|
|
590
|
+
|
|
591
|
+
/* Play button toggles to a "stop/pause" look while running. */
|
|
592
|
+
.btn.icon.playing { background: var(--green); border-color: var(--green); color: #04150a; }
|
|
593
|
+
|
|
594
|
+
/* Export progress */
|
|
595
|
+
.progress { display: flex; align-items: center; gap: 8px; }
|
|
596
|
+
.progress-track { flex: 1; height: 6px; background: var(--bg); border: 1px solid var(--border); border-radius: 999px; overflow: hidden; }
|
|
597
|
+
.progress-bar { height: 100%; width: 0%; background: var(--accent); transition: width 0.1s linear; }
|
|
598
|
+
.progress-pct { min-width: 34px; text-align: right; font-variant-numeric: tabular-nums; }
|
|
599
|
+
|
|
600
|
+
/* Toast */
|
|
601
|
+
.toast {
|
|
602
|
+
position: fixed;
|
|
603
|
+
bottom: 18px;
|
|
604
|
+
left: 50%;
|
|
605
|
+
transform: translateX(-50%);
|
|
606
|
+
background: var(--panel-2);
|
|
607
|
+
border: 1px solid var(--border);
|
|
608
|
+
border-radius: 8px;
|
|
609
|
+
padding: 10px 16px;
|
|
610
|
+
font-size: 13px;
|
|
611
|
+
box-shadow: 0 8px 24px rgba(0, 0, 0, 0.5);
|
|
612
|
+
z-index: 10;
|
|
613
|
+
}
|
|
614
|
+
|
|
615
|
+
/* ------------------------------------------------------------ content edits */
|
|
616
|
+
|
|
617
|
+
.edit-toolbar {
|
|
618
|
+
display: flex;
|
|
619
|
+
align-items: center;
|
|
620
|
+
gap: 10px;
|
|
621
|
+
min-height: 28px;
|
|
622
|
+
flex-wrap: wrap;
|
|
623
|
+
}
|
|
624
|
+
.btn[aria-pressed="true"] {
|
|
625
|
+
background: var(--accent-blue);
|
|
626
|
+
border-color: var(--accent-blue);
|
|
627
|
+
color: #ffffff;
|
|
628
|
+
}
|
|
629
|
+
.edit-hint { flex: 1; min-width: 120px; }
|
|
630
|
+
.edit-tools { display: flex; align-items: center; gap: 8px; }
|
|
631
|
+
.btn.danger-text { color: var(--red); }
|
|
632
|
+
.btn.danger-text:hover { border-color: var(--red); }
|
|
633
|
+
|
|
634
|
+
/* Selection overlay sits exactly over the rendered <img>. */
|
|
635
|
+
.preview-wrap { position: relative; }
|
|
636
|
+
.sel-overlay {
|
|
637
|
+
position: absolute;
|
|
638
|
+
z-index: 4;
|
|
639
|
+
cursor: crosshair;
|
|
640
|
+
touch-action: none;
|
|
641
|
+
}
|
|
642
|
+
.sel-overlay.hidden { display: none; }
|
|
643
|
+
/* Eyedropper mode: let canvas clicks fall through the inline editor so any cell
|
|
644
|
+
is sampleable, and signal the picking cursor. */
|
|
645
|
+
.sel-overlay.eyedrop { cursor: crosshair; }
|
|
646
|
+
.sel-overlay.eyedrop .sel-editor { pointer-events: none; }
|
|
647
|
+
.sel-cell { position: absolute; pointer-events: none; border-radius: 2px; }
|
|
648
|
+
.sel-hover { background: color-mix(in srgb, var(--select) 22%, transparent); }
|
|
649
|
+
.sel-rect {
|
|
650
|
+
background: color-mix(in srgb, var(--select) 30%, transparent);
|
|
651
|
+
outline: 1px solid var(--select);
|
|
652
|
+
}
|
|
653
|
+
|
|
654
|
+
/* Live in-canvas text editor (sits over the selected block) */
|
|
655
|
+
.sel-editor {
|
|
656
|
+
position: absolute;
|
|
657
|
+
overflow: hidden;
|
|
658
|
+
z-index: 5;
|
|
659
|
+
outline: 1px solid var(--select);
|
|
660
|
+
box-shadow: 0 0 0 2px color-mix(in srgb, var(--select) 35%, transparent);
|
|
661
|
+
}
|
|
662
|
+
.sel-editor.hidden { display: none; }
|
|
663
|
+
.sel-edit-ghost {
|
|
664
|
+
position: absolute;
|
|
665
|
+
inset: 0;
|
|
666
|
+
pointer-events: none;
|
|
667
|
+
opacity: 0.3;
|
|
668
|
+
font-family: 'SFMono-Regular', 'SF Mono', Menlo, Consolas, 'Liberation Mono', monospace;
|
|
669
|
+
white-space: pre;
|
|
670
|
+
}
|
|
671
|
+
.sel-edit-text {
|
|
672
|
+
position: absolute;
|
|
673
|
+
inset: 0;
|
|
674
|
+
pointer-events: none;
|
|
675
|
+
font-family: 'SFMono-Regular', 'SF Mono', Menlo, Consolas, 'Liberation Mono', monospace;
|
|
676
|
+
white-space: pre;
|
|
677
|
+
}
|
|
678
|
+
.sel-edit-char {
|
|
679
|
+
position: absolute;
|
|
680
|
+
top: 0;
|
|
681
|
+
text-align: left;
|
|
682
|
+
overflow: hidden;
|
|
683
|
+
line-height: 1;
|
|
684
|
+
}
|
|
685
|
+
.sel-caret {
|
|
686
|
+
position: absolute;
|
|
687
|
+
top: 0;
|
|
688
|
+
width: 2px;
|
|
689
|
+
pointer-events: none;
|
|
690
|
+
background: currentColor;
|
|
691
|
+
animation: sel-caret-blink 1.06s steps(1, end) infinite;
|
|
692
|
+
}
|
|
693
|
+
.sel-caret.solid { animation: none; }
|
|
694
|
+
@keyframes sel-caret-blink {
|
|
695
|
+
0%, 50% { opacity: 1; }
|
|
696
|
+
50.01%, 100% { opacity: 0; }
|
|
697
|
+
}
|
|
698
|
+
.sel-input {
|
|
699
|
+
position: absolute;
|
|
700
|
+
inset: 0;
|
|
701
|
+
margin: 0;
|
|
702
|
+
padding: 0;
|
|
703
|
+
border: none;
|
|
704
|
+
background: transparent;
|
|
705
|
+
color: transparent;
|
|
706
|
+
caret-color: transparent;
|
|
707
|
+
outline: none;
|
|
708
|
+
font-family: 'SFMono-Regular', 'SF Mono', Menlo, Consolas, 'Liberation Mono', monospace;
|
|
709
|
+
white-space: pre;
|
|
710
|
+
}
|
|
711
|
+
.sel-input::selection { background: transparent; }
|
|
712
|
+
.ep-hint { margin: 0; line-height: 1.4; }
|
|
713
|
+
.ep-hint em { font-style: normal; color: var(--accent); }
|
|
714
|
+
|
|
715
|
+
/* Edits manager (right settings panel) */
|
|
716
|
+
.edits-section { margin-top: 18px; border-top: 1px solid var(--border); padding-top: 12px; }
|
|
717
|
+
.edits-head { margin-top: 2px; }
|
|
718
|
+
.edits-empty { margin: 0 0 8px; }
|
|
719
|
+
.edits-list { list-style: none; display: flex; flex-direction: column; gap: 6px; }
|
|
720
|
+
.edit-item {
|
|
721
|
+
display: flex;
|
|
722
|
+
align-items: center;
|
|
723
|
+
gap: 8px;
|
|
724
|
+
border: 1px solid var(--border);
|
|
725
|
+
border-radius: 6px;
|
|
726
|
+
background: var(--panel-2);
|
|
727
|
+
padding: 6px 8px;
|
|
728
|
+
font-size: 12px;
|
|
729
|
+
}
|
|
730
|
+
.edit-item .ei-main { flex: 1; min-width: 0; cursor: pointer; }
|
|
731
|
+
.edit-item .ei-kind {
|
|
732
|
+
display: inline-block;
|
|
733
|
+
font-size: 10px;
|
|
734
|
+
text-transform: uppercase;
|
|
735
|
+
letter-spacing: 0.04em;
|
|
736
|
+
color: var(--muted);
|
|
737
|
+
margin-right: 6px;
|
|
738
|
+
}
|
|
739
|
+
.edit-item .ei-text {
|
|
740
|
+
font-family: var(--mono);
|
|
741
|
+
white-space: nowrap;
|
|
742
|
+
overflow: hidden;
|
|
743
|
+
text-overflow: ellipsis;
|
|
744
|
+
display: inline-block;
|
|
745
|
+
max-width: 100%;
|
|
746
|
+
vertical-align: bottom;
|
|
747
|
+
}
|
|
748
|
+
.edit-item .ei-swatch {
|
|
749
|
+
width: 10px;
|
|
750
|
+
height: 10px;
|
|
751
|
+
border-radius: 2px;
|
|
752
|
+
border: 1px solid rgba(255, 255, 255, 0.25);
|
|
753
|
+
display: inline-block;
|
|
754
|
+
vertical-align: middle;
|
|
755
|
+
margin-left: 4px;
|
|
756
|
+
}
|
|
757
|
+
.edit-item .ei-remove {
|
|
758
|
+
appearance: none;
|
|
759
|
+
border: none;
|
|
760
|
+
background: transparent;
|
|
761
|
+
color: var(--muted);
|
|
762
|
+
cursor: pointer;
|
|
763
|
+
font-size: 14px;
|
|
764
|
+
line-height: 1;
|
|
765
|
+
padding: 2px 4px;
|
|
766
|
+
}
|
|
767
|
+
.edit-item .ei-remove:hover { color: var(--red); }
|
|
768
|
+
|
|
769
|
+
/* Edit popover */
|
|
770
|
+
.edit-popover {
|
|
771
|
+
position: fixed;
|
|
772
|
+
z-index: 30;
|
|
773
|
+
width: 280px;
|
|
774
|
+
max-width: calc(100vw - 24px);
|
|
775
|
+
background: var(--panel);
|
|
776
|
+
border: 1px solid var(--border);
|
|
777
|
+
border-radius: var(--radius);
|
|
778
|
+
box-shadow: 0 12px 32px rgba(0, 0, 0, 0.6);
|
|
779
|
+
padding: 12px;
|
|
780
|
+
display: flex;
|
|
781
|
+
flex-direction: column;
|
|
782
|
+
gap: 10px;
|
|
783
|
+
font-size: 12.5px;
|
|
784
|
+
}
|
|
785
|
+
.edit-popover.hidden { display: none; }
|
|
786
|
+
.ep-row { display: flex; align-items: center; gap: 8px; }
|
|
787
|
+
.ep-selected {
|
|
788
|
+
font-family: var(--mono);
|
|
789
|
+
background: var(--bg);
|
|
790
|
+
border: 1px solid var(--border);
|
|
791
|
+
border-radius: 4px;
|
|
792
|
+
padding: 2px 6px;
|
|
793
|
+
white-space: nowrap;
|
|
794
|
+
overflow: hidden;
|
|
795
|
+
text-overflow: ellipsis;
|
|
796
|
+
flex: 1;
|
|
797
|
+
}
|
|
798
|
+
.ep-field { display: flex; flex-direction: column; gap: 5px; }
|
|
799
|
+
.ep-field > span em { font-style: normal; }
|
|
800
|
+
.swatches { display: flex; flex-wrap: wrap; gap: 5px; }
|
|
801
|
+
.swatch {
|
|
802
|
+
width: 18px;
|
|
803
|
+
height: 18px;
|
|
804
|
+
border-radius: 4px;
|
|
805
|
+
border: 1px solid rgba(255, 255, 255, 0.18);
|
|
806
|
+
cursor: pointer;
|
|
807
|
+
padding: 0;
|
|
808
|
+
position: relative;
|
|
809
|
+
}
|
|
810
|
+
.swatch:hover { transform: scale(1.12); }
|
|
811
|
+
.swatch.selected { outline: 2px solid var(--select); outline-offset: 1px; }
|
|
812
|
+
.swatch.clear {
|
|
813
|
+
background:
|
|
814
|
+
linear-gradient(45deg, transparent 45%, var(--red) 45%, var(--red) 55%, transparent 55%),
|
|
815
|
+
var(--panel-2);
|
|
816
|
+
}
|
|
817
|
+
.ep-swatch-row { display: flex; align-items: center; gap: 7px; }
|
|
818
|
+
.ep-swatch-row .swatches { flex: 1; }
|
|
819
|
+
.btn-eyedrop {
|
|
820
|
+
flex: 0 0 auto;
|
|
821
|
+
display: inline-flex;
|
|
822
|
+
align-items: center;
|
|
823
|
+
justify-content: center;
|
|
824
|
+
width: 24px;
|
|
825
|
+
height: 24px;
|
|
826
|
+
padding: 0;
|
|
827
|
+
border-radius: 5px;
|
|
828
|
+
border: 1px solid var(--border);
|
|
829
|
+
background: var(--panel-2);
|
|
830
|
+
color: var(--text);
|
|
831
|
+
cursor: pointer;
|
|
832
|
+
}
|
|
833
|
+
.btn-eyedrop:hover { border-color: var(--select); }
|
|
834
|
+
.btn-eyedrop[aria-pressed='true'] {
|
|
835
|
+
background: color-mix(in srgb, var(--select) 30%, transparent);
|
|
836
|
+
border-color: var(--select);
|
|
837
|
+
color: var(--text);
|
|
838
|
+
}
|
|
839
|
+
.visually-hidden {
|
|
840
|
+
position: absolute;
|
|
841
|
+
width: 1px;
|
|
842
|
+
height: 1px;
|
|
843
|
+
margin: -1px;
|
|
844
|
+
padding: 0;
|
|
845
|
+
overflow: hidden;
|
|
846
|
+
clip: rect(0 0 0 0);
|
|
847
|
+
white-space: nowrap;
|
|
848
|
+
border: 0;
|
|
849
|
+
}
|
|
850
|
+
.ep-check { display: flex; align-items: center; gap: 7px; }
|
|
851
|
+
.ep-spacing-row { display: flex; align-items: center; gap: 10px; }
|
|
852
|
+
.ep-spacing-row .btn { min-width: 56px; }
|
|
853
|
+
.ep-actions { display: flex; align-items: center; gap: 8px; margin-top: 2px; }
|
|
854
|
+
.ep-actions .ep-spacer { flex: 1; }
|
|
855
|
+
|
|
856
|
+
/* Timing debug HUD */
|
|
857
|
+
.hud {
|
|
858
|
+
position: absolute;
|
|
859
|
+
top: 10px;
|
|
860
|
+
right: 10px;
|
|
861
|
+
z-index: 30;
|
|
862
|
+
min-width: 168px;
|
|
863
|
+
max-width: 280px;
|
|
864
|
+
padding: 8px 10px;
|
|
865
|
+
font-family: var(--mono);
|
|
866
|
+
font-size: 11px;
|
|
867
|
+
line-height: 1.5;
|
|
868
|
+
color: var(--text);
|
|
869
|
+
background: color-mix(in srgb, var(--bg) 82%, transparent);
|
|
870
|
+
border: 1px solid var(--border);
|
|
871
|
+
border-radius: 8px;
|
|
872
|
+
box-shadow: 0 4px 16px rgba(0, 0, 0, 0.45);
|
|
873
|
+
backdrop-filter: blur(6px);
|
|
874
|
+
pointer-events: none;
|
|
875
|
+
user-select: none;
|
|
876
|
+
}
|
|
877
|
+
.hud.hidden { display: none; }
|
|
878
|
+
.hud-row { display: flex; justify-content: space-between; gap: 12px; }
|
|
879
|
+
.hud-title { margin-bottom: 4px; padding-bottom: 4px; border-bottom: 1px solid var(--border); }
|
|
880
|
+
.hud-state { color: var(--muted); font-weight: 600; letter-spacing: 0.02em; }
|
|
881
|
+
.hud-state.live { color: var(--green); }
|
|
882
|
+
.hud-tag { color: var(--muted); text-transform: uppercase; font-size: 9.5px; letter-spacing: 0.08em; }
|
|
883
|
+
.hud-k { color: var(--muted); }
|
|
884
|
+
.hud-v { color: var(--text); font-variant-numeric: tabular-nums; }
|
|
885
|
+
.hud-v.warn { color: var(--red); }
|
|
886
|
+
.hud-foot { margin-top: 4px; padding-top: 4px; border-top: 1px solid var(--border); }
|
|
887
|
+
.hud-foot .hud-v { color: var(--muted); font-size: 10px; }
|
|
888
|
+
/* The HUD is a click-through overlay; re-enable pointer events on its controls. */
|
|
889
|
+
.hud-close {
|
|
890
|
+
pointer-events: auto;
|
|
891
|
+
appearance: none;
|
|
892
|
+
background: none;
|
|
893
|
+
border: none;
|
|
894
|
+
margin: -2px -2px 0 auto;
|
|
895
|
+
padding: 0 2px;
|
|
896
|
+
color: var(--muted);
|
|
897
|
+
font-size: 12px;
|
|
898
|
+
line-height: 1;
|
|
899
|
+
cursor: pointer;
|
|
900
|
+
}
|
|
901
|
+
.hud-close:hover { color: var(--text); }
|
|
902
|
+
.hud-actions { margin-top: 8px; pointer-events: auto; }
|
|
903
|
+
.hud-actions .btn { width: 100%; }
|
|
904
|
+
.hud .timing-result { pointer-events: auto; margin-top: 6px; font-size: 10.5px; }
|
|
905
|
+
|
|
906
|
+
/* Timing debug controls */
|
|
907
|
+
.timing-debug-link {
|
|
908
|
+
display: inline-block;
|
|
909
|
+
margin: 20px 0 4px;
|
|
910
|
+
padding: 4px 0;
|
|
911
|
+
appearance: none;
|
|
912
|
+
background: none;
|
|
913
|
+
border: none;
|
|
914
|
+
font: inherit;
|
|
915
|
+
font-size: 11px;
|
|
916
|
+
color: var(--muted);
|
|
917
|
+
cursor: pointer;
|
|
918
|
+
text-decoration: underline;
|
|
919
|
+
text-underline-offset: 2px;
|
|
920
|
+
}
|
|
921
|
+
.timing-debug-link:hover { color: var(--text); }
|
|
922
|
+
.timing-result { margin: 0; font-family: var(--mono); white-space: pre-wrap; }
|
|
923
|
+
.timing-result.hidden { display: none; }
|
|
924
|
+
.timing-result.ok { color: var(--green); }
|
|
925
|
+
.timing-result.warn { color: var(--red); }
|