File size: 28,390 Bytes
05ae0b9
0a9c963
f1e9302
d69d44c
6955891
 
623bad5
6955891
 
 
 
 
 
 
 
 
d69d44c
 
6955891
d69d44c
 
6955891
 
 
 
 
d69d44c
 
 
 
6955891
d69d44c
 
 
6955891
 
 
 
d69d44c
 
6955891
 
 
 
 
 
d69d44c
 
4b47c3d
 
 
 
 
 
 
 
 
 
 
 
6955891
 
 
 
 
 
 
 
 
 
d69d44c
6955891
 
 
 
 
 
 
 
 
 
 
d69d44c
d724849
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
d69d44c
 
 
6955891
623bad5
4b47c3d
 
 
 
 
d724849
4b47c3d
d69d44c
4b47c3d
 
 
 
 
 
 
bcae6dd
4b47c3d
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
d69d44c
 
4b47c3d
 
 
 
 
 
 
 
4e8e87d
4b47c3d
 
 
 
 
 
 
 
 
 
 
 
fe9c939
f1e9302
4b47c3d
 
d724849
4b47c3d
 
 
 
 
1197046
0a9c963
4b47c3d
 
 
 
 
 
 
 
 
 
 
 
 
 
d69d44c
87e3cb1
 
4b47c3d
 
 
 
 
 
1def05c
 
4b47c3d
 
 
 
 
1def05c
72ade06
4b47c3d
 
 
 
 
 
 
 
 
 
 
 
d69d44c
4b47c3d
bcae6dd
d724849
 
 
 
 
bcae6dd
 
d724849
 
 
 
 
bcae6dd
 
 
4b47c3d
d724849
 
 
4b47c3d
d724849
4b47c3d
 
d724849
 
4b47c3d
 
 
 
 
 
d724849
 
4b47c3d
d724849
 
4b47c3d
 
 
 
 
 
d724849
 
4b47c3d
 
 
d724849
 
 
 
4b47c3d
 
 
d724849
 
4b47c3d
 
 
 
 
d724849
 
 
4b47c3d
 
 
 
 
d724849
 
4b47c3d
 
d69d44c
 
d724849
 
 
 
4b47c3d
d724849
 
 
72ade06
7d2f112
4b47c3d
 
 
 
 
 
 
 
 
 
 
 
 
 
 
7d2f112
550c5aa
7d2f112
 
d724849
550c5aa
d724849
623bad5
d724849
623bad5
 
d724849
7d2f112
 
 
 
 
 
 
e99491d
623bad5
 
 
 
 
 
d724849
 
 
623bad5
 
 
 
 
 
 
 
 
 
 
bcae6dd
 
d724849
7d2f112
623bad5
 
 
d724849
623bad5
 
d724849
623bad5
 
d724849
 
623bad5
 
 
 
d724849
 
 
623bad5
 
d724849
623bad5
 
 
d724849
623bad5
 
d724849
623bad5
 
 
 
 
 
 
d724849
623bad5
 
 
8f7658e
623bad5
d724849
 
8f7658e
5e07b31
 
 
 
 
 
 
 
 
 
 
 
d724849
 
 
 
5e07b31
d724849
 
 
5e07b31
d724849
 
 
623bad5
 
0a9c963
f1e9302
0a9c963
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
<!DOCTYPE html>
<html class="dark" lang="en">

<head>
    <meta charset="utf-8" />
    <meta content="width=device-width, initial-scale=1.0" name="viewport" />
    <title>Continuity</title>
    <link href="https://fonts.googleapis.com" rel="preconnect" />
    <link crossorigin="" href="https://fonts.gstatic.com" rel="preconnect" />
    <link href="https://fonts.googleapis.com/css2?family=Space+Grotesk:wght@300;400;500;600;700&display=swap"
        rel="stylesheet" />
    <link href="https://fonts.googleapis.com/css2?family=Noto+Sans:wght@300;400;500;600;700&display=swap"
        rel="stylesheet" />
    <link href="https://fonts.googleapis.com/css2?family=Material+Symbols+Outlined:wght,FILL@100..700,0..1&display=swap"
        rel="stylesheet" />
    <script src="https://cdn.tailwindcss.com?plugins=forms,container-queries"></script>
    <script>
        tailwind.config = {
            darkMode: "class",
            theme: {
                extend: {
                    colors: { "primary": "#7f0df2", "background-dark": "#0a060f", "surface-dark": "#1a1221", "border-dark": "#362445" },
                    fontFamily: { "display": ["Space Grotesk", "sans-serif"], "body": ["Noto Sans", "sans-serif"] },
                    boxShadow: { "neon": "0 0 20px rgba(127, 13, 242, 0.4)" }
                },
            },
        }
    </script>
    <style>
        body {
            background-color: #0a060f;
        }

        .glass-panel {
            background: rgba(26, 18, 33, 0.95);
            backdrop-filter: blur(16px);
            -webkit-backdrop-filter: blur(16px);
            border: 1px solid rgba(255, 255, 255, 0.08);
        }

        .force-clip {
            -webkit-mask-image: -webkit-radial-gradient(white, black);
            mask-image: radial-gradient(white, black);
            transform: translateZ(0);
            border-radius: 1rem;
            overflow: hidden;
        }

        #gallery-drawer {
            transition: transform 0.3s cubic-bezier(0.4, 0, 0.2, 1);
        }

        .drawer-open {
            transform: translateX(0%);
        }

        .drawer-closed {
            transform: translateX(100%);
        }

        input[type=range] {
            -webkit-appearance: none;
            background: transparent;
        }

        input[type=range]::-webkit-slider-thumb {
            -webkit-appearance: none;
            height: 16px;
            width: 16px;
            border-radius: 50%;
            background: #7f0df2;
            margin-top: -6px;
            cursor: pointer;
            box-shadow: 0 0 10px rgba(127, 13, 242, 0.5);
        }

        input[type=range]::-webkit-slider-runnable-track {
            width: 100%;
            height: 4px;
            cursor: pointer;
            background: #362445;
            border-radius: 2px;
        }

        /* Custom Scrollbar */
        .custom-scrollbar::-webkit-scrollbar {
            width: 6px;
        }

        .custom-scrollbar::-webkit-scrollbar-track {
            background: rgba(255, 255, 255, 0.05);
            border-radius: 4px;
        }

        .custom-scrollbar::-webkit-scrollbar-thumb {
            background: rgba(127, 13, 242, 0.5);
            border-radius: 4px;
        }

        .custom-scrollbar::-webkit-scrollbar-thumb:hover {
            background: rgba(127, 13, 242, 0.8);
        }
    </style>
</head>

<body
    class="bg-background-dark font-body text-white h-screen w-screen overflow-hidden flex flex-col selection:bg-primary selection:text-white relative">
    <header
        class="flex items-center justify-between px-6 py-4 z-40 relative w-full border-b border-white/5 bg-background-dark/50 backdrop-blur-sm">
        <div class="flex items-center gap-3">
            <div
                class="size-8 flex items-center justify-center bg-primary/20 rounded-lg border border-primary/30 text-primary">
                <span class="material-symbols-outlined">movie_filter</span></div>
            <h1 class="text-xl font-display font-bold tracking-tight">Continuity</h1>
        </div>
        <div class="flex items-center gap-3">
            <button onclick="toggleDrawer(true)"
                class="flex items-center gap-2 px-4 py-2 bg-primary hover:bg-[#6b0bc9] text-white rounded-lg transition-colors text-xs font-bold uppercase tracking-wider shadow-neon">
                <span class="material-symbols-outlined text-lg">history</span> Gallery
            </button>
        </div>
    </header>
    <main class="flex-1 w-full overflow-y-auto relative flex flex-col items-center pt-8 pb-[32rem]">
        <div class="w-full max-w-6xl mx-auto flex items-center justify-center gap-4 md:gap-8 lg:gap-12 px-4">
            <div class="flex flex-col gap-3 flex-1 max-w-[320px] group">
                <div class="flex justify-between px-1"><span
                        class="text-[10px] font-bold tracking-widest text-gray-500 uppercase">Scene A (Start)</span>
                </div>
                <div class="relative aspect-[9/16] md:aspect-[3/4] bg-surface-dark border-2 border-dashed border-border-dark rounded-2xl flex flex-col items-center justify-center gap-4 hover:border-primary/50 hover:bg-surface-dark/80 transition-all cursor-pointer shadow-lg overflow-hidden"
                    onclick="document.getElementById('video-upload-a').click()">
                    <div
                        class="size-12 rounded-full bg-white/5 flex items-center justify-center group-hover:scale-110 transition-transform relative z-10">
                        <span
                            class="material-symbols-outlined text-2xl text-gray-400 group-hover:text-white">upload</span>
                    </div>
                    <p id="label-a" class="text-xs font-medium text-gray-400 text-center px-4 relative z-10">Upload
                        Start Clip</p>
                    <input type="file" id="video-upload-a" accept="video/*" class="hidden"
                        onchange="handleFileSelect(this, 'label-a')">
                </div>
            </div>
            <div class="flex flex-col gap-3 flex-[1.5] max-w-[500px] relative z-20">
                <div class="flex justify-center px-1"><span
                        class="text-[10px] font-bold tracking-[0.2em] text-primary uppercase animate-pulse">Generated
                        Bridge</span></div>
                <div id="bridge-card-outer"
                    class="relative aspect-video rounded-2xl shadow-neon transition-all duration-500 border border-primary/20">
                    <div id="bridge-card-inner" class="force-clip w-full h-full bg-black relative">
                        <div id="bridge-content" class="w-full h-full">
                            <div
                                class="absolute inset-0 bg-[url('https://images.unsplash.com/photo-1614850523060-8da1d56ae167?q=80&w=1000&auto=format&fit=crop')] bg-cover bg-center opacity-20 mix-blend-overlay">
                            </div>
                            <div class="absolute inset-0 flex flex-col items-center justify-center text-center p-6">
                                <div
                                    class="size-16 rounded-full bg-primary/10 border border-primary/20 flex items-center justify-center mb-3">
                                    <span class="material-symbols-outlined text-3xl text-primary">auto_awesome</span>
                                </div>
                                <p class="text-sm text-gray-300">Ready to bridge the gap</p>
                            </div>
                        </div>
                        <div id="bridge-border"
                            class="absolute inset-0 rounded-2xl border-2 border-transparent pointer-events-none z-30">
                        </div>
                    </div>
                </div>
                <div id="merged-download-container"
                    class="hidden flex justify-center mt-8 relative z-30 animate-in fade-in slide-in-from-top-2">
                    <a id="merged-download-btn" href="#" download
                        class="flex items-center gap-2 px-6 py-3 bg-surface-dark hover:bg-white/5 border border-primary/30 hover:border-primary text-primary hover:text-white rounded-xl font-bold text-xs uppercase tracking-widest transition-all shadow-lg group">
                        <span class="material-symbols-outlined group-hover:animate-bounce">movie</span> Download Merged
                        (A+B+C)
                    </a>
                </div>
            </div>
            <div class="flex flex-col gap-3 flex-1 max-w-[320px] group">
                <div class="flex justify-end px-1"><span
                        class="text-[10px] font-bold tracking-widest text-gray-500 uppercase">Scene C (End)</span></div>
                <div class="relative aspect-[9/16] md:aspect-[3/4] bg-surface-dark border-2 border-dashed border-border-dark rounded-2xl flex flex-col items-center justify-center gap-4 hover:border-primary/50 hover:bg-surface-dark/80 transition-all cursor-pointer shadow-lg overflow-hidden"
                    onclick="document.getElementById('video-upload-c').click()">
                    <div
                        class="size-12 rounded-full bg-white/5 flex items-center justify-center group-hover:scale-110 transition-transform relative z-10">
                        <span
                            class="material-symbols-outlined text-2xl text-gray-400 group-hover:text-white">upload</span>
                    </div>
                    <p id="label-c" class="text-xs font-medium text-gray-400 text-center px-4 relative z-10">Upload End
                        Clip</p>
                    <input type="file" id="video-upload-c" accept="video/*" class="hidden"
                        onchange="handleFileSelect(this, 'label-c')">
                </div>
            </div>
        </div>
    </main>
    <div class="fixed bottom-8 left-1/2 -translate-x-1/2 z-50 w-full max-w-2xl px-4 pointer-events-none">
        <div id="analysis-panel"
            class="glass-panel p-2 rounded-full shadow-neon flex items-center justify-between pl-6 pr-2 pointer-events-auto">
            <div class="flex flex-col"><span class="text-sm font-bold text-white">Continuity Engine</span><span
                    class="text-[10px] text-gray-400 uppercase tracking-wide">Ready for analysis</span></div>
            <div class="flex gap-2">
                <button onclick="toggleDrawer(true)"
                    class="bg-surface-dark hover:bg-white/10 text-white p-3 rounded-full transition-all flex items-center justify-center border border-white/10"><span
                        class="material-symbols-outlined text-lg">history</span></button>
                <button id="analyze-btn"
                    class="bg-primary hover:bg-[#6b0bc9] text-white px-6 py-3 rounded-full font-bold text-sm transition-all flex items-center gap-2 shadow-lg"><span
                        class="material-symbols-outlined text-lg">analytics</span> Analyze Scenes</button>
            </div>
        </div>
        <div id="review-panel"
            class="hidden glass-panel rounded-2xl p-5 shadow-2xl flex flex-col gap-4 animate-in slide-in-from-bottom-4 duration-300 max-h-[80vh] overflow-y-auto custom-scrollbar pointer-events-auto">
            <div class="flex items-center justify-between border-b border-white/10 pb-3">
                <h3 class="text-sm font-bold text-white flex items-center gap-2"><span
                        class="material-symbols-outlined text-primary">movie_edit</span> Director's Configuration</h3>
                <div class="flex gap-2">
                    <button onclick="toggleDrawer(true)"
                        class="text-xs text-gray-400 hover:text-white uppercase tracking-wider flex items-center gap-1"><span
                            class="material-symbols-outlined text-sm">history</span> History</button>
                    <span class="text-white/10">|</span>
                    <button onclick="resetUI()"
                        class="text-xs text-gray-500 hover:text-white uppercase tracking-wider">Reset</button>
                </div>
            </div>
            <div class="grid grid-cols-2 gap-4 mb-2">
                <div class="bg-white/5 p-3 rounded-lg border border-white/10">
                    <span class="text-[10px] font-bold text-primary uppercase flex items-center gap-1"><span
                            class="material-symbols-outlined text-xs">videocam</span> Scene A Analysis</span>
                    <p id="analysis-a-text"
                        class="text-[11px] text-gray-300 h-24 overflow-y-auto custom-scrollbar mt-2 leading-relaxed">
                        Waiting for analysis...</p>
                </div>
                <div class="bg-white/5 p-3 rounded-lg border border-white/10">
                    <span class="text-[10px] font-bold text-primary uppercase flex items-center gap-1"><span
                            class="material-symbols-outlined text-xs">videocam</span> Scene C Analysis</span>
                    <p id="analysis-c-text"
                        class="text-[11px] text-gray-300 h-24 overflow-y-auto custom-scrollbar mt-2 leading-relaxed">
                        Waiting for analysis...</p>
                </div>
            </div>
            <div><label class="text-[10px] font-bold text-gray-500 uppercase tracking-widest mb-1 block">Visual
                    Direction (Bridge B)</label>
                <textarea id="prompt-box" rows="4"
                    class="w-full bg-black/20 border border-white/10 rounded-lg p-3 text-sm text-white focus:border-primary focus:ring-1 focus:ring-primary outline-none resize-none custom-scrollbar"></textarea>
            </div>

            <div class="grid grid-cols-2 gap-4">
                <div><label class="text-[10px] font-bold text-gray-500 uppercase tracking-widest mb-1 block">Visual
                        Style</label>
                    <select id="style-select" onchange="savePreference('style', this.value)"
                        class="w-full bg-black/20 border border-white/10 rounded-lg p-2.5 text-sm text-white focus:border-primary outline-none cursor-pointer">
                        <option value="Cinematic">Cinematic</option>
                        <option value="Anime">Anime</option>
                        <option value="Cyberpunk">Cyberpunk</option>
                        <option value="VHS">VHS Glitch</option>
                        <option value="Noir">Noir</option>
                    </select>
                </div>
                <div><label class="text-[10px] font-bold text-gray-500 uppercase tracking-widest mb-1 block">Audio
                        Mood</label>
                    <select id="audio-input" onchange="savePreference('audio', this.value)"
                        class="w-full bg-black/20 border border-white/10 rounded-lg p-2.5 text-sm text-white focus:border-primary outline-none cursor-pointer">
                        <option value="Cinematic orchestral score">Cinematic</option>
                        <option value="Industrial synthwave">Cyberpunk</option>
                        <option value="Nature sounds">Nature</option>
                        <option value="Tense atmosphere">Horror</option>
                        <option value="High energy rock">Action</option>
                    </select>
                </div>
            </div>
            <div class="border-t border-white/10 pt-3">
                <button onclick="document.getElementById('advanced-settings').classList.toggle('hidden')"
                    class="flex items-center gap-2 text-xs font-bold text-gray-400 uppercase tracking-widest hover:text-white transition-colors w-full">
                    <span class="material-symbols-outlined text-sm">tune</span> Advanced Physics & Controls <span
                        class="material-symbols-outlined text-sm ml-auto">expand_more</span>
                </button>
                <div id="advanced-settings"
                    class="hidden pt-3 grid grid-cols-1 md:grid-cols-2 gap-4 animate-in fade-in slide-in-from-top-2">
                    <div class="col-span-1 md:col-span-2"><label
                            class="text-[10px] text-gray-500 uppercase font-bold">Negative Prompt</label>
                        <input id="negative-prompt" type="text" placeholder="text, blurry, watermark"
                            class="w-full bg-black/20 border border-white/10 rounded-lg p-2 text-xs text-white focus:border-red-500/50 outline-none mt-1">
                    </div>
                    <div>
                        <div class="flex justify-between"><label
                                class="text-[10px] text-gray-500 uppercase font-bold">Guidance Scale</label><span
                                id="guidance-val" class="text-[10px] text-primary">5.0</span></div>
                        <input id="guidance-scale" type="range" min="1" max="20" value="5" step="0.5"
                            class="w-full mt-2"
                            oninput="document.getElementById('guidance-val').innerText = this.value">
                    </div>
                    <div>
                        <div class="flex justify-between"><label
                                class="text-[10px] text-gray-500 uppercase font-bold">Motion Strength</label><span
                                id="motion-val" class="text-[10px] text-primary">5</span></div>
                        <input id="motion-strength" type="range" min="1" max="10" value="5" class="w-full mt-2"
                            oninput="document.getElementById('motion-val').innerText = this.value">
                    </div>
                </div>
            </div>
            <a id="panel-download-btn" href="#" download
                class="hidden w-full bg-surface-dark border border-green-500/50 text-green-400 hover:bg-green-500/10 py-3.5 rounded-xl font-bold text-sm tracking-wide shadow-lg flex items-center justify-center gap-2 mb-3 transition-all">
                <span class="material-symbols-outlined">download</span> Download Final Video
            </a>
            <button id="generate-btn"
                class="w-full bg-gradient-to-r from-primary to-[#9d4edd] hover:brightness-110 text-white py-3.5 rounded-xl font-bold text-sm tracking-wide shadow-lg flex items-center justify-center gap-2 mt-1">
                <span class="material-symbols-outlined">auto_fix_high</span> Generate Video
            </button>
        </div>
    </div>
    <div id="drawer-overlay" onclick="toggleDrawer(false)"
        class="fixed inset-0 bg-black/80 backdrop-blur-sm z-[90] hidden transition-opacity"></div>
    <aside id="gallery-drawer"
        class="fixed top-0 right-0 h-full w-[400px] bg-background-dark border-l border-white/10 z-[100] drawer-closed flex flex-col shadow-2xl">
        <div class="p-6 border-b border-white/5 flex items-center justify-between bg-surface-dark">
            <h2 class="text-lg font-bold text-white flex items-center gap-2"><span
                    class="material-symbols-outlined text-primary">history</span> History</h2>
            <button onclick="toggleDrawer(false)"
                class="text-gray-400 hover:text-white transition-colors cursor-pointer"><span
                    class="material-symbols-outlined">close</span></button>
        </div>
        <div id="gallery-content" class="flex-1 overflow-y-auto p-4 space-y-4 custom-scrollbar">
            <div class="text-center text-gray-500 mt-10">Loading history...</div>
        </div>
    </aside>
    <script>
        function toggleDrawer(show) {
            const drawer = document.getElementById('gallery-drawer');
            const overlay = document.getElementById('drawer-overlay');
            if (!drawer || !overlay) return;
            if (show) {
                drawer.classList.remove('drawer-closed'); drawer.classList.add('drawer-open'); overlay.classList.remove('hidden'); fetchHistory();
            } else {
                drawer.classList.remove('drawer-open'); drawer.classList.add('drawer-closed'); overlay.classList.add('hidden');
            }
        }
        let currentVideoAPath = "", currentVideoCPath = "";
        function savePreference(key, value) { localStorage.setItem('continuity_' + key, value); }
        function loadPreferences() {
            const s = localStorage.getItem('continuity_style');
            const a = localStorage.getItem('continuity_audio');
            if (s) document.getElementById('style-select').value = s;
            if (a) document.getElementById('audio-input').value = a;
        }
        loadPreferences();
        async function fetchHistory() {
            const c = document.getElementById('gallery-content');
            c.innerHTML = '<div class="text-center mt-10"><span class="material-symbols-outlined animate-spin">progress_activity</span></div>';
            try {
                const res = await fetch('/history');
                const data = await res.json();
                if (!data || !data.length) { c.innerHTML = '<div class="text-center text-gray-500 mt-10 text-xs">No history found.</div>'; return; }
                c.innerHTML = data.map(i => `<div class="bg-black/40 rounded-lg overflow-hidden border border-white/5 mb-4 group"><video src="${i.url}" class="w-full aspect-video object-cover" controls></video><div class="p-2 flex justify-between items-center bg-white/5"><span class="text-[10px] text-gray-400 truncate w-32">${i.name}</span><a href="${i.url}" download class="text-gray-400 hover:text-white transition-colors"><span class="material-symbols-outlined text-sm">download</span></a></div></div>`).join('');
            } catch (e) { c.innerHTML = '<div class="text-center text-red-400 mt-10">Error loading history.</div>'; }
        }
        function handleFileSelect(input, labelId) {
            if (input.files[0]) {
                document.getElementById(labelId).innerText = input.files[0].name;
                document.getElementById(labelId).classList.add("text-primary", "font-bold");
            }
        }
        function resetUI() {
            document.getElementById("analysis-panel").classList.remove("hidden");
            document.getElementById("review-panel").classList.add("hidden");
            document.getElementById("prompt-box").value = "";
            document.getElementById("analysis-a-text").innerText = "Waiting for analysis...";
            document.getElementById("analysis-c-text").innerText = "Waiting for analysis...";
            currentVideoAPath = ""; currentVideoCPath = "";
            document.getElementById("bridge-content").innerHTML = `<div class="absolute inset-0 bg-cover bg-center opacity-20" style="background-image:url('https://images.unsplash.com/photo-1614850523060-8da1d56ae167')"></div><div class="absolute inset-0 flex flex-col items-center justify-center"><span class="material-symbols-outlined text-3xl text-primary mb-2">auto_awesome</span><p class="text-xs text-gray-400">Ready</p></div>`;
            document.getElementById("bridge-card-outer").classList.replace("border-primary", "border-primary/20");
            document.getElementById("bridge-border").classList.replace("border-primary/50", "border-transparent");
            document.getElementById("merged-download-container").classList.add("hidden");
            document.getElementById("panel-download-btn").classList.add("hidden");
        }
        document.getElementById("analyze-btn").addEventListener("click", async () => {
            const fA = document.getElementById("video-upload-a").files[0], fC = document.getElementById("video-upload-c").files[0];
            if (!fA || !fC) return alert("Upload both scenes.");
            const btn = document.getElementById("analyze-btn");
            btn.disabled = true; btn.innerHTML = `Analyzing...`;
            const fd = new FormData(); fd.append("video_a", fA); fd.append("video_c", fC);
            try {
                const res = await fetch("/analyze", { method: "POST", body: fd });
                const data = await res.json();
                document.getElementById("prompt-box").value = data.prompt;
                document.getElementById("analysis-a-text").innerText = data.analysis_a || "No details.";
                document.getElementById("analysis-c-text").innerText = data.analysis_c || "No details.";
                currentVideoAPath = data.video_a_path; currentVideoCPath = data.video_c_path;
                document.getElementById("analysis-panel").classList.add("hidden");
                document.getElementById("review-panel").classList.remove("hidden");
            } catch (e) { alert(e.message); } finally { btn.disabled = false; btn.innerHTML = `<span class="material-symbols-outlined text-lg">analytics</span> Analyze Scenes`; }
        });
        document.getElementById("generate-btn").addEventListener("click", async () => {
            const btn = document.getElementById("generate-btn");
            btn.disabled = true; btn.innerHTML = `Generating...`;
            try {
                const res = await fetch("/generate", {
                    method: "POST", headers: { "Content-Type": "application/json" },
                    body: JSON.stringify({
                        prompt: document.getElementById("prompt-box").value,
                        style: document.getElementById("style-select").value,
                        audio_prompt: document.getElementById("audio-input").value,
                        negative_prompt: document.getElementById("negative-prompt").value,
                        guidance_scale: document.getElementById("guidance-scale").value,
                        motion_strength: document.getElementById("motion-strength").value,
                        video_a_path: currentVideoAPath, video_c_path: currentVideoCPath
                    })
                });
                const data = await res.json();
                const pollStartTime = Date.now();
                const poll = setInterval(async () => {
                    if (Date.now() - pollStartTime > 600000) { // 10 min timeout
                        clearInterval(poll); alert("Timeout."); btn.disabled = false; btn.innerHTML = "Timeout"; return;
                    }
                    try {
                        const sRes = await fetch(`/status/${data.job_id}?t=${Date.now()}`);
                        if (sRes.ok) {
                            const s = await sRes.json();
                            if (s.status === "completed") {
                                clearInterval(poll);
                                document.getElementById("bridge-content").innerHTML = `<video controls autoplay loop class="w-full h-full object-contain bg-black"><source src="${s.video_url}" type="video/mp4"></video>`;
                                document.getElementById("bridge-card-outer").classList.replace("border-primary/20", "border-primary");
                                if (s.merged_video_url) {
                                    const dlBtn = document.getElementById("merged-download-btn");
                                    dlBtn.href = s.merged_video_url;
                                    document.getElementById("merged-download-container").classList.remove("hidden");
                                    // Show panel button
                                    const panelBtn = document.getElementById("panel-download-btn");
                                    panelBtn.href = s.merged_video_url;
                                    panelBtn.classList.remove("hidden");
                                }
                                btn.innerHTML = "Done!"; setTimeout(() => { btn.disabled = false; btn.innerHTML = `<span class="material-symbols-outlined">auto_fix_high</span> Generate Video`; }, 3000);
                            } else if (s.status === "error") { clearInterval(poll); alert(s.log); btn.disabled = false; btn.innerHTML = "Try Again"; }
                            else { btn.innerHTML = `${s.log} (${s.progress}%)`; }
                        }
                    } catch (e) { console.error(e); }
                }, 2000);
            } catch (e) { alert(e.message); btn.disabled = false; }
        });
    </script>
</body>

</html>