Instagram Reels ++

Full-screen reels viewer with max quality, anti-pause, and instant-load scrolling.

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Greasemonkey 油猴子Violentmonkey 暴力猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Violentmonkey 暴力猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Userscripts ,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展后才能安装此脚本。

(我已经安装了用户脚本管理器,让我安装!)

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

(我已经安装了用户样式管理器,让我安装!)

// ==UserScript==
// @name         Instagram Reels ++
// @namespace    http://tampermonkey.net/
// @version      3.3.0
// @description  Full-screen reels viewer with max quality, anti-pause, and instant-load scrolling.
// @author       Kristijan1001
// @match        https://www.instagram.com/*
// @icon         https://www.google.com/s2/favicons?sz=64&domain=instagram.com
// @grant        none
// @license      MIT
// ==/UserScript==

(function() {
    'use strict';

    class InstagramFeed {
        constructor() {
            this.activePost = { element: null };
            this.activeDisplayedMedia = { element: null, placeholder: null, isClone: false };
            this.isActive = false;
            this.isNavigating = false;
            this.isWaitingForModal = false;
            this.container = null;
            this.uiElements = {};
            this.modalObserver = null;
            this.savedVolume = Math.min(1, Math.max(0, parseFloat(localStorage.getItem('igreels_volume')) || 0.7));
            this.savedMuted = localStorage.getItem('igreels_muted') === 'true';
            this.savedPlaybackRate = parseFloat(localStorage.getItem('igreels_playbackRate')) || 1.0;
            this.autoScrollDelay = parseInt(localStorage.getItem('igreels_autoScrollDelay') || '0', 10);
            this.skipCarouselMode = localStorage.getItem('igreels_skipCarousel') === 'true';
            this.autoScrollTimeoutId = null;
            this.videoEndedListener = null;
            this.boundHandleKeydown = this.handleKeydown.bind(this);
            this.isProcessingInteraction = false;
            this.userIntendedPause = false;
        }

        /* -------------------- IMPROVED MAX QUALITY LOGIC -------------------- */

        getHighQualityUrl(imgElement) {
            let bestUrl = imgElement.src;

            // 1. Check srcset for the widest available candidate
            if (imgElement.srcset) {
                const candidates = imgElement.srcset.split(',').map(s => {
                    const parts = s.trim().split(/\s+/);
                    return {
                        url: parts[0],
                        width: parts[1] ? parseInt(parts[1].replace('w', '')) : 0
                    };
                });
                candidates.sort((a, b) => b.width - a.width);
                if (candidates.length > 0) {
                    bestUrl = candidates[0].url;
                }
            }

            // 2. Aggressive URL Cleaning
            try {
                const urlObj = new URL(bestUrl);
                const cleanedPath = urlObj.pathname.replace(/\/([sp]\d+x\d+|e\d+)\//g, '/');
                if (cleanedPath !== urlObj.pathname) {
                    urlObj.pathname = cleanedPath;
                    return urlObj.toString();
                }
            } catch (e) { /* ignore */ }

            return bestUrl;
        }

        /* -------------------- CORE LOGIC -------------------- */

        setupWheelListener() {
            this.removeWheelListener();
            this.boundHandleWheel = this.handleWheel.bind(this);
            document.addEventListener('wheel', this.boundHandleWheel, { passive: false, capture: true });
        }

        removeWheelListener() {
            if (this.boundHandleWheel) {
                document.removeEventListener('wheel', this.boundHandleWheel, { capture: true });
                this.boundHandleWheel = null;
            }
        }

        handleWheel(e) {
            if (!this.isActive) return;

            if (e.target.closest('.video-controls-overlay') || e.target.closest('#igreels-autoscroll-menu')) {
                return;
            }

            e.preventDefault();
            e.stopPropagation();

            const now = Date.now();
            if (now - (this.lastWheelTime || 0) < 300) return;
            this.lastWheelTime = now;

            if (this.skipCarouselMode) {
                if (e.deltaY > 0) {
                    this.smartNavigate('next');
                } else {
                    this.smartNavigate('prev');
                }
                return;
            }

            const mediaContainer = this.activePost.element?.firstElementChild;
            if (e.deltaY > 0) {
                const hasNextMedia = mediaContainer?.querySelector('button[aria-label="Next"]');
                if (hasNextMedia) {
                    this.navigateMedia('next');
                } else {
                    this.smartNavigate('next');
                }
            } else {
                const hasPrevMedia = mediaContainer?.querySelector('button[aria-label="Go back"]');
                if (hasPrevMedia) {
                    this.navigateMedia('prev');
                } else {
                    this.smartNavigate('prev');
                }
            }
        }

        sleep(ms) { return new Promise(res => setTimeout(res, ms)); }

        intersectionArea(a, b) {
            const xOverlap = Math.max(0, Math.min(a.right, b.right) - Math.max(a.left, b.left));
            const yOverlap = Math.max(0, Math.min(a.bottom, b.bottom) - Math.max(a.top, b.top));
            return xOverlap * yOverlap;
        }

        extractBackgroundImageUrl(styleStr) {
            if (!styleStr || styleStr === 'none') return null;
            const m = /url\((['"]?)(.*?)\1\)/.exec(styleStr);
            return m ? m[2] : null;
        }

        async waitForImageToLoad(imgEl, timeout = 2000) {
            try {
                if (imgEl.complete && imgEl.naturalWidth > 0) return true;
                let ok = false;
                const race = new Promise((resolve) => {
                    const onload = () => { ok = true; cleanup(); resolve(true); };
                    const onerror = () => { cleanup(); resolve(false); };
                    const cleanup = () => { imgEl.removeEventListener('load', onload); imgEl.removeEventListener('error', onerror); };
                    imgEl.addEventListener('load', onload);
                    imgEl.addEventListener('error', onerror);
                    if (imgEl.decode) {
                        imgEl.decode().then(() => { ok = true; cleanup(); resolve(true); }).catch(()=>{ /* ignore */ });
                    }
                });
                const timer = new Promise(res => setTimeout(res, timeout, false));
                return await Promise.race([race, timer]) || ok;
            } catch (e) {
                return false;
            }
        }

        async waitForVideoReady(videoEl, timeout = 2000) {
            const HAVE_ENOUGH = 4;
            if (videoEl.readyState >= HAVE_ENOUGH) return true;
            return new Promise((resolve) => {
                const oncan = () => { cleanup(); resolve(true); };
                const onerr = () => { cleanup(); resolve(false); };
                const cleanup = () => { videoEl.removeEventListener('canplay', oncan); videoEl.removeEventListener('error', onerr); };
                videoEl.addEventListener('canplay', oncan);
                videoEl.addEventListener('error', onerr);
                setTimeout(() => { cleanup(); resolve(videoEl.readyState >= HAVE_ENOUGH); }, timeout);
            });
        }

        init() {
            if ('scrollRestoration' in history) {
                history.scrollRestoration = 'manual';
            }
            console.log('📸 IG Max Quality Reels Initializing...');
            document.removeEventListener('keydown', this.boundHandleKeydown, { capture: true });
            document.addEventListener('keydown', this.boundHandleKeydown, { capture: true });
            const setupTrigger = () => {
                const oldTrigger = document.getElementById('ig-reels-trigger');
                if (oldTrigger) oldTrigger.remove();
                this.addManualTrigger();
            };
            setTimeout(setupTrigger, 2000);
            this.setupUrlChangeObserver(setupTrigger);
            this.injectStyles();
        }

        injectStyles() {
            const css = `
                #ig-feed-container { overflow: hidden !important; }
                .igreels-controls-column { position: absolute; right: 20px; bottom: 100px; display: flex; flex-direction: column; gap: 14px; z-index: 1000002; align-items: center; pointer-events: auto; }
                .igreels-btn { background: rgba(255,255,255,0.2); border: none; border-radius: 50%; width: 45px; height: 45px; font-size: 20px; color: white; display: flex; align-items: center; justify-content: center; cursor: pointer; backdrop-filter: blur(10px); box-shadow: 0 2px 10px rgba(0,0,0,0.3); transition: all 0.3s ease; }
                .custom-video-container input[type="range"]::-webkit-slider-thumb { -webkit-appearance: none; appearance: none; width: 12px; height: 12px; border-radius: 50%; background: #f09433; cursor: pointer; box-shadow: 0 2px 4px rgba(0,0,0,0.3); }
                .custom-video-container input[type="range"]::-moz-range-thumb { width: 12px; height: 12px; border-radius: 50%; background: #f09433; cursor: pointer; border: none; box-shadow: 0 2px 4px rgba(0,0,0,0.3); }
                .video-controls-overlay:hover .progress-fill .progress-thumb { opacity: 1; }
                .custom-video-container:hover .video-controls-overlay { opacity: 1; }
                @keyframes pulse-ring { 0% { transform: scale(0.95); opacity: 1; } 50% { transform: scale(1.05); opacity: 0.7; } 100% { transform: scale(1.15); opacity: 0; } }
                @keyframes pulse-rect { 0% { transform: scale(0.98); opacity: 1; } 50% { transform: scale(1.02); opacity: 0.7; } 100% { transform: scale(1.06); opacity: 0; } }
                @keyframes heart-beat { 0%, 100% { transform: scale(1); } 25% { transform: scale(1.2); } 50% { transform: scale(1.1); } 75% { transform: scale(1.25); } }
                @keyframes float-up { 0% { transform: translateY(0) scale(1); opacity: 1; } 100% { transform: translateY(-8px) scale(1.1); opacity: 0; } }
                @keyframes float-down { 0% { transform: translateY(0) scale(1); opacity: 1; } 100% { transform: translateY(8px) scale(1.1); opacity: 0; } }
                @keyframes bookmark-fill { 0%, 100% { transform: scale(1) rotateZ(0deg); } 50% { transform: scale(1.2) rotateZ(-5deg); } }
                @keyframes exit-shake { 0%, 100% { transform: translateX(0) rotate(0deg); } 25% { transform: translateX(-3px) rotate(-5deg); } 75% { transform: translateX(3px) rotate(5deg); } }
                .fancy-exit-btn { position: relative; }
                .fancy-exit-btn::before { content: ''; position: absolute; inset: 0; border-radius: 16px; background: radial-gradient(circle at center, rgba(255,255,255,0.3) 0%, transparent 70%); opacity: 0; transition: opacity 0.4s ease; pointer-events: none; z-index: 1; }
                .fancy-exit-btn:hover::before { opacity: 1; }
                .fancy-exit-btn:hover { transform: translateY(-3px) scale(1.05); background: linear-gradient(135deg, rgba(239, 68, 68, 0.5) 0%, rgba(220, 38, 38, 0.5) 100%) !important; border-color: rgba(239, 68, 68, 0.9) !important; box-shadow: 0 12px 40px rgba(239, 68, 68, 0.5), 0 0 30px rgba(239, 68, 68, 0.3) inset !important; }
                .fancy-exit-btn:hover svg { animation: exit-shake 0.5s ease; }
                .fancy-exit-btn:hover .exit-pulse { animation: pulse-rect 1s cubic-bezier(0.4, 0, 0.6, 1) infinite !important; }
                .fancy-exit-btn:active { transform: translateY(-1px) scale(1.02); transition: all 0.1s ease; }
                .fancy-action-btn { position: relative; }
                .fancy-action-btn::before { content: ''; position: absolute; inset: 0; border-radius: 50%; background: radial-gradient(circle at center, rgba(255,255,255,0.3) 0%, transparent 70%); opacity: 0; transition: opacity 0.4s ease; pointer-events: none; z-index: 1; }
                .fancy-action-btn:hover::before { opacity: 1; }
                .fancy-action-btn:hover { transform: translateY(-4px) scale(1.08); }
                .fancy-action-btn:hover .like-icon, .fancy-action-btn:hover .save-icon, .fancy-action-btn:hover .follow-icon, .fancy-action-btn:hover .arrow-icon { transform: scale(1.15); }
                .fancy-action-btn:active { transform: translateY(-2px) scale(1.02); transition: all 0.1s ease; }
                #igreels-like:hover .pulse-ring { animation: pulse-ring 1s cubic-bezier(0.4, 0, 0.6, 1) infinite !important; }
                #igreels-prev:hover .arrow-icon { animation: float-up 0.6s ease infinite; }
                #igreels-next:hover .arrow-icon { animation: float-down 0.6s ease infinite; }
                .igreels-liked .heart-path { fill: #ff306c !important; stroke: #ff306c !important; animation: heart-beat 0.6s cubic-bezier(0.34, 1.56, 0.64, 1); transform-origin: center; }
                .igreels-liked { background: linear-gradient(135deg, rgba(255, 48, 108, 0.5) 0%, rgba(237, 29, 82, 0.5) 100%) !important; border-color: rgba(255, 48, 108, 0.8) !important; box-shadow: 0 12px 40px rgba(255, 48, 108, 0.5), 0 0 30px rgba(255, 48, 108, 0.3) inset !important; }
                .igreels-bookmarked .bookmark-path { fill: #ffc107 !important; stroke: #ffc107 !important; animation: bookmark-fill 0.6s cubic-bezier(0.34, 1.56, 0.64, 1); transform-origin: center; }
                .igreels-bookmarked { background: linear-gradient(135deg, rgba(255, 193, 7, 0.5) 0%, rgba(255, 152, 0, 0.5) 100%) !important; border-color: rgba(255, 193, 7, 0.8) !important; box-shadow: 0 12px 40px rgba(255, 193, 7, 0.5), 0 0 30px rgba(255, 193, 7, 0.3) inset !important; }
                .igreels-following .follow-plus-v, .igreels-following .follow-plus-h { opacity: 0; transform: scale(0); }
                .igreels-following { background: linear-gradient(135deg, rgba(131, 58, 180, 0.5) 0%, rgba(195, 42, 163, 0.5) 100%) !important; border-color: rgba(131, 58, 180, 0.8) !important; box-shadow: 0 12px 40px rgba(131, 58, 180, 0.5), 0 0 30px rgba(131, 58, 180, 0.3) inset !important; }
                .igreels-following::after { content: '✓'; position: absolute; top: 50%; right: -4px; transform: translate(0, -50%); font-size: 14px; color: white; font-weight: bold; z-index: 3; text-shadow: 0 2px 8px rgba(0,0,0,0.4); }
                .custom-video-container button:hover { background: rgba(255,255,255,0.25) !important; border-color: rgba(255,255,255,0.4) !important; transform: scale(1.1); box-shadow: 0 6px 20px rgba(0,0,0,0.4) !important; }
                .custom-video-container button:active { transform: scale(0.95); }
                .custom-video-container button::before { content: ''; position: absolute; inset: 0; border-radius: 50%; background: radial-gradient(circle, rgba(255,255,255,0.3) 0%, transparent 70%); opacity: 0; transition: opacity 0.3s ease; pointer-events: none; }
                .custom-video-container button:hover::before { opacity: 1; }
            `;
            const s = document.createElement('style');
            s.type = 'text/css';
            s.id = 'igreels-styles';
            s.appendChild(document.createTextNode(css));
            document.head.appendChild(s);
        }

        setupUrlChangeObserver(callback) {
            let lastUrl = location.href;
            new MutationObserver(() => {
                const url = location.href;
                if (url !== lastUrl) {
                    lastUrl = url;
                    setTimeout(callback, 1000);
                }
            }).observe(document.body, { subtree: true, childList: true });
        }

        addManualTrigger() {
            if (document.getElementById('ig-reels-trigger')) return;
            const trigger = document.createElement('div');
            trigger.id = 'ig-reels-trigger';
            trigger.innerHTML = `
                <div class="trigger-icon">
                    <svg width="18" height="18" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
                        <path d="M19.59 10.59L12 3l-7.59 7.59-1.42-1.41L12 0l8.99 9-1.4 1.59z" fill="currentColor"/>
                        <path d="M12 3v18M3 12h18" stroke="currentColor" stroke-width="2" stroke-linecap="round"/>
                    </svg>
                </div>
                <div class="trigger-content">
                    <div class="trigger-title">IG Max</div>
                    <div class="trigger-subtitle">Press X</div>
                </div>
            `;

            trigger.style.cssText = `
                position: fixed; top: 20px; right: 20px; z-index: 1000000; display: flex; align-items: center; gap: 12px; padding: 14px 20px;
                background: linear-gradient(135deg, rgba(15, 15, 15, 0.95) 0%, rgba(30, 30, 30, 0.95) 100%);
                border: 1px solid rgba(255, 0, 80, 0.3); border-radius: 16px; cursor: pointer; user-select: none;
                box-shadow: 0 8px 32px rgba(0, 0, 0, 0.6), 0 0 0 1px rgba(255, 255, 255, 0.05) inset, 0 0 20px rgba(255, 0, 80, 0.15);
                backdrop-filter: blur(20px) saturate(180%); -webkit-backdrop-filter: blur(20px) saturate(180%);
                transition: all 0.4s cubic-bezier(0.34, 1.56, 0.64, 1); transform: translateY(0) scale(1); opacity: 1;
            `;

            const style = document.createElement('style');
            style.textContent = `
                #ig-reels-trigger { animation: slideInDown 0.5s cubic-bezier(0.34, 1.56, 0.64, 1); }
                #ig-reels-trigger .trigger-icon { width: 42px; height: 42px; display: flex; align-items: center; justify-content: center; background: linear-gradient(135deg, #ff0050 0%, #ff4081 100%); border-radius: 10px; flex-shrink: 0; box-shadow: 0 4px 16px rgba(255, 0, 80, 0.4), 0 0 0 1px rgba(255, 255, 255, 0.1) inset; transition: all 0.3s ease; }
                #ig-reels-trigger .trigger-icon svg { color: white; width: 22px; height: 22px; animation: iconPulse 2.5s ease-in-out infinite; }
                #ig-reels-trigger .trigger-content { display: flex; flex-direction: column; gap: 1px; }
                #ig-reels-trigger .trigger-title { color: #ffffff; font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif; font-size: 15px; font-weight: 700; letter-spacing: 0.5px; line-height: 1.2; }
                #ig-reels-trigger .trigger-subtitle { color: rgba(255, 255, 255, 0.55); font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif; font-size: 11px; font-weight: 500; letter-spacing: 0.3px; }
                #ig-reels-trigger:hover { transform: translateY(-3px) scale(1.02); border-color: rgba(255, 0, 80, 0.5); box-shadow: 0 10px 32px rgba(0, 0, 0, 0.6), 0 0 0 1px rgba(255, 255, 255, 0.1) inset, 0 0 25px rgba(255, 0, 80, 0.25); }
                #ig-reels-trigger:hover .trigger-icon { transform: scale(1.08) rotate(5deg); box-shadow: 0 5px 16px rgba(255, 0, 80, 0.5), 0 0 0 1px rgba(255, 255, 255, 0.2) inset; }
                #ig-reels-trigger:hover .trigger-icon svg { animation: iconSpin 0.5s cubic-bezier(0.34, 1.56, 0.64, 1); }
                #ig-reels-trigger:active { transform: translateY(-1px) scale(0.98); transition: all 0.1s ease; }
                #ig-reels-trigger::before { content: ''; position: absolute; inset: -2px; background: linear-gradient(135deg, #ff0050, #ff4081, #ff0050); border-radius: 14px; opacity: 0; transition: opacity 0.3s ease; z-index: -1; filter: blur(8px); }
                #ig-reels-trigger:hover::before { opacity: 0.25; animation: gradientRotate 2s linear infinite; }
                @keyframes slideInDown { from { opacity: 0; transform: translateY(-30px) scale(0.9); } to { opacity: 1; transform: translateY(0) scale(1); } }
                @keyframes iconPulse { 0%, 100% { transform: scale(1); opacity: 1; } 50% { transform: scale(1.05); opacity: 0.9; } }
                @keyframes iconSpin { from { transform: rotate(0deg) scale(1); } to { transform: rotate(360deg) scale(1.08); } }
                @keyframes gradientRotate { 0% { background-position: 0% 50%; } 50% { background-position: 100% 50%; } 100% { background-position: 0% 50%; } }
                @media (max-width: 768px) { #ig-reels-trigger { top: 12px; right: 12px; padding: 8px 12px; gap: 8px; } #ig-reels-trigger .trigger-icon { width: 32px; height: 32px; } #ig-reels-trigger .trigger-icon svg { width: 16px; height: 16px; } #ig-reels-trigger .trigger-title { font-size: 12px; } #ig-reels-trigger .trigger-subtitle { font-size: 9px; } }
            `;
            if (!document.getElementById('ig-reels-pulse-style')) {
                style.id = 'ig-reels-pulse-style';
                document.head.appendChild(style);
            }

            trigger.addEventListener('click', (e) => { e.stopPropagation(); this.armFeedStart(); });
            document.body.appendChild(trigger);
        }

        armFeedStart() {
            if (this.isActive || this.isWaitingForModal) return;
            const existing = this.getCurrentArticle();
            if (existing) {
                this.startFeed(existing);
                return;
            }
            const isBookmarksPage = window.location.pathname.includes('/saved/');
            if (!isBookmarksPage) {
                console.warn('No posts found on the page');
                return;
            }
            this.isWaitingForModal = true;
            const trigger = document.getElementById('ig-reels-trigger');
            if (trigger) {
                const subtitle = trigger.querySelector('.trigger-subtitle');
                if(subtitle) subtitle.textContent = "Click a post...";
            }
            this.modalObserver = new MutationObserver((mutations) => {
                for (const mutation of mutations) {
                    for (const node of mutation.addedNodes) {
                        if (node.nodeType === 1 && node.querySelector('div[role="dialog"] article')) {
                            this.startFeed(node.querySelector('div[role="dialog"] article'));
                            return;
                        }
                    }
                }
            });
            this.modalObserver.observe(document.body, { childList: true, subtree: true });
        }

        getCurrentArticle() {
            const modalArticle = document.querySelector('div[role="dialog"] article');
            if (modalArticle) return modalArticle;
            return this.findCentralArticle();
        }

        findCentralArticle() {
            const allArticles = Array.from(document.querySelectorAll('article'));
            if (allArticles.length === 0) return null;
            const viewportHeight = window.innerHeight;
            const viewportCenter = viewportHeight / 2;
            let closestArticle = null;
            let minDistance = Infinity;
            for (const article of allArticles) {
                if (!this.isValidArticle(article)) continue;
                const rect = article.getBoundingClientRect();
                if (rect.bottom > 0 && rect.top < viewportHeight) {
                    const articleCenter = rect.top + rect.height / 2;
                    const distance = Math.abs(viewportCenter - articleCenter);
                    if (distance < minDistance) {
                        minDistance = distance;
                        closestArticle = article;
                    }
                }
            }
            return closestArticle;
        }

        startFeed(initialPostElement) {
            if (this.isWaitingForModal) {
                this.isWaitingForModal = false;
                if (this.modalObserver) this.modalObserver.disconnect();
            }
            console.log('🚀 Starting Max Quality Feed Mode...');
            this.isActive = true;
            this.setupWheelListener();
            const trig = document.getElementById('ig-reels-trigger');
            if (trig) trig.style.display = 'none';
            this.createContainer();
            this.updateView(initialPostElement);
        }

        exit() {
            if (!this.isActive) return;
            console.log('👋 Exiting Feed Mode...');
            this.isActive = false;
            this.isProcessingInteraction = false;
            this.stopAutoScrollTimer();
            this.removeWheelListener();
            this.restoreOriginalMediaPosition();
            if (this.container) this.container.remove();
            this.container = null;
            const closeButton = document.querySelector('div[role="dialog"] svg[aria-label="Close"]')?.closest('div[role="button"]');
            if (closeButton) closeButton.click();
            setTimeout(() => {
                const trigger = document.getElementById('ig-reels-trigger');
                if (trigger) {
                    trigger.style.display = 'flex';
                    const subtitle = trigger.querySelector('.trigger-subtitle');
                    if(subtitle) subtitle.textContent = "Press X";
                } else {
                    this.addManualTrigger();
                }
            }, 50);
        }

        isValidArticle(article) {
            if (!article) return false;
            const hasMedia = article.querySelector('video, img[src*="cdninstagram"], div[style*="background-image"]');
            if (!hasMedia) return false;
            const hasSuggestedText = article.textContent.includes('Suggested for you');
            const hasCloseButton = article.querySelector('svg[aria-label="Close"]');
            if (hasSuggestedText && hasCloseButton) {
                const rect = article.getBoundingClientRect();
                if (rect.height < 200) return false;
            }
            const rect = article.getBoundingClientRect();
            if (rect.height < 100) return false;
            article.dataset.isSuggested = hasSuggestedText ? 'true' : 'false';
            return true;
        }

        createContainer() {
            this.container = document.createElement('div');
            this.container.id = 'ig-feed-container';
            this.container.style.cssText = `position: fixed; top: 0; left: 0; width: 100vw; height: 100vh; background: rgba(0, 0, 0, 0.95); z-index: 2147483647; pointer-events: none; overflow: hidden;`;
            this.container.innerHTML = `
                <div class="media-wrapper" style="position: absolute; top: 0; left: 0; width: 100%; height: 100%; display: flex; align-items: center; justify-content: center; pointer-events: auto; overflow: hidden;"></div>
                <div class="ui-container" style="position: relative; z-index: 1000002; width: 100%; height: 100%; pointer-events: none;">
                    <div style="position: absolute; top: 20px; left: 20px; display: flex; flex-direction: column; align-items: flex-start; gap: 5px; pointer-events: auto;">
                        <div class="info-controls-wrapper" style="color: rgba(255,255,255,0.9); background: rgba(0,0,0,0.6); padding: 6px 10px; border-radius: 15px; font-size: 12px; backdrop-filter: blur(10px); pointer-events: auto; transition: all 0.3s ease;">
                            <div class="info-header" style="color: white; cursor: pointer; text-align: left; display: flex; align-items: center; justify-content: flex-start; gap: 5px;">
                                Keyboard Shortcuts
                                <span style="display: inline-block; width: 12px; height: 12px; background-image: url('data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D%2224%22%20height%3D%2224%22%20viewBox%3D%220%200%2024%2024%22%20fill%3D%22none%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E%0A%3Cpath%20d%3D%22M7.41%208.59L12%2013.17L16.59%208.59L18%2010L12%2016L6%2010L7.41%208.59Z%22%20fill%3D%22%23f09433%22%2F%3E%0A%3C%2Fsvg%3E'); background-repeat: no-repeat; background-position: center; background-size: contain; transform: rotate(0deg); transition: transform 0.3s ease-out;"></span>
                            </div>
                            <div class="controls-expanded" style="max-height: 0; overflow: hidden; opacity: 0; transition: max-height 0.3s ease-out, opacity 0.3s ease-out; padding-top: 0; font-weight: 400;">
                                • X: <span style="color:#f09433;">Enter/Exit Feed</span> <br>
                                • Scroll: <span style="color:#f09433;">⬆️/⬇️</span> <br>
                                • Cycle Media: <span style="color:#f09433;">⬅️/➡️</span> <br>
                                • Space: <span style="color:#f09433;">Play/Pause</span> <br>
                                • &lt; / &gt; : <span style="color:#f09433;">Scrub ±5s</span> <br>
                                • L: <span style="color:#f09433;">Like</span> <br>
                                • S: <span style="color:#f09433;">Save</span> <br>
                                • F: <span style="color:#f09433;">Follow</span> <br>
                                • Q/Esc: <span style="color:#f09433;">Exit</span>
                            </div>
                        </div>
                    </div>
                    <div style="position: absolute; top: 20px; right: 20px; display: flex; flex-direction: column; align-items: flex-end; gap: 8px; pointer-events: auto;">
                        <button id="igreels-exit" class="igreels-btn igreels-exit fancy-exit-btn" style="background: linear-gradient(135deg, rgba(239, 68, 68, 0.3) 0%, rgba(220, 38, 38, 0.3) 100%); border: 1px solid rgba(239, 68, 68, 0.6); padding: 10px 16px; border-radius: 16px; width: auto; height: auto; font-size: 13px; font-weight: 700; backdrop-filter: blur(20px) saturate(180%); box-shadow: 0 8px 32px rgba(239, 68, 68, 0.35), 0 0 20px rgba(239, 68, 68, 0.15) inset; transition: all 0.4s cubic-bezier(0.34, 1.56, 0.64, 1); display: flex; align-items: center; gap: 8px; position: relative; overflow: hidden;" title="Exit (Q/Esc)">
                            <svg width="16" height="16" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg" style="transition: all 0.3s ease;">
                                <path d="M18 6L6 18M6 6l12 12" stroke="white" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round" style="filter: drop-shadow(0 2px 4px rgba(0,0,0,0.4));"/>
                            </svg>
                            <span style="position: relative; z-index: 2;">Exit</span>
                            <div class="exit-pulse" style="position: absolute; inset: -2px; border-radius: 16px; border: 2px solid rgba(239, 68, 68, 0.6); opacity: 0; animation: pulse-rect 2s cubic-bezier(0.4, 0, 0.6, 1) infinite;"></div>
                        </button>
                        <div style="color: white; background: rgba(0,0,0,0.6); padding: 8px 12px; border-radius: 15px; font-size: 12px; font-weight: 600; backdrop-filter: blur(10px); display: flex; align-items: center; gap: 8px; pointer-events: auto; cursor: pointer;" id="igreels-autoscroll-container">  <span>Auto: <span id="igreels-autoscroll-display" style="color: #f09433;">Off</span></span>  <span style="color: #f09433;">▼</span></div><div id="igreels-autoscroll-menu" style="display: none; position: absolute; top: 90px; right: 20px; background: rgba(0,0,0,0.9); border-radius: 10px; padding: 8px; backdrop-filter: blur(10px); pointer-events: auto; z-index: 10000000;">  <div class="autoscroll-option" data-value="0" style="padding: 8px 16px; cursor: pointer; color: #f09433; border-radius: 5px; transition: background 0.2s;">Off</div>  <div class="autoscroll-option" data-value="-1" style="padding: 8px 16px; cursor: pointer; color: white; border-radius: 5px; transition: background 0.2s;">Auto (Smart)</div>  <div class="autoscroll-option" data-value="1000" style="padding: 8px 16px; cursor: pointer; color: white; border-radius: 5px; transition: background 0.2s;">1s</div>  <div class="autoscroll-option" data-value="2000" style="padding: 8px 16px; cursor: pointer; color: white; border-radius: 5px; transition: background 0.2s;">2s</div>  <div class="autoscroll-option" data-value="3000" style="padding: 8px 16px; cursor: pointer; color: white; border-radius: 5px; transition: background 0.2s;">3s</div>  <div class="autoscroll-option" data-value="5000" style="padding: 8px 16px; cursor: pointer; color: white; border-radius: 5px; transition: background 0.2s;">5s</div>  <div class="autoscroll-option" data-value="8000" style="padding: 8px 16px; cursor: pointer; color: white; border-radius: 5px; transition: background 0.2s;">8s</div>  <div class="autoscroll-option" data-value="30000" style="padding: 8px 16px; cursor: pointer; color: white; border-radius: 5px; transition: background 0.2s;">30s</div>  <div class="autoscroll-option" data-value="60000" style="padding: 8px 16px; cursor: pointer; color: white; border-radius: 5px; transition: background 0.2s;">60s</div></div>
                        <div style="color: white; background: rgba(0,0,0,0.6); padding: 8px 12px; border-radius: 15px; font-size: 12px; font-weight: 600; backdrop-filter: blur(10px); display: flex; align-items: center; gap: 8px; pointer-events: auto; cursor: pointer;">
                            <input type="checkbox" id="igreels-skip-media" style="cursor: pointer; width: 16px; height: 16px; accent-color: #f09433;">
                            <label for="igreels-skip-media" style="cursor: pointer; user-select: none;">Skip carousel</label>
                        </div>
                    </div>
                    <div class="info" style="position: absolute; bottom: 75px; left: 20px; right: 100px; color: white; background: rgba(0,0,0,0.0); padding: 20px; border-radius: 16px; max-height: 120px; overflow-y: hidden; text-shadow: 1px 1px 4px rgba(0,0,0,0.8); word-wrap: break-word; overflow-wrap: break-word; white-space: normal; pointer-events: auto;"></div>
                </div>
            `;
            const controls = document.createElement('div');
            controls.className = 'igreels-controls-column';
            controls.innerHTML = `
                <button id="igreels-like" class="igreels-btn fancy-action-btn" style="background: linear-gradient(135deg, rgba(255, 48, 108, 0.25) 0%, rgba(237, 29, 82, 0.25) 100%); border: 1px solid rgba(255, 48, 108, 0.5); border-radius: 50%; width: 54px; height: 54px; cursor: pointer; backdrop-filter: blur(20px) saturate(180%); box-shadow: 0 8px 32px rgba(255, 48, 108, 0.35), 0 0 20px rgba(255, 48, 108, 0.2) inset; transition: all 0.5s cubic-bezier(0.34, 1.56, 0.64, 1); display: flex; align-items: center; justify-content: center; position: relative; overflow: visible;" title="Like (L)">
                    <svg width="26" height="26" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg" class="like-icon" style="position: relative; z-index: 2; transition: all 0.4s cubic-bezier(0.34, 1.56, 0.64, 1); overflow: visible;">
                        <path class="heart-path" d="M12 21.35l-1.45-1.32C5.4 15.36 2 12.28 2 8.5 2 5.42 4.42 3 7.5 3c1.74 0 3.41.81 4.5 2.09C13.09 3.81 14.76 3 16.5 3 19.58 3 22 5.42 22 8.5c0 3.78-3.4 6.86-8.55 11.54L12 21.35z" fill="none" stroke="white" stroke-width="2" stroke-linejoin="round" style="filter: drop-shadow(0 2px 8px rgba(0,0,0,0.4)); transition: all 0.4s ease;"/>
                    </svg>
                    <div class="pulse-ring" style="position: absolute; inset: -2px; border-radius: 50%; border: 2px solid rgba(255, 48, 108, 0.6); opacity: 0; animation: pulse-ring 2s cubic-bezier(0.4, 0, 0.6, 1) infinite;"></div>
                </button>
                <button id="igreels-save" class="igreels-btn fancy-action-btn" style="background: linear-gradient(135deg, rgba(255, 193, 7, 0.25) 0%, rgba(255, 152, 0, 0.25) 100%); border: 1px solid rgba(255, 193, 7, 0.5); border-radius: 50%; width: 54px; height: 54px; cursor: pointer; backdrop-filter: blur(20px) saturate(180%); box-shadow: 0 8px 32px rgba(255, 193, 7, 0.35), 0 0 20px rgba(255, 193, 7, 0.2) inset; transition: all 0.5s cubic-bezier(0.34, 1.56, 0.64, 1); display: flex; align-items: center; justify-content: center; position: relative; overflow: visible;" title="Save (S)">
                    <svg width="26" height="26" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg" class="save-icon" style="position: relative; z-index: 2; transition: all 0.4s cubic-bezier(0.34, 1.56, 0.64, 1);">
                        <path class="bookmark-path" d="M17 3H7c-1.1 0-2 .9-2 2v16l7-3 7 3V5c0-1.1-.9-2-2-2z" fill="none" stroke="white" stroke-width="2" stroke-linejoin="round" style="filter: drop-shadow(0 2px 8px rgba(0,0,0,0.4)); transition: all 0.4s ease;"/>
                    </svg>
                    <div class="pulse-ring" style="position: absolute; inset: -2px; border-radius: 50%; border: 2px solid rgba(255, 193, 7, 0.6); opacity: 0; animation: pulse-ring 2s cubic-bezier(0.4, 0, 0.6, 1) infinite 0.3s;"></div>
                </button>
                <button id="igreels-follow" class="igreels-btn fancy-action-btn" style="background: linear-gradient(135deg, rgba(131, 58, 180, 0.25) 0%, rgba(195, 42, 163, 0.25) 100%); border: 1px solid rgba(131, 58, 180, 0.5); border-radius: 50%; width: 54px; height: 54px; cursor: pointer; backdrop-filter: blur(20px) saturate(180%); box-shadow: 0 8px 32px rgba(131, 58, 180, 0.35), 0 0 20px rgba(131, 58, 180, 0.2) inset; transition: all 0.5s cubic-bezier(0.34, 1.56, 0.64, 1); display: flex; align-items: center; justify-content: center; position: relative; overflow: visible;" title="Follow (F)">
                    <svg width="26" height="26" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg" class="follow-icon" style="position: relative; z-index: 2; transition: all 0.4s cubic-bezier(0.34, 1.56, 0.64, 1);">
                        <circle cx="12" cy="8" r="4" stroke="white" stroke-width="2" fill="none" style="filter: drop-shadow(0 2px 8px rgba(0,0,0,0.4));"/>
                        <path d="M6 21v-2a4 4 0 0 1 4-4h4a4 4 0 0 1 4 4v2" stroke="white" stroke-width="2" stroke-linecap="round" style="filter: drop-shadow(0 2px 8px rgba(0,0,0,0.4));"/>
                        <line x1="19" y1="8" x2="19" y2="14" stroke="white" stroke-width="2" stroke-linecap="round" class="follow-plus-v" style="filter: drop-shadow(0 2px 8px rgba(0,0,0,0.4)); transition: all 0.3s ease;"/>
                        <line x1="16" y1="11" x2="22" y2="11" stroke="white" stroke-width="2" stroke-linecap="round" class="follow-plus-h" style="filter: drop-shadow(0 2px 8px rgba(0,0,0,0.4)); transition: all 0.3s ease;"/>
                    </svg>
                    <div class="pulse-ring" style="position: absolute; inset: -2px; border-radius: 50%; border: 2px solid rgba(131, 58, 180, 0.6); opacity: 0; animation: pulse-ring 2s cubic-bezier(0.4, 0, 0.6, 1) infinite 0.6s;"></div>
                </button>
                <button id="igreels-prev" class="igreels-btn fancy-action-btn" style="background: linear-gradient(135deg, rgba(100, 150, 255, 0.25) 0%, rgba(70, 120, 255, 0.25) 100%); border: 1px solid rgba(100, 150, 255, 0.5); border-radius: 50%; width: 54px; height: 54px; cursor: pointer; backdrop-filter: blur(20px) saturate(180%); box-shadow: 0 8px 32px rgba(100, 150, 255, 0.35), 0 0 20px rgba(100, 150, 255, 0.2) inset; transition: all 0.5s cubic-bezier(0.34, 1.56, 0.64, 1); display: flex; align-items: center; justify-content: center; position: relative; overflow: visible;" title="Previous (↑)">
                    <svg width="26" height="26" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg" class="arrow-icon" style="position: relative; z-index: 2; transition: all 0.3s ease;">
                        <path d="M12 19V5M5 12l7-7 7 7" stroke="white" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round" style="filter: drop-shadow(0 2px 8px rgba(0,0,0,0.4));"/>
                    </svg>
                    <div class="pulse-ring" style="position: absolute; inset: -2px; border-radius: 50%; border: 2px solid rgba(100, 150, 255, 0.6); opacity: 0; animation: pulse-ring 2s cubic-bezier(0.4, 0, 0.6, 1) infinite 0.9s;"></div>
                </button>
                <button id="igreels-next" class="igreels-btn fancy-action-btn" style="background: linear-gradient(135deg, rgba(100, 150, 255, 0.25) 0%, rgba(70, 120, 255, 0.25) 100%); border: 1px solid rgba(100, 150, 255, 0.5); border-radius: 50%; width: 54px; height: 54px; cursor: pointer; backdrop-filter: blur(20px) saturate(180%); box-shadow: 0 8px 32px rgba(100, 150, 255, 0.35), 0 0 20px rgba(100, 150, 255, 0.2) inset; transition: all 0.5s cubic-bezier(0.34, 1.56, 0.64, 1); display: flex; align-items: center; justify-content: center; position: relative; overflow: visible;" title="Next (↓)">
                    <svg width="26" height="26" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg" class="arrow-icon" style="position: relative; z-index: 2; transition: all 0.3s ease;">
                        <path d="M12 5v14M5 12l7 7 7-7" stroke="white" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round" style="filter: drop-shadow(0 2px 8px rgba(0,0,0,0.4));"/>
                    </svg>
                    <div class="pulse-ring" style="position: absolute; inset: -2px; border-radius: 50%; border: 2px solid rgba(100, 150, 255, 0.6); opacity: 0; animation: pulse-ring 2s cubic-bezier(0.4, 0, 0.6, 1) infinite 1.2s;"></div>
                </button>
            `;
            this.container.querySelector('.ui-container').appendChild(controls);

            document.body.appendChild(this.container);
            this.uiElements = {
                mediaWrapper: this.container.querySelector('.media-wrapper'),
                info: this.container.querySelector('.info'),
                exitButton: this.container.querySelector('#igreels-exit'),
                prevButton: this.container.querySelector('#igreels-prev'),
                nextButton: this.container.querySelector('#igreels-next'),
                likeButton: this.container.querySelector('#igreels-like'),
                saveButton: this.container.querySelector('#igreels-save'),
                followButton: this.container.querySelector('#igreels-follow'),
            };
            this.uiElements.exitButton.addEventListener('click', (e) => { e.stopPropagation(); this.exit(); });
            this.uiElements.prevButton.addEventListener('click', (e) => { e.stopPropagation(); this.smartNavigate('prev'); });
            this.uiElements.nextButton.addEventListener('click', (e) => { e.stopPropagation(); this.smartNavigate('next'); });
            this.uiElements.likeButton.addEventListener('click', (e) => { e.stopPropagation(); this.toggleAction('like'); });
            this.uiElements.saveButton.addEventListener('click', (e) => { e.stopPropagation(); this.toggleAction('save'); });
            this.uiElements.followButton.addEventListener('click', (e) => { e.stopPropagation(); this.toggleFollow(); });
            this.setupKeyboardShortcutsToggle();
            this.setupSkipCarouselToggle();
            this.setupAutoScrollControls();
            for (const btn of Object.values(this.uiElements)) {
                if (btn && btn.addEventListener) {
                    btn.addEventListener('mousedown', (ev) => ev.preventDefault());
                }
            }
        }

        setupKeyboardShortcutsToggle() {
            const infoControlsWrapper = this.container.querySelector('.info-controls-wrapper');
            const controlsExpanded = this.container.querySelector('.controls-expanded');
            const infoHeader = this.container.querySelector('.info-header');
            const infoArrow = infoHeader.querySelector('span');
            let isHoveringInfo = false;
            let isInfoExpanded = false;
            let hideInfoTimeoutId = null;
            infoControlsWrapper.addEventListener('mouseenter', () => {
                isHoveringInfo = true;
                clearTimeout(hideInfoTimeoutId);
                if (!isInfoExpanded) {
                    controlsExpanded.style.maxHeight = '200px';
                    controlsExpanded.style.opacity = '1';
                    controlsExpanded.style.paddingTop = '8px';
                    infoArrow.style.transform = 'rotate(180deg)';
                    isInfoExpanded = true;
                }
            });
            infoControlsWrapper.addEventListener('mouseleave', () => {
                isHoveringInfo = false;
                hideInfoTimeoutId = setTimeout(() => {
                    if (!isHoveringInfo) {
                        controlsExpanded.style.maxHeight = '0';
                        controlsExpanded.style.opacity = '0';
                        controlsExpanded.style.paddingTop = '0';
                        infoArrow.style.transform = 'rotate(0deg)';
                        isInfoExpanded = false;
                    }
                }, 500);
            });
        }

        setupSkipCarouselToggle() {
            const checkbox = this.container.querySelector('#igreels-skip-media');
            if (checkbox) {
                checkbox.checked = this.skipCarouselMode;
                checkbox.addEventListener('change', (e) => {
                    this.skipCarouselMode = e.target.checked;
                    localStorage.setItem('igreels_skipCarousel', this.skipCarouselMode.toString());
                    console.log(`Skip carousel mode: ${this.skipCarouselMode ? 'ON' : 'OFF'}`);
                });
            }
        }

        setupAutoScrollControls() {
            const container = document.getElementById('igreels-autoscroll-container');
            const menu = document.getElementById('igreels-autoscroll-menu');
            const display = document.getElementById('igreels-autoscroll-display');

            const timeLabels = { 0: 'Off', '-1': 'Auto (Smart)', 1000: '1s', 2000: '2s', 3000: '3s', 5000: '5s', 8000: '8s', 30000: '30s', 60000: '60s' };
            display.textContent = timeLabels[this.autoScrollDelay] || 'Off';

            container.addEventListener('click', (e) => {
                e.stopPropagation();
                menu.style.display = menu.style.display === 'none' ? 'block' : 'none';
            });

            document.querySelectorAll('.autoscroll-option').forEach(option => {
                option.addEventListener('mouseenter', () => {
                    option.style.background = 'rgba(255,255,255,0.1)';
                });
                option.addEventListener('mouseleave', () => {
                    option.style.background = 'transparent';
                });
                option.addEventListener('click', (e) => {
                    e.stopPropagation();
                    const value = parseInt(option.dataset.value, 10);
                    this.autoScrollDelay = value;
                    localStorage.setItem('igreels_autoScrollDelay', value.toString());
                    display.textContent = timeLabels[value];
                    menu.style.display = 'none';

                    if (this.isActive && (value > 0 || value === -1)) {
                        this.startAutoScrollTimer();
                    } else if (value === 0) {
                        this.stopAutoScrollTimer();
                    }
                });
            });

            document.addEventListener('click', () => {
                if (menu) menu.style.display = 'none';
            });
        }

        startAutoScrollTimer() {
            this.stopAutoScrollTimer();
            if (!this.isActive || this.isProcessingInteraction) return;

            if (this.autoScrollDelay === -1) {
                if (this.skipCarouselMode) {
                    const video = this.uiElements.mediaWrapper.querySelector('video');
                    if (video) {
                        const onEnded = () => {
                            if (!this.isActive || this.isProcessingInteraction) return;
                            this.userIntendedPause = false; // Reset intent before auto-nav
                            this.navigatePost('next');
                        };
                        this.videoEndedListener = onEnded;
                        video.addEventListener('ended', onEnded);
                    } else {
                        this.autoScrollTimeoutId = setTimeout(() => {
                            if (!this.isActive || this.isProcessingInteraction) return;
                            this.navigatePost('next');
                        }, 3000);
                    }
                } else {
                    const video = this.uiElements.mediaWrapper.querySelector('video');
                    if (video) {
                        const onEnded = () => {
                            if (!this.isActive || this.isProcessingInteraction) return;
                            this.userIntendedPause = false;
                            this.smartNavigate('next');
                        };
                        this.videoEndedListener = onEnded;
                        video.addEventListener('ended', onEnded);
                    } else {
                        this.autoScrollTimeoutId = setTimeout(() => {
                            if (!this.isActive || this.isProcessingInteraction) return;
                            this.smartNavigate('next');
                        }, 3000);
                    }
                }
            } else if (this.autoScrollDelay > 0) {
                this.autoScrollTimeoutId = setTimeout(() => {
                    if (!this.isActive || this.isProcessingInteraction) return;
                    this.userIntendedPause = false;
                    if (this.skipCarouselMode) {
                        this.navigatePost('next');
                    } else {
                        this.smartNavigate('next');
                    }
                }, this.autoScrollDelay);
            }
        }

        stopAutoScrollTimer() {
            if (this.autoScrollTimeoutId) {
                clearTimeout(this.autoScrollTimeoutId);
                this.autoScrollTimeoutId = null;
            }
            if (this.videoEndedListener) {
                const video = this.uiElements?.mediaWrapper?.querySelector('video');
                if (video) {
                    video.removeEventListener('ended', this.videoEndedListener);
                }
                this.videoEndedListener = null;
            }
        }

        findCandidateMedia(article) {
            if (!article) return null;
            const articleRect = article.getBoundingClientRect();
            const candidates = [];
            const carouselContainer = article.querySelector('ul[style*="flex-direction"]') ||
                                    article.querySelector('div[style*="flex-direction"] ul') ||
                                     article.querySelector('div._ac7v');
            article.querySelectorAll('video, img').forEach(el => {
                const rect = el.getBoundingClientRect();
                if (rect.width < 12 || rect.height < 12) return;
                const alt = (el.alt || '').toLowerCase();
                const src = (el.src || '').toLowerCase();
                if (alt.includes('profile') || alt.includes('avatar') ||
                    src.includes('profile') || src.includes('avatar') ||
                    (rect.width <= 48 && rect.height <= 48)) {
                    return;
                }
                let carouselOrder = -1;
                if (carouselContainer) {
                    const carouselItems = Array.from(carouselContainer.querySelectorAll('li'));
                    for (let i = 0; i < carouselItems.length; i++) {
                        if (carouselItems[i].contains(el)) {
                            carouselOrder = i;
                            break;
                        }
                    }
                }
                const isInView = rect.top >= 0 && rect.left >= 0 &&
                    rect.bottom <= (window.innerHeight || document.documentElement.clientHeight) &&
                    rect.right <= (window.innerWidth || document.documentElement.clientWidth);
                candidates.push({
                    el,
                    rect,
                    kind: el.tagName.toLowerCase(),
                    isInView,
                    area: rect.width * rect.height,
                    carouselOrder
                });
            });

            article.querySelectorAll('*').forEach(el => {
                try {
                    const cs = getComputedStyle(el);
                    const bg = cs.backgroundImage;
                    if (bg && bg !== 'none') {
                        const rect = el.getBoundingClientRect();
                        if (rect.width >= 100 && rect.height >= 100) {
                            candidates.push({ el, rect, kind: 'background', bg, area: rect.width * rect.height, carouselOrder: -1 });
                        }
                    }
                } catch (e) { /* ignore */ }
            });

            if (candidates.length === 0) return null;

            let best = null;
            let bestScore = -Infinity;
            for (const c of candidates) {
                const intersectArea = this.intersectionArea(c.rect, articleRect);
                const centerDist = Math.hypot(
                    (c.rect.left + c.rect.right) / 2 - (articleRect.left + articleRect.right) / 2,
                    (c.rect.top + c.rect.bottom) / 2 - (articleRect.top + articleRect.bottom) / 2
                );
                let score = intersectArea - centerDist;
                if (c.isInView && c.carouselOrder >= 0) {
                    score += 50000 - (c.carouselOrder * 1000);
                } else if (c.isInView) {
                    score += 10000;
                }
                if (c.area > 50000) score += 2000;
                if (score > bestScore) {
                    bestScore = score;
                    best = c;
                }
            }
            return best ? best.el : null;
        }

        getMediaIdentifier(el) {
            if (!el) return null;
            if (el.tagName === 'IMG') return el.currentSrc || el.src || el.getAttribute('src') || el.getAttribute('data-src') || null;
            if (el.tagName === 'VIDEO') return el.currentSrc || el.src || (el.querySelector('source')?.src) || null;
            const bg = getComputedStyle(el).backgroundImage;
            return this.extractBackgroundImageUrl(bg);
        }

        async pickActiveMediaWithWait(article, maxAttempts = 25, interval = 150) {
            const isSuggested = article.dataset.isSuggested === 'true';
            const adjustedAttempts = isSuggested ? 8 : maxAttempts;
            const adjustedInterval = isSuggested ? 50 : interval;

            for (let attempt = 0; attempt < adjustedAttempts; attempt++) {
                const candidate = this.findCandidateMedia(article);
                if (candidate) {
                    const id = this.getMediaIdentifier(candidate);
                    if (candidate.tagName === 'IMG') {
                        const rect = candidate.getBoundingClientRect();
                        if (rect.width > 50 && rect.height > 50) {
                            if (isSuggested) {
                                if (attempt > 0 || candidate.complete) return { el: candidate, id };
                            } else {
                                const loaded = await this.waitForImageToLoad(candidate, 1500);
                                if (loaded) return { el: candidate, id };
                            }
                        }
                    } else if (candidate.tagName === 'VIDEO') {
                        if (isSuggested) {
                            if (candidate.readyState > 0 || attempt > 1) return { el: candidate, id };
                        } else {
                            const ready = await this.waitForVideoReady(candidate, 1500);
                            if (ready) return { el: candidate, id };
                        }
                    } else {
                        const bg = getComputedStyle(candidate).backgroundImage;
                        const url = this.extractBackgroundImageUrl(bg);
                        if (url) return { el: candidate, id: url };
                    }
                }
                const waitTime = isSuggested ? 50 : Math.min(interval * (1 + attempt * 0.2), 500);
                await this.sleep(waitTime);
            }
            return null;
        }

        async mountMediaForDisplay(mediaEl) {
            this.restoreOriginalMediaPosition();
            if (mediaEl.tagName !== 'IMG' && mediaEl.tagName !== 'VIDEO') {
                const bg = getComputedStyle(mediaEl).backgroundImage;
                const url = this.extractBackgroundImageUrl(bg);
                if (!url) return null;
                const img = document.createElement('img');
                img.style.cssText = 'width: 100%; height: 100%; object-fit: contain; background: black; pointer-events: auto;';
                img.src = url;
                this.uiElements.mediaWrapper.appendChild(img);
                this.activeDisplayedMedia = { element: img, placeholder: null, isClone: true, original: mediaEl };
                await this.waitForImageToLoad(img, 1500);
                return img;
            }
            const rect = mediaEl.getBoundingClientRect();
            // IMPROVED PLACEHOLDER: Ensure it matches the original EXACTLY to prevent layout shift
            const placeholder = document.createElement('div');
            placeholder.style.cssText = `width: ${rect.width}px; height: ${rect.height}px; flex-shrink: 0; display: block; background: transparent;`;

            if (mediaEl.parentNode) {
                try { mediaEl.parentNode.replaceChild(placeholder, mediaEl); } catch (e) { /* ignore */ }
            }
            this.activeDisplayedMedia = { element: mediaEl, placeholder, isClone: false, originalParent: placeholder.parentNode };

            if (mediaEl.tagName === 'VIDEO') {
                mediaEl.setAttribute('preload', 'auto');
                if (mediaEl.videoWidth > 0 && mediaEl.videoHeight > 0) {
                    mediaEl.style.width = '100vw';
                    mediaEl.style.height = '100vh';
                }
                // Reset intended pause state when mounting new video
                this.userIntendedPause = false;
                this.displayVideo(mediaEl);
            } else {
                const originalSrc = mediaEl.src;
                const highResUrl = this.getHighQualityUrl(mediaEl);

                mediaEl.style.cssText = `width: 100%; height: 100%; object-fit: contain; background: black; pointer-events: auto;`;

                if (highResUrl && highResUrl !== originalSrc) {
                    mediaEl.onerror = () => {
                        console.warn("Max quality image failed, reverting to standard.");
                        mediaEl.src = originalSrc;
                        mediaEl.onerror = null;
                    };
                    mediaEl.src = highResUrl;
                }
                this.uiElements.mediaWrapper.appendChild(mediaEl);
            }
            return mediaEl;
        }

        displayVideo(videoElement) {
            const mediaWrapper = this.uiElements.mediaWrapper;
            const videoContainer = document.createElement('div');
            videoContainer.className = 'custom-video-container';
            videoContainer.style.cssText = `position: relative; width: 100%; height: 100%; background: black; display: flex; align-items: center; justify-content: center; cursor: pointer; pointer-events: auto;`;
            videoElement.style.cssText = `width: 100%; height: 100%; object-fit: contain; border-radius: 0; display: block; background: black;`;

            videoElement.muted = this.savedMuted;
            videoElement.volume = this.savedVolume;
            videoElement.playbackRate = this.savedPlaybackRate;
            videoElement.loop = false;
            videoElement.controls = false;
            videoElement.preload = 'auto'; // Force buffer

            const controlsOverlay = document.createElement('div');
            controlsOverlay.className = 'video-controls-overlay';
            controlsOverlay.style.cssText = `position: absolute; bottom: 0; left: 0; right: 0; background: linear-gradient(to top, rgba(0,0,0,0.8) 0%, rgba(0,0,0,0.4) 50%, transparent 100%); padding: 12px 30px 12px 12px; opacity: 0; transition: opacity 0.3s ease; pointer-events: all; z-index: 1000010;`;

            const progressContainer = document.createElement('div');
            progressContainer.style.cssText = `width: 100%; height: 14px; background: transparent; border-radius: 10px; margin-bottom: 10px; cursor: pointer; pointer-events: all; position: relative; display: flex; align-items: center; padding: 5px 0;`;

            const progressBackground = document.createElement('div');
            progressBackground.style.cssText = `width: 100%; height: 4px; background: rgba(255,255,255,0.3); border-radius: 2px; position: relative;`;

            const progressBar = document.createElement('div');
            progressBar.className = 'progress-fill';
            progressBar.style.cssText = `height: 100%; background: linear-gradient(90deg, #f09433, #e6683c); border-radius: 3px; width: 0%; transition: width 0.1s ease; position: relative;`;

            const progressThumb = document.createElement('div');
            progressThumb.className = 'progress-thumb';
            progressThumb.style.cssText = `position: absolute; right: -5px; top: 50%; transform: translateY(-50%); width: 10px; height: 10px; background: #f09433; border-radius: 50%; opacity: 0; transition: opacity 0.3s ease; box-shadow: 0 2px 8px rgba(0,0,0,0.3);`;
            progressBar.appendChild(progressThumb);
            progressBackground.appendChild(progressBar);
            progressContainer.appendChild(progressBackground);

            const controlsContainer = document.createElement('div');
            controlsContainer.style.cssText = `display: flex; align-items: center; gap: 15px; pointer-events: all;`;

            const playButton = document.createElement('button');
            playButton.innerHTML = `
                <svg class="play-icon" width="18" height="18" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg" style="transition: all 0.3s ease;">
                    <path d="M8 5v14l11-7z" fill="white" style="filter: drop-shadow(0 2px 4px rgba(0,0,0,0.4));"/>
                </svg>
                <svg class="pause-icon" style="display: none; transition: all 0.3s ease;" width="18" height="18" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
                    <path d="M6 4h4v16H6V4zm8 0h4v16h-4V4z" fill="white" style="filter: drop-shadow(0 2px 4px rgba(0,0,0,0.4));"/>
                </svg>
            `;
            playButton.style.cssText = `
                background: rgba(255,255,255,0.15);
                border: 1px solid rgba(255,255,255,0.2);
                color: white;
                font-size: 16px;
                cursor: pointer;
                padding: 0;
                border-radius: 50%;
                transition: all 0.3s cubic-bezier(0.34, 1.56, 0.64, 1);
                display: flex;
                align-items: center;
                justify-content: center;
                width: 36px;
                height: 36px;
                position: relative;
                overflow: hidden;
                backdrop-filter: blur(10px);
                box-shadow: 0 4px 12px rgba(0,0,0,0.3);
                flex-shrink: 0;
            `;

            const updatePlayPauseIcon = () => {
                const playIcon = playButton.querySelector('.play-icon');
                const pauseIcon = playButton.querySelector('.pause-icon');
                if (playIcon && pauseIcon) {
                    if (videoElement.paused) {
                        playIcon.style.display = 'block';
                        pauseIcon.style.display = 'none';
                    } else {
                        playIcon.style.display = 'none';
                        pauseIcon.style.display = 'block';
                    }
                }
            };

            const timeDisplay = document.createElement('div');
            timeDisplay.style.cssText = `color: white; font-size: 11px; font-weight: 600; min-width: 70px; text-shadow: 0 1px 2px rgba(0,0,0,0.8);`;
            timeDisplay.textContent = '0:00 / 0:00';

            // Playback speed button
            const speedButton = document.createElement('button');
            speedButton.innerHTML = this.savedPlaybackRate.toFixed(2) + 'x';
            speedButton.style.cssText = `background: rgba(255,255,255,0.2); border: none; color: white; font-size: 11px; font-weight: 600; cursor: pointer; padding: 4px 8px; border-radius: 12px; transition: all 0.3s ease; min-width: 35px;`;
            speedButton.title = 'Playback Speed';

            const volumeContainer = document.createElement('div');
            volumeContainer.style.cssText = `display: flex; align-items: center; gap: 10px; margin-left: auto; margin-right: 25px;`;

            const muteButton = document.createElement('button');
            muteButton.innerHTML = this.savedMuted ? '🔇' : '🔊';
            muteButton.style.cssText = `background: none; border: none; color: white; font-size: 16px; cursor: pointer; padding: 6px; border-radius: 4px; transition: background 0.3s ease; flex-shrink: 0;`;

            const volumeSliderContainer = document.createElement('div');
            volumeSliderContainer.style.cssText = `width: 80px; height: 20px; display: flex; align-items: center; cursor: pointer; position: relative;`;

            const volumeTrack = document.createElement('div');
            volumeTrack.style.cssText = `width: 100%; height: 4px; background: rgba(255,255,255,0.3); border-radius: 2px; position: relative;`;

            const volumeFill = document.createElement('div');
            volumeFill.style.cssText = `height: 100%; background: linear-gradient(90deg, #f09433, #e6683c); border-radius: 2px; width: ${this.savedVolume * 100}%; position: relative;`;

            const volumeThumb = document.createElement('div');
            volumeThumb.style.cssText = `position: absolute; top: 50%; right: -6px; transform: translateY(-50%); width: 12px; height: 12px; background: white; border-radius: 50%; box-shadow: 0 2px 4px rgba(0,0,0,0.3); cursor: grab;`;

            volumeTrack.appendChild(volumeFill);
            volumeFill.appendChild(volumeThumb);
            volumeSliderContainer.appendChild(volumeTrack);
            volumeContainer.appendChild(muteButton);
            volumeContainer.appendChild(volumeSliderContainer);
            controlsContainer.appendChild(playButton);
            controlsContainer.appendChild(timeDisplay);
            controlsContainer.appendChild(speedButton);
            controlsContainer.appendChild(volumeContainer);
            controlsOverlay.appendChild(progressContainer);
            controlsOverlay.appendChild(controlsContainer);
            videoContainer.appendChild(videoElement);
            videoContainer.appendChild(controlsOverlay);
            mediaWrapper.appendChild(videoContainer);

            let isDragging = false;
            let isVolumeDragging = false;

            const applyVolumeSettings = () => {
                videoElement.muted = this.savedMuted;
                videoElement.volume = this.savedVolume;
                muteButton.innerHTML = this.savedMuted ? '🔇' : '🔊';
                volumeFill.style.width = (this.savedVolume * 100) + '%';
            };

            const saveVolumeSettings = () => {
                this.savedVolume = videoElement.volume;
                this.savedMuted = videoElement.muted;
                localStorage.setItem('igreels_volume', this.savedVolume.toString());
                localStorage.setItem('igreels_muted', this.savedMuted.toString());
            };

            const updateVolume = (clientX) => {
                const rect = volumeTrack.getBoundingClientRect();
                const percent = Math.max(0, Math.min(1, (clientX - rect.left) / rect.width));
                videoElement.volume = percent;
                if (percent > 0 && videoElement.muted) {
                    videoElement.muted = false;
                }
                saveVolumeSettings();
                applyVolumeSettings();
            };

            volumeSliderContainer.addEventListener('mousedown', (e) => {
                e.stopPropagation();
                isVolumeDragging = true;
                volumeThumb.style.cursor = 'grabbing';
                updateVolume(e.clientX);
                const onMouseMove = (e) => {
                    if (isVolumeDragging) updateVolume(e.clientX);
                };
                const onMouseUp = () => {
                    isVolumeDragging = false;
                    volumeThumb.style.cursor = 'grab';
                    document.removeEventListener('mousemove', onMouseMove);
                    document.removeEventListener('mouseup', onMouseUp);
                };
                document.addEventListener('mousemove', onMouseMove);
                document.addEventListener('mouseup', onMouseUp);
            });

            const togglePlayPause = () => {
                this.stopAutoScrollTimer();
                this.isProcessingInteraction = true;

                if (videoElement.paused) {
                    this.userIntendedPause = false; // User wants to play
                    applyVolumeSettings();
                    videoElement.play().catch(err => console.warn('Play failed:', err));
                } else {
                    this.userIntendedPause = true; // User intentionally paused
                    videoElement.pause();
                }

                setTimeout(() => {
                    this.isProcessingInteraction = false;
                    if (!videoElement.paused) {
                        this.startAutoScrollTimer();
                    }
                }, 300);
            };

            playButton.addEventListener('click', (e) => { e.stopPropagation(); togglePlayPause(); });
            videoElement.addEventListener('click', togglePlayPause);

            const toggleMute = () => {
                videoElement.muted = !videoElement.muted;
                saveVolumeSettings();
                applyVolumeSettings();
            };

            videoElement.addEventListener('dblclick', (e) => { e.stopPropagation(); toggleMute(); });
            muteButton.addEventListener('click', (e) => { e.stopPropagation(); toggleMute(); });

            // Playback speed control
            const speedOptions = [0.25, 0.5, 0.75, 1, 1.25, 1.5, 1.75, 2, 2.5, 3, 3.5, 4];
            speedButton.addEventListener('click', (e) => {
                e.stopPropagation();
                const currentIndex = speedOptions.indexOf(this.savedPlaybackRate);
                const nextIndex = (currentIndex + 1) % speedOptions.length;
                this.savedPlaybackRate = speedOptions[nextIndex];
                videoElement.playbackRate = this.savedPlaybackRate;
                speedButton.innerHTML = this.savedPlaybackRate.toFixed(2) + 'x';
                localStorage.setItem('igreels_playbackRate', this.savedPlaybackRate.toString());
            });

            const updateProgress = () => {
                 if (!isDragging && videoElement.duration) {
                    progressBar.style.width = (videoElement.currentTime / videoElement.duration) * 100 + '%';
                 }
            };

            const updateTime = () => {
                const formatTime = s => `${Math.floor(s/60)}:${Math.floor(s%60).toString().padStart(2,'0')}`;
                timeDisplay.textContent = `${formatTime(videoElement.currentTime||0)} / ${formatTime(videoElement.duration||0)}`;
            };

            videoElement.addEventListener('timeupdate', () => { updateProgress(); updateTime(); });
            videoElement.addEventListener('loadedmetadata', () => { updateTime(); applyVolumeSettings(); videoElement.playbackRate = this.savedPlaybackRate; });
            videoElement.addEventListener('play', updatePlayPauseIcon);
            videoElement.addEventListener('pause', updatePlayPauseIcon);
            videoElement.addEventListener('loadeddata', () => { applyVolumeSettings(); videoElement.playbackRate = this.savedPlaybackRate; updatePlayPauseIcon(); });
            videoElement.addEventListener('canplay', () => { applyVolumeSettings(); videoElement.playbackRate = this.savedPlaybackRate; });

            // ANTI-PAUSE LOCK
            // If the video pauses AND the user didn't request it, assume IG killed it due to scroll drift.
            videoElement.addEventListener('pause', (e) => {
                if (this.isActive && !this.userIntendedPause && !this.isNavigating && !this.isProcessingInteraction) {
                    // console.warn('⚠️ Detected unwanted pause (IG Scroll Drift). Forcing Play & Re-syncing...');
                    videoElement.play().catch(()=>{});
                    // Force re-sync scroll to the current post to make IG happy
                    if (this.activePost.element) {
                        this.activePost.element.scrollIntoView({ behavior: 'auto', block: 'center' });
                    }
                }
            });

            // Force playback rate persistence
            const enforceSpeed = () => {
                if (Math.abs(videoElement.playbackRate - this.savedPlaybackRate) > 0.01) {
                    videoElement.playbackRate = this.savedPlaybackRate;
                }
            };
            videoElement.addEventListener('ratechange', enforceSpeed);
            videoElement.addEventListener('playing', enforceSpeed);
            videoElement.addEventListener('play', enforceSpeed);

            const handleProgressClick = (e) => {
                this.stopAutoScrollTimer();
                this.isProcessingInteraction = true;

                const rect = progressBackground.getBoundingClientRect();
                if (videoElement.duration) videoElement.currentTime = ((e.clientX - rect.left) / rect.width) * videoElement.duration;

                setTimeout(() => {
                    this.isProcessingInteraction = false;
                    this.startAutoScrollTimer();
                }, 300);
            };

            progressContainer.addEventListener('mousedown', (e) => {
                e.stopPropagation();
                 isDragging = true;
                 handleProgressClick(e);
                const onMove = (e) => { if(isDragging) handleProgressClick(e); };
                const onUp = () => { isDragging = false; document.removeEventListener('mousemove', onMove); document.removeEventListener('mouseup', onUp); };
                document.addEventListener('mousemove', onMove);
                document.addEventListener('mouseup', onUp);
            });

            let isHoveringControls = false;
            const controlsHoverZone = 150;
            videoContainer.addEventListener('mousemove', (e) => {
                const rect = videoContainer.getBoundingClientRect();
                const distanceFromBottom = rect.bottom - e.clientY;
                if (distanceFromBottom <= controlsHoverZone) {
                    if (!isHoveringControls) {
                        isHoveringControls = true;
                        controlsOverlay.style.opacity = '1';
                    }
                } else {
                    if (isHoveringControls) {
                        isHoveringControls = false;
                        if (!isDragging && !isVolumeDragging) {
                            controlsOverlay.style.opacity = '0';
                        }
                    }
                }
            });
            videoContainer.addEventListener('mouseleave', () => {
                isHoveringControls = false;
                if (!isDragging && !isVolumeDragging) {
                    controlsOverlay.style.opacity = '0';
                }
            });

            applyVolumeSettings();
            videoElement.playbackRate = this.savedPlaybackRate;
            speedButton.innerHTML = this.savedPlaybackRate.toFixed(2) + 'x';
            updatePlayPauseIcon();

            const playVideo = async () => {
                try {
                    if (videoElement.readyState < 2) {
                        await new Promise((resolve) => {
                            const onReady = () => {
                                videoElement.removeEventListener('canplay', onReady);
                                videoElement.removeEventListener('loadeddata', onReady);
                                resolve();
                            };
                            videoElement.addEventListener('canplay', onReady);
                            videoElement.addEventListener('loadeddata', onReady);
                            setTimeout(resolve, 1500);
                        });
                    }
                    applyVolumeSettings();
                    videoElement.playbackRate = this.savedPlaybackRate;
                    await videoElement.play();
                    applyVolumeSettings();
                    videoElement.playbackRate = this.savedPlaybackRate;
                } catch (err) {
                    console.warn('Play failed:', err);
                }
            };
            playVideo();
        }

        restoreOriginalMediaPosition() {
            const info = this.activeDisplayedMedia;
            if (!info || (!info.element && !info.placeholder)) {
                this.activeDisplayedMedia = { element: null, placeholder: null, isClone: false };
                if (this.uiElements.mediaWrapper) this.uiElements.mediaWrapper.innerHTML = '';
                return;
            }
            try {
                if (info.isClone) {
                    if (info.element && info.element.parentNode) info.element.parentNode.removeChild(info.element);
                } else {
                    const { element, placeholder } = info;
                    if (element && placeholder && placeholder.parentNode) {
                        if (element.tagName === 'VIDEO') element.pause();
                        element.style.cssText = '';
                        placeholder.parentNode.replaceChild(element, placeholder);
                    } else if (element && element.parentNode) {
                        element.parentNode.removeChild(element);
                    }
                }
            } catch (e) {}
            this.activeDisplayedMedia = { element: null, placeholder: null, isClone: false };
            if (this.uiElements.mediaWrapper) this.uiElements.mediaWrapper.innerHTML = '';
        }

        async updateView(postElement) {
            const article = postElement || document.querySelector('div[role="dialog"] article');;
            if (!article) { console.error("UpdateView: Could not find a valid post element."); this.exit(); return; }
            this.activePost.element = article;

            const currentVolume = this.savedVolume;
            const currentMuted = this.savedMuted;
            const currentPlaybackRate = this.savedPlaybackRate;

            const picked = await this.pickActiveMediaWithWait(article, 30, 110);
            if (!picked) { console.warn("Could not identify active media. Skipping display."); return; }
            const mediaEl = picked.el;
            await this.mountMediaForDisplay(mediaEl);

            this.savedVolume = currentVolume;
            this.savedMuted = currentMuted;
            this.savedPlaybackRate = currentPlaybackRate;

            let authorLink = article.querySelector('header a[role="link"]');
            if (!authorLink) {
                authorLink = article.querySelector('a[role="link"] span');
            }
            const author = authorLink?.textContent?.trim() || authorLink?.getAttribute('href')?.replace(/\//g, '') || 'Unknown';
            let caption = '';
            const captionContainer = article.querySelector('h1._aaco, h1, div[class*="Caption"], span[class*="caption"]');
            if (captionContainer) {
                caption = captionContainer.innerHTML || captionContainer.textContent;
            } else {
                const possibleCaption = article.querySelector('div[style*="webkit-box"]');
                if (possibleCaption) caption = possibleCaption.innerHTML;
            }

            this.uiElements.info.innerHTML = `<div class="author-name" style="font-weight: 700; font-size: 16px; margin-bottom: 8px; cursor: pointer;">${author}</div><div style="font-size: 14px; line-height: 1.4; opacity: 0.9; word-wrap: break-word; overflow-wrap: break-word; white-space: normal;">${caption}</div>`;
            const authorElement = this.uiElements.info.querySelector('.author-name');
            if (authorElement) {
                authorElement.addEventListener('click', (e) => {
                    e.stopPropagation();
                    window.open(`https://instagram.com/${author}`, '_blank');
                });
            }
            this.updateActionButtonStates();
            this.startAutoScrollTimer();
        }

        async attemptScrollToPost(element, attempts = 0, maxAttempts = 10, interval = 100) {
            if (!element || attempts >= maxAttempts) {
                console.warn('Failed to scroll post into view after multiple attempts.');
                return;
            }
            element.scrollIntoView({ behavior: 'auto', block: 'center' });
            await new Promise(resolve => setTimeout(resolve, interval));
            const rect = element.getBoundingClientRect();
            const viewportHeight = window.innerHeight;
            const margin = 50;
            const isInView = rect.top >= -margin && rect.bottom <= viewportHeight + margin;
            if (!isInView) {
                this.attemptScrollToPost(element, attempts + 1, maxAttempts, interval);
            }
        }

        findNextArticle(currentArticle) {
            const allArticles = Array.from(document.querySelectorAll('article'));
            const currentIndex = allArticles.indexOf(currentArticle);
            for (let i = currentIndex + 1; i < allArticles.length; i++) {
                const article = allArticles[i];
                if (article !== currentArticle && this.isValidArticle(article)) {
                    return article;
                }
            }
            return null;
        }

        findPrevArticle(currentArticle) {
            const allArticles = Array.from(document.querySelectorAll('article'));
            const currentIndex = allArticles.indexOf(currentArticle);
            for (let i = currentIndex - 1; i >= 0; i--) {
                const article = allArticles[i];
                if (article !== currentArticle && this.isValidArticle(article)) {
                    return article;
                }
            }
            return null;
        }

        updateActionButtonStates() {
            if (!this.activePost.element) return;
            const isLiked = this.activePost.element.querySelector('section svg[aria-label="Unlike"]');
            const heartPath = this.uiElements.likeButton.querySelector('.heart-path');
            if (isLiked) {
                this.uiElements.likeButton.classList.add('igreels-liked');
                if (heartPath) {
                    heartPath.setAttribute('fill', '#ff306c');
                    heartPath.setAttribute('stroke', '#ff306c');
                }
            } else {
                this.uiElements.likeButton.classList.remove('igreels-liked');
                if (heartPath) {
                    heartPath.setAttribute('fill', 'none');
                    heartPath.setAttribute('stroke', 'white');
                }
            }
            const isSaved = this.activePost.element.querySelector('section svg[aria-label="Remove"]');
            const bookmarkPath = this.uiElements.saveButton.querySelector('.bookmark-path');
            if (isSaved) {
                this.uiElements.saveButton.classList.add('igreels-bookmarked');
                if (bookmarkPath) {
                    bookmarkPath.setAttribute('fill', '#ffc107');
                    bookmarkPath.setAttribute('stroke', '#ffc107');
                }
            } else {
                this.uiElements.saveButton.classList.remove('igreels-bookmarked');
                if (bookmarkPath) {
                    bookmarkPath.setAttribute('fill', 'none');
                    bookmarkPath.setAttribute('stroke', 'white');
                }
            }
            let isFollowing = false;
            const isModal = !!document.querySelector('div[role="dialog"]');
            if (isModal) {
                const headerButtons = this.activePost.element.querySelectorAll('header button');
                for (const btn of headerButtons) {
                    const text = btn.textContent.trim();
                    if (text === 'Following' || text === 'Requested') {
                        isFollowing = true;
                        break;
                    }
                }
            } else {
                const articleHeader = this.activePost.element.querySelector('header');
                if (articleHeader) {
                    const divButtons = articleHeader.querySelectorAll('div[role="button"]');
                    for (const btn of divButtons) {
                        const text = btn.textContent.trim();
                        if (text === 'Following' || text === 'Requested') {
                            isFollowing = true;
                            break;
                        }
                    }
                    if (!isFollowing) {
                        const buttons = articleHeader.querySelectorAll('button');
                        for (const btn of buttons) {
                            const text = btn.textContent.trim();
                            if (text === 'Following' || text === 'Requested') {
                                isFollowing = true;
                                break;
                            }
                        }
                    }
                }
            }
            if (!isFollowing) {
                const followingSvg = this.activePost.element.querySelector('svg[aria-label="Following"]');
                if (followingSvg) {
                    isFollowing = true;
                }
            }
            if (isFollowing) {
                this.uiElements.followButton.classList.add('igreels-following');
            } else {
                this.uiElements.followButton.classList.remove('igreels-following');
            }
        }

        smartNavigate(direction) {
            if (this.skipCarouselMode) {
                this.navigatePost(direction);
                return;
            }
            const mediaContainer = this.activePost.element?.firstElementChild;
            if (!mediaContainer) return;
            const nextButton = mediaContainer.querySelector('button[aria-label="Next"]');
            const prevButton = mediaContainer.querySelector('button[aria-label="Go back"]');
            if (direction === 'next' && nextButton) {
                this.navigateMedia('next');
            } else if (direction === 'prev' && prevButton) {
                this.navigateMedia('prev');
            } else {
                this.navigatePost(direction);
            }
        }

        async navigatePost(direction) {
            if (this.isNavigating) return;
            this.isNavigating = true;
            this.stopAutoScrollTimer();
            this.isProcessingInteraction = true;
            const currentId = this.getMediaIdentifier(this.activeDisplayedMedia.element);
            const dialog = document.querySelector('div[role="dialog"]');
            if (dialog) {
                const svgSelector = direction === 'next' ? 'svg[aria-label="Next"]' : 'svg[aria-label="Go back"]';
                const navButton = Array.from(dialog.querySelectorAll(svgSelector)).find(svg => !svg.closest('article'))?.closest('button');
                if (!navButton) {
                    console.log(`No ${direction} post found.`);
                    this.isNavigating = false;
                    this.isProcessingInteraction = false;
                    this.startAutoScrollTimer();
                    return;
                }
                navButton.click();
                const start = Date.now();
                let success = false;
                while (Date.now() - start < 5000) {
                    await this.sleep(120);
                    const newArticle = document.querySelector('div[role="dialog"] article');
                    if (!newArticle) continue;
                    const picked = await this.pickActiveMediaWithWait(newArticle, 12, 100);
                    const newId = picked ? this.getMediaIdentifier(picked.el) : null;
                    if (newId && newId !== currentId) {
                        await this.updateView(newArticle);
                        success = true;
                        break;
                    }
                }
                if (!success) console.warn('navigatePost: timed out waiting for next post.');
            } else {
                document.body.style.scrollBehavior = 'auto';
                let nextPostElement = null;
                if (direction === 'prev') {
                    nextPostElement = this.findPrevArticle(this.activePost.element);
                } else {
                    nextPostElement = this.findNextArticle(this.activePost.element);
                }
                if (nextPostElement) {
                    await this.attemptScrollToPost(nextPostElement);
                    await this.sleep(650);
                    await this.updateView(nextPostElement);
                } else if (direction === 'next') {
                    console.log('No more visible posts. Scrolling to load more...');
                    // INSTANT LOAD LOGIC: Nudge scroll to wake up loader, then poll for new content
                    window.scrollTo({ top: document.body.scrollHeight, behavior: 'auto' });
                    // Give a small nudge just in case we were already at bottom
                    setTimeout(() => window.scrollBy(0, 100), 50);

                    const start = Date.now();
                    let foundNew = false;
                    // Poll for up to 2.5 seconds, checking every 100ms
                    while (Date.now() - start < 2500) {
                        await this.sleep(100);
                        const newlyLoadedPost = this.findNextArticle(this.activePost.element);
                        if (newlyLoadedPost && newlyLoadedPost !== this.activePost.element) {
                            await this.attemptScrollToPost(newlyLoadedPost);
                            await this.sleep(300); // Short settle time
                            await this.updateView(newlyLoadedPost);
                            foundNew = true;
                            break;
                        }
                    }
                    if (!foundNew) console.log('No new posts found after waiting.');
                }
            }
            this.isNavigating = false;
            this.isProcessingInteraction = false;
            this.startAutoScrollTimer();
        }

        async navigateMedia(direction) {
            if (this.isNavigating) return;
            this.isNavigating = true;
            this.stopAutoScrollTimer();
            this.isProcessingInteraction = true;
            const mediaContainer = this.activePost.element?.firstElementChild;
            if (!mediaContainer) {
                this.isNavigating = false;
                this.isProcessingInteraction = false;
                this.startAutoScrollTimer();
                return;
            }
            const selector = direction === 'next' ? 'button[aria-label="Next"]' : 'button[aria-label="Go back"]';
            const button = mediaContainer.querySelector(selector);
            if (!button) {
                this.isNavigating = false;
                this.isProcessingInteraction = false;
                this.startAutoScrollTimer();
                return;
            }
            const currentId = this.getMediaIdentifier(this.activeDisplayedMedia.element);
            button.click();
            const start = Date.now();
            let success = false;
            while (Date.now() - start < 3500) {
                await this.sleep(120);
                const picked = await this.pickActiveMediaWithWait(this.activePost.element, 10, 100);
                if (!picked) continue;
                const newId = this.getMediaIdentifier(picked.el);
                if (newId && newId !== currentId) {
                    await this.updateView(this.activePost.element);
                    success = true;
                    break;
                }
            }
            if (!success) { await this.sleep(260); await this.updateView(this.activePost.element); }
            this.isNavigating = false;
            this.isProcessingInteraction = false;
            this.startAutoScrollTimer();
        }

        async toggleAction(type) {
            if (!this.activePost.element) return;
            const selectors = {
                like: 'section svg[aria-label="Like"], section svg[aria-label="Unlike"]',
                save: 'section svg[aria-label="Save"], section svg[aria-label="Remove"]'
            };
            const uiButton = type === 'like' ? this.uiElements.likeButton : this.uiElements.saveButton;
            uiButton.style.transform = 'scale(1.3)'; uiButton.style.filter = 'brightness(1.5)';
            const svgElement = this.activePost.element.querySelector(selectors[type]);
            if (!svgElement) { console.warn(`toggleAction: ${type} SVG not found`); return; }
            let clickableElement = svgElement.closest('[role="button"], button');
            if (clickableElement) {
                clickableElement.click();
                await this.sleep(500);
                this.updateActionButtonStates();
            } else {
                console.warn(`toggleAction: No clickable element found for ${type}`);
            }
            setTimeout(() => { uiButton.style.transform = 'scale(1)'; uiButton.style.filter = 'brightness(1)'; }, 200);
        }

        async toggleFollow() {
            if (!this.activePost.element) return;
            this.uiElements.followButton.style.transform = 'scale(1.3)';
            this.uiElements.followButton.style.filter = 'brightness(1.5)';
            const isModal = !!document.querySelector('div[role="dialog"]');
            let followButton = null;
            if (isModal) {
                const headerButtons = this.activePost.element.querySelectorAll('header button');
                for (const btn of headerButtons) {
                    const text = btn.textContent.trim();
                    if (text === 'Follow' || text === 'Following' || text === 'Unfollow' || text === 'Requested') {
                        followButton = btn;
                        break;
                    }
                }
            } else {
                const articleHeader = this.activePost.element.querySelector('header');
                if (articleHeader) {
                    const divButtons = articleHeader.querySelectorAll('div[role="button"]');
                    for (const btn of divButtons) {
                        const text = btn.textContent.trim();
                        if (text === 'Follow' || text === 'Following' || text === 'Unfollow' || text === 'Requested') {
                            followButton = btn;
                            break;
                        }
                    }
                    if (!followButton) {
                        const buttons = articleHeader.querySelectorAll('button');
                        for (const btn of buttons) {
                            const text = btn.textContent.trim();
                            if (text === 'Follow' || text === 'Following' || text.includes('Follow')) {
                                followButton = btn;
                                break;
                            }
                        }
                    }
                }
            }
            if (!followButton) {
                const allDivButtons = this.activePost.element.querySelectorAll('div[role="button"]');
                for (const btn of allDivButtons) {
                    const text = btn.textContent.trim();
                    if (text === 'Follow' || text === 'Following') {
                        followButton = btn;
                        break;
                    }
                }
            }
            if (!followButton) {
                const allButtons = this.activePost.element.querySelectorAll('button');
                for (const btn of allButtons) {
                    const text = btn.textContent.trim();
                    if (text === 'Follow' || text === 'Following') {
                        followButton = btn;
                        break;
                    }
                }
            }
            if (!followButton) {
                const followSvg = this.activePost.element.querySelector('svg[aria-label="Follow"], svg[aria-label="Following"]');
                if (followSvg) {
                    followButton = followSvg.closest('button, div[role="button"]');
                }
            }
            if (followButton) {
                console.log('Found follow button:', followButton.textContent.trim(), 'Type:', followButton.tagName);
                followButton.click();
                await this.sleep(500);
                this.updateActionButtonStates();
            } else {
                console.warn('toggleFollow: Follow button not found. Page context:', isModal ? 'modal' : 'feed');
            }
            setTimeout(() => {
                this.uiElements.followButton.style.transform = 'scale(1)';
                this.uiElements.followButton.style.filter = 'brightness(1)';
            }, 200);
        }

        handleKeydown(e) {
            if (e.key.toLowerCase() === 'x') {
                e.preventDefault();
                e.stopImmediatePropagation();
                if (this.isActive) {
                    this.exit();
                } else {
                    this.armFeedStart();
                }
                return;
            }

            if (!this.isActive) return;

            if (/TEXTAREA|INPUT/.test(document.activeElement.tagName)) {
                if (e.key.toLowerCase() === 'q' || e.key === 'Escape') {
                    e.preventDefault();
                    e.stopImmediatePropagation();
                    this.exit();
                }
                return;
            }

            try { e.preventDefault(); e.stopImmediatePropagation(); } catch (err) {}
            const key = e.key.length === 1 ? e.key.toLowerCase() : e.key;
            const keyMap = {
                'ArrowUp': () => this.smartNavigate('prev'),
                'ArrowDown': () => this.smartNavigate('next'),
                'ArrowLeft': () => this.navigateMedia('prev'),
                'ArrowRight': () => this.navigateMedia('next'),
                'l': () => this.toggleAction('like'),
                's': () => this.toggleAction('save'),
                'f': () => this.toggleFollow(),
                ' ': () => {
                    this.stopAutoScrollTimer();
                    this.isProcessingInteraction = true;
                    const video = this.uiElements.mediaWrapper.querySelector('video');
                    if (video) {
                        if (video.paused) {
                            this.userIntendedPause = false;
                            video.play();
                        } else {
                            this.userIntendedPause = true;
                            video.pause();
                        }
                    }
                    setTimeout(() => {
                        this.isProcessingInteraction = false;
                        const videoCheck = this.uiElements.mediaWrapper.querySelector('video');
                        if (videoCheck && !videoCheck.paused) {
                            this.startAutoScrollTimer();
                        }
                    }, 300);
                },
                ',': () => this.scrubVideo(-5),
                '<': () => this.scrubVideo(-5),
                '.': () => this.scrubVideo(5),
                '>': () => this.scrubVideo(5),
                'Escape': () => this.exit(),
                'q': () => this.exit(),
            };
            const fn = keyMap[key];
            if (fn) fn();
        }

        scrubVideo(seconds) {
            this.stopAutoScrollTimer();
            this.isProcessingInteraction = true;
            const video = this.uiElements.mediaWrapper.querySelector('video');
            if (video) {
                video.currentTime = Math.max(0, Math.min(video.duration, video.currentTime + seconds));
            }
            setTimeout(() => {
                this.isProcessingInteraction = false;
                this.startAutoScrollTimer();
            }, 300);
        }
    }

    if (window.instagramFeedInstance) {
        try { window.instagramFeedInstance.exit(); } catch (e) {}
    }
    window.instagramFeedInstance = new InstagramFeed();
    window.instagramFeedInstance.init();

})();