PageSourceSearch

https://bbcc.ai/build/assets/DraggableMenu-Bk7Spryo.js

js bbcc.ai collected 2026-10-05 12:12:21 UTC 145,095 bytes, 3,436 lines download raw bytes

1import{r as n,j as t,b as ee,a as se,H as ke,L as Se}from"./app-DP13319Q.js";import{F as T,c as Ce,Z as Ee,h as Me,aV as le,a4 as Ie,aW as Be,aM as Re,aX as je,S as Pe,ai as He,aY as Le,ar as Ae,aZ as Te,aE as De,a_ as ze,a$ as Ne,ab as Oe,aG as _e,az as Ye,b0 as qe,aT as Fe,aR as We,aw as Ge,b1 as Ue,P as Xe,af as $e,b2 as Ze}from"./index-CtyZ6W6U.js";import{i as Ke}from"./index-DQkUn08L.js";const Q=`<!DOCTYPE html>
2<html lang="en">
3<head>
4<title>Embed Row & Masonry Builder</title>
5<meta name="viewport" content="width=device-width, initial-scale=1" />
6<link rel="preconnect" href="https://fonts.googleapis.com">
7<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
8<link href="https://fonts.googleapis.com/css2?family=IBM+Plex+Sans:wght@400;500;600;700&family=IBM+Plex+Mono:wght@400;500;600&display=swap" rel="stylesheet">
9
10<style>
11  :root {
12    --paper: #f3f4f1;
13    --paper-raised: #ffffff;
14    --ink: #14171a;
15    --ink-soft: #5b6066;
16    --ink-faint: #8b9096;
17    --line: #d9dbd4;
18    --line-strong: #c2c5bd;
19    --accent: #2f6fed;
20    --accent-ink: #ffffff;
21    --accent-soft: #e4ecfd;
22    --success: #1f8f5f;
23    --success-soft: #e2f4ea;
24    --code-bg: #0f1216;
25    --code-ink: #d9dee5;
26    --code-line: #262b32;
27    --code-accent: #7fb0ff;
28    --shadow: 0 1px 2px rgba(20, 23, 26, 0.04), 0 8px 24px -12px rgba(20, 23, 26, 0.12);
29    --radius: 10px;
30  }
31
32  @media (prefers-color-scheme: dark) {
33    :root:not([data-theme="light"]) {
34      --paper: #15171a;
35      --paper-raised: #1d2024;
36      --ink: #edeeea;
37      --ink-soft: #a3a8ad;
38      --ink-faint: #6b7176;
39      --line: #2c2f34;
40      --line-strong: #3b3f45;
41      --accent: #6c98ff;
42      --accent-ink: #0f1115;
43      --accent-soft: #212a3b;
44      --success: #4fbf8f;
45      --success-soft: #16261f;
46      --code-bg: #0a0c0e;
47      --code-ink: #dbe1e7;
48      --code-line: #22262b;
49      --code-accent: #8cbaff;
50      --shadow: 0 1px 2px rgba(0, 0, 0, 0.3), 0 8px 24px -12px rgba(0, 0, 0, 0.5);
51    }
52  }
53
54  :root[data-theme="dark"] {
55    --paper: #15171a;
56    --paper-raised: #1d2024;
57    --ink: #edeeea;
58    --ink-soft: #a3a8ad;
59    --ink-faint: #6b7176;
60    --line: #2c2f34;
61    --line-strong: #3b3f45;
62    --accent: #6c98ff;
63    --accent-ink: #0f1115;
64    --accent-soft: #212a3b;
65    --success: #4fbf8f;
66    --success-soft: #16261f;
67    --code-bg: #0a0c0e;
68    --code-ink: #dbe1e7;
69    --code-line: #22262b;
70    --code-accent: #8cbaff;
71    --shadow: 0 1px 2px rgba(0, 0, 0, 0.3), 0 8px 24px -12px rgba(0, 0, 0, 0.5);
72  }
73
74  * { box-sizing: border-box; }
75
76  body {
77    margin: 0;
78    background: var(--paper);
79    color: var(--ink);
80    font-family: "IBM Plex Sans", ui-sans-serif, system-ui, sans-serif;
81    -webkit-font-smoothing: antialiased;
82    min-height: 100vh;
83  }
84
85  .wrap {
86    max-width: 1180px;
87    margin: 0 auto;
88    padding: 32px 20px 70px;
89  }
90
91  header.top {
92    display: flex;
93    justify-content: space-between;
94    align-items: flex-start;
95    gap: 20px;
96    margin-bottom: 40px;
97  }
98
99  .brand-mark {
100    display: flex;
101    align-items: center;
102    gap: 12px;
103  }
104
105  .brand-mark .glyph {
106    display: flex;
107    gap: 3px;
108    flex-shrink: 0;
109  }
110
111  .brand-mark .glyph span {
112    width: 7px;
113    height: 26px;
114    border-radius: 2px;
115    background: var(--accent);
116  }
117  .brand-mark .glyph span:nth-child(1) { opacity: 0.45; }
118  .brand-mark .glyph span:nth-child(2) { opacity: 0.75; }
119  .brand-mark .glyph span:nth-child(3) { opacity: 1; }
120
121  h1 {
122    font-size: 22px;
123    font-weight: 600;
124    letter-spacing: -0.01em;
125    margin: 0 0 4px;
126    text-wrap: balance;
127  }
128
129  .subtitle {
130    margin: 0;
131    color: var(--ink-soft);
132    font-size: 14.5px;
133    max-width: 46ch;
134    line-height: 1.5;
135  }
136
137  .theme-toggle {
138    border: 1px solid var(--line-strong);
139    background: var(--paper-raised);
140    color: var(--ink-soft);
141    width: 38px;
142    height: 38px;
143    border-radius: 9px;
144    display: flex;
145    align-items: center;
146    justify-content: center;
147    cursor: pointer;
148    flex-shrink: 0;
149    font-size: 16px;
150    transition: border-color 0.15s ease, color 0.15s ease;
151  }
152  .theme-toggle:hover { border-color: var(--accent); color: var(--accent); }
153  .theme-toggle:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
154
155  section { margin-bottom: 36px; }
156
157  .section-label {
158    display: flex;
159    align-items: center;
160    justify-content: space-between;
161    gap: 12px;
162    margin-bottom: 12px;
163  }
164
165  .eyebrow {
166    font-family: "IBM Plex Mono", ui-monospace, monospace;
167    font-size: 11.5px;
168    letter-spacing: 0.08em;
169    text-transform: uppercase;
170    color: var(--ink-faint);
171  }
172
173  .slots {
174    display: grid;
175    grid-template-columns: repeat(4, minmax(0, 1fr));
176    gap: 14px;
177  }
178
179  @media (max-width: 1080px) {
180    .slots {
181      grid-template-columns: repeat(2, minmax(0, 1fr));
182    }
183  }
184
185  @media (max-width: 580px) {
186    .slots {
187      grid-template-columns: 1fr;
188    }
189  }
190
191  .slot-card {
192    background: var(--paper-raised);
193    border: 1px solid var(--line);
194    border-radius: var(--radius);
195    box-shadow: var(--shadow);
196    display: flex;
197    flex-direction: column;
198    overflow: hidden;
199    min-width: 0;
200    position: relative;
201    transition: transform 0.18s cubic-bezier(0.16, 1, 0.3, 1),
202                box-shadow 0.18s ease,
203                opacity 0.18s ease,
204                border-color 0.18s ease;
205  }
206
207  .slot-card.is-dragging {
208    opacity: 0.55;
209    cursor: grabbing !important;
210  }
211
212  .slot-card.is-drag-placeholder {
213    opacity: 0.35;
214    border-style: dashed;
215    border-color: var(--accent);
216    box-shadow: none;
217  }
218
219  .slot-drag-ghost {
220    position: fixed;
221    pointer-events: none;
222    z-index: 999999;
223    opacity: 0.92;
224    transform: rotate(2deg) scale(1.03);
225    box-shadow: 0 22px 48px -12px rgba(20, 23, 26, 0.32), 0 6px 14px -4px rgba(20, 23, 26, 0.18);
226    border-radius: var(--radius);
227    transition: none;
228    will-change: transform;
229    overflow: hidden;
230  }
231  .slot-drag-ghost .slot-input {
232    color: transparent !important;
233    background: transparent !important;
234  }
235  .slot-drag-ghost .slot-input::placeholder {
236    color: transparent !important;
237  }
238
239  .slot-drop-indicator {
240    position: absolute;
241    top: 0;
242    bottom: 0;
243    width: 3px;
244    background: var(--accent);
245    border-radius: 2px;
246    pointer-events: none;
247    z-index: 5;
248    box-shadow: 0 0 0 2px var(--accent-soft);
249    animation: pulseIndicator 1.2s ease-in-out infinite;
250  }
251
252  .slot-drop-indicator.indicator-left { left: -8px; }
253  .slot-drop-indicator.indicator-right { right: -8px; }
254
255  @keyframes pulseIndicator {
256    0%, 100% { opacity: 1; }
257    50% { opacity: 0.6; }
258  }
259
260  .slot-head {
261    display: flex;
262    align-items: center;
263    gap: 8px;
264    padding: 9px 12px;
265    border-bottom: 1px solid var(--line);
266  }
267
268  .slot-drag-handle {
269    cursor: grab;
270    color: var(--ink-faint);
271    font-size: 14px;
272    line-height: 1;
273    padding: 3px 4px;
274    user-select: none;
275    -webkit-user-select: none;
276    flex-shrink: 0;
277    transition: color 0.15s ease, background 0.15s ease;
278    display: flex;
279    align-items: center;
280    justify-content: center;
281    border-radius: 4px;
282    touch-action: none;
283  }
284  .slot-drag-handle:hover {
285    color: var(--accent);
286    background: var(--accent-soft);
287  }
288  .slot-drag-handle:active { cursor: grabbing; }
289
290  .slot-num {
291    font-family: "IBM Plex Mono", ui-monospace, monospace;
292    font-size: 11.5px;
293    font-weight: 600;
294    color: var(--accent-ink);
295    background: var(--accent);
296    width: 20px;
297    height: 20px;
298    border-radius: 5px;
299    display: flex;
300    align-items: center;
301    justify-content: center;
302    flex-shrink: 0;
303  }
304
305  .slot-title {
306    font-size: 12.5px;
307    font-weight: 600;
308    white-space: nowrap;
309    overflow: hidden;
310    text-overflow: ellipsis;
311  }
312
313  .slot-status {
314    margin-left: auto;
315    font-size: 10.5px;
316    font-family: "IBM Plex Mono", ui-monospace, monospace;
317    color: var(--ink-faint);
318  }
319  .slot-status.filled { color: var(--success); }
320
321  .remove-slot-btn {
322    border: none;
323    background: transparent;
324    color: var(--ink-faint);
325    cursor: pointer;
326    font-size: 15px;
327    line-height: 1;
328    padding: 2px 4px;
329    border-radius: 4px;
330    margin-left: 2px;
331    transition: color 0.15s ease, background 0.15s ease;
332  }
333  .remove-slot-btn:hover {
334    color: #e5484d;
335    background: rgba(229, 72, 77, 0.12);
336  }
337
338  textarea.slot-input {
339    border: none;
340    resize: vertical;
341    min-height: 110px;
342    padding: 10px 12px;
343    font-family: "IBM Plex Mono", ui-monospace, monospace;
344    font-size: 11.5px;
345    line-height: 1.5;
346    color: var(--ink);
347    background: transparent;
348    width: 100%;
349    box-sizing: border-box;
350  }
351  textarea.slot-input::placeholder { color: var(--ink-faint); }
352  textarea.slot-input:focus {
353    outline: none;
354    background: var(--accent-soft);
355  }
356
357  .controls-row {
358    display: flex;
359    align-items: center;
360    justify-content: space-between;
361    flex-wrap: wrap;
362    gap: 16px;
363  }
364
365  .gap-control {
366    display: inline-flex;
367    background: var(--paper-raised);
368    border: 1px solid var(--line);
369    border-radius: 8px;
370    padding: 3px;
371    gap: 2px;
372  }
373
374  .gap-control button {
375    border: none;
376    background: transparent;
377    color: var(--ink-soft);
378    font-family: "IBM Plex Sans", sans-serif;
379    font-size: 12.5px;
380    font-weight: 500;
381    padding: 7px 12px;
382    border-radius: 6px;
383    cursor: pointer;
384    transition: background 0.15s ease, color 0.15s ease;
385  }
386  .gap-control button:hover { color: var(--ink); }
387  .gap-control button[aria-pressed="true"] {
388    background: var(--accent);
389    color: var(--accent-ink);
390  }
391  .gap-control button:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
392
393  .masonry-controls-panel {
394    margin-top: 14px;
395    padding: 16px 18px;
396    background: var(--paper-raised);
397    border: 1px solid var(--line);
398    border-radius: var(--radius);
399    box-shadow: var(--shadow);
400    display: flex;
401    flex-direction: column;
402    gap: 14px;
403    animation: fadeInPanel 0.18s ease;
404  }
405
406  @keyframes fadeInPanel {
407    from { opacity: 0; transform: translateY(-4px); }
408    to { opacity: 1; transform: translateY(0); }
409  }
410
411  .masonry-controls-header {
412    display: flex;
413    align-items: center;
414    justify-content: space-between;
415    flex-wrap: wrap;
416    gap: 10px;
417    padding-bottom: 12px;
418    border-bottom: 1px solid var(--line);
419  }
420
421  .masonry-panel-badge {
422    display: inline-flex;
423    align-items: center;
424    gap: 8px;
425    font-size: 13.5px;
426    font-weight: 600;
427    color: var(--ink);
428  }
429  .masonry-panel-badge svg {
430    color: var(--accent);
431  }
432
433  .masonry-panel-hint {
434    font-size: 11.5px;
435    color: var(--ink-faint);
436  }
437
438  .masonry-presets-bar {
439    display: flex;
440    align-items: center;
441    flex-wrap: wrap;
442    gap: 8px;
443    padding: 10px 12px;
444    background: var(--paper);
445    border: 1px solid var(--line);
446    border-radius: 8px;
447  }
448
449  .masonry-presets-label {
450    font-size: 11px;
451    font-family: "IBM Plex Mono", monospace;
452    font-weight: 600;
453    text-transform: uppercase;
454    letter-spacing: 0.06em;
455    color: var(--ink-soft);
456    margin-right: 4px;
457  }
458
459  .masonry-preset-pill {
460    font-family: "IBM Plex Sans", sans-serif;
461    font-size: 12px;
462    font-weight: 600;
463    padding: 5px 11px;
464    border-radius: 6px;
465    border: 1px solid var(--line);
466    background: var(--paper-raised);
467    color: var(--ink-soft);
468    cursor: pointer;
469    transition: all 0.15s ease;
470    display: inline-flex;
471    align-items: center;
472    gap: 5px;
473  }
474  .masonry-preset-pill:hover {
475    border-color: var(--accent);
476    color: var(--ink);
477    transform: translateY(-1px);
478  }
479  .masonry-preset-pill[data-active="true"] {
480    background: var(--accent-soft);
481    border-color: var(--accent);
482    color: var(--accent);
483    font-weight: 700;
484  }
485
486  .masonry-controls-grid {
487    display: grid;
488    grid-template-columns: repeat(auto-fit, minmax(210px, 1fr));
489    gap: 14px;
490    align-items: start;
491  }
492
493  .masonry-control-group {
494    display: flex;
495    flex-direction: column;
496    gap: 6px;
497  }
498
499  .masonry-control-group .gap-control {
500    flex-wrap: wrap;
501  }
502
503  .action-buttons {
504    display: flex;
505    align-items: center;
506    gap: 14px;
507  }
508
509  button.btn {
510    font-family: "IBM Plex Sans", sans-serif;
511    font-size: 14px;
512    font-weight: 700;
513    border-radius: 10px;
514    padding: 10px 20px;
515    cursor: pointer;
516    border: none;
517    transition: background 0.15s ease, opacity 0.15s ease, transform 0.05s ease;
518    display: inline-flex;
519    align-items: center;
520    gap: 8px;
521    line-height: 1.2;
522  }
523  button.btn:active { transform: translateY(1px); }
524  button.btn:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
525
526  .btn-text {
527    background: transparent;
528    color: var(--ink);
529    font-weight: 600;
530    padding: 10px 12px;
531  }
532  .btn-text:hover { color: var(--accent); opacity: 0.85; }
533
534  .btn-primary {
535    background: #2b6bf3;
536    color: #ffffff;
537  }
538  .btn-primary:hover { background: #1e59e0; }
539
540  .btn-convo {
541    background: #00a66c;
542    color: #ffffff;
543  }
544  .btn-convo:hover { background: #008f5d; }
545  .btn-convo:disabled { opacity: 0.65;
545 cursor: not-allowed; }
546
547  .add-slot-bottom-wrap {
548    margin-top: 14px;
549    display: flex;
550    align-items: center;
551    justify-content: flex-start;
552  }
553
554  .btn-add-slot-bottom {
555    font-family: "IBM Plex Sans", -apple-system, sans-serif;
556    font-size: 13px;
557    font-weight: 600;
558    color: var(--ink);
559    background: var(--paper-raised);
560    border: 1px dashed var(--line-strong);
561    border-radius: 8px;
562    padding: 8px 16px;
563    cursor: pointer;
564    display: inline-flex;
565    align-items: center;
566    gap: 7px;
567    box-shadow: 0 1px 3px rgba(0, 0, 0, 0.04);
568    transition: all 0.15s ease;
569  }
570  .btn-add-slot-bottom:hover {
571    border-color: var(--accent);
572    color: var(--accent);
573    background: var(--accent-soft);
574    transform: translateY(-1px);
575    box-shadow: 0 2px 6px rgba(0, 0, 0, 0.06);
576  }
577  .btn-add-slot-bottom:active {
578    transform: translateY(0);
579  }
580
581  @keyframes spin {
582    from { transform: rotate(0deg); }
583    to { transform: rotate(360deg); }
584  }
585
586  .stage {
587    background: var(--paper-raised);
588    border: 1px solid var(--line);
589    border-radius: var(--radius);
590    box-shadow: var(--shadow);
591    padding: 20px;
592    overflow-x: auto;
593    overflow-y: auto;
594    max-height: 80vh;
595    -webkit-overflow-scrolling: touch;
596  }
597
598  .stage-row {
599    display: grid;
600    align-items: start;
601    min-width: min-content;
602    width: 100%;
603  }
604
605  .stage-row.is-single-embed,
606  .stage-row:has(> .stage-cell:only-child) {
607    max-width: 640px !important;
608    width: 100% !important;
609    margin: 0 auto !important;
610    min-width: 0 !important;
611    grid-template-columns: 1fr !important;
612  }
613
614  .masonry-preview {
615    display: flex;
616    flex-direction: row;
617    align-items: flex-start;
618    width: 100%;
619    overflow-x: auto;
620    -webkit-overflow-scrolling: touch;
621  }
622
623  .masonry-preview.is-single-embed {
624    max-width: 640px !important;
625    width: 100% !important;
626    margin: 0 auto !important;
627    min-width: 0 !important;
628  }
629
630  .masonry-preview-col {
631    flex: 1 1 0;
632    display: flex;
633    flex-direction: column;
634    min-width: 0;
635  }
636
637  .masonry-stage-cell {
638    display: flex !important;
639    flex-direction: column !important;
640    align-items: stretch !important;
641    justify-content: stretch !important;
642    width: 100% !important;
643    box-sizing: border-box !important;
644    vertical-align: top;
645    transition: transform 0.2s cubic-bezier(0.16, 1, 0.3, 1), box-shadow 0.2s cubic-bezier(0.16, 1, 0.3, 1), border-color 0.2s ease;
646  }
647
648  .masonry-stage-cell[data-mstyle="card"] {
649    background: var(--paper-raised);
650    border: 1px solid var(--line);
651    box-shadow: 0 4px 14px -2px rgba(0, 0, 0, 0.05), 0 2px 6px -1px rgba(0, 0, 0, 0.02);
652  }
653
654  .masonry-stage-cell[data-mstyle="minimal"] {
655    background: transparent;
656    border: 1px dashed var(--line);
657    box-shadow: none;
658  }
659
660  .masonry-stage-cell[data-mstyle="outline"] {
661    background: var(--paper-raised);
662    border: 1px solid var(--line-strong);
663    box-shadow: none;
664  }
665
666  .masonry-stage-cell[data-mstyle="glass"] {
667    background: rgba(255, 255, 255, 0.65);
668    backdrop-filter: blur(12px);
669    -webkit-backdrop-filter: blur(12px);
670    border: 1px solid rgba(255, 255, 255, 0.45);
671    box-shadow: 0 8px 24px 0 rgba(0, 0, 0, 0.06);
672  }
673
674  .masonry-stage-cell[data-mhover="lift"]:hover {
675    transform: translateY(-3px);
676    box-shadow: 0 10px 24px -4px rgba(0, 0, 0, 0.1), 0 4px 8px -2px rgba(0, 0, 0, 0.04);
677  }
678
679  .masonry-stage-cell[data-mhover="glow"]:hover {
680    border-color: var(--accent);
681    box-shadow: 0 0 0 3px var(--accent-soft), 0 4px 12px rgba(0, 0, 0, 0.06);
682  }
683
684  .masonry-slot-badge {
685    position: absolute;
686    top: 6px;
687    right: 6px;
688    font-family: "IBM Plex Mono", monospace;
689    font-size: 10px;
690    font-weight: 600;
691    padding: 2px 6px;
692    border-radius: 4px;
693    background: var(--accent);
694    color: var(--accent-ink);
695    opacity: 0.85;
696    pointer-events: none;
697    z-index: 2;
698  }
699
700  @media (max-width: 760px) {
701    .stage-row { grid-template-columns: repeat(auto-fit, minmax(260px, 1fr)) !important; }
702    .stage-row.is-single-embed,
703    .stage-row:has(> .stage-cell:only-child),
704    .masonry-preview.is-single-embed {
705      max-width: 100% !important;
706    }
707    .masonry-preview { flex-direction: column !important; }
708    .masonry-preview-col { width: 100% !important; }
709  }
710
711  .stage-cell {
712    min-width: 240px;
713    box-sizing: border-box;
714    border-radius: 12px;
715    background: var(--paper-raised);
716    border: 1px solid var(--line);
717    box-shadow: 0 2px 10px -2px rgba(0, 0, 0, 0.05);
718    padding: 10px;
719    display: flex; flex-direction: column;
720    transition: box-shadow 0.15s ease;
721    resize: both;
722    overflow: auto;
723    max-width: 100%;
724    min-height: 180px;
725    height: auto;
726    position: relative;
727  }
728  .stage-cell:hover {
729    box-shadow: 0 6px 18px -4px rgba(0, 0, 0, 0.08);
730  }
731
732  .stage-cell.is-resizing iframe,
733  .carousel-viewport.is-resizing iframe {
734    pointer-events: none !important;
735  }
736
737  .stage-cell iframe {
738    width: 100%;
739    min-width: 0;
740    min-height: 0;
741    flex: 1 1 auto;
742    height: 100%;
743    border: 1px dashed var(--line-strong);
744    border-radius: 8px;
745    background: var(--paper);
746    overflow: auto;
747    display: block;
748    box-sizing: border-box;
749  }
750
751  .stage-empty {
752    min-height: 120px;
753    height: 100%;
754    flex: 1;
755    min-width: 220px;
756    border: 1px dashed var(--line-strong);
757    border-radius: 8px;
758    display: flex;
759    align-items: center;
760    justify-content: center;
761    text-align: center;
762    padding: 16px;
763    color: var(--ink-faint);
764    font-size: 12.5px;
765    line-height: 1.5;
766    box-sizing: border-box;
767  }
768
769  .carousel-preview {
770    display: flex;
771    flex-direction: column;
772    gap: 14px;
773    width: 100%;
774    max-width: 640px;
775    margin: 0 auto;
776    box-sizing: border-box;
777  }
778
779  .carousel-controls {
780    order: -1;
781    display: flex;
782    align-items: center;
783    justify-content: center;
784    gap: 12px;
785    margin: 0 auto 4px auto;
786    padding: 5px 14px;
787    background: var(--paper);
788    border: 1px solid var(--line);
789    border-radius: 9999px;
790    box-shadow: 0 1px 3px rgba(0, 0, 0, 0.04);
791  }
792
793  .carousel-viewport {
794    order: 1;
795    position: relative;
796    border: 1px solid var(--line);
797    border-radius: 12px;
798    background: #ffffff;
799    overflow: auto;
800    resize: both;
801    box-shadow: 0 4px 16px -2px rgba(0, 0, 0, 0.06), 0 2px 6px -1px rgba(0, 0, 0, 0.03);
802    width: 100%;
803    min-width: 280px;
804    min-height: 180px;
805    height: auto;
806    display: flex;
807    flex-direction: column;
808    align-items: stretch;
809    justify-content: stretch;
810  }
811
812  .carousel-viewport iframe {
813    width: 100%;
814    height: 100%;
815    min-height: 0;
816    flex: 1 1 auto;
817    border: none;
818    display: block;
819    background: #ffffff;
820  }
821
822  .carousel-arrow {
823    width: 34px;
824    height: 34px;
825    border-radius: 50%;
826    border: 1px solid var(--line-strong);
827    background: var(--paper-raised);
828    color: var(--ink);
829    cursor: pointer;
830    font-size: 18px;
831    font-weight: 600;
832    line-height: 1;
833    display: flex;
834    align-items: center;
835    justify-content: center;
836    box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05);
837    transition: all 0.15s ease;
838  }
839  .carousel-arrow:hover:not(:disabled) {
840    border-color: var(--accent);
841    color: #ffffff;
842    background: var(--accent);
843    transform: translateY(-1px);
844    box-shadow: 0 4px 10px rgba(47, 111, 237, 0.25);
845  }
846  .carousel-arrow:active:not(:disabled) {
847    transform: translateY(0px) scale(0.95);
848  }
849  .carousel-arrow:disabled { opacity: 0.35; cursor: not-allowed; }
850  .carousel-arrow:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
851
852  .carousel-dots { display: flex; align-items: center; gap: 7px; padding: 0 4px; }
853  .carousel-dots button {
854    width: 8px;
855    height: 8px;
856    border-radius: 50%;
857    border: none;
858    background: var(--line-strong);
859    padding: 0;
860    cursor: pointer;
861    transition: all 0.2s cubic-bezier(0.16, 1, 0.3, 1);
862  }
863  .carousel-dots button.is-active {
864    background: var(--accent);
865    width: 22px;
866    border-radius: 9999px;
867  }
868  .carousel-dots button:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
869
870  .carousel-counter {
871    text-align: center;
872    font-family: "IBM Plex Mono", ui-monospace, monospace;
873    font-size: 12px;
874    color: var(--ink-faint);
875  }
876
877  .code-panel {
878    background: var(--code-bg);
879    border-radius: var(--radius);
880    border: 1px solid var(--code-line);
881    overflow: hidden;
882  }
883
884  .code-panel-head {
885    display: flex;
886    align-items: center;
887    justify-content: space-between;
888    padding: 10px 14px;
889    border-bottom: 1px solid var(--code-line);
890  }
891
892  .code-panel-head .dots { display: flex; gap: 6px; }
893  .code-panel-head .dots span {
894    width: 9px; height: 9px; border-radius: 50%;
895    background: var(--code-line);
896  }
897
898  .copy-btn {
899    font-family: "IBM Plex Mono", ui-monospace, monospace;
900    font-size: 12px;
901    font-weight: 500;
902    color: var(--code-ink);
903    background: transparent;
904    border: 1px solid var(--code-line);
905    border-radius: 6px;
906    padding: 6px 12px;
907    cursor: pointer;
908    display: inline-flex;
909    align-items: center;
910    gap: 6px;
911    transition: border-color 0.15s ease, color 0.15s ease;
912  }
913  .copy-btn:hover { border-color: var(--code-accent); color: var(--code-accent); }
914  .copy-btn:focus-visible { outline: 2px solid var(--code-accent); outline-offset: 2px; }
915  .copy-btn.copied { color: var(--success); border-color: var(--success); }
916
917  pre.code-out {
918    margin: 0;
919    padding: 16px;
920    overflow-x: auto;
921    font-family: "IBM Plex Mono", ui-monospace, monospace;
922    font-size: 12.5px;
923    line-height: 1.6;
924    color: var(--code-ink);
925    tab-size: 2;
926    white-space: pre;
927  }
928
929  footer.hint {
930    margin-top: 44px;
931    padding-top: 20px;
932    border-top: 1px solid var(--line);
933    color: var(--ink-faint);
934    font-size: 12.5px;
935    line-height: 1.6;
936  }
937
938  @media (prefers-reduced-motion: reduce) {
939    * { transition: none !important; }
940  }
941</style>
942</head>
943<body>
944
945<div class="wrap">
946  <header class="top">
947    <div class="brand-mark">
948      <div class="glyph"><span></span><span></span><span></span></div>
949      <div>
950        <h1>Embed Row & Masonry Builder</h1>
951        <p class="subtitle">Paste embed snippets, preview them together, and generate complete HTML files for Row, Carousel, or Masonry layouts (Max 4 columns per row). Drag the â ¿ handle to reorder slots.</p>
952      </div>
953    </div>
954    <button class="theme-toggle" id="themeToggle" type="button" aria-label="Toggle color theme" title="Toggle color theme">◐</button>
955  </header>
956
957  <section>
958    <div class="section-label">
959      <span class="eyebrow">Slots — left to right order (drag to reorder)</span>
960      <button class="btn btn-text" id="addSlotBtn" type="button" style="padding: 5px 12px; font-size: 12px;">+ Add on top slot</button>
961    </div>
962    <div class="slots" id="slotsContainer"></div>
963    <div class="add-slot-bottom-wrap">
964      <button class="btn-add-slot-bottom" id="addSlotBtnBottom" type="button">
965        <svg width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round">
966          <line x1="12" y1="5" x2="12" y2="19"></line>
967          <line x1="5" y1="12" x2="19" y2="12"></line>
968        </svg>
969        <span>Add on bottom slot</span>
970      </button>
971    </div>
972  </section>
973
974  <section>
975    <div class="controls-row">
976      <div style="display:flex; gap:24px; flex-wrap:wrap;">
977        <div>
978          <div class="eyebrow" style="margin-bottom:8px;">Layout</div>
979          <div class="gap-control" id="modeControl" role="group" aria-label="Layout">
980            <button type="button" data-mode="row" aria-pressed="true">Row</button>
981            <button type="button" data-mode="carousel" aria-pressed="false">Carousel</button>
982            <button type="button" data-mode="masonry" aria-pressed="false">Masonry</button>
983          </div>
984        </div>
985        <div id="gapControlWrap">
986          <div class="eyebrow" style="margin-bottom:8px;">Spacing between embeds</div>
987          <div class="gap-control" role="group" aria-label="Spacing between embeds">
988            <button type="button" data-gap="8" aria-pressed="false">Compact</button>
989            <button type="button" data-gap="24" aria-pressed="true">Comfortable</button>
990            <button type="button" data-gap="40" aria-pressed="false">Spacious</button>
991          </div>
992        </div>
993      </div>
994
995      <div class="action-buttons">
996        <button class="btn btn-text" id="resetBtn" type="button">Clear all</button>
997        <button class="btn btn-primary" id="generateBtn" type="button">Generate HTML</button>
998        <button class="btn btn-convo" id="convoBtn" type="button">
999          <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round">
1000            <path d="M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z"></path>
1001          </svg>
1002          <span id="convoBtnLabel">Convo</span>
1003        </button>
1004      </div>
1005    </div>
1006
1007    <div class="masonry-controls-panel" id="masonryControlsPanel" style="display:none;">
1008      <div class="masonry-controls-header">
1009        <div class="masonry-panel-badge">
1010          <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round">
1011            <rect x="3" y="3" width="7" height="9" rx="1"></rect>
1012            <rect x="14" y="3" width="7" height="5" rx="1"></rect>
1013            <rect x="14" y="12" width="7" height="9" rx="1"></rect>
1014            <rect x="3" y="16" width="7" height="5" rx="1"></rect>
1015          </svg>
1016          <span>Masonry Layout & Card Customizer</span>
1017        </div>
1018        <span class="masonry-panel-hint">Configure grid columns, spacing, card surfaces, and responsive breakpoints</span>
1019      </div>
1020
1021      <div class="masonry-presets-bar">
1022        <span class="masonry-presets-label">⚡ Presets:</span>
1023        <button type="button" class="masonry-preset-pill" data-preset="default" data-active="true">🎨 Default Cards</button>
1024        <button type="button" class="masonry-preset-pill" data-preset="fullbleed" data-active="false">🖼️ Full-Bleed Media</button>
1025        <button type="button" class="masonry-preset-pill" data-preset="bento" data-active="false">🗂️ Bento Board</button>
1026        <button type="button" class="masonry-preset-pill" data-preset="social" data-active="false">📱 Social Feed</button>
1027        <button type="button" class="masonry-preset-pill" data-preset="minimal" data-active="false">✨ Clean Minimal</button>
1028      </div>
1029
1030      <div class="masonry-controls-grid">
1031        <div class="masonry-control-group">
1032          <div class="eyebrow" style="margin-bottom:6px;">Grid Columns</div>
1033          <div class="gap-control" id="masonryColsControl" role="group" aria-label="Masonry Columns">
1034            <button type="button" data-mcols="auto" aria-pressed="true">Auto</button>
1035            <button type="button" data-mcols="1" aria-pressed="false">1 Col</button>
1036            <button type="button" data-mcols="2" aria-pressed="false">2 Cols</button>
1037            <button type="button" data-mcols="3" aria-pressed="false">3 Cols</button>
1038            <button type="button" data-mcols="4" aria-pressed="false">4 Cols</button>
1039            <button type="button" data-mcols="5" aria-pressed="false">5 Cols</button>
1040          </div>
1041        </div>
1042
1043        <div class="masonry-control-group">
1044          <div class="eyebrow" style="margin-bottom:6px;">
1044Column & Gutter Spacing</div>
1045          <div class="gap-control" id="masonryGapControl" role="group" aria-label="Masonry Spacing">
1046            <button type="button" data-mgap="0" aria-pressed="false">0px (Seamless)</button>
1047            <button type="button" data-mgap="8" aria-pressed="false">8px</button>
1048            <button type="button" data-mgap="16" aria-pressed="false">16px</button>
1049            <button type="button" data-mgap="24" aria-pressed="true">24px</button>
1050            <button type="button" data-mgap="36" aria-pressed="false">36px</button>
1051            <button type="button" data-mgap="48" aria-pressed="false">48px</button>
1052          </div>
1053        </div>
1054
1055        <div class="masonry-control-group">
1056          <div class="eyebrow" style="margin-bottom:6px;">Card Padding</div>
1057          <div class="gap-control" id="masonryPaddingControl" role="group" aria-label="Item Card Padding">
1058            <button type="button" data-mpadding="0" aria-pressed="false">0px (Flush)</button>
1059            <button type="button" data-mpadding="6" aria-pressed="false">6px</button>
1060            <button type="button" data-mpadding="12" aria-pressed="true">12px</button>
1061            <button type="button" data-mpadding="18" aria-pressed="false">18px</button>
1062            <button type="button" data-mpadding="24" aria-pressed="false">24px</button>
1063          </div>
1064        </div>
1065
1066        <div class="masonry-control-group">
1067          <div class="eyebrow" style="margin-bottom:6px;">Corner Radius</div>
1068          <div class="gap-control" id="masonryRadiusControl" role="group" aria-label="Item Card Corners">
1069            <button type="button" data-mradius="0" aria-pressed="false">0px (Sharp)</button>
1070            <button type="button" data-mradius="6" aria-pressed="false">6px (Subtle)</button>
1071            <button type="button" data-mradius="12" aria-pressed="true">12px (Smooth)</button>
1072            <button type="button" data-mradius="18" aria-pressed="false">18px (Modern)</button>
1073            <button type="button" data-mradius="26" aria-pressed="false">26px (Pill)</button>
1074          </div>
1075        </div>
1076
1077        <div class="masonry-control-group">
1078          <div class="eyebrow" style="margin-bottom:6px;">Card Surface</div>
1079          <div class="gap-control" id="masonryStyleControl" role="group" aria-label="Card Surface Style">
1080            <button type="button" data-mstyle="card" aria-pressed="true">Elevated Card</button>
1081            <button type="button" data-mstyle="minimal" aria-pressed="false">Minimal (No Card)</button>
1082            <button type="button" data-mstyle="outline" aria-pressed="false">Outline Only</button>
1083            <button type="button" data-mstyle="glass" aria-pressed="false">Frosted Glass</button>
1084          </div>
1085        </div>
1086
1087        <div class="masonry-control-group">
1088          <div class="eyebrow" style="margin-bottom:6px;">Hover Interaction</div>
1089          <div class="gap-control" id="masonryHoverControl" role="group" aria-label="Hover Interaction">
1090            <button type="button" data-mhover="lift" aria-pressed="true">✨ 3D Lift</button>
1091            <button type="button" data-mhover="glow" aria-pressed="false">🌟 Glow</button>
1092            <button type="button" data-mhover="none" aria-pressed="false">Static</button>
1093          </div>
1094        </div>
1095      </div>
1096    </div>
1097  </section>
1098
1099  <section>
1100    <div class="section-label">
1101      <span class="eyebrow">Live preview</span>
1102    </div>
1103    <div class="stage">
1104      <div class="stage-row" id="stageRow"></div>
1105    </div>
1106  </section>
1107
1108  <section id="outputSection" style="display:none;">
1109    <div class="section-label">
1110      <span class="eyebrow">Generated HTML</span>
1111      <button class="copy-btn" id="copyBtn" type="button">Copy code</button>
1112    </div>
1113    <div class="code-panel">
1114      <div class="code-panel-head">
1115        <div class="dots"><span></span><span></span><span></span></div>
1116        <span class="eyebrow" id="codeFileLabel" style="color:var(--code-ink); opacity:0.5;">row.html</span>
1117      </div>
1118      <pre class="code-out" id="codeOut"></pre>
1119    </div>
1120  </section>
1121
1122  <footer class="hint">
1123    Generates a complete standalone HTML document. Maximum 4 columns per row with automatic mobile responsiveness.
1124  </footer>
1125</div>
1126
1127<script>
1128(function () {
1129  'use strict';
1130
1131  var STORAGE_KEY = 'embed-row:slots:v5';
1132  var THEME_KEY = 'embed-row:theme:v1';
1133  var slotsContainer = document.getElementById('slotsContainer');
1134  var stageRow = document.getElementById('stageRow');
1135  var codeOut = document.getElementById('codeOut');
1136  var codeFileLabel = document.getElementById('codeFileLabel');
1137  var outputSection = document.getElementById('outputSection');
1138  var gapButtons = Array.prototype.slice.call(document.querySelectorAll('#gapControlWrap .gap-control button'));
1139  var gapControlWrap = document.getElementById('gapControlWrap');
1140  var modeButtons = Array.prototype.slice.call(document.querySelectorAll('#modeControl button'));
1141  var addSlotBtn = document.getElementById('addSlotBtn');
1142  var addSlotBtnBottom = document.getElementById('addSlotBtnBottom');
1143  var currentGap = 24;
1144  var layoutMode = 'row';
1145  var carouselIndex = 0;
1146  var carouselWidth = null;
1147  var carouselHeight = null;
1148  var slotsData = [];
1149  var isEditMode = false;
1150  var editId = null;
1151  var editSlug = null;
1152
1153  var dragState = null;
1154  var DRAG_THRESHOLD = 6;
1155  var DRAG_HOLD_MS = 0;
1156
1157  var MASONRY_CONFIG_KEY = 'embed-row:masonry-cfg:v2';
1158  var masonryCols = 'auto';
1159  var masonryGap = 24;
1160  var masonryPadding = 12;
1161  var masonryRadius = 12;
1162  var masonryStyle = 'card';
1163  var masonryHover = 'lift';
1164  var activePreset = 'default';
1165
1166  var masonryControlsPanel = document.getElementById('masonryControlsPanel');
1167  var masonryColsButtons = Array.prototype.slice.call(document.querySelectorAll('#masonryColsControl button'));
1168  var masonryGapButtons = Array.prototype.slice.call(document.querySelectorAll('#masonryGapControl button'));
1169  var masonryPaddingButtons = Array.prototype.slice.call(document.querySelectorAll('#masonryPaddingControl button'));
1170  var masonryRadiusButtons = Array.prototype.slice.call(document.querySelectorAll('#masonryRadiusControl button'));
1171  var masonryStyleButtons = Array.prototype.slice.call(document.querySelectorAll('#masonryStyleControl button'));
1172  var masonryHoverButtons = Array.prototype.slice.call(document.querySelectorAll('#masonryHoverControl button'));
1173  var masonryPresetButtons = Array.prototype.slice.call(document.querySelectorAll('.masonry-preset-pill'));
1174
1175  var MASONRY_PRESETS = {
1176    default: { cols: 'auto', gap: 24, padding: 12, radius: 12, style: 'card', hover: 'lift' },
1177    fullbleed: { cols: '3', gap: 16, padding: 0, radius: 8, style: 'minimal', hover: 'lift' },
1178    bento: { cols: '4', gap: 8, padding: 8, radius: 6, style: 'outline', hover: 'glow' },
1179    social: { cols: '2', gap: 16, padding: 12, radius: 18, style: 'card', hover: 'lift' },
1180    minimal: { cols: 'auto', gap: 24, padding: 0, radius: 0, style: 'minimal', hover: 'none' }
1181  };
1182
1183  window.addEventListener('message', function (e) {
1184    if (e.data && e.data.type === 'EZ_SET_EDIT_MODE') {
1185      isEditMode = !!e.data.isEdit;
1186      editId = e.data.editId || null;
1187      editSlug = e.data.editSlug || null;
1188      if (e.data.isEdit) {
1189        var labelSpan = document.getElementById('convoBtnLabel');
1190        if (labelSpan) labelSpan.textContent = 'Update';
1191      }
1192      if (e.data.initialHtml && typeof e.data.initialHtml === 'string' && e.data.initialHtml.trim()) {
1193        try {
1194          var parser = new DOMParser();
1195          var doc = parser.parseFromString(e.data.initialHtml, 'text/html');
1196
1197          if (doc.querySelector('.masonry-grid, .masonry-item')) {
1198            var mBtn = document.querySelector('#modeControl button[data-mode="masonry"]');
1199            if (mBtn) mBtn.click();
1200          } else if (doc.querySelector('.ec-track, .ec-slide, .embed-carousel')) {
1201            var cBtn = document.querySelector('#modeControl button[data-mode="carousel"]');
1202            if (cBtn) cBtn.click();
1203          } else {
1204            var rBtn = document.querySelector('#modeControl button[data-mode="row"]');
1205            if (rBtn) rBtn.click();
1206          }
1207
1208          var items = doc.querySelectorAll('.embed-row-item, .masonry-item, .ec-slide');
1209          if (items && items.length > 0) {
1210            slotsContainer.innerHTML = '';
1211            slotsData = [];
1212            items.forEach(function (item) {
1213              var w = null;
1214              var h = null;
1215              if (item.style && item.style.width) {
1216                var pw = parseInt(item.style.width, 10);
1217                if (pw > 0) w = pw;
1218              }
1219              if (item.style && item.style.height) {
1220                var ph = parseInt(item.style.height, 10);
1221                if (ph > 0) h = ph;
1222              }
1223              addSlot(item.innerHTML.trim(), false, w, h);
1224            });
1225            renderPreview();
1226          } else {
1227            var mediaNodes = doc.querySelectorAll('iframe, video, blockquote, twitter-tweet, audio, embed, object');
1228            if (mediaNodes && mediaNodes.length > 0) {
1229              slotsContainer.innerHTML = '';
1230              slotsData = [];
1231              mediaNodes.forEach(function (node) {
1232                addSlot(node.outerHTML.trim(), false);
1233              });
1234              renderPreview();
1235            } else {
1236              var bodyContent = extractBodyContent(e.data.initialHtml);
1237              if (bodyContent && bodyContent.trim().length > 0) {
1238                slotsContainer.innerHTML = '';
1239                slotsData = [];
1240                addSlot(bodyContent.trim(), false);
1241                renderPreview();
1242              }
1243            }
1244          }
1245        } catch (err) {
1246          console.error('Failed to parse initial embed html:', err);
1247        }
1248      }
1249    }
1250  });
1251
1252  window.addEventListener('message', function (e) {
1253    if (e.data && e.data.type === 'EZ_TRIGGER_SAVE') {
1254      var convoBtn = document.getElementById('convoBtn');
1255      if (convoBtn) {
1256        convoBtn.click();
1257      }
1258    }
1259  });
1260
1261  function parseSnippetHeight(code) {
1262    if (!code) return null;
1263    var match = code.match(/height=["']?(d+)(?:px)?["']?/i);
1264    if (match && match[1]) {
1265      var val = parseInt(match[1], 10);
1266      if (val > 50 && val < 2000) return val;
1267    }
1268    var styleMatch = code.match(/heights*:s*(d+)px/i);
1269    if (styleMatch && styleMatch[1]) {
1270      var sVal = parseInt(styleMatch[1], 10);
1271      if (sVal > 50 && sVal < 2000) return sVal;
1272    }
1273    return null;
1274  }
1275
1276  function extractBodyContent(raw) {
1277    if (!raw) return '';
1278    var trimmed = raw.trim();
1279
1280    if (!/<!DOCTYPEs+html/i.test(trimmed) && !/<html[s>]/i.test(trimmed)) {
1281      return trimmed;
1282    }
1283
1284    try {
1285      var parser = new DOMParser();
1286      var doc = parser.parseFromString(trimmed, 'text/html');
1287      return doc.body ? doc.body.innerHTML.trim() : trimmed;
1288    } catch (e) {
1289      return trimmed;
1290    }
1291  }
1292
1293  function updateMasonryButtonsUI() {
1294    masonryColsButtons.forEach(function (b) {
1295      b.setAttribute('aria-pressed', b.getAttribute('data-mcols') === masonryCols ? 'true' : 'false');
1296    });
1297    masonryGapButtons.forEach(function (b) {
1298      b.setAttribute('aria-pressed', parseInt(b.getAttribute('data-mgap'), 10) === masonryGap ? 'true' : 'false');
1299    });
1300    masonryPaddingButtons.forEach(function (b) {
1301      b.setAttribute('aria-pressed', parseInt(b.getAttribute('data-mpadding'), 10) === masonryPadding ? 'true' : 'false');
1302    });
1303    masonryRadiusButtons.forEach(function (b) {
1304      b.setAttribute('aria-pressed', parseInt(b.getAttribute('data-mradius'), 10) === masonryRadius ? 'true' : 'false');
1305    });
1306    masonryStyleButtons.forEach(function (b) {
1307      b.setAttribute('aria-pressed', b.getAttribute('data-mstyle') === masonryStyle ? 'true' : 'false');
1308    });
1309    masonryHoverButtons.forEach(function (b) {
1310      b.setAttribute('aria-pressed', b.getAttribute('data-mhover') === masonryHover ? 'true' : 'false');
1311    });
1312    masonryPresetButtons.forEach(function (b) {
1313      b.setAttribute('data-active', b.getAttribute('data-preset') === activePreset ? 'true' : 'false');
1314    });
1315  }
1316
1317  function applyMasonryPreset(presetKey) {
1318    if (!MASONRY_PRESETS[presetKey]) return;
1319    var p = MASONRY_PRESETS[presetKey];
1320    masonryCols = p.cols;
1321    masonryGap = p.gap;
1322    masonryPadding = p.padding;
1323    masonryRadius = p.radius;
1324    masonryStyle = p.style;
1325    masonryHover = p.hover;
1326    activePreset = presetKey;
1327    updateMasonryButtonsUI();
1328    saveMasonryConfig();
1329    if (layoutMode === 'masonry') {
1330      renderPreview();
1331      if (outputSection.style.display !== 'none') renderCode();
1332    }
1333  }
1334
1335  function saveMasonryConfig() {
1336    try {
1337      localStorage.setItem(MASONRY_CONFIG_KEY, JSON.stringify({
1338        cols: masonryCols,
1339        gap: masonryGap,
1340        padding: masonryPadding,
1341        radius: masonryRadius,
1342        style: masonryStyle,
1343        hover: masonryHover,
1344        preset: activePreset
1345      }));
1346    } catch (e) {}
1347  }
1348
1349  function loadMasonryConfig() {
1350    try {
1351      var raw = localStorage.getItem(MASONRY_CONFIG_KEY);
1352      if (raw) {
1353        var cfg = JSON.parse(raw);
1354        if (cfg.cols) masonryCols = cfg.cols;
1355        if (cfg.gap !== undefined) masonryGap = parseInt(cfg.gap, 10);
1356        if (cfg.padding !== undefined) masonryPadding = parseInt(cfg.padding, 10);
1357        if (cfg.radius !== undefined) masonryRadius = parseInt(cfg.radius, 10);
1358        if (cfg.style) masonryStyle = cfg.style;
1359        if (cfg.hover) masonryHover = cfg.hover;
1360        if (cfg.preset) activePreset = cfg.preset;
1361      }
1362    } catch (e) {}
1363    updateMasonryButtonsUI();
1364  }
1365
1366  var placeholders = [
1367    '<iframe src="https://example.com/widget-1" width="100%" height="220"></iframe>',
1368    '<blockquote class="reviews-widget">…</blockquote>\\n<script src="https://example.com/reviews.js"><' + '/script>',
1369    '<div id="chat-widget" data-id="12345"></div>\\n<script src="https://example.com/chat.js"><' + '/script>',
1370    '<iframe src="https://example.com/widget-4" width="100%" height="220"></iframe>'
1371  ];
1372
1373  function createSlotCard(val, index, customWidth, customHeight) {
1374    var card = document.createElement('div');
1375    card.className = 'slot-card';
1376
1377    var head = document.createElement('div');
1378    head.className = 'slot-head';
1379
1380    var dragHandle = document.createElement('span');
1381    dragHandle.className = 'slot-drag-handle';
1382    dragHandle.textContent = 'â ¿';
1383    dragHandle.title = 'Drag to reorder';
1384
1385    var num = document.createElement('span');
1386    num.className = 'slot-num';
1387    num.textContent = index + 1;
1388
1389    var title = document.createElement('span');
1390    title.className = 'slot-title';
1391    title.textContent = 'Embed ' + (index + 1);
1392
1393    var status = document.createElement('span');
1394    status.className = 'slot-status';
1395    status.textContent = val.trim() ? 'ready' : 'empty';
1396    if (val.trim()) status.classList.add('filled');
1397
1398    var removeBtn = document.createElement('button');
1399    removeBtn.type = 'button';
1400    removeBtn.className = 'remove-slot-btn';
1401    removeBtn.title = 'Remove slot';
1402    removeBtn.textContent = '×';
1403    removeBtn.addEventListener('click', function () {
1404      removeSlot(card);
1405    });
1406
1407    head.appendChild(dragHandle);
1408    head.appendChild(num);
1409    head.appendChild(title);
1410    head.appendChild(status);
1411    head.appendChild(removeBtn);
1412
1413    var input = document.createElement('textarea');
1414    input.className = 'slot-input';
1415    input.spellcheck = false;
1416    input.placeholder = placeholders[index % placeholders.length];
1417    input.value = val;
1418
1419    input.addEventListener('input', onInput);
1420
1421    card.appendChild(head);
1422    card.appendChild(input);
1423
1424    var slotObj = {
1425      card: card,
1426      input: input,
1427      status: status,
1428      num: num,
1429      title: title,
1430      removeBtn: removeBtn,
1431      dragHandle: dragHandle,
1432      customWidth: customWidth || null,
1433      customHeight: customHeight || null
1434    };
1435
1436    attachPointerDrag(slotObj);
1437
1438    return slotObj;
1439  }
1440
1441  function attachPointerDrag(slotObj) {
1442    var handle = slotObj.dragHandle;
1443
1444    handle.addEventListener('pointerdown', function (e) {
1445      if (e.button !== 0 && e.pointerType === 'mouse') return;
1446
1447      var sourceIndex = slotsData.indexOf(slotObj);
1448      if (sourceIndex === -1) return;
1449
1450      e.preventDefault();
1451      try { handle.setPointerCapture(e.pointerId); } catch (err) {}
1452
1453      dragState = {
1454        sourceIndex: sourceIndex,
1455        pointerId: e.pointerId,
1456        startX: e.clientX,
1457        startY: e.clientY,
1458        ghostEl: null,
1459        ghostOffsetX: 0,
1460        ghostOffsetY: 0,
1461        placeholderEl: null,
1462        currentTargetIndex: -1,
1463        currentInsertBefore: true,
1464        started: false
1465      };
1466    });
1467
1468    handle.addEventListener('pointermove', function (e) {
1469      if (!dragState || dragState.pointerId !== e.pointerId) return;
1470
1471      if (!dragState.started) {
1472        var dx = e.clientX - dragState.startX;
1473        var dy = e.clientY - dragState.startY;
1474        if (Math.sqrt(dx * dx + dy * dy) < DRAG_THRESHOLD) return;
1475        beginDrag(e);
1476      }
1477
1478      if (dragState.started) {
1479        e.preventDefault();
1480        updateGhostPosition(e.clientX, e.clientY);
1481        updateDropTarget(e.clientX, e.clientY);
1482      }
1483    });
1484
1485    handle.addEventListener('pointerup', function (e) {
1486      if (!dragState || dragState.pointerId !== e.pointerId) return;
1487      if (dragState.started) {
1488        endDrag(true);
1489      } else {
1490        dragState = null;
1491      }
1492    });
1493
1494    handle.addEventListener('pointercancel', function (e) {
1495      if (!dragState || dragState.pointerId !== e.pointerId) return;
1496      if (dragState.started) {
1497        endDrag(false);
1498      } else {
1499        dragState = null;
1500      }
1501    });
1502
1503    handle.addEventListener('lostpointercapture', function (e) {
1504      if (!dragState || dragState.pointerId !== e.pointerId) return;
1505      if (dragState.started) {
1506        endDrag(false);
1507      } else {
1508        dragState = null;
1509      }
1510    });
1511  }
1512
1513  function beginDrag(e) {
1514    if (!dragState) return;
1515    dragState.started = true;
1516
1517    var sourceSlot = slotsData[dragState.sourceIndex];
1518    if (!sourceSlot) return;
1519
1520    var srcRect = sourceSlot.card.getBoundingClientRect();
1521
1522    var ghost = sourceSlot.card.cloneNode(true);
1523    ghost.classList.add('slot-drag-ghost');
1524    ghost.classList.remove('is-dragging');
1525    ghost.style.width = srcRect.width + 'px';
1526    ghost.style.height = srcRect.height + 'px';
1527    ghost.style.left = '0px';
1528    ghost.style.top = '0px';
1529    document.body.appendChild(ghost);
1530    dragState.ghostEl = ghost;
1531
1532    dragState.ghostOffsetX = e.clientX - srcRect.left;
1533    dragState.ghostOffsetY = e.clientY - srcRect.top;
1534
1535    sourceSlot.card.classList.add('is-drag-placeholder');
1536
1537    document.body.style.userSelect = 'none';
1538    document.body.style.webkitUserSelect = 'none';
1539    document.body.style.cursor = 'grabbing';
1540
1541    updateGhostPosition(e.clientX, e.clientY);
1542  }
1543
1544  function updateGhostPosition(clientX, clientY) {
1545    if (!dragState || !dragState.ghostEl) return;
1546    var gx = clientX - dragState.ghostOffsetX;
1547    var gy = clientY - dragState.ghostOffsetY;
1548    dragState.ghostEl.style.transform = 'translate3d(' + gx + 'px, ' + gy + 'px, 0) rotate(2deg) scale(1.03)';
1549  }
1550
1551  function clearDropIndicators() {
1552    slotsData.forEach(function (o) {
1553      var ind = o.card.querySelector('.slot-drop-indicator');
1554      if (ind && ind.parentNode) ind.parentNode.removeChild(ind);
1555      o.card.classList.remove('is-drag-over');
1556    });
1557  }
1558
1559  function updateDropTarget(clientX, clientY) {
1560    if (!dragState) return;
1561
1562    var targetIndex = -1;
1563    var insertBefore = true;
1564
1565    for (var i = 0; i < slotsData.length; i++) {
1566      var card = slotsData[i].card;
1567      var rect = card.getBoundingClientRect();
1568      if (clientX >= rect.left && clientX <= rect.right &&
1569          clientY >= rect.top - 20 && clientY <= rect.bottom + 20) {
1570        targetIndex = i;
1571        insertBefore = clientX < (rect.left + rect.width / 2);
1572        break;
1573      }
1574    }
1575
1576    if (targetIndex === -1) {
1577      clearDropIndicators();
1578      dragState.currentTargetIndex = -1;
1579      return;
1580    }
1581
1582    if (dragState.currentTargetIndex === targetIndex &&
1583        dragState.currentInsertBefore === insertBefore) {
1584      return;
1585    }
1586
1587    dragState.currentTargetIndex = targetIndex;
1588    dragState.currentInsertBefore = insertBefore;
1589
1590    clearDropIndicators();
1591
1592    var targetCard = slotsData[targetIndex].card;
1593    var indicator = document.createElement('div');
1594    indicator.className = 'slot-drop-indicator ' + (insertBefore ? 'indicator-left' : 'indicator-right');
1595    targetCard.appendChild(indicator);
1596    targetCard.classList.add('is-drag-over');
1597  }
1598
1599  function endDrag(commit) {
1600    if (!dragState) return;
1601
1602    var sourceIndex = dragState.sourceIndex;
1603    var targetIndex = dragState.currentTargetIndex;
1604    var insertBefore = dragState.currentInsertBefore;
1605
1606    if (dragState.ghostEl && dragState.ghostEl.parentNode) {
1607      dragState.ghostEl.parentNode.removeChild(dragState.ghostEl);
1608    }
1609
1610    clearDropIndicators();
1611
1612    if (slotsData[sourceIndex]) {
1613      slotsData[sourceIndex].card.classList.remove('is-drag-placeholder');
1614    }
1615
1616    document.body.style.userSelect = '';
1617    document.body.style.webkitUserSelect = '';
1618    document.body.style.cursor = '';
1619
1620    if (commit && targetIndex !== -1) {
1621      var insertIndex = insertBefore ? targetIndex : targetIndex + 1;
1622      if (sourceIndex < insertIndex) insertIndex -= 1;
1623
1624      if (insertIndex !== sourceIndex) {
1625        reorderSlots(sourceIndex, insertIndex);
1626      }
1627    }
1628
1629    dragState = null;
1630  }
1631
1632  function reorderSlots(fromIndex, toIndex) {
1633    if (fromIndex === toIndex) return;
1634    if (fromIndex < 0 || fromIndex >= slotsData.length) return;
1635    if (toIndex < 0 || toIndex >= slotsData.length) return;
1636
1637    var moved = slotsData.splice(fromIndex, 1)[0];
1638    slotsData.splice(toIndex, 0, moved);
1639
1640    slotsData.forEach(function (o) {
1641      slotsContainer.appendChild(o.card);
1642    });
1643
1644    reindexSlots();
1645    updateStatuses();
1646    saveSlots();
1647    renderPreview();
1648    if (outputSection.style.display !== 'none') renderCode();
1649  }
1650
1651  function addSlot(val, shouldFocus, customWidth, customHeight, insertAtStart) {
1652    var slotObj = createSlotCard(val || '', insertAtStart ? 0 : slotsData.length, customWidth, customHeight);
1653
1654    if (insertAtStart) {
1655      slotsData.unshift(slotObj);
1656      slotsContainer.insertBefore(slotObj.card, slotsContainer.firstChild);
1657      reindexSlots();
1658    } else {
1659      slotsData.push(slotObj);
1660      slotsContainer.appendChild(slotObj.card);
1661    }
1662
1663    updateRemoveButtons();
1664    onInput();
1665    if (shouldFocus) {
1666      slotObj.card.scrollIntoView({ behavior: 'smooth', block: 'nearest' });
1667      setTimeout(function () {
1668        try { slotObj.input.focus(); } catch (e) {}
1669      }, 80);
1670    }
1671  }
1672
1673  function removeSlot(cardEl) {
1674    if (slotsData.length <= 1) return;
1675    var idx = -1;
1676    for (var i = 0; i < slotsData.length; i++) {
1677      if (slotsData[i].card === cardEl) { idx = i; break; }
1678    }
1679    if (idx !== -1) {
1680      slotsContainer.removeChild(cardEl);
1681      slotsData.splice(idx, 1);
1682      reindexSlots();
1683      updateRemoveButtons();
1684      onInput();
1685    }
1686  }
1687
1688  function reindexSlots() {
1689    slotsData.forEach(function (obj, i) {
1690      obj.num.textContent = i + 1;
1691      obj.title.textContent = 'Embed ' + (i + 1);
1692    });
1693  }
1694
1695  function updateRemoveButtons() {
1696    slotsData.forEach(function (obj) {
1697      obj.removeBtn.style.display = slotsData.length > 1 ? '' : 'none';
1698    });
1699  }
1700
1701  function saveSlots() {
1702    try {
1703      var data = slotsData.map(function (obj) {
1704        return {
1705          code: obj.input.value,
1706          width: obj.customWidth || null,
1707          height: obj.customHeight || null
1708        };
1709      });
1710      localStorage.setItem(STORAGE_KEY, JSON.stringify(data));
1711    } catch (e) {}
1712  }
1713
1714  function loadSlots() {
1715    try {
1716      var raw = localStorage.getItem(STORAGE_KEY);
1717      if (raw) {
1718        var data = JSON.parse(raw);
1719        if (Array.isArray(data) && data.length > 0) {
1720          data.forEach(function (val) {
1721            if (typeof val === 'string') {
1722              addSlot(val);
1723            } else if (val && typeof val === 'object') {
1724              addSlot(val.code || '', false, val.width, val.height);
1725            }
1726          });
1727          return;
1728        }
1729      }
1730    } catch (e) {}
1731    addSlot('');
1732    addSlot('');
1733    addSlot('');
1734    addSlot('');
1735  }
1736
1737  function applyTheme(theme) {
1738    if (theme === 'dark' || theme === 'light') {
1739      document.documentElement.setAttribute('data-theme', theme);
1740    } else {
1741      document.documentElement.removeAttribute('data-theme');
1742    }
1743  }
1744
1745  function initTheme() {
1746    try {
1747      var saved = localStorage.getItem(THEME_KEY);
1748      if (saved) applyTheme(saved);
1749    } catch (e) {}
1750  }
1751
1752  document.getElementById('themeToggle').addEventListener('click', function () {
1753    var current = document.documentElement.getAttribute('data-theme');
1754    var prefersDark = window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches;
1755    var effectiveDark = current === 'dark' || (!current && prefersDark);
1756    var next = effectiveDark ? 'light' : 'dark';
1757    applyTheme(next);
1758    try { localStorage.setItem(THEME_KEY, next); } catch (e) {}
1759  });
1760
1761  if (addSlotBtn) {
1762    addSlotBtn.addEventListener('click', function () {
1763      addSlot('', true, null, null, true);
1764    });
1765  }
1766
1767  if (addSlotBtnBottom) {
1768    addSlotBtnBottom.addEventListener('click', function () {
1769      addSlot('', true, null, null, false);
1770    });
1771  }
1772
1773  gapButtons.forEach(function (btn) {
1774    btn.addEventListener('click', function () {
1775      gapButtons.forEach(function (b) { b.setAttribute('aria-pressed', 'false'); });
1776      btn.setAttribute('aria-pressed', 'true');
1777      currentGap = parseInt(btn.getAttribute('data-gap'), 10);
1778      renderPreview();
1779      if (outputSection.style.display !== 'none') renderCode();
1780    });
1781  });
1782
1783  modeButtons.forEach(function (btn) {
1784    btn.addEventListener('click', function () {
1785      modeButtons.forEach(function (b) { b.setAttribute('aria-pressed', 'false'); });
1786      btn.setAttribute('aria-pressed', 'true');
1787      layoutMode = btn.getAttribute('data-mode');
1788      if (layoutMode === 'masonry') {
1789        gapControlWrap.style.display = 'none';
1790        if (masonryControlsPanel) masonryControlsPanel.style.display = '';
1791      } else if (layoutMode === 'carousel') {
1792        gapControlWrap.style.display = 'none';
1793        if (masonryControlsPanel) masonryControlsPanel.style.display = 'none';
1794      } else {
1795        gapControlWrap.style.display = '';
1796        if (masonryControlsPanel) masonryControlsPanel.style.display = 'none';
1797      }
1798      carouselIndex = 0;
1799      renderPreview();
1800      if (outputSection.style.display !== 'none') renderCode();
1801    });
1802  });
1803
1804  masonryPresetButtons.forEach(function (btn) {
1805    btn.addEventListener('click', function () {
1806      var presetKey = btn.getAttribute('data-preset');
1807      applyMasonryPreset(presetKey);
1808    });
1809  });
1810
1811  masonryColsButtons.forEach(function (btn) {
1812    btn.addEventListener('click', function () {
1813      masonryColsButtons.forEach(function (b) { b.setAttribute('aria-pressed', 'false'); });
1814      btn.setAttribute('aria-pressed', 'true');
1815      masonryCols = btn.getAttribute('data-mcols') || 'auto';
1816      activePreset = 'custom';
1817      updateMasonryButtonsUI();
1818      saveMasonryConfig();
1819      if (layoutMode === 'masonry') {
1820        renderPreview();
1821        if (outputSection.style.display !== 'none') renderCode();
1822      }
1823    });
1824  });
1825
1826  masonryGapButtons.forEach(function (btn) {
1827    btn.addEventListener('click', function () {
1828      masonryGapButtons.forEach(function (b) { b.setAttribute('aria-pressed', 'false'); });
1829      btn.setAttribute('aria-pressed', 'true');
1830      masonryGap = parseInt(btn.getAttribute('data-mgap'), 10) || 0;
1831      activePreset = 'custom';
1832      updateMasonryButtonsUI();
1833      saveMasonryConfig();
1834      if (layoutMode === 'masonry') {
1835        renderPreview();
1836        if (outputSection.style.display !== 'none') renderCode();
1837      }
1838    });
1839  });
1840
1841  masonryPaddingButtons.forEach(function (btn) {
1842    btn.addEventListener('click', function () {
1843      masonryPaddingButtons.forEach(function (b) { b.setAttribute('aria-pressed', 'false'); });
1844      btn.setAttribute('aria-pressed', 'true');
1845      masonryPadding = parseInt(btn.getAttribute('data-mpadding'), 10) || 0;
1846      activePreset = 'custom';
1847      updateMasonryButtonsUI();
1848      saveMasonryConfig();
1849      if (layoutMode === 'masonry') {
1850        renderPreview();
1851        if (outputSection.style.display !== 'none') renderCode();
1852      }
1853    });
1854  });
1855
1856  masonryRadiusButtons.forEach(function (btn) {
1857    btn.addEventListener('click', function () {
1858      masonryRadiusButtons.forEach(function (b) { b.setAttribute('aria-pressed', 'false'); });
1859      btn.setAttribute('aria-pressed', 'true');
1860      masonryRadius = parseInt(btn.getAttribute('data-mradius'), 10) || 0;
1861      activePreset = 'custom';
1862      updateMasonryButtonsUI();
1863      saveMasonryConfig();
1864      if (layoutMode === 'masonry') {
1865        renderPreview();
1866        if (outputSection.style.display !== 'none') renderCode();
1867      }
1868    });
1869  });
1870
1871  masonryStyleButtons.forEach(function (btn) {
1872    btn.addEventListener('click', function () {
1873      masonryStyleButtons.forEach(function (b) { b.setAttribute('aria-pressed', 'false'); });
1874      btn.setAttribute('aria-pressed', 'true');
1875      masonryStyle = btn.getAttribute('data-mstyle') || 'card';
1876      activePreset = 'custom';
1877      updateMasonryButtonsUI();
1878      saveMasonryConfig();
1879      if (layoutMode === 'masonry') {
1880        renderPreview();
1881        if (outputSection.style.display !== 'none') renderCode();
1882      }
1883    });
1884  });
1885
1886  masonryHoverButtons.forEach(function (btn) {
1887    btn.addEventListener('click', function () {
1888      masonryHoverButtons.forEach(function (b) { b.setAttribute('aria-pressed', 'false'); });
1889      btn.setAttribute('aria-pressed', 'true');
1890      masonryHover = btn.getAttribute('data-mhover') || 'none';
1891      activePreset = 'custom';
1892      updateMasonryButtonsUI();
1893      saveMasonryConfig();
1894      if (layoutMode === 'masonry') {
1895        renderPreview();
1896        if (outputSection.style.display !== 'none') renderCode();
1897      }
1898    });
1899  });
1900
1901  function buildFrameDoc(code) {
1902    return '<!doctype html><html><head><meta charset="utf-8">' +
1903      '<meta name="viewport" content="width=device-width, initial-scale=1">' +
1904      '<base target="_blank">' +
1905      '<style>' +
1906      '*,*::before,*::after{box-sizing:border-box;}' +
1907      'html{width:100%;margin:0;padding:0;background:transparent;}' +
1908      'body{margin:0;padding:8px;width:100%;box-sizing:border-box;font-family:system-ui,-apple-system,sans-serif;' +
1909      'color:#0f172a;background:transparent;display:block;overflow:hidden;}
1909' +
1910      'img{max-width:100%!important;height:auto!important;margin:0 auto;display:block;border-radius:6px;border:0;}' +
1911      'video,iframe,embed,object{max-width:100%!important;margin:0 auto;display:block;border-radius:6px;border:0;}' +
1912      'blockquote{max-width:100%!important;margin:0 auto!important;border-radius:6px;border:0;}' +
1913      '</style>' +
1914      '<script>' +
1915      '(function(){' +
1916      '  function sendSize(){' +
1917      '    var body = document.body, html = document.documentElement;' +
1918      '    var h = Math.max(body.scrollHeight, body.offsetHeight, html.scrollHeight, html.offsetHeight);' +
1919      '    if(h > 0){ window.parent.postMessage({ type: "EZ_FRAME_RESIZE", height: h }, "*"); }' +
1920      '  }' +
1921      '  window.addEventListener("load", function(){ sendSize(); setTimeout(sendSize, 300); setTimeout(sendSize, 1000); });' +
1922      '  window.addEventListener("resize", sendSize);' +
1923      '  if(window.ResizeObserver){ new ResizeObserver(sendSize).observe(document.body); }' +
1924      '})();' +
1925      '<' + '/script>' +
1926      '</head><body>' + code + '</body></html>';
1927  }
1928
1929  window.addEventListener('message', function (e) {
1930    if (e.data && e.data.type === 'EZ_FRAME_RESIZE' && e.data.height) {
1931      var frames = document.querySelectorAll('.stage-cell iframe, .carousel-viewport iframe');
1932      for (var i = 0; i < frames.length; i++) {
1933        if (frames[i].contentWindow === e.source) {
1934          var cell = frames[i].closest('.stage-cell, .carousel-viewport');
1935          if (cell && !cell.classList.contains('is-resizing')) {
1936            var targetH = Math.min(Math.max(e.data.height + 24, 180), 800);
1937            cell.style.height = targetH + 'px';
1938          }
1939        }
1940      }
1941    }
1942  });
1943
1944  function renderPreview() {
1945    if (layoutMode === 'carousel') renderCarouselPreview();
1946    else if (layoutMode === 'masonry') renderMasonryPreview();
1947    else renderRowPreview();
1948  }
1949
1950  function setupResizableCell(cell, obj, i) {
1951    var parsedH = parseSnippetHeight(obj.input.value);
1952    if (obj.customWidth) cell.style.width = obj.customWidth + 'px';
1953    if (obj.customHeight) cell.style.height = obj.customHeight + 'px';
1954    else if (parsedH) cell.style.height = (parsedH + 24) + 'px';
1955
1956    cell.addEventListener('pointerdown', function (e) {
1957      var rect = cell.getBoundingClientRect();
1958      if (e.clientX > rect.right - 30 && e.clientY > rect.bottom - 30) {
1959        cell.classList.add('is-resizing');
1960        var onUp = function () {
1961          cell.classList.remove('is-resizing');
1962          window.removeEventListener('pointerup', onUp);
1963          window.removeEventListener('pointercancel', onUp);
1964        };
1965        window.addEventListener('pointerup', onUp);
1966        window.addEventListener('pointercancel', onUp);
1967      }
1968    });
1969
1970    var isInitial = true;
1971    if (window.ResizeObserver) {
1972      var ro = new ResizeObserver(function () {
1973        if (isInitial) {
1974          isInitial = false;
1975          return;
1976        }
1977        if (cell.style.width || cell.style.height) {
1978          var w = Math.round(cell.getBoundingClientRect().width || cell.offsetWidth);
1979          var h = Math.round(cell.getBoundingClientRect().height || cell.offsetHeight);
1980          if (w > 50 && h > 50) {
1981            obj.customWidth = w;
1982            obj.customHeight = h;
1983            saveSlots();
1984            if (outputSection.style.display !== 'none') renderCode();
1985          }
1986        }
1987      });
1988      ro.observe(cell);
1989    }
1990
1991    cell.addEventListener('pointerup', function () {
1992      if (cell.style.width || cell.style.height) {
1993        var w = Math.round(cell.getBoundingClientRect().width || cell.offsetWidth);
1994        var h = Math.round(cell.getBoundingClientRect().height || cell.offsetHeight);
1995        if (w > 50) obj.customWidth = w;
1996        if (h > 50) obj.customHeight = h;
1997        saveSlots();
1998        if (outputSection.style.display !== 'none') renderCode();
1999      }
2000    });
2001  }
2002
2003  function renderRowPreview() {
2004    var maxCols = Math.min(slotsData.length, 4);
2005    var isSingle = slotsData.length === 1;
2006    stageRow.className = 'stage-row' + (isSingle ? ' is-single-embed' : '');
2007    stageRow.style.display = 'grid';
2008    stageRow.style.columnCount = '';
2009    stageRow.style.columnGap = '';
2010    stageRow.style.gap = currentGap + 'px';
2011    stageRow.style.gridTemplateColumns = isSingle ? '1fr' : 'repeat(' + maxCols + ', minmax(280px, 1fr))';
2012    stageRow.style.minWidth = isSingle ? '0' : (maxCols * 280 + (maxCols - 1) * currentGap) + 'px';
2013    stageRow.style.maxWidth = isSingle ? '640px' : '';
2014    stageRow.style.margin = '0 auto';
2015    stageRow.innerHTML = '';
2016
2017    slotsData.forEach(function (obj, i) {
2018      var cell = document.createElement('div');
2019      cell.className = 'stage-cell';
2020      var code = extractBodyContent(obj.input.value);
2021      if (code) {
2022        var frame = document.createElement('iframe');
2023        frame.setAttribute('sandbox', 'allow-scripts allow-same-origin allow-popups allow-popups-to-escape-sandbox allow-forms allow-modals allow-presentation allow-top-navigation-by-user-activation');
2024        frame.setAttribute('srcdoc', buildFrameDoc(code));
2025        frame.title = 'Preview of slot ' + (i + 1);
2026        cell.appendChild(frame);
2027      } else {
2028        var empty = document.createElement('div');
2029        empty.className = 'stage-empty';
2030        empty.textContent = 'Slot ' + (i + 1) + ' — paste embed code above to preview it here';
2031        cell.appendChild(empty);
2032      }
2033      setupResizableCell(cell, obj, i);
2034      stageRow.appendChild(cell);
2035    });
2036  }
2037
2038  function renderMasonryPreview() {
2039    var cols = masonryCols === 'auto' ? Math.min(slotsData.length, 4) : parseInt(masonryCols, 10);
2040    if (!cols || cols < 1) cols = 1;
2041    var isSingle = slotsData.length === 1 && (masonryCols === 'auto' || masonryCols === '1');
2042
2043    stageRow.className = 'masonry-preview' + (isSingle ? ' is-single-embed' : '');
2044    stageRow.style.display = 'flex';
2045    stageRow.style.flexDirection = 'row';
2046    stageRow.style.alignItems = 'flex-start';
2047    stageRow.style.gap = masonryGap + 'px';
2048    stageRow.style.columnCount = '';
2049    stageRow.style.columnGap = '';
2050    stageRow.style.gridTemplateColumns = '';
2051    stageRow.style.minWidth = isSingle ? '0' : '100%';
2052    stageRow.style.maxWidth = isSingle ? '640px' : '100%';
2053    stageRow.style.margin = '0 auto';
2054    stageRow.innerHTML = '';
2055
2056    var colEls = [];
2057    for (var c = 0; c < cols; c++) {
2058      var colDiv = document.createElement('div');
2059      colDiv.className = 'masonry-preview-col';
2060      colDiv.style.flex = '1 1 0';
2061      colDiv.style.display = 'flex';
2062      colDiv.style.flexDirection = 'column';
2063      colDiv.style.gap = masonryGap + 'px';
2064      colDiv.style.minWidth = '0';
2065      stageRow.appendChild(colDiv);
2066      colEls.push(colDiv);
2067    }
2068
2069    slotsData.forEach(function (obj, i) {
2070      var targetCol = colEls[i % cols];
2071
2072      var cell = document.createElement('div');
2073      cell.className = 'stage-cell masonry-stage-cell';
2074      cell.setAttribute('data-mstyle', masonryStyle);
2075      cell.setAttribute('data-mhover', masonryHover);
2076      cell.style.padding = masonryPadding + 'px';
2077      cell.style.borderRadius = masonryRadius + 'px';
2078
2079      var badge = document.createElement('span');
2080      badge.className = 'masonry-slot-badge';
2081      badge.textContent = '#' + (i + 1);
2082      cell.appendChild(badge);
2083
2084      var code = extractBodyContent(obj.input.value);
2085      if (code) {
2086        var frame = document.createElement('iframe');
2087        frame.setAttribute('sandbox', 'allow-scripts allow-same-origin allow-popups allow-popups-to-escape-sandbox allow-forms allow-modals allow-presentation allow-top-navigation-by-user-activation');
2088        frame.setAttribute('srcdoc', buildFrameDoc(code));
2089        frame.title = 'Preview of slot ' + (i + 1);
2090        cell.appendChild(frame);
2091      } else {
2092        var empty = document.createElement('div');
2093        empty.className = 'stage-empty';
2094        empty.textContent = 'Slot ' + (i + 1) + ' — paste embed code above to preview it here';
2095        cell.appendChild(empty);
2096      }
2097      setupResizableCell(cell, obj, i);
2098      targetCol.appendChild(cell);
2099    });
2100  }
2101
2102  function filledSlots() {
2103    return slotsData
2104      .map(function (obj, i) {
2105        return {
2106          i: i,
2107          code: extractBodyContent(obj.input.value),
2108          width: obj.customWidth || null,
2109          height: obj.customHeight || null
2110        };
2111      })
2112      .filter(function (s) { return s.code; });
2113  }
2114
2115  function renderCarouselPreview() {
2116    stageRow.className = 'carousel-preview';
2117    stageRow.style.display = 'flex';
2118    stageRow.style.flexDirection = 'column';
2119    stageRow.style.columnCount = '';
2120    stageRow.style.columnGap = '';
2121    stageRow.style.gap = '14px';
2122    stageRow.style.gridTemplateColumns = '';
2123    stageRow.style.minWidth = '0';
2124    stageRow.style.width = '100%';
2125    stageRow.style.maxWidth = '640px';
2126    stageRow.style.margin = '0 auto';
2127    stageRow.innerHTML = '';
2128    var filled = filledSlots();
2129
2130    if (!filled.length) {
2131      var empty = document.createElement('div');
2132      empty.className = 'stage-empty';
2133      empty.style.height = '360px';
2134      empty.style.minWidth = '100%';
2135      empty.textContent = 'Paste embed code into at least one slot to preview the carousel';
2136      stageRow.appendChild(empty);
2137      return;
2138    }
2139
2140    if (carouselIndex >= filled.length) carouselIndex = 0;
2141
2142    if (filled.length > 1) {
2143      var controls = document.createElement('div');
2144      controls.className = 'carousel-controls';
2145
2146      var prevBtn = document.createElement('button');
2147      prevBtn.type = 'button';
2148      prevBtn.className = 'carousel-arrow';
2149      prevBtn.setAttribute('aria-label', 'Previous clip');
2150      prevBtn.textContent = '‹';
2151      prevBtn.addEventListener('click', function () {
2152        carouselIndex = (carouselIndex - 1 + filled.length) % filled.length;
2153        renderCarouselPreview();
2154      });
2155
2156      var dots = document.createElement('div');
2157      dots.className = 'carousel-dots';
2158      filled.forEach(function (s, idx) {
2159        var d = document.createElement('button');
2160        d.type = 'button';
2161        d.setAttribute('aria-label', 'Go to clip ' + (idx + 1));
2162        if (idx === carouselIndex) d.className = 'is-active';
2163        d.addEventListener('click', function () {
2164          carouselIndex = idx;
2165          renderCarouselPreview();
2166        });
2167        dots.appendChild(d);
2168      });
2169
2170      var nextBtn = document.createElement('button');
2171      nextBtn.type = 'button';
2172      nextBtn.className = 'carousel-arrow';
2173      nextBtn.setAttribute('aria-label', 'Next clip');
2174      nextBtn.textContent = '›';
2175      nextBtn.addEventListener('click', function () {
2176        carouselIndex = (carouselIndex + 1) % filled.length;
2177        renderCarouselPreview();
2178      });
2179
2180      controls.appendChild(prevBtn);
2181      controls.appendChild(dots);
2182      controls.appendChild(nextBtn);
2183      stageRow.appendChild(controls);
2184    }
2185
2186    var viewport = document.createElement('div');
2187    viewport.className = 'carousel-viewport';
2188    if (carouselWidth) viewport.style.width = carouselWidth + 'px';
2189    if (carouselHeight) viewport.style.height = carouselHeight + 'px';
2190
2191    var frame = document.createElement('iframe');
2192    frame.setAttribute('sandbox', 'allow-scripts allow-same-origin allow-popups allow-popups-to-escape-sandbox allow-forms allow-modals allow-presentation allow-top-navigation-by-user-activation');
2193    frame.setAttribute('srcdoc', buildFrameDoc(filled[carouselIndex].code));
2194    frame.title = 'Preview of clip ' + (carouselIndex + 1) + ' of ' + filled.length;
2195    viewport.appendChild(frame);
2196    stageRow.appendChild(viewport);
2197
2198    viewport.addEventListener('pointerdown', function (e) {
2199      var rect = viewport.getBoundingClientRect();
2200      if (e.clientX > rect.right - 30 && e.clientY > rect.bottom - 30) {
2201        viewport.classList.add('is-resizing');
2202        var onUp = function () {
2203          viewport.classList.remove('is-resizing');
2204          window.removeEventListener('pointerup', onUp);
2205          window.removeEventListener('pointercancel', onUp);
2206        };
2207        window.addEventListener('pointerup', onUp);
2208        window.addEventListener('pointercancel', onUp);
2209      }
2210    });
2211
2212    var isInitialVp = true;
2213    if (window.ResizeObserver) {
2214      var roVp = new ResizeObserver(function () {
2215        if (isInitialVp) {
2216          isInitialVp = false;
2217          return;
2218        }
2219        if (viewport.style.width || viewport.style.height) {
2220          var w = Math.round(viewport.getBoundingClientRect().width || viewport.offsetWidth);
2221          var h = Math.round(viewport.getBoundingClientRect().height || viewport.offsetHeight);
2222          if (w > 50) carouselWidth = w;
2223          if (h > 50) carouselHeight = h;
2224          if (outputSection.style.display !== 'none') renderCode();
2225        }
2226      });
2227      roVp.observe(viewport);
2228    }
2229
2230    viewport.addEventListener('pointerup', function () {
2231      if (viewport.style.width || viewport.style.height) {
2232        var w = Math.round(viewport.getBoundingClientRect().width || viewport.offsetWidth);
2233        var h = Math.round(viewport.getBoundingClientRect().height || viewport.offsetHeight);
2234        if (w > 50) carouselWidth = w;
2235        if (h > 50) carouselHeight = h;
2236        if (outputSection.style.display !== 'none') renderCode();
2237      }
2238    });
2239  }
2240
2241  function updateStatuses() {
2242    slotsData.forEach(function (obj) {
2243      var filled = extractBodyContent(obj.input.value).length > 0;
2244      obj.status.textContent = filled ? 'ready' : 'empty';
2245      obj.status.classList.toggle('filled', filled);
2246    });
2247  }
2248
2249  function indent(code, spaces) {
2250    var pad = new Array(spaces + 1).join(' ');
2251    return code.split('\\n').map(function (line) { return pad + line; }).join('\\n');
2252  }
2253
2254  function buildRowHTML() {
2255    var filled = filledSlots();
2256    if (!filled.length) {
2257      return '<!DOCTYPE html>\\n<html lang="en">\\n<head>\\n  <meta charset="UTF-8">\\n  <title>Embed Row</title>\\n</head>\\n<body>\\n  <!-- Paste embed code into at least one slot above -->\\n</body>\\n</html>';
2258    }
2259
2260    var uid = 'embed-row-' + Math.random().toString(36).slice(2, 8);
2261    var cols = Math.min(filled.length, 4);
2262    var isSingle = filled.length === 1;
2263
2264    var itemsHtml = filled.map(function (s) {
2265      var styleParts = [];
2266      if (s.width) styleParts.push('width: ' + s.width + 'px');
2267      if (s.height) styleParts.push('height: ' + s.height + 'px');
2268      var styleAttr = styleParts.length ? ' style="' + styleParts.join('; ') + ';"' : '';
2269      return '    <div class="embed-row-item' + (isSingle ? ' is-single' : '') + '"' + styleAttr + '>\\n' + indent(s.code, 6) + '\\n    </div>';
2270    }).join('\\n');
2271
2272    return '<!DOCTYPE html>\\n' +
2273      '<html lang="en">\\n' +
2274      '<head>\\n' +
2275      '  <meta charset="UTF-8">\\n' +
2276      '  <meta name="viewport" content="width=device-width, initial-scale=1.0">\\n' +
2277      '  <title>Side-by-Side Embeds</title>\\n' +
2278      '  <style>\\n' +
2279      '    *, *::before, *::after {\\n' +
2280      '      box-sizing: border-box;\\n' +
2281      '    }\\n' +
2282      '    html, body {\\n' +
2283      '      margin: 0;\\n' +
2284      '      padding: 0;\\n' +
2285      '      font-family: system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;\\n' +
2286      '      background: #f8fafc;\\n' +
2287      '      color: #0f172a;\\n' +
2288      '      min-height: 100vh;\\n' +
2289      '      overflow-x: auto;\\n' +
2290      '      -webkit-overflow-scrolling: touch;\\n' +
2291      '    }\\n' +
2292      '    .embed-scroll-container {\\n' +
2293      '      width: 100%;\\n' +
2294      '      max-width: 1400px;\\n' +
2295      '      margin: 0 auto;\\n' +
2296      '      overflow-x: auto;\\n' +
2297      '      overflow-y: hidden;\\n' +
2298      '      padding: 24px 20px;\\n' +
2299      '      box-sizing: border-box;\\n' +
2300      '      -webkit-overflow-scrolling: touch;\\n' +
2301      '    }\\n' +
2302      '    #' + uid + ' {\\n' +
2303      '      display: grid;\\n' +
2304      '      grid-template-columns: ' + (isSingle ? '1fr' : 'repeat(' + cols + ', minmax(280px, 1fr))') + ';\\n' +
2305      '      gap: ' + currentGap + 'px;\\n' +
2306      '      width: 100%;\\n' +
2307      (isSingle ? '      max-width: 640px;\\n      margin: 0 auto;\\n' : '') +
2308      '      box-sizing: border-box;\\n' +
2309      '      align-items: start;\\n' +
2310      '    }\\n' +
2311      '    #' + uid + ' .embed-row-item {\\n' +
2312      '      min-width: 240px;\\n' +
2313      '      box-sizing: border-box;\\n' +
2314      '      border-radius: 14px;\\n' +
2315      '      background: #ffffff;\\n' +
2316      '      border: 1px solid #e2e8f0;\\n' +
2317      '      box-shadow: 0 4px 14px -2px rgba(0, 0, 0, 0.05), 0 2px 6px -1px rgba(0, 0, 0, 0.02);\\n' +
2318      '      padding: 12px;\\n' +
2319      '      display: flex;\\n' +
2320      '      flex-direction: column;\\n' +
2321      '      align-items: stretch;\\n' +
2322      '      justify-content: stretch;\\n' +
2323      '      resize: both;\\n' +
2324      '      overflow: auto;\\n' +
2325      '      min-height: 180px;\\n' +
2326      '      max-width: 100%;\\n' +
2327      '      transition: box-shadow 0.2s ease;\\n' +
2328      '    }\\n' +
2329      '    #' + uid + ' .embed-row-item:hover {\\n' +
2330      '      box-shadow: 0 8px 24px -4px rgba(0, 0, 0, 0.08), 0 3px 8px -2px rgba(0, 0, 0, 0.04);\\n' +
2331      '      transform: translateY(-2px);\\n' +
2332      '    }\\n' +
2333      '    #' + uid + ' .embed-row-item > * {\\n' +
2334      '      width: 100% !important;\\n' +
2335      '      height: 100% !important;\\n' +
2336      '      min-height: 0 !important;\\n' +
2337      '      max-width: 100% !important;\\n' +
2338      '      max-height: 100% !important;\\n' +
2339      '      flex: 1 1 auto !important;\\n' +
2340      '      box-sizing: border-box !important;\\n' +
2341      '    }\\n' +
2342      '    #' + uid + ' .embed-row-item iframe,\\n' +
2343      '    #' + uid + ' .embed-row-item video,\\n' +
2344      '    #' + uid + ' .embed-row-item embed,\\n' +
2345      '    #' + uid + ' .embed-row-item object {\\n' +
2346      '      width: 100% !important;\\n' +
2347      '      height: 100% !important;\\n' +
2348      '      min-height: 0 !important;\\n' +
2349      '      flex: 1 1 auto !important;\\n' +
2350      '      margin: 0 auto !important;\\n' +
2351      '      border: 0 !important;\\n' +
2352      '      border-radius: 8px;\\n' +
2353      '      display: block;\\n' +
2354      '    }\\n' +
2355      '    #' + uid + ' .embed-row-item img {\\n' +
2356      '      width: 100% !important;\\n' +
2357      '      height: 100% !important;\\n' +
2358      '      object-fit: contain !important;\\n' +
2359      '      min-height: 0 !important;\\n' +
2360      '      flex: 1 1 auto !important;\\n' +
2361      '      margin: 0 auto !important;\\n' +
2362      '      border: 0 !important;\\n' +
2363      '      border-radius: 8px;\\n' +
2364      '      display: block;\\n' +
2365      '    }\\n' +
2366      '    #' + uid + ' .embed-row-item blockquote {\\n' +
2367      '      width: 100% !important;\\n' +
2368      '      max-width: 100% !important;\\n' +
2369      '      max-height: 100% !important;\\n' +
2370      '      overflow: auto !important;\\n' +
2371      '      margin: 0 auto !important;\\n' +
2372      '      border: 0 !important;\\n' +
2373      '      border-radius: 8px;\\n' +
2374      '      display: block;\\n' +
2375      '    }\\n' +
2376      '    #' + uid + ' .embed-row-item div > iframe,\\n' +
2377      '    #' + uid + ' .embed-row-item div > video,\\n' +
2378      '    #' + uid + ' .embed-row-item div > embed,\\n' +
2379      '    #' + uid + ' .embed-row-item div > object {\\n' +
2380      '      width: 100% !important;\\n' +
2381      '      height: 100% !important;\\n' +
2382      '      min-height: 0 !important;\\n' +
2383      '    }\\n' +
2384      '    #' + uid + ' .embed-row-item div > img {\\n' +
2385      '      width: 100% !important;\\n' +
2386      '      height: 100% !important;\\n' +
2387      '      object-fit: contain !important;\\n' +
2388      '    }\\n' +
2389      '    @media (min-width: 769px) {\\n' +
2390      '      #' + uid + ':has(> .embed-row-item:only-child), #' + uid + '.is-single {\\n' +
2391      '        max-width: 640px !important;\\n' +
2392      '        width: 100% !important;\\n' +
2393      '        margin: 0 auto !important;\\n' +
2394      '      }\\n' +
2395      '    }\\n' +
2396      '    @media (max-width: 1100px) {\\n' +
2397      '      #' + uid + ' {\\n' +
2398      '        grid-template-columns: ' + (isSingle ? '1fr' : 'repeat(' + Math.min(cols, 3) + ', minmax(260px, 1fr))') + ';\\n' +
2399      '      }\\n' +
2400      '    }\\n' +
2401      '    @media (max-width: 768px) {\\n' +
2402      '      #' + uid + ' {\\n' +
2403      '        grid-template-columns: 1fr;\\n' +
2404      '        gap: ' + Math.max(12, Math.round(currentGap * 0.75
2404)) + 'px;\\n' +
2405      '        max-width: 100% !important;\\n' +
2406      '      }\\n' +
2407      '      .embed-scroll-container {\\n' +
2408      '        padding: 16px 12px;\\n' +
2409      '      }\\n' +
2410      '    }\\n' +
2411      '  </style>\\n' +
2412      '</head>\\n' +
2413      '<body>\\n' +
2414      '  <div class="embed-scroll-container">\\n' +
2415      '    <div class="embed-row-wrapper' + (isSingle ? ' is-single' : '') + '" id="' + uid + '">\\n' +
2416      itemsHtml + '\\n' +
2417      '    </div>\\n' +
2418      '  </div>\\n' +
2419      '</body>\\n' +
2420      '</html>';
2421  }
2422
2423  function buildMasonryHTML() {
2424    var filled = filledSlots();
2425    if (!filled.length) {
2426      return '<!DOCTYPE html>\\n<html lang="en">\\n<head>\\n  <meta charset="UTF-8">\\n  <title>Masonry Embeds</title>\\n</head>\\n<body>\\n  <!-- Paste embed code into at least one slot above -->\\n</body>\\n</html>';
2427    }
2428
2429    var uid = 'embed-masonry-' + Math.random().toString(36).slice(2, 8);
2430    var cols = masonryCols === 'auto' ? Math.min(filled.length, 4) : parseInt(masonryCols, 10);
2431    if (!cols || cols < 1) cols = 1;
2432    var isSingle = filled.length === 1 && (masonryCols === 'auto' || masonryCols === '1');
2433
2434    var surfaceCss = '';
2435    if (masonryStyle === 'minimal') {
2436      surfaceCss = '      background: transparent;\\n      border: none;\\n      box-shadow: none;';
2437    } else if (masonryStyle === 'outline') {
2438      surfaceCss = '      background: #ffffff;\\n      border: 1px solid #cbd5e1;\\n      box-shadow: none;';
2439    } else if (masonryStyle === 'glass') {
2440      surfaceCss = '      background: rgba(255, 255, 255, 0.75);\\n      backdrop-filter: blur(12px);\\n      -webkit-backdrop-filter: blur(12px);\\n      border: 1px solid rgba(255, 255, 255, 0.5);\\n      box-shadow: 0 8px 24px 0 rgba(0, 0, 0, 0.06);';
2441    } else {
2442      surfaceCss = '      background: #ffffff;\\n      border: 1px solid #e2e8f0;\\n      box-shadow: 0 4px 14px -2px rgba(0, 0, 0, 0.05), 0 2px 6px -1px rgba(0, 0, 0, 0.02);';
2443    }
2444
2445    var hoverCss = '';
2446    if (masonryHover === 'lift') {
2447      hoverCss = '    #' + uid + ' .masonry-item:hover {\\n' +
2448        '      transform: translateY(-3px);\\n' +
2449        '      box-shadow: 0 10px 24px -4px rgba(0, 0, 0, 0.1), 0 4px 8px -2px rgba(0, 0, 0, 0.04);\\n' +
2450        '    }\\n';
2451    } else if (masonryHover === 'glow') {
2452      hoverCss = '    #' + uid + ' .masonry-item:hover {\\n' +
2453        '      border-color: #2563eb;\\n' +
2454        '      box-shadow: 0 0 0 3px rgba(37, 99, 235, 0.18), 0 4px 12px rgba(0, 0, 0, 0.06);\\n' +
2455        '    }\\n';
2456    }
2457
2458    var colBuckets = [];
2459    for (var c = 0; c < cols; c++) {
2460      colBuckets.push([]);
2461    }
2462    filled.forEach(function (s, idx) {
2463      colBuckets[idx % cols].push(s);
2464    });
2465
2466    var colsHtml = colBuckets.map(function (bucket, colIdx) {
2467      var itemsHtml = bucket.map(function (s) {
2468        var styleParts = [];
2469        if (s.width) styleParts.push('width: ' + s.width + 'px');
2470        if (s.height) styleParts.push('height: ' + s.height + 'px');
2471        var styleAttr = styleParts.length ? ' style="' + styleParts.join('; ') + ';"' : '';
2472        return '      <div class="masonry-item' + (isSingle ? ' is-single' : '') + '"' + styleAttr + '>\\n' + indent(s.code, 8) + '\\n      </div>';
2473      }).join('\\n');
2474
2475      return '    <div class="masonry-col">\\n' + itemsHtml + '\\n    </div>';
2476    }).join('\\n');
2477
2478    return '<!DOCTYPE html>\\n' +
2479      '<html lang="en">\\n' +
2480      '<head>\\n' +
2481      '  <meta charset="UTF-8">\\n' +
2482      '  <meta name="viewport" content="width=device-width, initial-scale=1.0">\\n' +
2483      '  <title>Masonry Embeds</title>\\n' +
2484      '  <style>\\n' +
2485      '    *, *::before, *::after {\\n' +
2486      '      box-sizing: border-box;\\n' +
2487      '    }\\n' +
2488      '    html, body {\\n' +
2489      '      margin: 0;\\n' +
2490      '      padding: 0;\\n' +
2491      '      font-family: system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;\\n' +
2492      '      background: #f8fafc;\\n' +
2493      '      color: #0f172a;\\n' +
2494      '      min-height: 100vh;\\n' +
2495      '      overflow-x: auto;\\n' +
2496      '      -webkit-overflow-scrolling: touch;\\n' +
2497      '    }\\n' +
2498      '    .masonry-scroll-container {\\n' +
2499      '      width: 100%;\\n' +
2500      '      max-width: 1400px;\\n' +
2501      '      margin: 0 auto;\\n' +
2502      '      overflow-x: auto;\\n' +
2503      '      padding: 24px 20px;\\n' +
2504      '      box-sizing: border-box;\\n' +
2505      '      -webkit-overflow-scrolling: touch;\\n' +
2506      '    }\\n' +
2507      '    #' + uid + ' {\\n' +
2508      '      display: flex;\\n' +
2509      '      flex-direction: row;\\n' +
2510      '      align-items: flex-start;\\n' +
2511      '      gap: ' + masonryGap + 'px;\\n' +
2512      '      width: 100%;\\n' +
2513      (isSingle ? '      max-width: 640px;\\n      margin: 0 auto;\\n' : '') +
2514      '      box-sizing: border-box;\\n' +
2515      '    }\\n' +
2516      '    #' + uid + ' .masonry-col {\\n' +
2517      '      flex: 1 1 0;\\n' +
2518      '      display: flex;\\n' +
2519      '      flex-direction: column;\\n' +
2520      '      gap: ' + masonryGap + 'px;\\n' +
2521      '      min-width: 0;\\n' +
2522      '    }\\n' +
2523      '    #' + uid + ' .masonry-item {\\n' +
2524      '      display: flex;\\n' +
2525      '      flex-direction: column;\\n' +
2526      '      align-items: stretch;\\n' +
2527      '      justify-content: stretch;\\n' +
2528      '      width: 100%;\\n' +
2529      '      box-sizing: border-box;\\n' +
2530      '      min-width: 200px;\\n' +
2531      '      border-radius: ' + masonryRadius + 'px;\\n' +
2532      surfaceCss + '\\n' +
2533      '      padding: ' + masonryPadding + 'px;\\n' +
2534      '      resize: both;\\n' +
2535      '      overflow: auto;\\n' +
2536      '      min-height: 180px;\\n' +
2537      '      max-width: 100%;\\n' +
2538      '      transition: transform 0.2s ease, box-shadow 0.2s ease, border-color 0.2s ease;\\n' +
2539      '    }\\n' +
2540      hoverCss +
2541      '    #' + uid + ' .masonry-item > * {\\n' +
2542      '      width: 100% !important;\\n' +
2543      '      height: 100% !important;\\n' +
2544      '      min-height: 0 !important;\\n' +
2545      '      max-width: 100% !important;\\n' +
2546      '      max-height: 100% !important;\\n' +
2547      '      flex: 1 1 auto !important;\\n' +
2548      '      box-sizing: border-box !important;\\n' +
2549      '    }\\n' +
2550      '    #' + uid + ' .masonry-item iframe,\\n' +
2551      '    #' + uid + ' .masonry-item video,\\n' +
2552      '    #' + uid + ' .masonry-item embed,\\n' +
2553      '    #' + uid + ' .masonry-item object {\\n' +
2554      '      width: 100% !important;\\n' +
2555      '      height: 100% !important;\\n' +
2556      '      min-height: 0 !important;\\n' +
2557      '      flex: 1 1 auto !important;\\n' +
2558      '      margin: 0 auto !important;\\n' +
2559      '      border: 0 !important;\\n' +
2560      '      border-radius: inherit;\\n' +
2561      '      display: block;\\n' +
2562      '    }\\n' +
2563      '    #' + uid + ' .masonry-item img {\\n' +
2564      '      width: 100% !important;\\n' +
2565      '      height: 100% !important;\\n' +
2566      '      object-fit: contain !important;\\n' +
2567      '      min-height: 0 !important;\\n' +
2568      '      flex: 1 1 auto !important;\\n' +
2569      '      margin: 0 auto !important;\\n' +
2570      '      border: 0 !important;\\n' +
2571      '      border-radius: inherit;\\n' +
2572      '      display: block;\\n' +
2573      '    }\\n' +
2574      '    #' + uid + ' .masonry-item blockquote {\\n' +
2575      '      width: 100% !important;\\n' +
2576      '      max-width: 100% !important;\\n' +
2577      '      max-height: 100% !important;\\n' +
2578      '      overflow: auto !important;\\n' +
2579      '      margin: 0 auto !important;\\n' +
2580      '      border: 0 !important;\\n' +
2581      '      border-radius: inherit;\\n' +
2582      '      display: block;\\n' +
2583      '    }\\n' +
2584      '    #' + uid + ' .masonry-item div > iframe,\\n' +
2585      '    #' + uid + ' .masonry-item div > video,\\n' +
2586      '    #' + uid + ' .masonry-item div > embed,\\n' +
2587      '    #' + uid + ' .masonry-item div > object {\\n' +
2588      '      width: 100% !important;\\n' +
2589      '      height: 100% !important;\\n' +
2590      '      min-height: 0 !important;\\n' +
2591      '    }\\n' +
2592      '    #' + uid + ' .masonry-item div > img {\\n' +
2593      '      width: 100% !important;\\n' +
2594      '      height: 100% !important;\\n' +
2595      '      object-fit: contain !important;\\n' +
2596      '    }\\n' +
2597      '    @media (max-width: 768px) {\\n' +
2598      '      #' + uid + ' {\\n' +
2599      '        flex-direction: column;\\n' +
2600      '        gap: ' + Math.max(8, Math.round(masonryGap * 0.6)) + 'px;\\n' +
2601      '        max-width: 100% !important;\\n' +
2602      '      }\\n' +
2603      '      #' + uid + ' .masonry-col {\\n' +
2604      '        width: 100%;\\n' +
2605      '      }\\n' +
2606      '      #' + uid + ' .masonry-item {\\n' +
2607      '        padding: ' + Math.max(6, Math.round(masonryPadding * 0.75)) + 'px;\\n' +
2608      '      }\\n' +
2609      '      .masonry-scroll-container {\\n' +
2610      '        padding: 16px 10px;\\n' +
2611      '      }\\n' +
2612      '    }\\n' +
2613      '  </style>\\n' +
2614      '</head>\\n' +
2615      '<body>\\n' +
2616      '  <div class="masonry-scroll-container">\\n' +
2617      '    <div class="masonry-wrapper' + (isSingle ? ' is-single' : '') + '" id="' + uid + '">\\n' +
2618      colsHtml + '\\n' +
2619      '    </div>\\n' +
2620      '  </div>\\n' +
2621      '</body>\\n' +
2622      '</html>';
2623  }
2624
2625  function buildCarouselHTML() {
2626    var filled = filledSlots();
2627    if (!filled.length) {
2628      return '<!DOCTYPE html>\\n<html lang="en">\\n<head>\\n  <meta charset="UTF-8">\\n  <title>Embed Carousel</title>\\n</head>\\n<body>\\n  <!-- Paste embed code into at least one slot above -->\\n</body>\\n</html>';
2629    }
2630
2631    var uid = 'embed-carousel-' + Math.random().toString(36).slice(2, 8);
2632    var multi = filled.length > 1;
2633
2634    var slidesHtml = filled.map(function (s, i) {
2635      return '      <div class="ec-slide" data-active="' + (i === 0 ? 'true' : 'false') + '">\\n' +
2636        indent(s.code, 8) + '\\n      </div>';
2637    }).join('\\n');
2638
2639    var dotsHtml = filled.map(function (_, i) {
2640      return '          <button type="button" class="ec-dot' + (i === 0 ? ' is-active' : '') +
2641        '" aria-label="Go to slide ' + (i + 1) + '"></button>';
2642    }).join('\\n');
2643
2644    var controlsHtml = multi
2645      ? '    <div class="ec-controls">\\n' +
2646        '      <button type="button" class="ec-prev" aria-label="Previous clip">‹</button>\\n' +
2647        '      <div class="ec-dots">\\n' + dotsHtml + '\\n      </div>\\n' +
2648        '      <button type="button" class="ec-next" aria-label="Next clip">›</button>\\n' +
2649        '    </div>\\n'
2650      : '';
2651
2652    var controlsCss = multi
2653      ? '    #' + uid + ' { display: flex; flex-direction: column; width: 100%; max-width: 680px; margin: 0 auto; box-sizing: border-box; gap: 14px; }\\n' +
2654        '    #' + uid + ' .ec-controls { order: -1; display: flex; align-items: center; justify-content: center; gap: 12px; margin: 0 auto 4px auto; padding: 5px 14px; background: #f8fafc; border: 1px solid #e2e8f0; border-radius: 9999px; box-shadow: 0 1px 3px rgba(0, 0, 0, 0.04); width: fit-content; }\\n' +
2655        '    #' + uid + ' .ec-prev, #' + uid + ' .ec-next { width: 36px; height: 36px; border-radius: 50%; border: 1px solid #cbd5e1; background: #ffffff; color: #1e293b; cursor: pointer; font-size: 18px; font-weight: 600; line-height: 1; display: flex; align-items: center; justify-content: center; box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05); transition: all 0.15s ease; }\\n' +
2656        '    #' + uid + ' .ec-prev:hover, #' + uid + ' .ec-next:hover { border-color: #2563eb; background: #2563eb; color: #ffffff; transform: translateY(-1px); box-shadow: 0 4px 10px rgba(37, 99, 235, 0.25); }\\n' +
2657        '    #' + uid + ' .ec-prev:active, #' + uid + ' .ec-next:active { transform: translateY(0px) scale(0.95); }\\n' +
2658        '    #' + uid + ' .ec-dots { display: flex; align-items: center; gap: 7px; padding: 0 4px; }\\n' +
2659        '    #' + uid + ' .ec-dots button { width: 8px; height: 8px; border-radius: 50%; border: none; background: #cbd5e1; padding: 0; cursor: pointer; transition: all 0.2s cubic-bezier(0.16, 1, 0.3, 1); }\\n' +
2660        '    #' + uid + ' .ec-dots button.is-active { background: #2563eb; width: 22px; border-radius: 9999px; }\\n' +
2661        '    #' + uid + ' .ec-viewport { order: 1; position: relative; overflow: auto; -webkit-overflow-scrolling: touch; border-radius: 14px; background: #ffffff; box-shadow: 0 4px 20px -2px rgba(0, 0, 0, 0.08), 0 2px 6px -1px rgba(0, 0, 0, 0.04); border: 1px solid #e2e8f0; width: 100%; min-width: 280px; min-height: 180px; padding: 12px; box-sizing: border-box; resize: both; display: flex; flex-direction: column; align-items: stretch; justify-content: stretch; }\\n'
2662      : '    #' + uid + ' { width: 100%; max-width: 680px; margin: 0 auto; box-sizing: border-box; }\\n' +
2663        '    #' + uid + ' .ec-viewport { position: relative; overflow: auto; -webkit-overflow-scrolling: touch; border-radius: 14px; background: #ffffff; box-shadow: 0 4px 20px -2px rgba(0, 0, 0, 0.08), 0 2px 6px -1px rgba(0, 0, 0, 0.04); border: 1px solid #e2e8f0; width: 100%; min-width: 280px; min-height: 180px; padding: 12px; box-sizing: border-box; resize: both; display: flex; flex-direction: column; align-items: stretch; justify-content: stretch; }\\n';
2664
2665    var script = multi
2666      ? '  <script>\\n' +
2667        '  (function () {\\n' +
2668        '    var root = document.getElementById(\\'' + uid + '\\');\\n' +
2669        '    if (!root) return;\\n' +
2670        '    var slides = root.querySelectorAll(\\'.ec-slide\\');\\n' +
2671        '    var dots = root.querySelectorAll(\\'.ec-dot\\');\\n' +
2672        '    var prev = root.querySelector(\\'.ec-prev\\');\\n' +
2673        '    var next = root.querySelector(\\'.ec-next\\');\\n' +
2674        '    var idx = 0;\\n' +
2675        '    function show(i) {\\n' +
2676        '      idx = (i + slides.length) % slides.length;\\n' +
2677        '      for (var j = 0; j < slides.length; j++) slides[j].setAttribute(\\'data-active\\', j === idx ? \\'true\\' : \\'false\\');\\n' +
2678        '      for (var k = 0; k < dots.length; k++) dots[k].classList.toggle(\\'is-active\\', k === idx);\\n' +
2679        '    }\\n' +
2680        '    if (prev) prev.addEventListener(\\'click\\', function () { show(idx - 1); });\\n' +
2681        '    if (next) next.addEventListener(\\'click\\', function () { show(idx + 1); });\\n' +
2682        '    for (var d = 0; d < dots.length; d++) {\\n' +
2683        '      (function (n) { dots[n].addEventListener(\\'click\\', function () { show(n); }); })(d);\\n' +
2684        '    }\\n' +
2685        '    root.setAttribute(\\'tabindex\\', \\'0\\');\\n' +
2686        '    root.addEventListener(\\'keydown\\', function (e) {\\n' +
2687        '      if (e.key === \\'ArrowLeft\\') show(idx - 1);\\n' +
2688        '      if (e.key === \\'ArrowRight\\') show(idx + 1);\\n' +
2689        '    });\\n' +
2690        '    var startX = 0;\\n' +
2691        '    root.addEventListener(\\'touchstart\\', function (e) { if (e.touches[0]) startX = e.touches[0].clientX; }, { passive: true });\\n' +
2692        '    root.addEventListener(\\'touchend\\', function (e) {\\n' +
2693        '      if (!e.changedTouches[0]) return;\\n' +
2694        '      var diffX = e.changedTouches[0].clientX - startX;\\n' +
2695        '      if (Math.abs(diffX) > 45) {\\n' +
2696        '        if (diffX > 0) show(idx - 1); else show(idx + 1);\\n' +
2697        '      }\\n' +
2698        '    }, { passive: true });\\n' +
2699        '  })();\\n' +
2700        '  <' + '/script>'
2701      : '';
2702
2703    var viewportStyle = '';
2704    if (carouselWidth || carouselHeight) {
2705      var vpParts = [];
2706      if (carouselWidth) vpParts.push('width: ' + carouselWidth + 'px');
2707      if (carouselHeight) vpParts.push('height: ' + carouselHeight + 'px');
2708      viewportStyle = ' style="' + vpParts.join('; ') + ';"';
2709    }
2710
2711    return '<!DOCTYPE html>\\n' +
2712      '<html lang="en">\\n' +
2713      '<head>\\n' +
2714      '  <meta charset="UTF-8">\\n' +
2715      '  <meta name="viewport" content="width=device-width, initial-scale=1.0">\\n' +
2716      '  <title>Embed Carousel</title>\\n' +
2717      '  <style>\\n' +
2718      '    html, body {\\n' +
2719      '      margin: 0;\\n' +
2720      '      padding: 24px 16px;\\n' +
2721      '      font-family: system-ui, -apple-system, sans-serif;\\n' +
2722      '      background-color: #f1f5f9;\\n' +
2723      '      min-height: 100vh;\\n' +
2724      '      display: flex;\\n' +
2725      '      flex-direction: column;\\n' +
2726      '      align-items: center;\\n' +
2727      '      box-sizing: border-box;\\n' +
2728      '      overflow-x: hidden;\\n' +
2729      '      overflow-y: auto;\\n' +
2730      '    }\\n' +
2731      '    *, *::before, *::after { box-sizing: border-box; }\\n' +
2732      '    #' + uid + ' { width: 100%; max-width: 680px; margin: 0 auto; box-sizing: border-box; }\\n' +
2733      '    #' + uid + ' .ec-slide { display: none; width: 100%; height: 100%; min-height: 100%; align-items: stretch; justify-content: stretch; overflow: auto; -webkit-overflow-scrolling: touch; }\\n' +
2734      '    #' + uid + ' .ec-slide[data-active="true"] { display: flex; flex-direction: column; }\\n' +
2735      '    #' + uid + ' .ec-slide > * { width: 100% !important; height: 100% !important; min-height: 0 !important; max-width: 100% !important; max-height: 100% !important; flex: 1 1 auto !important; box-sizing: border-box !important; }\\n' +
2736      '    #' + uid + ' .ec-slide iframe, #' + uid + ' .ec-slide video, #' + uid + ' .ec-slide embed, #' + uid + ' .ec-slide object { width: 100% !important; height: 100% !important; min-height: 0 !important; flex: 1 1 auto !important; border: 0 !important; border-radius: 10px; display: block; margin: 0 auto; }\\n' +
2737      '    #' + uid + ' .ec-slide img { width: 100% !important; height: 100% !important; object-fit: contain !important; min-height: 0 !important; flex: 1 1 auto !important; border: 0 !important; border-radius: 10px; display: block; margin: 0 auto; }\\n' +
2738      '    #' + uid + ' .ec-slide blockquote { width: 100% !important; max-width: 100% !important; max-height: 100% !important; overflow: auto !important; border: 0 !important; border-radius: 10px; display: block; margin: 0 auto; }\\n' +
2739      '    #' + uid + ' .ec-slide div > iframe, #' + uid + ' .ec-slide div > video, #' + uid + ' .ec-slide div > embed, #' + uid + ' .ec-slide div > object { width: 100% !important; height: 100% !important; min-height: 0 !important; }\\n' +
2740      '    #' + uid + ' .ec-slide div > img { width: 100% !important; height: 100% !important; object-fit: contain !important; }\\n' +
2741      controlsCss +
2742      '  </style>\\n' +
2743      '</head>\\n' +
2744      '<body>\\n' +
2745      '  <div class="ec" id="' + uid + '">\\n' +
2746      controlsHtml +
2747      '    <div class="ec-viewport"' + viewportStyle + '>\\n' + slidesHtml + '\\n    </div>\\n' +
2748      '  </div>\\n' +
2749      (script ? '\\n' + script + '\\n' : '') +
2750      '</body>\\n' +
2751      '</html>';
2752  }
2753
2754  function renderCode() {
2755    var html;
2756    var filename;
2757    if (layoutMode === 'carousel') {
2758      html = buildCarouselHTML();
2759      filename = 'carousel.html';
2760    } else if (layoutMode === 'masonry') {
2761      html = buildMasonryHTML();
2762      filename = 'masonry.html';
2763    } else {
2764      html = buildRowHTML();
2765      filename = 'row.html';
2766    }
2767
2768    codeOut.textContent = html;
2769    codeOut.dataset.raw = html;
2770    codeFileLabel.textContent = filename;
2771  }
2772
2773  var debounceHandle = null;
2774  function onInput() {
2775    saveSlots();
2776    updateStatuses();
2777    clearTimeout(debounceHandle);
2778    debounceHandle = setTimeout(renderPreview, 350);
2779    if (outputSection.style.display !== 'none') renderCode();
2780  }
2781
2782  document.getElementById('generateBtn').addEventListener('click', function () {
2783    renderCode();
2784    outputSection.style.display = '';
2785    outputSection.scrollIntoView({ behavior: 'smooth', block: 'nearest' });
2786  });
2787
2788  var convoBtn = document.getElementById('convoBtn');
2789  if (convoBtn) {
2790    convoBtn.addEventListener('click', function () {
2791      var html = layoutMode === 'carousel' ? buildCarouselHTML() : (layoutMode === 'masonry' ? buildMasonryHTML() : buildRowHTML());
2792      
2793      convoBtn.disabled = true;
2794      var originalBtnContent = convoBtn.innerHTML;
2795      convoBtn.innerHTML = '<svg width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" style="animation:spin 1s linear infinite;"><circle cx="12" cy="12" r="10" stroke-opacity="0.25"></circle><path d="M12 2a10 10 0 0 1 10 10"></path></svg><span>Processing...</span>';
2796
2797      try {
2798        if (window.parent && window.parent !== window) {
2799          window.parent.postMessage({
2800            type: 'EZ_CREATE_CONVO_HTML',
2801            html: html,
2802            content_type: 'embed',
2803            isEdit: !!isEditMode,
2804            editId: editId,
2805            editSlug: editSlug
2806          }, '*');
2807          return;
2808        }
2809      } catch (e) {}
2810
2811      if (isEditMode && (editId || editSlug)) {
2812        var targetMsgIdentifier = editId || editSlug;
2813        fetch('/ai/message/' + encodeURIComponent(targetMsgIdentifier) + '/update-content', {
2814          method: 'PATCH',
2815          headers: headers,
2816          body: JSON.stringify({ content: html, content_type: 'embed' })
2817        })
2818        .then(function (res) { return res.json(); })
2819        .then(function (data) {
2820          if (data && data.success) {
2821            convoBtn.innerHTML = '<span>Updated!</span>';
2822            setTimeout(function () {
2823              convoBtn.disabled = false;
2824              convoBtn.innerHTML = originalBtnContent;
2825            }, 1500);
2826          } else {
2827            convoBtn.disabled = false;
2828            convoBtn.innerHTML = originalBtnContent;
2829            alert((data && data.error) || 'Failed to update embed content.');
2830          }
2831        })
2832        .catch(function (err) {
2833          console.error(err);
2834          convoBtn.disabled = false;
2835          convoBtn.innerHTML = originalBtnContent;
2836          alert('Failed to update embed content.');
2837        });
2838        return;
2839      }
2840
2841      var csrfToken = '';
2842      try {
2843        if (window.parent && window.parent.document) {
2844          var metaParent = window.parent.document.querySelector('meta[name="csrf-token"]');
2845          if (metaParent) csrfToken = metaParent.getAttribute('content') || '';
2846        }
2847      } catch (e) {}
2848      if (!csrfToken) {
2849        var metaLocal = document.querySelector('meta[name="csrf-token"]');
2850        if (metaLocal) csrfToken = metaLocal.getAttribute('content') || '';
2851      }
2852
2853      var headers = {
2854        'Content-Type': 'application/json',
2855        'Accept': 'application/json',
2856        'X-Requested-With': 'XMLHttpRequest'
2857      };
2858      if (csrfToken) {
2859        headers['X-CSRF-TOKEN'] = csrfToken;
2860      }
2861
2862      fetch('/content/comment', {
2863        method: 'POST',
2864        headers: headers,
2865        body: JSON.stringify({ content: html, content_type: 'embed' })
2866      })
2867      .then(function (res) {
2868        return res.json().catch(function () {
2869          return { success: res.ok, redirected: res.redirected, url: res.url };
2870        });
2871      })
2872      .then(function (data) {
2873        if (data && (data.slug || data.conversation_id)) {
2874          var targetSlug = data.slug || data.conversation_id;
2875          var targetUrl = '/X/' + encodeURIComponent(targetSlug);
2876          try {
2877            if (window.parent && window.parent !== window) {
2878              window.parent.location.href = targetUrl;
2879              return;
2880            }
2881          } catch (e) {}
2882          window.location.href = targetUrl;
2883        } else if (data && data.comment && data.comment.slug) {
2884          var targetUrl2 = '/X/' + encodeURIComponent(data.comment.slug);
2885          try {
2886            if (window.parent && window.parent !== window) {
2887              window.parent.location.href = targetUrl2;
2888              return;
2889            }
2890          } catch (e) {}
2891          window.location.href = targetUrl2;
2892        } else {
2893          submitFallbackForm(html, csrfToken);
2894        }
2895      })
2896      .catch(function () {
2897        submitFallbackForm(html, csrfToken);
2898      });
2899
2900      function submitFallbackForm(contentHtml, token) {
2901        try {
2902          var form = document.createElement('form');
2903          form.method = 'POST';
2904          form.action = '/content/comment';
2905          if (window.parent && window.parent !== window) {
2906            form.target = '_top';
2907          }
2908          if (token) {
2909            var tokenInput = document.createElement('input');
2910            tokenInput.type = 'hidden';
2911            tokenInput.name = '_token';
2912            tokenInput.value = token;
2913            form.appendChild(tokenInput);
2914          }
2915          var contentInput = document.createElement('input');
2916          contentInput.type = 'hidden';
2917          contentInput.name = 'content';
2918          contentInput.value = contentHtml;
2919          form.appendChild(contentInput);
2920          var contentTypeInput = document.createElement('input');
2921          contentTypeInput.type = 'hidden';
2922          contentTypeInput.name = 'content_type';
2923          contentTypeInput.value = 'embed';
2924          form.appendChild(contentTypeInput);
2925          document.body.appendChild(form);
2926          form.submit();
2927        } catch (err) {
2928          convoBtn.disabled = false;
2929          convoBtn.innerHTML = originalBtnContent;
2930          alert('Failed to save conversation. Please try again.');
2931        }
2932      }
2933    });
2934  }
2935
2936  document.getElementById('resetBtn').addEventListener('click', function () {
2937    slotsData.forEach(function (obj) {
2938      obj.input.value = '';
2939      obj.customWidth = null;
2940      obj.customHeight = null;
2941    });
2942    carouselWidth = null;
2943    carouselHeight = null;
2944    saveSlots();
2945    updateStatuses();
2946    renderPreview();
2947    outputSection.style.display = 'none';
2948  });
2949
2950  var copyBtn = document.getElementById('copyBtn');
2951  copyBtn.addEventListener('click', function () {
2952    var text = codeOut.dataset.raw || codeOut.textContent || '';
2953    function showCopied() {
2954      var original = 'Copy code';
2955      copyBtn.textContent = 'Copied ✓';
2956      copyBtn.classList.add('copied');
2957      setTimeout(function () {
2958        copyBtn.textContent = original;
2959        copyBtn.classList.remove('copied');
2960      }, 1600);
2961    }
2962    function fallbackCopy() {
2963      try {
2964        var ta = document.createElement('textarea');
2965        ta.value = text;
2966        ta.style.position = 'fixed';
2967        ta.style.opacity = '0';
2968        document.body.appendChild(ta);
2969        ta.focus();
2970        ta.select();
2971        var ok = document.execCommand('copy');
2972        document.body.removeChild(ta);
2973        if (ok) { showCopied(); return; }
2974      } catch (e) {}
2975      copyBtn.textContent = 'Select & press ⌘/Ctrl+C';
2976      setTimeout(function () { copyBtn.textContent = 'Copy code'; }, 2200);
2977    }
2978    if (navigator.clipboard && navigator.clipboard.writeText) {
2979      navigator.clipboard.writeText(text).then(showCopied, fallbackCopy);
2980    } else {
2981      fallbackCopy();
2982    }
2983  });
2984
2985  initTheme();
2986  loadMasonryConfig();
2987  loadSlots();
2988  try {
2989    if (window.parent && window.parent !== window) {
2990      window.parent.postMessage({ type: 'EZ_BUILDER_READY' }, '*');
2991    }
2992  } catch (e) {}
2993})();
2994<\/script>
2995
2996</body>
2997</html>`,Ve=({isOpen:o,onClose:d,parentSlug:v,conversationId:a,onChildConvoCreated:M,onCommentCreated:y,isEdit:C=!1,editId:p,editSlug:b,initialHtml:w,onUpdate:j})=>{const f=n.useRef(null),h=n.useCallback(()=>{f.current&&f.current.contentWindow&&f.current.contentWindow.postMessage({type:"EZ_SET_EDIT_MODE",isEdit:!!C,editId:p||null,editSlug:b||null,initialHtml:w||""},"*")},[C,p,b,w]);if(n.useEffect(()=>{if(!o)return;const c=setTimeout(h,100),r=setTimeout(h,300),k=setTimeout(h,600),E=setTimeout(h,1200);return()=>{clearTimeout(c),clearTimeout(r),clearTimeout(k),clearTimeout(E)}},[o,h]),n.useEffect(()=>{if(!o)return;const c=async r=>{var k;if(!(!f.current||!f.current.contentWindow)&&r.source===f.current.contentWindow){if(r.data&&r.data.type==="EZ_BUILDER_READY"){h();return}if(r.data&&r.data.type==="EZ_CREATE_CONVO_HTML"&&r.data.html){const E=r.data.html;if(C||j||r.data.isEdit){if(j)try{await j(E),d();return}catch(s){console.error("Failed in onUpdate:",s)}const x=p||r.data.editId||b||r.data.editSlug||v;if(x)try{const s=await ee.patch(`/ai/message/${x}/update-content`,{content:E,content_type:"embed"});if(s.data&&s.data.success){window.dispatchEvent(new CustomEvent("ez:conversation-updated",{detail:s.data})),d();return}}catch(s){console.error("Failed to update embed message:",s)}return}if(M)try{await M(E,"embed"),d();return}catch(x){console.error("Failed in onChildConvoCreated:",x)}try{const x={content:E,content_type:"embed",parent_slug:null,conversation_id:a||null},s=await ee.post("/content/comment",x,{headers:{Accept:"application/json","X-CSRF-TOKEN":((k=document.querySelector('meta[name="csrf-token"]'))==null?void 0:k.getAttribute("content"))||""}});if(s.data&&s.data.success){if(y&&s.data.conversation_messages){y(s.data.conversation_messages),d();return}if(v||a){d(),window.dispatchEvent(new CustomEvent("ez:conversation-updated",{detail:s.data}));return}s.data.slug?window.location.href="/X/"+encodeURIComponent(s.data.slug):s.data.conversation_id&&(window.location.href="/X/"+encodeURIComponent(s.data.conversation_id))}}catch(x){console.error("Failed to create conversation from message:",x)}}}};return window.addEventListener("message",c),()=>window.removeEventListener("message",c)},[o,d,v,a,M,y,C,p,b,j,h]),n.useEffect(()=>{if(!o)return;const c=r=>{r.key==="Escape"&&d()};return window.addEventListener("keydown",c),()=>window.removeEventListener("keydown",c)},[o,d]),!o)return null;const _=()=>{try{const c=new Blob([Q],{type:"text/html;charset=utf-8"}),r=URL.createObjectURL(c),k=window.open(r,"_blank");k&&k.focus()}catch{const c=window.open();c&&(c.document.open(),c.document.write(Q),c.document.close())}},Y=()=>{f.current&&f.current.contentWindow&&f.current.contentWindow.postMessage({type:"EZ_TRIGGER_SAVE"},"*")};return t.jsx("div",{className:"fixed inset-0 z-[100000] bg-black/80 backdrop-blur-md flex items-center justify-center p-2 sm:p-4 md:p-6 animate-in fade-in duration-200",onClick:d,children:t.jsxs("div",{className:"flex flex-col w-full max-w-[1240px] h-[92vh] max-h-[920px] bg-slate-900 rounded-2xl shadow-2xl overflow-hidden border border-slate-700/80 transition-all duration-300",onClick:c=>c.stopPropagation(),children:[t.jsxs("div",{className:"bg-slate-950 px-5 py-3 flex items-center justify-between border-b border-slate-800 select-none",children:[t.jsxs("div",{className:"flex items-center space-x-3",children:[t.jsxs("div",{className:"flex items-center space-x-1.5",children:[t.jsx("button",{type:"button",onClick:d,className:"w-3.5 h-3.5 rounded-full bg-[#ff5f56] hover:opacity-80 transition-opacity cursor-pointer border-0",title:"Close popup"}),t.jsx("span",{className:"w-3.5 h-3.5 rounded-full bg-[#ffbd2e] inline-block"}),t.jsx("span",{className:"w-3.5 h-3.5 rounded-full bg-[#27c93f] inline-block"})]}),t.jsx("div",{className:"h-4 w-px bg-slate-800 mx-1"}),t.jsxs("div",{className:"flex items-center space-x-2",children:[t.jsx(T,{icon:Ke,className:"text-orange-500 text-sm"}),t.jsx("span",{className:"text-sm font-bold text-white tracking-wide",children:"Embed Row & Masonry Builder"})]})]}),t.jsxs("div",{className:"flex items-center gap-2",children:[t.jsxs("button",{type:"button",onClick:Y,className:"px-3 py-1.5 text-xs rounded-lg bg-emerald-600 hover:bg-emerald-500 text-white font-medium flex items-center gap-1.5 transition-colors cursor-pointer",title:"Save and create conversation",children:[t.jsx(T,{icon:Ce}),t.jsx("span",{children:"Save"})]}),t.jsxs("button",{type:"button",onClick:_,className:"px-3 py-1.5 text-xs rounded-lg bg-slate-800 hover:bg-slate-700 text-emerald-400 hover:text-emerald-300 transition-colors flex items-center gap-1.5 font-medium border border-slate-700 cursor-pointer",title:"Open in a new tab",children:[t.jsx(T,{icon:Ee}),t.jsx("span",{className:"hidden sm:inline",children:"Open Tab"})]}),t.jsxs("button",{type:"button",onClick:d,className:"px-3 py-1.5 text-xs rounded-lg bg-rose-600 hover:bg-rose-700 text-white font-medium flex items-center gap-1.5 transition-colors cursor-pointer",title:"Close modal",children:[t.jsx(T,{icon:Me}),t.jsx("span",{children:"Close"})]})]})]}),t.jsx("div",{className:"flex-1 w-full h-full bg-white relative overflow-hidden",children:t.jsx("iframe",{ref:f,srcDoc:Q,title:"Embed Row & Masonry Builder",className:"w-full h-full border-0 block",style:{backgroundColor:"#f3f4f1"},sandbox:"allow-scripts allow-same-origin allow-popups allow-forms allow-modals",allow:"autoplay; clipboard-write; encrypted-media; picture-in-picture; web-share; fullscreen",allowFullScreen:!0,onLoad:h})})]})})},A={width:120,height:120,padding:20},Je=.25,Qe=350,et=2e3,de=4,ce=[{id:"1",angleStart:288,angleEnd:360,label:"1",color:"#f43f5e",gradient:["#f43f5e","#e11d48"],labelAngle:324},{id:"2",angleStart:0,angleEnd:72,label:"2",color:"#f59e0b",gradient:["#f59e0b","#d97706"],labelAngle:36},{id:"3",angleStart:72,angleEnd:144,label:"3",color:"#10b981",gradient:["#10b981","#059669"],labelAngle:108},{id:"4",angleStart:144,angleEnd:216,label:"4",color:"#3b82f6",gradient:["#3b82f6","#2563eb"],labelAngle:180},{id:"5",angleStart:216,angleEnd:288,label:"5",color:"#8b5cf6",gradient:["#8b5cf6","#7c3aed"],labelAngle:252}].map(o=>{const d=o.labelAngle*Math.PI/180,v=32,a=o.angleStart*Math.PI/180,M=o.angleEnd*Math.PI/180,y=(50+46*Math.cos(a)).toFixed(2),C=(50+46*Math.sin(a)).toFixed(2),p=(50+46*Math.cos(M)).toFixed(2),b=(50+46*Math.sin(M)).toFixed(2),w=`M 50 50 L ${y} ${C} A 46 46 0 0 1 ${p} ${b} Z`;return{...o,pathData:w,x:(50+v*Math.cos(d)).toFixed(2),y:(50+v*Math.sin(d)).toFixed(2)}}),tt={1:{bg:"linear-gradient(135deg, rgba(244,63,94,0.95), rgba(225,29,72,0.95))",glow:"rgba(244,63,94,0.35)",border:"rgba(244,63,94,0.6)"}
2997,2:{bg:"linear-gradient(135deg, rgba(245,158,11,0.95), rgba(217,119,6,0.95))",glow:"rgba(245,158,11,0.35)",border:"rgba(245,158,11,0.6)"},3:{bg:"linear-gradient(135deg, rgba(16,185,129,0.95), rgba(5,150,105,0.95))",glow:"rgba(16,185,129,0.35)",border:"rgba(16,185,129,0.6)"},4:{bg:"linear-gradient(135deg, rgba(59,130,246,0.95), rgba(37,99,235,0.95))",glow:"rgba(59,130,246,0.35)",border:"rgba(59,130,246,0.6)"},5:{bg:"linear-gradient(135deg, rgba(139,92,246,0.95), rgba(124,58,237,0.95))",glow:"rgba(139,92,246,0.35)",border:"rgba(139,92,246,0.6)"}},nt=({message:o,visible:d})=>t.jsxs("div",{id:"click-message",className:d?"visible":"",role:"status","aria-live":"polite",children:[t.jsx("div",{className:"msg-icon",children:"✦"}),t.jsx("span",{children:o})]}),at=({onLogoClick:o,onAvatarClick:d,isTopCorner:v})=>t.jsxs("div",{className:`logo-section-container absolute left-1/2 -translate-x-1/2 flex flex-col items-center gap-2.5 pointer-events-auto z-30 transition-all duration-500 ${v?"top-[calc(100%+14px)]":"bottom-[calc(100%+14px)]"}`,onPointerDown:a=>a.stopPropagation(),onMouseDown:a=>a.stopPropagation(),onTouchStart:a=>a.stopPropagation(),children:[t.jsxs("div",{className:"w-[3.6rem] h-[3.6rem] rounded-full flex items-center justify-center overflow-hidden relative avatar-glow cursor-pointer hover:scale-105 active:scale-95 transition-transform",onClick:d,onPointerDown:a=>a.stopPropagation(),onMouseDown:a=>a.stopPropagation(),onTouchStart:a=>a.stopPropagation(),role:"button",tabIndex:0,"aria-label":"Open Embed Row & Masonry Builder",title:"Click to open Embed Row & Masonry Builder",onKeyDown:a=>{(a.key==="Enter"||a.key===" ")&&(a.preventDefault(),d(a))},children:[t.jsx("div",{className:"absolute inset-0 rounded-full bg-gradient-to-tr from-[#059669] via-[#34d399] to-[#10b981] opacity-90"}),t.jsx("img",{src:"https://ez.wiki/logo.gif",className:"w-[78%] h-[78%] object-contain relative z-10 filter drop-shadow-lg pointer-events-none",alt:"ez.wiki Logo"})]}),t.jsx("div",{className:"split-logo",children:t.jsx("span",{className:"logo-ez cursor-pointer select-none",onClick:a=>o(a,"/dashboard","EZ Dashboard"),role:"button",tabIndex:0,onKeyDown:a=>{(a.key==="Enter"||a.key===" ")&&o(a,"/dashboard","EZ Dashboard")},children:"EZ.WIKI"})})]}),lt=({auth:o,parentSlug:d,conversationId:v,onChildConvoCreated:a,onCommentCreated:M})=>{const y=n.useRef(null),C=n.useRef(null),p=n.useRef(null),b=n.useRef(null),w=n.useRef(),[j,f]=n.useState("0.00"),[h,_]=n.useState(!1),[Y,c]=n.useState(null),[r,k]=n.useState(null),[E,x]=n.useState({visible:!1,text:""}),[s,te]=n.useState(!1),[ne,ae]=n.useState(!1),[q,oe]=n.useState(null),[P,pe]=n.useState("br"),[I,ue]=n.useState(null),[F,me]=n.useState({width:window.innerWidth,height:window.innerHeight}),[X,fe]=n.useState(!1);n.useEffect(()=>{fe(!0)},[]),n.useEffect(()=>{let e=!0;return(async()=>{if(o!=null&&o.user){_(!0),c(null);try{const m=await ee.get("/buy-bee/balance");e&&f(Number(m.data.balance||0).toFixed(2))}catch{e&&(f("0.00"),c("Failed to load balance"))}finally{e&&_(!1)}}})(),()=>{e=!1}},[o==null?void 0:o.user]),n.useEffect(()=>{const e=()=>me({width:window.innerWidth,height:window.innerHeight});return window.addEventListener("resize",e),()=>window.removeEventListener("resize",e)},[]),n.useEffect(()=>()=>{w.current&&clearTimeout(w.current)},[]);const $=n.useMemo(()=>h?"Loading...":Y?"--.-- EZ$":`${j} EZ$`,[h,Y,j]),ge=n.useMemo(()=>{const e=[{href:"/",action:"HOME",icon:le,label:"Home"},{href:"/login",action:"SIGN IN",icon:Ie,label:"Sign In"},{href:"/register",action:"SIGN UP",icon:Be,label:"Sign Up"}];return o!=null&&o.user?{1:[{href:"/aihome",action:"HOME",icon:le,label:"Home"},{href:"/dashboard",action:"DASHBOARD",icon:Ue,label:"Dashboard"},{href:"/settings/profile",action:"PROFILE",icon:Xe,label:"Profile"},{href:"/purchase",action:$,icon:$e,label:$}],2:[{href:"/sendbee",action:"Send EZ$",icon:qe,label:"Send EZ$"},{href:"/purchasehistory",action:"EZ$ Purchase History",icon:Fe,label:"EZ$ Purchase History"},{href:"/ez-transfer",action:"EZ TRANSFER",icon:We,label:"EZ Transfer"},{href:"/transfer/history",action:"EZ TRANSFER HISTORY",icon:Ge,label:"Transfer History"}],3:[{href:"/marketplace",action:"DOMAIN MART",icon:Ne,label:"Domain Mart"},{href:"/my-coupons",action:"Coupon Usage",icon:Oe,label:"Coupon Usage"},{href:"/handlepurchasehistory",action:"Handle Purchase History",icon:_e,label:"Handle Purchase History"},{href:"/handlesellhistory",action:"Handle Sell History",icon:Ye,label:"Handle Sell History"}],4:[{href:"/token-transactions",action:"EZ$ Transaction History",icon:Ae,label:"EZ$ Transaction History"},{href:"/incentivehistory",action:"Incentive History",icon:Te,label:"Incentive History"},{href:"/pending-transfers",action:"Pending Transaction",icon:De,label:"Pending Transaction"},{href:"/refund-transfers",action:"Refund History",icon:ze,label:"Refund History"}],5:[{href:"/",action:"New Conversation",icon:Re,label:"New Conversation"},{href:"/public/ai/history",action:"Slug Wall",icon:je,label:"Slug Wall"},{href:"/ai/history",action:"Slug Management",icon:Pe,label:"Slug Management"},{href:"/domains",action:"Domain Management",icon:He,label:"Domain Management"},{href:"/logout",action:"Logout",icon:Le,label:"Logout",method:"post",isDestructive:!0}]}:{1:e,2:e,3:e,4:e,5:e}},[o==null?void 0:o.user,$]),Z=n.useMemo(()=>
2997{if(P)return P;if(I){const e=I.left+A.width/2,l=I.top+A.height/2,{width:m,height:S}=F;return l<S/2?e<m/2?"tl":"tr":e<m/2?"bl":"br"}return"br"},[P,I,F]),K=Z==="tr"||Z==="tl",B=n.useCallback(()=>k(null),[]),W=n.useCallback(e=>{k(l=>l===e?null:e)},[]),re=n.useCallback(e=>{w.current&&clearTimeout(w.current),x({visible:!0,text:e}),w.current=setTimeout(()=>{x(l=>({...l,visible:!1}))},et)},[]),G=n.useCallback((e,l,m="get")=>{re(`Navigating to ${l}...`),B(),setTimeout(()=>{m==="post"?se.post(e):se.visit(e)},Qe)},[B,re]),ie=n.useCallback((e,l,m,S="get")=>{e.preventDefault(),e.stopPropagation(),G(m,l,S)},[G]),be=n.useCallback((e,l,m)=>{e.preventDefault(),e.stopPropagation(),G(l,m)},[G]),he=n.useCallback(e=>{e.preventDefault(),e.stopPropagation(),B(),ae(!0)},[B]),xe=n.useCallback(e=>{(e.key==="Enter"||e.key===" ")&&(e.preventDefault(),W(r||"1"))},[r,W]);n.useEffect(()=>{const e=C.current,l=y.current;if(!e||!l)return;const m=i=>{if(!p.current)return;const g=i.clientX-p.current.pointerX,u=i.clientY-p.current.pointerY;if(!p.current.hasMoved&&(Math.abs(g)>de||Math.abs(u)>de)&&(p.current.hasMoved=!0,te(!0),B()),p.current.hasMoved){let D=p.current.elementY+u,z=p.current.elementX+g;const{width:V,height:J}=F,N=l.offsetWidth||120,O=l.offsetHeight||120;z=Math.max(A.padding,Math.min(z,V-N-A.padding)),D=Math.max(A.padding,Math.min(D,J-O-A.padding));const U={top:D,left:z};oe(U),b.current=U}},S=i=>{var g;window.removeEventListener("pointermove",m),window.removeEventListener("pointerup",S);try{e.releasePointerCapture(i.pointerId)}catch{}if((g=p.current)!=null&&g.hasMoved)b.current&&(ue(b.current),pe(null));else{const u=e.getBoundingClientRect(),D=i.clientX-u.left,z=i.clientY-u.top,V=u.width/2,J=u.height/2,N=D-V,O=z-J,U=Math.sqrt(N*N+O*O),we=u.width*Je;if(U>=we){const R=(Math.atan2(O,N)*(180/Math.PI)+360)%360;let L;R>=288||R<18?L="1":R>=18&&R<90?L="2":R>=90&&R<162?L="3":R>=162&&R<234?L="4":L="5",W(L)}}p.current=null,te(!1),oe(null),b.current=null},H=i=>{if(i.button!==0)return;const g=i.target;if(g&&g.closest(".logo-section-container, .avatar-glow, .split-logo, .logo-ez, .logo-wiki"))return;e.setPointerCapture(i.pointerId);const u=l.getBoundingClientRect();p.current={pointerX:i.clientX,pointerY:i.clientY,elementX:u.left,elementY:u.top,hasMoved:!1},window.addEventListener("pointermove",m),window.addEventListener("pointerup",S)};return e.addEventListener("pointerdown",H),()=>{e.removeEventListener("pointerdown",H),window.removeEventListener("pointermove",m),window.removeEventListener("pointerup",S)}},[B,W,F]),n.useEffect(()=>{if(!r)return;const e=l=>{s||y.current&&!y.current.contains(l.target)&&B()};return document.addEventListener("mousedown",e),document.addEventListener("touchstart",e),()=>{document.removeEventListener("mousedown",e),document.removeEventListener("touchstart",e)}},[r,B,s]);const ve=n.useCallback(()=>{const e="24px";return s&&q?{position:"fixed",transform:`translate3d(${q.left}px, ${q.top}px, 0)`,transition:"none",zIndex:9999}:I?{position:"fixed",top:`${I.top}px`,left:`${I.left}px`,transition:"none"}:{position:"fixed",...P?{br:{bottom:e,right:e},bl:{bottom:e,left:e},tr:{top:e,right:e},tl:{top:e,left:e}}[P]:{},transition:X?"all 0.5s cubic-bezier(0.23, 1, 0.32, 1)":"none"}},[s,q,I,P,X]),ye=n.useMemo(()=>{const e=["group z-50 select-none"];return r&&e.push(`q${r}-open`,"menu-open"),K&&e.push("tl-open","tr-open"),s&&e.push("dragging"),e.join(" ")},[r,K,s]);return t.jsxs(t.Fragment,{children:[t.jsxs(ke,{children:[t.jsx("meta",{name:"viewport",content:"width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no"}),t.jsx("style",{children:`
2998                    #draggable-menu-container {
2999                        z-index: 9999 !important;
3000                        backface-visibility: hidden;
3001                        will-change: transform, top, left, bottom, right;
3002                    }
3003
3004                    /* Ambient glow behind the button */
3005                    #draggable-menu-container::before {
3006                        content: '';
3007                        position: absolute;
3008                        inset: -20px;
3009                        border-radius: 50%;
3010                        background: radial-gradient(circle, rgba(52,211,153,0.15) 0%, transparent 70%);
3011                        pointer-events: none;
3012                        z-index: -1;
3013                        opacity: 0;
3014                        transition: opacity 0.5s ease;
3015                    }
3016
3017                    #draggable-menu-container.menu-open::before {
3018                        opacity: 1;
3019                    }
3020
3021                    #main-button {
3022                        width: 7.6rem;
3023                        height: 7.6rem;
3024                        box-shadow:
3025                            0 0 0 1px rgba(255,255,255,0.1),
3026                            0 20px 50px rgba(0,0,0,0.4),
3027                            0 8px 20px rgba(0,0,0,0.3),
3028                            inset 0 1px 0 rgba(255,255,255,0.15),
3029                            inset 0 -1px 0 rgba(0,0,0,0.2);
3030                        transition: transform 0.4s cubic-bezier(0.23, 1, 0.32, 1), box-shadow 0.4s ease;
3031                        touch-action: none;
3032                        position: relative;
3033                        background: #0f172a;
3034                        border-radius: 9999px;
3035                        outline: none;
3036                        border: 2.5px solid rgba(255,255,255,0.9);
3037                        overflow: visible;
3038                    }
3039
3040                    #main-button:focus-visible {
3041                        box-shadow:
3042                            0 0 0 4px rgba(52,211,153,0.4),
3043                            0 20px 50px rgba(0,0,0,0.4),
3044                            inset 0 1px 0 rgba(255,255,255,0.15);
3045                    }
3046
3047                    #main-button:hover {
3048                        transform: scale(1.06);
3049                        box-shadow:
3050                            0 0 0 1px rgba(255,255,255,0.15),
3051                            0 25px 60px rgba(0,0,0,0.5),
3052                            0 0 30px rgba(52,211,153,0.25),
3053                            inset 0 1px 0 rgba(255,255,255,0.2);
3054                    }
3055
3056                    #main-button:active {
3057                        transform: scale(0.97);
3058                    }
3059
3060                    #main-button svg {
3061                        overflow: visible !important;
3062                    }
3063
3064                    /* Wedge slices with individual gradients */
3065                    .wedge-slice {
3066                        transition: all 0.25s cubic-bezier(0.23, 1, 0.32, 1);
3067                        stroke: rgba(255,255,255,0.35);
3068                        stroke-width: 1.5px;
3069                        cursor: pointer;
3070                        filter: drop-shadow(0 2px 4px rgba(0,0,0,0.3));
3071                    }
3072
3073                    .wedge-slice:hover {
3074                        filter: brightness(1.2) drop-shadow(0 0 12px rgba(255,255,255,0.6));
3075                        stroke: rgba(255,255,255,0.8);
3076                        stroke-width: 2px;
3077                    }
3078
3079                    /* Active wedge glow ring */
3080                    .active-wedge-ring {
3081                        opacity: 0;
3082                        transition: opacity 0.3s ease;
3083                        pointer-events: none;
3084                    }
3085
3086                    .group.q1-open .ring-q1,
3087                    .group.q2-open .ring-q2,
3088                    .group.q3-open .ring-q3,
3089                    .group.q4-open .ring-q4,
3090                    .group.q5-open .ring-q5 {
3091                        opacity: 1;
3092                    }
3093
3094                    /* Center hub */
3095                    .center-hub {
3096                        width: 30%;
3097                        height: 30%;
3098                        background: #0f172a;
3099                        border-radius: 50%;
3100                        border: 2px solid rgba(255,255,255,0.8);
3101                        z-index: 20;
3102                        display: flex;
3103                        align-items: center;
3104                        justify-content: center;
3105                        box-shadow:
3106                            inset 0 2px 8px rgba(0,0,0,0.5),
3107                            0 0 0 3px rgba(52,211,153,0.15),
3108                            0 2px 8px rgba(0,0,0,0.3);
3109                        pointer-events: none;
3110                        position: relative;
3111                    }
3112
3113                    .center-hub::after {
3114                        content: '';
3115                        position: absolute;
3116                        inset: -6px;
3117                        border-radius: 50%;
3118                        border: 1.5px solid rgba(52,211,153,0.3);
3119                        animation: hub-pulse 2.5s ease-in-out infinite;
3120                    }
3121
3122                    @keyframes hub-pulse {
3123                        0%, 100% { transform: scale(1); opacity: 0.6; }
3124                        50% { transform: scale(1.08); opacity: 0; }
3125                    }
3126
3127                    /* Menu items - color-coded per quadrant with glassmorphism */
3128                    .menu-item {
3129                        display: flex;
3130                        align-items: center;
3131                        gap: 0.75rem;
3132                        padding: 0.55rem 1rem;
3133                        border-radius: 1rem;
3134                        font-weight: 600;
3135                        transition: all 0.3s cubic-bezier(0.23, 1, 0.32, 1);
3136                        position: relative;
3137                        overflow: hidden;
3138                        min-width: 195px;
3139                        font-size: 0.8rem;
3140                        backdrop-filter: blur(24px) saturate(1.4);
3141                        -webkit-backdrop-filter: blur(24px) saturate(1.4);
3142                        border: 1px solid rgba(255,255,255,0.25);
3143                        border-top: 1px solid rgba(255,255,255,0.5);
3144                        color: #ffffff !important;
3145                        font-variant-numeric: tabular-nums;
3146                        text-shadow: 0 1px 3px rgba(0,0,0,0.25);
3147                        box-shadow:
3148                            0 8px 32px rgba(0,0,0,0.25),
3149                            inset 0 1px 0 rgba(255,255,255,0.25);
3150                    }
3151
3152                    .menu-item::before {
3153                        content: '';
3154                        position: absolute;
3155                        inset: 0;
3156                        border-radius: inherit;
3157                        opacity: 0;
3158                        transition: opacity 0.3s ease;
3159                        background: linear-gradient(135deg, rgba(255,255,255,0.15), transparent);
3160                    }
3161
3162                    .menu-item:hover::before,
3163                    .menu-item:focus-visible::before {
3164                        opacity: 1;
3165                    }
3166
3167                    .menu-item:hover, .menu-item:focus-visible {
3168                        transform: translateY(-3px) scale(1.03);
3169                        box-shadow:
3170                            0 16px 40px rgba(0,0,0,0.35),
3171                            0 0 20px var(--item-glow, rgba(16,185,129,0.3)),
3172                            inset 0 1px 0 rgba(255,255,255,0.4);
3173                        border-color: rgba(255,255,255,0.6) !important;
3174                    }
3175
3176                    .menu-item .icon-wrapper {
3177                        display: flex;
3178                        align-items: center;
3179                        justify-content: center;
3180                        width: 1.7rem;
3181                        height: 1.7rem;
3182                        font-size: 0.78rem;
3183                        border-radius: 0.55rem;
3184                        transition: all 0.3s cubic-bezier(0.23, 1, 0.32, 1);
3185                        background: rgba(255,255,255,0.18) !important;
3186                        border: 1px solid rgba(255,255,255,0.4);
3187                        color: #ffffff;
3188                        flex-shrink: 0;
3189                        box-shadow: inset 0 1px 2px rgba(255,255,255,0.1);
3190                    }
3191
3192                    .menu-item:hover .icon-wrapper,
3193                    .menu-item:focus-visible .icon-wrapper {
3194                        transform: scale(1.15) rotate(-6deg);
3195                        background: rgba(255,255,255,0.35) !important;
3196                        border-color: rgba(255,255,255,0.7) !important;
3197                        box-shadow: 0 0 12px rgba(255,255,255,0.4);
3198                    }
3199
3200                    .menu-item.destructive {
3201                        --item-glow: rgba(244,63,94,0.4);
3202                        background: linear-gradient(135deg, rgba(244,63,94,0.92), rgba(190,18,60,0.92)) !important;
3203                        border-color: rgba(244,63,94,0.4);
3204                    }
3205
3206                    .menu-item.destructive .icon-wrapper {
3207                        background: rgba(255,255,255,0.15) !important;
3208                        border-color: rgba(255,255,255,0.4) !important;
3209                    }
3210
3211                    .menu-item.destructive:hover {
3212                        background: linear-gradient(135deg, rgba(251,113,133,0.95), rgba(244,63,94,0.95)) !important;
3213                        border-color: rgba(255,255,255,0.6) !important;
3214                    }
3215
3216                    /* Staggered entrance animation */
3217                    @keyframes slide-in-blur {
3218                        0% { transform: translateY(12px) scale(0.92); opacity: 0; filter: blur(6px); }
3219                        100% { transform: translateY(0) scale(1); opacity: 1; filter: blur(0); }
3220                    }
3221
3222                    .quadrant-menu.open .menu-item {
3223                        animation: slide-in-blur 0.35s cubic-bezier(0.23, 1, 0.32, 1) both;
3224                    }
3225
3226                    .quadrant-menu.open .menu-item:nth-child(1) { animation-delay: 0.02s; }
3227                    .quadrant-menu.open .menu-item:nth-child(2) { animation-delay: 0.05s; }
3228                    .quadrant-menu.open .menu-item:nth-child(3) { animation-delay: 0.08s; }
3229                    .quadrant-menu.open .menu-item:nth-child(4) { animation-delay: 0.11s; }
3230                    .quadrant-menu.open .menu-item:nth-child(5) { animation-delay: 0.14s; }
3231                    .quadrant-menu.open .menu-item:nth-child(6) { animation-delay: 0.17s; }
3232
3233                    /* Float animation */
3234                    @keyframes float {
3235                        0%, 100% { transform: translateY(0); }
3236                        50% { transform: translateY(-6px); }
3237                    }
3238
3239                    #draggable-menu-container:not(.menu-open):not(.dragging) {
3240                        animation: float 5s ease-in-out infinite;
3241                    }
3242
3243                    #draggable-menu-container.dragging {
3244                        animation: none;
3245                        opacity: 0.88;
3246                        cursor: grabbing !important;
3247                    }
3248
3249                    #draggable-menu-container.dragging #main-button {
3250                        box-shadow:
3251                            0 0 0 2px rgba(52,211,153,0.3),
3252                            0 30px 70px rgba(0,0,0,0.5),
3253                            inset 0 1px 0 rgba(255,255,255,0.1);
3254                    }
3255
3256                    /* Click message / Toast */
3257                    #click-message {
3258                        position: fixed;
3259                        bottom: 2.5rem;
3260                        left: 50%;
3261                        transform: translate(-50%, 40px) scale(0.9);
3262                        padding: 0.7rem 1.6rem 0.7rem 1.2rem;
3263                        border-radius: 1rem;
3264                        font-weight: 600;
3265                        transition: all 0.4s cubic-bezier(0.23, 1, 0.32, 1);
3266                        background: rgba(15,23,42,0.92);
3267                        border: 1px solid rgba(52,211,153,0.4);
3268                        color: #ffffff;
3269                        backdrop-filter: blur(24px) saturate(1.3);
3270                        -webkit-backdrop-filter: blur(24px) saturate(1.3);
3271                        box-shadow:
3272                            0 20px 50px rgba(0,0,0,0.4),
3273                            0 0 30px rgba(52,211,153,0.15),
3274                            inset 0 1px 0 rgba(255,255,255,0.1);
3275                        opacity: 0;
3276                        pointer-events: none;
3277                        z-index: 10000;
3278                        font-size: 0.85rem;
3279                        text-shadow: 0 1px 2px rgba(0,0,0,0.2);
3280                        display: flex;
3281                        align-items: center;
3282                        gap: 0.5rem;
3283                        letter-spacing: 0.01em;
3284                    }
3285
3286                    #click-message .msg-icon {
3287                        width: 1.4rem;
3288                        height: 1.4rem;
3289                        display: flex;
3290                        align-items: center;
3291                        justify-content: center;
3292                        border-radius: 0.4rem;
3293                        background: rgba(52,211,153,0.2);
3294                        color: #34d399;
3295                        font-size: 0.75rem;
3296                        flex-shrink: 0;
3297                    }
3298
3299                    #click-message.visible {
3300                        transform: translate(-50%, 0) scale(1);
3301                        opacity: 1;
3302                    }
3303
3304                    /* Quadrant menus */
3305                    .quadrant-menu {
3306                        position: absolute;
3307                        display: none;
3308                        flex-direction: column;
3309                        gap: 0.35rem;
3310                        opacity: 0;
3311                        visibility: hidden;
3312                        pointer-events: none;
3313                        transition: opacity 0.25s ease, visibility 0s linear 0.25s, transform 0.3s ease;
3314                        z-index: 20;
3315                        max-height: calc(100vh - 160px);
3316                        overflow-y: auto;
3317                        padding: 6px;
3318                        scrollbar-width: none;
3319                    }
3320
3321                    .quadrant-menu.open {
3322                        display: flex;
3323                        opacity: 1;
3324                        visibility: visible;
3325                        pointer-events: auto;
3326                        transition-delay: 0s;
3327                    }
3328
3329                    .quadrant-menu::-webkit-scrollbar { display: none; }
3330
3331                    .group.open .quadrant-menu { pointer-events: auto; }
3332
3333                    .group.q1-open #menu-q1,
3334                    .group.q2-open #menu-q2,
3335                    .group.q3-open #menu-q3,
3336                    .group.q4-open #menu-q4,
3337                    .group.q5-open #menu-q5 {
3338                        display: flex;
3339                        opacity: 1;
3340                        visibility: visible;
3341                        pointer-events: auto;
3342                        transition-delay: 0s;
3343                    }
3344
3345                    .group.tr-open .quadrant-menu,
3346                    .group.tl-open .quadrant-menu {
3347                        flex-direction: column-reverse;
3348                    }
3349
3350                    /* Logo styling */
3351                    .split-logo {
3352                        display: flex;
3353                        gap: 0.35rem;
3354                        background: transparent;
3355                        position: relative;
3356                        z-index: 30;
3357                        pointer-events: auto;
3358                    }
3359
3360                    .logo-ez {
3361                        padding: 0.4rem 0.9rem;
3362                        border-radius: 9999px;
3363                        transition: all 0.3s cubic-bezier(0.23, 1, 0.32, 1);
3364                        font-weight: 800;
3365                        font-size: 0.68rem;
3366                        position: relative;
3367                        z-index: 31;
3368                        cursor: pointer;
3369                        text-align: center;
3370                        min-width: 3.2rem;
3371                        border: 1.5px solid rgba(255,255,255,0.5);
3372                        letter-spacing: 0.08em;
3373                        background: linear-gradient(135deg, #10b981, #047857);
3374                        color: #ffffff;
3375                        box-shadow:
3376                            0 4px 15px rgba(5,150,105,0.35),
3377                            0 0 10px rgba(52,211,153,0.15),
3378                            inset 0 1px 0 rgba(255,255,255,0.2);
3379                        text-shadow: 0 1px 2px rgba(0,0,0,0.2);
3380                    }
3381
3382                    .logo-ez:hover {
3383                        transform: translateY(-2px) scale(1.08);
3384                        filter: brightness(1.15);
3385                        box-shadow:
3386                            0 8px 25px rgba(5,150,105,0.45),
3387                            0 0 20px rgba(52,211,153,0.3),
3388                            inset 0 1px 0 rgba(255,255,255,0.3);
3389                        border-color: rgba(255,255,255,0.8);
3390                    }
3391
3392                    /* Avatar glow */
3393                    .avatar-glow {
3394                        box-shadow:
3395                            0 0 0 2px rgba(255,255,255,0.8),
3396                            0 0 25px rgba(52,211,153,0.5),
3397                            0 0 50px rgba(52,211,153,0.2);
3398                        animation: avatar-pulse 3s infinite ease-in-out;
3399                    }
3400
3401                    @keyframes avatar-pulse {
3402                        0%, 100% {
3403                            box-shadow:
3404                                0 0 0 2px rgba(255,255,255,0.8),
3405                                0 0 20px rgba(52,211,153,0.4),
3406                                0 0 40px rgba(52,211,153,0.15);
3407                        }
3408                        50% {
3409                            box-shadow:
3410                                0 0 0 2px rgba(255,255,255,0.9),
3411                                0 0 35px rgba(52,211,153,0.7),
3412                                0 0 70px rgba(52,211,153,0.3);
3413                        }
3414                    }
3415
3416                    /* Wedge numbers */
3417                    .wedge-number-outer {
3418                        font-family: 'SF Pro Display', system-ui, -apple-system, sans-serif;
3419                        text-anchor: middle;
3420                        dominant-baseline: central;
3421                        pointer-events: none;
3422                        font-size: 14px;
3423                        font-weight: 800;
3424                        fill: rgba(255,255,255,0.85);
3425                        transition: all 0.25s cubic-bezier(0.23, 1, 0.32, 1);
3426                        text-shadow: 0 1px 4px rgba(0,0,0,0.5);
3427                    }
3428
3429                    .active-num-1, .active-num-2, .active-num-3, .active-num-4, .active-num-5 {
3430                        fill: #ffffff !important;
3431                        opacity: 1 !important;
3432                        filter: drop-shadow(0 0 10px rgba(255,255,255,0.9));
3433                        font-size: 16px;
3434                        font-weight: 900;
3435                    }
3436                `})]}),t.jsx(nt,{message:E.text,visible:E.visible}),ne&&t.jsx(Ve,{isOpen:ne,onClose:()=>ae(!1),parentSlug:d,conversationId:v,onChildConvoCreated:a,onCommentCreated:M}),t.jsxs("div",{id:"draggable-menu-container",ref:y,className:ye,style:ve(),children:[t.jsxs("div",{id:"main-button",ref:C,className:`relative z-10 cursor-pointer flex items-center justify-center ${r?`q${r}-active`:""}`,role:"button","aria-label":"Quadrant Menu - Click to open, drag to move","aria-haspopup":"true","aria-expanded":!!r,tabIndex:0,onKeyDown:xe,children:[t.jsx(at,{onLogoClick:be,onAvatarClick:he,isTopCorner:K}),t.jsxs("svg",{viewBox:"0 0 100 100",className:"w-full h-full select-none absolute inset-0 overflow-visible pointer-events-none",children:[t.jsx("circle",{cx:"50",cy:"50",r:"49",fill:"none",stroke:"rgba(255,255,255,0.08)",strokeWidth:"0.5"}),t.jsx("circle",{cx:"50",cy:"50",r:"48",fill:"#0f172a"}),ce.map(e=>t.jsx("path",{d:e.pathData,fill:"none",stroke:e.color,strokeWidth:"3",className:`active-wedge-ring ring-q${e.id}`,style:{filter:`drop-shadow(0 0 8px ${e.color})`}},`ring-${e.id}`)),ce.map(e=>t.jsxs("g",{children:[t.jsx("defs",{children:t.jsxs("linearGradient",{id:`grad-${e.id}`,x1:"0%",y1:"0%",x2:"100%",y2:"100%",children:[t.jsx("stop",{offset:"0%",stopColor:e.gradient[0]}),t.jsx("stop",{offset:"100%",stopColor:e.gradient[1]})]})}),t.jsx("path",{d:e.pathData,fill:`url(#grad-${e.id})`,className:`wedge-slice ${r===e.id?"opacity-100":"opacity-90"}`}),t.jsx("text",{className:`wedge-number-outer ${r===e.id?`active-num-${e.id}`:""}`,x:e.x,y:e.y,children:e.label})]},e.id))]}),t.jsx("div",{className:"center-hub","aria-hidden":"true",children:t.jsx(T,{icon:Ze,className:"text-white/70 text-[10px]"})})]}),Object.entries(ge).map(([e,l])=>{const m={br:"bottom-full left-1/2 -translate-x-1/2 mb-4",bl:"bottom-full right-1/2 translate-x-1/2 mb-4",tr:"top-full left-1/2 -translate-x-1/2 mt-4",tl:"top-full right-1/2 translate-x-1/2 mt-4"}[Z],S=X&&r===e,H=tt[e];return S?t.jsx("div",{id:`menu-q${e}`,className:`quadrant-menu ${m} open`,role:"menu","aria-labelledby":"main-button",style:{display:"flex",opacity:1,visibility:"visible",pointerEvents:"auto"},children:l.map((i,g)=>t.jsxs(Se,{href:i.href,method:i.method||"get",as:i.method==="post"?"button":"a",className:`menu-item ${i.isDestructive?"destructive":""}`,title:i.label,role:"menuitem","aria-label":i.label,onClick:u=>ie(u,i.action,i.href,i.method),onKeyDown:u=>{(u.key==="Enter"||u.key===" ")&&ie(u,i.action,i.href,i.method)},tabIndex:S?0:-1,style:{animationDelay:`${g*.03}s`,background:i.isDestructive?void 0:H.bg,"--item-glow":H.glow,borderColor:i.isDestructive?void 0:H.border},children:[t.jsx("div",{className:"icon-wrapper",children:t.jsx(T,{icon:i.icon})}),t.jsxs("span",{className:"truncate",children:[`${e}.${g+1}`," ",i.label]})]},`${i.href}-${g}`))},e):null})]})]})};export{lt as D,Ve as E};

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.