jQuery(function($) {

    function seoEscape(str) {
        return String(str || '').replace(/&/g,'&amp;').replace(/</g,'&lt;').replace(/>/g,'&gt;').replace(/"/g,'&quot;');
    }
    function seoToast(msg, type) {
        if (typeof showImpulseToast === 'function') { showImpulseToast(msg, type); return; }
        var $t = $('<div>').text(msg).css({
            position:'fixed',bottom:'20px',right:'20px',
            background: type==='error' ? '#555' : '#3a3f44',
            color:'#e0e0e0',padding:'8px 14px',borderRadius:'3px',fontSize:'11px',zIndex:99999
        }).appendTo('body');
        setTimeout(function(){ $t.fadeOut(300, function(){ $t.remove(); }); }, 2500);
    }

    var _seoState = {
        pages:            [],
        currentPageId:    null,
        currentSlug:      '',
        currentPermalink: '',
        redirects:        [],
        settings:         null,
        dirty:            false,
        saveTimer:        null,
        analysis:         null,
        initialized:      false
    };
    window._seoState = _seoState;

    function seoApi(path, method, data) {
        return $.ajax({
            url:         Impulse.api + 'seo' + path,
            method:      method || 'GET',
            contentType: 'application/json',
            beforeSend:  function(xhr) { xhr.setRequestHeader('X-WP-Nonce', Impulse.nonce); },
            data:        data ? JSON.stringify(data) : undefined});
    }

    function seoScoreColor(score) {
        if (score >= 75) return '#e0e0e0';
        if (score >= 55) return '#aaa';
        if (score >= 35) return '#777';
        return '#555';
    }
    function seoScoreCls(score) {
        if (score >= 75) return 's-high';
        if (score >= 40) return 's-mid';
        return 's-low';
    }

    $(document).on('impulse:workspace:seo', function() { seoInitWorkspace(); });

    

    

    
    $(document).on('impulse:workspace:settings', function() {
        if (!_seoState.settings) seoLoadSettings();
    });

    
    $(document).ready(function() {
        if (window.Impulse && window.Impulse.workspace === 'settings' && !_seoState.settings) {
            seoLoadSettings();
        }
    });

    function seoInitWorkspace() {
        if (!_seoState.pages.length) seoLoadPages();
        if (!_seoState.settings)     seoLoadSettings();
        seoLoadOverview();
        seoShowTab('pages');
        _gscLoad();
    }

    

    var _gscLoaded = false;
    var _gscData = null;
    function _gscShow() {
        if (!_gscData) return;
        $('#gsc-fallback').hide();
        $('#gsc-panel').show();
        $('#seo-center-empty').css({ 'align-items': 'stretch', 'justify-content': 'flex-start' });
    }

    var _gscRange  = '28d';
    var _gscByRange = {};

    function _gscLoad(force) {
        if (_gscLoaded && !force) { _gscShow(); return; }
        _gscLoaded = true;
        if (_gscByRange[_gscRange]) { _gscData = _gscByRange[_gscRange]; _gscShow(); _gscPaint(_gscData); return; }
        $.ajax({ url: Impulse.api + 'analytics/gsc?range=' + encodeURIComponent(_gscRange), method: 'GET', headers: { 'X-WP-Nonce': Impulse.nonce } })
        .done(function(d) {
            if (d && d.available) _gscByRange[_gscRange] = d;
            _gscPaint(d);
        });
    }

    function _gscPaint(d) {
        (function(d) {
            if (!d || !d.available) return;
            _gscData = d;
            _gscShow();
            $('#gsc-kpi-clicks').text(_fmtNum((d.totals || {}).clicks || 0));
            $('#gsc-kpi-impressions').text(_fmtNum((d.totals || {}).impressions || 0));

            if (d.range) $('#gsc-range').text(d.range.from + ' to ' + d.range.to
                + (d.range.lag_days ? '  ·  Google reports up to ' + d.range.lag_days + ' days behind' : ''));

            var GRID = 'display:grid;grid-template-columns:1fr 56px 70px 48px;gap:0 10px;align-items:baseline';
            function gscHeader(labelCol) {
                return '<div style="' + GRID + ';margin-bottom:6px;font-size:10px;color:#666;text-transform:uppercase;letter-spacing:.5px">'
                    + '<span>' + labelCol + '</span>'
                    + '<span style="text-align:right">Clicks</span>'
                    + '<span style="text-align:right">Impr</span>'
                    + '<span style="text-align:right">Pos</span>'
                  + '</div>';
            }
            function gscRow(label, r) {
                return '<div style="' + GRID + ';margin-bottom:4px">'
                    + '<span style="color:#bbb;font-size:11px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap">' + _esc(label) + '</span>'
                    + '<span style="text-align:right;font-size:11px;color:' + ((r.clicks|0) ? '#e0e0e0' : '#666') + '">' + _fmtNum(r.clicks) + '</span>'
                    + '<span style="text-align:right;font-size:11px;color:#999">' + _fmtNum(r.impressions) + '</span>'
                    + '<span style="text-align:right;font-size:11px;color:#999">' + r.position + '</span>'
                  + '</div>';
            }
            function gscTable(rows, labelCol, keyFn, emptyMsg) {
                if (!rows.length) return '<div style="color:#555;font-size:11px">' + emptyMsg + '</div>';
                return gscHeader(labelCol) + rows.map(function(r){ return gscRow(keyFn(r), r); }).join('');
            }
            var byTraffic = function(a, b) { return (b.clicks - a.clicks) || (b.impressions - a.impressions); };

            var nm = (d.nearMiss || []).slice();
            $('#gsc-nearmiss').html(gscTable(nm, 'Query', function(r){ return r.query; }, 'Nothing sitting just below page 1 right now.'));

            var qs = (d.queries || []).slice().sort(byTraffic).slice(0, 15);
            $('#gsc-queries').html(gscTable(qs, 'Query', function(r){ return r.query; }, 'No search data yet.'));

            var ps = (d.pages || []).slice().sort(byTraffic).slice(0, 15);
            $('#gsc-pages').html(gscTable(ps, 'Page', function(r){ return r.path; }, 'No search data yet.'));
        })(d);
    }

    $(document).on('click', '.gsc-range-btn', function() {
        var $b = $(this);
        if ($b.hasClass('active')) return;
        $('.gsc-range-btn').removeClass('active').css({background:'transparent',border:'1px solid #2a2e33',color:'#999'});
        $b.addClass('active').css({background:'#e0e0e0',border:'1px solid #e0e0e0',color:'#1d2327'});
        _gscRange = $b.data('range');
        $('#gsc-range').text('Loading…');
        _gscLoad(true);
    });

    
    function seoShowTab(tab) {
        $('#seo-center-empty,#seo-page-editor').hide();
        $('#seo-right-analysis,#seo-settings-right').hide();

        if (tab === 'pages') {
            _seoState.currentPageId ? $('#seo-page-editor').show() : $('#seo-center-empty').show();
            if (!_seoState.currentPageId) _gscLoad();
            if (_seoState.currentPageId) {
                $('#seo-right-analysis').show();
                if (_seoState.analysis) seoRenderChecks(_seoState.analysis);
            } else {
                
                $('#seo-settings-right').show();
                seoRenderSettingsRight();
            }
        }
    }

    var _seoOverviewData = {};

    function seoLoadOverview() {
        seoApi('/overview').done(function(d) {
            _seoOverviewData = d;
            var score  = d.avg_score || 0;
            var issues = [];
            if (d.missing_title   > 0) issues.push(d.missing_title   + ' no title');
            if (d.missing_desc    > 0) issues.push(d.missing_desc    + ' no desc');
            if (d.cannibal_count  > 0) issues.push(d.cannibal_count  + ' keyword conflict');
            if (d.low_score_count > 0) issues.push(d.low_score_count + ' low score');
            $('#seo-strip-score').text(score);
            $('#seo-strip-issues').text(issues.length ? issues.join(' · ') : 'No issues');

            var ringClr = seoScoreColor(score);
            var circ    = 289.0;
            var offset  = circ - (score / 100) * circ;
            var cannibal = d.cannibal_count || 0;
            var cannibalTips = (d.cannibal_keywords || []).slice(0,5).join(', ');
            var cards = [
                { num: d.total_pages,  label: 'Pages',     filter: null,          ai: null },
                { num: d.issues_total, label: 'Issues',    filter: 'issues',      ai: null },
                { num: d.missing_title,label: 'No Title',  filter: 'no_title',    ai: 'title' },
                { num: d.missing_desc, label: 'No Desc',   filter: 'no_desc',     ai: 'desc' },
                { num: d.noindex_count,label: 'Noindex',   filter: 'noindex',     ai: null },
                { num: cannibal,       label: 'Duplicate Keywords', filter: 'cannibal', ai: null, tip: cannibalTips }];
            var cardsHtml = '<div style="display:grid;grid-template-columns:1fr 1fr;gap:5px;margin-bottom:6px">';
            cards.forEach(function(c) {
                var clickable = c.filter ? ' seo-stat-card-clickable" data-filter="' + c.filter + '"' : '"';
                var tip = c.tip ? ' title="' + seoEscape(c.tip) + '"' : '';
                cardsHtml += '<div class="seo-stat-card' + clickable + tip + '>'
                    + '<div class="seo-stat-card-num">' + (c.num||0) + '</div>'
                    + '<div class="seo-stat-card-label">' + c.label + '</div>'
                    + '</div>';
            });
            cardsHtml += '</div>';

            var html = '<div style="padding:6px 0 8px;text-align:center">'
                + '<div style="position:relative;display:inline-block;width:110px;height:110px">'
                + '<svg width="110" height="110" viewBox="0 0 110 110" style="transform:rotate(-90deg)">'
                + '<circle cx="55" cy="55" r="46" fill="none" stroke="#2a2e33" stroke-width="10"/>'
                + '<circle cx="55" cy="55" r="46" fill="none" stroke="#e0e0e0" stroke-width="10" stroke-dasharray="289.0" stroke-dashoffset="' + (289.0 - (score/100)*289.0) + '" stroke-linecap="round"/>'
                + '</svg>'
                + '<div style="position:absolute;inset:0;display:flex;flex-direction:column;align-items:center;justify-content:center">'
                + '<span style="font-size:28px;font-weight:700;color:#e0e0e0;line-height:1">' + score + '</span>'
                + '<span style="font-size:11px;color:#555">/100</span>'
                + '</div></div>'
                + '<div style="font-size:11px;color:#777;margin-top:4px">Site Health</div>'
                + '</div>'
                + cardsHtml
                ;

            $('#seo-settings-right-inner').html(html);
            
            if (d.sitemap_url) $('#seo-sitemap-url').text(d.sitemap_url);
        });
    }

    var _seoOverviewDataCache = null;
    function seoRenderSettingsRight() {
        if (_seoOverviewDataCache) {
            _seoOverviewData = _seoOverviewDataCache;
        }
        if (!$('#seo-settings-right-inner').text().trim() || $('#seo-settings-right-inner').text().trim() === 'Loading…') {
            seoLoadOverview();
        }
        $('#seo-settings-right').show();
    }

    $(document).on('click', '#seo-sitemap-generate', function() {
        var $btn = $(this);
        $btn.text('Generating\u2026').prop('disabled', true);
        seoApi('/sitemap/generate', 'POST', {}).done(function(data) {
            $btn.text('Generate Sitemap').prop('disabled', false);
            var ts = new Date().toLocaleTimeString([], {hour:'2-digit',minute:'2-digit'});
            $('#seo-sitemap-ts').text('Last generated: ' + ts);
            if (data.sitemap_url) {
                $('#seo-sitemap-url').html('<a href="' + seoEscape(data.sitemap_url) + '" target="_blank" style="color:#555">' + seoEscape(data.sitemap_url) + '</a>');
                $('#seo-sitemap-view').attr('href', data.sitemap_url).css('display', 'flex');
                seoToast('Sitemap generated');
            }
        }).fail(function(xhr) {
            var msg = 'Failed';
            try { msg = JSON.parse(xhr.responseText).message || msg; } catch(e) {}
            $btn.text('Generate Sitemap').prop('disabled', false);
            seoToast('Sitemap generation failed: ' + msg, 'error');
        });
    });

    function expandRobots() {
        var el = document.getElementById('seo-s-robots');
        if (!el) return;
        el.style.height = '26px';
        el.style.height = Math.max(26, el.scrollHeight) + 'px';
    }
    $(document).on('input', '#seo-s-robots', expandRobots);
    $(document).on('impulse:seo:rendered', expandRobots);
    
    $(document).on('impulse:seo:settings:loaded', function() { setTimeout(expandRobots, 50); });

    $(document).on('click', '#seo-robots-preview', function() {
        seoApi('/robots')
            .done(function(data) {
                $('#seo-robots-content').text(data.content || '(empty)');
                $('#seo-robots-modal').show();
            })
            .fail(function(xhr) {
                var msg = (xhr.responseJSON && (xhr.responseJSON.message || xhr.responseJSON.error)) || ('HTTP ' + xhr.status);
                $('#seo-robots-content').text('Error: ' + msg);
                $('#seo-robots-modal').show();
            });
    });

    function seoLoadPages() {
        seoApi('/pages').done(function(pages) {
            _seoState.pages = Array.isArray(pages) ? pages : [];
            seoRenderPagesList();
        }).fail(function(xhr) {
            console.error('[SEO] seoLoadPages failed:', xhr.status, xhr.responseText);
            $('#seo-pages-list').html('<div style="padding:20px;text-align:center;color:#555;font-size:11px">Failed to load pages (see console).</div>');
        });
    }

    var _seoView = 'list'; 

    function seoRenderPagesList() {
        var pages = _seoState.pages;
        if (!pages.length) {
            $('#seo-pages-list').html('<div style="padding:20px;text-align:center;color:#555;font-size:11px">No pages found.</div>');
            return;
        }
        if (_seoView === 'grid') {
            seoRenderPagesGrid(pages);
        } else {
            seoRenderPagesListView(pages);
        }
    }

    function seoRenderPagesListView(pages) {
        var $list = $('#seo-pages-list').removeClass('grid-mode');
        var html = '';
        pages.forEach(function(p) {
            var active    = _seoState.currentPageId === p.id ? ' active' : '';
            var scoreNum  = (p.score != null && p.score > 0) ? p.score : null;
            var scoreCls  = scoreNum ? seoScoreCls(scoreNum) : '';
            var scoreText = scoreNum ? (scoreNum + '/100') : '—';
            html += '<div class="seo-page-row' + active + '" data-page-id="' + p.id + '">'
                + '<div class="seo-page-row-info">'
                + '<div class="seo-page-row-name" title="Double-click to rename">' + seoEscape(p.title) + '</div>'
                + '</div>'
                + '<div class="seo-page-row-score ' + scoreCls + '">' + scoreText + '</div>'
                + '</div>';
        });
        $list.html(html);
    }

    function seoRenderPagesGrid(pages) {
        var $list = $('#seo-pages-list').addClass('grid-mode');
        var html = '';
        pages.forEach(function(p) {
            var active    = _seoState.currentPageId === p.id ? ' active' : '';
            var scoreNum  = (p.score != null && p.score > 0) ? p.score : null;
            var scoreCls  = scoreNum ? seoScoreCls(scoreNum) : '';
            var scoreText = scoreNum ? scoreNum : '—';
            var thumbUrl  = p.thumbnail || '';
            var thumb     = thumbUrl
                ? '<img src="' + seoEscape(thumbUrl) + '" loading="lazy" alt="">'
                : '<div class="seo-page-card-no-thumb"><svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="#3a3f44" stroke-width="1.5"><rect x="3" y="3" width="18" height="18" rx="2"/><path d="m3 9 5-5 4 4 3-3 6 6"/><circle cx="8.5" cy="8.5" r="1.5"/></svg></div>';
            html += '<div class="seo-page-card' + active + '" data-page-id="' + p.id + '">'
                + '<div class="seo-page-card-thumb">' + thumb + '</div>'
                + '<div class="seo-page-card-foot">'
                + '<div class="seo-page-card-name" title="' + seoEscape(p.title) + '">' + seoEscape(p.title) + '</div>'
                + '<div class="seo-page-card-score ' + scoreCls + '">' + scoreText + '</div>'
                + '</div>'
                + '</div>';
        });
        $list.html(html);
    }

    $(document).on('click', '#seo-view-list', function() {
        _seoView = 'list';
        $('#seo-view-list').addClass('active');
        $('#seo-view-grid').removeClass('active');
        seoRenderPagesList();
    });
    $(document).on('click', '#seo-view-grid', function() {
        _seoView = 'grid';
        $('#seo-view-grid').addClass('active');
        $('#seo-view-list').removeClass('active');
        seoRenderPagesList();
    });

    $(document).on('click', '.seo-page-row, .seo-page-card', function(e) {
        
        if ($(e.target).is('.seo-page-row-name-input')) return;
        var id = parseInt($(this).data('pageId'), 10);
        _seoState.currentPageId = id;
        _seoState.analysis = null;
        $('.seo-page-row, .seo-page-card').removeClass('active');
        $(this).addClass('active');
        $('#seo-center-empty').hide();
        $('#seo-page-editor').show().scrollTop(0);
        seoOpenPageEditor(id);
        seoLoadPageImages(id); seoSpeedReset(id);
    });

    $(document).on('dblclick', '.seo-page-row-name', function(e) {
        e.stopPropagation();
        var $name = $(this);
        var $row  = $name.closest('.seo-page-row');
        var id    = parseInt($row.data('pageId'), 10);
        var cur   = $name.text();
        if ($name.find('.seo-page-row-name-input').length) return; 

        var $inp = $('<input class="seo-page-row-name-input">')
            .val(cur)
            .css({
                width: '100%', height: '20px', padding: '0 4px',
                background: '#2a2e33', border: '1px solid #555',
                borderRadius: '2px', color: '#e0e0e0',
                fontSize: '11px', boxSizing: 'border-box', outline: 'none'
            });

        $name.empty().append($inp);
        $inp.focus().select();

        function commitRename() {
            var newName = $.trim($inp.val());
            if (!newName || newName === cur) {
                $name.text(cur);
                return;
            }
            $name.text(newName);
            
            var page = (_seoState.pages || []).find(function(p) { return p.id === id; });
            if (page) page.title = newName;
            
            $.ajax({
                url: window.Impulse.api + 'pages/' + id,
                method: 'PUT',
                contentType: 'application/json',
                data: JSON.stringify({ name: newName }),
                beforeSend: function(xhr) { xhr.setRequestHeader('X-WP-Nonce', window.Impulse.nonce); }
            }).fail(function() {
                seoToast('Failed to rename page', 'error');
                $name.text(cur);
                if (page) page.title = cur;
            });
        }

        $inp.on('blur', commitRename);
        $inp.on('keydown', function(e) {
            if (e.key === 'Enter')  { e.preventDefault(); commitRename(); }
            if (e.key === 'Escape') { e.preventDefault(); $name.text(cur); }
        });
    });

    function seoOpenPageEditor(postId) {
        
        $('#seo-settings-right').hide();
        $('#seo-right-analysis').show();
        
        $('#seo-field-meta-title,#seo-field-meta-desc,#seo-field-focus-keyword').val('');
        $('#seo-field-canonical,#seo-field-og-title,#seo-field-og-desc').val('');
        $('#seo-field-og-image').val('');
        
        seoSetOgType('website');
        $('#seo-og-thumb').hide();
        $('#seo-og-clear-btn').hide();
        $('#seo-og-pick-btn').show();
        $('#seo-field-noindex,#seo-field-nofollow').prop('checked', false);
        $('#seo-save-status').text('');
        _seoState.currentSlug      = '';
        _seoState.currentPermalink = '';
        seoResetAnalysis();

        seoApi('/pages/' + postId).done(function(data) {
            var seo  = data.seo  || {};
            $('#seo-field-meta-title').val(seo.meta_title || '');
            $('#seo-field-meta-desc').val(seo.meta_description || '');
            $('#seo-field-focus-keyword').val(seo.focus_keyword || '');
            $('#seo-field-canonical').val(seo.canonical_url || '');
            $('#seo-field-og-title').val(seo.og_title || '');
            $('#seo-field-og-desc').val(seo.og_description || '');
            seoSetOgType(seo.og_type || 'website');
            $('#seo-field-noindex').prop('checked',  !!+seo.noindex);
            $('#seo-field-nofollow').prop('checked', !!+seo.nofollow);

            if (seo.og_image_url) {
                $('#seo-field-og-image').val(seo.og_image_url);
                $('#seo-og-thumb-img').attr('src', seo.og_image_url);
                $('#seo-og-thumb').show();
                $('#seo-og-clear-btn').show();
            }

            _seoState.currentSlug      = data.slug      || '';
            _seoState.currentPermalink = data.permalink || '';

            seoUpdateSERP({ title: seo.meta_title || data.title || '', desc: seo.meta_description || '', slug: data.slug || '', perm: data.permalink || '' });
            seoUpdateCharCount($('#seo-field-meta-title'), 'title');
            seoUpdateCharCount($('#seo-field-meta-desc'), 'desc');
            seoUpdateKeywordDensity(seo.focus_keyword || '');

            $('#seo-right-empty').hide();
            $('#seo-right-analyze-prompt').css('display','flex');
            seoRunAnalyze(postId);
        });
    }

    function seoResetAnalysis() {
        $('#seo-right-score-area').hide();
        $('#seo-right-analyze-prompt').hide();
        $('#seo-checks-list').empty();
        $('#seo-right-empty').show().text('Loading…');
        $('#seo-ring-arc').attr('stroke-dashoffset', 289.0).attr('stroke', '#e0e0e0');
        $('#seo-right-score-num').text('—');
    }

    
    function seoOpenPicker(callback) {
        if (typeof window.openImglibPicker !== 'function') {
            seoToast('Image library not available', 'error'); return;
        }
        window.openImglibPicker({ label: 'Select OG Image', simple: true }, function(img) {
            callback(img);
        });
    }

    $(document).on('click keydown', '#seo-og-pick-btn', function(e) {
        if (e.type === 'keydown' && e.key !== 'Enter' && e.key !== ' ') return;
        seoOpenPicker(function(img) {
            $('#seo-field-og-image').val(img.url);
            $('#seo-og-thumb-img').attr('src', img.url);
            $('#seo-og-thumb').show();
            $('#seo-og-clear-btn').show();
            seoScheduleSave();
        });
    });

    $(document).on('click', '#seo-og-clear-btn', function() {
        $('#seo-field-og-image').val('');
        $('#seo-og-thumb').hide();
        $('#seo-og-clear-btn').hide();
        seoScheduleSave();
    });

    function seoSetOgType(val) {
        var allowed = ['website', 'article', 'product'];
        if (allowed.indexOf(val) === -1) val = 'website';
        $('#seo-field-og-type').val(val);
        $('#seo-og-type-group .seo-og-type-btn').removeClass('active');
        $('#seo-og-type-group .seo-og-type-btn[data-value="' + val + '"]').addClass('active');
    }

    $(document).on('click', '.seo-og-type-btn', function() {
        seoSetOgType($(this).data('value'));
        seoScheduleSave();
    });

    function seoUpdateSERP(opts) {
        var title    = opts.title || '';
        var settings = _seoState.settings || {};
        var siteName = settings.site_name || '';
        var sep      = ' | ';
        var display  = title || 'Page Title';
        if (!opts.rawTitle && siteName && display.indexOf(siteName) === -1) {
            display = display + sep + siteName;
        }
        
        var perm = opts.perm || _seoState.currentPermalink || '';
        var slug = opts.slug || _seoState.currentSlug || '';
        var urlDisplay = '';
        try {
            var u = new URL(perm || window.location.origin);
            urlDisplay = u.hostname + (slug ? '/' + slug : '');
        } catch(e) { urlDisplay = slug || 'example.com/page'; }
        $('#seo-serp-title').text(display).toggleClass('truncated', display.length > 60);
        $('#seo-serp-desc').text(opts.desc || 'No meta description set.');
        $('#seo-serp-url').text(urlDisplay);
    }

    function seoUpdateCharCount($el, type) {
        var len = $el.val().length;
        var max = type === 'title' ? 60 : 160;
        var min = type === 'title' ? 30 : 70;
        var pct = Math.min(100, (len / (max * 1.3)) * 100);
        var cls = len > max ? 'over' : len >= min ? 'good' : 'warn';
        $('#seo-' + type + '-count').text(len + '/' + max);
        
        if (type === 'desc') {
            $('#seo-desc-bar').css('width', pct + '%').attr('class', 'seo-char-bar-fill ' + cls);
        }
    }

    $(document).on('input', '#seo-field-meta-title', function() {
        seoUpdateCharCount($(this), 'title');
        seoUpdateSERP({ title: $(this).val(), desc: $('#seo-field-meta-desc').val(), rawTitle: true });
        seoScheduleSave();
    });
    $(document).on('input', '#seo-field-meta-desc', function() {
        seoUpdateCharCount($(this), 'desc');
        seoUpdateSERP({ title: $('#seo-field-meta-title').val(), desc: $(this).val(), rawTitle: true });
        seoScheduleSave();
    });
    $(document).on('input change', '.seo-field', function() { seoScheduleSave(); });

    function seoUpdateKeywordDensity(keyword) {
        
    }

    function seoScheduleSave() {
        _seoState.dirty = true;
        clearTimeout(_seoState.saveTimer);
        _seoState.saveTimer = setTimeout(seoAutoSave, 1500);
    }

    function seoAutoSave() {
        if (!_seoState.currentPageId || !_seoState.dirty) return;
        var data = seoCollectFields();
        $('#seo-save-status').text('Saving…').css('color','#555');
        seoApi('/pages/' + _seoState.currentPageId, 'POST', data).done(function(res) {
            _seoState.dirty = false;
            $('#seo-save-status').text('Saved').css('color','#777');
            setTimeout(function() { $('#seo-save-status').text(''); }, 2000);
            
            var page = _seoState.pages.find(function(p) { return p.id === _seoState.currentPageId; });
            if (page && res.score != null) {
                page.score = res.score;
                var $row = $('.seo-page-row[data-page-id="' + _seoState.currentPageId + '"] .seo-page-row-score');
                var scoreText = res.score > 0 ? (res.score + '/100') : '—';
                $row.text(scoreText).attr('class', 'seo-page-row-score ' + (res.score > 0 ? seoScoreCls(res.score) : ''));
            }
        }).fail(function() {
            $('#seo-save-status').text('Save failed').css('color','#555');
        });
    }

    function seoCollectFields() {
        return {
            meta_title:       $('#seo-field-meta-title').val(),
            meta_description: $('#seo-field-meta-desc').val(),
            focus_keyword:    $('#seo-field-focus-keyword').val(),
            canonical_url:    $('#seo-field-canonical').val(),
            og_title:         $('#seo-field-og-title').val(),
            og_description:   $('#seo-field-og-desc').val(),
            og_type:          $('#seo-field-og-type').val(),
            og_image_url:     $('#seo-field-og-image').val(),
            noindex:          $('#seo-field-noindex').is(':checked')  ? 1 : 0,
            nofollow:         $('#seo-field-nofollow').is(':checked') ? 1 : 0};
    }

    function seoRunAnalyze(postId) {
        var $btns = $('#seo-analyze-btn, #seo-analyze-btn-prompt');
        $btns.text('Analyzing…').prop('disabled', true);
        $('#seo-checks-list').css('opacity', '0.4');
        seoApi('/pages/' + postId + '/analyze').done(function(data) {
            _seoState.analysis = data;
            seoRenderChecks(data);
            $('#seo-checks-list').css('opacity', '1');
        }).fail(function(xhr) {
            var msg = 'Analysis failed';
            try { var r = JSON.parse(xhr.responseText); msg = r.message || r.error || msg; } catch(e) {}
            seoToast(msg + ' (HTTP ' + xhr.status + ')', 'error');
            $('#seo-right-empty').show().text(msg);
            $('#seo-right-score-area').hide();
            $('#seo-right-analyze-prompt').hide();
        }).always(function() {
            $btns.text('Analyze').prop('disabled', false);
        });
    }

    $(document).on('click', '#seo-analyze-btn, #seo-analyze-btn-prompt', function() {
        if (!_seoState.currentPageId) { seoToast('No page selected', 'error'); return; }
        seoRunAnalyze(_seoState.currentPageId);
    });

    function seoRenderChecks(data) {
        var score  = parseInt(data.score, 10) || 0;
        var checks = data.checks || [];

        var circ   = 289.0; 
        var offset = circ - (score / 100) * circ;
        var clr    = seoScoreColor(score);
        $('#seo-ring-arc').attr('stroke-dashoffset', offset).attr('stroke', clr);
        $('#seo-right-score-num').text(score).css('color', clr);

        $('#seo-right-empty').hide();
        $('#seo-right-analyze-prompt').hide();
        $('#seo-right-score-area').css('display', 'flex');

        
        var typeMap = {
            good:    { cls: 'seo-ok',   icon: 'circle-check' },
            warning: { cls: 'seo-warn', icon: 'circle-alert' },
            error:   { cls: 'seo-err',  icon: 'circle-alert' },
            notice:  { cls: 'seo-info', icon: 'circle-alert' }};
        var html = '';
        checks.forEach(function(c) {
            var t   = typeMap[c.type] || typeMap.notice;
            var svg = (typeof lucideSvg === 'function') ? lucideSvg(t.icon, 17) : '';
            html += '<div class="seo-check-item ' + t.cls + '">'
                + '<div class="seo-check-icon">' + svg + '</div>'
                + '<div style="flex:1;line-height:1.4">' + seoEscape(c.msg) + '</div>'
                + '</div>';
        });
        $('#seo-checks-list').html(html || '<div style="font-size:11px;color:#555;padding:8px 0">No checks available.</div>');
    }

    $(document).on('click', '.seo-analyze-btn', function() {
        if (!_seoState.currentPageId) return;
        var $btn = $(this);
        $btn.text('Analyzing…').prop('disabled', true);
        var keyword = $('#seo-field-focus-keyword').val();
        
        var dTitle = seoApi('/ai-generate', 'POST', {
            post_id: _seoState.currentPageId,
            field:   'meta_title',
            keyword: keyword});
        var dDesc = seoApi('/ai-generate', 'POST', {
            post_id: _seoState.currentPageId,
            field:   'meta_description',
            keyword: keyword});
        $.when(dTitle, dDesc).done(function(rTitle, rDesc) {
            var title = (rTitle[0] || {}).text;
            var desc  = (rDesc[0]  || {}).text;
            if (title) { $('#seo-field-meta-title').val(title).trigger('input'); }
            if (desc)  { $('#seo-field-meta-desc').val(desc).trigger('input'); }
            if (title || desc) { seoScheduleSave(); }
            if (!title && !desc) { seoToast('No content returned', 'error'); }
        }).fail(function(xhr) {
            var msg = 'Generation failed';
            try { var r = JSON.parse(xhr.responseText); msg = r.message || r.error || msg; } catch(e) {}
            seoToast(msg + ' (HTTP ' + xhr.status + ')', 'error');
        }).always(function() {
            $btn.text('Analyze').prop('disabled', false);
        });
    });

    var _redirEditing = null; 

    function seoLoadRedirects() {
        seoApi('/redirects').done(function(data) {
            _seoState.redirects = data;
            seoRenderRedirectList();
        });
    }

    function seoRenderRedirectList() {
        var list = _seoState.redirects;
        var $el  = $('#seo-settings-redir-list');
        if (!$el.length) return;
        if (!list.length) {
            $el.html('');
            return;
        }
        var html = '';
        list.forEach(function(r) {
            var dim = r.is_active == 1 ? '' : 'opacity:.45;';
            html += '<div class="seo-settings-redir-row" data-id="' + r.id + '" style="' + dim + 'display:flex;align-items:center;gap:6px;padding:5px 0;border-bottom:1px solid #22252a;cursor:pointer">'
                + '<div style="flex:1;min-width:0">'
                + '<div style="font-size:11px;color:#e0e0e0;white-space:nowrap;overflow:hidden;text-overflow:ellipsis">' + seoEscape(r.source_url) + '</div>'
                + '<div style="font-size:10px;color:#555;white-space:nowrap;overflow:hidden;text-overflow:ellipsis">→ ' + seoEscape(r.target_url) + '</div>'
                + '</div>'
                + '<span style="font-size:10px;color:#555;flex-shrink:0">' + r.redirect_type + '</span>'
                + '<span style="font-size:10px;color:#555;flex-shrink:0">' + (r.hit_count||0) + ' hits</span>'
                + '</div>';
        });
        $el.html(html);
    }

    function seoRenderRedirectForm(r) {
        _redirEditing = r ? r.id : null;
        var src  = r ? seoEscape(r.source_url) : '';
        var tgt  = r ? seoEscape(r.target_url) : '';
        var type = r ? r.redirect_type         : '301';
        var html = '<div id="seo-settings-redir-form" style="margin-top:8px">'
            + '<div class="seo-two-col" style="margin-bottom:8px">'
            + '<div><label class="seo-field-label">From URL</label><input type="text" id="seo-rf-source" class="seo-dark-input" value="' + src + '" placeholder="/old-slug"></div>'
            + '<div><label class="seo-field-label">To URL</label><input type="text" id="seo-rf-target" class="seo-dark-input" value="' + tgt + '" placeholder="/new-slug or https://…"></div>'
            + '</div>'
            + '<div style="display:flex;gap:6px;align-items:center">'
            + '<select id="seo-rf-type" class="seo-dark-input" style="height:26px;padding:0 6px;flex:1;appearance:none;-webkit-appearance:none;background:#2a2e33;border:1px solid #3a3f44;border-radius:3px;color:#e0e0e0;font-size:11px;outline:none" title="301 Permanent: use when a page has moved forever. 302 Temporary: use for short-term redirects.">'
            + '<option value="301"' + (type==301?' selected':'') + '>301 Permanent</option>'
            + '<option value="302"' + (type==302?' selected':'') + '>302 Temporary</option>'
            + '</select>'
            + '<button type="button" class="impulse-btn-sm" style="height:26px;flex:1" id="seo-rf-save">Save</button>'
            + (r ? '<button type="button" class="impulse-btn-sm" style="height:26px" id="seo-rf-delete">Delete</button>' : '')
            + '<button type="button" class="impulse-btn-sm" style="height:26px" id="seo-rf-cancel">Cancel</button>'
            + '</div>'
            + '</div>';
        $('#seo-settings-redir-form').remove();
        $('#seo-settings-redir-list').after(html);
    }

    $(document).on('click', '.seo-settings-redir-row', function() {
        var id = parseInt($(this).data('id'), 10);
        var r  = _seoState.redirects.find(function(x) { return x.id == id; });
        if (r) seoRenderRedirectForm(r);
    });

    $(document).on('click', '#seo-rf-cancel', function() {
        $('#seo-settings-redir-form').remove();
        _redirEditing = null;
    });

    $(document).on('click', '#seo-rf-delete', function() {
        if (!_redirEditing || !window.impulseConfirm('Delete this redirect?')) return;
        var id = _redirEditing;
        seoApi('/redirects/' + id, 'DELETE').done(function() {
            _seoState.redirects = _seoState.redirects.filter(function(r) { return r.id != id; });
            _redirEditing = null;
            $('#seo-settings-redir-form').remove();
            seoRenderRedirectList();
            seoToast('Redirect deleted');
        });
    });

    $(document).on('click', '#seo-rf-save', function() {
        var data = {
            source_url:    $('#seo-rf-source').val().trim(),
            target_url:    $('#seo-rf-target').val().trim(),
            redirect_type: parseInt($('#seo-rf-type').val(), 10),
            is_active:     1};
        if (!data.source_url || !data.target_url) { seoToast('Source and target URLs required', 'error'); return; }
        var id = _redirEditing;
        seoApi(id ? '/redirects/'+id : '/redirects', id ? 'PUT' : 'POST', data).done(function(res) {
            seoLoadRedirects();
            $('#seo-settings-redir-form').remove();
            _redirEditing = null;
            seoToast('Redirect saved');
        }).fail(function() { seoToast('Failed to save', 'error'); });
    });

    function seoLoadSettings() {
        $.when(
            seoApi('/settings'),
            seoApi('/redirects')
        ).done(function(settingsRes, redirRes) {
            _seoState.settings  = settingsRes[0];
            _seoState.redirects = redirRes[0];
            
            if ($('#seo-s-robots').length) {
                var _r = document.getElementById('seo-s-robots');
                _r.value = _seoState.settings.robots_custom || '';
                expandRobots();
                _r.style.height = '26px';
                _r.style.height = Math.max(26, _r.scrollHeight) + 'px';
            }
            
            seoRenderSettingsLeft();
            seoRenderSettingsCenter();
        });
    }

    function seoInput(id, val, placeholder) {
        return '<input type="text" id="' + id + '" class="seo-dark-input" value="' + seoEscape(val||'') + '" placeholder="' + seoEscape(placeholder||'') + '">';
    }

    function seoRenderSchemaCompleteness() {
        var s  = _seoState.settings  || {};
        var si = s.store_info        || {};
        var fields = [
            { key: 'name',         label: 'Store Name',     ok: !!(si.name),            tip: 'Set in Settings' },
            { key: 'description',  label: 'Description',    ok: !!(s.store_description), tip: 'Set in Settings' },
            { key: 'phone',        label: 'Phone',          ok: !!(si.phone),            tip: 'Set in Settings' },
            { key: 'email',        label: 'Email',          ok: !!(si.email),            tip: 'Set in Settings' },
            { key: 'address',      label: 'Street Address', ok: !!(si.address1),         tip: 'Fill in the Street Address field above' },
            { key: 'city',         label: 'City',           ok: !!(si.city),             tip: 'Fill in the City field above' },
            { key: 'postcode',     label: 'Postal Code',    ok: !!(si.postcode),         tip: 'Fill in the Postal Code field above' },
            { key: 'image',        label: 'OG Image',       ok: !!(s.og_image_url),      tip: 'Set the OG image in the Social Sharing section of this page' }];
        var filled = fields.filter(function(f){ return f.ok; }).length;
        var total  = fields.length;
        var pct    = Math.round(filled / total * 100);
        var barClr = pct === 100 ? '#e0e0e0' : pct >= 60 ? '#999' : '#555';
        var txtClr = pct === 100 ? '#e0e0e0' : pct >= 60 ? '#999' : '#777';

        var html = '<div id="seo-lb-completeness" style="margin-top:8px">'
            + '<div style="display:flex;align-items:center;gap:8px;margin-bottom:6px">'
            + '<div style="flex:1;height:4px;background:#2a2e33;border-radius:2px;overflow:hidden">'
            + '<div style="height:4px;width:' + pct + '%;background:' + barClr + ';border-radius:2px;transition:width .3s"></div>'
            + '</div>'
            + '<span style="font-size:11px;color:' + txtClr + ';flex-shrink:0">' + filled + '/' + total + '</span>'
            + '</div>'
            + '<div style="display:grid;grid-template-columns:1fr 1fr;gap:3px 8px">';

        fields.forEach(function(f) {
            var icon  = f.ok
                ? '<span style="color:#777;font-size:11px">&#10003;</span>'
                : '<span style="color:#555;font-size:11px">&#10005;</span>';
            var label = f.ok
                ? '<span style="font-size:11px;color:#555">' + f.label + '</span>'
                : '<span class="seo-lb-missing-field" data-lbkey="' + f.key + '" style="font-size:11px;color:#777;cursor:pointer;text-decoration:underline;text-underline-offset:2px" title="' + f.tip + '">' + f.label + '</span>';
            html += '<div style="display:flex;align-items:center;gap:5px">' + icon + label + '</div>';
        });

        html += '</div>';
        if (filled < total) {
            html += '<div style="font-size:11px;color:#555;margin-top:6px">Missing fields reduce schema coverage.</div>';
        }
        html += '</div>';
        return html;
    }

    var _socialPlatforms = {
        'facebook.com':    'Facebook',
        'fb.com':          'Facebook',
        'instagram.com':   'Instagram',
        'x.com':           'X',
        'twitter.com':     'X',
        'linkedin.com':    'LinkedIn',
        'youtube.com':     'YouTube',
        'youtu.be':        'YouTube',
        'tiktok.com':      'TikTok',
        'pinterest.com':   'Pinterest',
        'github.com':      'GitHub',
        'threads.net':     'Threads',
        'reddit.com':      'Reddit',
        'discord.gg':      'Discord',
        'discord.com':     'Discord',
        'twitch.tv':       'Twitch',
        'vimeo.com':       'Vimeo',
        'spotify.com':     'Spotify',
        'soundcloud.com':  'SoundCloud',
        't.me':            'Telegram',
        'telegram.org':    'Telegram',
        'wa.me':           'WhatsApp',
        'whatsapp.com':    'WhatsApp',
        'snapchat.com':    'Snapchat',
        'medium.com':      'Medium',
        'dribbble.com':    'Dribbble',
        'behance.net':     'Behance',
        'yelp.com':        'Yelp',
        'patreon.com':     'Patreon',
        'substack.com':    'Substack'
    };

    function seoDetectPlatform(url) {
        if (!url) return '';
        try {
            var hostname = new URL(url.indexOf('://') === -1 ? 'https://' + url : url).hostname.replace(/^www\./, '');
            
            if (_socialPlatforms[hostname]) return _socialPlatforms[hostname];
            for (var domain in _socialPlatforms) {
                if (hostname === domain || hostname.endsWith('.' + domain)) return _socialPlatforms[domain];
            }
        } catch(e) {}
        return '';
    }

    function seoSocialRow(url, idx) {
        var platform = seoDetectPlatform(url);
        var label = platform || 'Paste URL';
        return '<div class="impulse-settings-left-row seo-social-row" data-idx="' + idx + '" style="display:flex;align-items:center;gap:4px">'
            + '<span class="seo-social-label" style="font-size:10px;color:#888;min-width:60px;white-space:nowrap">' + label + '</span>'
            + '<input type="text" class="impulse-settings-input seo-social-url" value="' + seoEscape(url) + '" placeholder="https://..." style="flex:1">'
            + '<button type="button" class="seo-social-remove impulse-remove-social" title="Remove" style="width:26px;height:26px;flex-shrink:0;background:#2a2e33;border:1px solid #3a3f44;border-radius:3px;cursor:pointer;display:inline-flex;align-items:center;justify-content:center;padding:0;color:#999"><svg viewBox="0 0 24 24" width="10" height="10" fill="none" stroke="currentColor" stroke-width="2.5"><line x1="18" y1="6" x2="6" y2="18"/><line x1="6" y1="6" x2="18" y2="18"/></svg></button>'
            + '</div>';
    }

    function seoRenderSettingsLeft() {
        var s = _seoState.settings || {};

        var profiles = s.social_profiles || [];
        if (!profiles.length) {
            var legacy = [
                s.social_twitter || (s.twitter_handle ? 'https://x.com/' + s.twitter_handle.replace(/^@/, '') : ''),
                s.social_facebook || '',
                s.social_instagram || '',
                s.social_linkedin || '',
                s.social_youtube || ''
            ];
            legacy.forEach(function(u) { if (u) profiles.push(u); });
        }
        
        var html = '<div id="seo-social-list">';
        profiles.forEach(function(url, i) {
            html += seoSocialRow(url, i);
        });
        html += '</div>';

        

        

        var _seoAddBtnMt = profiles.length ? '6px' : '0';
        html += '<button type="button" class="impulse-btn-sm" id="seo-social-add" style="width:100%;margin-top:' + _seoAddBtnMt + '">+ Add Profile</button>';
        
        $('#store-seo-settings-left').html(html);

        var lbHtml = '<div style="margin-bottom:10px">'
            + '<label style="display:flex;align-items:center;justify-content:space-between;font-size:11px;color:#999;cursor:pointer;gap:8px">'
            + '<span>Enable structured data</span>'
            + '<input type="checkbox" id="seo-s-lb-enabled"' + (s.localbusiness_enabled ? ' checked' : '') + ' style="margin:0;flex-shrink:0"></label>'
            + '</div>'
            + '<div id="seo-s-lb-type-wrap" style="' + (s.localbusiness_enabled ? '' : 'display:none;') + '">'
            + '<label class="seo-field-label" style="margin-bottom:4px">Business Type</label>'
            + (function() {
                var types = [
                    { val: 'LocalBusiness',      label: 'Store'      },
                    { val: 'FoodEstablishment',   label: 'Restaurant' },
                    { val: 'ProfessionalService', label: 'Service'    },
                    { val: 'MedicalBusiness',     label: 'Medical'    },
                    { val: 'Hotel',               label: 'Hotel'      },
                    { val: '__other__',           label: 'Other'      }];
                var cur = s.localbusiness_type || 'LocalBusiness';
                var isOther = !types.slice(0,-1).find(function(t){ return t.val === cur; });

                var btns = '<div class="impulse-btn-group" style="display:grid;grid-template-columns:repeat(3,1fr);gap:3px;margin-bottom:6px">';
                types.forEach(function(t) {
                    var active = (t.val === '__other__' ? isOther : cur === t.val) ? ' active' : '';
                    btns += '<button type="button" class="impulse-btn-sm seo-lb-type-btn' + active + '" data-value="' + t.val + '" style="min-width:0;height:26px;box-sizing:border-box">' + t.label + '</button>';
                });
                btns += '</div>';
                btns += '<input type="text" id="seo-s-lb-type" class="seo-dark-input" value="' + seoEscape(cur) + '" placeholder="e.g. Restaurant, LegalService" style="display:' + (isOther ? 'block' : 'none') + ';margin-bottom:6px">';
                return btns;
            })()
            + (function() {
                var lbd = (s.localbusiness_data) || {};
                var si2 = (s.store_info) || {};
                return '<div style="margin-bottom:6px"><label class="seo-field-label" title="e.g. Mo-Fr 09:00-17:00, Sa 10:00-14:00.">Opening Hours</label>'
                    + '<input type="text" id="seo-s-lb-hours" class="seo-dark-input" value="' + seoEscape(lbd.opening_hours||'') + '" placeholder="Mo-Fr 09:00-17:00"></div>'
                    + '<div style="margin-bottom:6px"><label class="seo-field-label" title="e.g. $, $$, $$$, $$$$">Price Range</label>'
                    + '<input type="text" id="seo-s-lb-price" class="seo-dark-input" value="' + seoEscape(lbd.price_range||'') + '" placeholder="$$ or 10-50"></div>'

                    
                    
                    + '<div style="margin-bottom:6px"><label class="seo-field-label">Street Address</label>'
                    + '<input type="text" id="seo-s-lb-address" class="seo-dark-input" value="' + seoEscape(si2.address1||'') + '" placeholder="123 Main St"></div>'
                    + '<div style="display:grid;grid-template-columns:1fr 1fr;gap:6px;margin-bottom:6px">'
                    + '<div><label class="seo-field-label">City</label>'
                    + '<input type="text" id="seo-s-lb-city" class="seo-dark-input" value="' + seoEscape(si2.city||'') + '"></div>'
                    + '<div><label class="seo-field-label">Postal Code</label>'
                    + '<input type="text" id="seo-s-lb-postcode" class="seo-dark-input" value="' + seoEscape(si2.postcode||'') + '"></div>'
                    + '</div>';
            })()
            + seoRenderSchemaCompleteness()
            + '</div>';
        $('#store-lb-schema-content').html(lbHtml);
        $('#store-lb-schema-wrap').show();
        var curLbType = (s.localbusiness_type) || 'LocalBusiness';
        applyLbTypeVisibility(curLbType);
    }

    function seoRenderSettingsCenter() {
        var s = _seoState.settings || {};

        var nfMode   = s.not_found_mode    || 'none';
        var nfPageId = s.not_found_page_id || 0;

        var html = ''

            
            
            + '<div class="settings-card">'

            + '<div class="impulse-section-divider" style="margin-bottom:10px">Routing</div>'

            + '<div style="font-size:11px;color:#888;margin-bottom:4px">404 behavior</div>'
            + '<div class="impulse-btn-group" id="seo-nf-mode-group" style="display:flex;margin-bottom:8px">'
            + '<button type="button" class="impulse-btn-sm seo-nf-mode-btn' + (nfMode==='none'   ? ' active' : '') + '" data-value="none"   style="flex:1;height:26px;box-sizing:border-box" title="Return a real 404 status. Best for SEO.">None</button>'
            + '<button type="button" class="impulse-btn-sm seo-nf-mode-btn' + (nfMode==='home'   ? ' active' : '') + '" data-value="home"   style="flex:1;height:26px;box-sizing:border-box" title="Redirect all 404s to your homepage.">Home</button>'
            + '<button type="button" class="impulse-btn-sm seo-nf-mode-btn' + (nfMode==='custom' ? ' active' : '') + '" data-value="custom" style="flex:1;height:26px;box-sizing:border-box" title="Redirect all 404s to a page you choose.">Custom</button>'
            + '</div>'
            + '<input type="hidden" id="seo-nf-mode" value="' + nfMode + '">'
            + (function() {
                var pages = (_seoState.pages || []);
                var opts = '<option value="">\u2014 select page \u2014</option>';
                pages.forEach(function(p) { opts += '<option value="' + p.id + '"' + (p.id == nfPageId ? ' selected' : '') + '>' + seoEscape(p.title || p.slug || ('Page ' + p.id)) + '</option>'; });
                return '<div id="seo-nf-custom-wrap" style="display:' + (nfMode==='custom' ? 'flex' : 'none') + ';gap:4px;align-items:center;margin-bottom:8px">'
                    + '<input type="hidden" id="seo-nf-page-id" value="' + nfPageId + '">'
                    + '<select id="seo-nf-page-select" style="flex:1;min-width:0;height:26px;appearance:none;-webkit-appearance:none;background:#2a2e33;border:1px solid #3a3f44;border-radius:3px;color:#e0e0e0;font-size:11px;padding:0 6px;box-sizing:border-box;overflow:hidden;outline:none">' + opts + '</select>'
                    + '</div>';
            })()

            + '<div style="font-size:11px;color:#888;margin-bottom:4px">Redirects</div>'
            + '<div style="margin-bottom:8px"><button type="button" class="impulse-btn-sm" id="seo-settings-redir-add-right" style="height:26px" title="Create a 301 or 302 redirect from one URL to another.">+ Add Redirect</button></div>'
            + '<div id="seo-settings-redir-list"></div>'

            + '<div style="margin-top:14px"><label class="seo-field-label" title="Verifies your site with Google Search Console. Paste only the content= value from the HTML meta tag.">Google Search Console</label>' + seoInput('seo-s-gsc', s.gsc_verify, 'Paste content= value from meta tag') + '<div style="margin-bottom:14px"></div></div>'

            
            
            + '<div style="margin-top:14px"><label class="seo-field-label" title="Free key from console.cloud.google.com: enable the PageSpeed Insights API, then create an API key. Without one, Google rejects the request.">PageSpeed API key</label>' + seoInput('seo-s-psi', s.pagespeed_api_key, 'Paste your PageSpeed Insights API key') + '<div style="font-size:11px;color:#555;margin:4px 0 14px">Needed for the Page Speed panel. Free, 25,000 checks a day.</div></div>'

            + '</div><div class="settings-card">'
            + '<div class="impulse-section-divider" style="margin-bottom:10px" title="XML sitemap helps search engines discover and index all your pages and products.">Sitemap</div>'
            + '<div style="display:flex;align-items:center;margin-bottom:6px">'
            + '<label style="display:flex;align-items:center;gap:4px;font-size:11px;color:#999;cursor:pointer;flex-shrink:0"><input type="checkbox" id="seo-s-sitemap-pages"' + ((_seoState.settings||{}).sitemap_pages ? ' checked' : '') + ' style="margin:0"> Pages</label>'
            + '<label style="display:flex;align-items:center;gap:4px;font-size:11px;color:#999;cursor:pointer;flex-shrink:0;margin-left:auto">Products <input type="checkbox" id="seo-s-sitemap-products"' + ((_seoState.settings||{}).sitemap_products ? ' checked' : '') + ' style="margin:0 0 0 4px"></label>'
            + '</div>'
            + '<div style="display:flex;gap:4px;margin-bottom:4px">'
            + '<button type="button" class="impulse-btn-sm" style="flex:1;height:26px" id="seo-sitemap-generate" title="Generate XML sitemap and submit to search engines.">Generate Sitemap</button>'
            + (s.sitemap_url ? '<a href="' + seoEscape(s.sitemap_url) + '" target="_blank" class="impulse-btn-sm" id="seo-sitemap-view" style="flex-shrink:0;height:26px;display:flex;align-items:center;padding:0 10px;text-decoration:none" title="Open sitemap in new tab">View</a>' : '<a href="#" class="impulse-btn-sm" id="seo-sitemap-view" style="flex-shrink:0;height:26px;display:none;align-items:center;padding:0 10px;text-decoration:none" target="_blank">View</a>')
            + '</div>'
            + '<div id="seo-sitemap-url" style="font-size:11px;color:#555;margin-bottom:2px;word-break:break-all"></div>'
            + '<div id="seo-sitemap-ts" style="font-size:10px;color:#444;margin-bottom:6px"></div>'

            + '</div>'
            + (s.directory_manage_url
                ? '<div class="settings-card"><div class="impulse-section-divider" style="margin-top:10px;margin-bottom:6px" title="Your page in the Instinctor business directory.">Directory</div>'
                + '<div style="font-size:11px;color:#888;margin-bottom:6px">This site is listed in the Instinctor directory.</div>'
                + '<a href="' + seoEscape(s.directory_manage_url) + '" target="_blank" rel="noopener" class="impulse-btn-sm" style="display:flex;align-items:center;justify-content:center;height:26px;text-decoration:none;margin-bottom:6px" title="Edit your listing and read messages from your page.">Manage your listing</a></div>'
                : '')

            + '<div class="settings-card">'
            + '<div class="impulse-section-divider" style="margin-top:10px;margin-bottom:6px" title="Custom rules appended after Instinctor\'s automatic robots.txt defaults.">robots.txt</div>'
            + '<textarea id="seo-s-robots" rows="1" placeholder="# Additional rules\u2026"'
            + ' class="impulse-autoexpand" style="width:100%;height:26px;min-height:26px;padding:4px 8px;font-size:11px;background:#2a2e33!important;border:1px solid #3a3f44!important;border-radius:3px;color:#e0e0e0!important;box-sizing:border-box;resize:none;font-family:monospace;line-height:1.5;box-shadow:none!important;overflow:hidden;margin-bottom:6px">'
            + seoEscape((_seoState.settings||{}).robots_custom||'') + '</textarea>'
            + '<div style="display:flex;gap:4px">'
            + '<button type="button" class="impulse-btn-sm" style="flex:1;height:26px" id="seo-robots-preview">Preview</button>'
            + '<button type="button" class="impulse-btn-sm" style="flex:1;height:26px" id="seo-robots-suggest">Auto-Optimize</button>'
            + '</div>'
            + '<div id="seo-robots-ts" style="font-size:10px;color:#444;margin-top:4px"></div>'
            + '</div>';

        $('#store-seo-settings-center-inner').html(html);
        seoRenderRedirectList();
        if (typeof window.upgradeCheckboxes === 'function') {
            window.upgradeCheckboxes(document.getElementById('store-seo-settings-center-inner'));
        }
        
        var $robots = $('#seo-s-robots');
        if ($robots.length && $robots.val()) {
            $robots[0].style.height = '26px';
            $robots[0].style.height = Math.max(26, $robots[0].scrollHeight) + 'px';
        }
    }

    var _settingsSaveTimer = null;

    function seoCollectSettings() {
        
        var profiles = [];
        var legacyMap = { Facebook: '', Instagram: '', X: '', LinkedIn: '', YouTube: '' };
        $('#seo-social-list .seo-social-url').each(function() {
            var url = $(this).val().trim();
            if (url) {
                profiles.push(url);
                var p = seoDetectPlatform(url);
                if (p === 'X' && !legacyMap.X) legacyMap.X = url;
                else if (p === 'Facebook' && !legacyMap.Facebook) legacyMap.Facebook = url;
                else if (p === 'Instagram' && !legacyMap.Instagram) legacyMap.Instagram = url;
                else if (p === 'LinkedIn' && !legacyMap.LinkedIn) legacyMap.LinkedIn = url;
                else if (p === 'YouTube' && !legacyMap.YouTube) legacyMap.YouTube = url;
            }
        });
        
        var twitterHandle = '';
        if (legacyMap.X) {
            try { twitterHandle = new URL(legacyMap.X).pathname.replace(/^\//, '').replace(/\/.*/, ''); } catch(e) {}
        }
        return {
            site_name:              (_seoState.settings||{}).site_name || '',
            page_title_template:    (_seoState.settings||{}).page_title_template || '{title}{sep}{site_name}',
            product_title_template: (_seoState.settings||{}).product_title_template || '{title}{sep}{site_name}',
            twitter_handle:         twitterHandle,
            twitter_card:           'summary_large_image',
            social_twitter:         legacyMap.X,
            social_facebook:        legacyMap.Facebook,
            social_instagram:       legacyMap.Instagram,
            social_linkedin:        legacyMap.LinkedIn,
            social_youtube:         legacyMap.YouTube,
            social_profiles:        JSON.stringify(profiles),
            gsc_verify:             $('#seo-s-gsc').val(),
            pagespeed_api_key:      $('#seo-s-psi').val(),

            robots_custom:          $('#seo-s-robots').val(),
            sitemap_pages:          $('#seo-s-sitemap-pages').is(':checked')    ? 1 : 0,
            sitemap_products:       $('#seo-s-sitemap-products').is(':checked') ? 1 : 0,
            localbusiness_enabled:  $('#seo-s-lb-enabled').is(':checked')       ? 1 : 0,
            localbusiness_type:     $('#seo-s-lb-type').val() || (_seoState.settings||{}).localbusiness_type || 'LocalBusiness',
            localbusiness_opening_hours: $('#seo-s-lb-hours').val() || '',
            localbusiness_price_range:   $('#seo-s-lb-price').val() || '',
            store_address_1:        $('#seo-s-lb-address').val() || '',
            store_city:             $('#seo-s-lb-city').val() || '',
            store_postcode:         $('#seo-s-lb-postcode').val() || '',
            not_found_mode:         $('#seo-nf-mode').val(),
            not_found_page_id:      parseInt($('#seo-nf-page-id').val(), 10) || 0};
    }

    function seoSettingsAutoSave() {
        clearTimeout(_settingsSaveTimer);
        _settingsSaveTimer = setTimeout(function() {
            var data = seoCollectSettings();
            seoApi('/settings', 'POST', data).done(function() {
                _seoState.settings = $.extend({}, _seoState.settings, data);
                seoToast('Settings saved');
            }).fail(function() { seoToast('Failed to save settings', 'error'); });
        }, 800);
    }

    
    var _seoPageFilter = null;
    $(document).on('click', '.seo-stat-card[data-filter]', function(e) {
        if ($(e.target).hasClass('seo-fill-btn') || $(e.target).closest('.seo-fill-btn').length) return;
        var filter = $(this).data('filter');
        if (filter === 'cannibal') {
            seoShowCannibalizationModal();
            return;
        }
        if (_seoPageFilter === filter) {
            _seoPageFilter = null;
            $('.seo-stat-card').removeClass('active');
        } else {
            _seoPageFilter = filter;
            $('.seo-stat-card').removeClass('active');
            $(this).addClass('active');
        }
        seoRenderPagesList();
        
        switchWorkspace('seo');
    });

    var _origRenderPagesList = seoRenderPagesList;
    seoRenderPagesList = function() {
        var pages = _seoState.pages;
        if (_seoPageFilter === 'no_title') {
            pages = pages.filter(function(p) { return !p.meta_title; });
        } else if (_seoPageFilter === 'no_desc') {
            pages = pages.filter(function(p) { return !p.meta_description; });
        } else if (_seoPageFilter === 'noindex') {
            pages = pages.filter(function(p) { return p.noindex; });
        }
        if (!pages.length) {
            var msg = _seoPageFilter ? 'No pages match this filter.' : 'No pages found.';
            if (_seoPageFilter) msg += ' <span style="color:#777;cursor:pointer;text-decoration:underline" id="seo-clear-filter">Clear filter</span>';
            $('#seo-pages-list').html('<div style="padding:20px;text-align:center;color:#555;font-size:11px">' + msg + '</div>');
            return;
        }
        if (_seoView === 'grid') { seoRenderPagesGrid(pages); } else { seoRenderPagesListView(pages); }
    };
    $(document).on('click', '#seo-clear-filter', function() {
        _seoPageFilter = null; $('.seo-stat-card').removeClass('active'); seoRenderPagesList();
    });

    $(document).on('click', '.seo-batch-ai-btn', function(e) {
        e.stopPropagation();
        var type   = $(this).data('type'); 
        var fields = type === 'title' ? ['meta_title', 'meta_description'] : ['meta_description'];
        var pages  = _seoState.pages.filter(function(p) {
            return type === 'title' ? !p.meta_title : !p.meta_description;
        });
        if (!pages.length) { seoToast('No pages need filling', 'info'); return; }
        seoBatchGenerate(pages, fields, type === 'title' ? 'titles + descriptions' : 'descriptions');
    });

    $(document).on('click', '.seo-fill-btn', function(e) {
        e.stopPropagation();
        var fillType = $(this).data('fill'); 
        var fields   = fillType === 'no_title' ? ['meta_title', 'meta_description'] : ['meta_description'];
        var label    = fillType === 'no_title' ? 'titles + descriptions' : 'descriptions';
        var pages    = _seoState.pages.filter(function(p) {
            return fillType === 'no_title' ? !p.meta_title : !p.meta_description;
        });
        if (!pages.length) { seoToast('No pages need filling', 'info'); return; }

        seoBatchGenerate(pages, fields, label);
    });

    function seoBatchGenerate(pages, fields, label) {
        $('#seo-batch-modal-title').text('Generating ' + label + '…');
        $('#seo-batch-progress-bar').css('width', '0%');
        $('#seo-batch-progress-text').text('0 / ' + pages.length + ' pages');
        $('#seo-batch-log').empty();
        $('#seo-batch-close-btn').prop('disabled', true);
        $('#seo-batch-modal').show();

        var idx = 0, done = 0, _batchAborted = false;
        $('#seo-batch-close-btn').off('click.batch').on('click.batch', function() {
            _batchAborted = true; $('#seo-batch-modal').hide();
        });

        function next() {
            if (_batchAborted || idx >= pages.length) {
                $('#seo-batch-progress-text').text('Done — ' + done + ' pages updated');
                $('#seo-batch-progress-bar').css('width', '100%');
                $('#seo-batch-close-btn').prop('disabled', false);
                if (!_batchAborted) { seoToast('Generated meta for ' + done + ' pages'); seoLoadPages(); seoLoadOverview(); }
                return;
            }
            var p = pages[idx++];
            $('#seo-batch-progress-text').text(idx + ' / ' + pages.length + ' — ' + seoEscape(p.title));
            $('#seo-batch-progress-bar').css('width', Math.round((idx / pages.length) * 100) + '%');
            seoApi('/ai-batch-meta', 'POST', { post_id: p.id, fields: fields })
                .done(function(r) {
                    if (r.generated) done++;
                    $('#seo-batch-log').append('<div style="color:#777">✓ ' + seoEscape(p.title) + '</div>').scrollTop(9999);
                })
                .fail(function() {
                    $('#seo-batch-log').append('<div style="color:#555">✗ ' + seoEscape(p.title) + ' (failed)</div>').scrollTop(9999);
                })
                .always(function() { setTimeout(next, 200); });
        }
        next();
    }

    function seoShowCannibalizationModal() {
        var kws = _seoOverviewData.cannibal_keywords || [];
        if (!kws.length) { seoToast('No keyword conflicts found'); return; }
        var pages = _seoState.pages;
        var html = '';
        kws.forEach(function(kw) {
            var matches = pages.filter(function(p) { return (p.focus_keyword||'').toLowerCase() === kw.toLowerCase(); });
            html += '<div style="margin-bottom:12px">';
            html += '<div style="font-size:11px;font-weight:600;color:#e0e0e0;margin-bottom:4px">&ldquo;' + seoEscape(kw) + '&rdquo;</div>';
            matches.forEach(function(p) {
                html += '<div style="font-size:11px;color:#888;padding:3px 0;border-bottom:1px solid #2a2e33;cursor:pointer" class="seo-cannibal-page" data-page-id="' + p.id + '">'
                    + '→ ' + seoEscape(p.title) + '</div>';
            });
            html += '</div>';
        });
        $('#seo-cannibal-list').html(html);
        $('#seo-cannibal-modal').show();
    }
    $(document).on('click', '.seo-cannibal-page', function() {
        $('#seo-cannibal-modal').hide();
        var id = parseInt($(this).data('pageId'), 10);
        var $row = $('.seo-page-row[data-page-id="' + id + '"], .seo-page-card[data-page-id="' + id + '"]');
        if ($row.length) { $row.trigger('click'); }
        else { _seoState.currentPageId = id; seoOpenPageEditor(id); seoLoadPageImages(id); seoSpeedReset(id); seoShowTab('pages'); }
    });

    $(document).on('click', '#seo-lb-preview-btn, #seo-s-lb-preview', function() {
        seoApi('/schema-preview').done(function(data) {
            $('#seo-schema-content').text(JSON.stringify(data.schema || data, null, 2));
            $('#seo-schema-modal').show();
        }).fail(function() {
            var s = _seoState.settings || {};
            var schema = {
                '@context': 'https://schema.org',
                '@type':    ($('#seo-s-lb-type').val() || s.localbusiness_type || 'LocalBusiness'),
                'name':     (s.site_name || ''),
                'url':      window.location.origin,
                'note':     'Preview only — address/phone/email load from Settings at runtime'
            };
            $('#seo-schema-content').text(JSON.stringify(schema, null, 2));
            $('#seo-schema-modal').show();
        });
    });

    
    $(document).on('click', '.impulse-goto-seo-site', function() {
        switchWorkspace('settings');
    });

    $(document).on('click', '.seo-lb-missing-field, .seo-goto-store-settings', function() {

        var key   = $(this).data('lbkey') || '';
        var local = { address: '#seo-s-lb-address', city: '#seo-s-lb-city', postcode: '#seo-s-lb-postcode' };
        if (local[key]) {
            var $in = $(local[key]);
            if ($in.length) { $in.trigger('focus'); return; }
        }
        if (key === 'image') return; 
        
        $('.impulse-main-tab[data-tab="store"]').trigger('click');
        setTimeout(function() {
            $('.impulse-panel-tab[data-panel-tab="settings"]').trigger('click');
        }, 150);
    });

    
    $(document).on('input', '#seo-s-lb-address, #seo-s-lb-city, #seo-s-lb-postcode', function() {
        var s = _seoState.settings || {};
        s.store_info = s.store_info || {};
        s.store_info.address1 = $('#seo-s-lb-address').val() || '';
        s.store_info.city     = $('#seo-s-lb-city').val() || '';
        s.store_info.postcode = $('#seo-s-lb-postcode').val() || '';
        $('#seo-lb-completeness').replaceWith(seoRenderSchemaCompleteness());
        seoSettingsAutoSave();
    });

    $(document).on('click', '#seo-robots-suggest', function() {
        var $btn = $(this);
        $btn.text('Thinking…').prop('disabled', true);
        seoApi('/robots-suggest', 'POST', {}).done(function(r) {
            if (r.robots_rules) {
                var cur = $('#seo-s-robots').val().trim();
                $('#seo-s-robots').val(cur ? cur + '\n\n' + r.robots_rules : r.robots_rules);
                
                var el = document.getElementById('seo-s-robots');
                if (el) { el.style.height = '26px'; el.style.height = Math.max(26, el.scrollHeight) + 'px'; }
                seoSettingsAutoSave();
                var ts = new Date().toLocaleTimeString([], {hour:'2-digit',minute:'2-digit'});
                $('#seo-robots-ts').text('Last optimized: ' + ts);
                seoToast('Rules added — review before saving');
            }
        }).fail(function() {
            seoToast('Could not generate suggestions', 'error');
        }).always(function() {
            $btn.text('Auto-Optimize').prop('disabled', false);
        });
    });

    $(document).on('change', '#seo-s-sitemap-pages, #seo-s-sitemap-products', function() {
        seoSettingsAutoSave();
    });

    var _lbPhysicalTypes = ['FoodEstablishment', 'Hotel', 'MedicalBusiness'];
    function applyLbTypeVisibility(type) {
        var isPhysical = _lbPhysicalTypes.indexOf(type) !== -1;
        $('#seo-s-lb-hours').closest('div[style]').toggle(isPhysical);
        $('#seo-s-lb-price').closest('div[style]').toggle(isPhysical);
    }

    $(document).on('click', '.seo-lb-type-btn', function() {
        var val = $(this).data('value');
        $('.seo-lb-type-btn').removeClass('active');
        $(this).addClass('active');
        if (val === '__other__') {
            $('#seo-s-lb-type').show().focus();
            applyLbTypeVisibility('');
        } else {
            $('#seo-s-lb-type').hide().val(val);
            applyLbTypeVisibility(val);
            seoSettingsAutoSave();
        }
    });

    $(document).on('click', '.seo-nf-mode-btn', function() {
        var val = $(this).data('value');
        $('.seo-nf-mode-btn').removeClass('active');
        $(this).addClass('active');
        $('#seo-nf-mode').val(val);
        $('#seo-nf-custom-wrap').css('display', val === 'custom' ? 'flex' : 'none');
        seoSettingsAutoSave();
    });

    $(document).on('click', '#seo-settings-redir-add-right', function() {
        if ($('#seo-settings-redir-form').length) { $('#seo-settings-redir-form').remove(); return; }
        var $list = $('#seo-settings-redir-list');
        seoRenderRedirectForm(null);
        $('#seo-settings-redir-form').detach().insertAfter($list);
    });

    $(document).on('input change', '#store-seo-settings-center-inner input, #store-seo-settings-center-inner textarea, #store-seo-settings-left input, #store-lb-schema-content input, #store-lb-schema-content textarea', function() {
        
        if ($(this).is('#seo-s-lb-enabled')) {
            $('#seo-s-lb-type-wrap').toggle($(this).is(':checked'));
        }
        if ($(this).is('#seo-s-lb-enabled') || $(this).closest('#seo-s-lb-type-wrap').length) {
            $('#seo-lb-completeness').replaceWith(seoRenderSchemaCompleteness());
        }
        seoSettingsAutoSave();
    });
    $(document).on('input', '#seo-settings-right-inner textarea', function() {
        seoSettingsAutoSave();
    });

    
    $(document).on('click', '#seo-social-add', function() {
        var $list = $('#seo-social-list');
        var idx = $list.find('.seo-social-row').length;
        $list.append(seoSocialRow('', idx));
        $list.find('.seo-social-row').last().find('.seo-social-url').focus();
    });
    $(document).on('click', '.seo-social-remove', function() {
        $(this).closest('.seo-social-row').remove();
        seoSettingsAutoSave();
    });
    $(document).on('input', '.seo-social-url', function() {
        var url = $(this).val().trim();
        var platform = seoDetectPlatform(url);
        $(this).closest('.seo-social-row').find('.seo-social-label').text(platform || 'Paste URL');
    });

    if ($('.impulse-editor').data('workspace') === 'seo') {
        seoInitWorkspace();
    }

    window.seoLoadSettings          = seoLoadSettings;
    window.seoRenderSettingsCenter  = seoRenderSettingsCenter;
    window.seoRenderSettingsLeft    = seoRenderSettingsLeft;
    window.seoRenderSettingsRight   = seoRenderSettingsRight;

    

    var _speedStrategy = 'mobile';

    function seoSpeedReset(pageId) {
        if (!pageId) { $('#seo-speed-panel').hide(); return; }
        $('#seo-speed-panel').show();
        $('#seo-speed-body').hide();
        $('#seo-speed-status').text('');
        $('#seo-speed-stamp').text('');
        seoSpeedLoad(false);
    }

    function seoSpeedLoad(refresh) {
        var pageId = _seoState.currentPageId;
        if (!pageId) return;

        if (refresh) {
            $('#seo-speed-run-btn').prop('disabled', true).text('Measuring…');
            $('#seo-speed-status').text('Google is loading the page. This takes up to 30 seconds.');
        }
        seoApi('/pages/' + pageId + '/pagespeed?strategy=' + _speedStrategy + (refresh ? '&refresh=1' : ''))
            .done(function(d) { seoSpeedRender(d, refresh); })
            .fail(function() {
                $('#seo-speed-status').text('Could not reach PageSpeed.');
            })
            .always(function() {
                $('#seo-speed-run-btn').prop('disabled', false).text('Measure');
            });
    }

    function seoSpeedRender(d, wasRefresh) {
        if (!d || !d.ok) {
            $('#seo-speed-body').hide();

            $('#seo-speed-status').text(d && d.pending ? (wasRefresh ? '' : 'Not measured yet.') : ((d && d.error) || 'No result.'));
            return;
        }
        $('#seo-speed-status').text('');
        $('#seo-speed-body').show();

        var score = (typeof d.score === 'number') ? d.score : null;
        $('#seo-speed-score').text(score === null ? '—' : score)
                             .css('color', seoScoreColor(score === null ? 0 : score));
        $('#seo-speed-stamp').text(d.fetched_at ? (d.cached ? 'Measured ' : 'Just measured ') + seoSpeedAge(d.fetched_at) : '');

        var $m = $('#seo-speed-metrics').empty();
        (d.metrics || []).forEach(function(m) {
            $m.append(seoSpeedTile(m.label, m.display, seoSpeedAuditColor(m.score)));
        });

        var $f = $('#seo-speed-field').empty();
        if ((d.field || []).length) {
            d.field.forEach(function(m) {
                $f.append(seoSpeedTile(m.label, m.display, seoSpeedFieldColor(m.category)));
            });
            $('#seo-speed-field-wrap').show();
        } else {
            $('#seo-speed-field-wrap').hide();
        }

        var $o = $('#seo-speed-opps').empty();
        if ((d.opportunities || []).length) {
            d.opportunities.forEach(function(o) {
                $o.append($('<div/>').css({display:'flex',justifyContent:'space-between',gap:'10px',padding:'4px 0',borderBottom:'1px solid #22252a'})
                    .append($('<span/>').css({minWidth:0,overflow:'hidden',textOverflow:'ellipsis',whiteSpace:'nowrap'}).text(o.title))
                    .append($('<span/>').css({color:'#888',flexShrink:0}).text('−' + (o.savings_ms / 1000).toFixed(1) + 's')));
            });
            $('#seo-speed-opps-wrap').show();
        } else {
            $('#seo-speed-opps-wrap').hide();
        }
    }

    function seoSpeedTile(label, value, color) {
        return $('<div/>').css({background:'#22252a',borderRadius:'3px',padding:'8px 10px',minWidth:0})
            .append($('<div/>').css({fontSize:'11px',color:'#888'}).text(label))
            .append($('<div/>').css({fontSize:'13px',color:color,marginTop:'2px',overflow:'hidden',textOverflow:'ellipsis',whiteSpace:'nowrap'}).text(value || '—'));
    }

    
    function seoSpeedAuditColor(s) {
        if (s === null || typeof s === 'undefined') return '#999';
        return seoScoreColor(Math.round(s * 100));
    }
    function seoSpeedFieldColor(cat) {
        if (cat === 'FAST')     return '#e0e0e0';
        if (cat === 'AVERAGE')  return '#aaa';
        if (cat === 'SLOW')     return '#777';
        return '#999';
    }
    function seoSpeedAge(ts) {
        var mins = Math.max(0, Math.round((Date.now() / 1000 - ts) / 60));
        if (mins < 1)  return 'just now';
        if (mins < 60) return mins + ' min ago';
        var hrs = Math.round(mins / 60);
        return hrs === 1 ? '1 hour ago' : hrs + ' hours ago';
    }

    $(document).on('click', '#seo-speed-run-btn', function() { seoSpeedLoad(true); });
    $(document).on('click', '#seo-speed-strategy button', function() {
        var $b = $(this);
        if ($b.hasClass('active')) return;
        $('#seo-speed-strategy button').removeClass('active');
        $b.addClass('active');
        _speedStrategy = $b.data('strategy') === 'desktop' ? 'desktop' : 'mobile';
        
        seoSpeedLoad(false);
    });

    function seoLoadPageImages(pageId) {
        if (!pageId) { $('#seo-images-panel').hide(); return; }
        $('#seo-images-panel').show();
        $('#seo-images-summary').text('Loading…');
        $('#seo-images-list').empty();
        $('#seo-images-result').hide();

        seoApi('/pages/' + pageId + '/images').done(function(data) {
            seoRenderPageImages(data.images || []);
        }).fail(function() {
            $('#seo-images-summary').text('Could not load images');
        });
    }

    function seoRenderPageImages(images) {
        var $list = $('#seo-images-list');
        $list.empty();

        if (!images.length) {
            $('#seo-images-summary').text('No Instinctor library images on this page');
            $('#seo-images-optimize-btn').hide();
            return;
        }
        $('#seo-images-optimize-btn').show();

        var total       = images.length;
        var optimized   = images.filter(function(i) { return i.optimized && Object.keys(i.derivatives || {}).length > 0; }).length;
        var unoptimized = total - optimized;
        var rawBytes    = images.reduce(function(s, i) { return s + (!i.optimized ? (i.orig_size || 0) : 0); }, 0);
        var savingEst   = rawBytes > 0 ? ' · ~' + seoFmtBytes(Math.round(rawBytes * 0.65)) + ' potential saving' : '';

        $('#seo-images-summary').text(
            total + ' image' + (total !== 1 ? 's' : '') + ' · ' + unoptimized + ' unoptimized' + savingEst
        );

        $('#seo-images-optimize-btn')
            .text(unoptimized === 0 ? 'Re-optimize all' : 'Optimize all')
            .css(unoptimized === 0
                ? {background:'#2a2e33', color:'#e0e0e0', borderColor:'#3a3f44'}
                : {background:'#fff', color:'#1d2327', borderColor:'#fff'}
            );

        images.forEach(function(img) {
            var hasDerivs   = img.derivatives && Object.keys(img.derivatives).length > 0;
            var isStretched = (img.orig_w || 0) > 0 && Object.values(img.target_dims || {}).some(function(wh) { return wh[0] > img.orig_w; });
            var dimStr    = (img.orig_w && img.orig_h) ? img.orig_w + '×' + img.orig_h : '';
            var origSz    = img.orig_size ? seoFmtBytes(img.orig_size) : '';
            var webpSz    = (hasDerivs && img.derivatives.d) ? seoFmtBytes(img.derivatives.d.size) : '';
            var sizeStr   = (origSz && webpSz) ? origSz + ' → ' + webpSz : origSz;
            var altText   = img.alt || '';
            var altTrunc  = altText.length > 38 ? altText.slice(0, 36) + '…' : altText;
            var titleName = img.title || img.filename || ('Image ' + img.id);

            var badge = hasDerivs
                ? '<span style="font-size:11px;font-weight:600;background:#3a3f44;color:#e0e0e0;padding:1px 5px;border-radius:2px;white-space:nowrap">Optimized</span>'
                : '<span style="font-size:11px;color:#555;padding:1px 5px;white-space:nowrap">Original</span>';

            var thumbBorder = isStretched ? '2px solid #c44' : 'none';
            var stretchTip  = isStretched ? ' title="Stretched — image smaller than display size"' : '';

            var rowHtml = '<div class="seo-img-row" data-img-id="' + img.id + '">'
                + '<div class="seo-img-row-head">'
                +   '<div class="seo-img-thumb-cell" style="border:' + thumbBorder + '"' + stretchTip + '>'
                +     '<img src="' + seoEscape(img.thumb) + '" loading="lazy" style="width:100%;height:100%;object-fit:cover;display:block">'
                +   '</div>'
                +   '<div class="seo-img-name-cell">'
                +     '<div style="font-size:11px;color:#e0e0e0;white-space:nowrap;overflow:hidden;text-overflow:ellipsis" title="' + seoEscape(titleName) + '">' + seoEscape(titleName) + '</div>'
                +     '<div style="font-size:11px;color:#666;margin-top:2px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis">' + [dimStr, sizeStr].filter(Boolean).join(' · ') + '</div>'
                +   '</div>'
                +   '<div class="seo-img-alt-cell" title="' + seoEscape(altText || 'No alt text') + '">'
                +     (altTrunc || '')
                +   '</div>'
                +   '<div class="seo-img-badge-cell">' + badge + '</div>'
                + '</div>'
                
                + '<div class="seo-img-row-body">'
                +   '<div style="display:flex;align-items:stretch;height:100%">'
                +     '<div style="flex:0 0 160px;position:relative;display:flex;flex-direction:column;background:#2a2e33;overflow:hidden">'
                +       '<img src="' + seoEscape(img.thumb) + '" class="seo-img-body-thumb" style="width:100%;flex:1;object-fit:cover;display:block;min-height:0;cursor:pointer" title="Click to collapse">'
                +       '<button type="button" class="seo-img-row-close" style="position:absolute;top:6px;left:6px;width:20px;height:20px;background:none;border:none;color:white;font-size:12px;line-height:1;cursor:pointer;display:flex;align-items:center;justify-content:center;padding:0;mix-blend-mode:difference" title="Collapse">▲</button>';

            if (hasDerivs) {
                rowHtml += '<button type="button" class="impulse-btn-sm seo-img-restore-btn" data-img-id="' + img.id + '" style="flex-shrink:0;width:100%;border-radius:0;height:26px;font-size:11px">Restore Original</button>';
            } else {
                rowHtml += '<button type="button" class="impulse-btn-sm seo-img-optimize-btn" data-img-id="' + img.id + '" style="flex-shrink:0;width:100%;border-radius:0;height:26px;font-size:11px">'
                        +    (isStretched ? 'Optimize (stretched)' : 'Optimize')
                        +  '</button>';
            }
            rowHtml +=   '</div>'
                +     '<div style="flex:1;min-width:0;padding:12px 10px 12px;display:flex;flex-direction:column;justify-content:flex-start">'
                +       '<div style="margin-bottom:6px">'
                +         '<div style="font-size:11px;color:#888;margin-bottom:3px">Alt text</div>'
                +         '<div style="display:flex;gap:4px;align-items:stretch">'
                +           '<input type="text" class="seo-img-alt-input" data-img-id="' + img.id + '" value="' + seoEscape(altText) + '" placeholder="Describe image…" style="flex:1;min-width:0;height:26px;background:#2a2e33;border:1px solid #3a3f44;border-radius:3px;color:#e0e0e0;padding:0 8px;font-size:11px;box-sizing:border-box">'
                +           (window.Impulse.isPro ? '<button type="button" class="seo-img-alt-gen-btn impulse-btn-sm" data-img-id="' + img.id + '" data-src="' + seoEscape(img.url || img.thumb) + '" style="flex:0 0 130px;height:30px !important;min-height:30px;font-size:11px;padding:0 8px;box-sizing:border-box;line-height:1">Analyze &amp; Generate</button>' : '<span style="flex:0 0 70px;font-size:11px;color:#444;display:flex;align-items:center;justify-content:center" title="Pro feature">Auto (Pro)</span>')
                +         '</div>'
                +       '</div>'
                +       '<div>'
                +         '<div style="font-size:11px;color:#888;margin-bottom:3px">Title</div>'
                +         '<input type="text" class="seo-img-title-input" data-img-id="' + img.id + '" value="' + seoEscape(titleName) + '" placeholder="Image title…" style="width:100%;height:26px;background:#2a2e33;border:1px solid #3a3f44;border-radius:3px;color:#e0e0e0;padding:0 8px;font-size:11px;box-sizing:border-box">'
                +       '</div>'
                +       '<div style="font-size:11px;color:#666;margin-top:5px">' + [dimStr, sizeStr].filter(Boolean).join(' · ') + '</div>'
                +       '<span class="seo-img-row-status" style="font-size:11px;color:#888;margin-top:2px"></span>'
                +     '</div>'
                +   '</div>'
                + '</div>'
                + '</div>';

            $list.append(rowHtml);
        });

        $('#seo-images-result').hide();
    }

    $(document).on('click', '.seo-img-row-head', function() {
        var $row   = $(this).closest('.seo-img-row');
        var $body  = $row.find('.seo-img-row-body');
        var isOpen = $body.is(':visible');
        
        $('.seo-img-row-body').not($body).hide();
        if (!isOpen) {
            $body.hide().fadeIn(180);
        } else {
            $body.fadeOut(140);
        }
    });
    
    $(document).on('click', '.seo-img-row-close, .seo-img-body-thumb', function(e) {
        e.stopPropagation();
        var $row = $(this).closest('.seo-img-row');
        $row.find('.seo-img-row-body').fadeOut(140);
    });
    
    $(document).on('click', function(e) {
        if (!$(e.target).closest('.seo-img-row').length) {
            $('.seo-img-row-body').fadeOut(140);
            }
    });

    $(document).on('blur', '.seo-img-alt-input', function() {
        var $inp = $(this);
        var imgId = parseInt($inp.data('imgId'), 10);
        var alt   = $inp.val();
        $.post(ajaxurl, {
            action: 'instinctor_imglib_update',
            nonce: window.Impulse.adminNonce,
            id: imgId,
            alt: alt
        });
        
        var $row = $inp.closest('.seo-img-row');
        var trunc = alt.length > 38 ? alt.slice(0, 36) + '…' : alt;
        $row.find('.seo-img-alt-cell').html(
            trunc ? seoEscape(trunc) : '<span style="color:#444;font-style:italic">No alt text</span>'
        );
    });

    $(document).on('blur', '.seo-img-title-input', function() {
        var $inp  = $(this);
        var imgId = parseInt($inp.data('imgId'), 10);
        $.post(ajaxurl, {
            action: 'instinctor_imglib_update',
            nonce: window.Impulse.adminNonce,
            id: imgId,
            title: $inp.val()
        });
    });

    $(document).on('click', '.seo-img-alt-gen-btn', function() {
        if (!window.Impulse.isPro) return;
        var $btn        = $(this);
        var $row        = $btn.closest('.seo-img-row');
        var imgId       = parseInt($btn.data('imgId'), 10);
        var src         = $btn.data('src') || '';
        var $altInput   = $row.find('.seo-img-alt-input');
        var $titleInput = $row.find('.seo-img-title-input');

        var s = _seoState.settings || {};
        var storeName = s.store_name        || s.site_name || '';
        var storeDesc = s.store_description || '';
        if (!storeName || !storeDesc) {
            var missing = [];
            if (!storeName) missing.push('Store Name');
            if (!storeDesc) missing.push('Store Description');
            seoToast(
                'Fill in ' + missing.join(' and ') + ' in Settings before running analysis.',
                'error'
            );
            return;
        }

        $btn.prop('disabled', true).text('…');

        var ctx = {
            image_url:        src,
            store_name:       storeName,
            store_description:storeDesc,
            page_title:       $('#seo-field-meta-title').val()    || '',
            page_description: $('#seo-field-meta-desc').val()     || '',
            focus_keyword:    $('#seo-field-focus-keyword').val()  || '',
            page_slug:        _seoState.currentSlug || ''};

        $.ajax({
            url: window.Impulse.api + 'seo/images/' + imgId + '/generate-alt',
            method: 'POST',
            contentType: 'application/json',
            beforeSend: function(xhr) { xhr.setRequestHeader('X-WP-Nonce', window.Impulse.nonce); },
            data: JSON.stringify(ctx),
            success: function(r) {
                if (r.alt_text || r.image_title) {
                    if (r.alt_text)   { $altInput.val(r.alt_text).trigger('blur'); }
                    if (r.image_title){ $titleInput.val(r.image_title).trigger('blur'); }
                    $btn.text('Done').css('color','#e0e0e0');
                    setTimeout(function() { $btn.prop('disabled', false).text('Analyze & Generate').css('color',''); }, 1800);
                } else {
                    $btn.prop('disabled', false).text('Retry');
                }
            },
            error: function(xhr) {
                var msg = 'Failed';
                try { var r = JSON.parse(xhr.responseText); msg = r.message || r.error || msg; } catch(e) {}
                $btn.prop('disabled', false).text('Retry').removeAttr('title');
                seoToast('Alt generate failed: ' + msg, 'error');
                setTimeout(function() { $btn.text('Analyze & Generate'); }, 3000);
            }
        });
    });

    $(document).on('click', '.seo-img-optimize-btn', function(e) {
        e.stopPropagation();
        var imgId = parseInt($(this).data('imgId'), 10);
        var $btn  = $(this);
        var $status = $btn.closest('.seo-img-row').find('.seo-img-row-status');
        $btn.prop('disabled', true).text('Optimizing…');
        $.post(ajaxurl, {
            action: 'instinctor_imglib_optimize_one',
            nonce: window.Impulse.adminNonce,
            id: imgId,
            quality: 75,
            max_width: 1600,
            max_height: 1600,
            webp: '0'
        }, function(r) {
            if (r.success) {
                var d = r.data;
                if (d.status === 'already_optimal') {
                    $btn.prop('disabled', false).text('Optimize');
                    $status.text('Already optimal');
                } else {
                    var saved = seoFmtBytes(d.saved || 0);
                    $status.text('Saved ' + saved);
                    
                    seoLoadPageImages(_seoState.currentPageId);
                }
            } else {
                $btn.prop('disabled', false).text('Optimize');
                $status.css('color','#c44').text('Failed');
            }
        }).fail(function() {
            $btn.prop('disabled', false).text('Optimize');
            $status.css('color','#c44').text('Error');
        });
    });

    $(document).on('click', '.seo-img-restore-btn', function(e) {
        e.stopPropagation();
        var imgId = parseInt($(this).data('imgId'), 10);
        var $btn  = $(this);
        $btn.prop('disabled', true).text('…');

        seoApi('/images/' + imgId + '/restore', 'POST', {}).done(function() {
            seoLoadPageImages(_seoState.currentPageId);
        }).fail(function() {
            $btn.prop('disabled', false).text('Restore Original');
            seoToast('Restore failed', 'error');
        });
    });

    $(document).on('click', '#seo-images-optimize-btn', function() {
        if (!_seoState.currentPageId) return;
        var $btn = $(this);
        $btn.prop('disabled', true).text('Optimizing…');
        $('#seo-images-result').text('Creating WebP derivatives…').show();

        seoApi('/pages/' + _seoState.currentPageId + '/images/optimize', 'POST', {}).done(function(data) {
            var results = data.results || [];
            var done    = results.filter(function(r) { return r.status === 'optimized'; }).length;
            var skipped = results.filter(function(r) { return r.status === 'stretched'; }).length;
            var saved   = results.reduce(function(sum, r) {
                return sum + Object.values(r.derivatives || {}).reduce(function(s, d) { return s + (d.saved || 0); }, 0);
            }, 0);
            var msg = done + ' image' + (done !== 1 ? 's' : '') + ' optimized';
            if (saved > 0) msg += ' · ' + seoFmtBytes(saved) + ' saved';
            if (skipped > 0) msg += ' · ' + skipped + ' skipped (stretched)';
            $('#seo-images-result').text(msg);
            seoLoadPageImages(_seoState.currentPageId);
        }).fail(function(xhr) {
            var msg = 'Optimization failed';
            try { msg = JSON.parse(xhr.responseText).message || msg; } catch(e) {}
            $('#seo-images-result').text(msg);
        }).always(function() {
            $btn.prop('disabled', false);
        });
    });

    function seoFmtBytes(bytes) {
        if (bytes >= 1048576) return (bytes / 1048576).toFixed(1) + 'MB';
        if (bytes >= 1024)    return Math.round(bytes / 1024) + 'KB';
        return bytes + 'B';
    }

    

    

    

    
    var _trafficRange = 'today';
    var _trafficLoaded = false;
    var _dropoffPageId = null;   

    $(document).on('click', '.seo-mode-tab', function() {
        var $b = $(this);
        var mode = $b.data('mode');
        $('.seo-mode-tab').removeClass('active').css({background:'transparent',color:'#888'});
        $b.addClass('active').css({background:'transparent',color:'#e0e0e0'});

        var traffic = (mode === 'traffic');
        $('#seo-health-strip, #seo-pages-list').toggle(!traffic);
        $('#traffic-range-picker').toggle(traffic);

        

        if (traffic) {
            $('#seo-center-empty, #seo-page-editor').hide();
        } else if (_seoState.currentPageId) {
            $('#seo-page-editor').show();
            $('#seo-center-empty').hide();
        } else {
            $('#seo-page-editor').hide();
            $('#seo-center-empty').show();
        }
        $('#traffic-dashboard').toggle(traffic);

        
        
        if (traffic) {
            $('#seo-right-analysis, #seo-settings-right').hide();
            $('#traffic-right-panel').show();

            
            if (_lastChart) _renderLineChart(_lastChart.series, _lastChart.range);
        } else {
            $('#traffic-right-panel').hide();
            if (_seoState.currentPageId) {
                $('#seo-right-analysis').show();
            } else {
                _gscLoad();
                $('#seo-settings-right').show();
                seoRenderSettingsRight();
            }
        }

        if (traffic) {
            _exclLoad();
            if (!_trafficLoaded) _trafficLoad();
        }
    });

    

    var _exclLoaded = false;
    function _exclLoad() {
        if (_exclLoaded) return;
        _exclLoaded = true;
        $.ajax({ url: Impulse.api + 'analytics/exclusions', method: 'GET', headers: { 'X-WP-Nonce': Impulse.nonce } })
            .done(function(d) { $('#traffic-excl').val((d && d.raw) || ''); });
    }
    $(document).on('click', '#traffic-excl-save', function() {
        var $b = $(this).prop('disabled', true).text('Saving…');
        $.ajax({
            url: Impulse.api + 'analytics/exclusions',
            method: 'POST',
            contentType: 'application/json',
            headers: { 'X-WP-Nonce': Impulse.nonce },
            data: JSON.stringify({ hosts: $('#traffic-excl').val() })
        }).done(function() {
            _trafficLoad();
        }).always(function() {
            $b.prop('disabled', false).text('Apply');
        });
    });

    $(document).on('click', '.traffic-range-btn', function() {
        var $b = $(this);
        _trafficRange = $b.data('range');
        $('.traffic-range-btn').removeClass('active').css({background:'transparent',color:'#999',border:'1px solid #2a2e33'});
        $b.addClass('active').css({background:'#e0e0e0',color:'#1d2327',border:'1px solid #e0e0e0'});
        _trafficLoad();
    });

    

    function _renderDropoff(d) {
        var drop    = d.dropoff || [];
        var pages   = d.exitPages || [];
        var screens = parseInt(d.dropoffScreens) || 0;
        if (d.dropoffPageId) _dropoffPageId = d.dropoffPageId;

        var _selPage = null;
        pages.forEach(function(p){ if (p.page_id === _dropoffPageId) _selPage = p; });
        var _unit = (_selPage && _selPage.classic) ? 'Section' : 'Screen';
        $('#traffic-dropoff-title').text('Where visitors leave (by ' + _unit.toLowerCase() + ')');
        var sel = '';
        if (pages.length) {
            sel = '<select id="traffic-dropoff-page" class="seo-dark-input" style="width:100%;height:26px;font-size:11px;margin-bottom:8px">'
                + pages.map(function(p){
                    var s = (p.page_id === _dropoffPageId) ? ' selected' : '';
                    return '<option value="' + p.page_id + '"' + s + '>' + seoEscape(p.label) + ' (' + _fmtNum(p.sessions) + ')</option>';
                  }).join('') + '</select>';
        }
        if (!drop.length) {
            $('#traffic-dropoff').html(sel + '<div style="color:#555;font-size:11px">No exit data for this page yet.</div>');
            return;
        }
        var inRange = [], older = 0;
        drop.forEach(function(r){
            var idx = r.exit_screen | 0;
            if (screens > 0 && idx >= screens) { older += (r.sessions | 0); }
            else { inRange.push(r); }
        });
        var dropMax = inRange.reduce(function(m,r){return Math.max(m, r.sessions|0);}, 0) || 1;
        var rows = inRange.map(function(r){
            var pct = Math.round((r.sessions / dropMax) * 100);
            return '<div style="margin-bottom:7px">'
                + '<div style="display:flex;justify-content:space-between;margin-bottom:3px">'
                +   '<span style="color:#e0e0e0;font-size:12px">' + _unit + ' ' + ((r.exit_screen|0) + 1) + '</span>'
                +   '<span style="color:#999;font-size:11px">' + _fmtNum(r.sessions) + ' left here</span>'
                + '</div>'
                + '<div style="height:3px;background:#22252a;border-radius:2px;overflow:hidden"><div style="height:100%;width:' + pct + '%;background:#999"></div></div>'
              + '</div>';
        }).join('');
        if (older > 0) {
            rows += '<div style="margin-top:6px;color:#666;font-size:10px">' + _fmtNum(older) + ' left on a previous layout</div>';
        }
        $('#traffic-dropoff').html(sel + rows);
    }
    function _loadDropoff(pageId) {
        _dropoffPageId = pageId;
        var url = Impulse.api + 'analytics/summary?range=' + encodeURIComponent(_trafficRange) + '&exit_page_id=' + encodeURIComponent(pageId);
        $.ajax({ url: url, method: 'GET', headers: { 'X-WP-Nonce': Impulse.nonce } }).done(function(data){ _renderDropoff(data); });
    }
    $(document).on('change', '#traffic-dropoff-page', function() {
        _loadDropoff(parseInt($(this).val(), 10));
    });
    function _trafficLoad() {
        var url = Impulse.api + 'analytics/summary?range=' + encodeURIComponent(_trafficRange)
                + (_dropoffPageId ? '&exit_page_id=' + encodeURIComponent(_dropoffPageId) : '');
        $.ajax({
            url: url,
            method: 'GET',
            headers: { 'X-WP-Nonce': Impulse.nonce }
        }).done(function(data) {
            _trafficLoaded = true;
            _trafficRender(data);
        }).fail(function() {
            $('#traffic-kpi-views').text('—');
            $('#traffic-kpi-visitors').text('—');
            $('#traffic-chart-empty').text('Failed to load analytics.').show();
        });
    }

    function _trafficRender(d) {

        var ex = d.excluded || {};
        $('#traffic-excl-note').text(
            (ex.hosts && ex.hosts.length)
                ? ('Holding back ' + _fmtNum(ex.views || 0) + ' view' + ((ex.views === 1) ? '' : 's') + ' in this range')
                : 'Nothing excluded'
        );
        
        var t = d.totals || { views: 0, visitors: 0 };
        $('#traffic-kpi-views').text(_fmtNum(t.views));
        $('#traffic-kpi-visitors').text(_fmtNum(t.visitors));
        $('#traffic-kpi-views-range, #traffic-kpi-visitors-range').text(d.range.label || '');

        function _fmtTime(s) { s = s | 0; if (s < 60) return s + 's'; return Math.floor(s / 60) + 'm ' + (s % 60) + 's'; }
        var eng = d.engagement || { avg_seconds: 0, avg_scroll: 0, bounce_rate: 0, engaged_views: 0 };
        var hasEng = (eng.engaged_views | 0) > 0;
        $('#traffic-kpi-time').text(hasEng ? _fmtTime(eng.avg_seconds) : '—');
        $('#traffic-kpi-bounce').text(hasEng ? (eng.bounce_rate + '%') : '—');

        _renderDropoff(d);

        _renderLineChart(d.viewsOverTime || [], d.range);

        

        var _chLabels = { search:'Search', video:'Video', social:'Social', campaign:'Campaign', referral:'Referral', direct:'Direct' };
        var chans = d.channels || [];
        var chMax = chans.reduce(function(m,r){return Math.max(m, r.views|0);}, 0) || 1;
        var chHtml = chans.length ? chans.map(function(r){
            var pct = Math.round(((r.views|0) / chMax) * 100);
            var q = (r.avg_engaged|0) + 's · ' + (r.avg_scroll|0) + '% scroll';
            return '<div style="margin-bottom:8px">'
                + '<div style="display:flex;justify-content:space-between;align-items:baseline;margin-bottom:3px">'
                +   '<span style="color:#e0e0e0;font-size:12px">' + (_chLabels[r.channel] || _esc(r.channel)) + '</span>'
                +   '<span style="color:#999;font-size:11px;flex-shrink:0">' + _fmtNum(r.views) + ' <span style="color:#666">(' + _fmtNum(r.visitors) + ' visitors · ' + q + ')</span></span>'
                + '</div>'
                + '<div style="height:3px;background:#22252a;border-radius:2px;overflow:hidden"><div style="height:100%;width:' + pct + '%;background:#999"></div></div>'
              + '</div>';
        }).join('') : '<div style="color:#555;font-size:11px">No traffic in this range yet.</div>';
        $('#traffic-channels').html(chHtml);

        var lands = d.channelLanding || [];
        var byCh = {};
        lands.forEach(function(r){ (byCh[r.channel] = byCh[r.channel] || []).push(r); });
        var landHtml = Object.keys(byCh).length ? Object.keys(byCh).map(function(ch){
            var rows = byCh[ch].slice(0, 5).map(function(r){
                return '<div style="display:flex;justify-content:space-between;margin-bottom:2px">'
                    + '<span style="color:#bbb;font-size:11px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;max-width:75%">' + _esc(r.path || '/') + '</span>'
                    + '<span style="color:#777;font-size:11px">' + _fmtNum(r.views) + '</span>'
                  + '</div>';
            }).join('');
            return '<div style="margin-bottom:10px">'
                + '<div style="color:#888;font-size:10px;text-transform:uppercase;letter-spacing:.5px;margin-bottom:4px">' + (_chLabels[ch] || _esc(ch)) + '</div>'
                + rows
              + '</div>';
        }).join('') : '<div style="color:#555;font-size:11px">No traffic in this range yet.</div>';
        $('#traffic-landing').html(landHtml);

        var jrs = d.journeys || [];
        var jrHtml = jrs.length ? jrs.map(function(r){
            var steps = (r.journey || '').split(' > ');
            var shown = steps.slice(0, 4).map(_esc).join('<span style="color:#666"> → </span>')
                      + (steps.length > 4 ? '<span style="color:#666"> → +' + (steps.length - 4) + '</span>' : '');
            return '<div style="display:flex;justify-content:space-between;align-items:baseline;margin-bottom:6px;gap:8px">'
                + '<span style="color:#bbb;font-size:11px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap">' + shown + '</span>'
                + '<span style="color:#777;font-size:11px;flex-shrink:0">×' + _fmtNum(r.sessions) + '</span>'
              + '</div>';
        }).join('') : '<div style="color:#555;font-size:11px">No journeys in this range yet.</div>';
        $('#traffic-journeys').html(jrHtml);

        
        
        var leads = d.leadsBySource || [];
        var ldLabels = { search:'Search', video:'Video', social:'Social', campaign:'Campaign', referral:'Referral', direct:'Direct', unknown:'Unknown' };
        var ldByChan = {};
        leads.forEach(function(r){ ldByChan[r.channel] = r; });

        
        var conv = d.conversion || {};
        var cch = conv.channels || [];
        var ccHtml = cch.length ? cch.map(function(r){
            var rate = (r.rate === null || r.rate === undefined) ? '' : (r.rate + '%');
            var ld = ldByChan[r.channel];
            var parts = [];
            if (ld) {
                if (ld.chat|0)    parts.push(_fmtNum(ld.chat) + ' chat');
                if (ld.form|0)    parts.push(_fmtNum(ld.form) + ' form');
                if (ld.booking|0) parts.push(_fmtNum(ld.booking) + ' booking');
                if (ld.quote|0)   parts.push(_fmtNum(ld.quote) + ' quote');
            }
            return '<div style="margin-bottom:7px">'
                + '<div style="display:flex;justify-content:space-between;align-items:baseline;gap:8px">'
                +   '<span style="color:#e0e0e0;font-size:12px">' + (ldLabels[r.channel] || _esc(r.channel)) + '</span>'
                +   '<span style="color:#999;font-size:11px;flex-shrink:0">'
                +     (rate ? '<span style="color:#e0e0e0">' + rate + '</span> <span style="color:#666">·</span> ' : '')
                +     _fmtNum(r.leads) + ' leads <span style="color:#666">/ ' + _fmtNum(r.visitors) + ' visitors</span>'
                +   '</span>'
                + '</div>'
                + (parts.length ? '<div style="color:#666;font-size:10px;margin-top:2px">' + parts.join(' · ') + '</div>' : '')
              + '</div>';
        }).join('') : '<div style="color:#555;font-size:11px">No conversion data in this range yet.</div>';
        $('#traffic-conversion').html(ccHtml);

        
        var cpg = (conv.pages || []).filter(function(r){ return (r.leads|0) > 0 || (r.visitors|0) >= 5; }).slice(0, 10);
        var hasConvPages = (conv.pages || []).some(function(r){ return (r.leads|0) > 0; });
        $('#traffic-conv-pages-card').toggle(hasConvPages);
        var cpHtml = cpg.length ? cpg.map(function(r){
            var rate = (r.rate === null || r.rate === undefined) ? '' : (r.rate + '%');
            return '<div style="display:flex;justify-content:space-between;align-items:baseline;margin-bottom:5px;gap:8px">'
                + '<span style="color:#bbb;font-size:11px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;max-width:60%">' + _esc(r.path || '/') + '</span>'
                + '<span style="color:#999;font-size:11px;flex-shrink:0">'
                +   ((r.leads|0) ? '<span style="color:#e0e0e0">' + _fmtNum(r.leads) + ' leads</span>' : '<span style="color:#666">0 leads</span>')
                +   ' <span style="color:#666">/ ' + _fmtNum(r.visitors) + ' landed' + (rate ? ' · ' + rate : '') + '</span>'
                + '</span>'
              + '</div>';
        }).join('') : '<div style="color:#555;font-size:11px">No landing data in this range yet.</div>';
        $('#traffic-conv-pages').html(cpHtml);

        
        var refs = (d.topReferrers || []).map(function(r){ return { label: r.referrer_host, views: r.views | 0 }; });
        var direct = d.direct || { views: 0, visitors: 0 };
        if ((direct.views | 0) > 0) refs.unshift({ label: 'Direct / none', views: direct.views | 0, _direct: true });
        var refMax = refs.reduce(function(m,r){return Math.max(m, r.views);}, 0) || 1;
        var refHtml = refs.length ? refs.map(function(r){
            var pct = Math.round((r.views / refMax) * 100);
            return '<div style="margin-bottom:7px">'
                + '<div style="display:flex;justify-content:space-between;align-items:baseline;margin-bottom:3px">'
                +   '<span style="color:' + (r._direct ? '#888' : '#e0e0e0') + ';font-size:12px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;max-width:65%">' + _esc(r.label) + '</span>'
                +   '<span style="color:#999;font-size:11px;flex-shrink:0">' + _fmtNum(r.views) + '</span>'
                + '</div>'
                + '<div style="height:3px;background:#22252a;border-radius:2px;overflow:hidden">'
                +   '<div style="height:100%;width:' + pct + '%;background:#999"></div>'
                + '</div>'
              + '</div>';
        }).join('') : '<div style="color:#555;font-size:11px">No traffic in this range yet.</div>';
        $('#traffic-referrers').html(refHtml);

        
        var srcs = d.topSources || [];
        var srcMax = srcs.reduce(function(m,r){return Math.max(m, r.views|0);}, 0) || 1;
        var srcHtml = srcs.length ? srcs.map(function(r){
            var pct = Math.round((r.views / srcMax) * 100);
            var label = [r.utm_source, r.utm_medium, r.utm_campaign].filter(function(x){ return x && x !== ''; }).join(' · ');
            return '<div style="margin-bottom:7px">'
                + '<div style="display:flex;justify-content:space-between;align-items:baseline;margin-bottom:3px">'
                +   '<span style="color:#e0e0e0;font-size:12px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;max-width:78%">' + _esc(label) + '</span>'
                +   '<span style="color:#999;font-size:11px;flex-shrink:0">' + _fmtNum(r.views) + '</span>'
                + '</div>'
                + '<div style="height:3px;background:#22252a;border-radius:2px;overflow:hidden">'
                +   '<div style="height:100%;width:' + pct + '%;background:#999"></div>'
                + '</div>'
              + '</div>';
        }).join('') : '';

        $('#traffic-sources-card').toggle(srcs.length > 0);
        $('#traffic-sources').html(srcHtml);

        var devs = d.deviceBreakdown || [];
        var devTotal = devs.reduce(function(s,d){return s+(d.views|0);}, 0) || 1;
        var devHtml = devs.length ? devs.map(function(r){
            var pct = Math.round((r.views / devTotal) * 100);
            return '<div style="margin-bottom:7px">'
                + '<div style="display:flex;justify-content:space-between;margin-bottom:3px">'
                +   '<span style="color:#e0e0e0;font-size:12px;text-transform:capitalize">' + _esc(r.device) + '</span>'
                +   '<span style="color:#999;font-size:11px">' + pct + '%</span>'
                + '</div>'
                + '<div style="height:3px;background:#22252a;border-radius:2px;overflow:hidden">'
                +   '<div style="height:100%;width:' + pct + '%;background:#999"></div>'
                + '</div>'
              + '</div>';
        }).join('') : '<div style="color:#555;font-size:11px">—</div>';
        $('#traffic-devices').html(devHtml);

        var cs = d.countryBreakdown || [];
        var cTotal = cs.reduce(function(s,d){return s+(d.views|0);}, 0) || 1;
        var cHtml = cs.length ? cs.slice(0, 10).map(function(r){
            var pct = Math.round((r.views / cTotal) * 100);
            return '<div style="margin-bottom:7px">'
                + '<div style="display:flex;justify-content:space-between;margin-bottom:3px">'
                +   '<span style="color:#e0e0e0;font-size:12px">' + _esc(r.country) + '</span>'
                +   '<span style="color:#999;font-size:11px">' + pct + '%</span>'
                + '</div>'
                + '<div style="height:3px;background:#22252a;border-radius:2px;overflow:hidden">'
                +   '<div style="height:100%;width:' + pct + '%;background:#999"></div>'
                + '</div>'
              + '</div>';
        }).join('') : '<div style="color:#555;font-size:11px">No location data in this range yet. Countries fill in as new (non-bot) visits arrive.</div>';
        $('#traffic-countries').html(cHtml);

        var pages = d.topPages || [];
        var pgMax = pages.reduce(function(m,r){return Math.max(m, r.views|0);}, 0) || 1;
        $('#traffic-pages').html(pages.length ? pages.map(function(r){
            var pct = Math.round((r.views / pgMax) * 100);
            var pathTxt = (r.path && r.path !== '') ? r.path : '/';
            var nm = (r.label && r.label !== '') ? r.label : '';
            var label = nm || pathTxt;

            
            
            return '<div style="margin-bottom:7px">'
                + '<div style="display:flex;justify-content:space-between;align-items:baseline;gap:8px;margin-bottom:3px">'
                +   '<span style="min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;color:#e0e0e0;font-size:12px" title="' + _esc(label) + (nm ? ' (' + _esc(pathTxt) + ')' : '') + '">'
                +     _esc(label)
                +     (nm ? ' <span style="color:#666;font-size:11px">' + _esc(pathTxt) + '</span>' : '')
                +   '</span>'
                +   '<span style="color:#999;font-size:11px;flex-shrink:0">' + _fmtNum(r.views) + '</span>'
                + '</div>'
                + '<div style="height:3px;background:#22252a;border-radius:2px;overflow:hidden"><div style="height:100%;width:' + pct + '%;background:#999"></div></div>'
              + '</div>';
        }).join('') : '<div style="color:#555;font-size:11px">No page views in this range yet.</div>');
    }

    
    
    var _lastChart = null;
    $(window).on('resize', function() {
        if (!_lastChart) return;
        clearTimeout(_lastChart.t);
        _lastChart.t = setTimeout(function() {
            if ($('#traffic-dashboard').is(':visible')) _renderLineChart(_lastChart.series, _lastChart.range);
        }, 150);
    });

    function _renderLineChart(series, range) {
        _lastChart = { series: series, range: range, t: _lastChart && _lastChart.t };
        var $svg = $('#traffic-chart-svg');
        $svg.empty();
        $('#traffic-chart-empty').hide();

        if (!series.length) {
            $('#traffic-chart-empty').show();
            return;
        }

        var days = _enumerateDays(range.from, range.to);
        var byDay = {};
        series.forEach(function(p){ byDay[p.day] = p.views|0; });
        var points = days.map(function(day){ return { day: day, views: byDay[day]|0 }; });

        var w = $svg.parent().width();
        var h = 200;
        var pad = { t: 12, r: 8, b: 26, l: 38 };
        var iw = w - pad.l - pad.r;
        var ih = h - pad.t - pad.b;
        $svg.attr('viewBox', '0 0 ' + w + ' ' + h);

        var maxV = points.reduce(function(m,p){return Math.max(m, p.views);}, 0);
        if (maxV < 4) maxV = 4; 

        var ns = 'http://www.w3.org/2000/svg';
        function el(tag, attrs) {
            var n = document.createElementNS(ns, tag);
            for (var k in attrs) n.setAttribute(k, attrs[k]);
            return n;
        }
        var svg = $svg[0];

        for (var i = 0; i <= 4; i++) {
            var y = pad.t + (ih * i / 4);
            svg.appendChild(el('line', { x1: pad.l, y1: y, x2: pad.l + iw, y2: y, stroke: '#22252a', 'stroke-width': 1 }));
            var label = el('text', { x: pad.l - 6, y: y + 3, fill: '#555', 'font-size': 10, 'text-anchor': 'end' });
            label.textContent = _fmtNum(Math.round(maxV * (4 - i) / 4));
            svg.appendChild(label);
        }

        var labelStep = Math.max(1, Math.ceil(points.length / 6));
        points.forEach(function(p, idx){
            if (idx % labelStep !== 0 && idx !== points.length - 1) return;
            var x = pad.l + (points.length === 1 ? iw/2 : (iw * idx / (points.length - 1)));
            var t = el('text', { x: x, y: pad.t + ih + 16, fill: '#555', 'font-size': 10, 'text-anchor': 'middle' });
            t.textContent = _shortDay(p.day);
            svg.appendChild(t);
        });

        var pts = points.map(function(p, idx){
            var x = pad.l + (points.length === 1 ? iw/2 : (iw * idx / (points.length - 1)));
            var y = pad.t + ih - (ih * (p.views / maxV));
            return [x, y];
        });
        var path = 'M' + pts.map(function(p){return p[0]+','+p[1];}).join(' L');
        var areaPath = path + ' L' + pts[pts.length-1][0] + ',' + (pad.t + ih) + ' L' + pts[0][0] + ',' + (pad.t + ih) + ' Z';
        svg.appendChild(el('path', { d: areaPath, fill: 'rgba(224,224,224,0.08)' }));
        svg.appendChild(el('path', { d: path, fill: 'none', stroke: '#e0e0e0', 'stroke-width': 1.5 }));

        pts.forEach(function(p, idx){
            var c = el('circle', { cx: p[0], cy: p[1], r: 2.5, fill: '#e0e0e0' });
            var tt = el('title');
            tt.textContent = _shortDay(points[idx].day) + ' — ' + _fmtNum(points[idx].views) + ' views';
            c.appendChild(tt);
            svg.appendChild(c);
        });
    }

    function _enumerateDays(from, to) {
        var out = [];
        var cur = new Date(from + 'T00:00:00Z');
        var end = new Date(to + 'T00:00:00Z');
        while (cur <= end) {
            out.push(cur.toISOString().slice(0, 10));
            cur.setUTCDate(cur.getUTCDate() + 1);
        }
        return out;
    }
    function _shortDay(d) {
        
        var p = d.split('-');
        return parseInt(p[1], 10) + '/' + parseInt(p[2], 10);
    }
    function _fmtNum(n) {
        n = n|0;
        if (n >= 1e6) return (n/1e6).toFixed(1) + 'M';
        if (n >= 1e3) return (n/1e3).toFixed(1) + 'k';
        return String(n);
    }
    function _esc(s) {
        s = String(s == null ? '' : s);
        return s.replace(/[&<>"]/g, function(c){ return {'&':'&amp;','<':'&lt;','>':'&gt;','"':'&quot;'}[c]; });
    }

});
