Pinterest Dark Mode Toggle

A customizable AMOLED dark theme for Pinterest

이 스크립트를 설치하려면 Tampermonkey, Greasemonkey 또는 Violentmonkey와 같은 확장 프로그램이 필요합니다.

이 스크립트를 설치하려면 Tampermonkey와 같은 확장 프로그램을 설치해야 합니다.

이 스크립트를 설치하려면 Tampermonkey 또는 Violentmonkey와 같은 확장 프로그램이 필요합니다.

이 스크립트를 설치하려면 Tampermonkey 또는 Userscripts와 같은 확장 프로그램이 필요합니다.

이 스크립트를 설치하려면 Tampermonkey와 같은 확장 프로그램이 필요합니다.

이 스크립트를 설치하려면 유저 스크립트 관리자 확장 프로그램이 필요합니다.

(이미 유저 스크립트 관리자가 설치되어 있습니다. 설치를 진행합니다!)

Advertisement:

이 스타일을 설치하려면 Stylus와 같은 확장 프로그램이 필요합니다.

이 스타일을 설치하려면 Stylus와 같은 확장 프로그램이 필요합니다.

이 스타일을 설치하려면 Stylus와 같은 확장 프로그램이 필요합니다.

이 스타일을 설치하려면 유저 스타일 관리자 확장 프로그램이 필요합니다.

이 스타일을 설치하려면 유저 스타일 관리자 확장 프로그램이 필요합니다.

이 스타일을 설치하려면 유저 스타일 관리자 확장 프로그램이 필요합니다.

(이미 유저 스타일 관리자가 설치되어 있습니다. 설치를 진행합니다!)

Advertisement:

// ==UserScript==
// @name         Pinterest Dark Mode Toggle
// @namespace    https://github.com/thetalhachy/pinterest-amoled-dark-mode
// @version      1.0.0
// @description  A customizable AMOLED dark theme for Pinterest
// @author       Talha Mohammad Chowdhury
// @license      AGPL-3.0-or-later
// @match        https://www.pinterest.com/*
// @grant        GM_addStyle
// @grant        GM_getValue
// @grant        GM_setValue
// ==/UserScript==

(function () {
    'use strict';

    const ID = {
        STYLE:  'pdm-style',
        TOAST:  'pdm-toast',
        BTN:    'pdm-btn',
        MENU:   'pdm-menu',
    };

    const KEY = {
        ENABLED:   'pdm_enabled',
        ACCENT:    'pdm_accent',
        CONTRAST:  'pdm_contrast',
    };

    const CLS = 'pdm-dark';

    // Accent colour options: [label, r, g, b]
    const ACCENTS = [
        { label: '🔴', r: 220, g: 50,  b: 50  },
        { label: '🟠', r: 210, g: 100, b: 20  },
        { label: '🟣', r: 130, g: 60,  b: 220 },
        { label: '🔵', r: 40,  g: 120, b: 220 },
        { label: '🟢', r: 40,  g: 180, b: 100 },
        { label: '⚪', r: 180, g: 180, b: 180 },
    ];

    let enabled        = GM_getValue(KEY.ENABLED,  true);
    let accentIndex    = GM_getValue(KEY.ACCENT,   0);       // index into ACCENTS
    let contrastLevel  = GM_getValue(KEY.CONTRAST, 1);       // 0 = soft, 1 = mid, 2 = AMOLED

    function bgFromContrast() {
        // Returns the base background colour for the chosen contrast level
        return ['#1a1a1a', '#0f0f0f', '#000000'][contrastLevel];
    }

    function surfaceFromContrast() {
        return ['#242424', '#161616', '#0d0d0d'][contrastLevel];
    }

    function accentRGB() {
        const a = ACCENTS[accentIndex];
        return `${a.r},${a.g},${a.b}`;
    }

    function buildCSS() {
        const bg      = bgFromContrast();
        const surface = surfaceFromContrast();
        const acc     = accentRGB();

        return `

/* ── BASE ─────────────────────────────────────────────────── */

html.pdm-dark,
html.pdm-dark body,
html.pdm-dark #__PWS_ROOT__ {
    background: ${bg} !important;
    color: #e6e6e6 !important;
}

/* ── BLANKET RESET ──────────────────────────────────────────
   Make all structural elements transparent so the body
   colour shows through. Specific surfaces are set below.
──────────────────────────────────────────────────────────── */

html.pdm-dark div,
html.pdm-dark section,
html.pdm-dark main,
html.pdm-dark article,
html.pdm-dark aside,
html.pdm-dark footer,
html.pdm-dark li,
html.pdm-dark ul,
html.pdm-dark ol,
html.pdm-dark form,
html.pdm-dark label {
    background-color: transparent !important;
    border-color: rgba(255,255,255,0.06) !important;
    color: #e6e6e6 !important;
}

/* ── TYPOGRAPHY ─────────────────────────────────────────────── */

html.pdm-dark span,
html.pdm-dark p,
html.pdm-dark h1,
html.pdm-dark h2,
html.pdm-dark h3,
html.pdm-dark h4,
html.pdm-dark h5,
html.pdm-dark h6,
html.pdm-dark button,
html.pdm-dark a,
html.pdm-dark a:visited {
    color: #e6e6e6 !important;
}

html.pdm-dark a:hover {
    color: rgba(${acc},0.9) !important;
}

html.pdm-dark .tappable,
html.pdm-dark .small,
html.pdm-dark .meta,
html.pdm-dark .description {
    color: rgba(230,230,230,0.6) !important;
}

/* ── HEADER / NAV ───────────────────────────────────────────── */

html.pdm-dark header,
html.pdm-dark header[role="banner"],
html.pdm-dark nav,
html.pdm-dark nav[role="navigation"],
html.pdm-dark [data-test-id="header"],
html.pdm-dark .Header,
html.pdm-dark .topNav,
html.pdm-dark .zCH5,
html.pdm-dark .zI7,
html.pdm-dark .X8m,
html.pdm-dark .CCY,
html.pdm-dark .S9a,
html.pdm-dark .SHI,
html.pdm-dark .ujU {
    background: linear-gradient(180deg, ${surface} 0%, ${bg} 100%) !important;
    border-bottom: 1px solid rgba(255,255,255,0.05) !important;
    backdrop-filter: blur(20px) !important;
    -webkit-backdrop-filter: blur(20px) !important;
    color: #e6e6e6 !important;
}

/* ── CATEGORY / TAB BAR ─────────────────────────────────────── */

html.pdm-dark [role="tablist"],
html.pdm-dark div[role="navigation"] {
    background: ${surface} !important;
    border-bottom: 1px solid rgba(255,255,255,0.05) !important;
}

/* ── SEARCH ──────────────────────────────────────────────────── */

html.pdm-dark input,
html.pdm-dark textarea,
html.pdm-dark select,
html.pdm-dark input[type="search"],
html.pdm-dark input[placeholder*="Search"],
html.pdm-dark [data-test-id="search-box"],
html.pdm-dark .searchBox,
html.pdm-dark .SearchBox,
html.pdm-dark .XiG,
html.pdm-dark .tBJ,
html.pdm-dark .Jea,
html.pdm-dark .JME {
    background: rgba(28,28,30,0.95) !important;
    color: #e6e6e6 !important;
    border: 1px solid rgba(255,255,255,0.1) !important;
    backdrop-filter: blur(10px) !important;
    -webkit-backdrop-filter: blur(10px) !important;
}

html.pdm-dark input::placeholder,
html.pdm-dark textarea::placeholder {
    color: rgba(200,200,200,0.4) !important;
}

html.pdm-dark .SearchResults,
html.pdm-dark [data-test-id="search-results"],
html.pdm-dark .zI7.iyn,
html.pdm-dark .Jea .Jea {
    background: rgba(14,14,16,0.98) !important;
    border: 1px solid rgba(255,255,255,0.08) !important;
    backdrop-filter: blur(20px) !important;
    -webkit-backdrop-filter: blur(20px) !important;
}

/* ── PINS / CARDS ────────────────────────────────────────────── */

html.pdm-dark [data-test-id="pin"],
html.pdm-dark .pin,
html.pdm-dark .pinWrapper {
    background: transparent !important;
}

html.pdm-dark .XtM,
html.pdm-dark .YRc,
html.pdm-dark .KS5,
html.pdm-dark .Pj7 {
    background: ${surface} !important;
    border-color: rgba(255,255,255,0.06) !important;
}

html.pdm-dark .Modal,
html.pdm-dark .modal,
html.pdm-dark [data-test-id="closeup-body"],
html.pdm-dark [data-test-id="pin-closeup-modal"] {
    background: ${surface} !important;
    box-shadow: 0 8px 40px rgba(0,0,0,0.8) !important;
}

/* ── NEVER TOUCH MEDIA ───────────────────────────────────────── */

html.pdm-dark img,
html.pdm-dark video,
html.pdm-dark picture,
html.pdm-dark canvas {
    filter: none !important;
    background: transparent !important;
}

/* ── SVG ICONS ───────────────────────────────────────────────── */

html.pdm-dark svg:not(:root) {
    fill: #e6e6e6 !important;
    stroke: none !important;
    background: transparent !important;
}

/* ── SAVE BUTTON ─────────────────────────────────────────────── */

html.pdm-dark button[aria-label*="Save"],
html.pdm-dark [data-test-id="save-button"],
html.pdm-dark .zI7.iyn.Hsu,
html.pdm-dark .HnA {
    background: rgba(${acc},0.88) !important;
    color: #fff !important;
    font-weight: 600 !important;
    backdrop-filter: blur(4px) !important;
    -webkit-backdrop-filter: blur(4px) !important;
    border: 1px solid rgba(255,255,255,0.2) !important;
    box-shadow: 0 2px 8px rgba(0,0,0,0.4) !important;
    transition: transform 0.15s ease, box-shadow 0.15s ease !important;
}

html.pdm-dark button[aria-label*="Save"]:hover,
html.pdm-dark [data-test-id="save-button"]:hover,
html.pdm-dark .zI7.iyn.Hsu:hover,
html.pdm-dark .HnA:hover {
    background: rgba(${acc},0.98) !important;
    transform: translateY(-1px) !important;
    box-shadow: 0 4px 16px rgba(${acc},0.4) !important;
}

/* ── MENUS / DROPDOWNS / TOOLTIPS / DIALOGS ─────────────────── */

html.pdm-dark [role="dialog"],
html.pdm-dark [role="menu"],
html.pdm-dark [role="listbox"],
html.pdm-dark [role="tooltip"],
html.pdm-dark .Overlay,
html.pdm-dark .Tooltip,
html.pdm-dark .Popover,
html.pdm-dark .Dropdown,
html.pdm-dark .dropdown,
html.pdm-dark .Menu,
html.pdm-dark .menu,
html.pdm-dark .Picker,
html.pdm-dark .picker {
    background: rgba(12,12,14,0.97) !important;
    color: #e6e6e6 !important;
    border: 1px solid rgba(255,255,255,0.09) !important;
    backdrop-filter: blur(22px) !important;
    -webkit-backdrop-filter: blur(22px) !important;
    box-shadow: 0 8px 32px rgba(0,0,0,0.55) !important;
}

html.pdm-dark .RCK,
html.pdm-dark .Hsu,
html.pdm-dark .wsz,
html.pdm-dark .QhT,
html.pdm-dark .C9q,
html.pdm-dark [data-test-id="board-dropdown"],
html.pdm-dark [data-test-id="board-picker"],
html.pdm-dark [data-test-id="dropdown"],
html.pdm-dark [data-test-id="menu"],
html.pdm-dark [data-test-id="popover"],
html.pdm-dark [data-test-id="tooltip"] {
    background: rgba(13,13,15,0.98) !important;
    border: 1px solid rgba(255,255,255,0.1) !important;
    backdrop-filter: blur(22px) !important;
    -webkit-backdrop-filter: blur(22px) !important;
}

html.pdm-dark [role="menuitem"],
html.pdm-dark [role="option"] {
    background: transparent !important;
    color: #e6e6e6 !important;
}

html.pdm-dark [role="menuitem"]:hover,
html.pdm-dark [role="option"]:hover {
    background: rgba(255,255,255,0.07) !important;
}

/* ── PROFILE HEADER ──────────────────────────────────────────── */

html.pdm-dark .ProfilePageHeader,
html.pdm-dark [data-test-id="profile-header"],
html.pdm-dark .qiB,
html.pdm-dark [data-test-id="self-profile-header"] {
    background: ${bg} !important;
}

/* ── NOTIFICATION BADGE ──────────────────────────────────────── */

html.pdm-dark [data-test-id="notifications-count"],
html.pdm-dark .badge,
html.pdm-dark .Badge,
html.pdm-dark .notificationBadge {
    background: rgba(${acc},1) !important;
    color: #fff !important;
    border: 2px solid ${bg} !important;
}

/* ── INLINE STYLE OVERRIDES ──────────────────────────────────── */

html.pdm-dark [style*="background: rgb(255, 255, 255)"],
html.pdm-dark [style*="background: rgb(250, 250, 250)"],
html.pdm-dark [style*="background: rgb(249, 249, 249)"],
html.pdm-dark [style*="background-color: rgb(255, 255, 255)"],
html.pdm-dark [style*="background-color: rgb(250, 250, 250)"],
html.pdm-dark [style*="background-color: rgb(249, 249, 249)"],
html.pdm-dark [style*="background:#fff"],
html.pdm-dark [style*="background: #fff"],
html.pdm-dark [style*="background:#ffffff"],
html.pdm-dark [style*="background: #ffffff"] {
    background-color: ${surface} !important;
}

/* ── SCROLLBARS ──────────────────────────────────────────────── */

html.pdm-dark ::-webkit-scrollbar { width: 8px; height: 8px; }
html.pdm-dark ::-webkit-scrollbar-track  { background: ${bg}; }
html.pdm-dark ::-webkit-scrollbar-thumb  { background: rgba(255,255,255,0.12); border-radius: 8px; }
html.pdm-dark ::-webkit-scrollbar-thumb:hover { background: rgba(255,255,255,0.22); }
html.pdm-dark * { scrollbar-color: rgba(255,255,255,0.12) ${bg}; }

/* Moon button */
#pdm-btn {
    position: fixed;
    bottom: 24px;
    right: 24px;
    z-index: 2147483647;
    width: 44px;
    height: 44px;
    border-radius: 50%;
    border: 1px solid rgba(255,255,255,0.14);
    background: rgba(18,18,20,0.92);
    color: #e6e6e6;
    font-size: 20px;
    cursor: pointer;
    display: flex;
    align-items: center;
    justify-content: center;
    box-shadow: 0 4px 18px rgba(0,0,0,0.5);
    backdrop-filter: blur(14px);
    -webkit-backdrop-filter: blur(14px);
    transition: transform 0.16s ease, box-shadow 0.16s ease;
    padding: 0;
    line-height: 1;
    font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
}
#pdm-btn:hover {
    transform: scale(1.1);
    box-shadow: 0 6px 24px rgba(0,0,0,0.65);
}
#pdm-btn.pdm-menu-open {
    background: rgba(38,38,42,0.98);
    border-color: rgba(255,255,255,0.22);
}

/* Settings card */
#pdm-menu {
    position: fixed;
    bottom: 80px;
    right: 24px;
    z-index: 2147483646;
    width: 220px;
    background: rgba(16,16,18,0.97);
    border: 1px solid rgba(255,255,255,0.1);
    border-radius: 16px;
    padding: 14px 16px 18px;
    box-shadow: 0 12px 40px rgba(0,0,0,0.7);
    backdrop-filter: blur(24px);
    -webkit-backdrop-filter: blur(24px);
    font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
    color: #e6e6e6;
    /* hide / show */
    opacity: 0;
    transform: translateY(8px) scale(0.97);
    pointer-events: none;
    transition: opacity 0.2s ease, transform 0.2s ease;
}
#pdm-menu.pdm-menu-visible {
    opacity: 1;
    transform: translateY(0) scale(1);
    pointer-events: all;
}

/* Section label */
.pdm-label {
    font-size: 10px;
    font-weight: 700;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    color: rgba(200,200,200,0.45);
    margin: 0 0 8px;
}

/* Divider */
.pdm-divider {
    height: 1px;
    background: rgba(255,255,255,0.07);
    margin: 14px 0;
}

/* THEME row */
.pdm-theme-row {
    display: flex;
    gap: 6px;
}
.pdm-theme-btn {
    flex: 1;
    padding: 7px 0;
    border-radius: 9px;
    border: 1px solid rgba(255,255,255,0.1);
    background: rgba(255,255,255,0.05);
    color: #bbb;
    font-size: 12px;
    cursor: pointer;
    text-align: center;
    transition: background 0.15s, border-color 0.15s, color 0.15s;
    line-height: 1.3;
}
.pdm-theme-btn:hover {
    background: rgba(255,255,255,0.1);
    color: #e6e6e6;
}
.pdm-theme-btn.pdm-active {
    background: rgba(255,255,255,0.14);
    border-color: rgba(255,255,255,0.3);
    color: #fff;
    font-weight: 600;
}

/* ACCENT row */
.pdm-accent-row {
    display: flex;
    gap: 5px;
    flex-wrap: wrap;
}
.pdm-accent-dot {
    width: 30px;
    height: 30px;
    border-radius: 50%;
    border: 2px solid transparent;
    cursor: pointer;
    font-size: 17px;
    display: flex;
    align-items: center;
    justify-content: center;
    transition: transform 0.14s ease, border-color 0.14s ease;
}
.pdm-accent-dot:hover {
    transform: scale(1.18);
}
.pdm-accent-dot.pdm-active {
    border-color: rgba(255,255,255,0.55);
    transform: scale(1.18);
}

/* CONTRAST slider */
.pdm-contrast-row {
    display: flex;
    gap: 5px;
}
.pdm-contrast-btn {
    flex: 1;
    padding: 6px 0;
    border-radius: 8px;
    border: 1px solid rgba(255,255,255,0.08);
    background: rgba(255,255,255,0.04);
    color: #aaa;
    font-size: 11px;
    cursor: pointer;
    text-align: center;
    transition: background 0.15s, border-color 0.15s, color 0.15s;
}
.pdm-contrast-btn:hover {
    background: rgba(255,255,255,0.09);
    color: #e6e6e6;
}
.pdm-contrast-btn.pdm-active {
    background: rgba(255,255,255,0.13);
    border-color: rgba(255,255,255,0.28);
    color: #fff;
    font-weight: 600;
}

/* Close button — pinned to top-right corner of card */
#pdm-close {
    position: absolute;
    top: 12px;
    right: 12px;
    width: 26px;
    height: 26px;
    border-radius: 50%;
    border: 1px solid rgba(255,255,255,0.1);
    background: rgba(255,255,255,0.06);
    color: #aaa;
    font-size: 14px;
    cursor: pointer;
    display: flex;
    align-items: center;
    justify-content: center;
    transition: background 0.14s, color 0.14s;
    padding: 0;
    line-height: 1;
}
#pdm-close:hover {
    background: rgba(255,255,255,0.12);
    color: #fff;
}

/* Toast */
#pdm-toast {
    position: fixed;
    bottom: 80px;
    right: 24px;
    z-index: 2147483645;
    background: rgba(18,18,20,0.95);
    color: #e6e6e6;
    border: 1px solid rgba(255,255,255,0.1);
    border-radius: 10px;
    padding: 7px 13px;
    font-size: 12px;
    font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
    backdrop-filter: blur(16px);
    -webkit-backdrop-filter: blur(16px);
    box-shadow: 0 4px 20px rgba(0,0,0,0.5);
    pointer-events: none;
    opacity: 0;
    transform: translateY(6px);
    transition: opacity 0.2s ease, transform 0.2s ease;
}
#pdm-toast.pdm-show {
    opacity: 1;
    transform: translateY(0);
}

`;
    }  // end buildCSS()

    const StyleManager = {

        inject() {
            this.remove();   // always rebuild from current state
            if (typeof GM_addStyle === 'function') {
                GM_addStyle(buildCSS());
                const styles = document.querySelectorAll('style');
                const el = styles[styles.length - 1];
                if (el) el.id = ID.STYLE;
            } else {
                this._createElement();
            }
        },

        _createElement() {
            const el = document.createElement('style');
            el.id = ID.STYLE;
            el.textContent = buildCSS();
            (document.head || document.documentElement).appendChild(el);
        },

        remove() {
            const el = document.getElementById(ID.STYLE);
            if (el) el.remove();
        },

        apply() {
            const html = document.documentElement;
            if (enabled) {
                html.classList.add(CLS);
                this.inject();
            } else {
                html.classList.remove(CLS);
                this.remove();
            }
        },

        ensureAlive() {
            if (!enabled) return;
            if (!document.getElementById(ID.STYLE)) this._createElement();
            if (!document.documentElement.classList.contains(CLS))
                document.documentElement.classList.add(CLS);
        },

        fixInlineStyles() {
            if (!enabled) return;
            const WHITE = ['rgb(255, 255, 255)', 'rgb(250, 250, 250)', 'rgb(249, 249, 249)'];
            const surface = surfaceFromContrast();
            document.querySelectorAll('*').forEach(el => {
                if (['IMG','VIDEO','CANVAS'].includes(el.tagName)) return;
                const bg = el.style.backgroundColor || el.style.background;
                if (bg && WHITE.some(w => bg.includes(w)))
                    el.style.setProperty('background-color', surface, 'important');
            });
        },

        fixHeader() {
            if (!enabled) return;
            const bg      = bgFromContrast();
            const surface = surfaceFromContrast();
            const sels = [
                'header[role="banner"]', 'nav[role="navigation"]',
                '[data-test-id="header"]',
                '.zCH5','.zI7','.X8m','.CCY','.S9a','.SHI','.ujU',
            ];
            sels.forEach(sel => {
                document.querySelectorAll(sel).forEach(el => {
                    el.style.setProperty('background', `linear-gradient(180deg,${surface},${bg})`, 'important');
                    el.style.setProperty('backdrop-filter', 'blur(20px)', 'important');
                    el.style.setProperty('-webkit-backdrop-filter', 'blur(20px)', 'important');
                });
            });
        },

        fixSearchInputs() {
            if (!enabled) return;
            ['input[type="search"]','input[placeholder*="Search"]','[data-test-id="search-box"]']
                .forEach(sel => {
                    document.querySelectorAll(sel).forEach(el => {
                        el.style.setProperty('background', 'rgba(28,28,30,0.95)', 'important');
                        el.style.setProperty('color', '#e6e6e6', 'important');
                    });
                });
        },
    };

    const Observer = {
        _obs: null, _raf: null,
        start() {
            this._obs = new MutationObserver(() => {
                if (this._raf) return;
                this._raf = requestAnimationFrame(() => {
                    this._raf = null;
                    StyleManager.ensureAlive();
                    StyleManager.fixInlineStyles();
                });
            });
            this._obs.observe(document.documentElement, {
                childList: true, subtree: true,
                attributes: true, attributeFilter: ['style','class'],
            });
        },
        stop() {
            if (this._obs) { this._obs.disconnect(); this._obs = null; }
            if (this._raf) { cancelAnimationFrame(this._raf); this._raf = null; }
        },
    };

    let fixerInterval = null;

    function startFixer() {
        if (fixerInterval) return;
        fixerInterval = setInterval(() => {
            StyleManager.fixHeader();
            StyleManager.fixSearchInputs();
            StyleManager.fixInlineStyles();
        }, 2500);
    }

    function stopFixer() {
        clearInterval(fixerInterval);
        fixerInterval = null;
    }

    function showToast(msg) {
        let t = document.getElementById(ID.TOAST);
        if (!t) {
            t = document.createElement('div');
            t.id = ID.TOAST;
            document.body.appendChild(t);
        }
        t.textContent = msg;
        t.classList.add('pdm-show');
        clearTimeout(t._timer);
        t._timer = setTimeout(() => t.classList.remove('pdm-show'), 1800);
    }

    let menuOpen = false;

    function buildMenu() {
        if (document.getElementById(ID.MENU)) return;

        const menu = document.createElement('div');
        menu.id = ID.MENU;

        menu.innerHTML = `

            <!-- CLOSE — absolutely positioned top-right -->
            <button id="pdm-close">✕</button>

            <!-- THEME -->
            <p class="pdm-label">Theme</p>
            <div class="pdm-theme-row">
                <button class="pdm-theme-btn" data-theme="light">☀️<br>Light</button>
                <button class="pdm-theme-btn" data-theme="dark">🌙<br>Dark</button>
            </div>

            <div class="pdm-divider"></div>

            <!-- ACCENT -->
            <p class="pdm-label">Accent colour</p>
            <div class="pdm-accent-row" id="pdm-accent-row"></div>

            <div class="pdm-divider"></div>

            <!-- CONTRAST -->
            <p class="pdm-label">Contrast</p>
            <div class="pdm-contrast-row">
                <button class="pdm-contrast-btn" data-contrast="0">Soft</button>
                <button class="pdm-contrast-btn" data-contrast="1">Mid</button>
                <button class="pdm-contrast-btn" data-contrast="2">AMOLED</button>
            </div>
        `;

        document.body.appendChild(menu);

        // Populate accent dots
        const accentRow = menu.querySelector('#pdm-accent-row');
        ACCENTS.forEach((a, i) => {
            const dot = document.createElement('button');
            dot.className = 'pdm-accent-dot' + (i === accentIndex ? ' pdm-active' : '');
            dot.textContent = a.label;
            dot.title = a.label;
            dot.addEventListener('click', () => setAccent(i));
            accentRow.appendChild(dot);
        });

        // Theme buttons
        menu.querySelectorAll('.pdm-theme-btn').forEach(btn => {
            const t = btn.dataset.theme;
            if ((t === 'dark') === enabled) btn.classList.add('pdm-active');
            btn.addEventListener('click', () => {
                const wantDark = t === 'dark';
                if (enabled !== wantDark) toggleEnabled();
                refreshMenuState();
            });
        });

        // Contrast buttons
        menu.querySelectorAll('.pdm-contrast-btn').forEach(btn => {
            const c = parseInt(btn.dataset.contrast);
            if (c === contrastLevel) btn.classList.add('pdm-active');
            btn.addEventListener('click', () => setContrast(c));
        });

        // Close button
        menu.querySelector('#pdm-close').addEventListener('click', closeMenu);
    }

    function refreshMenuState() {
        const menu = document.getElementById(ID.MENU);
        if (!menu) return;

        // Theme buttons
        menu.querySelectorAll('.pdm-theme-btn').forEach(btn => {
            btn.classList.toggle('pdm-active', (btn.dataset.theme === 'dark') === enabled);
        });

        // Accent dots
        menu.querySelectorAll('.pdm-accent-dot').forEach((dot, i) => {
            dot.classList.toggle('pdm-active', i === accentIndex);
        });

        // Contrast
        menu.querySelectorAll('.pdm-contrast-btn').forEach(btn => {
            btn.classList.toggle('pdm-active', parseInt(btn.dataset.contrast) === contrastLevel);
        });
    }

    function openMenu() {
        buildMenu();
        menuOpen = true;
        document.getElementById(ID.BTN).classList.add('pdm-menu-open');
        requestAnimationFrame(() => {
            document.getElementById(ID.MENU).classList.add('pdm-menu-visible');
        });
    }

    function closeMenu() {
        menuOpen = false;
        const btn  = document.getElementById(ID.BTN);
        const menu = document.getElementById(ID.MENU);
        if (btn)  btn.classList.remove('pdm-menu-open');
        if (menu) menu.classList.remove('pdm-menu-visible');
    }

    function toggleMenu() {
        menuOpen ? closeMenu() : openMenu();
    }

    function toggleEnabled() {
        enabled = !enabled;
        GM_setValue(KEY.ENABLED, enabled);
        StyleManager.apply();
        if (enabled) { startFixer(); Observer.start(); doFixes(); }
        else          { stopFixer(); Observer.stop(); }
        showToast(enabled ? 'Dark mode ON' : 'Dark mode OFF');
    }

    function setAccent(i) {
        accentIndex = i;
        GM_setValue(KEY.ACCENT, i);
        StyleManager.apply();
        refreshMenuState();
    }

    function setContrast(c) {
        contrastLevel = c;
        GM_setValue(KEY.CONTRAST, c);
        StyleManager.apply();
        refreshMenuState();
        if (enabled) doFixes();
    }

    function doFixes() {
        setTimeout(() => {
            StyleManager.fixHeader();
            StyleManager.fixSearchInputs();
            StyleManager.fixInlineStyles();
        }, 120);
    }

    function createButton() {
        if (document.getElementById(ID.BTN)) return;
        const btn = document.createElement('button');
        btn.id = ID.BTN;
        btn.title = 'Pinterest Dark Mode settings';
        btn.textContent = '🌙';
        btn.addEventListener('click', (e) => {
            e.stopPropagation();
            toggleMenu();
        });
        document.body.appendChild(btn);
    }

    // Close menu when clicking outside
    document.addEventListener('click', (e) => {
        if (!menuOpen) return;
        const menu = document.getElementById(ID.MENU);
        const btn  = document.getElementById(ID.BTN);
        if (menu && !menu.contains(e.target) && btn && !btn.contains(e.target)) {
            closeMenu();
        }
    });

    window.addEventListener('scroll', () => {
        if (enabled) StyleManager.fixHeader();
    }, { passive: true });

    if (typeof GM_registerMenuCommand === 'function') {
        GM_registerMenuCommand('Pinterest Dark Mode Settings', toggleMenu);
    }

    // Apply CSS immediately before page paint
    StyleManager.apply();

    function onReady() {
        createButton();
        if (enabled) {
            doFixes();
            startFixer();
            Observer.start();
        }
    }

    window.addEventListener('load', () => {
        if (enabled) {
            StyleManager.apply();
            doFixes();
        }
    });

    if (document.readyState === 'loading') {
        document.addEventListener('DOMContentLoaded', onReady, { once: true });
    } else {
        onReady();
    }

})();