@leverege/tpi-viz 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.
- package/README.md +62 -0
- package/package.json +30 -0
- package/src/main.js +2616 -0
- package/src/skeleton.js +99 -0
- package/src/standalone.js +18 -0
- package/src/styles/scene_viewer.css +926 -0
- package/src/styles/viewer_common.css +818 -0
|
@@ -0,0 +1,818 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* viewer_common.css - Shared styles for ply and flow viewers
|
|
3
|
+
*
|
|
4
|
+
* Palette is centralized in :root tokens so future tweaks land in one
|
|
5
|
+
* place. Per-component rules still use hex where they need a one-off,
|
|
6
|
+
* but anything semantic (bg, border, text, accent) goes through a var.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
:root {
|
|
10
|
+
/* Surfaces — layered darks, cool-tinted */
|
|
11
|
+
--bg-canvas: #0b0d14;
|
|
12
|
+
--bg-sidebar: #11141d;
|
|
13
|
+
--bg-panel: #161a26;
|
|
14
|
+
--bg-panel-strong: #1c2030;
|
|
15
|
+
--bg-hover: #1d2230;
|
|
16
|
+
--bg-active: #232a3d;
|
|
17
|
+
--bg-overlay: rgba(10, 12, 20, 0.88);
|
|
18
|
+
|
|
19
|
+
/* Borders — barely-there to subtly-visible */
|
|
20
|
+
--border-hairline: #1a1d28;
|
|
21
|
+
--border-subtle: #232733;
|
|
22
|
+
--border-strong: #2e3344;
|
|
23
|
+
|
|
24
|
+
/* Text scale */
|
|
25
|
+
--text-1: #e7e9ef; /* body / primary */
|
|
26
|
+
--text-2: #aab1c0; /* labels */
|
|
27
|
+
--text-3: #7b8294; /* secondary, counts */
|
|
28
|
+
--text-4: #6b7488; /* hints, disabled — bumped from #535a6b for legibility on dark bg */
|
|
29
|
+
|
|
30
|
+
/* Accents (paired w/ semantic uses across the app) */
|
|
31
|
+
--accent-blue: #7a9bff; /* elements / general info */
|
|
32
|
+
--accent-blue-soft: #5063a8;
|
|
33
|
+
--accent-pink: #ff95c2; /* flows */
|
|
34
|
+
--accent-pink-soft: #a8537a;
|
|
35
|
+
--accent-green: #7adea0; /* active step, success */
|
|
36
|
+
--accent-amber: #f0c34a; /* highlight, warning */
|
|
37
|
+
--accent-orange: #f0844a; /* active flow */
|
|
38
|
+
--accent-red: #ff7878; /* errors */
|
|
39
|
+
|
|
40
|
+
/* Motion */
|
|
41
|
+
--t-fast: 120ms cubic-bezier(0.4, 0, 0.2, 1);
|
|
42
|
+
--t-med: 200ms cubic-bezier(0.4, 0, 0.2, 1);
|
|
43
|
+
--t-slow: 300ms ease; /* collapse/expand animations */
|
|
44
|
+
|
|
45
|
+
/* Shape */
|
|
46
|
+
--r-sm: 4px;
|
|
47
|
+
--r-md: 6px;
|
|
48
|
+
--r-lg: 10px;
|
|
49
|
+
|
|
50
|
+
/* Shadows */
|
|
51
|
+
--shadow-soft: 0 2px 10px rgba(0, 0, 0, 0.35);
|
|
52
|
+
--shadow-med: 0 4px 18px rgba(0, 0, 0, 0.45);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/* Reset and base */
|
|
56
|
+
* { margin: 0; padding: 0; box-sizing: border-box; }
|
|
57
|
+
|
|
58
|
+
body {
|
|
59
|
+
font-family: 'Inter', 'Segoe UI', system-ui, -apple-system, sans-serif;
|
|
60
|
+
font-feature-settings: 'tnum' 1, 'cv11' 1; /* tabular numerals */
|
|
61
|
+
background: var(--bg-canvas);
|
|
62
|
+
color: var(--text-1);
|
|
63
|
+
height: 100vh;
|
|
64
|
+
overflow: hidden;
|
|
65
|
+
-webkit-font-smoothing: antialiased;
|
|
66
|
+
text-rendering: optimizeLegibility;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/* Subtle vignette over the canvas adds depth and pulls focus to the
|
|
70
|
+
center of the 3D scene without obscuring anything. */
|
|
71
|
+
.canvas-container::after {
|
|
72
|
+
content: '';
|
|
73
|
+
position: absolute;
|
|
74
|
+
inset: 0;
|
|
75
|
+
pointer-events: none;
|
|
76
|
+
background: radial-gradient(
|
|
77
|
+
ellipse at center,
|
|
78
|
+
transparent 55%,
|
|
79
|
+
rgba(0, 0, 0, 0.35) 100%
|
|
80
|
+
);
|
|
81
|
+
z-index: 5;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/* Custom scrollbars — thin, blend with the dark surface */
|
|
85
|
+
* {
|
|
86
|
+
scrollbar-width: thin;
|
|
87
|
+
scrollbar-color: var(--border-strong) transparent;
|
|
88
|
+
}
|
|
89
|
+
*::-webkit-scrollbar {
|
|
90
|
+
width: 8px;
|
|
91
|
+
height: 8px;
|
|
92
|
+
}
|
|
93
|
+
*::-webkit-scrollbar-track { background: transparent; }
|
|
94
|
+
*::-webkit-scrollbar-thumb {
|
|
95
|
+
background: var(--border-subtle);
|
|
96
|
+
border-radius: 999px;
|
|
97
|
+
border: 2px solid transparent;
|
|
98
|
+
background-clip: padding-box;
|
|
99
|
+
}
|
|
100
|
+
*::-webkit-scrollbar-thumb:hover {
|
|
101
|
+
background: var(--border-strong);
|
|
102
|
+
background-clip: padding-box;
|
|
103
|
+
border: 2px solid transparent;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
/* Selection styling */
|
|
107
|
+
::selection {
|
|
108
|
+
background: rgba(122, 155, 255, 0.32);
|
|
109
|
+
color: var(--text-1);
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
/* Focus ring for keyboard nav (subtle but visible) */
|
|
113
|
+
:focus-visible {
|
|
114
|
+
outline: 2px solid var(--accent-blue);
|
|
115
|
+
outline-offset: 2px;
|
|
116
|
+
border-radius: var(--r-sm);
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
/* Layout */
|
|
120
|
+
.container {
|
|
121
|
+
display: flex;
|
|
122
|
+
height: 100vh;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
.sidebar {
|
|
126
|
+
width: 280px;
|
|
127
|
+
background: var(--bg-sidebar);
|
|
128
|
+
border-right: 1px solid var(--border-subtle);
|
|
129
|
+
display: flex;
|
|
130
|
+
flex-direction: column;
|
|
131
|
+
overflow: hidden;
|
|
132
|
+
box-shadow: var(--shadow-soft);
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
.sidebar h3 {
|
|
136
|
+
padding: 12px 16px 11px;
|
|
137
|
+
background: linear-gradient(180deg, var(--bg-panel-strong) 0%, var(--bg-panel) 100%);
|
|
138
|
+
border-bottom: 1px solid var(--border-subtle);
|
|
139
|
+
font-size: 11px;
|
|
140
|
+
font-weight: 600;
|
|
141
|
+
letter-spacing: 0.08em;
|
|
142
|
+
text-transform: uppercase;
|
|
143
|
+
color: var(--text-2);
|
|
144
|
+
margin: 0;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
/* Sidebar header accent — left bar tied to viewer-specific color */
|
|
148
|
+
.sidebar h3 {
|
|
149
|
+
position: relative;
|
|
150
|
+
}
|
|
151
|
+
.sidebar h3::before {
|
|
152
|
+
content: '';
|
|
153
|
+
position: absolute;
|
|
154
|
+
left: 0; top: 8px; bottom: 8px;
|
|
155
|
+
width: 3px;
|
|
156
|
+
border-radius: 0 2px 2px 0;
|
|
157
|
+
background: var(--text-3);
|
|
158
|
+
opacity: 0.6;
|
|
159
|
+
}
|
|
160
|
+
.sidebar h3.accent-blue { color: var(--accent-blue); }
|
|
161
|
+
.sidebar h3.accent-blue::before { background: var(--accent-blue); opacity: 0.85; }
|
|
162
|
+
.sidebar h3.accent-red { color: var(--accent-pink); }
|
|
163
|
+
.sidebar h3.accent-red::before { background: var(--accent-pink); opacity: 0.85; }
|
|
164
|
+
|
|
165
|
+
.main-area {
|
|
166
|
+
flex: 1;
|
|
167
|
+
display: flex;
|
|
168
|
+
flex-direction: column;
|
|
169
|
+
min-height: 0;
|
|
170
|
+
overflow: hidden;
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
.canvas-container {
|
|
174
|
+
flex: 1;
|
|
175
|
+
position: relative;
|
|
176
|
+
min-height: 100px;
|
|
177
|
+
overflow: hidden;
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
#threeCanvas {
|
|
181
|
+
width: 100%;
|
|
182
|
+
height: 100%;
|
|
183
|
+
display: block;
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
/* Tree structure (for plies) */
|
|
187
|
+
.tree-list {
|
|
188
|
+
flex: 1;
|
|
189
|
+
overflow-y: auto;
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
.tree-ply {
|
|
193
|
+
border-bottom: 1px solid var(--border-hairline);
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
.tree-header {
|
|
197
|
+
padding: 10px 16px;
|
|
198
|
+
cursor: pointer;
|
|
199
|
+
background: var(--bg-panel);
|
|
200
|
+
font-size: 12.5px;
|
|
201
|
+
font-weight: 600;
|
|
202
|
+
color: var(--text-1);
|
|
203
|
+
display: flex;
|
|
204
|
+
justify-content: space-between;
|
|
205
|
+
align-items: center;
|
|
206
|
+
user-select: none;
|
|
207
|
+
transition: background var(--t-fast);
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
.tree-header:hover { background: var(--bg-hover); }
|
|
211
|
+
|
|
212
|
+
.tree-header .arrow {
|
|
213
|
+
transition: transform var(--t-med);
|
|
214
|
+
font-size: 10px;
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
.tree-header.collapsed .arrow {
|
|
218
|
+
transform: rotate(-90deg);
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
.tree-content {
|
|
222
|
+
max-height: 800px;
|
|
223
|
+
overflow: hidden;
|
|
224
|
+
transition: max-height var(--t-slow);
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
.tree-content.collapsed {
|
|
228
|
+
max-height: 0;
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
/* Camera level in tree */
|
|
232
|
+
.tree-camera {
|
|
233
|
+
padding-left: 15px;
|
|
234
|
+
border-top: 1px solid var(--border-hairline);
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
.tree-camera-header {
|
|
238
|
+
padding: 8px 15px;
|
|
239
|
+
cursor: pointer;
|
|
240
|
+
font-size: 12px;
|
|
241
|
+
color: var(--text-2);
|
|
242
|
+
display: flex;
|
|
243
|
+
justify-content: space-between;
|
|
244
|
+
align-items: center;
|
|
245
|
+
user-select: none;
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
.tree-camera-header:hover { background: var(--bg-hover); }
|
|
249
|
+
|
|
250
|
+
.tree-camera-content {
|
|
251
|
+
padding-left: 15px;
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
/* Step level in tree */
|
|
255
|
+
.tree-step {
|
|
256
|
+
padding: 6px 15px;
|
|
257
|
+
cursor: pointer;
|
|
258
|
+
font-size: 11px;
|
|
259
|
+
color: var(--text-3);
|
|
260
|
+
display: flex;
|
|
261
|
+
justify-content: space-between;
|
|
262
|
+
user-select: none;
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
.tree-step { transition: background var(--t-fast), color var(--t-fast); }
|
|
266
|
+
.tree-step:hover { background: var(--bg-hover); color: var(--text-2); }
|
|
267
|
+
|
|
268
|
+
.tree-step.active {
|
|
269
|
+
background: linear-gradient(90deg, rgba(122, 222, 160, 0.18) 0%, transparent 100%);
|
|
270
|
+
color: var(--accent-green);
|
|
271
|
+
border-left: 3px solid var(--accent-green);
|
|
272
|
+
padding-left: 12px; /* compensate for the 3px border */
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
.tree-step .badge {
|
|
276
|
+
background: var(--bg-panel-strong);
|
|
277
|
+
border: 1px solid var(--border-subtle);
|
|
278
|
+
padding: 2px 8px;
|
|
279
|
+
border-radius: 999px;
|
|
280
|
+
font-size: 10px;
|
|
281
|
+
color: var(--text-3);
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
/* Flow list (flat list for flows) */
|
|
285
|
+
.flow-list {
|
|
286
|
+
flex: 1;
|
|
287
|
+
overflow-y: auto;
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
.flow-item {
|
|
291
|
+
padding: 10px 16px;
|
|
292
|
+
cursor: pointer;
|
|
293
|
+
border-bottom: 1px solid var(--border-hairline);
|
|
294
|
+
display: flex;
|
|
295
|
+
flex-direction: column;
|
|
296
|
+
gap: 4px;
|
|
297
|
+
transition: background var(--t-fast), border-color var(--t-fast);
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
.flow-item:hover { background: var(--bg-hover); }
|
|
301
|
+
|
|
302
|
+
.flow-item.active {
|
|
303
|
+
background: linear-gradient(90deg, rgba(255, 149, 194, 0.14) 0%, transparent 100%);
|
|
304
|
+
border-left: 3px solid var(--accent-pink);
|
|
305
|
+
padding-left: 13px; /* compensate for the 3px border */
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
.flow-item .flow-name { font-size: 12px; font-weight: 500; color: var(--text-1); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
|
309
|
+
.flow-item .flow-stats { font-size: 10px; color: var(--text-3); }
|
|
310
|
+
|
|
311
|
+
/* Controls (top-right) */
|
|
312
|
+
.controls {
|
|
313
|
+
position: absolute;
|
|
314
|
+
top: 12px;
|
|
315
|
+
right: 12px;
|
|
316
|
+
background: var(--bg-overlay);
|
|
317
|
+
backdrop-filter: blur(8px);
|
|
318
|
+
-webkit-backdrop-filter: blur(8px);
|
|
319
|
+
border: 1px solid var(--border-subtle);
|
|
320
|
+
padding: 10px;
|
|
321
|
+
border-radius: var(--r-md);
|
|
322
|
+
font-size: 11px;
|
|
323
|
+
display: flex;
|
|
324
|
+
gap: 6px;
|
|
325
|
+
z-index: 10;
|
|
326
|
+
flex-wrap: wrap;
|
|
327
|
+
max-width: 400px;
|
|
328
|
+
box-shadow: var(--shadow-med);
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
/* Buttons */
|
|
332
|
+
.btn {
|
|
333
|
+
padding: 6px 12px;
|
|
334
|
+
background: var(--bg-panel);
|
|
335
|
+
border: 1px solid var(--border-subtle);
|
|
336
|
+
color: var(--text-2);
|
|
337
|
+
font-size: 11px;
|
|
338
|
+
font-weight: 500;
|
|
339
|
+
cursor: pointer;
|
|
340
|
+
border-radius: var(--r-sm);
|
|
341
|
+
transition: background var(--t-fast), color var(--t-fast), border-color var(--t-fast),
|
|
342
|
+
transform var(--t-fast);
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
.btn:hover {
|
|
346
|
+
background: var(--bg-hover);
|
|
347
|
+
color: var(--text-1);
|
|
348
|
+
border-color: var(--border-strong);
|
|
349
|
+
}
|
|
350
|
+
.btn:active { transform: translateY(1px); }
|
|
351
|
+
.btn.active {
|
|
352
|
+
background: var(--bg-active);
|
|
353
|
+
color: var(--accent-blue);
|
|
354
|
+
border-color: var(--accent-blue-soft);
|
|
355
|
+
box-shadow: 0 0 0 1px rgba(122, 155, 255, 0.18);
|
|
356
|
+
}
|
|
357
|
+
.btn.active.accent-red {
|
|
358
|
+
color: var(--accent-pink);
|
|
359
|
+
border-color: var(--accent-pink-soft);
|
|
360
|
+
box-shadow: 0 0 0 1px rgba(255, 149, 194, 0.18);
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
/* Step navigation (for flows) */
|
|
364
|
+
.step-nav {
|
|
365
|
+
display: flex;
|
|
366
|
+
align-items: center;
|
|
367
|
+
justify-content: center;
|
|
368
|
+
gap: 15px;
|
|
369
|
+
margin-top: 8px;
|
|
370
|
+
padding-top: 8px;
|
|
371
|
+
border-top: 1px solid var(--border-subtle);
|
|
372
|
+
width: 100%;
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
.step-nav .btn {
|
|
376
|
+
font-size: 14px;
|
|
377
|
+
padding: 6px 14px;
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
.step-nav .step-info {
|
|
381
|
+
font-size: 13px;
|
|
382
|
+
font-weight: bold;
|
|
383
|
+
min-width: 80px;
|
|
384
|
+
text-align: center;
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
/* Info panel (bottom-left overlay) */
|
|
388
|
+
.info-panel {
|
|
389
|
+
position: absolute;
|
|
390
|
+
bottom: 12px;
|
|
391
|
+
left: 12px;
|
|
392
|
+
background: var(--bg-overlay);
|
|
393
|
+
backdrop-filter: blur(8px);
|
|
394
|
+
-webkit-backdrop-filter: blur(8px);
|
|
395
|
+
padding: 14px 16px;
|
|
396
|
+
border-radius: var(--r-md);
|
|
397
|
+
font-size: 11px;
|
|
398
|
+
max-width: 380px;
|
|
399
|
+
border: 1px solid var(--border-subtle);
|
|
400
|
+
box-shadow: var(--shadow-med);
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
.info-panel h4 {
|
|
404
|
+
margin-bottom: 10px;
|
|
405
|
+
font-size: 13px;
|
|
406
|
+
font-weight: 600;
|
|
407
|
+
letter-spacing: 0.02em;
|
|
408
|
+
}
|
|
409
|
+
.info-panel h4.accent-blue { color: var(--accent-blue); }
|
|
410
|
+
.info-panel h4.accent-red { color: var(--accent-pink); }
|
|
411
|
+
.info-panel p { margin: 5px 0; color: var(--text-2); }
|
|
412
|
+
.info-panel span {
|
|
413
|
+
color: var(--accent-green);
|
|
414
|
+
font-family: ui-monospace, 'SF Mono', 'JetBrains Mono', Menlo, monospace;
|
|
415
|
+
font-size: 11px;
|
|
416
|
+
}
|
|
417
|
+
|
|
418
|
+
.info-panel .ptz-values {
|
|
419
|
+
background: var(--bg-panel-strong);
|
|
420
|
+
padding: 10px 12px;
|
|
421
|
+
border: 1px solid var(--border-subtle);
|
|
422
|
+
border-radius: var(--r-sm);
|
|
423
|
+
margin-top: 10px;
|
|
424
|
+
}
|
|
425
|
+
|
|
426
|
+
.info-panel .ptz-values p { margin: 3px 0; }
|
|
427
|
+
|
|
428
|
+
/* Resize handle (lightbox) */
|
|
429
|
+
.resize-handle {
|
|
430
|
+
height: 8px;
|
|
431
|
+
background: var(--bg-panel);
|
|
432
|
+
cursor: ns-resize;
|
|
433
|
+
display: flex;
|
|
434
|
+
align-items: center;
|
|
435
|
+
justify-content: center;
|
|
436
|
+
flex-shrink: 0;
|
|
437
|
+
touch-action: none;
|
|
438
|
+
border-top: 1px solid var(--border-subtle);
|
|
439
|
+
border-bottom: 1px solid var(--border-subtle);
|
|
440
|
+
}
|
|
441
|
+
|
|
442
|
+
.resize-handle:hover {
|
|
443
|
+
background: var(--bg-hover);
|
|
444
|
+
}
|
|
445
|
+
|
|
446
|
+
.resize-handle::after {
|
|
447
|
+
content: '\22EF'; /* horizontal ellipsis */
|
|
448
|
+
color: var(--text-3);
|
|
449
|
+
font-size: 16px;
|
|
450
|
+
letter-spacing: 2px;
|
|
451
|
+
}
|
|
452
|
+
|
|
453
|
+
.image-panel {
|
|
454
|
+
height: 350px;
|
|
455
|
+
background: var(--bg-canvas);
|
|
456
|
+
display: flex;
|
|
457
|
+
flex-direction: column;
|
|
458
|
+
position: relative;
|
|
459
|
+
}
|
|
460
|
+
|
|
461
|
+
.image-header {
|
|
462
|
+
padding: 8px 12px;
|
|
463
|
+
background: var(--bg-sidebar);
|
|
464
|
+
border-bottom: 1px solid var(--border-subtle);
|
|
465
|
+
display: flex;
|
|
466
|
+
justify-content: space-between;
|
|
467
|
+
align-items: center;
|
|
468
|
+
}
|
|
469
|
+
|
|
470
|
+
.image-title {
|
|
471
|
+
font-size: 12px;
|
|
472
|
+
color: var(--text-2);
|
|
473
|
+
}
|
|
474
|
+
|
|
475
|
+
.attempt-info {
|
|
476
|
+
font-size: 11px;
|
|
477
|
+
color: var(--accent-green);
|
|
478
|
+
background: rgba(122, 222, 160, 0.12);
|
|
479
|
+
padding: 4px 10px;
|
|
480
|
+
border-radius: 12px;
|
|
481
|
+
}
|
|
482
|
+
|
|
483
|
+
.image-controls {
|
|
484
|
+
display: flex;
|
|
485
|
+
gap: 8px;
|
|
486
|
+
}
|
|
487
|
+
|
|
488
|
+
.image-content {
|
|
489
|
+
flex: 1;
|
|
490
|
+
position: relative;
|
|
491
|
+
overflow: hidden;
|
|
492
|
+
display: flex;
|
|
493
|
+
align-items: center;
|
|
494
|
+
justify-content: center;
|
|
495
|
+
width: 100%;
|
|
496
|
+
height: 100%;
|
|
497
|
+
}
|
|
498
|
+
|
|
499
|
+
#imageWrapper {
|
|
500
|
+
position: relative;
|
|
501
|
+
display: flex;
|
|
502
|
+
align-items: center;
|
|
503
|
+
justify-content: center;
|
|
504
|
+
width: 100%;
|
|
505
|
+
height: 100%;
|
|
506
|
+
}
|
|
507
|
+
|
|
508
|
+
#imageWrapper img {
|
|
509
|
+
display: block;
|
|
510
|
+
max-width: 100%;
|
|
511
|
+
max-height: 100%;
|
|
512
|
+
width: auto;
|
|
513
|
+
height: auto;
|
|
514
|
+
object-fit: contain;
|
|
515
|
+
}
|
|
516
|
+
|
|
517
|
+
.overlay-img {
|
|
518
|
+
position: absolute;
|
|
519
|
+
max-width: 100%;
|
|
520
|
+
max-height: 100%;
|
|
521
|
+
width: auto;
|
|
522
|
+
height: auto;
|
|
523
|
+
object-fit: contain;
|
|
524
|
+
pointer-events: none;
|
|
525
|
+
}
|
|
526
|
+
|
|
527
|
+
/* Loading indicator */
|
|
528
|
+
#loading, .loading {
|
|
529
|
+
position: fixed;
|
|
530
|
+
top: 50%;
|
|
531
|
+
left: 50%;
|
|
532
|
+
transform: translate(-50%, -50%);
|
|
533
|
+
background: var(--bg-panel);
|
|
534
|
+
color: var(--text-2);
|
|
535
|
+
padding: 20px 40px;
|
|
536
|
+
border-radius: var(--r-lg);
|
|
537
|
+
border: 1px solid var(--border-subtle);
|
|
538
|
+
z-index: 1000;
|
|
539
|
+
}
|
|
540
|
+
|
|
541
|
+
.hidden { display: none !important; }
|
|
542
|
+
|
|
543
|
+
/* Navigation hints */
|
|
544
|
+
.navigation-hint, .keyboard-hint {
|
|
545
|
+
position: absolute;
|
|
546
|
+
bottom: 10px;
|
|
547
|
+
right: 10px;
|
|
548
|
+
font-size: 10px;
|
|
549
|
+
color: var(--text-3);
|
|
550
|
+
background: var(--bg-overlay);
|
|
551
|
+
padding: 6px 12px;
|
|
552
|
+
border-radius: var(--r-sm);
|
|
553
|
+
pointer-events: none;
|
|
554
|
+
}
|
|
555
|
+
|
|
556
|
+
.keyboard-hint kbd {
|
|
557
|
+
background: var(--bg-panel-strong);
|
|
558
|
+
padding: 2px 6px;
|
|
559
|
+
border-radius: var(--r-sm);
|
|
560
|
+
margin: 0 2px;
|
|
561
|
+
}
|
|
562
|
+
|
|
563
|
+
/* ════ Landing page (shown when no ?scene= param) ════ */
|
|
564
|
+
.landing {
|
|
565
|
+
/* height (not min-height) so overflow-y on the INNER list takes effect.
|
|
566
|
+
body has overflow:hidden, so anything past 100vh would otherwise be
|
|
567
|
+
clipped instead of scrollable. */
|
|
568
|
+
height: 100vh;
|
|
569
|
+
overflow: hidden;
|
|
570
|
+
background:
|
|
571
|
+
radial-gradient(ellipse 80% 60% at 20% -10%, rgba(122, 155, 255, 0.10), transparent 60%),
|
|
572
|
+
radial-gradient(ellipse 70% 50% at 80% 110%, rgba(255, 149, 194, 0.08), transparent 60%),
|
|
573
|
+
radial-gradient(ellipse 40% 40% at 50% 50%, rgba(240, 132, 74, 0.04), transparent 70%),
|
|
574
|
+
var(--bg-canvas);
|
|
575
|
+
padding: 48px 24px;
|
|
576
|
+
display: flex;
|
|
577
|
+
justify-content: center;
|
|
578
|
+
align-items: flex-start;
|
|
579
|
+
}
|
|
580
|
+
|
|
581
|
+
.landing-card {
|
|
582
|
+
width: 100%;
|
|
583
|
+
max-width: 820px;
|
|
584
|
+
max-height: calc(100vh - 96px);
|
|
585
|
+
background: linear-gradient(180deg, var(--bg-sidebar) 0%, var(--bg-canvas) 100%);
|
|
586
|
+
border: 1px solid var(--border-subtle);
|
|
587
|
+
border-radius: var(--r-lg);
|
|
588
|
+
padding: 32px 36px;
|
|
589
|
+
box-shadow:
|
|
590
|
+
0 1px 0 rgba(255, 255, 255, 0.04) inset,
|
|
591
|
+
var(--shadow-med);
|
|
592
|
+
display: flex;
|
|
593
|
+
flex-direction: column;
|
|
594
|
+
min-height: 0; /* lets the flex child use scroll */
|
|
595
|
+
}
|
|
596
|
+
|
|
597
|
+
.landing-header h1 {
|
|
598
|
+
font-size: 24px;
|
|
599
|
+
font-weight: 700;
|
|
600
|
+
color: var(--text-1);
|
|
601
|
+
letter-spacing: -0.01em;
|
|
602
|
+
background: linear-gradient(180deg, var(--text-1) 0%, var(--text-2) 100%);
|
|
603
|
+
-webkit-background-clip: text;
|
|
604
|
+
background-clip: text;
|
|
605
|
+
-webkit-text-fill-color: transparent;
|
|
606
|
+
}
|
|
607
|
+
|
|
608
|
+
.landing-subtitle {
|
|
609
|
+
margin-top: 8px;
|
|
610
|
+
color: var(--text-3);
|
|
611
|
+
font-size: 13.5px;
|
|
612
|
+
line-height: 1.5;
|
|
613
|
+
}
|
|
614
|
+
|
|
615
|
+
.landing-scenes {
|
|
616
|
+
margin-top: 24px;
|
|
617
|
+
display: flex;
|
|
618
|
+
flex-direction: column;
|
|
619
|
+
min-height: 0; /* let the inner list shrink/scroll inside the card */
|
|
620
|
+
flex: 1;
|
|
621
|
+
}
|
|
622
|
+
|
|
623
|
+
.landing-scenes h2 {
|
|
624
|
+
font-size: 11px;
|
|
625
|
+
font-weight: 600;
|
|
626
|
+
text-transform: uppercase;
|
|
627
|
+
letter-spacing: 0.1em;
|
|
628
|
+
color: var(--accent-blue);
|
|
629
|
+
margin-bottom: 10px;
|
|
630
|
+
}
|
|
631
|
+
|
|
632
|
+
.landing-count {
|
|
633
|
+
color: var(--text-4);
|
|
634
|
+
font-weight: 400;
|
|
635
|
+
margin-left: 6px;
|
|
636
|
+
font-variant-numeric: tabular-nums;
|
|
637
|
+
}
|
|
638
|
+
|
|
639
|
+
.landing-filter {
|
|
640
|
+
width: 100%;
|
|
641
|
+
padding: 10px 14px;
|
|
642
|
+
background: var(--bg-canvas);
|
|
643
|
+
color: var(--text-1);
|
|
644
|
+
border: 1px solid var(--border-subtle);
|
|
645
|
+
border-radius: var(--r-md);
|
|
646
|
+
font: inherit;
|
|
647
|
+
font-size: 13px;
|
|
648
|
+
margin-bottom: 12px;
|
|
649
|
+
outline: none;
|
|
650
|
+
transition: border-color var(--t-fast), box-shadow var(--t-fast);
|
|
651
|
+
}
|
|
652
|
+
.landing-filter:focus {
|
|
653
|
+
border-color: var(--accent-blue-soft);
|
|
654
|
+
box-shadow: 0 0 0 3px rgba(122, 155, 255, 0.12);
|
|
655
|
+
}
|
|
656
|
+
|
|
657
|
+
/* The scrollable inner surface — header + filter above stay pinned. */
|
|
658
|
+
.landing-scene-groups {
|
|
659
|
+
flex: 1;
|
|
660
|
+
overflow-y: auto;
|
|
661
|
+
margin: 0 -8px; /* visually align rows with the filter input */
|
|
662
|
+
padding: 0 8px 4px;
|
|
663
|
+
min-height: 0;
|
|
664
|
+
}
|
|
665
|
+
|
|
666
|
+
.landing-scene-group {
|
|
667
|
+
margin-bottom: 18px;
|
|
668
|
+
--group-accent: var(--text-3); /* fallback; JS sets the actual color */
|
|
669
|
+
}
|
|
670
|
+
|
|
671
|
+
.landing-scene-group:last-child { margin-bottom: 6px; }
|
|
672
|
+
|
|
673
|
+
.landing-group-label {
|
|
674
|
+
display: flex;
|
|
675
|
+
align-items: center;
|
|
676
|
+
gap: 10px;
|
|
677
|
+
padding: 14px 4px 8px;
|
|
678
|
+
margin-bottom: 4px;
|
|
679
|
+
border-bottom: 1px solid var(--border-subtle);
|
|
680
|
+
position: sticky;
|
|
681
|
+
top: 0;
|
|
682
|
+
background: linear-gradient(180deg, var(--bg-sidebar) 0%, var(--bg-sidebar) 75%, transparent 100%);
|
|
683
|
+
z-index: 1;
|
|
684
|
+
}
|
|
685
|
+
|
|
686
|
+
.landing-group-label::before {
|
|
687
|
+
content: "";
|
|
688
|
+
width: 6px;
|
|
689
|
+
height: 6px;
|
|
690
|
+
border-radius: 50%;
|
|
691
|
+
background: var(--group-accent);
|
|
692
|
+
box-shadow: 0 0 8px var(--group-accent);
|
|
693
|
+
flex-shrink: 0;
|
|
694
|
+
}
|
|
695
|
+
|
|
696
|
+
.landing-group-name {
|
|
697
|
+
font-size: 11px;
|
|
698
|
+
font-weight: 700;
|
|
699
|
+
text-transform: uppercase;
|
|
700
|
+
letter-spacing: 0.1em;
|
|
701
|
+
color: var(--text-1);
|
|
702
|
+
flex: 1;
|
|
703
|
+
}
|
|
704
|
+
|
|
705
|
+
.landing-group-count {
|
|
706
|
+
font-size: 11px;
|
|
707
|
+
font-variant-numeric: tabular-nums;
|
|
708
|
+
color: var(--text-3);
|
|
709
|
+
padding: 1px 8px;
|
|
710
|
+
border-radius: 999px;
|
|
711
|
+
background: var(--bg-panel);
|
|
712
|
+
border: 1px solid var(--border-subtle);
|
|
713
|
+
}
|
|
714
|
+
|
|
715
|
+
.landing-scene-link {
|
|
716
|
+
display: flex;
|
|
717
|
+
align-items: center;
|
|
718
|
+
gap: 12px;
|
|
719
|
+
padding: 10px 14px;
|
|
720
|
+
color: var(--text-2);
|
|
721
|
+
text-decoration: none;
|
|
722
|
+
border-radius: var(--r-md);
|
|
723
|
+
border: 1px solid transparent;
|
|
724
|
+
border-left: 2px solid transparent;
|
|
725
|
+
transition: background var(--t-fast), border-color var(--t-fast), color var(--t-fast),
|
|
726
|
+
transform var(--t-fast), padding var(--t-fast);
|
|
727
|
+
}
|
|
728
|
+
|
|
729
|
+
.landing-scene-link:hover {
|
|
730
|
+
background: var(--bg-hover);
|
|
731
|
+
border-color: var(--border-subtle);
|
|
732
|
+
border-left-color: var(--group-accent);
|
|
733
|
+
color: var(--text-1);
|
|
734
|
+
padding-left: 16px;
|
|
735
|
+
}
|
|
736
|
+
.landing-scene-link:active { transform: translateY(1px); }
|
|
737
|
+
|
|
738
|
+
.landing-scene-id {
|
|
739
|
+
flex: 1;
|
|
740
|
+
font-family: ui-monospace, 'SF Mono', 'JetBrains Mono', Menlo, monospace;
|
|
741
|
+
font-size: 12.5px;
|
|
742
|
+
overflow: hidden;
|
|
743
|
+
text-overflow: ellipsis;
|
|
744
|
+
white-space: nowrap;
|
|
745
|
+
}
|
|
746
|
+
|
|
747
|
+
.landing-scene-arrow {
|
|
748
|
+
color: var(--text-4);
|
|
749
|
+
font-size: 14px;
|
|
750
|
+
opacity: 0;
|
|
751
|
+
transform: translateX(-4px);
|
|
752
|
+
transition: opacity var(--t-fast), transform var(--t-fast), color var(--t-fast);
|
|
753
|
+
}
|
|
754
|
+
|
|
755
|
+
.landing-scene-link:hover .landing-scene-arrow {
|
|
756
|
+
opacity: 1;
|
|
757
|
+
transform: translateX(0);
|
|
758
|
+
color: var(--group-accent);
|
|
759
|
+
}
|
|
760
|
+
|
|
761
|
+
.landing-empty {
|
|
762
|
+
color: var(--text-3);
|
|
763
|
+
font-size: 13px;
|
|
764
|
+
padding: 8px 12px;
|
|
765
|
+
font-style: italic;
|
|
766
|
+
}
|
|
767
|
+
|
|
768
|
+
.landing-help {
|
|
769
|
+
margin-top: 20px;
|
|
770
|
+
border-top: 1px solid var(--border-subtle);
|
|
771
|
+
padding-top: 18px;
|
|
772
|
+
flex-shrink: 0; /* don't get squeezed by the scrolling scenes list */
|
|
773
|
+
}
|
|
774
|
+
|
|
775
|
+
.landing-help summary {
|
|
776
|
+
cursor: pointer;
|
|
777
|
+
color: var(--text-3);
|
|
778
|
+
font-size: 12px;
|
|
779
|
+
user-select: none;
|
|
780
|
+
list-style: none;
|
|
781
|
+
padding: 4px 0;
|
|
782
|
+
transition: color var(--t-fast);
|
|
783
|
+
}
|
|
784
|
+
.landing-help summary::-webkit-details-marker { display: none; }
|
|
785
|
+
.landing-help summary::before {
|
|
786
|
+
content: "▸ ";
|
|
787
|
+
display: inline-block;
|
|
788
|
+
transition: transform var(--t-fast);
|
|
789
|
+
color: var(--text-4);
|
|
790
|
+
}
|
|
791
|
+
.landing-help[open] summary::before { transform: rotate(90deg); }
|
|
792
|
+
.landing-help summary:hover { color: var(--text-1); }
|
|
793
|
+
|
|
794
|
+
.landing-help pre {
|
|
795
|
+
background: var(--bg-canvas);
|
|
796
|
+
border: 1px solid var(--border-subtle);
|
|
797
|
+
color: var(--text-2);
|
|
798
|
+
padding: 14px 16px;
|
|
799
|
+
border-radius: var(--r-md);
|
|
800
|
+
overflow-x: auto;
|
|
801
|
+
font-size: 12px;
|
|
802
|
+
line-height: 1.7;
|
|
803
|
+
margin: 14px 0;
|
|
804
|
+
}
|
|
805
|
+
|
|
806
|
+
.landing-hint {
|
|
807
|
+
color: var(--text-3);
|
|
808
|
+
font-size: 12px;
|
|
809
|
+
}
|
|
810
|
+
|
|
811
|
+
.landing-hint code {
|
|
812
|
+
background: var(--bg-panel);
|
|
813
|
+
border: 1px solid var(--border-subtle);
|
|
814
|
+
color: var(--accent-blue);
|
|
815
|
+
padding: 1px 6px;
|
|
816
|
+
border-radius: var(--r-sm);
|
|
817
|
+
font-size: 11px;
|
|
818
|
+
}
|