Greasy Fork Minimal UI

Clean, minimal dark theme for Greasy Fork

You will need to install an extension such as Tampermonkey, Greasemonkey or Violentmonkey to install this script.

You will need to install an extension such as Tampermonkey to install this script.

You will need to install an extension such as Tampermonkey or Violentmonkey to install this script.

You will need to install an extension such as Tampermonkey or Userscripts to install this script.

You will need to install an extension such as Tampermonkey to install this script.

You will need to install a user script manager extension to install this script.

(Tôi đã có Trình quản lý tập lệnh người dùng, hãy cài đặt nó!)

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

You will need to install a user style manager extension to install this style.

You will need to install a user style manager extension to install this style.

You will need to install a user style manager extension to install this style.

(I already have a user style manager, let me install it!)

// ==UserScript==
// @name         Greasy Fork Minimal UI
// @namespace    https://greasyfork.org/
// @version      2.5.0
// @description  Clean, minimal dark theme for Greasy Fork
// @author       quantavil
// @license      MIT
// @match        https://greasyfork.org/*
// @match        https://*.greasyfork.org/*
// @icon         https://greasyfork.org/vite/assets/blacklogo96-CxYTSM_T.png
// @grant        GM_addStyle
// @run-at       document-start
// ==/UserScript==

(function() {
    'use strict';

    // ========== CRITICAL: Prevent FOUC Immediately ==========
    // This runs BEFORE anything else - hide everything instantly
    
    // 1. Set background on html element directly (fastest possible)
    document.documentElement.style.cssText = 'background:#09090b!important;';
    
    // 2. Create critical CSS to hide all content
    const criticalStyle = document.createElement('style');
    criticalStyle.id = 'gf-critical';
    criticalStyle.textContent = `
        html {
            background: #09090b !important;
        }
        html:not(.gf-ready) body {
            opacity: 0 !important;
            visibility: hidden !important;
            pointer-events: none !important;
        }
        html:not(.gf-ready)::before {
            content: '';
            position: fixed;
            inset: 0;
            background: #09090b;
            z-index: 999999;
        }
        html.gf-ready body {
            opacity: 1 !important;
            visibility: visible !important;
            pointer-events: auto !important;
            transition: opacity 0.12s ease-out !important;
        }
    `;
    
    // 3. Insert at the earliest possible point
    document.documentElement.insertBefore(criticalStyle, document.documentElement.firstChild);

    // ========== Full CSS ==========
    const css = `
        /* ========== Variables ========== */
        :root {
            --bg-0: #09090b;
            --bg-1: #121215;
            --bg-2: #1a1a1f;
            --bg-3: #242429;
            --border: #2a2a30;
            --border-hover: #3a3a42;
            --text-1: #f0f0f2;
            --text-2: #a1a1aa;
            --text-3: #71717a;
            --accent: #22c55e;
            --accent-hover: #16a34a;
            --accent-dim: rgba(34, 197, 94, 0.12);
            --accent-glow: rgba(34, 197, 94, 0.25);
            --red: #ef4444;
            --yellow: #facc15;
            --blue: #3b82f6;
            --purple: #a855f7;
            --radius: 6px;
            --font: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
            --mono: ui-monospace, 'SF Mono', Consolas, monospace;
        }

        /* ========== Base ========== */
        html, body {
            background: var(--bg-0) !important;
            color: var(--text-1) !important;
            font-family: var(--font) !important;
        }
        body {
            font-size: 15px;
            line-height: 1.6;
        }

        a { color: var(--accent); text-decoration: none; transition: color 0.15s; }
        a:hover { color: var(--accent-hover); }
        ::selection { background: var(--accent-glow); color: var(--text-1); }

        ::-webkit-scrollbar { width: 10px; height: 10px; }
        ::-webkit-scrollbar-track { background: var(--bg-0); }
        ::-webkit-scrollbar-thumb { background: var(--bg-3); border-radius: 5px; }
        ::-webkit-scrollbar-thumb:hover { background: var(--text-3); }

        /* ========== Hide Ads Completely ========== */
        .ad-entry,
        .ad,
        #script-list-ea,
        .ethical-ads,
        [data-ea-publisher] {
            display: none !important;
            visibility: hidden !important;
            height: 0 !important;
            overflow: hidden !important;
        }

        /* ========== Header ========== */
        #main-header {
            background: var(--bg-1) !important;
            border-bottom: 1px solid var(--border) !important;
            position: sticky !important;
            top: 0;
            z-index: 1000;
        }

        #main-header > .width-constraint {
            max-width: 1100px;
            margin: 0 auto;
            padding: 12px 24px;
            display: flex;
            align-items: center;
            justify-content: space-between;
        }

        #site-name { display: flex; align-items: center; gap: 12px; }
        #site-name img { width: 36px !important; height: 36px !important; transition: transform 0.2s; }
        #site-name:hover img { transform: scale(1.05); }
        #site-name-text h1 { margin: 0; font-size: 20px; font-weight: 700; }
        #site-name-text h1 a { color: var(--text-1) !important; }

        #site-nav { display: flex; align-items: center; gap: 8px; }
        #site-nav nav { display: flex; gap: 4px; list-style: none; margin: 0; padding: 0; }
        #site-nav nav > li { position: relative; }
        #site-nav nav > li > a {
            padding: 8px 14px;
            border-radius: var(--radius);
            color: var(--text-2) !important;
            font-size: 14px;
            font-weight: 500;
            transition: all 0.15s;
        }
        #site-nav nav > li > a:hover { background: var(--bg-2); color: var(--text-1) !important; }
        #site-nav nav > li.scripts-index-link > a { background: var(--accent-dim); color: var(--accent) !important; }

        #site-nav nav > li.with-submenu > nav {
            position: absolute;
            top: calc(100% + 4px);
            right: 0;
            background: var(--bg-2);
            border: 1px solid var(--border);
            border-radius: var(--radius);
            padding: 6px;
            min-width: 170px;
            opacity: 0;
            visibility: hidden;
            transform: translateY(-8px);
            transition: all 0.2s;
            z-index: 100;
        }
        #site-nav nav > li.with-submenu:hover > nav { opacity: 1; visibility: visible; transform: translateY(0); }
        #site-nav nav > li.with-submenu > nav > li > a {
            display: block;
            padding: 8px 12px;
            border-radius: 4px;
            color: var(--text-2) !important;
            font-size: 13px;
        }
        #site-nav nav > li.with-submenu > nav > li > a:hover { background: var(--bg-3); color: var(--text-1) !important; }

        #nav-user-info { display: flex; align-items: center; gap: 12px; font-size: 14px; }
        #nav-user-info .notification-widget {
            padding: 4px 10px;
            background: var(--red);
            color: #fff !important;
            border-radius: 12px;
            font-size: 12px;
            font-weight: 600;
        }
        #nav-user-info .user-profile-link a { color: var(--text-1) !important; font-weight: 500; }
        #nav-user-info .sign-out-link a { color: var(--text-3) !important; font-size: 13px; }

        .language-selector-locale {
            background: var(--bg-2) !important;
            border: 1px solid var(--border) !important;
            border-radius: var(--radius);
            color: var(--text-2) !important;
            padding: 6px 10px;
            font-size: 12px;
        }

        #mobile-nav { display: none !important; }

        /* ========== Layout ========== */
        .width-constraint { max-width: 1100px !important; margin: 0 auto !important; padding: 24px !important; }
        .sidebarred { display: block !important; }
        .sidebar, .open-sidebar, .close-sidebar { display: none !important; }
        .sidebarred-main-content { max-width: 100%; }

        /* ========== Script List ========== */
        #browse-script-list {
            list-style: none !important;
            padding: 0 !important;
            margin: 0 !important;
            display: flex;
            flex-direction: column;
            gap: 12px;
        }

        #browse-script-list > li {
            background: var(--bg-1);
            border: 1px solid var(--border);
            border-radius: var(--radius);
            padding: 20px 24px;
            transition: border-color 0.2s, background 0.2s;
        }
        #browse-script-list > li:hover { border-color: var(--accent); background: var(--bg-2); }

        #browse-script-list article h2 {
            margin: 0 0 10px 0;
            font-size: 17px;
            font-weight: 600;
            display: flex;
            align-items: center;
            gap: 10px;
            flex-wrap: wrap;
        }
        #browse-script-list article h2 .script-link { color: var(--text-1) !important; }
        #browse-script-list article h2 .script-link:hover { color: var(--accent) !important; }

        .badge { padding: 4px 8px; border-radius: 4px; font-size: 10px; font-weight: 700; text-transform: uppercase; }
        .badge-js { background: var(--accent-dim); color: var(--accent); }
        .badge-css { background: rgba(168, 85, 247, 0.15); color: var(--purple); }

        .name-description-separator { display: none !important; }
        .script-description { color: var(--text-2) !important; font-size: 14px; margin-bottom: 12px; }

        /* List Stats */
        .inline-script-stats { display: flex; flex-wrap: wrap; gap: 16px; margin: 0; }
        .inline-script-stats dt { display: none !important; }
        .inline-script-stats dd { margin: 0; font-size: 13px; color: var(--text-3); display: flex; align-items: center; gap: 5px; }
        .inline-script-stats dd span { color: var(--text-2); }

        .script-list-author::before { content: ''; }
        .script-list-daily-installs::before { content: '📥 '; }
        .script-list-total-installs::before { content: '📊 '; }
        .script-list-ratings::before { content: '⭐ '; }
        .script-list-updated-date::before { content: '🔄 '; }
        .script-list-created-date { display: none !important; }

        .good-rating-count { color: var(--accent) !important; font-weight: 600; }
        .ok-rating-count { color: var(--yellow) !important; }
        .bad-rating-count { color: var(--red) !important; }
        .script-list-author a { color: var(--accent) !important; font-weight: 500; }

        /* ========== Pagination ========== */
        .pagination,
        .pagy.series-nav {
            display: flex;
            align-items: center;
            justify-content: center;
            gap: 6px;
            margin-top: 28px;
            padding-top: 24px;
            border-top: 1px solid var(--border);
        }
        .pagination a,
        .pagination span,
        .pagination em,
        .pagy.series-nav a, 
        .pagy.series-nav [role="link"] {
            min-width: 38px;
            height: 38px;
            display: flex;
            align-items: center;
            justify-content: center;
            background: var(--bg-1);
            border: 1px solid var(--border);
            border-radius: var(--radius);
            color: var(--text-2) !important;
            font-size: 14px;
            font-weight: 500;
            font-style: normal;
            transition: all 0.15s;
        }
        .pagination a:hover,
        .pagy.series-nav a:hover { 
            border-color: var(--accent); 
            color: var(--accent) !important; 
            background: var(--accent-dim); 
        }
        .pagination .current,
        .pagination em.current,
        .pagy.series-nav [aria-current="page"] { 
            background: var(--accent) !important; 
            border-color: var(--accent) !important; 
            color: #000 !important; 
            font-weight: 600; 
        }
        .pagination .disabled,
        .pagy.series-nav [aria-disabled="true"] { 
            opacity: 0.35; 
            pointer-events: none; 
        }

        /* ========== Script Detail Page ========== */
        #script-info {
            background: var(--bg-1);
            border: 1px solid var(--border);
            border-radius: var(--radius);
            overflow: hidden;
        }

        /* ========== Tabs ========== */
        #script-links.tabs {
            display: flex;
            flex-wrap: wrap;
            gap: 0;
            margin: 0;
            padding: 0;
            list-style: none;
            background: var(--bg-2);
            border-bottom: 1px solid var(--border);
            overflow: visible;
        }

        #script-links.tabs li {
            flex-shrink: 0;
        }

        #script-links.tabs li span,
        #script-links.tabs li a span {
            display: block;
            padding: 12px 16px;
            font-size: 13px;
            font-weight: 500;
            color: var(--text-2);
            white-space: nowrap;
            transition: color 0.15s, background 0.15s;
        }

        #script-links.tabs li a:hover span {
            color: var(--text-1);
            background: var(--bg-3);
        }

        #script-links.tabs li.current {
            background: var(--bg-1);
            border-bottom: 2px solid var(--accent);
            margin-bottom: -1px;
        }

        #script-links.tabs li.current span {
            color: var(--accent);
            font-weight: 600;
        }

        #script-info > header { padding: 28px; border-bottom: 1px solid var(--border); }
        #script-info > header h2 { margin: 0 0 12px 0; font-size: 26px; font-weight: 700; color: var(--text-1); }
        #script-info #script-description { color: var(--text-2); font-size: 16px; margin: 0; }

        #script-content { padding: 28px; }

        /* Install Button */
        #install-area { display: inline-flex; align-items: center; gap: 12px; margin-bottom: 24px; }
        #install-area .install-link {
            display: inline-flex;
            align-items: center;
            gap: 8px;
            padding: 14px 28px;
            background: var(--accent);
            color: #000 !important;
            font-size: 15px;
            font-weight: 700;
            border-radius: var(--radius);
            transition: all 0.2s;
        }
        #install-area .install-link:hover { background: var(--accent-hover); transform: translateY(-1px); }
        #install-area .install-link::before { content: '↓'; font-size: 18px; font-weight: 700; }
        #install-area .install-help-link {
            width: 32px;
            height: 32px;
            display: flex;
            align-items: center;
            justify-content: center;
            background: var(--bg-2);
            border: 1px solid var(--border);
            border-radius: 50%;
            color: var(--text-3) !important;
            font-size: 13px;
            font-weight: 600;
        }

        #script-feedback-suggestion {
            padding: 16px 20px;
            background: var(--bg-2);
            border-left: 3px solid var(--accent);
            border-radius: 0 var(--radius) var(--radius) 0;
            margin-bottom: 24px;
            font-size: 14px;
            color: var(--text-2);
        }

        /* ========== Script Meta Block ========== */
        .script-meta-block {
            background: var(--bg-2);
            border-radius: var(--radius);
            padding: 24px;
            margin-bottom: 24px;
        }

        .script-meta-block #script-stats.inline-script-stats {
            display: grid;
            grid-template-columns: max-content 1fr;
            gap: 10px 24px;
            align-items: baseline;
        }

        .script-meta-block #script-stats.inline-script-stats > dt {
            display: block !important;
            font-size: 12px;
            font-weight: 600;
            text-transform: uppercase;
            letter-spacing: 0.3px;
            color: var(--text-3);
            padding: 4px 0;
        }

        .script-meta-block #script-stats.inline-script-stats > dd {
            font-size: 14px;
            color: var(--text-1);
            padding: 4px 0;
            margin: 0;
        }

        .script-meta-block #script-stats.inline-script-stats > dd::before {
            display: none !important;
        }

        .script-meta-block #script-stats.inline-script-stats > dd a {
            color: var(--accent) !important;
        }

        .script-meta-block #script-stats .good-rating-count,
        .script-meta-block #script-stats .ok-rating-count,
        .script-meta-block #script-stats .bad-rating-count {
            display: inline-block;
            padding: 2px 8px;
            border-radius: 4px;
            font-size: 13px;
            margin-right: 4px;
        }
        .script-meta-block #script-stats .good-rating-count { background: var(--accent-dim); }
        .script-meta-block #script-stats .ok-rating-count { background: rgba(250, 204, 21, 0.15); }
        .script-meta-block #script-stats .bad-rating-count { background: rgba(239, 68, 68, 0.15); }

        .script-meta-block .browser-compatible {
            width: 22px;
            height: 22px;
            margin-right: 6px;
            vertical-align: middle;
            filter: brightness(0.9);
        }

        /* Applies-to section */
        .script-show-applies-to .block-list {
            display: flex;
            flex-wrap: wrap;
            gap: 8px;
            list-style: none;
            padding: 0;
            margin: 0;
        }
        .script-show-applies-to .block-list.expandable { max-height: none !important; height: auto !important; }
        .script-show-applies-to .block-list li a {
            display: inline-block;
            padding: 5px 12px;
            background: var(--bg-3);
            border-radius: 20px;
            font-size: 12px;
            color: var(--text-2) !important;
        }
        .script-show-applies-to .block-list li a:hover { background: var(--accent-dim); color: var(--accent) !important; }
        .script-show-applies-to .expander { display: none !important; }

        /* Additional Info */
        #additional-info {
            padding: 24px;
            background: var(--bg-2);
            border-radius: var(--radius);
            margin-top: 24px;
            font-size: 15px;
            line-height: 1.7;
            color: var(--text-2);
        }
        #additional-info p { margin: 0 0 16px 0; }
        #additional-info p:last-child { margin-bottom: 0; }
        #additional-info a { color: var(--accent) !important; }
        #additional-info strong { color: var(--text-1); font-weight: 600; }
        #additional-info code {
            padding: 3px 8px;
            background: var(--bg-1);
            border-radius: 4px;
            font-family: var(--mono);
            font-size: 13px;
            color: var(--accent);
        }
        #additional-info pre {
            padding: 16px;
            background: var(--bg-1);
            border-radius: var(--radius);
            overflow-x: auto;
            margin: 0 0 16px 0;
        }
        #additional-info pre code { padding: 0; background: none; color: var(--text-1); }
        #additional-info img { max-width: 100%; border-radius: var(--radius); margin: 16px 0; }

        .user-screenshots { display: grid; grid-template-columns: repeat(auto-fill, minmax(200px, 1fr)); gap: 16px; margin-top: 20px; }
        .user-screenshots a { display: block; border-radius: var(--radius); overflow: hidden; border: 1px solid var(--border); transition: all 0.2s; }
        .user-screenshots a:hover { border-color: var(--accent); transform: scale(1.02); }
        .user-screenshots img { width: 100%; display: block; margin: 0 !important; }

        /* ========== Control Bar ========== */
        #gf-control-bar {
            display: flex;
            align-items: center;
            gap: 16px;
            margin-bottom: 20px;
            padding: 16px 20px;
            background: var(--bg-1);
            border: 1px solid var(--border);
            border-radius: var(--radius);
            flex-wrap: wrap;
        }

        #gf-control-bar .cb-section {
            display: flex;
            align-items: center;
            gap: 10px;
        }

        #gf-control-bar .cb-label {
            font-size: 12px;
            font-weight: 600;
            color: var(--text-3);
            text-transform: uppercase;
            letter-spacing: 0.5px;
            white-space: nowrap;
        }

        #gf-control-bar select {
            background: var(--bg-2);
            border: 1px solid var(--border);
            border-radius: var(--radius);
            padding: 8px 12px;
            font-size: 13px;
            color: var(--text-1);
            cursor: pointer;
            outline: none;
        }
        #gf-control-bar select:focus { border-color: var(--accent); }

        #gf-control-bar .cb-divider {
            width: 1px;
            height: 28px;
            background: var(--border);
        }

        /* Slider Styles */
        #gf-control-bar .slider-group {
            display: flex;
            align-items: center;
            gap: 8px;
        }

        #gf-control-bar .slider-container {
            display: flex;
            align-items: center;
            gap: 8px;
        }

        #gf-control-bar input[type="range"] {
            -webkit-appearance: none;
            width: 100px;
            height: 6px;
            background: var(--bg-3);
            border-radius: 3px;
            outline: none;
            cursor: pointer;
        }

        #gf-control-bar input[type="range"]::-webkit-slider-thumb {
            -webkit-appearance: none;
            width: 16px;
            height: 16px;
            background: var(--accent);
            border-radius: 50%;
            cursor: pointer;
            transition: transform 0.15s;
        }

        #gf-control-bar input[type="range"]::-webkit-slider-thumb:hover {
            transform: scale(1.15);
        }

        #gf-control-bar input[type="range"]::-moz-range-thumb {
            width: 16px;
            height: 16px;
            background: var(--accent);
            border-radius: 50%;
            border: none;
            cursor: pointer;
        }

        #gf-control-bar .slider-value {
            min-width: 55px;
            padding: 4px 8px;
            background: var(--bg-2);
            border-radius: 4px;
            font-size: 12px;
            font-weight: 600;
            color: var(--text-1);
            text-align: center;
            font-family: var(--mono);
        }

        #gf-control-bar .cb-stats {
            margin-left: auto;
            font-size: 13px;
            color: var(--text-3);
        }
        #gf-control-bar .cb-stats strong { color: var(--accent); font-weight: 600; }

        /* ========== Scroll Top Button ========== */
        #gf-scroll-top {
            position: fixed;
            bottom: 24px;
            right: 24px;
            width: 44px;
            height: 44px;
            background: var(--bg-2);
            border: 1px solid var(--border);
            border-radius: var(--radius);
            color: var(--text-2);
            font-size: 18px;
            cursor: pointer;
            display: flex;
            align-items: center;
            justify-content: center;
            z-index: 999;
            opacity: 0;
            visibility: hidden;
            transform: translateY(10px);
            transition: all 0.2s;
        }
        #gf-scroll-top.show { opacity: 1; visibility: visible; transform: translateY(0); }
        #gf-scroll-top:hover { border-color: var(--accent); color: var(--accent); background: var(--accent-dim); }

        /* ========== Forms & Inputs ========== */
        input[type="text"],
        input[type="search"],
        input[type="email"],
        input[type="password"],
        textarea,
        select {
            background: var(--bg-2) !important;
            border: 1px solid var(--border) !important;
            border-radius: var(--radius) !important;
            color: var(--text-1) !important;
            padding: 10px 14px !important;
            font-size: 14px !important;
            outline: none !important;
            transition: border-color 0.15s !important;
        }

        input:focus,
        textarea:focus,
        select:focus {
            border-color: var(--accent) !important;
        }

        button,
        input[type="submit"],
        .button {
            background: var(--bg-3) !important;
            border: 1px solid var(--border) !important;
            border-radius: var(--radius) !important;
            color: var(--text-1) !important;
            padding: 10px 18px !important;
            font-size: 14px !important;
            font-weight: 500 !important;
            cursor: pointer !important;
            transition: all 0.15s !important;
        }

        button:hover,
        input[type="submit"]:hover,
        .button:hover {
            background: var(--bg-2) !important;
            border-color: var(--border-hover) !important;
        }

        /* ========== Responsive ========== */
        @media (max-width: 768px) {
            #main-header > .width-constraint { padding: 10px 16px; }
            #site-nav { display: none; }
            #mobile-nav { display: block !important; }
            .width-constraint { padding: 16px !important; }
            #browse-script-list > li { padding: 16px 18px; }
            #browse-script-list article h2 { font-size: 15px; }
            #script-info > header { padding: 20px; }
            #script-info > header h2 { font-size: 20px; }
            #script-content { padding: 20px; }
            .script-meta-block { padding: 16px; }
            .script-meta-block #script-stats.inline-script-stats { gap: 6px 16px; }
            #gf-control-bar { gap: 12px; }
            #gf-control-bar input[type="range"] { width: 80px; }
            #gf-control-bar .cb-stats { width: 100%; margin-left: 0; margin-top: 8px; }
            #script-links.tabs li span,
            #script-links.tabs li a span { padding: 10px 12px; font-size: 12px; }
        }

        @media (max-width: 480px) {
            #script-links.tabs { flex-wrap: nowrap; overflow-x: auto; -webkit-overflow-scrolling: touch; }
            #script-links.tabs::-webkit-scrollbar { display: none; }
            #script-links.tabs { -ms-overflow-style: none; scrollbar-width: none; }
        }

        /* ========== Hide junk ========== */
        #pagetual-sideController, .umdl-fab, .umdl-pick, .umdl-toast,
        .sae-bubble, .sae-palette { display: none !important; }
    `;

    // ========== Apply Main CSS Immediately ==========
    // Don't wait for DOM - inject now
    function injectMainCSS() {
        const style = document.createElement('style');
        style.id = 'gf-main-styles';
        style.textContent = css;
        
        // Try head first, fall back to documentElement
        const target = document.head || document.documentElement;
        target.appendChild(style);
    }
    
    // Inject immediately
    injectMainCSS();
    
    // Also use GM_addStyle as backup
    if (typeof GM_addStyle !== 'undefined') {
        try {
            GM_addStyle(css);
        } catch (e) {
            // Already injected above
        }
    }

    // ========== Reveal Page After Styles Applied ==========
    function revealPage() {
        // Small delay to ensure styles are painted
        requestAnimationFrame(() => {
            requestAnimationFrame(() => {
                document.documentElement.classList.add('gf-ready');
            });
        });
    }

    // ========== Logarithmic Scale Helpers ==========
    const LOG_POWER = 3; // Controls curve steepness (higher = more log-like)
    
    function sliderToLogValue(position, max) {
        // Convert linear slider position (0-100) to logarithmic value
        // Uses power function: value = max * (position/100)^power
        if (position <= 0) return 0;
        if (position >= 100) return max;
        return Math.round(max * Math.pow(position / 100, LOG_POWER));
    }
    
    function logValueToSlider(value, max) {
        // Convert logarithmic value back to slider position
        if (value <= 0) return 0;
        if (value >= max) return 100;
        return Math.round(100 * Math.pow(value / max, 1 / LOG_POWER));
    }

    // ========== Utility Functions ==========
    function formatNumber(n) {
        if (n >= 1000000) return (n / 1000000).toFixed(1).replace(/\.0$/, '') + 'M';
        if (n >= 1000) return (n / 1000).toFixed(1).replace(/\.0$/, '') + 'K';
        return n.toString();
    }

    // ========== Initialization ==========
    function init() {
        revealPage();
        expandCollapsed();
        addScrollTop();
        
        if (document.querySelector('#browse-script-list')) {
            addControlBar();
        }
    }

    function expandCollapsed() {
        document.querySelectorAll('.expandable.collapsed').forEach(el => {
            el.style.maxHeight = 'none';
            el.style.height = 'auto';
            el.classList.remove('collapsed');
        });
        document.querySelectorAll('.expander').forEach(el => el.style.display = 'none');
    }

    function addScrollTop() {
        if (document.getElementById('gf-scroll-top')) return;
        
        const btn = document.createElement('button');
        btn.id = 'gf-scroll-top';
        btn.innerHTML = '↑';
        btn.title = 'Scroll to top (G)';
        btn.onclick = () => window.scrollTo({ top: 0, behavior: 'smooth' });
        document.body.appendChild(btn);

        let ticking = false;
        window.addEventListener('scroll', () => {
            if (!ticking) {
                requestAnimationFrame(() => {
                    btn.classList.toggle('show', window.scrollY > 400);
                    ticking = false;
                });
                ticking = true;
            }
        }, { passive: true });
    }

    function addControlBar() {
        const main = document.querySelector('.sidebarred-main-content');
        if (!main || document.getElementById('gf-control-bar')) return;

        const list = document.getElementById('browse-script-list');
        const scripts = Array.from(list?.querySelectorAll('li[data-script-id]') || []);
        if (!scripts.length) return;

        // Get actual max values from data
        let maxDaily = 0, maxTotal = 0;
        scripts.forEach(li => {
            const daily = parseInt(li.dataset.scriptDailyInstalls) || 0;
            const total = parseInt(li.dataset.scriptTotalInstalls) || 0;
            if (daily > maxDaily) maxDaily = daily;
            if (total > maxTotal) maxTotal = total;
        });

        // Ensure minimum ranges
        maxDaily = Math.max(maxDaily, 100);
        maxTotal = Math.max(maxTotal, 1000);

        // Get current sort from URL
        const urlParams = new URLSearchParams(window.location.search);
        const currentSort = urlParams.get('sort') || '';

        const bar = document.createElement('div');
        bar.id = 'gf-control-bar';
        bar.innerHTML = `
            <div class="cb-section">
                <span class="cb-label">Sort</span>
                <select id="gf-sort">
                    <option value="" ${currentSort === '' ? 'selected' : ''}>Daily Installs</option>
                    <option value="total_installs" ${currentSort === 'total_installs' ? 'selected' : ''}>Total Installs</option>
                    <option value="ratings" ${currentSort === 'ratings' ? 'selected' : ''}>Ratings</option>
                    <option value="created" ${currentSort === 'created' ? 'selected' : ''}>Created Date</option>
                    <option value="updated" ${currentSort === 'updated' ? 'selected' : ''}>Updated Date</option>
                    <option value="name" ${currentSort === 'name' ? 'selected' : ''}>Name</option>
                </select>
            </div>
            <div class="cb-divider"></div>
            <div class="cb-section slider-group">
                <span class="cb-label">Daily ≥</span>
                <div class="slider-container">
                    <input type="range" id="gf-daily-slider" min="0" max="100" value="0">
                    <span class="slider-value" id="gf-daily-value">0</span>
                </div>
            </div>
            <div class="cb-section slider-group">
                <span class="cb-label">Total ≥</span>
                <div class="slider-container">
                    <input type="range" id="gf-total-slider" min="0" max="100" value="0">
                    <span class="slider-value" id="gf-total-value">0</span>
                </div>
            </div>
            <div class="cb-stats">
                <strong id="gf-visible">${scripts.length}</strong> / ${scripts.length} scripts
            </div>
        `;
        main.insertBefore(bar, main.firstChild);

        // Sort handler
        const sortSelect = document.getElementById('gf-sort');
        sortSelect.onchange = function() {
            const url = new URL(window.location.href);
            if (this.value) {
                url.searchParams.set('sort', this.value);
            } else {
                url.searchParams.delete('sort');
            }
            window.location.href = url.toString();
        };

        const dailySlider = document.getElementById('gf-daily-slider');
        const totalSlider = document.getElementById('gf-total-slider');
        const dailyValue = document.getElementById('gf-daily-value');
        const totalValue = document.getElementById('gf-total-value');
        const visibleCount = document.getElementById('gf-visible');

        // Store max values for log calculations
        const dailyMaxVal = maxDaily;
        const totalMaxVal = maxTotal;

        function applyFilters() {
            // Convert slider positions (0-100) to actual values using log scale
            const dailyPos = parseInt(dailySlider.value) || 0;
            const totalPos = parseInt(totalSlider.value) || 0;
            
            // Daily uses linear scale (smaller range)
            const minDaily = sliderToLogValue(dailyPos, dailyMaxVal);
            // Total uses logarithmic scale (larger range)
            const minTotal = sliderToLogValue(totalPos, totalMaxVal);
            
            let visible = 0;

            scripts.forEach(li => {
                const daily = parseInt(li.dataset.scriptDailyInstalls) || 0;
                const total = parseInt(li.dataset.scriptTotalInstalls) || 0;
                const show = daily >= minDaily && total >= minTotal;
                li.style.display = show ? '' : 'none';
                if (show) visible++;
            });

            dailyValue.textContent = formatNumber(minDaily);
            totalValue.textContent = formatNumber(minTotal);
            visibleCount.textContent = visible;
        }

        // Debounce for smoother performance
        let filterTimeout;
        function debouncedFilter() {
            clearTimeout(filterTimeout);
            filterTimeout = setTimeout(applyFilters, 16);
        }

        dailySlider.oninput = debouncedFilter;
        totalSlider.oninput = debouncedFilter;
        
        // Initialize display values
        applyFilters();
    }

    // ========== Keyboard Shortcuts ==========
    document.addEventListener('keydown', e => {
        if (e.target.tagName === 'INPUT' || e.target.tagName === 'TEXTAREA' || e.target.isContentEditable) return;
        
        switch(e.key.toLowerCase()) {
            case '/':
                e.preventDefault();
                const search = document.querySelector('.sidebar-search input') || 
                              document.querySelector('input[type="search"]') ||
                              document.querySelector('input[name="q"]');
                search?.focus();
                break;
            case 'i':
                document.querySelector('.install-link')?.click();
                break;
            case 'g':
                window.scrollTo({ top: 0, behavior: 'smooth' });
                break;
        }
    });

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