/**
 * TamRank SEO Audit — Dedicated JavaScript
 *
 * Uses fetch API, reads config from #tr-audit-data JSON block.
 * No jQuery dependency.
 */
(function () {
    'use strict';

    /* ========================================
       CONFIG
       ======================================== */

    // Config is provided via wp_add_inline_script (window.tamrankAuditData) instead of an
    // inline <script type="application/json"> data island (wp.org compliance).
    const cfg = window.tamrankAuditData || {};
    const i18n = cfg.i18n || {};

    /* ========================================
       HELPERS
       ======================================== */

    function $(sel, ctx) {
        return (ctx || document).querySelector(sel);
    }

    function $$(sel, ctx) {
        return Array.from((ctx || document).querySelectorAll(sel));
    }

    function ajaxPost(action, data) {
        const body = new FormData();
        body.append('action', action);
        body.append('nonce', cfg.nonce);
        if (data) {
            Object.keys(data).forEach(function (k) {
                body.append(k, data[k]);
            });
        }
        return fetch(cfg.ajaxUrl, { method: 'POST', body: body })
            .then(function (r) { return r.json(); });
    }

    function showToast(message, type) {
        var existing = $('.tr-toast');
        if (existing) existing.remove();

        var toast = document.createElement('div');
        toast.className = 'tr-toast' + (type ? ' tr-toast--' + type : '');
        toast.textContent = message;
        document.body.appendChild(toast);

        // Force reflow then show
        toast.offsetHeight;
        toast.classList.add('is-visible');

        setTimeout(function () {
            toast.classList.remove('is-visible');
            setTimeout(function () { toast.remove(); }, 300);
        }, 3000);
    }

    /* ========================================
       TAB NAVIGATION
       ======================================== */

    function initTabs() {
        var nav = $('.tr-pill-nav[role="tablist"]');
        if (!nav) return;
        var tabs = $$('.tr-pill[data-tab]', nav);
        var panels = $$('.tr-tab-panel');

        // Restore hash
        var hash = window.location.hash.replace('#', '');
        if (hash) {
            var target = document.getElementById('tab-' + hash);
            if (target) {
                tabs.forEach(function (t) { t.classList.remove('is-active'); });
                panels.forEach(function (p) { p.classList.remove('is-active'); });
                var btn = $('[data-tab="' + hash + '"]');
                if (btn) btn.classList.add('is-active');
                target.classList.add('is-active');
            }
        }

        tabs.forEach(function (tab) {
            tab.addEventListener('click', function () {
                var tabName = this.getAttribute('data-tab');

                tabs.forEach(function (t) { t.classList.remove('is-active'); });
                panels.forEach(function (p) { p.classList.remove('is-active'); });

                this.classList.add('is-active');
                var panel = document.getElementById('tab-' + tabName);
                if (panel) panel.classList.add('is-active');

                window.location.hash = tabName;
            });
        });
    }

    /* ========================================
       FILTER PILLS (Overview table)
       ======================================== */

    function initFilterPills() {
        var pills = $$('.tr-pill[data-filter]');

        pills.forEach(function (pill) {
            pill.addEventListener('click', function () {
                var filter = this.getAttribute('data-filter');

                pills.forEach(function (p) { p.classList.remove('is-active'); });
                this.classList.add('is-active');

                // Filter table rows
                var rows = $$('.tr-audit-table tbody tr[data-post-type]');
                rows.forEach(function (row) {
                    if (filter === 'all' || row.getAttribute('data-post-type') === filter) {
                        row.style.display = '';
                    } else {
                        row.style.display = 'none';
                    }
                });

                // Re-stripe the visible rows so the zebra stays even after
                // filtering. Rows are striped per item (not by DOM position),
                // so we recompute the alternation across only the visible ones.
                var visibleIndex = 0;
                rows.forEach(function (row) {
                    if (row.style.display === 'none') {
                        row.classList.remove('tr-row--alt');
                        return;
                    }
                    if (visibleIndex % 2 === 1) {
                        row.classList.add('tr-row--alt');
                    } else {
                        row.classList.remove('tr-row--alt');
                    }
                    visibleIndex++;
                });

                // Also filter expand rows
                var expandRows = $$('.tr-expand-row[data-post-type]');
                expandRows.forEach(function (row) {
                    if (filter === 'all' || row.getAttribute('data-post-type') === filter) {
                        // Keep original display state (hidden unless expanded)
                        // Don't force show — only allow if it was already visible
                    } else {
                        row.style.display = 'none';
                    }
                });
            });
        });
    }


    /* ========================================
       SCAN (Overview + Tools tab)
       ======================================== */

    var scanPolling = null;
    var scanCancelled = false;

    function ajaxPostWithTimeout(action, data, timeoutMs) {
        var controller = new AbortController();
        var timer = setTimeout(function () { controller.abort(); }, timeoutMs);

        var body = new FormData();
        body.append('action', action);
        body.append('nonce', cfg.nonce);
        if (data) {
            Object.keys(data).forEach(function (k) {
                var val = data[k];
                if (Array.isArray(val)) {
                    val.forEach(function (v) { body.append(k + '[]', v); });
                } else {
                    body.append(k, val);
                }
            });
        }

        return fetch(cfg.ajaxUrl, { method: 'POST', body: body, signal: controller.signal })
            .then(function (r) { clearTimeout(timer); return r.json(); });
    }

    function startScan(progressFillId, progressCountId, progressBannerId, scanBannerId) {
        var progressFill = document.getElementById(progressFillId);
        var progressCount = document.getElementById(progressCountId);
        var progressBanner = document.getElementById(progressBannerId);
        var scanBanner = scanBannerId ? document.getElementById(scanBannerId) : null;

        scanCancelled = false;

        // Show progress, hide idle banner
        if (progressBanner) progressBanner.style.display = '';
        if (scanBanner) scanBanner.style.display = 'none';

        var offset = 0;
        var total = 0;
        var retries = 0;
        var maxRetries = 3;
        var skipIds = [];       // posts that failed twice — skip on retry
        var failCounts = {};    // post_id → failure count
        var conflictResetTried = false; // stale-lock recovery guard

        function updateUI() {
            var pct = total > 0 ? Math.round((offset / total) * 100) : 0;
            if (progressFill) progressFill.style.width = pct + '%';
            if (progressCount) progressCount.textContent = offset + ' / ' + total;
        }

        function cleanup() {
            ajaxPost('tam_rank_reset_scan_lock', {});
            scanCancelled = false;
        }

        // Restore the idle UI when a scan can't start or finish (e.g. another
        // scan is genuinely running). Prevents the progress banner from being
        // left frozen at "0 / 0".
        function bailOut(msg) {
            if (msg) showToast(msg, 'warning');
            if (progressBanner) progressBanner.style.display = 'none';
            if (scanBanner) scanBanner.style.display = '';
            ['tr-start-scan', 'tr-bulk-scan'].forEach(function (id) {
                var b = document.getElementById(id);
                if (b) b.disabled = false;
            });
            var cancelBtn = document.getElementById('tr-cancel-scan');
            if (cancelBtn) cancelBtn.style.display = 'none';
        }

        function poll() {
            if (scanCancelled) {
                showToast(i18n.scan_cancelled || 'Scan cancelled.', 'info');
                cleanup();
                return;
            }

            ajaxPostWithTimeout('tam_rank_bulk_audit', {
                offset: offset,
                skip_ids: skipIds
            }, 30000) // 30 second timeout
                .then(function (res) {
                    if (scanCancelled) {
                        showToast(i18n.scan_cancelled || 'Scan cancelled.', 'info');
                        cleanup();
                        return;
                    }

                    if (res.success) {
                        var d = res.data;
                        total = d.total || total;
                        retries = 0;

                        // Track failed posts — add to skip list after 2 failures
                        if (d.failed_ids && d.failed_ids.length) {
                            d.failed_ids.forEach(function (id) {
                                failCounts[id] = (failCounts[id] || 0) + 1;
                                if (failCounts[id] >= 2 && skipIds.indexOf(id) === -1) {
                                    skipIds.push(id);
                                }
                            });
                        }

                        // Stall protection: if offset didn't move, force it forward
                        var newOffset = d.offset || offset;
                        if (newOffset <= offset && !d.complete) {
                            // Force skip past this batch
                            newOffset = offset + 1;
                        }

                        offset = newOffset;
                        updateUI();

                        if (d.complete || offset >= total) {
                            var skipped = skipIds.length;
                            var msg = i18n.scan_complete || 'Scan complete!';
                            if (skipped > 0) {
                                msg += ' (' + skipped + ' ' + (i18n.posts_skipped || 'pages skipped') + ')';
                            }
                            showToast(msg, 'success');
                            cleanup();
                            markScanJustFinished();
                            setTimeout(function () { location.reload(); }, 1000);
                            return;
                        }

                        scanPolling = setTimeout(poll, 500);
                    } else {
                        var code = res.data && res.data.code;
                        if (code === 'conflict') {
                            // A lock exists. On a single-admin tool this is almost
                            // always a stale lock from an interrupted scan, which
                            // would otherwise freeze the banner at "0 / 0" forever.
                            // Reset it once and retry; if it still conflicts, a real
                            // scan is running elsewhere — bail out with a message.
                            if (!conflictResetTried) {
                                conflictResetTried = true;
                                ajaxPost('tam_rank_reset_scan_lock', {}).finally(function () {
                                    scanPolling = setTimeout(poll, 400);
                                });
                            } else {
                                bailOut(i18n.scan_already_running || 'A scan is already running. Please wait until it finishes.');
                            }
                        } else {
                            showToast(
                                (res.data && res.data.message) || res.data || i18n.scan_error || 'Error during scan',
                                'error'
                            );
                            cleanup();
                            bailOut(null);
                        }
                    }
                })
                .catch(function () {
                    // Network error or timeout
                    retries++;
                    if (retries <= maxRetries) {
                        var delay = Math.pow(2, retries) * 1000;
                        scanPolling = setTimeout(poll, delay);
                    } else {
                        // Last resort: skip forward and reset retries
                        retries = 0;
                        offset = offset + 1;
                        updateUI();
                        if (offset >= total) {
                            showToast(i18n.scan_complete || 'Scan complete!', 'success');
                            cleanup();
                            markScanJustFinished();
                            setTimeout(function () { location.reload(); }, 1000);
                        } else {
                            showToast(i18n.scan_skip_batch || 'Batch skipped, scan continues...', 'warning');
                            scanPolling = setTimeout(poll, 1000);
                        }
                    }
                });
        }

        poll();
    }

    function cancelScan() {
        scanCancelled = true;
        if (scanPolling) {
            clearTimeout(scanPolling);
            scanPolling = null;
        }
    }

    function initScanButtons() {
        // Overview start scan
        var startBtn = document.getElementById('tr-start-scan');
        if (startBtn) {
            startBtn.addEventListener('click', function () {
                this.disabled = true;
                // Show cancel button
                var cancelBtn = document.getElementById('tr-cancel-scan');
                if (cancelBtn) cancelBtn.style.display = '';
                startScan('tr-progress-fill', 'tr-progress-count', 'tr-progress-banner', 'tr-scan-banner');
            });
        }

        // Cancel scan
        var cancelBtn = document.getElementById('tr-cancel-scan');
        if (cancelBtn) {
            cancelBtn.addEventListener('click', function () {
                cancelScan();
                this.style.display = 'none';
            });
        }

        // Tools bulk scan
        var bulkBtn = document.getElementById('tr-bulk-scan');
        if (bulkBtn) {
            bulkBtn.addEventListener('click', function () {
                this.disabled = true;
                var toolsProgress = document.getElementById('tr-tools-progress');
                if (toolsProgress) toolsProgress.style.display = '';
                startScan('tr-tools-progress-fill', 'tr-tools-progress-count', 'tr-tools-progress', null);
            });
        }

        // If scan is already running on page load, resume polling
        if (cfg.scanStatus === 'running') {
            var overviewProgressBanner = document.getElementById('tr-progress-banner');
            if (overviewProgressBanner) {
                startScan('tr-progress-fill', 'tr-progress-count', 'tr-progress-banner', 'tr-scan-banner');
            }
        }
    }


    /* ========================================
       TOOLS TAB
       ======================================== */

    function initTools() {
        // Export CSV (FREE) — overview toolbar button + Tools tab card both
        // download the audit results. Generate Report stays in the PRO add-on.
        var exportBtn = document.getElementById('tr-export-btn');
        if (exportBtn) { exportBtn.addEventListener('click', doExport); }
        var exportCsvBtn = document.getElementById('tr-export-csv');
        if (exportCsvBtn) { exportCsvBtn.addEventListener('click', doExport); }

        function doExport() {
            this.disabled = true;
            var self = this;
            ajaxPost('tam_rank_export_audit_results')
                .then(function (res) {
                    if (res.success && res.data && res.data.csv) {
                        var blob = new Blob([res.data.csv], { type: 'text/csv;charset=utf-8;' });
                        var url = URL.createObjectURL(blob);
                        var a = document.createElement('a');
                        a.href = url;
                        a.download = res.data.filename || 'tamrank-audit-export.csv';
                        document.body.appendChild(a);
                        a.click();
                        document.body.removeChild(a);
                        URL.revokeObjectURL(url);
                        showToast((i18n.export_downloaded || 'Export downloaded!'), 'success');
                    } else {
                        showToast(res.data || (i18n.export_failed || 'Export failed'), 'error');
                    }
                })
                .catch(function () {
                    showToast(i18n.network_error || 'Network error', 'error');
                })
                .finally(function () {
                    self.disabled = false;
                });
        }

        // Reset Data
        var resetBtn = document.getElementById('tr-reset-data');
        if (resetBtn) {
            resetBtn.addEventListener('click', function () {
                var btn = this;
                window.TamRank.confirm({
                    title: (i18n.reset_audit_title || 'Reset audit data?'),
                    message: (i18n.reset_audit_message || 'All audit data will be permanently deleted. This action cannot be undone.'),
                    confirmLabel: (i18n.reset || 'Reset'),
                    variant: 'danger'
                }).then(function (ok) {
                    if (!ok) return;
                    doReset(btn);
                });
            });
        }
        function doReset(btn) {
                btn.disabled = true;
                var self = btn;
                ajaxPost('tam_rank_reset_audit_data')
                    .then(function (res) {
                        if (res.success) {
                            showToast((i18n.audit_reset_success || 'All audit data has been reset'), 'success');
                            setTimeout(function () { location.reload(); }, 1000);
                        } else {
                            showToast(res.data || (i18n.audit_reset_failed || 'Reset failed'), 'error');
                        }
                    })
                    .catch(function () {
                        showToast(i18n.network_error || 'Network error', 'error');
                    })
                    .finally(function () {
                        self.disabled = false;
                    });
        }
    }


    /* ========================================
       EXCLUSION PANEL
       ======================================== */

    function initExclusionPanel() {
        var btn   = $('#tr-exclusion-btn');
        var panel = $('#tr-exclusion-panel');
        if (!btn || !panel) return;

        var excludedSet   = new Set((cfg.excludedPosts || []).map(Number));
        var searchTimeout = null;
        var panelLoaded   = false;

        // Toggle panel open/closed
        btn.addEventListener('click', function () {
            var visible = panel.style.display !== 'none';
            panel.style.display = visible ? 'none' : 'block';
            if (!visible && !panelLoaded) {
                panelLoaded = true;
                loadPosts(''); // Load initial list on first open
            }
        });

        // Cancel — close the panel without saving
        var cancelBtn = $('#tr-cancel-exclusions');
        if (cancelBtn) {
            cancelBtn.addEventListener('click', function () {
                panel.style.display = 'none';
            });
        }

        // Search with debounce
        var searchInput = $('#tr-exclusion-search-input');
        if (searchInput) {
            searchInput.addEventListener('input', function () {
                clearTimeout(searchTimeout);
                searchTimeout = setTimeout(function () {
                    loadPosts(searchInput.value);
                }, 300);
            });
        }

        // Load posts via AJAX
        function loadPosts(search) {
            var list = $('#tr-exclusion-list');
            if (!list) return;
            list.innerHTML = '<p style="color:var(--tr-color-slate-400);font-size:var(--tr-text-sm);">' + (i18n.loading || 'Loading...') + '</p>';

            var fd = new FormData();
            fd.append('action', 'tam_rank_search_posts_for_exclusion');
            fd.append('_ajax_nonce', cfg.nonce);
            fd.append('search', search);

            fetch(cfg.ajaxUrl, { method: 'POST', body: fd })
                .then(function (res) { return res.json(); })
                .then(function (json) {
                    if (!json.success) {
                        list.innerHTML = '<p style="color:var(--tr-color-slate-400);font-size:var(--tr-text-sm);">' + (i18n.load_error || 'Error loading') + '</p>';
                        return;
                    }

                    list.innerHTML = '';

                    if (json.data.length === 0) {
                        list.innerHTML = '<p style="color:var(--tr-color-slate-400);font-size:var(--tr-text-sm);">' + (i18n.no_results || 'No results') + '</p>';
                        return;
                    }

                    json.data.forEach(function (post) {
                        var label   = document.createElement('label');
                        label.className = 'tr-exclusion-item';
                        var checked = excludedSet.has(post.id) ? 'checked' : '';
                        label.innerHTML =
                            '<input type="checkbox" class="tr-check" value="' + post.id + '" ' + checked + '>' +
                            '<span class="tr-check-box"></span>' +
                            '<span class="tr-exclusion-item__title">' + post.title + '</span>' +
                            '<span class="tr-exclusion-item__type">' + post.type + '</span>';

                        label.querySelector('input').addEventListener('change', function (e) {
                            if (e.target.checked) {
                                excludedSet.add(post.id);
                            } else {
                                excludedSet.delete(post.id);
                            }
                        });

                        list.appendChild(label);
                    });
                })
                .catch(function () {
                    list.innerHTML = '<p style="color:var(--tr-color-slate-400);font-size:var(--tr-text-sm);">' + (i18n.network_error || 'Network error') + '</p>';
                });
        }

        // Save exclusions
        var saveBtn = $('#tr-save-exclusions');
        if (saveBtn) {
            saveBtn.addEventListener('click', function () {
                saveBtn.disabled  = true;
                saveBtn.textContent = i18n.saving || 'Saving...';

                var noindexCheck = $('#tr-exclude-noindex');
                var fd = new FormData();
                fd.append('action', 'tam_rank_save_audit_exclusions');
                fd.append('_ajax_nonce', cfg.nonce);
                fd.append('excluded_posts', JSON.stringify(Array.from(excludedSet)));
                fd.append('exclude_noindex', (noindexCheck && noindexCheck.checked) ? '1' : '0');

                // Collect excluded taxonomies
                var excludedTaxonomies = [];
                document.querySelectorAll('.tr-exclude-taxonomy:checked').forEach(function(cb) {
                    excludedTaxonomies.push(cb.dataset.taxonomy);
                });
                fd.append('excluded_taxonomies', JSON.stringify(excludedTaxonomies));

                fetch(cfg.ajaxUrl, { method: 'POST', body: fd })
                    .then(function (res) { return res.json(); })
                    .then(function (json) {
                        if (json.success) {
                            // Reload page to reflect new exclusions in table + stats
                            window.location.reload();
                        } else {
                            saveBtn.textContent = i18n.save_error || 'Error — try again';
                            saveBtn.disabled    = false;
                        }
                    })
                    .catch(function () {
                        saveBtn.textContent = i18n.network_error || 'Network error';
                        saveBtn.disabled    = false;
                    });
            });
        }
    }

    /* ========================================
       SCORE-ONTHULLING (piek-moment)
       Alleen direct na een afgeronde scan; de vlag wordt gezet vóór de
       reload zodat een gewoon paginabezoek rustig blijft. Richtlijnen:
       Branding.md §Motion & Feedback; laag in common/motion.css +
       tr-reveal.js.
       ======================================== */

    var REVEAL_FLAG = 'trAuditReveal';

    function markScanJustFinished() {
        try {
            sessionStorage.setItem(REVEAL_FLAG, '1');
        } catch (e) {
            // sessionStorage geblokkeerd (private mode) — dan geen reveal.
        }
    }

    function initScoreReveal() {
        var flagged = false;
        try {
            flagged = sessionStorage.getItem(REVEAL_FLAG) === '1';
            if (flagged) sessionStorage.removeItem(REVEAL_FLAG);
        } catch (e) {
            return;
        }
        if (!flagged) return;

        var statsBar = $('.tr-stats-bar');
        if (!statsBar) return;

        statsBar.classList.add('tr-reveal');
        var barFill = $('.tr-score-bar-fill', statsBar);
        if (barFill) barFill.classList.add('tr-reveal-bar');
        if (window.TamRankReveal) {
            window.TamRankReveal.numbersIn(statsBar, '.tr-stat-num');
        }
    }

    /* ========================================
       ORPHAN PAGES — "Scan now" (link graph)
       ======================================== */

    function initOrphansScan() {
        var btn = $('#tr-orphans-scan');
        if (!btn) return;

        btn.addEventListener('click', function () {
            if (btn.disabled) return;
            // The button holds an SVG + label, so save/restore innerHTML.
            var original = btn.innerHTML;
            btn.disabled = true;
            btn.textContent = (cfg.i18n && cfg.i18n.orphans_scanning) || 'Scanning...';

            function restore(message) {
                showToast(message, 'error');
                btn.disabled = false;
                btn.innerHTML = original;
            }

            ajaxPost('tam_rank_link_graph_scan')
                .then(function (res) {
                    if (res && res.success) {
                        // Keep the orphans tab active across the reload.
                        window.location.hash = 'orphans';
                        window.location.reload();
                    } else {
                        restore((res && res.data && res.data.message) ||
                            (cfg.i18n && cfg.i18n.orphans_scan_failed) || 'Scan failed. Try again.');
                    }
                })
                .catch(function () {
                    restore((cfg.i18n && cfg.i18n.orphans_scan_failed) || 'Scan failed. Try again.');
                });
        });
    }

    /* ========================================
       ORPHAN PAGES — ignore / restore a row
       ======================================== */

    function initOrphansIgnore() {
        var table = $('#tab-orphans .tr-audit-table');
        if (!table) return;

        var line     = $('#tr-orphans-ignored-line');
        var countEl  = $('#tr-orphans-ignored-count');
        var toggle   = $('#tr-orphans-toggle-ignored');
        var allclear = $('#tr-orphans-allclear');
        var revealed = false;

        // Single source of truth for the table's state: recount the rows and
        // let the counter line, the reveal and the all-clear row follow.
        function refresh() {
            var rows    = $$('.tr-orphan-row', table);
            var ignored = 0;

            rows.forEach(function (row) {
                var isIgnored = row.classList.contains('is-ignored');
                if (isIgnored) ignored++;
                row.hidden = isIgnored && !revealed;
            });

            if (ignored === 0 && revealed) {
                revealed = false; // nothing left to reveal
            }
            if (allclear) allclear.hidden = (rows.length - ignored) > 0;
            if (line) line.hidden = ignored === 0;
            if (countEl) {
                countEl.textContent = ((i18n.orphans_ignored_count || '%d ignored') + '')
                    .replace('%d', ignored);
            }
            if (toggle) {
                toggle.textContent = revealed
                    ? (i18n.orphans_hide_ignored || 'hide')
                    : (i18n.orphans_show_ignored || 'show');
                toggle.setAttribute('aria-expanded', revealed ? 'true' : 'false');
            }
        }

        if (toggle) {
            toggle.addEventListener('click', function () {
                revealed = !revealed;
                refresh();
            });
        }

        table.addEventListener('click', function (e) {
            var btn = e.target.closest ? e.target.closest('.tr-orphan-ignore') : null;
            if (!btn || btn.disabled) return;

            var row     = btn.closest('.tr-orphan-row');
            var postId  = btn.getAttribute('data-post-id');
            var ignore  = btn.getAttribute('data-ignored') !== '1';
            var label   = btn.textContent;

            btn.disabled = true;

            function fail() {
                btn.disabled    = false;
                btn.textContent = label;
                showToast(i18n.orphans_ignore_failed || 'Could not save that. Try again.', 'error');
            }

            ajaxPost('tam_rank_link_graph_ignore', { post_id: postId, ignore: ignore ? '1' : '0' })
                .then(function (res) {
                    if (!res || !res.success) { fail(); return; }
                    btn.disabled = false;
                    btn.setAttribute('data-ignored', ignore ? '1' : '0');
                    btn.textContent = ignore
                        ? (i18n.orphans_restore || 'Restore')
                        : (i18n.orphans_ignore || 'Ignore');
                    if (row) row.classList.toggle('is-ignored', ignore);
                    refresh();
                })
                .catch(fail);
        });

        refresh();
    }

    /* ========================================
       INIT
       ======================================== */

    function init() {
        initTabs();
        initFilterPills();
        initScanButtons();
        initTools();
        initExclusionPanel();
        initScoreReveal();
        initOrphansScan();
        initOrphansIgnore();
        // Detail expand, Bulk Meta editor + AI, CSV export and report moved to
        // the tam-rank-pro add-on (cluster-13 strip); PRO inits them from
        // tamrank-audit-pro.js when seo_audit is licensed.
    }

    // Run when DOM is ready
    if (document.readyState === 'loading') {
        document.addEventListener('DOMContentLoaded', init);
    } else {
        init();
    }

})();
