explodeview 0.2.0 → 1.0.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.
@@ -0,0 +1,2239 @@
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <meta http-equiv="Cache-Control" content="no-cache, no-store, must-revalidate">
7
+ <meta http-equiv="Pragma" content="no-cache">
8
+ <meta http-equiv="Expires" content="0">
9
+ <title>ExplodeView Demo</title>
10
+ <link rel="preconnect" href="https://fonts.googleapis.com">
11
+ <link href="https://fonts.googleapis.com/css2?family=Inter:wght@200;300;400;500;600;700;800;900&family=SF+Pro+Display:wght@200;300;400;500;600;700&display=swap" rel="stylesheet">
12
+ <style>
13
+ :root {
14
+ --cyan: #0055A4;
15
+ --yellow: #FFD100;
16
+ --bg: #0a0e1a;
17
+ --ui-bg: rgba(10,12,20,0.75);
18
+ --ui-bg-solid: rgba(0,0,0,0.92);
19
+ --ui-border: rgba(255,255,255,0.1);
20
+ --ui-text: #fff;
21
+ --ui-text-dim: rgba(255,255,255,0.5);
22
+ --ui-text-muted: rgba(255,255,255,0.25);
23
+ --3d-bg: #0a0e1a;
24
+ }
25
+ /* Light theme */
26
+ [data-theme="light"] {
27
+ --bg: #f0f2f5;
28
+ --ui-bg: rgba(255,255,255,0.85);
29
+ --ui-bg-solid: rgba(245,247,250,0.96);
30
+ --ui-border: rgba(0,0,0,0.12);
31
+ --ui-text: #1a1a2e;
32
+ --ui-text-dim: rgba(0,0,0,0.5);
33
+ --ui-text-muted: rgba(0,0,0,0.25);
34
+ --3d-bg: #e8eaed;
35
+ }
36
+ [data-theme="light"] body { color: #1a1a2e; }
37
+ [data-theme="light"] .vc-btn { color: #1a1a2e !important; border-color: rgba(0,0,0,0.15) !important; background: rgba(255,255,255,0.6) !important; }
38
+ [data-theme="light"] .vc-btn:hover { background: rgba(0,85,164,0.1) !important; border-color: var(--cyan) !important; color: var(--cyan) !important; }
39
+ [data-theme="light"] .vc-btn.active { background: rgba(0,85,164,0.15) !important; border-color: var(--cyan) !important; color: var(--cyan) !important; }
40
+ [data-theme="light"] #top-nav { background: rgba(255,255,255,0.9) !important; border-bottom-color: rgba(0,0,0,0.08) !important; }
41
+ [data-theme="light"] .top-logo { color: #1a1a2e !important; }
42
+ [data-theme="light"] #ce-buttons { background: var(--ui-bg) !important; border-color: var(--ui-border) !important; }
43
+ [data-theme="light"] #product-title { background: rgba(255,255,255,0.85) !important; color: #1a1a2e !important; }
44
+ [data-theme="light"] #product-title span { color: #1a1a2e !important; }
45
+ [data-theme="light"] #product-title span:last-child { color: var(--cyan) !important; }
46
+ [data-theme="light"] #product-stats { color: rgba(0,0,0,0.45) !important; }
47
+ [data-theme="light"] .cface { background: rgba(255,255,255,0.85) !important; color: #333 !important; border-color: rgba(0,0,0,0.15) !important; }
48
+ [data-theme="light"] #vc-rot-target { background: rgba(255,255,255,0.9) !important; border-color: rgba(0,0,0,0.1) !important; }
49
+ [data-theme="light"] .rot-target-btn { color: #333 !important; }
50
+ [data-theme="light"] .rot-target-btn.active { background: rgba(0,85,164,0.2) !important; color: var(--cyan) !important; }
51
+ [data-theme="light"] #view-controls { background: rgba(255,255,255,0.85) !important; border-color: rgba(0,0,0,0.1) !important; }
52
+ [data-theme="light"] #settings-panel,
53
+ [data-theme="light"] #embed-settings-panel,
54
+ [data-theme="light"] #imported-models-panel,
55
+ [data-theme="light"] #share-panel,
56
+ [data-theme="light"] #export-panel { background: rgba(245,247,250,0.96) !important; border-color: rgba(0,0,0,0.1) !important; color: #1a1a2e !important; }
57
+ [data-theme="light"] #left-nav { background: rgba(245,247,250,0.95) !important; border-color: rgba(0,0,0,0.08) !important; }
58
+ [data-theme="light"] .nav-item { color: #333 !important; border-color: rgba(0,0,0,0.06) !important; }
59
+ [data-theme="light"] .nav-item:hover, [data-theme="light"] .nav-item.active { background: rgba(0,85,164,0.08) !important; }
60
+ [data-theme="light"] #vc-home { background: rgba(255,255,255,0.8) !important; border-color: rgba(0,0,0,0.15) !important; }
61
+ [data-theme="light"] #vc-home svg { stroke: rgba(0,0,0,0.5) !important; }
62
+ /* Slate theme */
63
+ [data-theme="slate"] {
64
+ --bg: #2a2d3a;
65
+ --ui-bg: rgba(42,45,58,0.85);
66
+ --ui-bg-solid: rgba(38,41,54,0.96);
67
+ --ui-border: rgba(255,255,255,0.08);
68
+ --ui-text: #d0d4dc;
69
+ --ui-text-dim: rgba(255,255,255,0.45);
70
+ --ui-text-muted: rgba(255,255,255,0.2);
71
+ --3d-bg: #2a2d3a;
72
+ }
73
+ * { margin: 0; padding: 0; box-sizing: border-box; }
74
+ html { scroll-behavior: smooth; overflow: hidden; overscroll-behavior: none; }
75
+ body {
76
+ background: var(--bg);
77
+ color: white;
78
+ font-family: 'Inter', -apple-system, BlinkMacSystemFont, sans-serif;
79
+ overscroll-behavior: none;
80
+ overflow: hidden;
81
+ }
82
+
83
+ /* ─── Fixed 3D Canvas ─── */
84
+ #three-canvas {
85
+ position: fixed;
86
+ top: 0; left: 0;
87
+ width: 100vw; height: 100vh;
88
+ z-index: 1;
89
+ }
90
+ #three-canvas canvas {
91
+ touch-action: none;
92
+ }
93
+
94
+ /* ─── Scroll Container (drives animation) ─── */
95
+ #scroll-driver {
96
+ position: relative;
97
+ z-index: 2;
98
+ pointer-events: none;
99
+ }
100
+ #scroll-driver .assembly-text,
101
+ #scroll-driver .finale .cta,
102
+ #scroll-driver .hero {
103
+ pointer-events: none;
104
+ }
105
+
106
+ /* ─── Hero Section ─── */
107
+ .hero {
108
+ height: 100vh;
109
+ display: flex;
110
+ flex-direction: column;
111
+ align-items: center;
112
+ justify-content: center;
113
+ text-align: center;
114
+ position: relative;
115
+ pointer-events: none;
116
+ }
117
+ .hero-badge {
118
+ font-size: 0.65rem;
119
+ letter-spacing: 0.35em;
120
+ text-transform: uppercase;
121
+ color: var(--cyan);
122
+ font-weight: 500;
123
+ margin-bottom: 1.5rem;
124
+ opacity: 0;
125
+ animation: fadeUp 1s ease 0.3s forwards;
126
+ }
127
+ .hero h1 {
128
+ font-size: clamp(3rem, 8vw, 7rem);
129
+ font-weight: 200;
130
+ letter-spacing: 0.15em;
131
+ line-height: 1;
132
+ opacity: 0;
133
+ animation: fadeUp 1.2s ease 0.5s forwards;
134
+ }
135
+ .hero h1 span {
136
+ font-weight: 800;
137
+ background: linear-gradient(135deg, var(--cyan), var(--yellow));
138
+ -webkit-background-clip: text;
139
+ -webkit-text-fill-color: transparent;
140
+ }
141
+ .hero .model-name {
142
+ font-size: clamp(1rem, 2.5vw, 1.8rem);
143
+ font-weight: 300;
144
+ letter-spacing: 0.4em;
145
+ color: rgba(255,255,255,0.55);
146
+ margin-top: 1rem;
147
+ opacity: 0;
148
+ animation: fadeUp 1s ease 0.8s forwards;
149
+ text-shadow: 0 1px 6px rgba(0,0,0,0.4);
150
+ }
151
+ .hero .tagline {
152
+ font-size: 1rem;
153
+ font-weight: 400;
154
+ letter-spacing: 0.12em;
155
+ color: rgba(255,255,255,0.7);
156
+ margin-top: 2rem;
157
+ max-width: 550px;
158
+ line-height: 1.8;
159
+ opacity: 0;
160
+ animation: fadeUp 1s ease 1.1s forwards;
161
+ text-shadow: 0 1px 8px rgba(0,0,0,0.5);
162
+ }
163
+ .scroll-hint {
164
+ position: absolute;
165
+ bottom: 40px;
166
+ font-size: 0.6rem;
167
+ letter-spacing: 0.3em;
168
+ text-transform: uppercase;
169
+ color: #334;
170
+ opacity: 0;
171
+ animation: fadeUp 1s ease 1.5s forwards, pulse 2s ease 2.5s infinite;
172
+ }
173
+ .scroll-hint::after {
174
+ content: '';
175
+ display: block;
176
+ width: 1px; height: 30px;
177
+ background: linear-gradient(to bottom, #334, transparent);
178
+ margin: 0.8rem auto 0;
179
+ }
180
+
181
+ /* ─── Assembly Sections ─── */
182
+ .assembly-section {
183
+ display: none; /* Hidden — navigation is via left nav clicks and bottom prev/next buttons */
184
+ }
185
+ .assembly-text {
186
+ position: sticky;
187
+ top: 0;
188
+ height: 100vh;
189
+ display: flex;
190
+ flex-direction: column;
191
+ justify-content: flex-end;
192
+ padding: 0 0 6vh 20px;
193
+ max-width: 300px;
194
+ opacity: 0;
195
+ transform: translateY(20px);
196
+ transition: opacity 0.6s ease, transform 0.6s ease;
197
+ pointer-events: none;
198
+ }
199
+ .assembly-text.visible {
200
+ opacity: 1;
201
+ transform: translateY(0);
202
+ }
203
+ .assembly-text > * {
204
+ background: rgba(0,0,0,0.5);
205
+ backdrop-filter: blur(10px);
206
+ -webkit-backdrop-filter: blur(10px);
207
+ padding: 8px 14px;
208
+ border-radius: 6px;
209
+ margin-bottom: 4px;
210
+ }
211
+ .assembly-number {
212
+ font-size: 0.5rem;
213
+ letter-spacing: 0.3em;
214
+ text-transform: uppercase;
215
+ font-weight: 500;
216
+ display: inline-block;
217
+ width: auto;
218
+ }
219
+ .assembly-name {
220
+ font-size: 1.1rem;
221
+ font-weight: 700;
222
+ letter-spacing: 0.04em;
223
+ line-height: 1.2;
224
+ }
225
+ .assembly-subtitle {
226
+ font-size: 0.7rem;
227
+ font-weight: 400;
228
+ color: rgba(255,255,255,0.6);
229
+ letter-spacing: 0.04em;
230
+ }
231
+ .assembly-detail {
232
+ font-size: 0.6rem;
233
+ color: rgba(255,255,255,0.45);
234
+ letter-spacing: 0.03em;
235
+ line-height: 1.6;
236
+ max-width: 280px;
237
+ }
238
+ .assembly-line {
239
+ width: 30px; height: 2px;
240
+ border-radius: 1px;
241
+ display: inline-block;
242
+ }
243
+
244
+ /* ─── Spacer Sections ─── */
245
+ .spacer { height: 100vh; }
246
+ .spacer-half { height: 50vh; }
247
+
248
+ /* ─── Finale ─── */
249
+ .finale {
250
+ height: 100vh;
251
+ display: flex;
252
+ flex-direction: column;
253
+ align-items: center;
254
+ justify-content: center;
255
+ text-align: center;
256
+ pointer-events: none;
257
+ }
258
+ .finale .cta { pointer-events: auto; }
259
+ .finale h2 {
260
+ font-size: clamp(2.5rem, 6vw, 5rem);
261
+ font-weight: 200;
262
+ letter-spacing: 0.2em;
263
+ text-shadow: 0 2px 20px rgba(0,0,0,0.6);
264
+ }
265
+ .finale h2 span {
266
+ font-weight: 800;
267
+ background: linear-gradient(135deg, var(--cyan), var(--yellow));
268
+ -webkit-background-clip: text;
269
+ -webkit-text-fill-color: transparent;
270
+ }
271
+ .finale .specs {
272
+ display: flex;
273
+ gap: 4rem;
274
+ margin-top: 3rem;
275
+ padding: 2rem 3rem;
276
+ background: rgba(0,0,0,0.5);
277
+ backdrop-filter: blur(16px);
278
+ -webkit-backdrop-filter: blur(16px);
279
+ border: 1px solid rgba(255,255,255,0.08);
280
+ border-radius: 12px;
281
+ }
282
+ .spec {
283
+ text-align: center;
284
+ }
285
+ .spec-value {
286
+ font-size: 2.2rem;
287
+ font-weight: 700;
288
+ background: linear-gradient(135deg, var(--cyan), var(--yellow));
289
+ -webkit-background-clip: text;
290
+ -webkit-text-fill-color: transparent;
291
+ }
292
+ .spec-label {
293
+ font-size: 0.65rem;
294
+ letter-spacing: 0.2em;
295
+ text-transform: uppercase;
296
+ color: rgba(255,255,255,0.55);
297
+ margin-top: 0.4rem;
298
+ }
299
+ .finale .cta {
300
+ margin-top: 3rem;
301
+ padding: 14px 40px;
302
+ background: linear-gradient(135deg, var(--cyan), var(--yellow));
303
+ color: #000;
304
+ font-family: inherit;
305
+ font-size: 0.75rem;
306
+ font-weight: 600;
307
+ letter-spacing: 0.15em;
308
+ text-transform: uppercase;
309
+ border: none;
310
+ border-radius: 50px;
311
+ cursor: pointer;
312
+ transition: transform 0.3s ease, box-shadow 0.3s ease;
313
+ }
314
+ .finale .cta:hover {
315
+ transform: scale(1.05);
316
+ box-shadow: 0 0 40px rgba(0,85,164,0.4);
317
+ }
318
+
319
+ /* ─── Loading ─── */
320
+ #loader {
321
+ position: fixed; inset: 0;
322
+ background: #0a0e1a;
323
+ display: flex; flex-direction: column;
324
+ align-items: center; justify-content: center;
325
+ z-index: 1000;
326
+ transition: opacity 1.2s ease;
327
+ }
328
+ #loader.hidden { opacity: 0; pointer-events: none; }
329
+
330
+ /* Animated logo */
331
+ .loader-logo {
332
+ position: relative;
333
+ margin-bottom: 2rem;
334
+ }
335
+ .loader-logo h1 {
336
+ font-size: clamp(2rem, 6vw, 3.5rem);
337
+ font-weight: 200;
338
+ letter-spacing: 0.3em;
339
+ opacity: 0;
340
+ animation: logoFadeIn 1.5s ease 0.2s forwards;
341
+ }
342
+ .loader-logo h1 span {
343
+ font-weight: 800;
344
+ background: linear-gradient(135deg, var(--yellow), #fff, var(--yellow));
345
+ background-size: 200% 100%;
346
+ -webkit-background-clip: text;
347
+ -webkit-text-fill-color: transparent;
348
+ animation: logoShimmer 2.5s ease infinite;
349
+ }
350
+ .loader-product {
351
+ font-size: clamp(0.7rem, 2vw, 1rem);
352
+ font-weight: 300;
353
+ letter-spacing: 0.5em;
354
+ color: rgba(255,255,255,0.3);
355
+ text-align: center;
356
+ margin-top: 0.5rem;
357
+ opacity: 0;
358
+ animation: logoFadeIn 1s ease 0.8s forwards;
359
+ }
360
+ .loader-ring {
361
+ width: 80px; height: 80px;
362
+ border: 2px solid rgba(255,255,255,0.05);
363
+ border-top: 2px solid var(--yellow);
364
+ border-right: 2px solid var(--cyan);
365
+ border-radius: 50%;
366
+ animation: loaderSpin 1.2s linear infinite;
367
+ margin-bottom: 2rem;
368
+ }
369
+ #progress-bar {
370
+ width: 200px; height: 2px;
371
+ background: rgba(255,255,255,0.06); margin-top: 0;
372
+ border-radius: 1px; overflow: hidden;
373
+ }
374
+ #progress-fill {
375
+ height: 100%; width: 0%;
376
+ background: linear-gradient(90deg, var(--cyan), var(--yellow));
377
+ transition: width 0.3s;
378
+ border-radius: 1px;
379
+ }
380
+ #progress-text {
381
+ margin-top: 0.8rem; font-size: 0.55rem;
382
+ color: rgba(255,255,255,0.2); letter-spacing: 0.15em;
383
+ }
384
+
385
+ @keyframes logoFadeIn {
386
+ from { opacity: 0; transform: translateY(10px); }
387
+ to { opacity: 1; transform: translateY(0); }
388
+ }
389
+ @keyframes logoShimmer {
390
+ 0% { background-position: -200% center; }
391
+ 100% { background-position: 200% center; }
392
+ }
393
+ @keyframes loaderSpin {
394
+ to { transform: rotate(360deg); }
395
+ }
396
+
397
+ /* ─── Sound Toggle ─── */
398
+ #sound-btn {
399
+ background: rgba(255,255,255,0.06);
400
+ border: 1px solid rgba(255,255,255,0.1);
401
+ color: #667;
402
+ width: 30px; height: 30px;
403
+ border-radius: 50%;
404
+ font-size: 0.8rem;
405
+ cursor: pointer;
406
+ transition: all 0.3s;
407
+ display: flex; align-items: center; justify-content: center;
408
+ }
409
+ #sound-btn:hover { border-color: var(--cyan); color: var(--cyan); }
410
+ #sound-btn.on { border-color: var(--cyan); color: var(--cyan); }
411
+
412
+ /* ─── Top Navigation Bar ─── */
413
+ #top-nav {
414
+ position: fixed;
415
+ top: 0; left: 0; right: 0;
416
+ z-index: 60;
417
+ display: flex;
418
+ align-items: center;
419
+ justify-content: space-between;
420
+ padding: 0 30px;
421
+ height: 52px;
422
+ background: rgba(0,0,0,0.6);
423
+ backdrop-filter: blur(20px) saturate(180%);
424
+ -webkit-backdrop-filter: blur(20px) saturate(180%);
425
+ border-bottom: 1px solid rgba(255,255,255,0.06);
426
+ transition: transform 0.4s ease;
427
+ }
428
+ /* ViewCube */
429
+ .cface {
430
+ position: absolute; width: 90px; height: 90px;
431
+ display: flex; align-items: center; justify-content: center;
432
+ font-size: 9px; font-weight: 600; letter-spacing: 0.1em;
433
+ color: rgba(255,255,255,0.7); text-transform: uppercase;
434
+ background: rgba(100,120,140,0.4);
435
+ border: 1px solid rgba(255,255,255,0.15);
436
+ backdrop-filter: blur(4px);
437
+ backface-visibility: visible;
438
+ transition: background 0.2s;
439
+ }
440
+ .cface:hover { background: rgba(0,85,164,0.5); color: #fff; }
441
+
442
+ .top-logo { display: none; }
443
+ .logo-brand { font-weight: 200; }
444
+ .logo-product { font-weight: 700; color: var(--yellow); }
445
+ /* Fallback for non-JS */
446
+ .top-logo span { font-weight: 700; color: var(--yellow); }
447
+ .top-links {
448
+ display: flex;
449
+ gap: 28px;
450
+ }
451
+ .top-link {
452
+ font-size: 0.65rem;
453
+ letter-spacing: 0.1em;
454
+ color: rgba(255,255,255,0.45);
455
+ text-decoration: none;
456
+ text-transform: uppercase;
457
+ font-weight: 400;
458
+ transition: color 0.3s;
459
+ cursor: pointer;
460
+ }
461
+ .top-link:hover, .top-link.active { color: white; }
462
+ .top-sep { display: none; }
463
+ .top-assemblies { display: none; }
464
+
465
+ /* Mobile assembly info — shown when sub-assembly selected */
466
+ #mob-asm-info {
467
+ display: none;
468
+ position: fixed;
469
+ left: 12px; bottom: 12px;
470
+ z-index: 55;
471
+ background: rgba(0,0,0,0.6);
472
+ backdrop-filter: blur(12px);
473
+ border: 1px solid rgba(255,255,255,0.08);
474
+ border-radius: 10px;
475
+ padding: 12px 16px;
476
+ max-width: 220px;
477
+ pointer-events: none;
478
+ }
479
+ .top-asm {
480
+ font-size: 0.55rem; letter-spacing: 0.06em; color: rgba(255,255,255,0.3);
481
+ text-decoration: none; text-transform: uppercase; cursor: pointer;
482
+ padding: 4px 8px; border-radius: 3px; white-space: nowrap;
483
+ transition: all 0.3s; border: 1px solid transparent;
484
+ }
485
+ .top-asm:hover { color: rgba(255,255,255,0.6); }
486
+ .top-asm.active { color: white; border-color: currentColor; background: rgba(255,255,255,0.05); }
487
+ .top-actions {
488
+ display: flex;
489
+ align-items: center;
490
+ gap: 12px;
491
+ }
492
+
493
+ /* ─── Bottom Controls ─── */
494
+ #bottom-controls {
495
+ position: fixed;
496
+ bottom: 20px;
497
+ left: 50%;
498
+ transform: translateX(-50%);
499
+ z-index: 60;
500
+ display: flex;
501
+ align-items: center;
502
+ gap: 12px;
503
+ padding: 8px 16px;
504
+ background: rgba(0,0,0,0.5);
505
+ backdrop-filter: blur(16px);
506
+ -webkit-backdrop-filter: blur(16px);
507
+ border: 1px solid rgba(255,255,255,0.06);
508
+ border-radius: 50px;
509
+ }
510
+ .ctrl-btn {
511
+ width: 32px; height: 32px;
512
+ border-radius: 50%;
513
+ background: rgba(255,255,255,0.06);
514
+ border: 1px solid rgba(255,255,255,0.1);
515
+ color: #aaa;
516
+ font-size: 0.8rem;
517
+ cursor: pointer;
518
+ display: flex;
519
+ align-items: center;
520
+ justify-content: center;
521
+ transition: all 0.3s;
522
+ font-family: inherit;
523
+ }
524
+ .ctrl-btn:hover {
525
+ background: rgba(0,212,255,0.15);
526
+ border-color: var(--cyan);
527
+ color: var(--cyan);
528
+ }
529
+ .ctrl-progress {
530
+ position: relative;
531
+ width: 200px;
532
+ height: 3px;
533
+ background: rgba(255,255,255,0.08);
534
+ border-radius: 2px;
535
+ overflow: hidden;
536
+ }
537
+ .ctrl-progress-fill {
538
+ height: 100%;
539
+ width: 0%;
540
+ background: linear-gradient(90deg, var(--cyan), var(--yellow));
541
+ border-radius: 2px;
542
+ transition: width 0.2s;
543
+ }
544
+ .ctrl-progress-label {
545
+ position: absolute;
546
+ top: -20px;
547
+ left: 50%;
548
+ transform: translateX(-50%);
549
+ font-size: 0.5rem;
550
+ letter-spacing: 0.15em;
551
+ text-transform: uppercase;
552
+ color: #556;
553
+ white-space: nowrap;
554
+ }
555
+
556
+ /* ─── 3D View Controls (right side) ─── */
557
+ #view-controls {
558
+ position: fixed;
559
+ right: 14px;
560
+ bottom: 70px;
561
+ z-index: 55;
562
+ display: flex;
563
+ flex-direction: column;
564
+ gap: 4px;
565
+ padding: 8px;
566
+ background: rgba(0,0,0,0.6);
567
+ backdrop-filter: blur(16px);
568
+ -webkit-backdrop-filter: blur(16px);
569
+ border: 1px solid rgba(255,255,255,0.12);
570
+ border-radius: 10px;
571
+ }
572
+ .vc-btn {
573
+ width: auto; height: auto;
574
+ border-radius: 8px;
575
+ background: rgba(20,25,35,0.85);
576
+ border: 1px solid rgba(255,255,255,0.18);
577
+ color: #ccd;
578
+ font-size: 0.85rem;
579
+ cursor: pointer;
580
+ display: flex;
581
+ align-items: center;
582
+ justify-content: center;
583
+ transition: all 0.25s;
584
+ font-family: inherit;
585
+ padding: 8px 14px;
586
+ white-space: nowrap;
587
+ backdrop-filter: blur(12px);
588
+ -webkit-backdrop-filter: blur(12px);
589
+ }
590
+ .vc-btn:hover {
591
+ background: rgba(0,85,164,0.45);
592
+ border-color: rgba(0,85,164,0.6);
593
+ color: white;
594
+ }
595
+ .vc-btn.active {
596
+ background: rgba(0,85,164,0.5);
597
+ border-color: rgba(0,85,164,0.7);
598
+ color: #4da6ff;
599
+ }
600
+ .vc-divider {
601
+ width: 24px;
602
+ height: 1px;
603
+ background: rgba(255,255,255,0.06);
604
+ margin: 2px auto;
605
+ }
606
+
607
+ /* ─── Left Navigation ─── */
608
+ #left-nav {
609
+ display: none;
610
+ flex-direction: column;
611
+ gap: 0;
612
+ .nav-line { display: none; }
613
+ .nav-items {
614
+ display: flex;
615
+ flex-direction: column;
616
+ gap: 4px;
617
+ }
618
+ .nav-item {
619
+ display: flex;
620
+ align-items: center;
621
+ gap: 10px;
622
+ padding: 10px 14px;
623
+ cursor: pointer;
624
+ transition: all 0.35s ease;
625
+ position: relative;
626
+ border: 1px solid rgba(255,255,255,0.1);
627
+ border-radius: 6px;
628
+ background: rgba(0,0,0,0.55);
629
+ backdrop-filter: blur(14px);
630
+ -webkit-backdrop-filter: blur(14px);
631
+ min-width: 180px;
632
+ }
633
+ .nav-item:hover {
634
+ border-color: rgba(255,255,255,0.15);
635
+ background: rgba(255,255,255,0.04);
636
+ }
637
+ .nav-dot {
638
+ width: 8px; height: 8px;
639
+ border-radius: 50%;
640
+ background: rgba(255,255,255,0.12);
641
+ transition: all 0.4s ease;
642
+ flex-shrink: 0;
643
+ }
644
+ .nav-item.active {
645
+ border-color: currentColor;
646
+ background: rgba(0,85,164,0.12);
647
+ box-shadow: 0 0 20px rgba(0,85,164,0.15);
648
+ }
649
+ .nav-item.active .nav-dot {
650
+ box-shadow: 0 0 10px currentColor;
651
+ width: 10px; height: 10px;
652
+ }
653
+ .nav-item.past {
654
+ border-color: rgba(255,255,255,0.08);
655
+ }
656
+ .nav-item.past .nav-dot {
657
+ opacity: 0.5;
658
+ }
659
+ .nav-label {
660
+ font-size: 0.7rem;
661
+ letter-spacing: 0.08em;
662
+ text-transform: uppercase;
663
+ color: rgba(255,255,255,0.7);
664
+ white-space: nowrap;
665
+ transition: all 0.4s ease;
666
+ font-weight: 500;
667
+ text-shadow: 0 1px 6px rgba(0,0,0,0.8);
668
+ }
669
+ .nav-item.active .nav-label {
670
+ color: inherit;
671
+ font-weight: 700;
672
+ text-shadow: 0 1px 8px rgba(0,0,0,0.6);
673
+ }
674
+ .nav-item.past .nav-label {
675
+ color: inherit;
676
+ opacity: 0.5;
677
+ }
678
+ .nav-item:hover .nav-label {
679
+ color: rgba(255,255,255,0.7);
680
+ }
681
+
682
+ /* ─── Mobile Toggle Buttons ─── */
683
+ .mob-toggle {
684
+ display: none;
685
+ position: fixed;
686
+ z-index: 55;
687
+ width: 36px; height: 36px;
688
+ border-radius: 50%;
689
+ background: rgba(0,0,0,0.6);
690
+ backdrop-filter: blur(10px);
691
+ border: 1px solid rgba(255,255,255,0.1);
692
+ color: #aaa;
693
+ font-size: 0.9rem;
694
+ cursor: pointer;
695
+ align-items: center;
696
+ justify-content: center;
697
+ transition: all 0.3s;
698
+ }
699
+ .mob-toggle.open { background: rgba(0,85,164,0.3); border-color: rgba(0,85,164,0.5); color: #4da6ff; }
700
+ #mob-parts { left: 10px; bottom: 55px; }
701
+ #mob-tools { right: 10px; bottom: 55px; }
702
+
703
+ /* ─── Mobile Responsive ─── */
704
+ @media (max-width: 768px) {
705
+ /* HIDE everything that overlaps the 3D model */
706
+ #left-nav { display: none !important; }
707
+ #bottom-controls { display: none !important; }
708
+ #scroll-driver { display: none !important; }
709
+ body { overflow: hidden !important; }
710
+
711
+ /* Top nav: compact, scrollable */
712
+ #top-nav { height: 38px !important; padding: 0 6px !important; overflow-x: auto; -webkit-overflow-scrolling: touch; }
713
+ .top-logo { font-size: 0.55rem !important; letter-spacing: 0.08em; max-width: 90px; overflow: hidden; text-overflow: ellipsis; }
714
+ .top-links { gap: 2px; flex-shrink: 0; }
715
+ .top-link { padding: 3px 6px; font-size: 0.45rem; white-space: nowrap; }
716
+ #btn-explode-toggle { display: none !important; }
717
+
718
+ /* Show mobile-only elements */
719
+ /* product-title adjusts for mobile nav height */
720
+ #product-title { bottom: 0 !important; top: auto !important; font-size: 0.55rem !important; }
721
+ .mob-toggle { display: flex !important; }
722
+ .top-sep { display: inline !important; }
723
+ .top-assemblies { display: flex !important; }
724
+ #mob-asm-info.show { display: block !important; }
725
+ #sound-btn { display: none !important; }
726
+
727
+ /* Right controls: inline in top nav */
728
+ #view-controls {
729
+ position: static !important; transform: none !important;
730
+ flex-direction: row !important; padding: 0 !important; gap: 2px !important;
731
+ background: none !important; backdrop-filter: none !important;
732
+ border: none !important; border-radius: 0 !important;
733
+ }
734
+ .vc-btn { width: auto !important; height: auto !important; font-size: 0.75rem !important; padding: 6px 10px !important; }
735
+ .vc-divider { width: 1px !important; height: 18px !important; margin: 0 1px !important; }
736
+ }
737
+
738
+ /* ─── Animations ─── */
739
+ @keyframes fadeUp {
740
+ from { opacity: 0; transform: translateY(20px); }
741
+ to { opacity: 1; transform: translateY(0); }
742
+ }
743
+ @keyframes pulse {
744
+ 0%, 100% { opacity: 0.4; }
745
+ 50% { opacity: 0.8; }
746
+ }
747
+ </style>
748
+ </head>
749
+ <body>
750
+ <!-- Loader -->
751
+ <div id="loader">
752
+ <div class="loader-ring"></div>
753
+ <div class="loader-logo">
754
+ <h1 id="loader-title">cycle<span>WASH</span></h1>
755
+ <div class="loader-product">STATION BASIC</div>
756
+ </div>
757
+ <div id="progress-bar"><div id="progress-fill"></div></div>
758
+ <div id="progress-text">Loading 3D model...</div>
759
+ </div>
760
+
761
+ <!-- 3D Canvas -->
762
+ <div id="three-canvas"></div>
763
+
764
+ <!-- Scroll-driven content -->
765
+ <div id="scroll-driver">
766
+ <!-- Hero -->
767
+ <section class="hero">
768
+ <div class="hero-badge">Professional Bike Washing</div>
769
+ <h1>cycle<span>WASH</span></h1>
770
+ <div class="model-name">STATION BASIC</div>
771
+ <div class="tagline">Engineered in Germany. 399 precision components. One seamless cleaning experience.</div>
772
+ <div class="scroll-hint">Scroll to explore</div>
773
+ </section>
774
+
775
+ <!-- Spacer for initial explosion -->
776
+ <section class="spacer" data-phase="explode"></section>
777
+
778
+ <!-- Assembly sections (generated by JS) -->
779
+ <div id="assembly-sections"></div>
780
+
781
+ <!-- Reassemble spacer -->
782
+ <section class="spacer" data-phase="reassemble"></section>
783
+
784
+ <!-- Finale -->
785
+ <section class="finale" data-phase="finale">
786
+ <h2>cycleWASH <span>Station Basic</span></h2>
787
+ <div class="specs">
788
+ <div class="spec">
789
+ <div class="spec-value">399</div>
790
+ <div class="spec-label">Components</div>
791
+ </div>
792
+ <div class="spec">
793
+ <div class="spec-value">6</div>
794
+ <div class="spec-label">Sub-Assemblies</div>
795
+ </div>
796
+ <div class="spec">
797
+ <div class="spec-value">100%</div>
798
+ <div class="spec-label">Stainless Steel</div>
799
+ </div>
800
+ </div>
801
+ </section>
802
+ </div>
803
+
804
+ <!-- Left Navigation Button + Dropdown -->
805
+ <!-- Left-nav sidebar hidden — replaced by Tree panel -->
806
+ <div id="left-nav-btn" style="display:none;position:fixed;left:14px;top:125px;z-index:50;cursor:pointer;">
807
+ <div class="nav-item" id="nav-toggle" style="color:#FFD100;border-color:rgba(255,209,0,0.2);background:rgba(0,0,0,0.5);min-width:auto;padding:10px 16px;gap:10px;">
808
+ <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="#FFD100" stroke-width="2" stroke-linecap="round"><rect x="3" y="3" width="7" height="7"/><rect x="14" y="3" width="7" height="7"/><rect x="3" y="14" width="7" height="7"/><rect x="14" y="14" width="7" height="7"/></svg>
809
+ <div class="nav-label" style="font-size:0.8rem;color:rgba(255,255,255,0.7);font-weight:600;">Views</div>
810
+ <svg id="nav-chevron" width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="rgba(255,255,255,0.4)" stroke-width="2" stroke-linecap="round" style="transition:transform 0.3s;"><polyline points="6 9 12 15 18 9"/></svg>
811
+ </div>
812
+ </div>
813
+ <div id="selected-asm-info" style="display:none;"><div id="sel-asm-name"></div><div id="sel-asm-sub"></div><div id="sel-asm-parts"></div></div>
814
+ <nav id="left-nav" style="display:none !important;"><div class="nav-items" id="nav-items"></div></nav>
815
+
816
+ <!-- Top Navigation Bar -->
817
+ <header id="top-nav">
818
+ <div class="top-logo" id="top-logo">cycleWASH <span>Station Basic</span></div>
819
+ <nav class="top-links"></nav>
820
+ <div class="top-actions" id="top-actions">
821
+ <select id="top-lang-select" style="background:rgba(255,255,255,0.08);border:1px solid rgba(255,255,255,0.15);color:#ccd;padding:4px 8px;border-radius:6px;font-size:0.7rem;font-family:inherit;cursor:pointer;outline:none;">
822
+ <option value="en">🌐 EN</option>
823
+ <option value="de">🌐 DE</option>
824
+ <option value="fr">🌐 FR</option>
825
+ <option value="es">🌐 ES</option>
826
+ <option value="it">🌐 IT</option>
827
+ <option value="nl">🌐 NL</option>
828
+ </select>
829
+ </div>
830
+ </header>
831
+
832
+ <!-- Mobile title bar (shows full product name) -->
833
+ <!-- ViewCube (top-right) -->
834
+ <!-- Toolbar (compact, grouped logically) -->
835
+ <div id="ce-buttons" style="position:fixed;left:50%;transform:translateX(-50%);top:60px;z-index:60;display:flex;flex-wrap:wrap;gap:4px;align-items:center;justify-content:center;background:rgba(10,12,20,0.75);backdrop-filter:blur(16px);-webkit-backdrop-filter:blur(16px);border-radius:12px;padding:6px 10px;border:1px solid rgba(255,255,255,0.1);max-width:95vw;">
836
+ <!-- Assembly Tree -->
837
+ <button class="vc-btn" id="btn-tree" title="Assembly Tree — components &amp; AI drawings"><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" style="vertical-align:-2px;margin-right:3px;"><rect x="2" y="2" width="6" height="6" rx="1"/><rect x="12" y="6" width="6" height="6" rx="1"/><rect x="12" y="16" width="6" height="6" rx="1"/><line x1="8" y1="5" x2="12" y2="9"/><line x1="8" y1="5" x2="8" y2="19"/><line x1="8" y1="19" x2="12" y2="19"/></svg>Tree</button>
838
+ <button class="vc-btn" id="btn-export" title="Export/Screenshot">&#128247;</button>
839
+ <div style="width:1px;height:20px;background:rgba(255,255,255,0.1);margin:0 2px;"></div>
840
+ <!-- Media group: Animate / Record / Hero Shots -->
841
+ <button class="vc-btn" id="btn-animation" title="Animation Sequence">🎥 Anim</button>
842
+ <button class="vc-btn" id="btn-record-gif" title="Record Explode-to-GIF / Video"><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" style="vertical-align:-2px;margin-right:3px;"><circle cx="12" cy="12" r="10"/><circle cx="12" cy="12" r="3" fill="currentColor"/></svg>Record</button>
843
+ <button class="vc-btn" id="btn-hero-shots" title="Auto-generate marketing hero images"><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" style="vertical-align:-2px;margin-right:3px;"><rect x="3" y="3" width="18" height="18" rx="2" ry="2"/><circle cx="8.5" cy="8.5" r="1.5"/><polyline points="21 15 16 10 5 21"/></svg>Hero Shots</button>
844
+ <div style="width:1px;height:20px;background:rgba(255,255,255,0.1);margin:0 2px;"></div>
845
+ <!-- AR / QR group -->
846
+ <button class="vc-btn" id="btn-camera-scan" title="AR Scanner — identify subassembly with camera">📸 AR</button>
847
+ <button class="vc-btn" id="btn-qr-share" title="QR Code for sharing / AR"><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" style="vertical-align:-2px;margin-right:3px;"><rect x="2" y="2" width="8" height="8" rx="1"/><rect x="14" y="2" width="8" height="8" rx="1"/><rect x="2" y="14" width="8" height="8" rx="1"/><rect x="14" y="14" width="4" height="4"/><line x1="22" y1="18" x2="22" y2="22"/><line x1="18" y1="22" x2="22" y2="22"/></svg>QR</button>
848
+ <div style="width:1px;height:20px;background:rgba(255,255,255,0.1);margin:0 2px;"></div>
849
+ <!-- Manufacturing group: Slicer (BOM accessible via tree panel) -->
850
+ <button class="vc-btn" id="btn-slicer" title="3D Print Slicer — G-code generation"><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" style="vertical-align:-2px;margin-right:3px;"><path d="M12 2L2 7l10 5 10-5-10-5z"/><path d="M2 17l10 5 10-5"/><path d="M2 12l10 5 10-5"/></svg>Slicer</button>
851
+ <button class="vc-btn" id="btn-standards" title="DIN/ISO Standard Parts & McMaster-Carr">🔩 Standards</button>
852
+ <div style="width:1px;height:20px;background:rgba(255,255,255,0.1);margin:0 2px;"></div>
853
+ <!-- Analysis group: Section Cut / Measure / Annotate / AI Render -->
854
+ <button class="vc-btn" id="btn-section-cut" title="Cross-Section Cut — slice through the model">✂️ Section</button>
855
+ <button class="vc-btn" id="btn-measure" title="Measurement Tool">📏 Measure</button>
856
+ <button class="vc-btn" id="btn-annotate" title="Add Annotation">📌 Annotate</button>
857
+ <button class="vc-btn" id="btn-ai-render" title="AI Render" style="position:relative;">✨ AI<span style="position:absolute;top:-2px;right:-2px;width:6px;height:6px;background:linear-gradient(135deg,#0055A4,#FFD100);border-radius:50%;"></span></button>
858
+ <div style="width:1px;height:20px;background:rgba(255,255,255,0.1);margin:0 2px;"></div>
859
+ <!-- Tools group -->
860
+ <button class="vc-btn" id="btn-share" title="Share & Embed">🔗 Share</button>
861
+ <button class="vc-btn" id="btn-load-model" title="Model Library">📦 Library</button>
862
+ <button class="vc-btn" id="btn-docs-mode" title="Interactive Manual / Documentation">📖 Manual</button>
863
+ <button class="vc-btn" id="btn-export-bom" title="Export Bill of Materials as CSV">📊 BOM</button>
864
+ <div style="width:1px;height:20px;background:rgba(255,255,255,0.1);margin:0 2px;"></div>
865
+ <!-- Settings group -->
866
+ <button class="vc-btn" id="btn-settings" title="Configure UI"><svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" style="vertical-align:-2px;margin-right:3px;"><path d="M14.7 6.3a1 1 0 000 1.4l1.6 1.6a1 1 0 001.4 0l3.77-3.77a6 6 0 01-7.94 7.94l-6.91 6.91a2.12 2.12 0 01-3-3l6.91-6.91a6 6 0 017.94-7.94l-3.76 3.76z"/></svg>Configure</button>
867
+ <button class="vc-btn" id="btn-theme" title="Switch Theme">🎨</button>
868
+ <button class="vc-btn" id="btn-debug-console" title="Debug Console — logs, warnings &amp; errors (Ctrl+Shift+D)"><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" style="vertical-align:-2px;"><polyline points="4 17 10 11 4 5"/><line x1="12" y1="19" x2="20" y2="19"/></svg></button>
869
+ <!-- Version badge -->
870
+ <!-- Fullscreen moved to right nav -->
871
+ </div>
872
+ <span id="version-badge" style="position:fixed;bottom:8px;left:50%;transform:translateX(-50%);z-index:70;font-size:0.65rem;color:rgba(255,255,255,0.45);letter-spacing:0.08em;white-space:nowrap;padding:3px 10px;user-select:all;pointer-events:auto;font-family:monospace;background:rgba(0,0,0,0.3);border-radius:4px;" title="ExplodeView version">ExplodeView v205</span>
873
+ <!-- Hidden explode button (used by JS, actual UI in Tree panel) -->
874
+ <button id="btn-explode-toggle" style="display:none;">Explode</button>
875
+ <!-- Hidden nav buttons (used by JS, actual UI in Tree panel) -->
876
+ <button id="btn-prev" style="display:none;">←</button>
877
+ <button id="btn-next" style="display:none;">→</button>
878
+ <div id="ctrl-progress-fill" style="display:none;"></div>
879
+ <div id="ctrl-label" style="display:none;"></div>
880
+
881
+ <!-- Embed Settings Panel -->
882
+ <div id="embed-settings-panel" style="display:none;position:fixed;right:14px;top:95px;z-index:200;background:rgba(0,0,0,0.92);backdrop-filter:blur(20px);border:1px solid rgba(255,255,255,0.12);border-radius:12px;padding:18px 22px;width:320px;max-width:90vw;font-family:Inter,sans-serif;max-height:80vh;overflow-y:auto;">
883
+ <div style="display:flex;align-items:center;justify-content:space-between;margin-bottom:14px;">
884
+ <div style="font-size:0.8rem;letter-spacing:0.12em;text-transform:uppercase;color:#4da6ff;font-weight:600;display:flex;align-items:center;gap:6px;" id="settings-title"><svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="#4da6ff" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="3"/><path d="M1 12s4-8 11-8 11 8 11 8-4 8-11 8-11-8-11-8z"/></svg>Show / Hide Features</div>
885
+ <button id="settings-close" style="background:none;border:none;color:#667;font-size:1.3rem;cursor:pointer;">×</button>
886
+ </div>
887
+ <!-- Language selector -->
888
+ <div style="margin-bottom:14px;">
889
+ <div style="font-size:0.7rem;color:rgba(255,255,255,0.5);margin-bottom:6px;text-transform:uppercase;letter-spacing:0.1em;" id="settings-lang-label">Language</div>
890
+ <select id="settings-lang" style="width:100%;background:rgba(255,255,255,0.06);border:1px solid rgba(255,255,255,0.12);color:#ccd;padding:8px 12px;border-radius:8px;font-size:0.8rem;font-family:inherit;">
891
+ <option value="en">English</option>
892
+ <option value="de">Deutsch</option>
893
+ <option value="fr">Français</option>
894
+ <option value="es">Español</option>
895
+ <option value="it">Italiano</option>
896
+ <option value="nl">Nederlands</option>
897
+ </select>
898
+ </div>
899
+ <!-- Toggle controls visibility -->
900
+ <div style="margin-bottom:14px;">
901
+ <div style="font-size:0.7rem;color:rgba(255,255,255,0.5);margin-bottom:8px;text-transform:uppercase;letter-spacing:0.1em;" id="settings-showhide-label">Show / Hide Controls</div>
902
+ <div id="settings-toggles" style="display:flex;flex-direction:column;gap:6px;"></div>
903
+ </div>
904
+ <!-- Copy embed code -->
905
+ <button class="vc-btn" id="settings-copy-embed" style="width:100%;justify-content:center;font-size:0.8rem;padding:10px;margin-top:8px;">Copy Embed Code</button>
906
+ </div>
907
+
908
+ <!-- Export Panel -->
909
+ <div id="export-panel" style="display:none;position:fixed;right:14px;top:95px;z-index:65;background:rgba(0,0,0,0.8);backdrop-filter:blur(16px);border:1px solid rgba(255,255,255,0.1);border-radius:10px;padding:14px 18px;width:280px;font-family:Inter,sans-serif;">
910
+ <div style="display:flex;align-items:center;justify-content:space-between;margin-bottom:10px;">
911
+ <div style="font-size:0.8rem;letter-spacing:0.2em;text-transform:uppercase;color:rgba(255,255,255,0.3);">Export Screenshot</div>
912
+ <button class="panel-close-btn" data-close-panel="export-panel" style="background:none;border:none;color:#667;font-size:1.3rem;cursor:pointer;line-height:1;padding:2px 6px;">×</button>
913
+ </div>
914
+ <div style="display:flex;flex-direction:column;gap:5px;">
915
+ <button class="vc-btn" id="exp-png" style="width:100%;font-size:0.8rem;padding:8px 10px;justify-content:center;">PNG (transparent)</button>
916
+ <button class="vc-btn" id="exp-png-bg" style="width:100%;font-size:0.8rem;padding:8px 10px;justify-content:center;">PNG (with background)</button>
917
+ <button class="vc-btn" id="exp-jpg" style="width:100%;font-size:0.8rem;padding:8px 10px;justify-content:center;">JPG (with background)</button>
918
+ <button class="vc-btn" id="exp-webp" style="width:100%;font-size:0.8rem;padding:8px 10px;justify-content:center;">WebP (smaller file)</button>
919
+ <button class="vc-btn" id="exp-tiff" style="width:100%;font-size:0.8rem;padding:8px 10px;justify-content:center;">TIFF (print quality)</button>
920
+ </div>
921
+ <div style="font-size:0.8rem;letter-spacing:0.2em;text-transform:uppercase;color:rgba(255,255,255,0.3);margin:10px 0 6px;">Resolution</div>
922
+ <select id="exp-res" style="width:100%;background:rgba(255,255,255,0.06);border:1px solid rgba(255,255,255,0.1);color:#aaa;padding:4px;border-radius:4px;font-size:0.8rem;font-family:inherit;">
923
+ <option value="1">1x (screen)</option>
924
+ <option value="2" selected>2x (high-res)</option>
925
+ <option value="4">4x (print quality)</option>
926
+ </select>
927
+ </div>
928
+
929
+ <!-- Record GIF / Video Panel -->
930
+ <div id="record-panel" style="display:none;position:fixed;right:14px;top:95px;z-index:65;background:rgba(0,0,0,0.92);backdrop-filter:blur(20px);border:1px solid rgba(255,255,255,0.12);border-radius:12px;padding:18px 22px;width:340px;font-family:Inter,sans-serif;">
931
+ <div style="display:flex;align-items:center;justify-content:space-between;margin-bottom:14px;">
932
+ <div style="font-size:0.85rem;letter-spacing:0.12em;text-transform:uppercase;color:#ff4466;font-weight:600;">Record Explode Animation</div>
933
+ <button class="panel-close-btn" data-close-panel="record-panel" style="background:none;border:none;color:#667;font-size:1.3rem;cursor:pointer;line-height:1;padding:2px 6px;">×</button>
934
+ </div>
935
+ <div style="font-size:0.75rem;color:rgba(255,255,255,0.4);margin-bottom:12px;">Captures a smooth explode → orbit → collapse animation as GIF or WebM video.</div>
936
+ <div style="display:flex;flex-direction:column;gap:8px;">
937
+ <div style="display:flex;gap:8px;align-items:center;">
938
+ <label style="font-size:0.75rem;color:rgba(255,255,255,0.5);min-width:70px;">Duration</label>
939
+ <select id="rec-duration" style="flex:1;background:rgba(255,255,255,0.06);border:1px solid rgba(255,255,255,0.1);color:#ccd;padding:6px 10px;border-radius:6px;font-size:0.8rem;font-family:inherit;">
940
+ <option value="3">3 seconds</option>
941
+ <option value="5" selected>5 seconds</option>
942
+ <option value="8">8 seconds</option>
943
+ <option value="12">12 seconds</option>
944
+ </select>
945
+ </div>
946
+ <div style="display:flex;gap:8px;align-items:center;">
947
+ <label style="font-size:0.75rem;color:rgba(255,255,255,0.5);min-width:70px;">Size</label>
948
+ <select id="rec-size" style="flex:1;background:rgba(255,255,255,0.06);border:1px solid rgba(255,255,255,0.1);color:#ccd;padding:6px 10px;border-radius:6px;font-size:0.8rem;font-family:inherit;">
949
+ <option value="480">480p (fast)</option>
950
+ <option value="720" selected>720p</option>
951
+ <option value="1080">1080p (large)</option>
952
+ </select>
953
+ </div>
954
+ <div style="display:flex;gap:8px;align-items:center;">
955
+ <label style="font-size:0.75rem;color:rgba(255,255,255,0.5);min-width:70px;">Format</label>
956
+ <select id="rec-format" style="flex:1;background:rgba(255,255,255,0.06);border:1px solid rgba(255,255,255,0.1);color:#ccd;padding:6px 10px;border-radius:6px;font-size:0.8rem;font-family:inherit;">
957
+ <option value="mp4" selected>MP4 video</option>
958
+ <option value="gif">Animated GIF</option>
959
+ <option value="webm">WebM video</option>
960
+ </select>
961
+ </div>
962
+ <div style="display:flex;gap:6px;margin-top:6px;">
963
+ <button class="vc-btn" id="rec-start" style="flex:1;justify-content:center;font-size:0.85rem;padding:10px;background:rgba(255,68,102,0.15);border-color:rgba(255,68,102,0.4);color:#ff4466;">⏺ Start Recording</button>
964
+ </div>
965
+ <div id="rec-progress" style="display:none;">
966
+ <div style="height:4px;background:rgba(255,255,255,0.06);border-radius:2px;overflow:hidden;margin-bottom:6px;">
967
+ <div id="rec-progress-bar" style="height:100%;width:0%;background:linear-gradient(90deg,#ff4466,#FFD100);border-radius:2px;transition:width 0.1s;"></div>
968
+ </div>
969
+ <div id="rec-status" style="font-size:0.7rem;color:rgba(255,255,255,0.4);text-align:center;">Recording...</div>
970
+ </div>
971
+ </div>
972
+ </div>
973
+
974
+ <!-- BOM (Bill of Materials) Panel -->
975
+ <div id="bom-panel" style="display:none;position:fixed;left:50%;top:50%;transform:translate(-50%,-50%);z-index:200;background:rgba(0,0,0,0.95);backdrop-filter:blur(20px);border:1px solid rgba(255,255,255,0.12);border-radius:14px;padding:20px 24px;width:700px;max-width:92vw;max-height:80vh;overflow:hidden;font-family:Inter,sans-serif;display:none;flex-direction:column;">
976
+ <div style="display:flex;align-items:center;justify-content:space-between;margin-bottom:14px;">
977
+ <div style="font-size:0.9rem;letter-spacing:0.12em;text-transform:uppercase;color:#4da6ff;font-weight:600;">Bill of Materials</div>
978
+ <div style="display:flex;gap:8px;align-items:center;">
979
+ <button class="vc-btn" id="bom-copy" style="font-size:0.75rem;padding:5px 12px;">Copy</button>
980
+ <button class="vc-btn" id="bom-csv" style="font-size:0.75rem;padding:5px 12px;">CSV</button>
981
+ <button class="panel-close-btn" data-close-panel="bom-panel" style="background:none;border:none;color:#667;font-size:1.3rem;cursor:pointer;line-height:1;padding:2px 6px;">×</button>
982
+ </div>
983
+ </div>
984
+ <div style="font-size:0.7rem;color:rgba(255,255,255,0.3);margin-bottom:10px;" id="bom-summary">0 parts — 0 assemblies</div>
985
+ <div id="bom-table-wrap" style="flex:1;overflow-y:auto;max-height:60vh;">
986
+ <table id="bom-table" style="width:100%;border-collapse:collapse;font-size:0.78rem;">
987
+ <thead>
988
+ <tr style="position:sticky;top:0;background:rgba(0,0,0,0.95);z-index:1;">
989
+ <th style="text-align:left;padding:8px 10px;color:rgba(255,255,255,0.4);font-weight:600;border-bottom:1px solid rgba(255,255,255,0.1);font-size:0.7rem;text-transform:uppercase;letter-spacing:0.08em;">#</th>
990
+ <th style="text-align:left;padding:8px 10px;color:rgba(255,255,255,0.4);font-weight:600;border-bottom:1px solid rgba(255,255,255,0.1);font-size:0.7rem;text-transform:uppercase;letter-spacing:0.08em;">Part / Assembly</th>
991
+ <th style="text-align:left;padding:8px 10px;color:rgba(255,255,255,0.4);font-weight:600;border-bottom:1px solid rgba(255,255,255,0.1);font-size:0.7rem;text-transform:uppercase;letter-spacing:0.08em;">Parts</th>
992
+ <th style="text-align:left;padding:8px 10px;color:rgba(255,255,255,0.4);font-weight:600;border-bottom:1px solid rgba(255,255,255,0.1);font-size:0.7rem;text-transform:uppercase;letter-spacing:0.08em;">Assembly</th>
993
+ <th style="text-align:left;padding:8px 10px;color:rgba(255,255,255,0.4);font-weight:600;border-bottom:1px solid rgba(255,255,255,0.1);font-size:0.7rem;text-transform:uppercase;letter-spacing:0.08em;">Drawing</th>
994
+ </tr>
995
+ </thead>
996
+ <tbody id="bom-tbody"></tbody>
997
+ </table>
998
+ </div>
999
+ </div>
1000
+
1001
+ <!-- QR Code Panel -->
1002
+ <div id="qr-panel" style="display:none;position:fixed;right:14px;top:95px;z-index:65;background:rgba(0,0,0,0.92);backdrop-filter:blur(20px);border:1px solid rgba(255,255,255,0.12);border-radius:12px;padding:18px 22px;width:300px;font-family:Inter,sans-serif;text-align:center;">
1003
+ <div style="display:flex;align-items:center;justify-content:space-between;margin-bottom:14px;">
1004
+ <div style="font-size:0.85rem;letter-spacing:0.12em;text-transform:uppercase;color:#4da6ff;font-weight:600;">QR Code</div>
1005
+ <button class="panel-close-btn" data-close-panel="qr-panel" style="background:none;border:none;color:#667;font-size:1.3rem;cursor:pointer;line-height:1;padding:2px 6px;">×</button>
1006
+ </div>
1007
+ <div style="font-size:0.75rem;color:rgba(255,255,255,0.4);margin-bottom:12px;">Scan to open this viewer on any device. Share with clients or use for AR.</div>
1008
+ <canvas id="qr-canvas" width="200" height="200" style="background:#fff;border-radius:8px;margin:0 auto 12px;display:block;"></canvas>
1009
+ <div id="qr-url" style="font-size:0.7rem;color:rgba(255,255,255,0.3);word-break:break-all;margin-bottom:10px;"></div>
1010
+ <button class="vc-btn" id="qr-download" style="width:100%;justify-content:center;font-size:0.8rem;padding:8px;">Download QR PNG</button>
1011
+ </div>
1012
+
1013
+ <!-- Hero Shots Panel -->
1014
+ <div id="hero-panel" style="display:none;position:fixed;right:14px;top:95px;z-index:65;background:rgba(0,0,0,0.92);backdrop-filter:blur(20px);border:1px solid rgba(255,255,255,0.12);border-radius:12px;padding:18px 22px;width:340px;font-family:Inter,sans-serif;">
1015
+ <div style="display:flex;align-items:center;justify-content:space-between;margin-bottom:14px;">
1016
+ <div style="font-size:0.85rem;letter-spacing:0.12em;text-transform:uppercase;color:#FFD100;font-weight:600;">Marketing Hero Shots</div>
1017
+ <button class="panel-close-btn" data-close-panel="hero-panel" style="background:none;border:none;color:#667;font-size:1.3rem;cursor:pointer;line-height:1;padding:2px 6px;">×</button>
1018
+ </div>
1019
+ <div style="font-size:0.75rem;color:rgba(255,255,255,0.4);margin-bottom:12px;">One-click hero images for social media, presentations, and product pages.</div>
1020
+ <div style="display:flex;flex-direction:column;gap:6px;">
1021
+ <button class="vc-btn" id="hero-front" style="width:100%;font-size:0.8rem;padding:10px;justify-content:center;">Front Hero — white bg (1920×1080)</button>
1022
+ <button class="vc-btn" id="hero-iso" style="width:100%;font-size:0.8rem;padding:10px;justify-content:center;">Isometric — transparent (2048×2048)</button>
1023
+ <button class="vc-btn" id="hero-exploded" style="width:100%;font-size:0.8rem;padding:10px;justify-content:center;">Exploded View — transparent (2048×2048)</button>
1024
+ <button class="vc-btn" id="hero-social-sq" style="width:100%;font-size:0.8rem;padding:10px;justify-content:center;">Social Square — 1080×1080</button>
1025
+ <button class="vc-btn" id="hero-social-story" style="width:100%;font-size:0.8rem;padding:10px;justify-content:center;">Social Story — 1080×1920</button>
1026
+ <button class="vc-btn" id="hero-all" style="width:100%;font-size:0.85rem;padding:12px;justify-content:center;background:rgba(255,209,0,0.12);border-color:rgba(255,209,0,0.35);color:#FFD100;">⬇ Download All (ZIP)</button>
1027
+ </div>
1028
+ <div id="hero-progress" style="display:none;margin-top:10px;">
1029
+ <div style="height:4px;background:rgba(255,255,255,0.06);border-radius:2px;overflow:hidden;">
1030
+ <div id="hero-progress-bar" style="height:100%;width:0%;background:linear-gradient(90deg,#FFD100,#ff9900);border-radius:2px;transition:width 0.2s;"></div>
1031
+ </div>
1032
+ <div id="hero-status" style="font-size:0.7rem;color:rgba(255,255,255,0.4);text-align:center;margin-top:4px;">Generating...</div>
1033
+ </div>
1034
+ </div>
1035
+
1036
+
1037
+ <!-- Part Info Card Panel -->
1038
+ <div id="part-info-card" style="display:none;position:fixed;right:20px;top:100px;z-index:64;background:rgba(0,0,0,0.92);backdrop-filter:blur(16px);border:1px solid rgba(255,255,255,0.15);border-radius:14px;padding:16px;width:320px;max-width:90vw;font-family:Inter,sans-serif;color:#fff;box-shadow:0 8px 32px rgba(0,0,0,0.5);">
1039
+ <div style="display:flex;justify-content:space-between;align-items:flex-start;margin-bottom:12px;">
1040
+ <div>
1041
+ <div id="pic-part-number" style="font-size:0.75rem;color:rgba(255,255,255,0.5);letter-spacing:0.05em;margin-bottom:2px;">PART</div>
1042
+ <div id="pic-part-name" style="font-size:0.95rem;font-weight:600;color:#fff;margin-bottom:4px;">—</div>
1043
+ <div id="pic-assembly-name" style="font-size:0.8rem;color:rgba(255,255,255,0.6);">—</div>
1044
+ </div>
1045
+ <button id="pic-close" style="background:none;border:none;color:#888;font-size:1.1rem;cursor:pointer;padding:0;margin-top:-4px;">✕</button>
1046
+ </div>
1047
+ <div style="border-top:1px solid rgba(255,255,255,0.1);margin-bottom:12px;padding-top:12px;">
1048
+ <div style="display:grid;grid-template-columns:1fr 1fr;gap:10px;font-size:0.75rem;margin-bottom:12px;">
1049
+ <div>
1050
+ <div style="color:rgba(255,255,255,0.4);margin-bottom:2px;font-size:0.65rem;">Material</div>
1051
+ <div id="pic-material" style="color:rgba(255,255,255,0.8);font-weight:500;">—</div>
1052
+ </div>
1053
+ <div>
1054
+ <div style="color:rgba(255,255,255,0.4);margin-bottom:2px;font-size:0.65rem;">Weight</div>
1055
+ <div id="pic-weight" style="color:rgba(255,255,255,0.8);font-weight:500;">—</div>
1056
+ </div>
1057
+ </div>
1058
+ <div>
1059
+ <div style="color:rgba(255,255,255,0.4);margin-bottom:2px;font-size:0.65rem;">Finish</div>
1060
+ <div id="pic-finish" style="color:rgba(255,255,255,0.8);font-weight:500;font-size:0.75rem;">—</div>
1061
+ </div>
1062
+ </div>
1063
+ <div style="border-top:1px solid rgba(255,255,255,0.1);margin-bottom:12px;padding-top:12px;">
1064
+ <div style="color:rgba(255,255,255,0.4);margin-bottom:6px;font-size:0.65rem;font-weight:600;letter-spacing:0.05em;">Maintenance</div>
1065
+ <ul id="pic-maintenance" style="list-style:none;font-size:0.7rem;color:rgba(255,255,255,0.7);line-height:1.4;">
1066
+ </ul>
1067
+ </div>
1068
+ <div style="border-top:1px solid rgba(255,255,255,0.1);padding-top:12px;">
1069
+ <div style="color:rgba(255,255,255,0.4);margin-bottom:4px;font-size:0.65rem;font-weight:600;">Service Interval</div>
1070
+ <div id="pic-service-interval" style="color:rgba(255,255,255,0.8);font-weight:500;font-size:0.75rem;">—</div>
1071
+ </div>
1072
+ </div>
1073
+
1074
+ <!-- Measurement Panel -->
1075
+ <div id="measurement-panel" style="display:none;position:fixed;bottom:80px;right:20px;z-index:65;background:rgba(0,0,0,0.92);backdrop-filter:blur(16px);border:1px solid rgba(255,102,0,0.3);border-radius:12px;padding:16px;width:280px;max-height:400px;font-family:Inter,sans-serif;box-shadow:0 8px 32px rgba(0,0,0,0.5);overflow-y:auto;">
1076
+ <div style="display:flex;justify-content:space-between;align-items:center;margin-bottom:12px;">
1077
+ <div style="font-size:0.9rem;font-weight:600;color:#ff6600;letter-spacing:0.04em;">📏 MEASUREMENTS</div>
1078
+ <button id="measurement-panel-close" style="background:none;border:none;color:#888;font-size:1.1rem;cursor:pointer;padding:2px 6px;line-height:1;">✕</button>
1079
+ </div>
1080
+ <div id="measurement-list" style="font-size:0.8rem;color:#ddd;margin-bottom:12px;min-height:20px;">
1081
+ <div style="color:#888;font-style:italic;">No measurements yet</div>
1082
+ </div>
1083
+ <button id="btn-clear-all-measurements" class="vc-btn" style="width:100%;padding:10px;font-size:0.75rem;border-radius:6px;background:rgba(255,102,0,0.15);border-color:rgba(255,102,0,0.3);color:#ff6600;">Clear All</button>
1084
+ </div>
1085
+
1086
+ <!-- Section Cut Panel -->
1087
+ <div id="section-cut-panel" style="display:none;position:fixed;bottom:80px;left:50%;transform:translateX(-50%);z-index:65;background:rgba(0,0,0,0.92);backdrop-filter:blur(16px);border:1px solid rgba(255,255,255,0.1);border-radius:12px;padding:14px 20px;width:420px;max-width:90vw;font-family:Inter,sans-serif;">
1088
+ <div style="display:flex;justify-content:space-between;align-items:center;margin-bottom:10px;">
1089
+ <div style="font-size:0.85rem;font-weight:700;color:#fff;">✂️ Section Cut</div>
1090
+ <button id="section-cut-close" style="background:none;border:none;color:#888;font-size:1.1rem;cursor:pointer;padding:2px 6px;">✕</button>
1091
+ </div>
1092
+ <div style="display:flex;gap:8px;margin-bottom:10px;">
1093
+ <button class="sc-axis-btn active" data-axis="x" style="flex:1;padding:6px;border-radius:6px;border:1px solid rgba(255,80,80,0.4);background:rgba(255,80,80,0.15);color:#ff5050;font-size:0.75rem;font-weight:600;cursor:pointer;">X Axis</button>
1094
+ <button class="sc-axis-btn" data-axis="y" style="flex:1;padding:6px;border-radius:6px;border:1px solid rgba(80,255,80,0.4);background:rgba(80,255,80,0.08);color:#50ff50;font-size:0.75rem;font-weight:600;cursor:pointer;">Y Axis</button>
1095
+ <button class="sc-axis-btn" data-axis="z" style="flex:1;padding:6px;border-radius:6px;border:1px solid rgba(80,140,255,0.4);background:rgba(80,140,255,0.08);color:#508cff;font-size:0.75rem;font-weight:600;cursor:pointer;">Z Axis</button>
1096
+ </div>
1097
+ <div style="display:flex;align-items:center;gap:10px;margin-bottom:8px;">
1098
+ <span style="font-size:0.65rem;color:rgba(255,255,255,0.4);min-width:48px;">Position</span>
1099
+ <input type="range" id="section-cut-slider" min="0" max="100" value="50" style="flex:1;accent-color:#4da6ff;">
1100
+ <span id="section-cut-value" style="font-size:0.7rem;color:#4da6ff;min-width:35px;text-align:right;">50%</span>
1101
+ </div>
1102
+ <div style="display:flex;gap:8px;">
1103
+ <button id="section-cut-flip" style="flex:1;padding:6px;border-radius:6px;border:1px solid rgba(255,255,255,0.15);background:rgba(255,255,255,0.06);color:#ccc;font-size:0.7rem;cursor:pointer;">↔ Flip Direction</button>
1104
+ <button id="section-cut-toggle" style="flex:1;padding:6px;border-radius:6px;border:1px solid rgba(77,166,255,0.3);background:rgba(77,166,255,0.12);color:#4da6ff;font-size:0.7rem;font-weight:600;cursor:pointer;">● Enable Cut</button>
1105
+ </div>
1106
+ </div>
1107
+
1108
+ <!-- 3D Print Slicer Panel -->
1109
+ <div id="slicer-panel" style="display:none;position:fixed;left:50%;top:50%;transform:translate(-50%,-50%);z-index:200;background:rgba(0,0,0,0.96);backdrop-filter:blur(24px);border:1px solid rgba(255,255,255,0.12);border-radius:14px;padding:20px 24px;width:800px;max-width:95vw;max-height:90vh;overflow:hidden;font-family:Inter,sans-serif;flex-direction:column;">
1110
+ <div style="display:flex;align-items:center;justify-content:space-between;margin-bottom:14px;">
1111
+ <div style="display:flex;align-items:center;gap:10px;">
1112
+ <div style="font-size:0.9rem;letter-spacing:0.12em;text-transform:uppercase;color:#00cc88;font-weight:600;">3D Print Slicer</div>
1113
+ <span style="font-size:0.65rem;color:rgba(255,255,255,0.25);padding:2px 8px;border:1px solid rgba(255,255,255,0.1);border-radius:4px;">BETA</span>
1114
+ </div>
1115
+ <button class="panel-close-btn" data-close-panel="slicer-panel" style="background:none;border:none;color:#667;font-size:1.3rem;cursor:pointer;line-height:1;padding:2px 6px;">×</button>
1116
+ </div>
1117
+ <div id="slicer-target-label" style="font-size:0.7rem;color:rgba(255,255,255,0.5);margin-bottom:10px;padding:6px 10px;background:rgba(255,255,255,0.04);border-radius:6px;border:1px solid rgba(255,255,255,0.06);display:none;">Slicing: <span id="slicer-target-name" style="color:#00cc88;font-weight:600;">All Parts</span></div>
1118
+
1119
+ <div style="display:flex;gap:16px;flex:1;overflow:hidden;">
1120
+ <!-- Left: Settings -->
1121
+ <div style="width:320px;flex-shrink:0;overflow-y:auto;max-height:65vh;padding-right:10px;">
1122
+ <!-- Printer -->
1123
+ <div style="margin-bottom:12px;">
1124
+ <label style="font-size:0.7rem;color:rgba(255,255,255,0.4);text-transform:uppercase;letter-spacing:0.08em;display:block;margin-bottom:4px;">Printer</label>
1125
+ <select id="slicer-printer" style="width:100%;background:rgba(255,255,255,0.06);border:1px solid rgba(255,255,255,0.1);color:#ccd;padding:8px 10px;border-radius:6px;font-size:0.8rem;font-family:inherit;">
1126
+ <optgroup label="Creality">
1127
+ <option value="ender3" selected>Creality Ender 3 (220×220×250)</option>
1128
+ <option value="ender3v2">Creality Ender 3 V2 (220×220×250)</option>
1129
+ <option value="ender3s1">Creality Ender 3 S1 (220×220×270)</option>
1130
+ <option value="ender5">Creality Ender 5 (220×220×300)</option>
1131
+ <option value="cr10">Creality CR-10 (300×300×400)</option>
1132
+ </optgroup>
1133
+ <optgroup label="Prusa">
1134
+ <option value="prusamk3s">Prusa MK3S+ (250×210×210)</option>
1135
+ <option value="prusamk4">Prusa MK4 (250×210×220)</option>
1136
+ <option value="prusamini">Prusa MINI+ (180×180×180)</option>
1137
+ </optgroup>
1138
+ <optgroup label="Bambu Lab">
1139
+ <option value="bambux1">Bambu Lab X1 Carbon (256×256×256)</option>
1140
+ <option value="bambup1s">Bambu Lab P1S (256×256×256)</option>
1141
+ <option value="bambua1">Bambu Lab A1 (256×256×256)</option>
1142
+ </optgroup>
1143
+ <optgroup label="Anycubic">
1144
+ <option value="kobra2">Anycubic Kobra 2 (220×220×250)</option>
1145
+ <option value="megase">Anycubic Mega SE (220×220×245)</option>
1146
+ </optgroup>
1147
+ <optgroup label="Voron">
1148
+ <option value="voron24">Voron 2.4 (350×350×340)</option>
1149
+ <option value="voron01">Voron 0.1 (120×120×120)</option>
1150
+ </optgroup>
1151
+ <optgroup label="Generic">
1152
+ <option value="custom">Custom Printer...</option>
1153
+ </optgroup>
1154
+ </select>
1155
+ </div>
1156
+
1157
+ <!-- Material -->
1158
+ <div style="margin-bottom:12px;">
1159
+ <label style="font-size:0.7rem;color:rgba(255,255,255,0.4);text-transform:uppercase;letter-spacing:0.08em;display:block;margin-bottom:4px;">Material</label>
1160
+ <select id="slicer-material" style="width:100%;background:rgba(255,255,255,0.06);border:1px solid rgba(255,255,255,0.1);color:#ccd;padding:8px 10px;border-radius:6px;font-size:0.8rem;font-family:inherit;">
1161
+ <option value="pla" selected>PLA (190-220°C)</option>
1162
+ <option value="petg">PETG (220-250°C)</option>
1163
+ <option value="abs">ABS (230-260°C)</option>
1164
+ <option value="tpu">TPU Flexible (210-230°C)</option>
1165
+ <option value="nylon">Nylon (240-270°C)</option>
1166
+ <option value="asa">ASA (240-260°C)</option>
1167
+ <option value="pc">Polycarbonate (260-310°C)</option>
1168
+ <option value="pla+">PLA+ (200-230°C)</option>
1169
+ </select>
1170
+ </div>
1171
+
1172
+ <!-- Quality Preset -->
1173
+ <div style="margin-bottom:12px;">
1174
+ <label style="font-size:0.7rem;color:rgba(255,255,255,0.4);text-transform:uppercase;letter-spacing:0.08em;display:block;margin-bottom:4px;">Quality Preset</label>
1175
+ <div style="display:flex;gap:4px;">
1176
+ <button class="slicer-quality-btn active" data-quality="draft" style="flex:1;padding:6px;font-size:0.7rem;border:1px solid rgba(255,255,255,0.1);border-radius:5px;background:rgba(0,204,136,0.15);color:#00cc88;cursor:pointer;">Draft<br><span style="font-size:0.6rem;opacity:0.6;">0.3mm</span></button>
1177
+ <button class="slicer-quality-btn" data-quality="normal" style="flex:1;padding:6px;font-size:0.7rem;border:1px solid rgba(255,255,255,0.1);border-radius:5px;background:transparent;color:rgba(255,255,255,0.5);cursor:pointer;">Normal<br><span style="font-size:0.6rem;opacity:0.6;">0.2mm</span></button>
1178
+ <button class="slicer-quality-btn" data-quality="fine" style="flex:1;padding:6px;font-size:0.7rem;border:1px solid rgba(255,255,255,0.1);border-radius:5px;background:transparent;color:rgba(255,255,255,0.5);cursor:pointer;">Fine<br><span style="font-size:0.6rem;opacity:0.6;">0.12mm</span></button>
1179
+ <button class="slicer-quality-btn" data-quality="ultra" style="flex:1;padding:6px;font-size:0.7rem;border:1px solid rgba(255,255,255,0.1);border-radius:5px;background:transparent;color:rgba(255,255,255,0.5);cursor:pointer;">Ultra<br><span style="font-size:0.6rem;opacity:0.6;">0.06mm</span></button>
1180
+ </div>
1181
+ </div>
1182
+
1183
+ <!-- Layer Height -->
1184
+ <div style="margin-bottom:10px;">
1185
+ <div style="display:flex;justify-content:space-between;align-items:center;">
1186
+ <label style="font-size:0.7rem;color:rgba(255,255,255,0.4);text-transform:uppercase;letter-spacing:0.08em;">Layer Height</label>
1187
+ <span id="slicer-layer-val" style="font-size:0.75rem;color:#00cc88;font-weight:600;">0.3mm</span>
1188
+ </div>
1189
+ <input type="range" id="slicer-layer" min="0.04" max="0.4" step="0.02" value="0.3" style="width:100%;accent-color:#00cc88;margin-top:2px;">
1190
+ </div>
1191
+
1192
+ <!-- Infill -->
1193
+ <div style="margin-bottom:10px;">
1194
+ <div style="display:flex;justify-content:space-between;align-items:center;">
1195
+ <label style="font-size:0.7rem;color:rgba(255,255,255,0.4);text-transform:uppercase;letter-spacing:0.08em;">Infill</label>
1196
+ <span id="slicer-infill-val" style="font-size:0.75rem;color:#00cc88;font-weight:600;">20%</span>
1197
+ </div>
1198
+ <input type="range" id="slicer-infill" min="0" max="100" step="5" value="20" style="width:100%;accent-color:#00cc88;margin-top:2px;">
1199
+ </div>
1200
+
1201
+ <!-- Print Speed -->
1202
+ <div style="margin-bottom:10px;">
1203
+ <div style="display:flex;justify-content:space-between;align-items:center;">
1204
+ <label style="font-size:0.7rem;color:rgba(255,255,255,0.4);text-transform:uppercase;letter-spacing:0.08em;">Print Speed</label>
1205
+ <span id="slicer-speed-val" style="font-size:0.75rem;color:#00cc88;font-weight:600;">50 mm/s</span>
1206
+ </div>
1207
+ <input type="range" id="slicer-speed" min="20" max="300" step="10" value="50" style="width:100%;accent-color:#00cc88;margin-top:2px;">
1208
+ </div>
1209
+
1210
+ <!-- Temperatures -->
1211
+ <div style="display:flex;gap:8px;margin-bottom:10px;">
1212
+ <div style="flex:1;">
1213
+ <label style="font-size:0.65rem;color:rgba(255,255,255,0.4);text-transform:uppercase;letter-spacing:0.08em;display:block;margin-bottom:2px;">Nozzle °C</label>
1214
+ <input type="number" id="slicer-nozzle-temp" value="210" style="width:100%;background:rgba(255,255,255,0.06);border:1px solid rgba(255,255,255,0.1);color:#ccd;padding:6px 8px;border-radius:5px;font-size:0.8rem;font-family:inherit;">
1215
+ </div>
1216
+ <div style="flex:1;">
1217
+ <label style="font-size:0.65rem;color:rgba(255,255,255,0.4);text-transform:uppercase;letter-spacing:0.08em;display:block;margin-bottom:2px;">Bed °C</label>
1218
+ <input type="number" id="slicer-bed-temp" value="60" style="width:100%;background:rgba(255,255,255,0.06);border:1px solid rgba(255,255,255,0.1);color:#ccd;padding:6px 8px;border-radius:5px;font-size:0.8rem;font-family:inherit;">
1219
+ </div>
1220
+ </div>
1221
+
1222
+ <!-- Supports & Adhesion -->
1223
+ <div style="display:flex;gap:10px;margin-bottom:10px;">
1224
+ <label style="font-size:0.75rem;color:rgba(255,255,255,0.5);display:flex;align-items:center;gap:4px;cursor:pointer;">
1225
+ <input type="checkbox" id="slicer-supports" style="accent-color:#00cc88;"> Supports
1226
+ </label>
1227
+ <label style="font-size:0.75rem;color:rgba(255,255,255,0.5);display:flex;align-items:center;gap:4px;cursor:pointer;">
1228
+ <input type="checkbox" id="slicer-brim" checked style="accent-color:#00cc88;"> Brim
1229
+ </label>
1230
+ <label style="font-size:0.75rem;color:rgba(255,255,255,0.5);display:flex;align-items:center;gap:4px;cursor:pointer;">
1231
+ <input type="checkbox" id="slicer-raft" style="accent-color:#00cc88;"> Raft
1232
+ </label>
1233
+ </div>
1234
+
1235
+ <!-- Infill Pattern -->
1236
+ <div style="margin-bottom:12px;">
1237
+ <label style="font-size:0.7rem;color:rgba(255,255,255,0.4);text-transform:uppercase;letter-spacing:0.08em;display:block;margin-bottom:4px;">Infill Pattern</label>
1238
+ <select id="slicer-infill-pattern" style="width:100%;background:rgba(255,255,255,0.06);border:1px solid rgba(255,255,255,0.1);color:#ccd;padding:6px 10px;border-radius:6px;font-size:0.8rem;font-family:inherit;">
1239
+ <option value="lines">Lines</option>
1240
+ <option value="grid" selected>Grid</option>
1241
+ <option value="triangles">Triangles</option>
1242
+ <option value="honeycomb">Honeycomb</option>
1243
+ <option value="gyroid">Gyroid</option>
1244
+ <option value="concentric">Concentric</option>
1245
+ </select>
1246
+ </div>
1247
+
1248
+ <!-- Export STL + Kiri:Moto -->
1249
+ <div style="margin-top:8px;padding:10px;background:rgba(77,166,255,0.06);border:1px solid rgba(77,166,255,0.15);border-radius:8px;">
1250
+ <div style="font-size:0.7rem;color:rgba(255,255,255,0.4);margin-bottom:4px;">Export & Slice with</div>
1251
+ <button id="slicer-export-stl" class="vc-btn" style="width:100%;justify-content:center;font-size:0.8rem;padding:8px;background:rgba(77,166,255,0.12);border-color:rgba(77,166,255,0.35);color:#4da6ff;font-weight:600;margin-bottom:6px;">⬇ Export Selected as STL</button>
1252
+ <div style="display:flex;gap:6px;margin-bottom:4px;">
1253
+ <select id="slicer-kiri-mode" style="flex:1;padding:6px;border-radius:6px;background:rgba(255,255,255,0.06);border:1px solid rgba(255,255,255,0.12);color:#ccc;font-size:0.7rem;cursor:pointer;">
1254
+ <option value="FDM">🖨️ FDM (3D Print)</option>
1255
+ <option value="CAM">⚙️ CNC Milling</option>
1256
+ <option value="LASER">🔦 Laser Cutting</option>
1257
+ <option value="SLA">💧 SLA / Resin</option>
1258
+ </select>
1259
+ </div>
1260
+ <button id="slicer-open-kirimoto" class="vc-btn" style="width:100%;justify-content:center;font-size:0.8rem;padding:8px;background:rgba(0,204,136,0.12);border-color:rgba(0,204,136,0.35);color:#00cc88;font-weight:600;">🔗 Open in Kiri:Moto</button>
1261
+ <div style="font-size:0.6rem;color:rgba(255,255,255,0.25);margin-top:4px;">Export STL → open Kiri:Moto for 3D print, CNC, or laser</div>
1262
+ </div>
1263
+ </div>
1264
+
1265
+ <!-- Right: Preview & Actions -->
1266
+ <div style="flex:1;display:flex;flex-direction:column;gap:10px;">
1267
+ <!-- Print Estimate -->
1268
+ <div style="background:rgba(255,255,255,0.03);border:1px solid rgba(255,255,255,0.08);border-radius:10px;padding:14px;">
1269
+ <div style="font-size:0.7rem;color:rgba(255,255,255,0.4);text-transform:uppercase;letter-spacing:0.1em;margin-bottom:10px;">Print Estimate</div>
1270
+ <div style="display:grid;grid-template-columns:1fr 1fr;gap:8px;">
1271
+ <div>
1272
+ <div style="font-size:1.2rem;font-weight:700;color:#00cc88;" id="slicer-est-time">--:--</div>
1273
+ <div style="font-size:0.65rem;color:rgba(255,255,255,0.3);">Print Time</div>
1274
+ </div>
1275
+ <div>
1276
+ <div style="font-size:1.2rem;font-weight:700;color:#FFD100;" id="slicer-est-filament">-- g</div>
1277
+ <div style="font-size:0.65rem;color:rgba(255,255,255,0.3);">Filament</div>
1278
+ </div>
1279
+ <div>
1280
+ <div style="font-size:1.2rem;font-weight:700;color:#4da6ff;" id="slicer-est-layers">--</div>
1281
+ <div style="font-size:0.65rem;color:rgba(255,255,255,0.3);">Layers</div>
1282
+ </div>
1283
+ <div>
1284
+ <div style="font-size:1.2rem;font-weight:700;color:rgba(255,255,255,0.6);" id="slicer-est-cost">$--</div>
1285
+ <div style="font-size:0.65rem;color:rgba(255,255,255,0.3);">Est. Cost</div>
1286
+ </div>
1287
+ </div>
1288
+ </div>
1289
+
1290
+ <!-- Layer Preview -->
1291
+ <div style="flex:1;background:rgba(255,255,255,0.02);border:1px solid rgba(255,255,255,0.06);border-radius:10px;padding:12px;min-height:200px;position:relative;overflow:hidden;">
1292
+ <canvas id="slicer-preview" width="400" height="300" style="width:100%;height:100%;border-radius:6px;"></canvas>
1293
+ <div style="position:absolute;bottom:8px;left:8px;right:8px;display:flex;align-items:center;gap:8px;">
1294
+ <span style="font-size:0.65rem;color:rgba(255,255,255,0.3);min-width:50px;" id="slicer-layer-label">Layer 0</span>
1295
+ <input type="range" id="slicer-layer-slider" min="0" max="100" value="50" style="flex:1;accent-color:#00cc88;">
1296
+ </div>
1297
+ </div>
1298
+
1299
+ <!-- Progress -->
1300
+ <div id="slicer-progress" style="display:none;">
1301
+ <div style="height:4px;background:rgba(255,255,255,0.06);border-radius:2px;overflow:hidden;">
1302
+ <div id="slicer-progress-bar" style="height:100%;width:0%;background:linear-gradient(90deg,#00cc88,#4da6ff);border-radius:2px;transition:width 0.1s;"></div>
1303
+ </div>
1304
+ <div id="slicer-progress-text" style="font-size:0.7rem;color:rgba(255,255,255,0.4);text-align:center;margin-top:4px;">Slicing...</div>
1305
+ </div>
1306
+
1307
+ <!-- Actions -->
1308
+ <div style="display:flex;gap:8px;">
1309
+ <button class="vc-btn" id="slicer-slice-btn" style="flex:1;justify-content:center;font-size:0.85rem;padding:12px;background:rgba(0,204,136,0.12);border-color:rgba(0,204,136,0.35);color:#00cc88;font-weight:600;">⚙ Slice & Generate G-code</button>
1310
+ <button class="vc-btn" id="slicer-download-btn" style="padding:12px 16px;font-size:0.85rem;" disabled>⬇ Download .gcode</button>
1311
+ </div>
1312
+ </div>
1313
+ </div>
1314
+ </div>
1315
+
1316
+ <!-- Standards Identifier Panel (DIN/ISO parts) -->
1317
+ <div id="standards-panel" style="display:none;position:fixed;right:14px;top:95px;z-index:65;background:rgba(0,0,0,0.92);backdrop-filter:blur(20px);border:1px solid rgba(255,255,255,0.1);border-radius:12px;padding:0;width:380px;max-height:calc(100vh - 110px);overflow:hidden;font-family:Inter,sans-serif;flex-direction:column;">
1318
+ <!-- Header -->
1319
+ <div style="display:flex;align-items:center;justify-content:space-between;padding:12px 14px;border-bottom:1px solid rgba(255,255,255,0.08);flex-shrink:0;">
1320
+ <div>
1321
+ <div style="font-size:0.75rem;letter-spacing:0.12em;text-transform:uppercase;color:#4da6ff;font-weight:600;">🔩 DIN/ISO Standard Parts</div>
1322
+ <div id="standards-summary" style="font-size:0.65rem;color:rgba(255,255,255,0.45);margin-top:4px;">Ready to analyze</div>
1323
+ </div>
1324
+ <button class="panel-close-btn" data-close-panel="standards-panel" style="background:none;border:none;color:#667;font-size:1.1rem;cursor:pointer;line-height:1;padding:2px 6px;">×</button>
1325
+ </div>
1326
+ <!-- Toolbar -->
1327
+ <div style="display:flex;gap:6px;padding:8px 10px;border-bottom:1px solid rgba(255,255,255,0.06);flex-shrink:0;flex-wrap:wrap;">
1328
+ <button id="standards-analyze-btn" class="vc-btn" style="flex:1;min-width:140px;font-size:0.75rem;padding:8px 10px;justify-content:center;">🔍 Analyze Parts</button>
1329
+ <button id="standards-export-btn" class="vc-btn" style="flex:1;min-width:140px;font-size:0.75rem;padding:8px 10px;justify-content:center;margin-top:0;" disabled>📋 Export CSV</button>
1330
+ </div>
1331
+ <!-- Results container -->
1332
+ <div id="standards-results" style="flex:1;overflow-y:auto;padding:12px;color:#ccc;font-size:0.75rem;">
1333
+ <div style="text-align:center;color:rgba(255,255,255,0.4);padding:20px 10px;">Click "Analyze Parts" to identify standard components.</div>
1334
+ </div>
1335
+ </div>
1336
+
1337
+ <!-- Assembly Tree (left side, replaces assembly list when active) -->
1338
+ <div id="tree-panel" style="display:none;position:fixed;left:14px;top:60px;z-index:65;background:rgba(0,0,0,0.92);backdrop-filter:blur(20px);border:1px solid rgba(255,255,255,0.1);border-radius:12px;padding:0;width:280px;max-height:calc(100vh - 80px);overflow:hidden;font-family:Inter,sans-serif;flex-direction:column;">
1339
+ <!-- Header -->
1340
+ <div style="display:flex;align-items:center;justify-content:space-between;padding:10px 14px;border-bottom:1px solid rgba(255,255,255,0.08);flex-shrink:0;">
1341
+ <div>
1342
+ <div style="font-size:0.75rem;letter-spacing:0.12em;text-transform:uppercase;color:#4da6ff;font-weight:600;">Assembly Tree</div>
1343
+ <div style="font-size:0.55rem;color:rgba(255,255,255,0.4);letter-spacing:0.1em;margin-top:2px;">CYCLEWASH <span style="color:#FFD100;font-weight:600;">STATION BASIC</span> · 399 parts · 6 assemblies</div>
1344
+ </div>
1345
+ <button class="panel-close-btn" data-close-panel="tree-panel" style="background:none;border:none;color:#667;font-size:1.1rem;cursor:pointer;line-height:1;padding:2px 6px;">×</button>
1346
+ </div>
1347
+ <!-- Collapse/Expand toolbar -->
1348
+ <div style="display:flex;align-items:center;gap:4px;padding:4px 10px;border-bottom:1px solid rgba(255,255,255,0.06);flex-shrink:0;">
1349
+ <button id="tree-collapse-all" class="vc-btn" style="flex:1;font-size:0.6rem;padding:3px 6px;border-radius:4px;justify-content:center;" title="Collapse all assemblies">▶ Collapse All</button>
1350
+ <button id="tree-expand-all" class="vc-btn" style="flex:1;font-size:0.6rem;padding:3px 6px;border-radius:4px;justify-content:center;" title="Expand all assemblies">▼ Expand All</button>
1351
+ </div>
1352
+ <!-- Tree content (scrollable) -->
1353
+ <div id="tree-root" style="overflow-y:auto;padding:8px 6px;flex:1;min-height:0;">
1354
+ <!-- Dynamically populated by JS -->
1355
+ </div>
1356
+ <!-- Bottom toolbar: compact row with key actions -->
1357
+ <div style="border-top:1px solid rgba(255,255,255,0.08);padding:6px 10px;flex-shrink:0;">
1358
+ <div id="tree-selected-label" style="font-size:0.6rem;color:rgba(255,255,255,0.35);margin-bottom:4px;letter-spacing:0.05em;">No selection</div>
1359
+ <div style="display:flex;align-items:center;gap:4px;">
1360
+ <button class="vc-btn" id="tree-prev-btn" style="padding:4px 8px;font-size:0.7rem;border-radius:5px;" title="Previous Assembly">←</button>
1361
+ <button class="vc-btn" id="tree-explode-btn" style="flex:1;font-size:0.65rem;padding:5px 8px;border-radius:5px;justify-content:center;" title="Explode / Collapse">💥 Explode</button>
1362
+ <button id="tree-bom-btn" class="vc-btn" style="flex:1;font-size:0.65rem;padding:5px 8px;border-radius:5px;background:rgba(77,166,255,0.12);border-color:rgba(77,166,255,0.3);color:#4da6ff;justify-content:center;">📋 BOM</button>
1363
+ <button class="vc-btn" id="tree-next-btn" style="padding:4px 8px;font-size:0.7rem;border-radius:5px;" title="Next Assembly">→</button>
1364
+ </div>
1365
+ <div style="position:relative;height:4px;background:rgba(255,255,255,0.06);border-radius:2px;overflow:hidden;margin-top:4px;">
1366
+ <div id="tree-progress-fill" style="height:100%;width:0%;background:linear-gradient(90deg,var(--cyan),var(--yellow));border-radius:2px;transition:width 0.2s;"></div>
1367
+ </div>
1368
+ </div>
1369
+ <!-- Drawing controls (shown when selection exists) -->
1370
+ <div id="tree-draw-controls" style="display:none;border-top:1px solid rgba(255,255,255,0.08);padding:6px 10px;flex-shrink:0;">
1371
+ <select id="tree-draw-type" style="width:100%;background:rgba(255,255,255,0.06);border:1px solid rgba(255,255,255,0.1);border-radius:5px;color:#ccd;padding:4px 8px;font-size:0.65rem;font-family:inherit;margin-bottom:4px;">
1372
+ <option value="technical">Technical Drawing (3-View)</option>
1373
+ <option value="exploded">Exploded Assembly</option>
1374
+ <option value="isometric">Isometric View</option>
1375
+ <option value="dimensioned">Dimensioned Drawing</option>
1376
+ <option value="section">Cross-Section View</option>
1377
+ </select>
1378
+ <input type="text" id="tree-legend-input" placeholder="Legend: Material, Tolerances, Surface..." style="width:100%;background:rgba(255,255,255,0.06);border:1px solid rgba(255,255,255,0.1);border-radius:5px;color:#ccd;padding:4px 8px;font-size:0.6rem;font-family:inherit;margin-bottom:4px;outline:none;" title="Drawing legend — applied to all generated drawings" />
1379
+ <button id="tree-draw-btn" class="vc-btn" style="width:100%;font-size:0.65rem;padding:6px 10px;border-radius:6px;background:rgba(0,204,136,0.15);border-color:rgba(0,204,136,0.3);color:#0c8;justify-content:center;" disabled>✏️ Generate Drawing</button>
1380
+ </div>
1381
+ </div>
1382
+
1383
+ <!-- AI Drawing Preview Panel (center, shown when drawing is generated) -->
1384
+ <div id="drawing-preview-panel" style="display:none;position:fixed;left:50%;top:50%;transform:translate(-50%,-50%);z-index:210;background:rgba(0,0,0,0.96);backdrop-filter:blur(24px);border:1px solid rgba(255,255,255,0.12);border-radius:14px;padding:0;width:900px;max-width:92vw;height:75vh;overflow:hidden;font-family:Inter,sans-serif;flex-direction:column;">
1385
+ <div style="display:flex;align-items:center;justify-content:space-between;padding:12px 18px;border-bottom:1px solid rgba(255,255,255,0.08);flex-shrink:0;">
1386
+ <div style="display:flex;align-items:center;gap:10px;">
1387
+ <div style="font-size:0.9rem;letter-spacing:0.1em;text-transform:uppercase;color:#4da6ff;font-weight:600;">Technical Drawing</div>
1388
+ <span id="drawing-preview-title" style="font-size:0.7rem;color:rgba(255,255,255,0.4);"></span>
1389
+ </div>
1390
+ <div style="display:flex;align-items:center;gap:8px;">
1391
+ <select id="tree-draw-size" style="background:rgba(255,255,255,0.06);border:1px solid rgba(255,255,255,0.1);border-radius:6px;color:#ccd;padding:5px 8px;font-size:0.7rem;font-family:inherit;">
1392
+ <option value="a0">A0 (841×1189mm)</option>
1393
+ <option value="a1">A1 (594×841mm)</option>
1394
+ <option value="a2">A2 (420×594mm)</option>
1395
+ <option value="a3">A3 (297×420mm)</option>
1396
+ <option value="a4" selected>A4 (210×297mm)</option>
1397
+ <option value="letter">Letter (8.5×11")</option>
1398
+ </select>
1399
+ <select id="tree-draw-format" style="background:rgba(255,255,255,0.06);border:1px solid rgba(255,255,255,0.1);border-radius:6px;color:#ccd;padding:5px 8px;font-size:0.7rem;font-family:inherit;">
1400
+ <option value="png">PNG</option>
1401
+ <option value="pdf">PDF</option>
1402
+ <option value="tiff">TIFF</option>
1403
+ <option value="dxf">DXF</option>
1404
+ </select>
1405
+ <label id="tree-logo-label" style="cursor:pointer;background:rgba(255,255,255,0.06);border:1px solid rgba(255,255,255,0.1);border-radius:6px;color:#aab;padding:5px 10px;font-size:0.65rem;font-family:inherit;white-space:nowrap;" title="Upload company logo for title block">🏢 Logo
1406
+ <input type="file" id="tree-logo-input" accept="image/*" style="display:none;" />
1407
+ </label>
1408
+ <button id="tree-download-drawing" class="vc-btn" style="font-size:0.7rem;padding:6px 14px;border-radius:6px;" disabled>⬇ Download</button>
1409
+ <button id="tree-drawing-fullscreen" class="vc-btn" style="font-size:0.7rem;padding:6px 10px;border-radius:6px;" title="Fullscreen drawing view — hides all UI">⛶ Fullscreen</button>
1410
+ <button class="panel-close-btn" data-close-panel="drawing-preview-panel" style="background:none;border:none;color:#667;font-size:1.3rem;cursor:pointer;line-height:1;padding:2px 6px;">×</button>
1411
+ </div>
1412
+ </div>
1413
+ <div id="tree-drawing-preview" style="flex:1;display:flex;align-items:center;justify-content:center;overflow:auto;padding:16px;background:rgba(255,255,255,0.02);">
1414
+ <canvas id="tree-drawing-canvas" width="1920" height="1080" style="display:none;max-width:100%;max-height:100%;border:1px solid rgba(255,255,255,0.08);border-radius:4px;background:#fff;"></canvas>
1415
+ <div id="tree-drawing-placeholder" style="text-align:center;color:rgba(255,255,255,0.2);">
1416
+ <div style="font-size:0.85rem;">Generating drawing...</div>
1417
+ </div>
1418
+ </div>
1419
+ <div style="display:flex;align-items:center;gap:8px;padding:6px 16px;border-top:1px solid rgba(255,255,255,0.06);flex-shrink:0;">
1420
+ <label style="font-size:0.65rem;color:#889;white-space:nowrap;">Legend / Notes:</label>
1421
+ <input type="text" id="tree-draw-legend" placeholder="e.g. Material: 1.4301, Tolerances: ±0.5mm, Surface: Ra 1.6" style="flex:1;background:rgba(255,255,255,0.06);border:1px solid rgba(255,255,255,0.1);border-radius:4px;color:#ccd;padding:4px 8px;font-size:0.65rem;font-family:inherit;outline:none;" />
1422
+ <button id="tree-redraw-btn" style="background:rgba(255,255,255,0.06);border:1px solid rgba(255,255,255,0.1);border-radius:4px;color:#aab;padding:4px 10px;font-size:0.65rem;cursor:pointer;font-family:inherit;white-space:nowrap;" title="Redraw with updated legend">↻ Redraw</button>
1423
+ </div>
1424
+ <div id="tree-drawing-status" style="display:none;padding:8px 16px;border-top:1px solid rgba(255,255,255,0.06);font-size:0.7rem;color:rgba(255,255,255,0.5);flex-shrink:0;">
1425
+ <div style="height:3px;background:rgba(255,255,255,0.06);border-radius:2px;overflow:hidden;margin-bottom:4px;">
1426
+ <div id="tree-drawing-progress-bar" style="height:100%;width:0%;background:linear-gradient(90deg,#0c8,#4da6ff);transition:width 0.3s;"></div>
1427
+ </div>
1428
+ <span id="tree-drawing-progress-text">Generating...</span>
1429
+ </div>
1430
+ </div>
1431
+
1432
+ <!-- Share & Embed Panel -->
1433
+ <div id="share-panel" style="display:none;position:fixed;right:14px;top:95px;z-index:65;background:rgba(0,0,0,0.88);backdrop-filter:blur(16px);border:1px solid rgba(255,255,255,0.1);border-radius:12px;padding:16px 20px;width:320px;max-height:80vh;overflow-y:auto;font-family:Inter,sans-serif;">
1434
+ <div style="display:flex;align-items:center;justify-content:space-between;margin-bottom:12px;">
1435
+ <div style="font-size:0.85rem;letter-spacing:0.15em;text-transform:uppercase;color:#4da6ff;font-weight:600;">Share & Embed</div>
1436
+ <button id="share-close" style="background:none;border:none;color:#667;font-size:1rem;cursor:pointer;">×</button>
1437
+ </div>
1438
+
1439
+ <!-- Direct Link -->
1440
+ <div style="margin-bottom:14px;">
1441
+ <label style="font-size:0.8rem;color:rgba(255,255,255,0.5);letter-spacing:0.08em;text-transform:uppercase;">Direct Link</label>
1442
+ <div style="display:flex;gap:4px;margin-top:4px;">
1443
+ <input type="text" id="share-link" readonly style="flex:1;background:rgba(255,255,255,0.07);border:1px solid rgba(255,255,255,0.15);border-radius:6px;color:#dde;font-size:0.85rem;padding:6px 10px;font-family:inherit;outline:none;box-sizing:border-box;">
1444
+ <button id="share-copy-link" style="padding:6px 12px;background:rgba(255,255,255,0.1);border:1px solid rgba(255,255,255,0.15);border-radius:6px;color:#dde;font-size:0.8rem;cursor:pointer;font-family:inherit;white-space:nowrap;">📋 Copy</button>
1445
+ </div>
1446
+ </div>
1447
+
1448
+ <!-- Embed Code -->
1449
+ <div style="margin-bottom:14px;">
1450
+ <label style="font-size:0.8rem;color:rgba(255,255,255,0.5);letter-spacing:0.08em;text-transform:uppercase;">Embed Code</label>
1451
+ <div style="margin-top:4px;">
1452
+ <textarea id="share-embed" readonly rows="4" style="width:100%;background:rgba(255,255,255,0.07);border:1px solid rgba(255,255,255,0.15);border-radius:6px;color:#9ab;font-size:0.8rem;padding:8px 10px;font-family:'SF Mono',Monaco,monospace;resize:vertical;outline:none;box-sizing:border-box;line-height:1.5;"></textarea>
1453
+ <button id="share-copy-embed" style="width:100%;margin-top:4px;padding:6px;background:rgba(255,255,255,0.06);border:1px solid rgba(255,255,255,0.15);border-radius:6px;color:#dde;font-size:0.8rem;cursor:pointer;font-family:inherit;letter-spacing:0.08em;text-transform:uppercase;">📋 Copy Embed Code</button>
1454
+ </div>
1455
+ </div>
1456
+
1457
+ <!-- Embed Options -->
1458
+ <div style="margin-bottom:14px;">
1459
+ <label style="font-size:0.8rem;color:rgba(255,255,255,0.5);letter-spacing:0.08em;text-transform:uppercase;">Embed Size</label>
1460
+ <div style="display:flex;gap:6px;margin-top:4px;">
1461
+ <select id="share-size" style="flex:1;background:rgba(255,255,255,0.07);border:1px solid rgba(255,255,255,0.15);border-radius:6px;color:#dde;font-size:0.85rem;padding:6px 10px;font-family:inherit;outline:none;">
1462
+ <option value="600x400">600 × 400 (Small)</option>
1463
+ <option value="800x600" selected>800 × 600 (Medium)</option>
1464
+ <option value="1200x800">1200 × 800 (Large)</option>
1465
+ <option value="100%x600">Full Width × 600</option>
1466
+ <option value="100%x100%">Full Size (Responsive)</option>
1467
+ </select>
1468
+ </div>
1469
+ </div>
1470
+
1471
+ <!-- Share Options -->
1472
+ <div style="margin-bottom:14px;">
1473
+ <label style="font-size:0.8rem;color:rgba(255,255,255,0.5);letter-spacing:0.08em;text-transform:uppercase;margin-bottom:6px;display:block;">Options</label>
1474
+ <label style="display:flex;align-items:center;gap:6px;font-size:0.8rem;color:rgba(255,255,255,0.5);cursor:pointer;margin-bottom:4px;">
1475
+ <input type="checkbox" id="share-opt-autorotate" checked style="accent-color:#0055A4;"> Auto-rotate on load
1476
+ </label>
1477
+ <label style="display:flex;align-items:center;gap:6px;font-size:0.8rem;color:rgba(255,255,255,0.5);cursor:pointer;margin-bottom:4px;">
1478
+ <input type="checkbox" id="share-opt-explode" style="accent-color:#0055A4;"> Start exploded
1479
+ </label>
1480
+ <label style="display:flex;align-items:center;gap:6px;font-size:0.8rem;color:rgba(255,255,255,0.5);cursor:pointer;margin-bottom:4px;">
1481
+ <input type="checkbox" id="share-opt-hideui" style="accent-color:#0055A4;"> Minimal UI (hide controls)
1482
+ </label>
1483
+ </div>
1484
+
1485
+ <!-- Share Actions -->
1486
+ <div style="font-size:0.8rem;letter-spacing:0.15em;text-transform:uppercase;color:rgba(255,255,255,0.3);margin-bottom:8px;">Share</div>
1487
+ <div style="display:flex;gap:6px;">
1488
+ <button id="share-copy-url" style="flex:1;padding:8px 6px;background:rgba(77,166,255,0.12);border:1px solid rgba(77,166,255,0.3);border-radius:6px;color:#4da6ff;font-size:0.8rem;cursor:pointer;font-family:inherit;">📋 Copy Link</button>
1489
+ <button id="share-email" style="flex:1;padding:8px 6px;background:rgba(255,255,255,0.06);border:1px solid rgba(255,255,255,0.15);border-radius:6px;color:#aab;font-size:0.8rem;cursor:pointer;font-family:inherit;">✉ Email</button>
1490
+ </div>
1491
+ </div>
1492
+
1493
+ <!-- Animation Panel -->
1494
+ <div id="animation-panel" style="display:none;position:fixed;bottom:60px;left:50%;transform:translateX(-50%);z-index:65;background:rgba(0,0,0,0.88);backdrop-filter:blur(16px);border:1px solid rgba(255,255,255,0.1);border-radius:12px;padding:14px 18px;width:600px;max-width:90vw;font-family:Inter,sans-serif;">
1495
+ <!-- Panel header -->
1496
+ <div style="display:flex;align-items:center;justify-content:space-between;margin-bottom:10px;">
1497
+ <div>
1498
+ <div id="anim-header-title" style="font-size:0.8rem;letter-spacing:0.15em;text-transform:uppercase;color:#4da6ff;font-weight:600;">Animation Timeline</div>
1499
+ <div id="anim-guide-info" style="display:none;font-size:0.75rem;color:rgba(255,255,255,0.5);margin-top:3px;">Step: <span id="anim-step-counter">0</span> / <span id="anim-step-total">0</span></div>
1500
+ </div>
1501
+ <button id="anim-close" style="background:none;border:none;color:#667;font-size:1.3rem;cursor:pointer;">×</button>
1502
+ </div>
1503
+ <!-- Step description (shown only in guide mode) -->
1504
+ <div id="anim-step-description" style="display:none;font-size:0.85rem;color:rgba(255,255,255,0.7);margin-bottom:10px;padding:8px;background:rgba(77,166,255,0.08);border-radius:6px;border-left:3px solid #4da6ff;"></div>
1505
+ <!-- Timeline steps -->
1506
+ <div id="anim-timeline" style="display:flex;gap:6px;overflow-x:auto;padding:6px 0;margin-bottom:10px;"></div>
1507
+ <!-- Controls row 1: Auto-generate, mode toggle -->
1508
+ <div style="display:flex;gap:6px;align-items:center;flex-wrap:wrap;margin-bottom:8px;">
1509
+ <button class="vc-btn" id="anim-autogen" style="font-size:0.8rem;padding:6px 14px;">🔧 Auto-Generate</button>
1510
+ <button class="vc-btn" id="anim-toggle-mode" style="font-size:0.8rem;padding:6px 14px;display:none;">Assembly ↔ Disassembly</button>
1511
+ <div style="flex:1;"></div>
1512
+ </div>
1513
+ <!-- Controls row 2: Manual steps + playback -->
1514
+ <div style="display:flex;gap:6px;align-items:center;flex-wrap:wrap;">
1515
+ <button class="vc-btn" id="anim-add-step" style="font-size:0.8rem;padding:6px 14px;">+ Add Step</button>
1516
+ <button class="vc-btn" id="anim-prev-step" style="font-size:0.8rem;padding:6px 14px;display:none;">◀ Prev</button>
1517
+ <button class="vc-btn" id="anim-next-step" style="font-size:0.8rem;padding:6px 14px;display:none;">Next ▶</button>
1518
+ <div style="flex:1;"></div>
1519
+ <button class="vc-btn" id="anim-play" style="font-size:0.8rem;padding:6px 14px;">▶ Play</button>
1520
+ <button class="vc-btn" id="anim-stop" style="font-size:0.8rem;padding:6px 14px;display:none;">■ Stop</button>
1521
+ <select id="anim-speed" style="background:rgba(255,255,255,0.06);border:1px solid rgba(255,255,255,0.1);color:#aab;padding:6px 10px;border-radius:6px;font-size:0.8rem;font-family:inherit;">
1522
+ <option value="500">Fast</option>
1523
+ <option value="1500" selected>Normal</option>
1524
+ <option value="3000">Slow</option>
1525
+ </select>
1526
+ <button class="vc-btn" id="anim-save" style="font-size:0.8rem;padding:6px 14px;">💾 Save</button>
1527
+ <button class="vc-btn" id="anim-load" style="font-size:0.8rem;padding:6px 14px;">📂 Load</button>
1528
+ </div>
1529
+ </div>
1530
+
1531
+ <!-- Navigation Cube Column: Cube → Controls bar (evenly spaced) -->
1532
+ <div id="vc-column" style="position:fixed;top:120px;right:10px;z-index:56;display:flex;flex-direction:column;align-items:center;gap:8px;">
1533
+ <!-- Home button removed — Home is on right sidebar -->
1534
+ <!-- ViewCube -->
1535
+ <div id="viewcube" style="width:90px;height:70px;cursor:grab;position:relative;">
1536
+ <div style="position:absolute;top:0;left:50%;transform:translateX(-50%);width:60px;height:60px;perspective:150px;">
1537
+ <div id="cube3d" style="width:60px;height:60px;position:relative;transform-style:preserve-3d;transform:rotateX(-25deg) rotateY(45deg);">
1538
+ <div class="cface" data-view="front" style="width:60px;height:60px;transform:rotateY(0deg) translateZ(30px);">FRONT</div>
1539
+ <div class="cface" data-view="back" style="width:60px;height:60px;transform:rotateY(180deg) translateZ(30px);">BACK</div>
1540
+ <div class="cface" data-view="right" style="width:60px;height:60px;transform:rotateY(90deg) translateZ(30px);">RIGHT</div>
1541
+ <div class="cface" data-view="left" style="width:60px;height:60px;transform:rotateY(-90deg) translateZ(30px);">LEFT</div>
1542
+ <div class="cface" data-view="top" style="width:60px;height:60px;transform:rotateX(90deg) translateZ(30px);">TOP</div>
1543
+ <div class="cface" data-view="bottom" style="width:60px;height:60px;transform:rotateX(-90deg) translateZ(30px);">BTM</div>
1544
+ </div>
1545
+ </div>
1546
+ <svg id="vc-axis-svg" style="position:absolute;top:0;left:50%;transform:translateX(-50%);width:60px;height:60px;pointer-events:none;overflow:visible;">
1547
+ <line id="ax-line-x" x1="30" y1="30" x2="65" y2="30" stroke="#ff4444" stroke-width="1.5"/>
1548
+ <text id="ax-label-x" x="68" y="34" fill="#ff4444" font-size="9" font-weight="700">X</text>
1549
+ <line id="ax-line-y" x1="30" y1="30" x2="30" y2="-5" stroke="#44dd44" stroke-width="1.5"/>
1550
+ <text id="ax-label-y" x="26" y="-8" fill="#44dd44" font-size="9" font-weight="700">Y</text>
1551
+ <line id="ax-line-z" x1="30" y1="30" x2="0" y2="52" stroke="#4488ff" stroke-width="1.5"/>
1552
+ <text id="ax-label-z" x="-8" y="58" fill="#4488ff" font-size="9" font-weight="700">Z</text>
1553
+ </svg>
1554
+ </div>
1555
+ <!-- Rotation target (M/BG/All) + XYZ flip — unified row -->
1556
+ <div id="vc-rot-target" style="display:flex;gap:2px;background:rgba(10,12,20,0.85);border-radius:8px;padding:3px 4px;border:1px solid rgba(255,255,255,0.1);white-space:nowrap;align-items:center;">
1557
+ <button class="rot-target-btn active" data-target="model" title="Rotate Model" style="font-size:0.7rem;padding:5px 7px;border:none;border-radius:5px;cursor:pointer;color:#fff;background:rgba(77,166,255,0.35);letter-spacing:0.03em;min-width:28px;text-align:center;">M</button>
1558
+ <button class="rot-target-btn" data-target="bg" title="Rotate Background" style="font-size:0.7rem;padding:5px 7px;border:none;border-radius:5px;cursor:pointer;color:rgba(255,255,255,0.5);background:transparent;letter-spacing:0.03em;min-width:28px;text-align:center;">BG</button>
1559
+ <button class="rot-target-btn" data-target="both" title="Rotate Both" style="font-size:0.7rem;padding:5px 7px;border:none;border-radius:5px;cursor:pointer;color:rgba(255,255,255,0.5);background:transparent;letter-spacing:0.03em;min-width:28px;text-align:center;">All</button>
1560
+ <span style="width:1px;height:18px;background:rgba(255,255,255,0.15);margin:0 2px;"></span>
1561
+ <button id="vc-flip-x" title="Flip X 90°" style="font-size:0.7rem;padding:5px 7px;border:none;border-radius:5px;cursor:pointer;color:#ff6666;background:transparent;min-width:28px;text-align:center;font-weight:700;">X</button>
1562
+ <button id="vc-flip-y" title="Flip Y 90°" style="font-size:0.7rem;padding:5px 7px;border:none;border-radius:5px;cursor:pointer;color:#66dd66;background:transparent;min-width:28px;text-align:center;font-weight:700;">Y</button>
1563
+ <button id="vc-flip-z" title="Flip Z 90°" style="font-size:0.7rem;padding:5px 7px;border:none;border-radius:5px;cursor:pointer;color:#6688ff;background:transparent;min-width:28px;text-align:center;font-weight:700;">Z</button>
1564
+ </div>
1565
+ </div>
1566
+
1567
+ <!-- Product title below nav -->
1568
+ <!-- Product title moved to tree panel header -->
1569
+ <div id="product-title" style="display:none;"></div>
1570
+
1571
+ <!-- Bottom Controls (now integrated into ce-buttons toolbar) -->
1572
+ <div id="bottom-controls" style="display:none !important;">
1573
+ </div>
1574
+
1575
+ <!-- 3D View Controls (right side) -->
1576
+ <div id="view-controls">
1577
+ <button class="vc-btn" id="btn-home" title="Home — Collapse &amp; reset view" style="padding:6px 8px;"><svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M3 9l9-7 9 7v11a2 2 0 01-2 2H5a2 2 0 01-2-2z"/><polyline points="9 22 9 12 15 12 15 22"/></svg></button>
1578
+ <button class="vc-btn" id="btn-fit-frame" title="Fit to Frame" style="padding:6px 8px;"><svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M15 3h6v6"/><path d="M9 21H3v-6"/><path d="M21 3l-7 7"/><path d="M3 21l7-7"/></svg></button>
1579
+ <button class="vc-btn" id="btn-hard-refresh" title="Hard Refresh — Clear cache &amp; reload" style="padding:6px 8px;" onclick="if('caches' in window){caches.keys().then(k=>Promise.all(k.map(n=>caches.delete(n))))}fetch('./app.js?bust='+Date.now(),{cache:'no-store'}).finally(()=>window.location.replace(window.location.pathname+'?t='+Date.now()));"><svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="23 4 23 10 17 10"/><path d="M20.49 15a9 9 0 11-2.12-9.36L23 10"/></svg></button>
1580
+ <div class="vc-divider"></div>
1581
+ <button class="vc-btn" id="btn-zoom-in" title="Expand Explosion" style="padding:6px 8px;"><svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><line x1="12" y1="5" x2="12" y2="19"/><line x1="5" y1="12" x2="19" y2="12"/></svg></button>
1582
+ <button class="vc-btn" id="btn-zoom-out" title="Collapse" style="padding:6px 8px;"><svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><line x1="5" y1="12" x2="19" y2="12"/></svg></button>
1583
+ <div class="vc-divider"></div>
1584
+ <button class="vc-btn active" id="btn-auto-rotate" title="Auto Rotate" style="padding:6px 8px;"><svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><ellipse cx="12" cy="12" rx="10" ry="4" transform="rotate(-25 12 12)"/><polygon points="20,9 22.5,11 19.5,11.5" fill="currentColor" stroke="none"/><circle cx="12" cy="12" r="2.5"/></svg></button>
1585
+ <button class="vc-btn" id="btn-stop-rotate" title="Stop Rotation" style="padding:6px 8px;"><svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><rect x="6" y="6" width="12" height="12" rx="1"/></svg></button>
1586
+ <div class="vc-divider"></div>
1587
+ <button class="vc-btn" id="btn-wireframe" title="Wireframe" style="padding:6px 8px;"><svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M12 2L2 7l10 5 10-5-10-5z"/><path d="M2 17l10 5 10-5"/><path d="M2 12l10 5 10-5"/></svg></button>
1588
+ <div class="vc-divider"></div>
1589
+ <button class="vc-btn" id="btn-display-settings" title="Display Settings" style="padding:6px 8px;"><svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="13.5" cy="6.5" r="2.5"/><path d="M17.5 10.5c1.4 0 2.5 1.1 2.5 2.5s-1.1 2.5-2.5 2.5"/><circle cx="8.5" cy="13.5" r="2.5"/><circle cx="13.5" cy="17.5" r="2.5"/><path d="M3 12c0-4.97 4.03-9 9-9 1.4 0 2.8.3 4 1"/></svg></button>
1590
+ <div class="vc-divider"></div>
1591
+ <button class="vc-btn" id="btn-floor" title="Drop to floor" style="padding:6px 8px;"><svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M12 3v12"/><path d="M8 11l4 4 4-4"/><line x1="4" y1="21" x2="20" y2="21"/></svg></button>
1592
+ <div class="vc-divider"></div>
1593
+ <button class="vc-btn" id="btn-viewer-fullscreen" title="Fullscreen — press F to toggle" style="padding:6px 8px;"><svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="15 3 21 3 21 9"/><polyline points="9 21 3 21 3 15"/><line x1="21" y1="3" x2="14" y2="10"/><line x1="3" y1="21" x2="10" y2="14"/></svg></button>
1594
+ </div>
1595
+
1596
+ <!-- Settings Panel (lighting + background) -->
1597
+ <div id="settings-panel" style="display:none;position:fixed;right:60px;top:50%;transform:translateY(-50%);z-index:200;background:rgba(0,0,0,0.92);backdrop-filter:blur(20px);-webkit-backdrop-filter:blur(20px);border:1px solid rgba(255,255,255,0.12);border-radius:12px;padding:16px 20px;width:230px;max-height:80vh;overflow-y:auto;overscroll-behavior:contain;touch-action:pan-y;font-family:Inter,sans-serif;">
1598
+ <div style="display:flex;align-items:center;justify-content:space-between;margin-bottom:12px;">
1599
+ <div style="font-size:0.8rem;letter-spacing:0.2em;text-transform:uppercase;color:rgba(255,255,255,0.3);">Display Settings</div>
1600
+ <button class="panel-close-btn" data-close-panel="settings-panel" style="background:none;border:none;color:#667;font-size:1.3rem;cursor:pointer;line-height:1;padding:2px 6px;">×</button>
1601
+ </div>
1602
+
1603
+ <label style="font-size:0.85rem;color:rgba(255,255,255,0.5);letter-spacing:0.08em;text-transform:uppercase;">Brightness</label>
1604
+ <input type="range" id="ctrl-brightness" min="20" max="500" value="220" style="width:100%;margin:4px 0 10px;accent-color:#0055A4;">
1605
+
1606
+ <label style="font-size:0.85rem;color:rgba(255,255,255,0.5);letter-spacing:0.08em;text-transform:uppercase;">Contrast</label>
1607
+ <input type="range" id="ctrl-contrast" min="10" max="400" value="100" style="width:100%;margin:4px 0 10px;accent-color:#0055A4;">
1608
+
1609
+ <label style="font-size:0.85rem;color:rgba(255,255,255,0.5);letter-spacing:0.08em;text-transform:uppercase;">Ambient Light</label>
1610
+ <input type="range" id="ctrl-ambient" min="0" max="500" value="150" style="width:100%;margin:4px 0 10px;accent-color:#0055A4;">
1611
+
1612
+ <label style="font-size:0.85rem;color:rgba(255,255,255,0.5);letter-spacing:0.08em;text-transform:uppercase;">Model Scale</label>
1613
+ <input type="range" id="ctrl-scale" min="30" max="200" value="100" style="width:100%;margin:4px 0 10px;accent-color:#0055A4;">
1614
+
1615
+ <label style="font-size:0.85rem;color:rgba(255,255,255,0.5);letter-spacing:0.08em;text-transform:uppercase;">Field of View</label>
1616
+ <input type="range" id="ctrl-fov" min="15" max="90" value="35" style="width:100%;margin:4px 0 10px;accent-color:#0055A4;">
1617
+
1618
+ <div style="font-size:0.8rem;letter-spacing:0.2em;text-transform:uppercase;color:rgba(255,255,255,0.3);margin:12px 0 8px;">Scene</div>
1619
+
1620
+ <label style="font-size:0.85rem;color:rgba(255,255,255,0.5);letter-spacing:0.08em;text-transform:uppercase;">Vertical Position</label>
1621
+ <input type="range" id="ctrl-vpos" min="-1500" max="500" value="0" style="width:100%;margin:4px 0 10px;accent-color:#0055A4;">
1622
+
1623
+ <label style="font-size:0.85rem;color:rgba(255,255,255,0.5);letter-spacing:0.08em;text-transform:uppercase;">Env Rotation</label>
1624
+ <input type="range" id="ctrl-env-rotate" min="0" max="360" value="0" style="width:100%;margin:4px 0 10px;accent-color:#0055A4;">
1625
+
1626
+ <div style="display:flex;gap:10px;margin:6px 0;">
1627
+ <label style="display:flex;align-items:center;gap:5px;font-size:0.8rem;color:rgba(255,255,255,0.5);cursor:pointer;">
1628
+ <input type="checkbox" id="ctrl-ground" checked style="accent-color:#0055A4;"> Ground Plane
1629
+ </label>
1630
+ <label style="display:flex;align-items:center;gap:5px;font-size:0.8rem;color:rgba(255,255,255,0.5);cursor:pointer;">
1631
+ <input type="checkbox" id="ctrl-reflections" style="accent-color:#0055A4;"> Reflections
1632
+ </label>
1633
+ </div>
1634
+ <div style="display:flex;gap:10px;margin:6px 0;">
1635
+ <label style="display:flex;align-items:center;gap:5px;font-size:0.8rem;color:rgba(255,255,255,0.5);cursor:pointer;">
1636
+ <input type="checkbox" id="ctrl-shadows" checked style="accent-color:#0055A4;"> Shadows
1637
+ </label>
1638
+ <label style="display:flex;align-items:center;gap:5px;font-size:0.8rem;color:rgba(255,255,255,0.5);cursor:pointer;">
1639
+ <input type="checkbox" id="ctrl-edges" style="accent-color:#0055A4;"> Edges
1640
+ </label>
1641
+ </div>
1642
+
1643
+ <label style="font-size:0.85rem;color:rgba(255,255,255,0.5);letter-spacing:0.08em;text-transform:uppercase;margin-top:6px;">Shadow Intensity</label>
1644
+ <input type="range" id="ctrl-shadow-int" min="0" max="100" value="50" style="width:100%;margin:4px 0 10px;accent-color:#0055A4;">
1645
+
1646
+ <div style="font-size:0.8rem;letter-spacing:0.2em;text-transform:uppercase;color:rgba(255,255,255,0.3);margin:12px 0 8px;">Background</div>
1647
+ <div style="display:flex;gap:6px;flex-wrap:wrap;" id="bg-presets">
1648
+ <button class="bg-btn" data-bg="#0a0e1a" style="width:28px;height:28px;border-radius:6px;border:2px solid rgba(255,255,255,0.15);background:#0a0e1a;cursor:pointer;" title="Dark Navy"></button>
1649
+ <button class="bg-btn" data-bg="#000000" style="width:28px;height:28px;border-radius:6px;border:2px solid rgba(255,255,255,0.08);background:#000;cursor:pointer;" title="Pure Black"></button>
1650
+ <button class="bg-btn" data-bg="#1a1a2e" style="width:28px;height:28px;border-radius:6px;border:2px solid rgba(255,255,255,0.08);background:#1a1a2e;cursor:pointer;" title="Deep Purple"></button>
1651
+ <button class="bg-btn" data-bg="#f0f0f0" style="width:28px;height:28px;border-radius:6px;border:2px solid rgba(255,255,255,0.08);background:#f0f0f0;cursor:pointer;" title="Light Grey"></button>
1652
+ <button class="bg-btn" data-bg="#ffffff" style="width:28px;height:28px;border-radius:6px;border:2px solid rgba(255,255,255,0.08);background:#fff;cursor:pointer;" title="White"></button>
1653
+ <button class="bg-btn" data-bg="gradient-sunset" style="width:28px;height:28px;border-radius:6px;border:2px solid rgba(255,255,255,0.08);background:linear-gradient(180deg,#ff7e5f,#feb47b);cursor:pointer;" title="Sunset"></button>
1654
+ <button class="bg-btn" data-bg="gradient-sky" style="width:28px;height:28px;border-radius:6px;border:2px solid rgba(255,255,255,0.08);background:linear-gradient(180deg,#4facfe,#00f2fe);cursor:pointer;" title="Sky Blue"></button>
1655
+ <button class="bg-btn" data-bg="gradient-forest" style="width:28px;height:28px;border-radius:6px;border:2px solid rgba(255,255,255,0.08);background:linear-gradient(180deg,#134e5e,#71b280);cursor:pointer;" title="Forest"></button>
1656
+ <button class="bg-btn" data-bg="gradient-studio" style="width:28px;height:28px;border-radius:6px;border:2px solid rgba(255,255,255,0.08);background:linear-gradient(180deg,#3a3a3a,#1a1a1a);cursor:pointer;" title="Studio"></button>
1657
+ <button class="bg-btn" data-bg="gradient-warm" style="width:28px;height:28px;border-radius:6px;border:2px solid rgba(255,255,255,0.08);background:linear-gradient(180deg,#ffd89b,#19547b);cursor:pointer;" title="Warm"></button>
1658
+ <button class="bg-btn" data-bg="gradient-ocean" style="width:28px;height:28px;border-radius:6px;border:2px solid rgba(255,255,255,0.08);background:linear-gradient(180deg,#2193b0,#6dd5ed);cursor:pointer;" title="Ocean"></button>
1659
+ <button class="bg-btn" data-bg="gradient-arctic" style="width:28px;height:28px;border-radius:6px;border:2px solid rgba(255,255,255,0.08);background:linear-gradient(180deg,#e6dada,#274046);cursor:pointer;" title="Arctic"></button>
1660
+ <button class="bg-btn" data-bg="gradient-dawn" style="width:28px;height:28px;border-radius:6px;border:2px solid rgba(255,255,255,0.08);background:linear-gradient(180deg,#ff9a9e,#fecfef);cursor:pointer;" title="Dawn"></button>
1661
+ <button class="bg-btn" data-bg="gradient-night" style="width:28px;height:28px;border-radius:6px;border:2px solid rgba(255,255,255,0.08);background:linear-gradient(180deg,#0f0c29,#302b63,#24243e);cursor:pointer;" title="Night Sky"></button>
1662
+ <button class="bg-btn" data-bg="gradient-desert" style="width:28px;height:28px;border-radius:6px;border:2px solid rgba(255,255,255,0.08);background:linear-gradient(180deg,#c2956e,#ddd0a8);cursor:pointer;" title="Desert"></button>
1663
+ </div>
1664
+
1665
+ <div style="font-size:0.8rem;letter-spacing:0.2em;text-transform:uppercase;color:rgba(255,255,255,0.3);margin:12px 0 8px;">Environment (HDR)</div>
1666
+ <div style="display:flex;gap:6px;flex-wrap:wrap;" id="env-presets">
1667
+ <button class="bg-btn" data-env="warehouse" style="width:48px;height:28px;border-radius:6px;border:2px solid rgba(255,255,255,0.08);background:linear-gradient(135deg,#8a7d6a,#c4b49a);cursor:pointer;font-size:7px;color:#fff;text-shadow:0 1px 2px rgba(0,0,0,0.5);" title="Warehouse">Factory</button>
1668
+ <button class="bg-btn" data-env="city" style="width:48px;height:28px;border-radius:6px;border:2px solid rgba(255,255,255,0.08);background:linear-gradient(135deg,#5a6a7a,#8a9aaa);cursor:pointer;font-size:7px;color:#fff;text-shadow:0 1px 2px rgba(0,0,0,0.5);" title="City Street">Street</button>
1669
+ <button class="bg-btn" data-env="park" style="width:48px;height:28px;border-radius:6px;border:2px solid rgba(255,255,255,0.08);background:linear-gradient(135deg,#3a5a2a,#6a9a4a);cursor:pointer;font-size:7px;color:#fff;text-shadow:0 1px 2px rgba(0,0,0,0.5);" title="Park">Park</button>
1670
+ <button class="bg-btn" data-env="courtyard" style="width:48px;height:28px;border-radius:6px;border:2px solid rgba(255,255,255,0.08);background:linear-gradient(135deg,#9a8a6a,#d4c4a4);cursor:pointer;font-size:7px;color:#fff;text-shadow:0 1px 2px rgba(0,0,0,0.5);" title="Cobblestone Courtyard">Cobbles</button>
1671
+ </div>
1672
+
1673
+ <div style="font-size:0.8rem;letter-spacing:0.2em;text-transform:uppercase;color:rgba(255,255,255,0.3);margin:12px 0 8px;">Custom Backgrounds</div>
1674
+ <div id="custom-bg-list" style="display:flex;gap:6px;flex-wrap:wrap;"></div>
1675
+
1676
+ <div style="font-size:0.8rem;letter-spacing:0.2em;text-transform:uppercase;color:rgba(255,255,255,0.3);margin:12px 0 8px;">AI Backgrounds</div>
1677
+ <div id="ai-bg-grid" style="display:flex;gap:6px;flex-wrap:wrap;">
1678
+ <div id="ai-bg-grid-empty" style="font-size:0.7rem;color:rgba(255,255,255,0.2);">Generate backgrounds via ✨ AI Render → 🖼 Background</div>
1679
+ </div>
1680
+
1681
+ <div id="bg-adjust-section" style="display:none;">
1682
+ <div style="font-size:0.8rem;letter-spacing:0.2em;text-transform:uppercase;color:rgba(255,255,255,0.3);margin:12px 0 8px;">Background Adjustments</div>
1683
+ <label style="font-size:0.85rem;color:rgba(255,255,255,0.5);letter-spacing:0.08em;text-transform:uppercase;">Blur (Distance)</label>
1684
+ <input type="range" id="ctrl-bg-blur" min="0" max="100" value="0" style="width:100%;margin:4px 0 10px;accent-color:#0055A4;">
1685
+ <label style="font-size:0.85rem;color:rgba(255,255,255,0.5);letter-spacing:0.08em;text-transform:uppercase;">Brightness</label>
1686
+ <input type="range" id="ctrl-bg-intensity" min="10" max="200" value="100" style="width:100%;margin:4px 0 10px;accent-color:#0055A4;">
1687
+ <button id="btn-remove-bg" style="width:100%;margin-top:4px;padding:6px 10px;background:rgba(200,50,50,0.15);border:1px solid rgba(200,50,50,0.3);border-radius:6px;color:#e66;font-size:0.8rem;font-weight:600;letter-spacing:0.08em;text-transform:uppercase;cursor:pointer;font-family:inherit;">✕ Remove AI Background</button>
1688
+ </div>
1689
+ </div>
1690
+
1691
+ <!-- Annotation Labels Container -->
1692
+ <div id="annotation-labels" style="position:fixed;inset:0;z-index:45;pointer-events:none;"></div>
1693
+
1694
+ <!-- Annotation Panel -->
1695
+ <div id="annotation-panel" style="display:none;position:fixed;left:50%;top:110px;transform:translateX(-50%);z-index:60;background:rgba(0,0,0,0.92);backdrop-filter:blur(20px);border:1px solid rgba(77,166,255,0.3);border-radius:16px;padding:20px 36px;font-family:Inter,sans-serif;box-shadow:0 8px 32px rgba(0,0,0,0.5);">
1696
+ <div style="display:flex;align-items:center;justify-content:space-between;margin-bottom:6px;">
1697
+ <div style="font-size:1.1rem;letter-spacing:0.12em;text-transform:uppercase;color:#4da6ff;font-weight:600;">📌 Click on model to place annotation</div>
1698
+ <button class="panel-close-btn" data-close-panel="annotation-panel" style="background:none;border:none;color:#667;font-size:1.3rem;cursor:pointer;line-height:1;padding:2px 6px;margin-left:16px;">×</button>
1699
+ </div>
1700
+ <div style="display:flex;gap:12px;margin-top:16px;justify-content:center;">
1701
+ <button class="vc-btn" id="btn-clear-annotations" style="font-size:0.85rem;padding:10px 22px;border-radius:8px;">Clear All</button>
1702
+ <button class="vc-btn" id="btn-export-annotations" style="font-size:0.85rem;padding:10px 22px;border-radius:8px;">Export</button>
1703
+ <button class="vc-btn" id="btn-cancel-annotate" style="font-size:0.85rem;padding:10px 22px;border-radius:8px;background:rgba(0,85,164,0.3);border-color:rgba(0,85,164,0.5);color:#4da6ff;">Done</button>
1704
+ </div>
1705
+ </div>
1706
+
1707
+ <!-- Global Reset & Screenshot toolbar (floating, always accessible) -->
1708
+ <div id="tools-reset-bar" style="display:none;position:fixed;top:150px;left:50%;transform:translateX(-50%);z-index:65;background:rgba(0,0,0,0.88);backdrop-filter:blur(16px);border:1px solid rgba(255,255,255,0.12);border-radius:12px;padding:8px 14px;font-family:Inter,sans-serif;gap:8px;align-items:center;">
1709
+ <span style="font-size:0.6rem;color:rgba(255,255,255,0.4);letter-spacing:0.08em;margin-right:4px;">TOOLS:</span>
1710
+ <button id="btn-reset-all-tools" class="vc-btn" style="font-size:0.6rem;padding:6px 14px;border-radius:6px;background:rgba(200,50,50,0.15);border-color:rgba(200,50,50,0.3);color:#e66;" title="Clear all annotations, measurements, and hidden parts">🗑 Reset All</button>
1711
+ <button id="btn-screenshot-tools" class="vc-btn" style="font-size:0.6rem;padding:6px 14px;border-radius:6px;" title="Screenshot with annotations & measurements">📸 Screenshot</button>
1712
+ <button id="btn-edit-screenshot" class="vc-btn" style="font-size:0.6rem;padding:6px 14px;border-radius:6px;background:rgba(0,85,164,0.15);border-color:rgba(0,85,164,0.3);color:#4da6ff;" title="Capture screenshot & open in Image Editor">✏️ Edit</button>
1713
+ <button id="btn-show-hidden" class="vc-btn" style="font-size:0.6rem;padding:6px 14px;border-radius:6px;display:none;" title="Show all hidden parts">👁 Show Hidden (<span id="hidden-count">0</span>)</button>
1714
+ </div>
1715
+
1716
+ <!-- Right-click context menu for parts -->
1717
+ <div id="part-context-menu" style="display:none;position:fixed;z-index:100;background:rgba(8,12,24,0.96);backdrop-filter:blur(20px);border:1px solid rgba(255,255,255,0.15);border-radius:10px;padding:6px 0;font-family:Inter,sans-serif;box-shadow:0 8px 30px rgba(0,0,0,0.6);min-width:200px;">
1718
+ <div id="ctx-part-header" style="padding:8px 16px;border-bottom:1px solid rgba(255,255,255,0.06);margin-bottom:4px;">
1719
+ <div id="ctx-part-name" style="font-size:0.7rem;font-weight:700;color:#dde;"></div>
1720
+ <div id="ctx-part-assembly" style="font-size:0.8rem;color:rgba(255,255,255,0.4);margin-top:2px;"></div>
1721
+ </div>
1722
+ <div class="ctx-item" id="ctx-select-part" style="padding:8px 16px;font-size:0.65rem;color:#dde;cursor:pointer;display:flex;align-items:center;gap:8px;">
1723
+ <span style="width:18px;text-align:center;">🔍</span> Select Part
1724
+ </div>
1725
+ <div class="ctx-item" id="ctx-select-assembly" style="padding:8px 16px;font-size:0.65rem;color:#dde;cursor:pointer;display:flex;align-items:center;gap:8px;">
1726
+ <span style="width:18px;text-align:center;">📦</span> Select Assembly
1727
+ </div>
1728
+ <div style="height:1px;background:rgba(255,255,255,0.06);margin:4px 0;"></div>
1729
+ <div class="ctx-item" id="ctx-hide-part" style="padding:8px 16px;font-size:0.65rem;color:#dde;cursor:pointer;display:flex;align-items:center;gap:8px;">
1730
+ <span style="width:18px;text-align:center;">👁‍🗨</span> Hide Part
1731
+ </div>
1732
+ <div class="ctx-item" id="ctx-hide-assembly" style="padding:8px 16px;font-size:0.65rem;color:#dde;cursor:pointer;display:flex;align-items:center;gap:8px;">
1733
+ <span style="width:18px;text-align:center;">🙈</span> Hide Assembly
1734
+ </div>
1735
+ <div class="ctx-item" id="ctx-isolate" style="padding:8px 16px;font-size:0.65rem;color:#dde;cursor:pointer;display:flex;align-items:center;gap:8px;">
1736
+ <span style="width:18px;text-align:center;">🎯</span> Isolate (hide all others)
1737
+ </div>
1738
+ <div style="height:1px;background:rgba(255,255,255,0.06);margin:4px 0;"></div>
1739
+ <div class="ctx-item" id="ctx-move-part" style="padding:8px 16px;font-size:0.65rem;color:#4da6ff;cursor:pointer;display:flex;align-items:center;gap:8px;">
1740
+ <span style="width:18px;text-align:center;">✋</span> Move Part (drag)
1741
+ </div>
1742
+ <div class="ctx-item" id="ctx-reset-part" style="padding:8px 16px;font-size:0.65rem;color:#dde;cursor:pointer;display:flex;align-items:center;gap:8px;">
1743
+ <span style="width:18px;text-align:center;">↩️</span> Reset Part Position
1744
+ </div>
1745
+ <div style="height:1px;background:rgba(255,255,255,0.06);margin:4px 0;"></div>
1746
+ <div class="ctx-item" id="ctx-slicer" style="padding:8px 16px;font-size:0.65rem;color:#00cc88;cursor:pointer;display:flex;align-items:center;gap:8px;">
1747
+ <span style="width:18px;text-align:center;">🖨</span> Open in Slicer
1748
+ </div>
1749
+ <div class="ctx-item" id="ctx-export-stl" style="padding:8px 16px;font-size:0.65rem;color:#4da6ff;cursor:pointer;display:flex;align-items:center;gap:8px;">
1750
+ <span style="width:18px;text-align:center;">⬇</span> Export STL
1751
+ </div>
1752
+ <div style="height:1px;background:rgba(255,255,255,0.06);margin:4px 0;"></div>
1753
+ <div class="ctx-item" id="ctx-part-info" style="padding:8px 16px;font-size:0.65rem;color:#778;cursor:pointer;display:flex;align-items:center;gap:8px;">
1754
+ <span style="width:18px;text-align:center;">ℹ️</span> Part Info
1755
+ </div>
1756
+ </div>
1757
+ <style>
1758
+ .ctx-item:hover { background: rgba(255,255,255,0.08); }
1759
+ </style>
1760
+
1761
+ <!-- AR Overlay (DOM Overlay for WebXR) -->
1762
+ <div id="ar-overlay" style="display:none;position:fixed;bottom:20px;left:50%;transform:translateX(-50%);z-index:101;text-align:center;font-family:Inter,sans-serif;">
1763
+ <div style="background:rgba(0,0,0,0.7);padding:8px 16px;border-radius:20px;font-size:0.6rem;color:#fff;">Tap to place model</div>
1764
+ </div>
1765
+
1766
+ <!-- AI Render Panel -->
1767
+ <div id="ai-render-panel" style="display:none;position:fixed;top:0;right:0;bottom:0;width:340px;max-width:85vw;background:rgba(10,14,26,0.96);backdrop-filter:blur(24px);-webkit-backdrop-filter:blur(24px);border-left:1px solid rgba(255,255,255,0.06);z-index:60;font-family:Inter,sans-serif;transition:transform 0.35s cubic-bezier(0.4,0,0.2,1);overflow-y:auto;">
1768
+ <div style="display:flex;align-items:center;justify-content:space-between;padding:12px 16px;border-bottom:1px solid rgba(255,255,255,0.06);">
1769
+ <div style="font-size:0.7rem;font-weight:600;letter-spacing:0.12em;text-transform:uppercase;background:linear-gradient(90deg,#4da6ff,#FFD100);-webkit-background-clip:text;-webkit-text-fill-color:transparent;background-clip:text;">&#10024; AI Render</div>
1770
+ <button id="ai-close" style="background:none;border:none;color:#667;font-size:1.1rem;cursor:pointer;padding:4px 8px;border-radius:4px;">&times;</button>
1771
+ </div>
1772
+ <div style="padding:16px;display:flex;flex-direction:column;gap:16px;">
1773
+ <!-- Preview -->
1774
+ <div>
1775
+ <div data-i18n="aiScenePreview" style="font-size:0.85rem;font-weight:600;letter-spacing:0.12em;text-transform:uppercase;color:#8899aa;margin-bottom:6px;">Scene Preview</div>
1776
+ <div style="border-radius:6px;overflow:hidden;border:1px solid rgba(255,255,255,0.15);">
1777
+ <img id="ai-preview" style="width:100%;display:block;" alt="Current view" />
1778
+ <div data-i18n="aiCameraRef" style="font-size:0.8rem;color:#778;text-align:center;padding:4px;letter-spacing:0.08em;">Current camera view used as reference</div>
1779
+ </div>
1780
+ </div>
1781
+ <!-- Prompt -->
1782
+ <div>
1783
+ <div data-i18n="aiScenePrompt" style="font-size:0.85rem;font-weight:600;letter-spacing:0.12em;text-transform:uppercase;color:#8899aa;margin-bottom:6px;">Scene Prompt</div>
1784
+ <textarea id="ai-prompt" placeholder="Happy cyclists in sunny bike park, dynamic action, vibrant lifestyle, golden hour..." style="width:100%;min-height:72px;background:rgba(255,255,255,0.07);border:1px solid rgba(255,255,255,0.18);border-radius:6px;color:#dde;font-size:0.75rem;padding:10px 12px;font-family:inherit;resize:vertical;outline:none;box-sizing:border-box;"></textarea>
1785
+ </div>
1786
+ <!-- Style Presets -->
1787
+ <div>
1788
+ <div data-i18n="aiStylePreset" style="font-size:0.85rem;font-weight:600;letter-spacing:0.12em;text-transform:uppercase;color:#8899aa;margin-bottom:6px;">Style Preset</div>
1789
+ <div id="ai-presets" style="display:grid;grid-template-columns:1fr 1fr;gap:6px;">
1790
+ <div class="ai-preset active" data-preset="product" style="padding:8px 10px;background:rgba(0,85,164,0.1);border:1px solid rgba(0,85,164,0.5);border-radius:6px;cursor:pointer;text-align:center;font-size:0.6rem;letter-spacing:0.06em;color:#4da6ff;"><span style="font-size:1rem;display:block;margin-bottom:3px;">&#128247;</span><span data-i18n="aiProductPhoto">Product Photo</span></div>
1791
+ <div class="ai-preset" data-preset="marketing" style="padding:8px 10px;background:rgba(255,255,255,0.06);border:1px solid rgba(255,255,255,0.18);border-radius:6px;cursor:pointer;text-align:center;font-size:0.6rem;letter-spacing:0.06em;color:#8899aa;"><span style="font-size:1rem;display:block;margin-bottom:3px;">&#128692;</span><span data-i18n="aiLifestyle">Lifestyle</span></div>
1792
+ <div class="ai-preset" data-preset="technical" style="padding:8px 10px;background:rgba(255,255,255,0.06);border:1px solid rgba(255,255,255,0.18);border-radius:6px;cursor:pointer;text-align:center;font-size:0.6rem;letter-spacing:0.06em;color:#8899aa;"><span style="font-size:1rem;display:block;margin-bottom:3px;">&#128295;</span><span data-i18n="aiTechnical">Technical</span></div>
1793
+ <div class="ai-preset" data-preset="artistic" style="padding:8px 10px;background:rgba(255,255,255,0.06);border:1px solid rgba(255,255,255,0.18);border-radius:6px;cursor:pointer;text-align:center;font-size:0.6rem;letter-spacing:0.06em;color:#8899aa;"><span style="font-size:1rem;display:block;margin-bottom:3px;">&#127912;</span><span data-i18n="aiArtistic">Artistic</span></div>
1794
+ </div>
1795
+ </div>
1796
+ <!-- Detected Materials -->
1797
+ <div>
1798
+ <div data-i18n="aiDetectedMaterials" style="font-size:0.85rem;font-weight:600;letter-spacing:0.12em;text-transform:uppercase;color:#8899aa;margin-bottom:6px;">Detected Materials</div>
1799
+ <div id="ai-materials" style="display:flex;flex-wrap:wrap;gap:4px;"></div>
1800
+ </div>
1801
+ <!-- Model Selector -->
1802
+ <div>
1803
+ <div data-i18n="aiModel" style="font-size:0.85rem;font-weight:600;letter-spacing:0.12em;text-transform:uppercase;color:#8899aa;margin-bottom:6px;">AI Model</div>
1804
+ <select id="ai-model" style="width:100%;background:rgba(255,255,255,0.07);border:1px solid rgba(255,255,255,0.18);border-radius:6px;color:#dde;font-size:0.72rem;padding:8px 12px;font-family:inherit;outline:none;box-sizing:border-box;">
1805
+ <optgroup label="Google AI (free tier)">
1806
+ <option value="gemini-nano-banana" selected>Nano Banana v1 (FREE)</option>
1807
+ <option value="gemini-nano-banana-2">Nano Banana v2 — Latest</option>
1808
+ </optgroup>
1809
+ <optgroup label="Stability AI">
1810
+ <option value="stability-sdxl">Stability AI — SDXL</option>
1811
+ <option value="stability-sd3">Stability AI — SD3</option>
1812
+ </optgroup>
1813
+ <optgroup label="Other providers">
1814
+ <option value="openai-dall-e-3">OpenAI — DALL·E 3</option>
1815
+ <option value="fal-flux">Fal.ai — FLUX</option>
1816
+ <option value="replicate-custom">Replicate — Custom Model</option>
1817
+ </optgroup>
1818
+ </select>
1819
+ </div>
1820
+ <!-- API Key -->
1821
+ <div>
1822
+ <div data-i18n="aiApiKey" style="font-size:0.85rem;font-weight:600;letter-spacing:0.12em;text-transform:uppercase;color:#8899aa;margin-bottom:6px;">API Key</div>
1823
+ <div id="ai-key-hint" style="font-size:0.85rem;color:#4a8;margin-bottom:4px;"></div>
1824
+ <input type="password" id="ai-key" placeholder="Paste your API key..." style="width:100%;background:rgba(255,255,255,0.07);border:1px solid rgba(255,255,255,0.18);border-radius:6px;color:#dde;font-size:0.7rem;padding:8px 12px;font-family:monospace;outline:none;box-sizing:border-box;" />
1825
+ <div id="ai-key-status" data-i18n="aiKeyStored" style="font-size:0.85rem;color:#7788;margin-top:2px;">Key stored in browser only.</div>
1826
+ </div>
1827
+ <!-- Output Format (hidden in video mode) -->
1828
+ <div id="ai-output-format-section">
1829
+ <div data-i18n="aiOutputFormat" style="font-size:0.85rem;font-weight:600;letter-spacing:0.12em;text-transform:uppercase;color:#8899aa;margin-bottom:6px;">Output Format</div>
1830
+ <select id="ai-format" style="width:100%;background:rgba(255,255,255,0.07);border:1px solid rgba(255,255,255,0.18);border-radius:6px;color:#dde;font-size:0.72rem;padding:8px 12px;font-family:inherit;outline:none;box-sizing:border-box;">
1831
+ <option value="png">PNG (lossless)</option>
1832
+ <option value="jpg">JPG (smaller file)</option>
1833
+ <option value="webp">WebP (modern)</option>
1834
+ </select>
1835
+ </div>
1836
+ <!-- Video Output Format (shown only in video mode) -->
1837
+ <div id="ai-video-format-section" style="display:none;">
1838
+ <div data-i18n="aiVideoOutput" style="font-size:0.85rem;font-weight:600;letter-spacing:0.12em;text-transform:uppercase;color:#8899aa;margin-bottom:6px;">Video Output</div>
1839
+ <select id="ai-video-format" style="width:100%;background:rgba(255,255,255,0.07);border:1px solid rgba(255,255,255,0.18);border-radius:6px;color:#dde;font-size:0.72rem;padding:8px 12px;font-family:inherit;outline:none;box-sizing:border-box;">
1840
+ <option value="mp4" selected>MP4 (universal)</option>
1841
+ <option value="webm">WebM (web optimized)</option>
1842
+ <option value="gif">GIF (social/preview)</option>
1843
+ </select>
1844
+ </div>
1845
+ <!-- Mode Toggle -->
1846
+ <div style="display:flex;gap:4px;margin-bottom:4px;">
1847
+ <button class="ai-mode-btn active" data-mode="render" style="flex:1;padding:7px 6px;background:rgba(0,85,164,0.15);border:1px solid rgba(0,85,164,0.5);border-radius:6px;color:#4da6ff;font-size:0.8rem;font-weight:600;letter-spacing:0.08em;text-transform:uppercase;cursor:pointer;font-family:inherit;">🎨 <span data-i18n="aiRenderBtn">Render</span></button>
1848
+ <button class="ai-mode-btn" data-mode="background" style="flex:1;padding:7px 6px;background:rgba(255,255,255,0.06);border:1px solid rgba(255,255,255,0.18);border-radius:6px;color:#8899aa;font-size:0.8rem;font-weight:600;letter-spacing:0.08em;text-transform:uppercase;cursor:pointer;font-family:inherit;">🖼 <span data-i18n="aiBgBtn">BG</span></button>
1849
+ <button class="ai-mode-btn" data-mode="video" style="flex:1;padding:7px 6px;background:rgba(255,255,255,0.06);border:1px solid rgba(255,255,255,0.18);border-radius:6px;color:#8899aa;font-size:0.8rem;font-weight:600;letter-spacing:0.08em;text-transform:uppercase;cursor:pointer;font-family:inherit;">🎬 <span data-i18n="aiVideoBtn">Video</span></button>
1850
+ </div>
1851
+ <!-- Video progress bar (shown during video generation) -->
1852
+ <div id="ai-video-progress" style="display:none;margin-bottom:6px;">
1853
+ <div style="display:flex;align-items:center;gap:6px;margin-bottom:4px;">
1854
+ <div style="font-size:0.8rem;color:#4da6ff;font-weight:500;letter-spacing:0.05em;">GENERATING VIDEO...</div>
1855
+ <div id="ai-video-eta" style="font-size:0.75rem;color:#8899aa;"></div>
1856
+ </div>
1857
+ <div style="width:100%;height:4px;background:rgba(255,255,255,0.06);border-radius:2px;overflow:hidden;">
1858
+ <div id="ai-video-bar" style="width:0%;height:100%;background:linear-gradient(90deg,#0055A4,#4da6ff);border-radius:2px;transition:width 0.5s ease;"></div>
1859
+ </div>
1860
+ <div id="ai-video-status" style="font-size:0.72rem;color:#778;margin-top:3px;">Initializing...</div>
1861
+ </div>
1862
+ <!-- Generate -->
1863
+ <button id="ai-generate" style="width:100%;padding:11px 16px;background:linear-gradient(135deg,#0055A4,#003d75);border:1px solid rgba(0,85,164,0.5);border-radius:6px;color:#fff;font-size:0.7rem;font-weight:600;letter-spacing:0.1em;text-transform:uppercase;cursor:pointer;font-family:inherit;">&#10024; <span data-i18n="aiGenerate">Generate Render</span></button>
1864
+ <!-- Gallery Save Folder -->
1865
+ <div id="gallery-save-section">
1866
+ <div style="display:flex;align-items:center;justify-content:space-between;margin-bottom:6px;">
1867
+ <div style="font-size:0.85rem;font-weight:600;letter-spacing:0.12em;text-transform:uppercase;color:#8899aa;">Gallery</div>
1868
+ <button id="btn-set-gallery-folder" style="padding:3px 8px;background:rgba(255,255,255,0.06);border:1px solid rgba(255,255,255,0.15);border-radius:4px;color:#8899aa;font-size:0.75rem;cursor:pointer;font-family:inherit;letter-spacing:0.06em;text-transform:uppercase;" title="Choose a folder to auto-save renders and videos">📁 Save Folder</button>
1869
+ </div>
1870
+ <div id="gallery-folder-status" style="font-size:0.72rem;color:#4a8;margin-bottom:6px;display:none;"></div>
1871
+ </div>
1872
+ <!-- Gallery -->
1873
+ <div>
1874
+ <div id="ai-gallery">
1875
+ <div id="ai-empty" style="text-align:center;padding:24px 16px;color:#778;">
1876
+ <div style="font-size:2rem;margin-bottom:8px;opacity:0.4;">&#128444;</div>
1877
+ <div style="font-size:0.6rem;line-height:1.6;">No renders yet.<br/>Configure your scene and hit Generate.</div>
1878
+ </div>
1879
+ </div>
1880
+ </div>
1881
+ <!-- Chat Refinement removed -->
1882
+ <!-- Background Library -->
1883
+ <div id="ai-bg-section" style="display:none;">
1884
+ <div style="font-size:0.85rem;font-weight:600;letter-spacing:0.12em;text-transform:uppercase;color:#8899aa;margin-bottom:6px;">Background Library</div>
1885
+ <div id="ai-bg-library" style="display:grid;grid-template-columns:1fr 1fr;gap:4px;">
1886
+ <div id="ai-bg-empty" style="grid-column:1/-1;text-align:center;padding:16px;color:#334;">
1887
+ <div style="font-size:0.85rem;">No saved backgrounds. Generate some above!</div>
1888
+ </div>
1889
+ </div>
1890
+ </div>
1891
+ </div>
1892
+ </div>
1893
+
1894
+ <!-- Mobile toggle buttons (hidden on desktop) -->
1895
+ <button class="mob-toggle" id="mob-parts" title="Sub-assemblies">☰</button>
1896
+ <button class="mob-toggle" id="mob-tools" title="Controls">⚙</button>
1897
+
1898
+ <!-- Mobile assembly info (shown when sub-assembly selected) -->
1899
+ <div id="mob-asm-info">
1900
+ <div id="mob-asm-name" style="font-size:1rem;font-weight:700;letter-spacing:0.02em;"></div>
1901
+ <div id="mob-asm-sub" style="font-size:0.6rem;color:rgba(255,255,255,0.5);margin-top:4px;line-height:1.5;"></div>
1902
+ </div>
1903
+
1904
+ <script type="importmap">
1905
+ {"imports":{"three":"https://cdn.jsdelivr.net/npm/three@0.170.0/build/three.module.js","three/addons/":"https://cdn.jsdelivr.net/npm/three@0.170.0/examples/jsm/"}}
1906
+ </script>
1907
+ <script>
1908
+ // Mobile: move view-controls into top nav, set title, build assembly nav
1909
+ if (window.innerWidth <= 768) {
1910
+ const vc = document.getElementById('view-controls');
1911
+ const ta = document.getElementById('top-actions');
1912
+ if (vc && ta) ta.parentNode.insertBefore(vc, ta);
1913
+
1914
+ // Set mobile title from config or fallback
1915
+ const mt = document.getElementById('mob-title');
1916
+ if (mt && window.EXPLODEVIEW_CONFIG) {
1917
+ mt.textContent = window.EXPLODEVIEW_CONFIG.productName || 'Station Basic';
1918
+ }
1919
+ }
1920
+
1921
+ // Mobile toggle buttons — show/hide panels
1922
+ document.getElementById('mob-parts').addEventListener('click', function() {
1923
+ const nav = document.getElementById('left-nav');
1924
+ const tools = document.getElementById('view-controls');
1925
+ nav.classList.toggle('mob-show');
1926
+ tools.classList.remove('mob-show');
1927
+ this.classList.toggle('open');
1928
+ document.getElementById('mob-tools').classList.remove('open');
1929
+ });
1930
+ document.getElementById('mob-tools').addEventListener('click', function() {
1931
+ const tools = document.getElementById('view-controls');
1932
+ const nav = document.getElementById('left-nav');
1933
+ tools.classList.toggle('mob-show');
1934
+ nav.classList.remove('mob-show');
1935
+ this.classList.toggle('open');
1936
+ document.getElementById('mob-parts').classList.remove('open');
1937
+ });
1938
+ // Close panels when tapping the 3D canvas
1939
+ document.addEventListener('touchstart', function(e) {
1940
+ if (!e.target.closest('#left-nav') && !e.target.closest('#view-controls') && !e.target.closest('.mob-toggle')) {
1941
+ document.getElementById('left-nav').classList.remove('mob-show');
1942
+ document.getElementById('view-controls').classList.remove('mob-show');
1943
+ document.getElementById('mob-parts').classList.remove('open');
1944
+ document.getElementById('mob-tools').classList.remove('open');
1945
+ }
1946
+ });
1947
+ </script>
1948
+ <!-- ─── Image Overlay Editor Modal ─── -->
1949
+ <div id="overlay-editor" style="display:none;position:fixed;inset:0;z-index:200;background:rgba(0,0,0,0.85);backdrop-filter:blur(8px);font-family:Inter,sans-serif;">
1950
+ <div style="display:flex;height:100%;flex-direction:column;">
1951
+ <!-- Top bar -->
1952
+ <div style="display:flex;align-items:center;justify-content:space-between;padding:10px 16px;background:rgba(10,14,26,0.9);border-bottom:1px solid rgba(255,255,255,0.08);">
1953
+ <span style="color:#fff;font-size:0.7rem;font-weight:600;letter-spacing:0.05em;">✏️ IMAGE EDITOR</span>
1954
+ <div style="display:flex;gap:8px;">
1955
+ <button id="oe-save" style="padding:5px 14px;background:#0055A4;color:#fff;border:none;border-radius:5px;font-size:0.85rem;cursor:pointer;font-family:inherit;letter-spacing:0.05em;">💾 Save to Gallery</button>
1956
+ <button id="oe-download" style="padding:5px 14px;background:rgba(255,255,255,0.1);color:#dde;border:1px solid rgba(255,255,255,0.15);border-radius:5px;font-size:0.85rem;cursor:pointer;font-family:inherit;letter-spacing:0.05em;">⬇ Download</button>
1957
+ <button id="oe-close" style="padding:5px 10px;background:rgba(255,255,255,0.08);color:#aab;border:1px solid rgba(255,255,255,0.1);border-radius:5px;font-size:0.65rem;cursor:pointer;font-family:inherit;">✕</button>
1958
+ </div>
1959
+ </div>
1960
+ <!-- Main area: canvas + sidebar -->
1961
+ <div style="display:flex;flex:1;overflow:hidden;">
1962
+ <!-- Canvas area -->
1963
+ <div style="flex:1;display:flex;align-items:center;justify-content:center;overflow:auto;padding:20px;">
1964
+ <canvas id="oe-canvas" style="max-width:100%;max-height:100%;border-radius:8px;box-shadow:0 4px 24px rgba(0,0,0,0.4);cursor:crosshair;"></canvas>
1965
+ </div>
1966
+ <!-- Sidebar controls -->
1967
+ <div style="width:240px;background:rgba(10,14,26,0.95);border-left:1px solid rgba(255,255,255,0.06);padding:12px;overflow-y:auto;display:flex;flex-direction:column;gap:10px;">
1968
+ <!-- Add Text -->
1969
+ <div style="color:rgba(255,255,255,0.35);font-size:0.7rem;letter-spacing:0.12em;text-transform:uppercase;font-weight:600;">Add Text</div>
1970
+ <input type="text" id="oe-text-input" placeholder="Type text here..." style="width:100%;padding:6px 8px;background:rgba(255,255,255,0.06);border:1px solid rgba(255,255,255,0.1);border-radius:5px;color:#fff;font-size:0.85rem;font-family:inherit;box-sizing:border-box;" />
1971
+ <div style="display:flex;gap:6px;">
1972
+ <select id="oe-font" style="flex:1;padding:5px;background:rgba(255,255,255,0.06);border:1px solid rgba(255,255,255,0.1);border-radius:5px;color:#fff;font-size:0.8rem;font-family:inherit;">
1973
+ <option value="Inter">Inter</option>
1974
+ <option value="Arial">Arial</option>
1975
+ <option value="Georgia">Georgia</option>
1976
+ <option value="Courier New">Courier</option>
1977
+ <option value="Impact">Impact</option>
1978
+ <option value="Times New Roman">Times</option>
1979
+ <option value="Verdana">Verdana</option>
1980
+ </select>
1981
+ <input type="number" id="oe-font-size" value="36" min="8" max="200" style="width:50px;padding:5px;background:rgba(255,255,255,0.06);border:1px solid rgba(255,255,255,0.1);border-radius:5px;color:#fff;font-size:0.8rem;font-family:inherit;text-align:center;" />
1982
+ </div>
1983
+ <div style="display:flex;gap:6px;align-items:center;">
1984
+ <input type="color" id="oe-text-color" value="#ffffff" style="width:28px;height:28px;border:1px solid rgba(255,255,255,0.1);border-radius:4px;background:none;cursor:pointer;padding:0;" />
1985
+ <label style="color:rgba(255,255,255,0.5);font-size:0.75rem;">Color</label>
1986
+ <span style="flex:1;"></span>
1987
+ <button id="oe-bold" style="padding:3px 8px;background:rgba(255,255,255,0.06);border:1px solid rgba(255,255,255,0.1);border-radius:4px;color:#dde;font-size:0.85rem;cursor:pointer;font-weight:bold;font-family:inherit;">B</button>
1988
+ <button id="oe-italic" style="padding:3px 8px;background:rgba(255,255,255,0.06);border:1px solid rgba(255,255,255,0.1);border-radius:4px;color:#dde;font-size:0.85rem;cursor:pointer;font-style:italic;font-family:inherit;">I</button>
1989
+ </div>
1990
+ <button id="oe-add-text" style="padding:6px;background:rgba(0,85,164,0.3);border:1px solid rgba(0,85,164,0.5);border-radius:5px;color:#4da6ff;font-size:0.8rem;cursor:pointer;font-family:inherit;letter-spacing:0.05em;">+ Add Text Layer</button>
1991
+
1992
+ <!-- Add Logo -->
1993
+ <div style="color:rgba(255,255,255,0.35);font-size:0.7rem;letter-spacing:0.12em;text-transform:uppercase;font-weight:600;margin-top:6px;">Add Logo / Image</div>
1994
+ <label id="oe-logo-label" style="display:flex;align-items:center;justify-content:center;padding:10px;background:rgba(255,255,255,0.04);border:1px dashed rgba(255,255,255,0.15);border-radius:5px;color:rgba(255,255,255,0.4);font-size:0.75rem;cursor:pointer;text-align:center;">
1995
+ 📎 Click to upload logo/image
1996
+ <input type="file" id="oe-logo-input" accept="image/*" style="display:none;" />
1997
+ </label>
1998
+
1999
+ <!-- Layers list -->
2000
+ <div style="color:rgba(255,255,255,0.35);font-size:0.7rem;letter-spacing:0.12em;text-transform:uppercase;font-weight:600;margin-top:6px;">Layers</div>
2001
+ <div id="oe-layers" style="display:flex;flex-direction:column;gap:4px;max-height:200px;overflow-y:auto;"></div>
2002
+ <div style="color:rgba(255,255,255,0.25);font-size:0.7rem;margin-top:2px;">Click canvas to position • Drag to move</div>
2003
+ </div>
2004
+ </div>
2005
+ </div>
2006
+ </div>
2007
+
2008
+ <!-- Model import file input -->
2009
+ <input type="file" id="model-file-input" accept=".glb,.gltf,.stl,.obj,.iges,.igs,.step,.stp" style="display:none;" multiple>
2010
+
2011
+ <!-- Drag and drop overlay -->
2012
+ <div id="model-drop-zone" style="display:none;position:fixed;inset:0;z-index:100;background:rgba(0,85,164,0.15);border:3px dashed rgba(0,85,164,0.5);align-items:center;justify-content:center;font-family:Inter,sans-serif;">
2013
+ <div style="background:rgba(0,0,0,0.8);padding:30px 50px;border-radius:16px;text-align:center;">
2014
+ <div style="font-size:2rem;margin-bottom:10px;">📦</div>
2015
+ <div style="font-size:0.8rem;color:#4da6ff;letter-spacing:0.1em;">Drop 3D model here</div>
2016
+ <div style="font-size:0.8rem;color:#778;margin-top:6px;">Supports: GLB, glTF, STL, OBJ, IGES, STEP</div>
2017
+ </div>
2018
+ </div>
2019
+
2020
+ <!-- Model Library panel -->
2021
+ <div id="imported-models-panel" style="display:none;position:fixed;right:14px;top:95px;z-index:65;background:rgba(0,0,0,0.92);backdrop-filter:blur(20px);border:1px solid rgba(255,255,255,0.12);border-radius:12px;padding:18px 22px;width:400px;max-height:600px;overflow-y:auto;font-family:Inter,sans-serif;">
2022
+ <div id="library-drag-handle" style="display:flex;align-items:center;justify-content:space-between;margin-bottom:14px;cursor:move;user-select:none;">
2023
+ <div style="font-size:0.9rem;letter-spacing:0.12em;text-transform:uppercase;color:#4da6ff;font-weight:600;">📦 Model Library</div>
2024
+ <button id="imported-models-close" style="background:none;border:none;color:#667;font-size:1.5rem;cursor:pointer;padding:2px 6px;line-height:1;" title="Close">×</button>
2025
+ </div>
2026
+ <!-- Default model (always listed) -->
2027
+ <div style="font-size:0.65rem;letter-spacing:0.1em;text-transform:uppercase;color:rgba(255,255,255,0.25);margin-bottom:6px;">Built-in Model</div>
2028
+ <div id="default-model-entry" style="display:flex;align-items:center;gap:8px;padding:10px 12px;background:rgba(77,166,255,0.08);border-radius:8px;border:1px solid rgba(77,166,255,0.5);margin-bottom:14px;cursor:pointer;">
2029
+ <div style="width:36px;height:36px;border-radius:6px;background:rgba(77,166,255,0.3);display:flex;align-items:center;justify-content:center;font-size:0.7rem;color:#4da6ff;font-weight:700;flex-shrink:0;">GLB</div>
2030
+ <div style="flex:1;overflow:hidden;">
2031
+ <div style="font-size:0.85rem;color:#fff;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;font-weight:600;">cycleWASH Station Basic</div>
2032
+ <div style="font-size:0.7rem;color:rgba(255,255,255,0.45);">399 parts — 6 assemblies</div>
2033
+ </div>
2034
+ <div id="default-model-badge" style="font-size:0.6rem;color:#4da6ff;font-weight:600;padding:2px 6px;background:rgba(77,166,255,0.15);border-radius:4px;">ACTIVE</div>
2035
+ </div>
2036
+ <!-- Saved models from library -->
2037
+ <div style="font-size:0.65rem;letter-spacing:0.1em;text-transform:uppercase;color:rgba(255,255,255,0.25);margin-bottom:6px;">Imported Models</div>
2038
+ <div id="imported-models-list" style="display:flex;flex-direction:column;gap:6px;margin-bottom:14px;">
2039
+ <div style="font-size:0.8rem;color:rgba(255,255,255,0.2);text-align:center;padding:10px;">No imported models</div>
2040
+ </div>
2041
+ <!-- Import area -->
2042
+ <div style="margin-bottom:6px;">
2043
+ <label id="import-file-label" style="display:flex;flex-direction:column;align-items:center;justify-content:center;padding:20px 16px;background:rgba(255,255,255,0.03);border:2px dashed rgba(77,166,255,0.25);border-radius:10px;color:rgba(77,166,255,0.6);font-size:0.85rem;cursor:pointer;text-align:center;transition:all 0.2s;">
2044
+ <div style="font-size:1.5rem;margin-bottom:6px;">+</div>
2045
+ <div>Drop files or click to import</div>
2046
+ <div style="font-size:0.7rem;color:rgba(255,255,255,0.2);margin-top:4px;">GLB, glTF, STL, OBJ, IGES, STEP — multiple files supported</div>
2047
+ <input type="file" id="import-file-input" accept=".glb,.gltf,.stl,.obj,.iges,.igs,.step,.stp" style="display:none;" multiple />
2048
+ </label>
2049
+ </div>
2050
+ <div id="import-progress" style="display:none;margin-bottom:12px;">
2051
+ <div style="display:flex;align-items:center;justify-content:space-between;">
2052
+ <div style="font-size:0.8rem;color:#4da6ff;margin-bottom:4px;" id="import-progress-text">Loading...</div>
2053
+ <button id="import-cancel-btn" style="background:rgba(255,80,80,0.15);border:1px solid rgba(255,80,80,0.3);border-radius:4px;color:#f55;font-size:0.7rem;padding:2px 8px;cursor:pointer;">Cancel</button>
2054
+ </div>
2055
+ <div style="height:4px;background:rgba(255,255,255,0.1);border-radius:2px;overflow:hidden;">
2056
+ <div id="import-progress-bar" style="height:100%;background:#4da6ff;border-radius:2px;width:0%;transition:width 0.3s;"></div>
2057
+ </div>
2058
+ </div>
2059
+ </div>
2060
+
2061
+ <!-- Documentation Mode Banner -->
2062
+ <div id="docs-mode-banner" style="display:none;position:fixed;top:100px;left:50%;transform:translateX(-50%);z-index:60;background:rgba(0,85,164,0.9);backdrop-filter:blur(12px);border:1px solid rgba(77,166,255,0.4);border-radius:20px;padding:10px 22px;font-family:Inter,sans-serif;white-space:nowrap;box-shadow:0 4px 20px rgba(0,85,164,0.3);">
2063
+ <span style="font-size:0.85rem;color:#fff;letter-spacing:0.1em;">📖 MANUAL MODE — Point at any assembly for documentation</span>
2064
+ <button id="docs-mode-exit" style="margin-left:12px;background:rgba(255,255,255,0.15);border:1px solid rgba(255,255,255,0.3);border-radius:12px;color:#fff;font-size:0.8rem;padding:4px 14px;cursor:pointer;font-family:inherit;">✕ Exit</button>
2065
+ </div>
2066
+
2067
+ <!-- Documentation Popup -->
2068
+ <div id="docs-popup" style="display:none;position:fixed;z-index:62;font-family:Inter,sans-serif;pointer-events:auto;">
2069
+ <div id="docs-popup-inner" style="background:rgba(8,12,24,0.95);backdrop-filter:blur(20px);border:1px solid rgba(77,166,255,0.25);border-radius:14px;padding:0;width:480px;max-width:90vw;max-height:75vh;overflow:hidden;box-shadow:0 8px 40px rgba(0,0,0,0.5),0 0 60px rgba(0,85,164,0.15);">
2070
+ <!-- Header -->
2071
+ <div id="docs-popup-header" style="padding:16px 20px 12px;border-bottom:1px solid rgba(255,255,255,0.06);">
2072
+ <div style="display:flex;align-items:center;justify-content:space-between;">
2073
+ <div>
2074
+ <div id="docs-popup-name" style="font-size:1.05rem;font-weight:700;letter-spacing:0.04em;"></div>
2075
+ <div id="docs-popup-subtitle" style="font-size:0.8rem;color:rgba(255,255,255,0.5);margin-top:3px;"></div>
2076
+ </div>
2077
+ <div style="display:flex;gap:6px;align-items:center;">
2078
+ <button id="docs-edit-btn" title="Edit documentation" style="background:rgba(255,255,255,0.1);border:1px solid rgba(255,255,255,0.15);border-radius:6px;color:#aab;font-size:0.75rem;padding:6px 14px;cursor:pointer;font-family:inherit;">✏️ Edit</button>
2079
+ <button id="docs-popup-close" style="background:rgba(255,255,255,0.1);border:1px solid rgba(255,255,255,0.15);border-radius:6px;color:#aab;font-size:1rem;width:32px;height:32px;cursor:pointer;display:flex;align-items:center;justify-content:center;">×</button>
2080
+ </div>
2081
+ </div>
2082
+ <!-- Tab bar -->
2083
+ <div id="docs-tabs" style="display:flex;gap:6px;margin-top:12px;">
2084
+ <button class="docs-tab active" data-tab="overview" style="padding:6px 16px;background:rgba(0,85,164,0.3);border:1px solid rgba(0,85,164,0.4);border-radius:6px;color:#4da6ff;font-size:0.75rem;cursor:pointer;font-family:inherit;letter-spacing:0.08em;text-transform:uppercase;">Overview</button>
2085
+ <button class="docs-tab" data-tab="maintenance" style="padding:6px 16px;background:rgba(255,255,255,0.05);border:1px solid rgba(255,255,255,0.1);border-radius:6px;color:#778;font-size:0.75rem;cursor:pointer;font-family:inherit;letter-spacing:0.08em;text-transform:uppercase;">Maintenance</button>
2086
+ <button class="docs-tab" data-tab="specs" style="padding:6px 16px;background:rgba(255,255,255,0.05);border:1px solid rgba(255,255,255,0.1);border-radius:6px;color:#778;font-size:0.75rem;cursor:pointer;font-family:inherit;letter-spacing:0.08em;text-transform:uppercase;">Specs</button>
2087
+ <button class="docs-tab" data-tab="warnings" style="padding:6px 16px;background:rgba(255,255,255,0.05);border:1px solid rgba(255,255,255,0.1);border-radius:6px;color:#778;font-size:0.75rem;cursor:pointer;font-family:inherit;letter-spacing:0.08em;text-transform:uppercase;">⚠ Safety</button>
2088
+ </div>
2089
+ </div>
2090
+ <!-- Content -->
2091
+ <div id="docs-popup-content" style="padding:16px 20px;overflow-y:auto;max-height:50vh;font-size:0.85rem;line-height:1.6;">
2092
+ <div id="docs-tab-overview"></div>
2093
+ <div id="docs-tab-maintenance" style="display:none;"></div>
2094
+ <div id="docs-tab-specs" style="display:none;"></div>
2095
+ <div id="docs-tab-warnings" style="display:none;"></div>
2096
+ </div>
2097
+ <!-- Footer -->
2098
+ <div id="docs-popup-footer" style="padding:10px 20px 14px;border-top:1px solid rgba(255,255,255,0.06);display:flex;gap:8px;justify-content:flex-end;">
2099
+ <button id="docs-print" style="padding:8px 16px;background:rgba(255,255,255,0.06);border:1px solid rgba(255,255,255,0.12);border-radius:6px;color:#aab;font-size:0.75rem;cursor:pointer;font-family:inherit;letter-spacing:0.06em;text-transform:uppercase;">🖨 Print</button>
2100
+ <button id="docs-copy" style="padding:8px 16px;background:rgba(255,255,255,0.06);border:1px solid rgba(255,255,255,0.12);border-radius:6px;color:#aab;font-size:0.75rem;cursor:pointer;font-family:inherit;letter-spacing:0.06em;text-transform:uppercase;">📋 Copy</button>
2101
+ <button id="docs-export-pdf" style="padding:8px 16px;background:rgba(0,85,164,0.2);border:1px solid rgba(0,85,164,0.3);border-radius:6px;color:#4da6ff;font-size:0.75rem;cursor:pointer;font-family:inherit;letter-spacing:0.06em;text-transform:uppercase;">📄 Export All</button>
2102
+ </div>
2103
+ </div>
2104
+ <!-- Connecting line to 3D point -->
2105
+ <svg id="docs-popup-line" style="position:fixed;inset:0;z-index:61;pointer-events:none;" width="100%" height="100%">
2106
+ <line id="docs-connector-line" x1="0" y1="0" x2="0" y2="0" stroke="rgba(77,166,255,0.4)" stroke-width="1.5" stroke-dasharray="4,4"/>
2107
+ </svg>
2108
+ </div>
2109
+
2110
+ <!-- Camera Scan Overlay -->
2111
+ <div id="camera-scan-overlay" style="display:none;position:fixed;inset:0;z-index:200;background:#000;font-family:Inter,sans-serif;">
2112
+ <video id="camera-scan-video" autoplay playsinline muted style="width:100%;height:100%;object-fit:cover;"></video>
2113
+ <div style="position:absolute;top:0;left:0;right:0;padding:16px 20px;background:linear-gradient(rgba(0,0,0,0.7),transparent);display:flex;align-items:center;justify-content:space-between;">
2114
+ <div style="font-size:0.7rem;color:#fff;font-weight:600;letter-spacing:0.06em;">📸 Point at a subassembly</div>
2115
+ <button id="camera-scan-close" style="background:rgba(255,255,255,0.15);border:1px solid rgba(255,255,255,0.3);border-radius:8px;color:#fff;font-size:0.6rem;padding:8px 16px;cursor:pointer;font-family:inherit;">✕ Close</button>
2116
+ </div>
2117
+ <!-- Scanning crosshair -->
2118
+ <div style="position:absolute;top:50%;left:50%;transform:translate(-50%,-50%);width:200px;height:200px;border:2px solid rgba(77,166,255,0.5);border-radius:16px;pointer-events:none;"></div>
2119
+ <!-- Capture button -->
2120
+ <div style="position:absolute;bottom:0;left:0;right:0;padding:20px;background:linear-gradient(transparent,rgba(0,0,0,0.8));display:flex;flex-direction:column;align-items:center;gap:12px;">
2121
+ <div id="camera-scan-status" style="font-size:0.85rem;color:rgba(255,255,255,0.6);text-align:center;min-height:1.2em;"></div>
2122
+ <button id="camera-scan-capture" style="width:64px;height:64px;border-radius:50%;background:rgba(0,85,164,0.8);border:3px solid rgba(77,166,255,0.6);color:#fff;font-size:1.2rem;cursor:pointer;display:flex;align-items:center;justify-content:center;transition:all 0.2s;">🔍</button>
2123
+ <div id="camera-scan-result" style="display:none;width:100%;max-width:400px;background:rgba(8,12,24,0.95);backdrop-filter:blur(16px);border:1px solid rgba(77,166,255,0.3);border-radius:12px;padding:14px 18px;"></div>
2124
+ </div>
2125
+ <canvas id="camera-scan-canvas" style="display:none;"></canvas>
2126
+ </div>
2127
+
2128
+ <!-- Toast notification -->
2129
+ <div id="toast-notification" style="display:none;position:fixed;bottom:20px;right:20px;z-index:999;background:rgba(0,85,164,0.9);border:1px solid rgba(0,85,164,0.5);color:#fff;padding:12px 16px;border-radius:8px;font-family:Inter,sans-serif;font-size:0.85rem;box-shadow:0 4px 20px rgba(0,0,0,0.3);"></div>
2130
+
2131
+ <!-- Image Editor (full-screen overlay) -->
2132
+ <div id="image-editor-overlay" style="display:none;position:fixed;top:0;left:0;right:0;bottom:0;z-index:500;background:#0a0e1a;font-family:Inter,system-ui,sans-serif;">
2133
+ <!-- Top toolbar -->
2134
+ <div id="ie-toolbar" style="display:flex;align-items:center;gap:4px;padding:6px 12px;background:rgba(16,20,34,0.98);border-bottom:1px solid rgba(255,255,255,0.08);height:44px;overflow-x:auto;flex-shrink:0;">
2135
+ <span style="color:#4da6ff;font-weight:700;font-size:0.8rem;letter-spacing:0.1em;margin-right:8px;white-space:nowrap;">IMAGE EDITOR</span>
2136
+ <div style="width:1px;height:24px;background:rgba(255,255,255,0.1);margin:0 4px;flex-shrink:0;"></div>
2137
+ <!-- Tool buttons -->
2138
+ <button class="ie-tool active" data-tool="select" title="Select / Move (V)">↖</button>
2139
+ <button class="ie-tool" data-tool="draw" title="Draw / Pen (B)">✏</button>
2140
+ <button class="ie-tool" data-tool="eraser" title="Eraser (E)">🧹</button>
2141
+ <button class="ie-tool" data-tool="text" title="Add Text (T)">T</button>
2142
+ <button class="ie-tool" data-tool="rect" title="Rectangle (R)">▭</button>
2143
+ <button class="ie-tool" data-tool="circle" title="Circle (C)">○</button>
2144
+ <button class="ie-tool" data-tool="line" title="Line (L)">╱</button>
2145
+ <button class="ie-tool" data-tool="arrow" title="Arrow (A)">→</button>
2146
+ <div style="width:1px;height:24px;background:rgba(255,255,255,0.1);margin:0 4px;flex-shrink:0;"></div>
2147
+ <button class="ie-tool" data-tool="crop" title="Crop (X)">⬒</button>
2148
+ <div style="width:1px;height:24px;background:rgba(255,255,255,0.1);margin:0 4px;flex-shrink:0;"></div>
2149
+ <!-- Color & size -->
2150
+ <input type="color" id="ie-color" value="#ff3333" title="Stroke Color" style="width:28px;height:28px;border:1px solid rgba(255,255,255,0.15);border-radius:4px;cursor:pointer;background:none;padding:0;">
2151
+ <input type="color" id="ie-fill-color" value="#ffffff" title="Fill Color" style="width:28px;height:28px;border:1px solid rgba(255,255,255,0.15);border-radius:4px;cursor:pointer;background:none;padding:0;opacity:0.7;">
2152
+ <label style="color:#889;font-size:0.7rem;white-space:nowrap;margin-left:4px;">Size</label>
2153
+ <input type="range" id="ie-brush-size" min="1" max="40" value="3" style="width:70px;accent-color:#4da6ff;">
2154
+ <label style="color:#889;font-size:0.7rem;white-space:nowrap;margin-left:4px;">Opacity</label>
2155
+ <input type="range" id="ie-opacity" min="0" max="100" value="100" style="width:60px;accent-color:#4da6ff;">
2156
+ <div style="width:1px;height:24px;background:rgba(255,255,255,0.1);margin:0 4px;flex-shrink:0;"></div>
2157
+ <!-- Actions -->
2158
+ <button class="ie-action" id="ie-undo" title="Undo (Ctrl+Z)">↩</button>
2159
+ <button class="ie-action" id="ie-redo" title="Redo (Ctrl+Y)">↪</button>
2160
+ <button class="ie-action" id="ie-delete" title="Delete Selected (Del)">🗑</button>
2161
+ <div style="width:1px;height:24px;background:rgba(255,255,255,0.1);margin:0 4px;flex-shrink:0;"></div>
2162
+ <button class="ie-action" id="ie-rotate-l" title="Rotate Left 90°">⟲</button>
2163
+ <button class="ie-action" id="ie-rotate-r" title="Rotate Right 90°">⟳</button>
2164
+ <button class="ie-action" id="ie-flip-h" title="Flip Horizontal">⇔</button>
2165
+ <button class="ie-action" id="ie-flip-v" title="Flip Vertical">⇕</button>
2166
+ <div style="width:1px;height:24px;background:rgba(255,255,255,0.1);margin:0 4px;flex-shrink:0;"></div>
2167
+ <!-- Filters -->
2168
+ <select id="ie-filter" style="background:rgba(255,255,255,0.08);border:1px solid rgba(255,255,255,0.15);border-radius:4px;color:#ccd;font-size:0.7rem;padding:4px 6px;cursor:pointer;">
2169
+ <option value="">No Filter</option>
2170
+ <option value="grayscale">Grayscale</option>
2171
+ <option value="sepia">Sepia</option>
2172
+ <option value="invert">Invert</option>
2173
+ <option value="brightness">Brightness +</option>
2174
+ <option value="contrast">Contrast +</option>
2175
+ <option value="blur">Blur</option>
2176
+ <option value="sharpen">Sharpen</option>
2177
+ </select>
2178
+ <button class="ie-action" id="ie-apply-filter" title="Apply Filter">Apply</button>
2179
+ <button class="ie-action" id="ie-reset-filters" title="Reset All Filters">Reset</button>
2180
+ <div style="flex:1;"></div>
2181
+ <!-- Right side: Save & Close -->
2182
+ <button class="ie-action" id="ie-save" style="background:rgba(0,85,164,0.3);border-color:rgba(0,85,164,0.6);color:#4da6ff;font-weight:600;" title="Save (Ctrl+S)">💾 Save</button>
2183
+ <button class="ie-action" id="ie-download" style="color:#0c8;" title="Download as PNG">⬇ Download</button>
2184
+ <button class="ie-action" id="ie-close" style="color:#f55;font-size:1.1rem;" title="Close Editor (Esc)">✕</button>
2185
+ </div>
2186
+ <!-- Left sidebar: adjustments -->
2187
+ <div id="ie-sidebar" style="position:absolute;top:44px;left:0;bottom:0;width:200px;background:rgba(16,20,34,0.95);border-right:1px solid rgba(255,255,255,0.06);padding:12px;overflow-y:auto;font-size:0.72rem;color:#aab;">
2188
+ <div style="font-size:0.75rem;font-weight:600;color:#4da6ff;letter-spacing:0.1em;text-transform:uppercase;margin-bottom:10px;">Adjustments</div>
2189
+ <label style="display:block;margin-bottom:2px;">Brightness</label>
2190
+ <input type="range" id="ie-adj-brightness" min="-100" max="100" value="0" style="width:100%;accent-color:#4da6ff;margin-bottom:8px;">
2191
+ <label style="display:block;margin-bottom:2px;">Contrast</label>
2192
+ <input type="range" id="ie-adj-contrast" min="-100" max="100" value="0" style="width:100%;accent-color:#4da6ff;margin-bottom:8px;">
2193
+ <label style="display:block;margin-bottom:2px;">Saturation</label>
2194
+ <input type="range" id="ie-adj-saturation" min="-100" max="100" value="0" style="width:100%;accent-color:#4da6ff;margin-bottom:8px;">
2195
+ <label style="display:block;margin-bottom:2px;">Hue Rotate</label>
2196
+ <input type="range" id="ie-adj-hue" min="-180" max="180" value="0" style="width:100%;accent-color:#4da6ff;margin-bottom:8px;">
2197
+ <label style="display:block;margin-bottom:2px;">Blur</label>
2198
+ <input type="range" id="ie-adj-blur" min="0" max="20" value="0" style="width:100%;accent-color:#4da6ff;margin-bottom:8px;">
2199
+ <button id="ie-adj-reset" style="width:100%;padding:6px;background:rgba(255,255,255,0.06);border:1px solid rgba(255,255,255,0.12);border-radius:4px;color:#889;font-size:0.7rem;cursor:pointer;margin-top:4px;">Reset Adjustments</button>
2200
+ <div style="width:100%;height:1px;background:rgba(255,255,255,0.08);margin:14px 0;"></div>
2201
+ <div style="font-size:0.75rem;font-weight:600;color:#4da6ff;letter-spacing:0.1em;text-transform:uppercase;margin-bottom:10px;">Layers</div>
2202
+ <div id="ie-layers" style="font-size:0.68rem;color:#778;">
2203
+ <div style="padding:4px 6px;background:rgba(255,255,255,0.04);border-radius:3px;margin-bottom:2px;">🖼 Background Image</div>
2204
+ </div>
2205
+ <div style="width:100%;height:1px;background:rgba(255,255,255,0.08);margin:14px 0;"></div>
2206
+ <div style="font-size:0.75rem;font-weight:600;color:#4da6ff;letter-spacing:0.1em;text-transform:uppercase;margin-bottom:10px;">Canvas</div>
2207
+ <div style="display:flex;gap:6px;align-items:center;margin-bottom:6px;">
2208
+ <span id="ie-canvas-size" style="color:#778;">0 x 0</span>
2209
+ </div>
2210
+ <button id="ie-resize" style="width:100%;padding:6px;background:rgba(255,255,255,0.06);border:1px solid rgba(255,255,255,0.12);border-radius:4px;color:#889;font-size:0.7rem;cursor:pointer;">Resize Canvas</button>
2211
+ </div>
2212
+ <!-- Canvas area -->
2213
+ <div id="ie-canvas-wrap" style="position:absolute;top:44px;left:200px;right:0;bottom:0;overflow:auto;display:flex;align-items:center;justify-content:center;background:repeating-conic-gradient(#1a1e2e 0% 25%, #141824 0% 50%) 50% / 20px 20px;">
2214
+ <canvas id="ie-canvas"></canvas>
2215
+ </div>
2216
+ </div>
2217
+ <style>
2218
+ .ie-tool,.ie-action{background:rgba(255,255,255,0.06);border:1px solid rgba(255,255,255,0.12);border-radius:4px;color:#aab;font-size:0.8rem;padding:4px 8px;cursor:pointer;font-family:inherit;white-space:nowrap;flex-shrink:0;}
2219
+ .ie-tool:hover,.ie-action:hover{background:rgba(77,166,255,0.15);color:#fff;}
2220
+ .ie-tool.active{background:rgba(0,85,164,0.3);border-color:rgba(0,85,164,0.6);color:#4da6ff;}
2221
+ </style>
2222
+
2223
+ <!-- Debug Console Panel -->
2224
+ <div id="debug-console-panel" style="display:none;position:fixed;bottom:0;left:0;right:0;z-index:200;background:rgba(0,0,0,0.95);border-top:2px solid rgba(77,166,255,0.4);font-family:'SF Mono',Monaco,Consolas,monospace;font-size:0.75rem;">
2225
+ <div style="display:flex;align-items:center;justify-content:space-between;padding:6px 14px;background:rgba(77,166,255,0.08);border-bottom:1px solid rgba(255,255,255,0.08);">
2226
+ <div style="display:flex;align-items:center;gap:10px;"><span style="color:#4da6ff;font-weight:600;letter-spacing:0.1em;font-size:0.8rem;">DEBUG CONSOLE</span><span style="color:rgba(255,255,255,0.3);font-size:0.65rem;font-weight:400;letter-spacing:0;">Logs, warnings &amp; errors</span></div>
2227
+ <div style="display:flex;gap:8px;align-items:center;">
2228
+ <button id="debug-copy" style="background:rgba(255,255,255,0.06);border:1px solid rgba(255,255,255,0.12);border-radius:4px;color:#aab;font-size:0.7rem;padding:2px 10px;cursor:pointer;font-family:inherit;" title="Copy all logs to clipboard">Copy</button>
2229
+ <button id="debug-clear" style="background:rgba(255,255,255,0.06);border:1px solid rgba(255,255,255,0.12);border-radius:4px;color:#aab;font-size:0.7rem;padding:2px 10px;cursor:pointer;font-family:inherit;">Clear</button>
2230
+ <button id="debug-close" style="background:none;border:none;color:#667;font-size:1.2rem;cursor:pointer;padding:0 4px;">×</button>
2231
+ </div>
2232
+ </div>
2233
+ <div id="debug-console-output" style="height:200px;overflow-y:auto;padding:8px 14px;color:#ccd;line-height:1.6;"></div>
2234
+ </div>
2235
+
2236
+ <script src="https://cdn.jsdelivr.net/npm/qrcode-generator@1.4.4/qrcode.js"></script>
2237
+ <script type="module" src="./app.js?v=206"></script>
2238
+ </body>
2239
+ </html>