// edit-site.js — extracted from edit_site.html
// Data injected via window.__SITE_DATA__

    // Tab switching
    function showPanel(name) {
            document.querySelectorAll('.panel').forEach(p => p.classList.remove('active'));
            document.querySelectorAll('.tab').forEach(t => t.classList.remove('active'));
            document.getElementById('panel-' + name).classList.add('active');
            event.target.classList.add('active');
        }

        // Toggle advanced panel
        function toggleAdvanced(btn) {
            var row = btn.closest('.field-row');
            var adv = row.querySelector('.field-advanced');
            var isOpen = adv.classList.contains('open');
            adv.classList.toggle('open');
            btn.classList.toggle('active');
            btn.textContent = isOpen ? '⚙ Advanced' : '⚙ Close';
        }

        // Field type change handler — update advanced panel sections
        function onFieldTypeChange(select) {
            var row = select.closest('.field-row');
            var adv = row.querySelector('.field-advanced');
            var ftype = select.value;
            updateAdvancedSections(adv, ftype);
        }

        function updateAdvancedSections(adv, ftype) {
            // Show/hide sections based on type
            var sections = adv.querySelectorAll('.field-adv-section[data-section]');
            sections.forEach(function(sec) {
                var section = sec.getAttribute('data-section');
                if (section === 'basic') {
                    sec.style.display = ftype === 'computed' ? 'none' : 'block';
                } else if (section === 'validation') {
                    var show = (ftype === 'text' || ftype === 'email' || ftype === 'textarea' ||
                                ftype === 'phone' || ftype === 'number' || ftype === 'select' || ftype === 'radio');
                    sec.style.display = show ? 'block' : 'none';
                } else if (section === 'condition') {
                    sec.style.display = ftype !== 'computed' ? 'block' : 'none';
                } else if (section === 'calculation') {
                    sec.style.display = ftype === 'computed' ? 'block' : 'none';
                } else if (section === 'step') {
                    sec.style.display = 'block';
                }
            });

            // Show/hide min/max vs minLength/maxLength based on type
            var numFields = adv.querySelectorAll('[data-num-only]');
            var lenFields = adv.querySelectorAll('[data-len-only]');
            var patternFields = adv.querySelectorAll('[data-pattern-only]');
            numFields.forEach(function(el) { el.style.display = ftype === 'number' ? 'block' : 'none'; });
            lenFields.forEach(function(el) { el.style.display = (ftype === 'text' || ftype === 'email' || ftype === 'textarea' || ftype === 'phone') ? 'block' : 'none'; });
            patternFields.forEach(function(el) { el.style.display = (ftype === 'text' || ftype === 'email' || ftype === 'textarea' || ftype === 'phone') ? 'block' : 'none'; });

            // Trigger inline validation
            validateFieldRow(row);
        }

        // ========================
        // INLINE FIELD VALIDATION
        // ========================
        function validateFieldRow(row) {
            var errors = [];
            var key = (row.querySelector('.field-key') || {}).value || '';
            var label = (row.querySelector('.field-label') || {}).value || '';
            var ftype = (row.querySelector('.field-type') || {}).value || 'text';

            // Key checks
            if (!key) errors.push('Field key required');
            else if (!/^[a-zA-Z_][a-zA-Z0-9_]*$/.test(key)) errors.push('Key must start with letter/_, then alphanumeric/_');
            else {
                var allKeys = [];
                document.querySelectorAll('#field-list .field-row').forEach(function(r) {
                    if (r !== row) {
                        var k = (r.querySelector('.field-key') || {}).value || '';
                        if (k) allKeys.push(k);
                    }
                });
                if (allKeys.indexOf(key) !== -1) errors.push('Duplicate key: "' + key + '"');
            }

            if (!label) errors.push('Label required');

            // Validation rule checks
            var adv = row.querySelector('.field-advanced');
            if (adv) {
                var gv = function(sel) { var el = adv.querySelector(sel); return el ? el.value : ''; };
                var gn = function(sel) { var el = adv.querySelector(sel); return el ? el.value : ''; };

                // Regex pattern
                var pattern = gv('[data-field-pattern]');
                if (pattern) {
                    try { new RegExp(pattern); } catch(e) { errors.push('Invalid regex pattern'); }
                }

                // Min/Max (number type)
                if (ftype === 'number') {
                    var min = gn('[data-field-min]');
                    var max = gn('[data-field-max]');
                    if (min && max && Number(min) >= Number(max)) errors.push('Min must be less than Max');
                }

                // MinLength/MaxLength
                var minLength = gn('[data-field-min-length]');
                var maxLength = gn('[data-field-max-length]');
                if (minLength && maxLength && Number(minLength) > Number(maxLength)) errors.push('Min length must be ≤ Max length');
                if (minLength && Number(minLength) < 0) errors.push('Min length cannot be negative');
                if (maxLength && Number(maxLength) < 0) errors.push('Max length cannot be negative');
            }

            // Render errors
            renderFieldErrors(row, errors);
        }

        function renderFieldErrors(row, errors) {
            // Remove existing error elements
            var existingBar = row.querySelector('.field-error-bar');
            if (existingBar) existingBar.remove();
            var existingList = row.querySelector('.field-error-list');
            if (existingList) existingList.remove();

            if (errors.length === 0) {
                row.classList.remove('has-error');
                return;
            }

            row.classList.add('has-error');

            // Error bar on right
            var bar = document.createElement('div');
            bar.className = 'field-error-bar';
            row.appendChild(bar);

            // Error list below field-item
            var item = row.querySelector('.field-item');
            if (item) {
                var ul = document.createElement('ul');
                ul.className = 'field-error-list';
                errors.forEach(function(err) {
                    var li = document.createElement('li');
                    li.textContent = err;
                    ul.appendChild(li);
                });
                item.parentNode.insertBefore(ul, item.nextSibling);
            }
        }

        // Collect field data from a row (basic + advanced)
        function getFieldFromRow(row) {
            var item = row.querySelector('.field-item');
            var adv = row.querySelector('.field-advanced');

            var field = {
                key: item.querySelector('.field-key').value.trim(),
                type: item.querySelector('.field-type').value,
                label: item.querySelector('.field-label').value.trim(),
                required: item.querySelector('.field-required').value === '1'
            };

            // Advanced fields
            if (adv) {
                var val = function(cls) {
                    var el = adv.querySelector(cls);
                    return el ? el.value.trim() : '';
                };
                var numVal = function(cls) {
                    var el = adv.querySelector(cls);
                    return el ? el.value : '';
                };

                // Basic
                field.placeholder = val('[data-field-placeholder]');
                field.default = val('[data-field-default]');

                // Options (select/radio)
                var optionsStr = val('[data-field-options]');
                field.options = optionsStr ? optionsStr.split(',').map(function(s){ return s.trim(); }).filter(function(s){ return s; }) : [];

                // Validation
                var pattern = val('[data-field-pattern]');
                var errorMsg = val('[data-field-error-message]');
                if (pattern) field.pattern = pattern;
                if (errorMsg) field.errorMessage = errorMsg;

                var min = numVal('[data-field-min]');
                var max = numVal('[data-field-max]');
                if (min) field.min = Number(min);
                if (max) field.max = Number(max);

                var minLength = numVal('[data-field-min-length]');
                var maxLength = numVal('[data-field-max-length]');
                if (minLength) field.minLength = Number(minLength);
                if (maxLength) field.maxLength = Number(maxLength);

                // Condition
                var condField = val('[data-cond-field]');
                var condOp = val('[data-cond-operator]');
                var condVal = val('[data-cond-value]');
                if (condField && condOp) {
                    field.condition = { field: condField, operator: condOp };
                    if (condVal) field.condition.value = condVal;
                }

                // Calculation
                var formula = val('[data-calc-formula]');
                var calcRound = numVal('[data-calc-round]');
                if (formula) {
                    field.calculation = { formula: formula };
                    if (calcRound) field.calculation.round = Number(calcRound);
                }

                // Step
                var step = numVal('[data-field-step]');
                if (step) field.step = parseInt(step);
            }

            return field;
        }

        // Get all fields
        function getFields() {
            var rows = document.querySelectorAll('#field-list .field-row');
            var fields = [];
            rows.forEach(function(row) {
                var f = getFieldFromRow(row);
                if (f.key) fields.push(f);
            });
            return fields;
        }

        function addField() {
             var list = document.getElementById('field-list');
             list.style.display = 'flex';
             document.getElementById('empty-state').style.display = 'none';

             var row = document.createElement('div');
             row.className = 'field-row';
             row.innerHTML = '<div class="field-item">' +
                 '<input type="text" class="field-key" placeholder="Field key (e.g. name)">' +
                 '<select class="field-type" data-onchange="onFieldTypeChange(this)">' +
                     '<option value="text">Text</option>' +
                     '<option value="email">Email</option>' +
                     '<option value="phone">Phone</option>' +
                     '<option value="number">Number</option>' +
                     '<option value="textarea">Textarea</option>' +
                     '<option value="select">Select</option>' +
                     '<option value="radio">Radio</option>' +
                     '<option value="checkbox">Checkbox</option>' +
                     '<option value="date">Date</option>' +
                     '<option value="computed">Computed</option>' +
                 '</select>' +
                 '<input type="text" class="field-label" placeholder="Display label">' +
                 '<select class="field-required">' +
                     '<option value="0">Optional</option>' +
                     '<option value="1">Required</option>' +
                 '</select>' +
                 '<div class="field-actions">' +
                     '<button type="button" class="field-expand-btn" data-onclick="toggleAdvanced(this)">⚙ Advanced</button>' +
                     '<button type="button" class="field-remove" data-onclick="removeField(this)">&times;</button>' +
                 '</div>' +
             '</div>' +
             '<div class="field-advanced">' +
                 '<div class="field-adv-section" data-section="basic">' +
                     '<div class="field-adv-section-title">Basic</div>' +
                     '<div class="field-advanced-grid">' +
                         '<div class="field-adv-group">' +
                             '<label>Placeholder</label>' +
                             '<input type="text" data-field-placeholder placeholder="Hint text...">' +
                         '</div>' +
                         '<div class="field-adv-group">' +
                             '<label>Default Value</label>' +
                             '<input type="text" data-field-default placeholder="Default value...">' +
                         '</div>' +
                         '<div class="field-adv-group full-width" data-options-only>' +
                             '<label>Options (comma-separated)</label>' +
                             '<input type="text" data-field-options placeholder="Option 1, Option 2, Option 3">' +
                             '<div class="field-adv-hint">For select/radio field types.</div>' +
                         '</div>' +
                     '</div>' +
                 '</div>' +
                 '<div class="field-adv-section" data-section="validation">' +
                     '<div class="field-adv-section-title">Validation</div>' +
                     '<div class="field-advanced-grid">' +
                         '<div class="field-adv-group" data-num-only>' +
                             '<label>Min Value</label>' +
                             '<input type="number" data-field-min step="any">' +
                         '</div>' +
                         '<div class="field-adv-group" data-num-only>' +
                             '<label>Max Value</label>' +
                             '<input type="number" data-field-max step="any">' +
                         '</div>' +
                         '<div class="field-adv-group" data-len-only>' +
                             '<label>Min Length</label>' +
                             '<input type="number" data-field-min-length min="0" step="1">' +
                         '</div>' +
                         '<div class="field-adv-group" data-len-only>' +
                             '<label>Max Length</label>' +
                             '<input type="number" data-field-max-length min="0" step="1">' +
                         '</div>' +
                         '<div class="field-adv-group full-width" data-pattern-only>' +
                             '<label>Pattern (Regex)</label>' +
                             '<input type="text" data-field-pattern placeholder="^[A-Z]{2}\\d{4}$">' +
                             '<div class="field-adv-hint">JavaScript regex pattern for custom validation.</div>' +
                         '</div>' +
                         '<div class="field-adv-group full-width">' +
                             '<label>Error Message</label>' +
                             '<input type="text" data-field-error-message placeholder="Custom error message...">' +
                         '</div>' +
                     '</div>' +
                 '</div>' +
                 '<div class="field-adv-section" data-section="condition">' +
                     '<div class="field-adv-section-title">Conditional Visibility</div>' +
                     '<div class="field-advanced-grid">' +
                         '<div class="field-adv-group">' +
                             '<label>Depends On (Field Key)</label>' +
                             '<input type="text" data-field-condition-field placeholder="e.g. question_type">' +
                         '</div>' +
                         '<div class="field-adv-group">' +
                             '<label>Condition</label>' +
                             '<select data-field-condition-op>' +
                                 '<option value="">Always visible</option>' +
                                 '<option value="equals">Is</option>' +
                                 '<option value="not_equals">Is Not</option>' +
                                 '<option value="contains">Contains</option>' +
                                 '<option value="not_contains">Does Not Contain</option>' +
                             '</select>' +
                         '</div>' +
                         '<div class="field-adv-group full-width">' +
                             '<label>Dependent Value</label>' +
                             '<input type="text" data-field-condition-value placeholder="Value that triggers visibility">' +
                         '</div>' +
                     '</div>' +
                 '</div>' +
                 '<div class="field-adv-section" data-section="calculation" style="display:none;">' +
                     '<div class="field-adv-section-title">Calculation</div>' +
                     '<div class="field-advanced-grid">' +
                         '<div class="field-adv-group full-width">' +
                             '<label>Formula</label>' +
                             '<input type="text" data-field-formula placeholder="e.g. total * 0.08">' +
                             '<div class="field-adv-hint">Use field keys as variables. e.g. <code>qty * price</code></div>' +
                         '</div>' +
                     '</div>' +
                 '</div>' +
                 '<div class="field-adv-section" data-section="step">' +
                     '<div class="field-adv-section-title">Multi-Step</div>' +
                     '<div class="field-advanced-grid">' +
                         '<div class="field-adv-group">' +
                             '<label>Step Number</label>' +
                             '<input type="number" data-field-step min="1" step="1" placeholder="1">' +
                             '<div class="field-adv-hint">Leave blank for default (Step 1). Group fields by step number for multi-step forms.</div>' +
                         '</div>' +
                     '</div>' +
                 '</div>' +
             '</div>';
             row.querySelector('.field-key').focus();

             // Apply current filter if active
             var searchInput = document.getElementById('field-search-input');
             if (searchInput && searchInput.value.trim()) {
                 filterFields(searchInput.value);
             }

             list.appendChild(row);

             // Show options field only for select/radio
             var optionsEl = row.querySelector('[data-options-only]');
             if (optionsEl) optionsEl.style.display = 'none';

             // Init advanced sections
              var adv = row.querySelector('.field-advanced');
              updateAdvancedSections(adv, 'text');

              // Wire up inline validation on input changes
              row.addEventListener('input', function(e) {
                  validateFieldRow(row);
              });
             }

         // ========================
          // FIELD SEARCH / FILTER
          // ========================
          function filterFields(query) {
             var q = query.trim().toLowerCase();
             var rows = document.querySelectorAll('#field-list .field-row');
             var count = 0;
             var total = rows.length;

             rows.forEach(function(row) {
                 var item = row.querySelector('.field-item');
                 if (!item) return;

                 var key = (item.querySelector('.field-key') || {}).value || '';
                 var label = (item.querySelector('.field-label') || {}).value || '';
                 var type = (item.querySelector('.field-type') || {}).value || '';

                 if (!q || key.toLowerCase().includes(q) || label.toLowerCase().includes(q) || type.includes(q)) {
                     row.classList.remove('hidden');
                     count++;
                 } else {
                     row.classList.add('hidden');
                 }
             });

             // Update UI
             var clearBtn = document.getElementById('field-search-clear');
             var countEl = document.getElementById('field-search-count');
             if (clearBtn) clearBtn.style.display = q ? 'block' : 'none';
             if (countEl) {
                 if (q) {
                     countEl.textContent = count + ' of ' + total + ' fields shown';
                 } else {
                     countEl.textContent = '';
                 }
             }
         }

         function clearFieldFilter() {
             var input = document.getElementById('field-search-input');
             if (input) {
                 input.value = '';
                 filterFields('');
                 input.focus();
             }
         }

        function removeField(btn) {
            var row = btn.closest('.field-row');
            row.remove();
            var list = document.getElementById('field-list');
            if (list.querySelectorAll('.field-row').length === 0) {
                list.style.display = 'none';
                document.getElementById('empty-state').style.display = 'block';
            }
        }

        // Initialize advanced panels for existing fields on page load
        document.addEventListener('DOMContentLoaded', function() {
            var rows = document.querySelectorAll('#field-list .field-row');
            rows.forEach(function(row) {
                var item = row.querySelector('.field-item');
                var typeSelect = item.querySelector('.field-type');
                var ftype = typeSelect.value;
                var adv = row.querySelector('.field-advanced');
                if (adv) {
                    updateAdvancedSections(adv, ftype);

                    // Show options for select/radio
                    var optionsEl = adv.querySelector('[data-options-only]');
                    if (optionsEl) {
                        optionsEl.style.display = (ftype === 'select' || ftype === 'radio') ? 'block' : 'none';
                    }
                }

                // Wire up inline validation
                row.addEventListener('input', function(e) {
                    validateFieldRow(row);
                });
                validateFieldRow(row);
            });
        });

        // Also handle options visibility on type change
        var origOnType = onFieldTypeChange;
        onFieldTypeChange = function(select) {
            var row = select.closest('.field-row');
            var adv = row.querySelector('.field-advanced');
            var ftype = select.value;
            updateAdvancedSections(adv, ftype);
            var optionsEl = adv.querySelector('[data-options-only]');
            if (optionsEl) {
                optionsEl.style.display = (ftype === 'select' || ftype === 'radio') ? 'block' : 'none';
            }
        };

        // Serialize fields before form submit
        document.getElementById('edit-form').addEventListener('submit', function(e) {
            document.getElementById('field_config_json').value = JSON.stringify(getFields());
            document.getElementById('hidden_webhook_url').value = document.getElementById('webhook_url').value;
            document.getElementById('hidden_webhook_enabled').checked = document.getElementById('webhook_enabled').checked;
            document.getElementById('hidden_webhook_events').value = document.getElementById('webhook_events').value;
        });

        document.getElementById('webhook-form').addEventListener('submit', function(e) {
            document.getElementById('hidden_field_config').value = JSON.stringify(getFields());
        });
        document.getElementById('protection-form').addEventListener('submit', function(e) {
            document.getElementById('hidden_protection_field_config').value = JSON.stringify(getFields());
        });

        // Toggle rate limit config visibility
        document.getElementById('rate_limit_enabled').addEventListener('change', function(e) {
            document.getElementById('rate_limit_config').style.display = e.target.checked ? 'block' : 'none';
        });

        // Embed code copy
        function copyEmbedCode() {
            var snippet = document.getElementById('embed-snippet').textContent;
            navigator.clipboard.writeText(snippet).then(function() {
                var fb = document.getElementById('copy-feedback');
                fb.style.display = 'inline';
                setTimeout(function() { fb.style.display = 'none'; }, 2000);
            });
        }

        // Share panel — copy hosted form URL
        function copyShareUrl(token) {
            var baseUrl = window.location.origin;
            var url = baseUrl + '/f/' + token;
            document.getElementById('share-url-display').textContent = url;
            navigator.clipboard.writeText(url).then(function() {
                var fb = document.getElementById('share-url-feedback');
                fb.style.display = 'block';
                setTimeout(function() { fb.style.display = 'none'; }, 2000);
            });
        }

        // Share panel — load & copy email HTML
        var emailHtmlCache = '';
        function loadEmailHtml(token) {
            if (emailHtmlCache) return;
            fetch('/api/v2/forms/' + token + '/email-html')
                .then(function(r) { return r.text(); })
                .then(function(html) {
                    emailHtmlCache = html;
                    var preview = document.getElementById('email-html-preview');
                    if (preview) {
                        preview.textContent = html.substring(0, 500) + (html.length > 500 ? '\n...(truncated, click Copy to get full HTML)' : '');
                    }
                })
                .catch(function() {
                    var preview = document.getElementById('email-html-preview');
                    if (preview) preview.textContent = 'Failed to load email HTML.';
                });
        }
        function copyEmailHtml(token) {
            if (!emailHtmlCache) {
                loadEmailHtml(token);
                var fb = document.getElementById('email-html-feedback');
                fb.textContent = 'Loading...';
                fb.style.display = 'block';
                fb.style.color = 'var(--warning)';
                return;
            }
            navigator.clipboard.writeText(emailHtmlCache).then(function() {
                var fb = document.getElementById('email-html-feedback');
                fb.textContent = '\u2713 Copied to clipboard!';
                fb.style.color = 'var(--success)';
                fb.style.display = 'block';
                setTimeout(function() { fb.style.display = 'none'; }, 2000);
            });
        }

      // Embed theme toggle
        document.getElementById('embed-theme-check').addEventListener('change', function(e) {
            var snippet = document.getElementById('embed-snippet');
            var token = window.__SITE_DATA__.siteToken;
            var theme = e.target.checked ? 'dark' : 'light';
            snippet.innerHTML = '&lt;script src="https://agentforms.io/embed.js"&gt;&lt;\\/script&gt;\\n&lt;div id="agentform"&gt;&lt;\\/div&gt;\\n&lt;script&gt;\\n  AF.render(\\'agentform\\', {\\n    token: \\' + token + \\',\\n    theme: \\' + theme + \\',\\n    successMessage: "Thank you! Your submission was received.",\\n    onSubmit: function(data) { /* analytics hook */ }\\n  });\\n&lt;\\/script&gt;';
        });

        // Branding panel - load/save branding settings
        var brandingLoaded = false;

        function loadBranding() {
            if (brandingLoaded) return;
            brandingLoaded = true;

            fetch(''/api/v2/sites/' + window.__SITE_DATA__.siteId + '/branding'')
                .then(function(r) { return r.json(); })
                .then(function(data) {
                    // Populate fields
                    if (data.branding_color) {
                        document.getElementById('branding-color-picker').value = data.branding_color;
                        document.getElementById('branding-color-input').value = data.branding_color;
                        document.getElementById('branding-color-preview').style.background = data.branding_color;
                    }
                    if (data.logo_url) document.getElementById('branding-logo-url').value = data.logo_url;
                    if (data.favicon_url) document.getElementById('branding-favicon-url').value = data.favicon_url;
                    if (data.og_title) document.getElementById('branding-og-title').value = data.og_title;
                    if (data.og_description) document.getElementById('branding-og-description').value = data.og_description;
                    if (data.og_image) document.getElementById('branding-og-image').value = data.og_image;
                    if (data.custom_domain) document.getElementById('branding-custom-domain').value = data.custom_domain;

                    // Show/hide custom domain section based on Pro tier
                    if (data.is_pro) {
                        document.getElementById('branding-custom-domain-section').style.display = 'block';
                    }

                    // Color picker sync
                    document.getElementById('branding-color-picker').addEventListener('input', function(e) {
                        document.getElementById('branding-color-input').value = e.target.value;
                        document.getElementById('branding-color-preview').style.background = e.target.value;
                    });
                    document.getElementById('branding-color-input').addEventListener('input', function(e) {
                        if (/^#[0-9a-fA-F]{6}$/.test(e.target.value)) {
                            document.getElementById('branding-color-picker').value = e.target.value;
                            document.getElementById('branding-color-preview').style.background = e.target.value;
                        }
                    });
                })
                .catch(function(err) { console.error('Failed to load branding:', err); });
        }

        function saveBranding() {
            var data = {
                branding_color: document.getElementById('branding-color-input').value || null,
                logo_url: document.getElementById('branding-logo-url').value || null,
                favicon_url: document.getElementById('branding-favicon-url').value || null,
                og_title: document.getElementById('branding-og-title').value || null,
                og_description: document.getElementById('branding-og-description').value || null,
                og_image: document.getElementById('branding-og-image').value || null,
                custom_domain: document.getElementById('branding-custom-domain').value || null,
            };

            fetch(''/api/v2/sites/' + window.__SITE_DATA__.siteId + '/branding'', {
                method: 'PUT',
                headers: { 'Content-Type': 'application/json' },
                body: JSON.stringify(data),
            })
            .then(function(r) { return r.json(); })
            .then(function(result) {
                if (result.success) {
                    var feedback = document.getElementById('branding-save-feedback');
                    feedback.style.display = 'inline';
                    setTimeout(function() { feedback.style.display = 'none'; }, 3000);
                } else {
                    alert('Error: ' + result.error);
                }
            })
            .catch(function(err) { console.error('Failed to save branding:', err); });
        }

        // Analytics - fetch on tab click (triggered by showPanel override below)
        var analyticsLoaded = false;

        function fetchAnalytics(token) {
            fetch('/api/analytics/json/' + token)
                .then(function(r) { return r.json(); })
                .then(function(data) {
                    document.getElementById('analytics-loading').style.display = 'none';
                    
                    // Total submissions
                    document.getElementById('analytics-total').textContent = data.total_submissions || 0;
                    
                    // 7-day total
                    var days7 = data.daily_submissions.slice(0, 7);
                    var total7d = days7.reduce(function(s, d) { return s + d.count; }, 0);
                    document.getElementById('analytics-7d').textContent = total7d;
                    
                    // Avg/day
                    var avg = days7.length > 0 ? (total7d / Math.max(days7.length, 1)).toFixed(1) : 0;
                    document.getElementById('analytics-avg').textContent = avg;
                    
                    // Bar chart - last 7 days
                    renderBarChart(days7);
                })
                .catch(function(err) {
                    document.getElementById('analytics-loading').textContent = 'Failed to load analytics.';
                });
        }

        function renderBarChart(days) {
            var container = document.getElementById('bar-chart');
            var labels = document.getElementById('bar-labels');
            container.innerHTML = '';
            labels.innerHTML = '';
            
            var maxCount = Math.max(1, ...days.map(function(d) { return d.count; }));
            
            days.forEach(function(day) {
                var pct = (day.count / maxCount) * 100;
                var bar = document.createElement('div');
                bar.className = 'bar-segment';
                bar.style.flex = '1';
                bar.style.height = Math.max(2, pct) + '%';
                bar.title = day.date + ': ' + day.count + ' submissions';
                container.appendChild(bar);
                
                var label = document.createElement('div');
                label.className = 'bar-label';
                label.textContent = day.date.slice(5); // MM-DD
                labels.appendChild(label);
            });
            
            document.getElementById('analytics-chart').style.display = 'block';
        }

        // ========================
        // INTEGRATIONS
        // ========================
        var SITE_ID = window.__SITE_DATA__.siteId;
        var CSRF_TOKEN = 'window.__SITE_DATA__.csrfToken';
        var integrationsLoaded = false;
        var availableTypes = [];
        var selectedIntType = null;
        var editingIntId = null;

        // Integration type defaults (used as fallback when API hasn't loaded)
        var INTEGRATION_TYPES = {
            webhook: { icon: '🔗', name: 'Webhook', color: '#6366f1' },
            google_sheets: { icon: '📊', name: 'Google Sheets', color: '#34a853' },
            slack: { icon: '💬', name: 'Slack', color: '#4a154b' },
            discord: { icon: '🎮', name: 'Discord', color: '#5865f2' },
            telegram: { icon: '✈️', name: 'Telegram', color: '#0088cc' },
            airtable: { icon: '📋', name: 'Airtable', color: '#188fff' },
            notion: { icon: '📝', name: 'Notion', color: '#000000' },
        };

        // Override showPanel to load panel-specific data
         var _origShowPanel = showPanel;
         showPanel = function(name) {
             _origShowPanel(name);
             if (name === 'analytics' && !analyticsLoaded) {
                 analyticsLoaded = true;
                 fetchAnalytics(window.__SITE_DATA__.siteToken);
             }
             if (name === 'integrations' && !integrationsLoaded) {
                 integrationsLoaded = true;
                 loadIntegrations();
                 loadAvailableTypes();
             }
             if (name === 'share') {
                 loadEmailHtml(window.__SITE_DATA__.siteToken);
             }
             if (name === 'versions' && !versionsLoaded) {
                 versionsLoaded = true;
                 loadVersions();
             }
             if (name === 'abtest') loadABTest();
             if (name === 'documents') loadDocPanel();
         };

        function apiFetch(url, options) {
            var opts = options || {};
            opts.headers = opts.headers || {};
            opts.headers['X-CSRF-Token'] = CSRF_TOKEN;
            if (opts.body && typeof opts.body === 'object' && !(opts.body instanceof FormData)) {
                opts.headers['Content-Type'] = 'application/json';
                opts.body = JSON.stringify(opts.body);
            }
            return fetch(url, opts).then(function(r) {
                if (r.status === 204) return null;
                return r.json();
            });
        }

        function getIconInfo(type) {
            return INTEGRATION_TYPES[type] || { icon: '🔗', name: type, color: '#6366f1' };
        }

        function formatDate(d) {
            if (!d) return 'Never';
            var dt = new Date(d);
            return dt.toLocaleDateString() + ' ' + dt.toLocaleTimeString([], {hour:'2-digit', minute:'2-digit'});
        }

        function loadAvailableTypes() {
            apiFetch('/sites/' + SITE_ID + '/integrations/available')
                .then(function(types) {
                    availableTypes = types || [];
                    if (availableTypes.length) {
                        // Merge into defaults
                        availableTypes.forEach(function(t) {
                            INTEGRATION_TYPES[t.type] = {
                                icon: t.icon || '🔗',
                                name: t.name || t.type,
                                color: '#6366f1'
                            };
                        });
                    }
                })
                .catch(function() { /* use defaults */ });
        }

        function loadIntegrations() {
            var loading = document.getElementById('int-loading');
            var empty = document.getElementById('int-empty');
            var grid = document.getElementById('int-grid');
            loading.style.display = 'block';
            empty.style.display = 'none';
            grid.style.display = 'none';

            apiFetch('/sites/' + SITE_ID + '/integrations')
                .then(function(destinations) {
                    loading.style.display = 'none';
                    if (!destinations || destinations.length === 0) {
                        empty.style.display = 'block';
                        grid.style.display = 'none';
                    } else {
                        empty.style.display = 'none';
                        grid.style.display = 'grid';
                        renderIntegrations(destinations);
                    }
                })
                .catch(function(err) {
                    loading.innerHTML = '<p style="color:var(--danger);">Failed to load integrations.</p>';
                });
        }

        function renderIntegrations(destinations) {
            var grid = document.getElementById('int-grid');
            grid.innerHTML = '';
            destinations.forEach(function(dest) {
                var info = getIconInfo(dest.type);
                var card = document.createElement('div');
                card.className = 'int-card';
                card.id = 'int-card-' + dest.id;

                var statusDot = dest.last_status === 'success' ? 'dot-success' :
                                dest.last_status === 'failure' ? 'dot-failure' : 'dot-neutral';

                card.innerHTML =
                    '<div class="int-card-header">' +
                        '<div class="int-card-icon" style="background:' + info.color + '20;">' + info.icon + '</div>' +
                        '<div>' +
                            '<div class="int-card-title">' + escHtml(dest.name || info.name) + '</div>' +
                            '<div class="int-card-type">' + (dest.type || '').replace('_', ' ') + '</div>' +
                        '</div>' +
                        '<label class="int-toggle">' +
                            '<input type="checkbox" ' + (dest.enabled ? 'checked' : '') +
                            ' data-onchange="toggleIntegration(' + dest.id + ', this.checked)">' +
                            '<span class="slider"></span>' +
                        '</label>' +
                    '</div>' +
                    '<div class="int-card-body">' +
                        (dest.url ? '<div class="int-url">' + escHtml(dest.url) + '</div>' : '') +
                    '</div>' +
                    '<div class="int-status-row">' +
                        '<span class="int-status-item"><span class="dot dot-success"></span> ' + (dest.success_count || 0) + ' success</span>' +
                        '<span class="int-status-item"><span class="dot dot-failure"></span> ' + (dest.failure_count || 0) + ' failure</span>' +
                        '<span class="int-status-item"><span class="dot ' + statusDot + '"></span> Last: ' + formatDate(dest.last_delivered_at) + '</span>' +
                    '</div>' +
                    '<div class="int-footer">' +
                        '<button class="int-btn-sm" data-onclick="testIntegration(' + dest.id + ', this)">🧪 Test</button>' +
                        '<button class="int-btn-sm danger" data-onclick="deleteIntegration(' + dest.id + ')">🗑 Delete</button>' +
                    '</div>';

                grid.appendChild(card);
            });
        }

        // ---- MODAL ----

        function openIntModal(dest) {
            editingIntId = dest ? dest.id : null;
            var modal = document.getElementById('int-modal');
            var title = document.getElementById('int-modal-title');
            var saveBtn = document.getElementById('int-save-btn');

            title.textContent = dest ? 'Edit Integration' : 'Add Integration';
            saveBtn.textContent = dest ? 'Save Changes' : 'Add Integration';

            // Populate type selector
            renderTypeList(dest);

            // Pre-fill if editing
            if (dest) {
                document.getElementById('int-name').value = dest.name || '';
                document.getElementById('int-url').value = dest.url || '';
                document.getElementById('int-enabled').checked = dest.enabled !== false;
                // Pre-fill config fields
                if (dest.config) {
                    var configInputs = document.getElementById('int-config-fields').querySelectorAll('.int-config-input');
                    configInputs.forEach(function(inp) {
                        var key = inp.getAttribute('data-config-key');
                        if (dest.config[key] !== undefined) {
                            inp.value = dest.config[key];
                        }
                    });
                }
            } else {
                document.getElementById('int-name').value = '';
                document.getElementById('int-url').value = '';
                document.getElementById('int-enabled').checked = true;
            }

            modal.classList.add('open');
        }

        function closeIntModal() {
            document.getElementById('int-modal').classList.remove('open');
            editingIntId = null;
            selectedIntType = null;
        }

        function renderTypeList(dest) {
            var list = document.getElementById('int-type-list');
            list.innerHTML = '';

            var typesToUse = [];
            if (availableTypes.length) {
                typesToUse = availableTypes;
            } else {
                // Fallback from defaults
                Object.keys(INTEGRATION_TYPES).forEach(function(k) {
                    typesToUse.push({ type: k, name: INTEGRATION_TYPES[k].name, icon: INTEGRATION_TYPES[k].icon, description: '', config_fields: [], requires_url: true });
                });
            }

            typesToUse.forEach(function(t) {
                var info = getIconInfo(t.type);
                var opt = document.createElement('div');
                opt.className = 'int-type-option' + (dest && dest.type === t.type ? ' selected' : '');
                if (!dest && !selectedIntType && !dest) {
                    // Auto-select first on fresh open
                }
                opt.setAttribute('data-type', t.type);
                opt.innerHTML =
                    '<span class="type-icon">' + (t.icon || info.icon) + '</span>' +
                    '<div>' +
                        '<div class="type-name">' + (t.name || info.name) + '</div>' +
                        (t.description ? '<div class="type-desc">' + escHtml(t.description) + '</div>' : '') +
                    '</div>';
                opt.addEventListener('click', function() { selectIntType(t.type, t); });
                list.appendChild(opt);

                // Auto-select if editing or first
                if ((dest && dest.type === t.type) || (!dest && !selectedIntType && list.children.length === 1 && !dest)) {
                    if (dest && dest.type === t.type) {
                        opt.classList.add('selected');
                        selectIntType(t.type, t);
                    }
                }
            });

            // If no dest and not yet selected, auto-pick first
            if (!dest && !selectedIntType && list.children.length > 0) {
                list.children[0].classList.add('selected');
                var firstType = list.children[0].getAttribute('data-type');
                var firstData = typesToUse[0];
                selectIntType(firstType, firstData);
            }
        }

        function selectIntType(type, typeData) {
            selectedIntType = type;
            // Update UI selection
            var options = document.getElementById('int-type-list').querySelectorAll('.int-type-option');
            options.forEach(function(o) {
                o.classList.toggle('selected', o.getAttribute('data-type') === type);
            });

            // Show/hide URL field
            var urlGroup = document.getElementById('int-url-group');
            urlGroup.style.display = typeData.requires_url !== false ? 'block' : 'none';

            // Render config fields
            renderConfigFields(typeData);

            // Show setup guide
            renderSetupGuide(typeData);
        }

        function renderConfigFields(typeData) {
            var container = document.getElementById('int-config-fields');
            container.innerHTML = '';
            if (!typeData.config_fields || typeData.config_fields.length === 0) return;

            typeData.config_fields.forEach(function(cf) {
                var group = document.createElement('div');
                group.className = 'form-group';
                var inputType = cf.type === 'textarea' ? 'textarea' : cf.type || 'text';
                var tag = inputType === 'textarea' ? 'textarea' : 'input';
                var attrs = 'type="' + cf.type + '" class="int-config-input" data-config-key="' + cf.key + '"';
                if (cf.placeholder) attrs += ' placeholder="' + cf.placeholder + '"';
                if (cf.required) attrs += ' required';
                var closeTag = tag === 'textarea' ? '</textarea>' : '';
                group.innerHTML =
                    '<label>' + escHtml(cf.label) + (cf.required ? ' <span style="color:var(--danger);">*</span>' : '') + '</label>' +
                    '<' + tag + ' ' + attrs + '></' + tag + '>';
                container.appendChild(group);
            });
        }

        function renderSetupGuide(typeData) {
            var guideDiv = document.getElementById('int-setup-guide');
            if (!typeData || !typeData.setup_guide || !typeData.setup_guide.length) {
                guideDiv.style.display = 'none';
                guideDiv.innerHTML = '';
                return;
            }
            guideDiv.style.display = 'block';
            var info = getIconInfo(selectedIntType || typeData.type);
            guideDiv.innerHTML =
                '<details class="setup-guide">' +
                    '<summary>Setup Guide: ' + (typeData.name || info.name) + '</summary>' +
                    '<div class="guide-content">' +
                    typeData.setup_guide.map(function(s) {
                        if (typeof s === 'string') return '<p>' + escHtml(s) + '</p>';
                        if (s.title) return '<p><strong>' + escHtml(s.title) + '</strong>: ' + escHtml(s.step || '') + '</p>';
                        return '';
                    }).join('') +
                    '</div>' +
                '</details>';
        }

        // ---- CRUD ----

        function saveIntegration() {
            var name = document.getElementById('int-name').value.trim();
            var url = document.getElementById('int-url').value.trim();
            var enabled = document.getElementById('int-enabled').checked;
            if (!name) { alert('Please enter a name.'); return; }
            if (!selectedIntType) { alert('Please select an integration type.'); return; }

            // Collect config fields
            var config = {};
            document.querySelectorAll('.int-config-input').forEach(function(inp) {
                var key = inp.getAttribute('data-config-key');
                var val = inp.value.trim();
                if (val) config[key] = val;
            });

            var payload = {
                type: selectedIntType,
                name: name,
                url: url,
                config: config,
                enabled: enabled
            };

            var saveBtn = document.getElementById('int-save-btn');
            saveBtn.disabled = true;
            saveBtn.textContent = 'Saving...';

            var url_path = '/sites/' + SITE_ID + '/integrations';
            var method = 'POST';
            if (editingIntId) {
                url_path += '/' + editingIntId;
                method = 'PUT';
            }

            apiFetch(url_path, { method: method, body: payload })
                .then(function() {
                    closeIntModal();
                    loadIntegrations();
                })
                .catch(function(err) {
                    alert('Failed to save integration. ' + (err.message || ''));
                })
                .finally(function() {
                    saveBtn.disabled = false;
                    saveBtn.textContent = editingIntId ? 'Save Changes' : 'Add Integration';
                });
        }

        function toggleIntegration(id, enabled) {
            apiFetch('/sites/' + SITE_ID + '/integrations/' + id, {
                method: 'PUT',
                body: { enabled: enabled }
            })
            .catch(function(err) {
                alert('Failed to update integration.');
                loadIntegrations(); // refresh to show correct state
            });
        }

        function testIntegration(id, btn) {
            btn.disabled = true;
            btn.textContent = '⏳ Testing...';
            apiFetch('/sites/' + SITE_ID + '/integrations/' + id + '/test', { method: 'POST' })
                .then(function(result) {
                    if (result && result.success) {
                        btn.textContent = '✅ Success!';
                        setTimeout(function() {
                            btn.textContent = '🧪 Test';
                            btn.disabled = false;
                        }, 2000);
                        loadIntegrations(); // refresh counts
                    } else {
                        var msg = (result && result.error) || 'Test failed';
                        btn.textContent = '❌ Failed';
                        alert(msg);
                        setTimeout(function() {
                            btn.textContent = '🧪 Test';
                            btn.disabled = false;
                        }, 3000);
                    }
                })
                .catch(function(err) {
                    btn.textContent = '❌ Error';
                    alert('Test request failed.');
                    setTimeout(function() {
                        btn.textContent = '🧪 Test';
                        btn.disabled = false;
                    }, 3000);
                });
        }

        function deleteIntegration(id) {
            if (!confirm('Delete this integration? This cannot be undone.')) return;
            apiFetch('/sites/' + SITE_ID + '/integrations/' + id, { method: 'DELETE' })
                .then(function() {
                    var card = document.getElementById('int-card-' + id);
                    if (card) card.remove();
                    // Check if grid is empty
                    var grid = document.getElementById('int-grid');
                    if (!grid.querySelectorAll('.int-card').length) {
                        document.getElementById('int-empty').style.display = 'block';
                        grid.style.display = 'none';
                    }
                })
                .catch(function(err) {
                    alert('Failed to delete integration.');
                });
        }

        // Close modal on overlay click
        document.getElementById('int-modal').addEventListener('click', function(e) {
            if (e.target === this) closeIntModal();
        });

        // Keyboard shortcuts
        document.addEventListener('keydown', function(e) {
            // Ctrl+S: Save form fields
            if ((e.ctrlKey || e.metaKey) && e.key === 's') {
                e.preventDefault();
                var editForm = document.getElementById('edit-form');
                if (editForm && document.activeElement.closest('#panel-fields')) {
                    editForm.requestSubmit();
                }
            }
            // Ctrl+N: Add new field (only in fields panel)
            if ((e.ctrlKey || e.metaKey) && e.key === 'n') {
                e.preventDefault();
                if (document.getElementById('panel-fields').classList.contains('active')) {
                    addField();
                }
            }
            // Escape: Close modal
            if (e.key === 'Escape') {
                closeIntModal();
            }
        });

        function escHtml(s) {
            if (!s) return '';
            var div = document.createElement('div');
            div.textContent = s;
            return div.innerHTML;
        }

        // ========================
        // VERSION HISTORY
        // ========================
        var versionsLoaded = false;

        function loadVersions() {
            fetch('/versions/' + SITE_ID + '/history')
                .then(function(r) { return r.json(); })
                .then(function(data) {
                    document.getElementById('versions-loading').style.display = 'none';
                    var versions = data.versions || [];
                    if (versions.length === 0) {
                        document.getElementById('versions-empty').style.display = 'block';
                        return;
                    }
                    document.getElementById('versions-empty').style.display = 'none';
                    var timeline = document.getElementById('versions-timeline');
                    timeline.style.display = 'flex';
                    timeline.innerHTML = '';
                    versions.forEach(function(v) {
                        timeline.appendChild(createVersionItem(v));
                    });
                })
                .catch(function(err) {
                    document.getElementById('versions-loading').textContent = 'Failed to load version history.';
                    console.error('Error loading versions:', err);
                });
        }

        function createVersionItem(v) {
            var item = document.createElement('div');
            item.className = 'version-item';

            var changedKeys = v.changes ? Object.keys(v.changes) : [];
            var added = 0, removed = 0, modified = 0;
            changedKeys.forEach(function(key) {
                var ch = v.changes[key];
                if (ch.type === 'added') added++;
                else if (ch.type === 'removed') removed++;
                else modified++;
            });

            var diffHtml = '';
            if (added > 0 || removed > 0 || modified > 0) {
                diffHtml = '<div class="version-diff">';
                if (added > 0) diffHtml += '<span class="field-added">+' + added + ' added</span> ';
                if (removed > 0) diffHtml += '<span class="field-removed">-' + removed + ' removed</span> ';
                if (modified > 0) diffHtml += '<span class="field-modified">~' + modified + ' modified</span>';
                diffHtml += '</div>';
            }

            var now = new Date();
            var created = new Date(v.created_at);
            var timeDiff = Math.floor((now - created) / 1000);
            var timeStr;
            if (timeDiff < 60) timeStr = 'just now';
            else if (timeDiff < 3600) timeStr = Math.floor(timeDiff / 60) + 'm ago';
            else if (timeDiff < 86400) timeStr = Math.floor(timeDiff / 3600) + 'h ago';
            else timeStr = Math.floor(timeDiff / 86400) + 'd ago';

            var isCurrent = v.current ? ' (current)' : '';

            item.innerHTML = '<div class="version-dot-col">' +
                '<div class="version-dot"></div>' +
                '<div class="version-line"></div>' +
                '</div>' +
                '<div class="version-content">' +
                '<div class="version-header">' +
                '<div class="version-meta">' +
                '<strong>v' + v.version + '</strong> &middot; ' + timeStr + isCurrent +
                '</div>' +
                '</div>' +
                (v.reason ? '<div class="version-reason">' + escHtml(v.reason) + '</div>' : '') +
                diffHtml +
                '<div class="version-actions">' +
                (v.version > 1 ? '<button class="version-btn" data-onclick="compareVersions(' + v.version + ', ' + (v.version - 1) + ')">🔍 Compare</button>' : '') +
                (!v.current ? '<button class="version-btn danger" data-onclick="rollbackVersion(' + v.version + ')">↩ Rollback</button>' : '') +
                '<button class="version-btn" data-onclick="viewVersionDetail(' + v.version + ')">👁 Details</button>' +
                '</div>' +
                '</div>';

            return item;
        }

        function createSnapshot() {
            var reason = prompt('Snapshot reason (optional):', '');
            var btn = document.getElementById('snapshot-btn');
            btn.disabled = true;
            btn.textContent = 'Saving...';

            var body = {};
            if (reason) body.reason = reason;

            fetch('/versions/' + SITE_ID + '/snapshot', {
                method: 'POST',
                headers: { 'Content-Type': 'application/json', 'X-CSRF-Token': CSRF_TOKEN },
                body: JSON.stringify(body)
            })
                .then(function(r) { return r.json(); })
                .then(function(data) {
                    loadVersions();
                })
                .catch(function(err) {
                    alert('Failed to create snapshot: ' + (err.message || ''));
                })
                .finally(function() {
                    btn.disabled = false;
                    btn.textContent = '+ Save Snapshot';
                });
        }

        function compareVersions(newer, older) {
            fetch('/versions/' + SITE_ID + '/compare/' + newer + '/' + older)
                .then(function(r) { return r.json(); })
                .then(function(data) {
                    openDiffModal(data);
                })
                .catch(function(err) {
                    alert('Failed to compare versions: ' + (err.message || ''));
                });
        }

        function viewVersionDetail(versionId) {
            fetch('/versions/' + SITE_ID + '/versions/' + versionId)
                .then(function(r) { return r.json(); })
                .then(function(data) {
                    openDetailModal(data.version);
                })
                .catch(function(err) {
                    alert('Failed to load version details: ' + (err.message || ''));
                });
        }

        function rollbackVersion(versionId) {
            var confirmMsg = 'Rollback to v' + versionId + '? This will create a new snapshot with the old field configuration.';
            if (!confirm(confirmMsg)) return;

            fetch('/versions/' + SITE_ID + '/rollback/' + versionId, {
                method: 'POST',
                headers: { 'X-CSRF-Token': CSRF_TOKEN }
            })
                .then(function(r) {
                    if (!r.ok) return r.json().then(function(d) { throw new Error(d.error || 'Rollback failed'); });
                    return r.json();
                })
                .then(function(data) {
                    alert('Rolled back to v' + versionId + '.');
                    loadVersions();
                })
                .catch(function(err) {
                    alert('Rollback failed: ' + (err.message || ''));
                });
        }

        function openDiffModal(data) {
            var overlay = document.createElement('div');
            overlay.className = 'modal-overlay open';
            overlay.innerHTML = '<div class="modal-box" style="max-width:700px;">' +
                '<div class="modal-header">' +
                '<h3>Compare v' + data.newer + ' vs v' + data.older + '</h3>' +
                '<button class="modal-close" data-onclick="this.closest(\'.modal-overlay\').remove()">\u00d7</button>' +
                '</div>' +
                '<div class="modal-body">' +
                '<table class="diff-table">' +
                '<thead><tr><th>Field</th><th>Change</th><th>Old Value</th><th>New Value</th></tr></thead>' +
                '<tbody>' + renderDiffRows(data.changes) + '</tbody>' +
                '</table>' +
                '</div>' +
                '<div class="modal-footer">' +
                '<button class="btn btn-outline" data-onclick="this.closest(\'.modal-overlay\').remove()">Close</button>' +
                '</div>' +
                '</div>';
            overlay.addEventListener('click', function(e) { if (e.target === overlay) overlay.remove(); });
            document.body.appendChild(overlay);
        }

        function renderDiffRow(change, key) {
            var badge, rowClass;
            if (change.type === 'added') {
                badge = '<span class="diff-badge added">Added</span>';
                rowClass = 'diff-added';
            } else if (change.type === 'removed') {
                badge = '<span class="diff-badge removed">Removed</span>';
                rowClass = 'diff-removed';
            } else {
                badge = '<span class="diff-badge modified">Modified</span>';
                rowClass = 'diff-modified';
            }
            return '<tr class="' + rowClass + '">' +
                '<td>' + escHtml(key) + '</td>' +
                '<td>' + badge + '</td>' +
                '<td>' + escHtml(change.old ? JSON.stringify(change.old) : '—') + '</td>' +
                '<td>' + escHtml(change.new ? JSON.stringify(change.new) : '—') + '</td>' +
                '</tr>';
        }

        function renderDiffRows(changes) {
            var rows = '';
            Object.keys(changes).forEach(function(key) {
                rows += renderDiffRow(changes[key], key);
            });
            return rows || '<tr><td colspan="4" style="text-align:center;color:var(--text-dim);">No differences</td></tr>';
        }

        function openDetailModal(data) {
            var overlay = document.createElement('div');
            overlay.className = 'modal-overlay open';
            overlay.innerHTML = '<div class="modal-box">' +
                '<div class="modal-header">' +
                '<h3>Version ' + data.version + ' Details</h3>' +
                '<button class="modal-close" data-onclick="this.closest(\'.modal-overlay\').remove()">\u00d7</button>' +
                '</div>' +
                '<div class="modal-body">' +
                '<p><strong>Created:</strong> ' + escHtml(data.created_at) + '</p>' +
                '<p><strong>Reason:</strong> ' + escHtml(data.reason || '—') + '</p>' +
                '<p><strong>Fields:</strong> ' + (data.fields ? data.fields.length : 0) + '</p>' +
                (data.fields ? '<div style="margin-top:16px;"><table class="diff-table">' +
                '<thead><tr><th>Key</th><th>Label</th><th>Type</th><th>Required</th></tr></thead><tbody>' +
                data.fields.map(function(f) {
                    return '<tr><td>' + escHtml(f.key) + '</td><td>' + escHtml(f.label || '') + '</td><td>' + escHtml(f.type || '') + '</td><td>' + (f.required ? 'Yes' : 'No') + '</td></tr>';
                }).join('') +
                '</tbody></table></div>' : '') +
                '</div>' +
                '<div class="modal-footer">' +
                '<button class="btn btn-outline" data-onclick="this.closest(\'.modal-overlay\').remove()">Close</button>' +
                '</div>' +
                '</div>';
            overlay.addEventListener('click', function(e) { if (e.target === overlay) overlay.remove(); });
            document.body.appendChild(overlay);
        }

        // ─── A/B Testing (Phase 10.9) ─────────────────────────────────────────

        var abTestState = { loading: false, variants: null, csrf: 'window.__SITE_DATA__.csrfToken' };

        function loadABTest() {
            if (abTestState.loading) return;
            abTestState.loading = true;

            var panel = document.getElementById('panel-abtest');
            if (!panel) return;

            var xhr = new XMLHttpRequest();
            xhr.open('GET', '/sites/' + siteId + '/variants', true);
            xhr.onreadystatechange = function () {
                if (xhr.readyState === 4) {
                    abTestState.loading = false;
                    if (xhr.status === 200) {
                        try {
                            var data = JSON.parse(xhr.responseText);
                            abTestState.variants = data;
                            renderABTest(data);
                        } catch (e) {
                            console.error('Failed to parse A/B test data:', e);
                        }
                    }
                }
            };
            xhr.send();
        }

        function renderABTest(data) {
            var panel = document.getElementById('panel-abtest');
            if (!panel) return;

            var variants = data.variants || [];
            var hasActiveTest = variants.length >= 2;
            var stats = data.stats || { a: { impressions: 0, completions: 0, rate: 0 }, b: { impressions: 0, completions: 0, rate: 0 } };

            var html = '<div class="card">' +
                '<h3>A/B Testing</h3>' +
                '<p style="font-size:13px;color:var(--text-muted);margin-bottom:16px;">' +
                'Create two variants of your form to test which performs better. ' +
                'Traffic is split 50/50 between variants automatically.' +
                '</p>';

            // Status indicator
            if (hasActiveTest) {
                html += '<div style="background:#e6f7ee;color:#155724;padding:12px 16px;border-radius:8px;margin-bottom:20px;font-size:14px;">' +
                    '<strong>✓ Active Test</strong> — Variant A vs Variant B receiving equal traffic' +
                    '</div>';
            } else {
                html += '<div style="background:#fff3cd;color:#856404;padding:12px 16px;border-radius:8px;margin-bottom:20px;font-size:14px;">' +
                    '<strong>No Active Test</strong> — Create two variants to start A/B testing' +
                    '</div>';
            }

            // Stats comparison (if active)
            if (hasActiveTest) {
                var aStats = stats.a || { impressions: 0, completions: 0, rate: 0 };
                var bStats = stats.b || { impressions: 0, completions: 0, rate: 0 };
                var winner = aStats.rate > bStats.rate ? 'A' : (bStats.rate > aStats.rate ? 'B' : null);

                html += '<div style="display:grid;grid-template-columns:1fr 1fr;gap:16px;margin-bottom:24px;">';

                ['A', 'B'].forEach(function(key) {
                    var s = key === 'A' ? aStats : bStats;
                    var isWinner = winner === key;
                    html += '<div style="padding:16px;background:' + (isWinner ? '#e6f7ee' : 'var(--surface)') + ';border:2px solid ' + (isWinner ? '#22c55e' : 'var(--border)') + ';border-radius:8px;">' +
                        '<div style="font-size:12px;color:var(--text-muted);margin-bottom:4px;">VARIANT ' + key + (isWinner ? ' <span style="color:#22c55e;font-weight:bold;">★ LEADING</span>' : '') + '</div>' +
                        '<div style="font-size:28px;font-weight:bold;color:var(--primary);">' + s.rate.toFixed(1) + '%</div>' +
                        '<div style="font-size:12px;color:var(--text-muted);">completion rate (' + s.completions + '/' + s.impressions + ')</div>' +
                        '</div>';
                });

                html += '</div>';
            }

            // Variant forms
            html += '<div style="display:grid;grid-template-columns:1fr 1fr;gap:16px;">';

            ['A', 'B'].forEach(function(key) {
                var variant = variants.find(function(v) { return v.variant_key === key; });
                html += '<div style="border:1px solid var(--border);border-radius:8px;padding:16px;">' +
                    '<div style="font-weight:bold;margin-bottom:8px;color:' + (variant ? 'var(--primary)' : 'var(--text-muted)') + ';">' +
                    (variant ? 'Variant ' + key + ': ' + escapeAttr(variant.name || key) : 'Variant ' + key + ' — Not Set') +
                    '</div>';

                if (variant) {
                    html += '<div style="font-size:12px;color:var(--text-muted);margin-bottom:12px;">' +
                        (variant.field_config ? variant.field_config.length : 0) + ' fields' +
                        '</div>';
                    html += '<button class="btn btn-sm btn-outline" data-onclick="editVariant(\'' + key + '\')" style="margin-right:8px;">Edit</button>' +
                        '<button class="btn btn-sm btn-danger" data-onclick="deleteVariant(' + variant.id + ', \'' + key + '\')">Deactivate</button>';
                } else {
                    html += '<button class="btn btn-sm" data-onclick="createVariant(\'' + key + '\')">Create Variant</button>';
                }

                html += '</div>';
            });

            html += '</div></div>';

            // Variant modal (hidden)
            html += '<div id="ab-variant-modal" style="display:none;position:fixed;top:0;left:0;right:0;bottom:0;background:rgba(0,0,0,0.5);z-index:1000;align-items:center;justify-content:center;">' +
                '<div style="background:var(--bg);border-radius:12px;padding:24px;max-width:600px;width:90%;max-height:80vh;overflow-y:auto;">' +
                '<div style="display:flex;justify-content:space-between;align-items:center;margin-bottom:16px;">' +
                '<h3 id="ab-modal-title" style="margin:0;">Create Variant</h3>' +
                '<button data-onclick="closeVariantModal()" style="background:none;border:none;font-size:20px;cursor:pointer;color:var(--text-muted);">✕</button>' +
                '</div>' +
                '<div id="ab-modal-body"></div>' +
                '</div>' +
                '</div>';

            panel.innerHTML = html;
        }

        function createVariant(key) {
            // Get current field config
            var fieldConfigEl = document.getElementById('field_config_json');
            var fieldConfig = fieldConfigEl ? JSON.parse(fieldConfigEl.value) : getFields();

            var name = prompt('Name for Variant ' + key + ' (e.g. "Short Form", "With Phone"):');
            if (!name) return;

            var modal = document.getElementById('ab-variant-modal');
            var body = document.getElementById('ab-modal-body');
            document.getElementById('ab-modal-title').textContent = 'Create Variant ' + key;

            body.innerHTML = '<p style="font-size:13px;color:var(--text-muted);margin-bottom:16px;">' +
                'This variant will show different fields to 50% of visitors. ' +
                'Copy your current form and modify it below.' +
                '</p>' +
                '<div class="field-list" id="variant-field-list">' +
                renderVariantFields(fieldConfig, key) +
                '</div>' +
                '<div style="margin-top:16px;">' +
                '<label style="font-size:13px;color:var(--text-muted);">Success Message (optional):</label><br>' +
                '<input type="text" id="ab-success-msg" placeholder="Leave empty to use default" style="width:100%;padding:8px 12px;border:1px solid var(--border);border-radius:6px;margin-top:4px;">' +
                '</div>' +
                '<div style="margin-top:16px;display:flex;gap:8px;">' +
                '<button class="btn" data-onclick="saveVariant(\'' + key + '\')">Save & Start Test</button>' +
                '<button class="btn btn-outline" data-onclick="closeVariantModal()">Cancel</button>' +
                '</div>';

            modal.style.display = 'flex';
        }

        function editVariant(key) {
            var variant = abTestState.variants.variants.find(function(v) { return v.variant_key === key; });
            if (!variant) return;

            createVariant(key);

            // Update modal title
            document.getElementById('ab-modal-title').textContent = 'Edit Variant ' + key;

            // Update success message
            var successEl = document.getElementById('ab-success-msg');
            if (successEl && variant.success_message) {
                successEl.value = variant.success_message;
            }
        }

        function renderVariantFields(fields, key) {
            var html = '';
            (fields || []).forEach(function(field, idx) {
                html += '<div class="field-item" style="margin-bottom:8px;">' +
                    '<input type="text" class="vf-key" value="' + escapeAttr(field.key || '') + '" placeholder="Key" style="width:80px;">' +
                    '<input type="text" class="vf-label" value="' + escapeAttr(field.label || '') + '" placeholder="Label" style="flex:1;">' +
                    '<select class="vf-type" style="width:100px;">' +
                    ['text', 'email', 'phone', 'number', 'textarea', 'select', 'radio', 'checkbox'].map(function(t) {
                        return '<option value="' + t + '"' + (field.type === t ? ' selected' : '') + '>' + t.charAt(0).toUpperCase() + t.slice(1) + '</option>';
                    }).join('') +
                    '</select>' +
                    '<button data-onclick="this.parentElement.remove()" style="background:none;border:none;cursor:pointer;color:var(--text-muted);">✕</button>' +
                    '</div>';
            });
            html += '<button class="btn btn-sm btn-outline" data-onclick="addVariantField()" style="margin-top:8px;">+ Add Field</button>';
            return html;
        }

        function addVariantField() {
            var list = document.getElementById('variant-field-list');
            var div = document.createElement('div');
            div.className = 'field-item';
            div.style.marginBottom = '8px';
            div.innerHTML = '<input type="text" class="vf-key" placeholder="Key" style="width:80px;">' +
                '<input type="text" class="vf-label" placeholder="Label" style="flex:1;">' +
                '<select class="vf-type" style="width:100px;">' +
                ['text', 'email', 'phone', 'number', 'textarea', 'select', 'radio', 'checkbox'].map(function(t) {
                    return '<option value="' + t + '">' + t.charAt(0).toUpperCase() + t.slice(1) + '</option>';
                }).join('') +
                '</select>' +
                '<button data-onclick="this.parentElement.remove()" style="background:none;border:none;cursor:pointer;color:var(--text-muted);">✕</button>';
            list.appendChild(div);
        }

        function saveVariant(key) {
            var items = document.querySelectorAll('#variant-field-list .field-item');
            var fields = [];
            items.forEach(function(item) {
                var k = item.querySelector('.vf-key').value.trim();
                var label = item.querySelector('.vf-label').value.trim();
                var type = item.querySelector('.vf-type').value;
                if (k) {
                    fields.push({ key: k, label: label || k, type: type, required: false });
                }
            });

            if (fields.length === 0) {
                alert('Add at least one field.');
                return;
            }

            var successMsg = document.getElementById('ab-success-msg').value.trim();

            var xhr = new XMLHttpRequest();
            xhr.open('POST', '/sites/' + siteId + '/variants', true);
            xhr.setRequestHeader('Content-Type', 'application/json');
            xhr.setRequestHeader('X-CSRFToken', abTestState.csrf);
            xhr.onreadystatechange = function () {
                if (xhr.readyState === 4) {
                    if (xhr.status === 201 || xhr.status === 200) {
                        closeVariantModal();
                        loadABTest();
                    } else {
                        alert('Failed to save variant. Try again.');
                    }
                }
            };
            xhr.send(JSON.stringify({
                site_id: siteId,
                variant_key: key,
                name: document.getElementById('ab-success-msg').previousElementSibling ? document.getElementById('ab-success-msg').previousElementSibling.previousElementSibling.textContent : 'Variant ' + key,
                field_config: fields,
                success_message: successMsg || null
            }));
        }

        function deleteVariant(id, key) {
            if (!confirm('Deactivate Variant ' + key + '? This will end the A/B test if both variants are active.')) return;

            var xhr = new XMLHttpRequest();
            xhr.open('DELETE', '/sites/' + siteId + '/variants/' + id, true);
            xhr.setRequestHeader('X-CSRFToken', abTestState.csrf);
            xhr.onreadystatechange = function () {
                if (xhr.readyState === 4) {
                    if (xhr.status === 200) {
                        loadABTest();
                    } else {
                        alert('Failed to deactivate variant.');
                    }
                }
            };
            xhr.send();
        }

        function closeVariantModal() {
            var modal = document.getElementById('ab-variant-modal');
            if (modal) modal.style.display = 'none';
        }

        // ── DOCUMENTS PANEL ──
        var docTemplates = [];
        var docDocuments = [];
        var docSubmissions = [];
        var editingDocTemplateId = null;
        var SITE_ID = window.__SITE_DATA__.siteId;

        function loadDocPanel() {
            loadDocTemplates();
            loadDocDocuments();
            loadDocSubmissions();
        }

        function showDocSection(section) {
            document.querySelectorAll('.doc-section').forEach(function(el) { el.style.display = 'none'; });
            document.querySelectorAll('.doc-subtab').forEach(function(el) { el.classList.remove('active'); });
            var target = document.getElementById('doc-' + section);
            if (target) target.style.display = 'block';
            var tabs = document.querySelectorAll('.doc-subtab');
            var sectionMap = { templates: 0, generate: 1, history: 2, schedules: 3, gallery: 4 };
            var idx = sectionMap[section];
            if (idx !== undefined && tabs[idx]) tabs[idx].classList.add('active');
            if (section === 'schedules' && !window._schedulesLoaded) {
                window._schedulesLoaded = true;
                loadDocSchedules();
            }
            if (section === 'gallery' && !window._galleryLoaded) {
                window._galleryLoaded = true;
                loadDocGallery();
            }
        }

        function loadDocTemplates() {
            fetch('/sites/' + SITE_ID + '/templates')
                .then(function(r) { return r.json(); })
                .then(function(data) {
                    docTemplates = data.templates || [];
                    renderDocTemplates();
                    updateDocTemplateSelects();
                })
                .catch(function(err) { console.error('Failed to load templates:', err); });
        }

        function renderDocTemplates() {
            var grid = document.getElementById('doc-templates-grid');
            var empty = document.getElementById('doc-templates-empty');
            var loading = document.getElementById('doc-templates-loading');
            if (!grid) return;

            loading.style.display = 'none';
            if (docTemplates.length === 0) {
                empty.style.display = 'block';
                grid.style.display = 'none';
                return;
            }
            empty.style.display = 'none';
            grid.style.display = 'grid';
            grid.innerHTML = docTemplates.map(function(t) {
                var autoBadge = t.auto_generate ? '<span class="doc-status-badge ready" style="margin-left:8px;">⚡ auto-gen</span>' : '';
                return '<div class="int-card">' +
                    '<div class="int-card-header">' +
                        '<div class="int-card-icon" style="background:#f0f0ff;">📄</div>' +
                        '<div>' +
                            '<div class="int-card-title">' + escapeHtml(t.name) + autoBadge + '</div>' +
                            '<div class="int-card-type">' + t.layout + ' layout</div>' +
                        '</div>' +
                        '<div class="int-card-actions">' +
                            '<button class="int-btn-sm" data-onclick="editDocTemplate(' + t.id + ')">✏️ Edit</button>' +
                            '<button class="int-btn-sm danger" data-onclick="deleteDocTemplate(' + t.id + ')">🗑️</button>' +
                        '</div>' +
                    '</div>' +
                    '<div class="int-card-body">' +
                        '<div style="font-size:12px;color:var(--text-muted);">From: ' + escapeHtml(t.style.from_name || t.style.from_name || '—') + '</div>' +
                        '<div style="font-size:12px;color:var(--text-dim);">Currency: ' + (t.style.currency || '$') + ' • Tax: ' + (t.style.tax_rate || 0) + '%</div>' +
                    '</div>' +
                '</div>';
            }).join('');
        }

        function updateDocTemplateSelects() {
            var sel = document.getElementById('doc-gen-template');
            if (!sel) return;
            sel.innerHTML = '<option value="">Select a template...</option>' +
                docTemplates.map(function(t) {
                    return '<option value="' + t.id + '">' + escapeHtml(t.name) + '</option>';
                }).join('');
        }

        function loadDocSubmissions() {
            fetch('/sites/' + SITE_ID + '/api/submissions?limit=50')
                .then(function(r) { return r.json(); })
                .then(function(data) {
                    docSubmissions = data.submissions || [];
                    var sel = document.getElementById('doc-gen-submission');
                    if (!sel) return;
                    sel.innerHTML = '<option value="">Manual entry...</option>' +
                        docSubmissions.map(function(s) {
                            return '<option value="' + s.id + '">' + escapeHtml(s.customer_name || s.email || 'Submission #' + s.id) + ' — ' + s.submitted_at + '</option>';
                        }).join('');
                })
                .catch(function(err) { console.error('Failed to load submissions:', err); });
        }

        function loadDocDocuments() {
            fetch('/sites/' + SITE_ID + '/documents')
                .then(function(r) { return r.json(); })
                .then(function(data) {
                    docDocuments = data.documents || [];
                    renderDocHistory();
                })
                .catch(function(err) { console.error('Failed to load documents:', err); });
        }

        function renderDocHistory() {
              var list = document.getElementById('doc-history-list');
              var empty = document.getElementById('doc-history-empty');
              var loading = document.getElementById('doc-history-loading');
              var actions = document.getElementById('doc-history-actions');
              if (!list) return;

              loading.style.display = 'none';
              if (docDocuments.length === 0) {
                  empty.style.display = 'block';
                  list.style.display = 'none';
                  if (actions) actions.style.display = 'none';
                  return;
              }
              empty.style.display = 'none';
              list.style.display = 'block';
              if (actions) actions.style.display = 'flex';

              var now = new Date();
              var statusMap = { draft: 'draft', sent: 'sent', viewed: 'viewed', paid: 'paid', void: 'void' };
              var cycleLabels = { draft: '→ Sent', sent: '→ Viewed', viewed: '→ Paid', paid: '↺ Draft' };

              var rows = docDocuments.map(function(d) {
                  var status = d.status || 'draft';
                  var statusClass = statusMap[status] || 'draft';
                  var isOverdue = false;
                  var overdueBadge = '';
                  var rowClass = '';

                  if (d.due_date && status !== 'paid') {
                      var due = new Date(d.due_date + 'T23:59:59');
                      if (due < now) {
                          isOverdue = true;
                          overdueBadge = '<span class="doc-status-badge overdue" style="margin-left:4px;">OVERDUE</span>';
                          rowClass = 'doc-row-overdue';
                      }
                  }

                  var dueDateDisplay = d.due_date ? ' | Due: ' + escapeHtml(d.due_date) : '';
                  var docNum = d.document_number ? escapeHtml(d.document_number) : '# ' + d.id;

                  return '<tr class="' + rowClass + '">' +
                      '<td><input type="checkbox" class="doc-checkbox" data-id="' + d.id + '" data-onclick="toggleDocCheckbox(this)"></td>' +
                      '<td><strong>' + escapeHtml(docNum) + '</strong>' + overdueBadge +
                          '<div style="font-size:11px;color:var(--text-muted);">' + escapeHtml(d.to_name || d.customer_name || '—') + '</div></td>' +
                      '<td><span class="doc-status-badge ' + statusClass + '">' + status + '</span></td>' +
                      '<td style="font-size:12px;">' + (d.created_at || '—') + dueDateDisplay + '</td>' +
                      '<td style="white-space:nowrap;">' +
                          '<button class="int-btn-sm" data-onclick="cycleDocStatus(' + d.id + ')" title="Cycle status">' + (cycleLabels[status] || '↺') + '</button> ' +
                          '<a href="/documents/' + d.document_id + '/preview" class="int-btn-sm" target="_blank" title="Preview">👁</a> ' +
                          '<a href="/documents/' + d.document_id + '/download" class="int-btn-sm primary" download title="Download">⬇</a>' +
                      '</td>' +
                  '</tr>';
              }).join('');

              list.innerHTML = '<div class="card">' +
                  '<table class="history-table">' +
                  '<thead><tr>' +
                      '<th><input type="checkbox" id="doc-select-all" data-onchange="toggleAllDocCheckboxes(this)" title="Select all"></th>' +
                      '<th>Document</th>' +
                      '<th>Status</th>' +
                      '<th>Date</th>' +
                      '<th>Actions</th>' +
                  '</tr></thead>' +
                  '<tbody>' + rows + '</tbody>' +
                  '</table></div>';
          }

          // ── 13.3: Status Cycle ──
          function cycleDocStatus(docId) {
              fetch('/documents/' + docId + '/status/cycle', {
                  method: 'POST',
                  headers: { 'Content-Type': 'application/json', 'X-CSRFToken': getCsrfToken() }
              })
              .then(function(r) { return r.json(); })
              .then(function(data) {
                  loadDocDocuments();
              })
              .catch(function(err) { alert('Failed to cycle status: ' + err); });
          }

          // ── 13.4: Bulk Generate ──
          function toggleDocCheckbox(el) {
              var allCb = document.getElementById('doc-select-all');
              if (allCb) {
                  var allChecked = document.querySelectorAll('.doc-checkbox');
                  allCb.checked = allChecked.length > 0 && Array.from(allChecked).every(function(cb) { return cb.checked; });
              }
          }

          function toggleAllDocCheckboxes(el) {
              document.querySelectorAll('.doc-checkbox').forEach(function(cb) { cb.checked = el.checked; });
          }

          function bulkGenerateSelected() {
              var selected = Array.from(document.querySelectorAll('.doc-checkbox:checked')).map(function(cb) { return parseInt(cb.dataset.id); });
              if (selected.length === 0) { alert('Please select at least one document.'); return; }

              var progress = document.getElementById('doc-history-progress');
              progress.textContent = 'Generating ' + selected.length + ' documents...';

              var docIds = selected;
              var done = 0;
              var success = 0;
              var failed = 0;

              selected.forEach(function(docId, i) {
                  // Use the selected documents to generate new versions
                  fetch('/documents/' + docId + '/status/cycle', {
                      method: 'POST',
                      headers: { 'Content-Type': 'application/json', 'X-CSRFToken': getCsrfToken() }
                  })
                  .then(function(r) { return r.json(); })
                  .then(function() {
                      done++;
                      success++;
                      progress.textContent = 'Generated ' + done + '/' + selected.length + ' (' + success + ' ok, ' + failed + ' failed)';
                      if (done === selected.length) {
                          setTimeout(function() { progress.textContent = ''; }, 3000);
                          loadDocDocuments();
                      }
                  })
                  .catch(function() {
                      done++;
                      failed++;
                      progress.textContent = 'Generated ' + done + '/' + selected.length + ' (' + success + ' ok, ' + failed + ' failed)';
                      if (done === selected.length) {
                          setTimeout(function() { progress.textContent = ''; }, 3000);
                          loadDocDocuments();
                      }
                  });
              });
          }

        // ── TEMPLATE MODAL ──
        function openDocTemplateModal(tplId) {
            editingDocTemplateId = tplId || null;
            document.getElementById('doc-modal-title').textContent = tplId ? 'Edit Template' : 'New Template';

            if (tplId) {
                var tpl = docTemplates.find(function(t) { return t.id === tplId; });
                if (tpl) {
                    document.getElementById('doc-tpl-name').value = tpl.name || '';
                    document.getElementById('doc-tpl-layout').value = tpl.layout || 'classic';
                    document.getElementById('doc-tpl-from-name').value = (tpl.style && tpl.style.from_name) || '';
                    document.getElementById('doc-tpl-from-email').value = (tpl.style && tpl.style.from_email) || '';
                    document.getElementById('doc-tpl-from-address').value = (tpl.style && tpl.style.from_address) || '';
                    document.getElementById('doc-tpl-currency').value = (tpl.style && tpl.style.currency) || '$';
                    document.getElementById('doc-tpl-tax-rate').value = (tpl.style && tpl.style.tax_rate) || 0;
                    document.getElementById('doc-tpl-notes').value = (tpl.style && tpl.style.notes) || '';
                    document.getElementById('doc-tpl-primary').value = (tpl.style && tpl.style.primary_color) || '#2563eb';
                    document.getElementById('doc-tpl-logo').value = (tpl.style && tpl.style.logo_url) || '';
                    document.getElementById('doc-tpl-payment-link').value = (tpl.style && tpl.style.payment_link) || '';
                    document.getElementById('doc-tpl-payment-link-text').value = (tpl.style && tpl.style.payment_link_text) || 'Pay Now';
                    document.getElementById('doc-tpl-invoice-format').value = tpl.invoice_number_format || 'INV-YYYY-####';
                    document.getElementById('doc-tpl-next-invoice').value = tpl.next_invoice_number || '';
                    document.getElementById('doc-tpl-auto-gen').checked = !!tpl.auto_generate;
                }
            } else {
                clearDocTemplateForm();
            }

            document.getElementById('doc-template-modal').classList.add('open');
        }

        function closeDocTemplateModal() {
            document.getElementById('doc-template-modal').classList.remove('open');
            editingDocTemplateId = null;
        }

        function clearDocTemplateForm() {
            document.getElementById('doc-tpl-name').value = '';
            document.getElementById('doc-tpl-layout').value = 'classic';
            document.getElementById('doc-tpl-from-name').value = '';
            document.getElementById('doc-tpl-from-email').value = '';
            document.getElementById('doc-tpl-from-address').value = '';
            document.getElementById('doc-tpl-currency').value = '$';
            document.getElementById('doc-tpl-tax-rate').value = 0;
            document.getElementById('doc-tpl-notes').value = '';
            document.getElementById('doc-tpl-primary').value = '#2563eb';
            document.getElementById('doc-tpl-logo').value = '';
            document.getElementById('doc-tpl-payment-link').value = '';
            document.getElementById('doc-tpl-payment-link-text').value = 'Pay Now';
            document.getElementById('doc-tpl-invoice-format').value = 'INV-YYYY-####';
            document.getElementById('doc-tpl-next-invoice').value = '';
            }

        function saveDocTemplate() {
            var name = document.getElementById('doc-tpl-name').value.trim();
            if (!name) { alert('Template name is required'); return; }

            var style = {
                from_name: document.getElementById('doc-tpl-from-name').value.trim(),
                from_email: document.getElementById('doc-tpl-from-email').value.trim(),
                from_address: document.getElementById('doc-tpl-from-address').value.trim(),
                currency: document.getElementById('doc-tpl-currency').value,
                tax_rate: parseFloat(document.getElementById('doc-tpl-tax-rate').value) || 0,
                notes: document.getElementById('doc-tpl-notes').value.trim(),
                primary_color: document.getElementById('doc-tpl-primary').value,
                logo_url: document.getElementById('doc-tpl-logo').value.trim(),
                payment_link: document.getElementById('doc-tpl-payment-link').value.trim(),
                payment_link_text: document.getElementById('doc-tpl-payment-link-text').value.trim(),
                invoice_number_format: document.getElementById('doc-tpl-invoice-format').value.trim(),
                next_invoice_number: document.getElementById('doc-tpl-next-invoice').value.trim() || null
            };

            var url = editingDocTemplateId
                ? '/sites/' + SITE_ID + '/templates/' + editingDocTemplateId
                : '/sites/' + SITE_ID + '/templates';

            var method = editingDocTemplateId ? 'PUT' : 'POST';

            fetch(url, {
                method: method,
                headers: { 'Content-Type': 'application/json', 'X-CSRFToken': getCsrfToken() },
                body: JSON.stringify({
                    name: name,
                    layout: document.getElementById('doc-tpl-layout').value,
                    style: style,
                    auto_generate: document.getElementById('doc-tpl-auto-gen').checked,
                    invoice_number_format: style.invoice_number_format,
                    next_invoice_number: style.next_invoice_number
                })
            })
            .then(function(r) { return r.json(); })
            .then(function(data) {
                if (data.status === 'ok') {
                    closeDocTemplateModal();
                    loadDocTemplates();
                } else {
                    alert('Error: ' + (data.error || 'Unknown error'));
                }
            })
            .catch(function(err) { alert('Request failed: ' + err); });
        }

        function editDocTemplate(id) {
            openDocTemplateModal(id);
        }

        function deleteDocTemplate(id) {
            if (!confirm('Delete this template?')) return;
            fetch('/sites/' + SITE_ID + '/templates/' + id, {
                method: 'DELETE',
                headers: { 'X-CSRFToken': getCsrfToken() }
            })
            .then(function(r) { return r.json(); })
            .then(function(data) {
                if (data.status === 'ok') loadDocTemplates();
                else alert('Error: ' + (data.error || 'Unknown error'));
            })
            .catch(function(err) { alert('Request failed: ' + err); });
        }

        // ── DOCUMENT GENERATION ──
        function onDocTemplateChange() {
            var tplId = document.getElementById('doc-gen-template').value;
            var fieldsDiv = document.getElementById('doc-gen-fields');
            fieldsDiv.innerHTML = '';

            if (!tplId) return;

            var tpl = docTemplates.find(function(t) { return t.id === parseInt(tplId); });
            if (tpl && tpl.field_mappings) {
                fieldsDiv.innerHTML = buildDocFields(tpl.field_mappings);
            } else {
                fieldsDiv.innerHTML = buildDefaultDocFields();
            }
        }

        function buildDefaultDocFields() {
            return '<div class="form-group"><label>To (Customer Name)</label><input type="text" id="doc-to-name" placeholder="Customer Name"></div>' +
                '<div class="form-group"><label>To (Email)</label><input type="email" id="doc-to-email" placeholder="customer@example.com"></div>' +
                '<div class="form-group"><label>Document Number</label><input type="text" id="doc-number" placeholder="INV-001"></div>' +
                '<div class="form-group"><label>Issue Date</label><input type="date" id="doc-issue-date"></div>' +
                '<div class="form-group"><label>Due Date</label><input type="date" id="doc-due-date"></div>' +
                '<div class="form-group"><label>Line Items (JSON)</label><textarea id="doc-line-items" rows="4" placeholder=\'[{"description":"Service","quantity":1,"unit_price":100}]\'></textarea></div>';
        }

        function buildDocFields(mappings) {
            return buildDefaultDocFields();
        }

        function onDocSubmissionChange() {
            var subId = document.getElementById('doc-gen-submission').value;
            if (!subId) return;
            var sub = docSubmissions.find(function(s) { return s.id === parseInt(subId); });
            if (!sub) return;
            if (sub.customer_name) document.getElementById('doc-to-name').value = sub.customer_name;
            if (sub.customer_email) document.getElementById('doc-to-email').value = sub.customer_email;
        }

        function getDocPayload() {
            var lineItemsRaw = document.getElementById('doc-line-items').value || '[]';
            var lineItems;
            try { lineItems = JSON.parse(lineItemsRaw); } catch(e) { lineItems = []; }

            return {
                to: {
                    name: document.getElementById('doc-to-name').value.trim(),
                    email: document.getElementById('doc-to-email').value.trim()
                },
                document_number: document.getElementById('doc-number').value.trim(),
                issue_date: document.getElementById('doc-issue-date').value || null,
                due_date: document.getElementById('doc-due-date').value || null,
                line_items: lineItems
            };
        }

        function generateDoc() {
            var tplId = document.getElementById('doc-gen-template').value;
            if (!tplId) { alert('Please select a template'); return; }

            var payload = getDocPayload();
            if (!payload.to.name) { alert('Customer name is required'); return; }

            fetch('/documents/generate', {
                method: 'POST',
                headers: { 'Content-Type': 'application/json', 'X-CSRFToken': getCsrfToken() },
                body: JSON.stringify({
                    site_id: SITE_ID,
                    template_id: parseInt(tplId),
                    document_type: document.getElementById('doc-gen-type').value,
                    data: payload
                })
            })
            .then(function(r) { return r.json(); })
            .then(function(data) {
                if (data.status === 'ok') {
                    window.open('/documents/' + data.document_id + '/download', '_blank');
                    loadDocDocuments();
                } else {
                    alert('Error: ' + (data.error || 'Generation failed'));
                }
            })
            .catch(function(err) { alert('Request failed: ' + err); });
        }

        function previewDoc() {
            var tplId = document.getElementById('doc-gen-template').value;
            if (!tplId) { alert('Please select a template'); return; }

            var payload = getDocPayload();

            fetch('/sites/' + SITE_ID + '/documents/preview', {
                method: 'POST',
                headers: { 'Content-Type': 'application/json', 'X-CSRFToken': getCsrfToken() },
                body: JSON.stringify({
                    template_id: parseInt(tplId),
                    document_type: document.getElementById('doc-gen-type').value,
                    data: payload
                })
            })
            .then(function(r) { return r.text(); })
            .then(function(html) {
                var win = window.open('', '_blank');
                win.document.write(html);
            })
            .catch(function(err) { alert('Preview failed: ' + err); });
        }

        // ── 13.5: Invoice Schedules ──
        var docSchedules = [];

        function loadDocSchedules() {
            var loading = document.getElementById('doc-schedules-loading');
            if (loading) loading.style.display = 'block';
            fetch('/sites/' + SITE_ID + '/invoice-schedules')
                .then(function(r) { return r.json(); })
                .then(function(data) {
                    docSchedules = data.schedules || [];
                    renderDocSchedules();
                    updateScheduleTemplateSelect();
                })
                .catch(function(err) {
                    console.error('Failed to load schedules:', err);
                    if (loading) loading.style.display = 'none';
                });
        }

        function updateScheduleTemplateSelect() {
            var sel = document.getElementById('schedule-template');
            if (!sel) return;
            sel.innerHTML = '<option value="">Select a template...</option>' +
                docTemplates.map(function(t) {
                    return '<option value="' + t.id + '">' + escapeHtml(t.name) + '</option>';
                }).join('');
        }

        function renderDocSchedules() {
            var list = document.getElementById('doc-schedules-list');
            var empty = document.getElementById('doc-schedules-empty');
            var loading = document.getElementById('doc-schedules-loading');
            if (!list) return;

            loading.style.display = 'none';
            if (docSchedules.length === 0) {
                empty.style.display = 'block';
                list.style.display = 'none';
                return;
            }
            empty.style.display = 'none';
            list.style.display = 'block';

            var rows = docSchedules.map(function(s) {
                var enabled = !!s.enabled;
                return '<tr>' +
                    '<td><strong>' + escapeHtml(s.customer_name || '—') + '</strong>' +
                        '<div style="font-size:11px;color:var(--text-muted);">' + escapeHtml(s.customer_email || '') + '</div></td>' +
                    '<td>' + (s.template_name || '—') + '</td>' +
                    '<td>' + escapeHtml(s.interval) + (s.interval_count && s.interval_count > 1 ? ' x' + s.interval_count : '') + '</td>' +
                    '<td style="font-size:12px;">' + (s.next_run || '—') + '</td>' +
                    '<td style="font-size:12px;">' + (s.last_run || 'Never') + '</td>' +
                    '<td><label class="toggle-switch"><input type="checkbox" ' + (enabled ? 'checked' : '') + ' data-onchange="toggleScheduleEnabled(' + s.id + ', this.checked)"><span class="toggle-slider"></span></label></td>' +
                    '<td style="white-space:nowrap;">' +
                        '<button class="int-btn-sm" data-onclick="editSchedule(' + s.id + ')">✏️</button> ' +
                        '<button class="int-btn-sm danger" data-onclick="deleteSchedule(' + s.id + ')">🗑️</button>' +
                    '</td>' +
                '</tr>';
            }).join('');

            list.innerHTML = '<div class="card">' +
                '<table class="schedule-table">' +
                '<thead><tr>' +
                    '<th>Customer</th>' +
                    '<th>Template</th>' +
                    '<th>Interval</th>' +
                    '<th>Next Run</th>' +
                    '<th>Last Run</th>' +
                    '<th>Enabled</th>' +
                    '<th>Actions</th>' +
                '</tr></thead>' +
                '<tbody>' + rows + '</tbody>' +
                '</table></div>';
        }

        function openScheduleModal(editId) {
            document.getElementById('schedule-modal-title').textContent = editId ? 'Edit Schedule' : 'New Schedule';
            document.getElementById('schedule-edit-id').value = editId || '';
            document.getElementById('schedule-customer-name').value = '';
            document.getElementById('schedule-customer-email').value = '';
            document.getElementById('schedule-interval').value = 'monthly';
            document.getElementById('schedule-interval-count').value = '1';
            document.getElementById('schedule-start-date').value = '';
            document.getElementById('schedule-doc-prefix').value = 'INV';
            document.getElementById('schedule-line-items').value = '';
            document.getElementById('schedule-enabled').checked = true;
            updateScheduleTemplateSelect();

            if (editId) {
                var s = docSchedules.find(function(sc) { return sc.id === editId; });
                if (s) {
                    document.getElementById('schedule-template').value = s.template_id || '';
                    document.getElementById('schedule-customer-name').value = s.customer_name || '';
                    document.getElementById('schedule-customer-email').value = s.customer_email || '';
                    document.getElementById('schedule-interval').value = s.interval || 'monthly';
                    document.getElementById('schedule-interval-count').value = s.interval_count || 1;
                    document.getElementById('schedule-start-date').value = s.start_date || '';
                    document.getElementById('schedule-doc-prefix').value = s.document_number_prefix || 'INV';
                    if (s.line_items && Array.isArray(s.line_items)) {
                        document.getElementById('schedule-line-items').value = JSON.stringify(s.line_items, null, 2);
                    }
                    document.getElementById('schedule-enabled').checked = !!s.enabled;
                }
            }

            document.getElementById('doc-schedule-modal').classList.add('open');
        }

        function closeScheduleModal() {
            document.getElementById('doc-schedule-modal').classList.remove('open');
        }

        function saveSchedule() {
            var editId = document.getElementById('schedule-edit-id').value;
            var templateId = document.getElementById('schedule-template').value;
            var customerName = document.getElementById('schedule-customer-name').value.trim();
            var customerEmail = document.getElementById('schedule-customer-email').value.trim();
            var startDate = document.getElementById('schedule-start-date').value;

            if (!templateId || !customerName || !customerEmail || !startDate) {
                alert('Template, customer name, email, and start date are required.');
                return;
            }

            var lineItemsRaw = document.getElementById('schedule-line-items').value || '[]';
            var lineItems;
            try { lineItems = JSON.parse(lineItemsRaw); } catch(e) { lineItems = []; }

            var payload = {
                template_id: parseInt(templateId),
                customer_name: customerName,
                customer_email: customerEmail,
                line_items: lineItems,
                document_number_prefix: document.getElementById('schedule-doc-prefix').value.trim() || 'INV',
                interval: document.getElementById('schedule-interval').value,
                interval_count: parseInt(document.getElementById('schedule-interval-count').value) || 1,
                start_date: startDate,
                enabled: document.getElementById('schedule-enabled').checked
            };

            var url = editId
                ? '/sites/' + SITE_ID + '/invoice-schedules/' + editId
                : '/sites/' + SITE_ID + '/invoice-schedules';
            var method = editId ? 'PUT' : 'POST';

            fetch(url, {
                method: method,
                headers: { 'Content-Type': 'application/json', 'X-CSRFToken': getCsrfToken() },
                body: JSON.stringify(payload)
            })
            .then(function(r) { return r.json(); })
            .then(function(data) {
                closeScheduleModal();
                loadDocSchedules();
            })
            .catch(function(err) { alert('Failed to save schedule: ' + err); });
        }

        function editSchedule(id) {
            openScheduleModal(id);
        }

        function deleteSchedule(id) {
            if (!confirm('Delete this schedule?')) return;
            fetch('/sites/' + SITE_ID + '/invoice-schedules/' + id, {
                method: 'DELETE',
                headers: { 'X-CSRFToken': getCsrfToken() }
            })
            .then(function(r) { return r.json(); })
            .then(function() {
                loadDocSchedules();
            })
            .catch(function(err) { alert('Failed to delete schedule: ' + err); });
        }

        function toggleScheduleEnabled(id, enabled) {
            fetch('/sites/' + SITE_ID + '/invoice-schedules/' + id, {
                method: 'PUT',
                headers: { 'Content-Type': 'application/json', 'X-CSRFToken': getCsrfToken() },
                body: JSON.stringify({ enabled: enabled })
            })
            .then(function() { loadDocSchedules(); })
            .catch(function(err) { alert('Failed to update schedule: ' + err); });
        }

        function runDueSchedules() {
            fetch('/sites/' + SITE_ID + '/invoice-schedules/run', {
                method: 'POST',
                headers: { 'Content-Type': 'application/json', 'X-CSRFToken': getCsrfToken() }
            })
            .then(function(r) { return r.json(); })
            .then(function(data) {
                var results = data.results || [];
                var ok = results.filter(function(r) { return r.status === 'ok'; }).length;
                var err = results.filter(function(r) { return r.error; }).length;
                alert('Processed ' + results.length + ' schedules: ' + ok + ' ok, ' + err + ' errors');
                loadDocSchedules();
                loadDocDocuments();
            })
            .catch(function(err) { alert('Failed to run schedules: ' + err); });
        }

        // ── 13.7: Template Gallery ──
        function loadDocGallery() {
            var loading = document.getElementById('doc-gallery-loading');
            if (loading) loading.style.display = 'block';
            fetch('/documents/gallery')
                .then(function(r) { return r.json(); })
                .then(function(data) {
                    renderDocGallery(data.gallery || []);
                })
                .catch(function(err) {
                    console.error('Failed to load gallery:', err);
                    if (loading) loading.style.display = 'none';
                    var empty = document.getElementById('doc-gallery-empty');
                    if (empty) empty.style.display = 'block';
                });
        }

        function renderDocGallery(items) {
            var grid = document.getElementById('doc-gallery-grid');
            var empty = document.getElementById('doc-gallery-empty');
            var loading = document.getElementById('doc-gallery-loading');
            if (!grid) return;

            loading.style.display = 'none';
            if (items.length === 0) {
                empty.style.display = 'block';
                grid.style.display = 'none';
                return;
            }
            empty.style.display = 'none';
            grid.style.display = 'grid';

            grid.innerHTML = items.map(function(item) {
                var layoutIcons = { classic: '📄', modern: '✨', minimal: '◻️', bold: '💪' };
                var icon = layoutIcons[item.layout] || '📋';
                return '<div class="gallery-card">' +
                    '<span class="gallery-badge">' + escapeHtml(item.layout) + '</span>' +
                    '<h4>' + icon + ' ' + escapeHtml(item.name) + '</h4>' +
                    '<p>' + escapeHtml(item.description || item.preview || '') + '</p>' +
                    '<button class="btn" data-onclick="useGalleryTemplate(\'' + escapeHtml(item.layout) + '\', \'' + escapeHtml(item.name) + '\')">Use Template</button>' +
                '</div>';
            }).join('');
        }

        function useGalleryTemplate(layout, name) {
            // Pre-fill the template modal with gallery data
            openDocTemplateModal();
            document.getElementById('doc-tpl-name').value = name + ' Template';
            document.getElementById('doc-tpl-layout').value = layout;
            document.getElementById('doc-modal-title').textContent = 'New Template from Gallery';
        }

        function getCsrfToken() {
            var input = document.querySelector('input[name="csrf_token"]');
            return input ? input.value : '';
        }

        function escapeHtml(str) {
            if (!str) return '';
            return String(str).replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/"/g, '&quot;');
        }
