GrometsPlaza

Modernizes layout/typography, adds auto dark/light, improves readability across sub-sites

// ==UserScript==
// @name            GrometsPlaza
// @namespace       Gromet
// @description     Modernizes layout/typography, adds auto dark/light, improves readability across sub-sites
// @copyright       tightnshiny
// @icon            https://grometsplaza.net/favicon.ico
//
// @match           https://grometsplaza.net/*
// @match           https://www.grometsplaza.net/*
// @match           https://www.selfbound.net/*
// @match           https://www.mummified.net/*
// @match           https://www.boundstories.net/*
// @match           https://www.latexstories.net/*
// @match           https://www.packagedstories.net/*
// @match           https://www.dollstories.net/*
// @match           https://www.maidbots.net/*
// @match           https://www.trashcanstories.net/*
// @match           https://www.devouredstories.net/*
//
// @grant		none
// @run-at		document-start
//
// @license MIT
// @version         1.0.0
// ==/UserScript==

(function() {
    'use strict';

    // Settings
    const STORAGE_KEY = 'gp-theme'; // 'auto' | 'dark' | 'light'
    const READ_KEY = 'gp-reading'; // 'narrow' | 'wide'
    const DATA_ATTR = 'data-gp-theme';
    const READING_ATTR = 'data-gp-reading';
    const prefersDark = window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)');

    function getStoredMode() {
        try {
            const v = localStorage.getItem(STORAGE_KEY);
            return v === 'dark' || v === 'light' || v === 'auto' ? v : null;
        } catch (_) { return null; }
    }

    function setStoredMode(v) {
        try { localStorage.setItem(STORAGE_KEY, v); } catch (_) {}
    }

    function computeEffective(mode) {
        if (mode === 'dark' || mode === 'light') return mode;
        return prefersDark && prefersDark.matches ? 'dark' : 'light';
    }

    function applyThemeAttr(mode) {
        const effective = computeEffective(mode);
        document.documentElement.setAttribute(DATA_ATTR, effective);
        try {
            document.documentElement.style.colorScheme = effective === 'dark' ? 'dark' : 'light';
        } catch (_) {}
    }

    // Early paint: set initial theme and minimal background to reduce FOUC
    const initMode = getStoredMode() || 'auto';
    applyThemeAttr(initMode);
    try {
        if (computeEffective(initMode) === 'dark') {
            document.documentElement.style.backgroundColor = '#0f1115';
        }
    } catch (_) {}

    // React to OS theme changes in auto mode
    if (prefersDark && typeof prefersDark.addEventListener === 'function') {
        prefersDark.addEventListener('change', () => {
            if ((getStoredMode() || 'auto') === 'auto') applyThemeAttr('auto');
        });
    }

    // Reading width
    function getReadingMode() {
        try {
            const v = localStorage.getItem(READ_KEY);
            return v === 'wide' ? 'wide' : 'narrow';
        } catch (_) { return 'narrow'; }
    }
    function setReadingMode(v) {
        try { localStorage.setItem(READ_KEY, v); } catch (_) {}
    }
    function applyReadingAttr(mode) {
        const m = mode === 'wide' ? 'wide' : 'narrow';
        document.documentElement.setAttribute(READING_ATTR, m);
    }
    applyReadingAttr(getReadingMode());

    // Accent per host
    function applyHostAccent() {
        const host = (location.hostname || '').replace(/^www\./, '');
        const map = {
            'grometsplaza.net': '#2b90d9',
            'boundstories.net': '#ef4444',
            'selfbound.net': '#3b82f6',
            'mummified.net': '#a855f7',
            'latexstories.net': '#64748b',
            'packagedstories.net': '#14b8a6',
            'dollstories.net': '#ec4899',
            'maidbots.net': '#06b6d4',
            'trashcanstories.net': '#f97316',
            'devouredstories.net': '#10b981'
        };
        const accent = map[host] || '#2b90d9';
        try { document.documentElement.style.setProperty('--gp-accent', accent); } catch (_) {}
        document.documentElement.setAttribute('data-gp-host', host);
        // Mark legacy subsites that use older fixed layouts
        const legacyHosts = new Set([
          'boundstories.net','selfbound.net','mummified.net','latexstories.net',
          'packagedstories.net','dollstories.net','maidbots.net','trashcanstories.net','devouredstories.net'
        ]);
        document.documentElement.setAttribute('data-gp-legacy', legacyHosts.has(host) ? '1' : '0');
    }

    function applyPathContext() {
        const path = (location.pathname || '').toLowerCase();
        const isWorld = /(^|\/)world\//.test(path);
        document.documentElement.setAttribute('data-gp-world', isWorld ? '1' : '0');
    }
    applyPathContext();

    // Mark root subpages that should use the "home-like" layout tweaks
    function applyMainlikeContext() {
        const path = (location.pathname || '').toLowerCase();
        const mainlike = (
            /^\/search\.html$/.test(path) ||
            /^\/links\.html$/.test(path) ||
            /^\/pages\/(writers|storycodes)\.html$/.test(path) ||
            /^\/author_[a-z]+\.html$/.test(path)
        );
        document.documentElement.setAttribute('data-gp-mainlike', mainlike ? '1' : '0');
    }
    applyMainlikeContext();
    applyHostAccent();

    // Inject a viewport meta for better mobile layout
    function ensureViewport() {
        if (document.querySelector('meta[name="viewport"]')) return;
        const meta = document.createElement('meta');
        meta.name = 'viewport';
        meta.content = 'width=device-width, initial-scale=1';
        (document.head || document.documentElement).appendChild(meta);
    }

    // Critical CSS to normalize backgrounds fast
    function injectCriticalStyles() {
        if (document.getElementById('gp-critical')) return;
        const style = document.createElement('style');
        style.id = 'gp-critical';
        style.textContent = `
          html[${DATA_ATTR}="dark"], html[${DATA_ATTR}="dark"] body { background:#0f1115 !important; }
        `;
        const root = document.documentElement;
        if (root && root.firstChild) root.insertBefore(style, root.firstChild); else root.appendChild(style);
    }

    // Full stylesheet: typography, layout, light/dark tokens
    function injectFullStyles() {
        if (document.getElementById('gp-styles')) return;
        const style = document.createElement('style');
        style.id = 'gp-styles';
        style.textContent = `
          /* Tokens: default to light */
          :root {
            --gp-bg: #f7f8fb;
            --gp-surface: #ffffff;
            --gp-surface-2: #f3f4f6;
            --gp-fg: #111418;
            --gp-fg-muted: #4b5563;
            --gp-link: #0b6bcb;
            --gp-link-visited: #6b44b3;
            --gp-border: #d0d7de;
            --gp-accent: #2b90d9;
            --gp-chip-bg: #eef2ff;
            --gp-chip-fg: #384bfd;
            --gp-read-width: 66ch;

            /* extra taxonomy chips (light) */
            --chip-package-bg:#efe9ff; --chip-package-fg:#5b21b6; --chip-package-bd:#ddd6fe;
            --chip-mummify-bg:#fde7f4; --chip-mummify-fg:#9d174d; --chip-mummify-bd:#fbcfe8;
            --chip-trash-bg:#e7f5d8;   --chip-trash-fg:#166534; --chip-trash-bd:#ccebc0;
            --chip-doll-bg:#ffe9f6;    --chip-doll-fg:#9d174d;  --chip-doll-bd:#ffc7e8;
            --chip-machine-bg:#eeeeee; --chip-machine-fg:#374151; --chip-machine-bd:#d1d5db;
            --chip-buried-bg:#111111;  --chip-buried-fg:#e5e7eb; --chip-buried-bd:#27272a;
            --chip-giant-bg:#d6ffe0;   --chip-giant-fg:#065f46;  --chip-giant-bd:#a7f3d0;

            /* taxonomy chip defaults (light) */
            --chip-bound-bg: #fee2e2; --chip-bound-fg: #991b1b; --chip-bound-bd: #fecaca;
            --chip-sb-bg: #dbeafe;    --chip-sb-fg: #1e40af; --chip-sb-bd: #bfdbfe;
            --chip-latex-bg: #e5e7eb; --chip-latex-fg:#374151; --chip-latex-bd:#d1d5db;
            --chip-erotic-bg:#fde2f3; --chip-erotic-fg:#9d174d; --chip-erotic-bd:#fbcfe8;
          }

          html[${DATA_ATTR}="dark"] {
            --gp-bg: #0f1115;
            --gp-surface: #151a21;
            --gp-surface-2: #12161c;
            --gp-fg: #e6e8eb;
            --gp-fg-muted: #9aa4af;
            --gp-link: #8ab4f8;
            --gp-link-visited: #c58af9;
            --gp-border: #2a3138;
            --gp-accent: #4da6ff;
            --gp-chip-bg: #1f2630;
            --gp-chip-fg: #9db7ff;
            /* taxonomy chip defaults (dark) */
            --chip-bound-bg: #3b1f23; --chip-bound-fg: #fca5a5; --chip-bound-bd: #7f1d1d;
            --chip-sb-bg: #1e293b;    --chip-sb-fg: #93c5fd; --chip-sb-bd: #1e3a8a;
            --chip-latex-bg:#1f2937;  --chip-latex-fg:#cbd5e1; --chip-latex-bd:#334155;
            --chip-erotic-bg:#3a1f2d; --chip-erotic-fg:#f9a8d4; --chip-erotic-bd:#831843;

            --chip-package-bg:#2a2238; --chip-package-fg:#c4b5fd; --chip-package-bd:#4c1d95;
            --chip-mummify-bg:#3a1f2d; --chip-mummify-fg:#f9a8d4; --chip-mummify-bd:#831843;
            --chip-trash-bg:#132916;   --chip-trash-fg:#86efac; --chip-trash-bd:#14532d;
            --chip-doll-bg:#3a1f2d;    --chip-doll-fg:#f9a8d4;  --chip-doll-bd:#831843;
            --chip-machine-bg:#1f2937; --chip-machine-fg:#cbd5e1; --chip-machine-bd:#374151;
            --chip-buried-bg:#0b0b0c;  --chip-buried-fg:#e5e7eb; --chip-buried-bd:#27272a;
            --chip-giant-bg:#052e24;   --chip-giant-fg:#6ee7b7;  --chip-giant-bd:#065f46;
          }

          /* Base */
          html[${DATA_ATTR}], html[${DATA_ATTR}] body {
            background: var(--gp-bg) !important; /* reset any gradients */
            background-image: none !important;
            color: var(--gp-fg) !important;
            text-rendering: optimizeLegibility;
            -webkit-font-smoothing: antialiased;
          }
          html[${DATA_ATTR}] body {
            font-family: "Segoe UI", system-ui, -apple-system, "Helvetica Neue", Arial, sans-serif !important;
            font-size: 16px !important;
            line-height: 1.7 !important;
          }

          /* Legacy subsites (light mode): restore classic body styling for layout compatibility */
          html[${DATA_ATTR}][data-gp-legacy="1"][data-gp-theme="light"] BODY {
            background: #F0F0F0 !important;
            color: #303030 !important;
            font-family: Arial, Helvetica, sans-serif !important;
            font-size: 12px !important;
            margin: 0 !important;
            padding: 0 !important;
          }

          /* Containers */
          html[${DATA_ATTR}] #top,
          html[${DATA_ATTR}] #head-outer,
          html[${DATA_ATTR}] #head,
          html[${DATA_ATTR}] #main {
            background: var(--gp-surface) !important;
            color: var(--gp-fg) !important;
            box-shadow: none !important;
          }
          html[${DATA_ATTR}] #main { 
            max-width: 1320px; 
            margin: 0 auto; 
            padding: 12px 16px !important;
          }
          /* Home pages: no inner padding and wider max width */
          html[${DATA_ATTR}] .home #main { padding: 0 !important; max-width: 1440px !important; }
          /* Main-like subpages: replicate home layout tweaks */
          html[${DATA_ATTR}][data-gp-mainlike="1"] #main { padding: 0 !important; max-width: 1440px !important; margin: 0 auto; }
          html[${DATA_ATTR}][data-gp-mainlike="1"] #main > table { width: 100% !important; table-layout: fixed !important; }
          html[${DATA_ATTR}][data-gp-mainlike="1"] #main > table td { vertical-align: top !important; }
          html[${DATA_ATTR}][data-gp-mainlike="1"] #main > table > tbody > tr > td:first-child { width: 210px !important; }
          html[${DATA_ATTR}][data-gp-mainlike="1"] #main > table > tbody > tr > td:last-child { width: auto !important; }
          html[${DATA_ATTR}][data-gp-mainlike="1"] .sidebar { width: 210px !important; min-width: 210px !important; }
          html[${DATA_ATTR}][data-gp-mainlike="1"] .sidebar a { white-space: normal !important; word-break: normal !important; }
          html[${DATA_ATTR}][data-gp-mainlike="1"] .sidebar li { line-height: 1.35; }

          /* Author/links/search tables on main-like pages: normalize borders and backgrounds */
          html[${DATA_ATTR}][data-gp-mainlike="1"] #main table { width: 100% !important; border-collapse: collapse !important; table-layout: fixed; }
          html[${DATA_ATTR}][data-gp-mainlike="1"] #main th,
          html[${DATA_ATTR}][data-gp-mainlike="1"] #main td { 
            border: 1px solid var(--gp-border) !important;
            background: transparent !important; color: var(--gp-fg) !important;
            padding: 4px 6px !important; vertical-align: top !important; 
          }
          html[${DATA_ATTR}="dark"][data-gp-mainlike="1"] #main th { background: var(--gp-surface-2) !important; }
          html[${DATA_ATTR}][data-gp-mainlike="1"] #main th[bgcolor],
          html[${DATA_ATTR}][data-gp-mainlike="1"] #main td[bgcolor],
          html[${DATA_ATTR}][data-gp-mainlike="1"] #main tr[bgcolor] { background: transparent !important; color: var(--gp-fg) !important; }
          html[${DATA_ATTR}][data-gp-mainlike="1"] #main a { color: var(--gp-link) !important; }
          html[${DATA_ATTR}][data-gp-mainlike="1"] #main a:visited { color: var(--gp-link-visited) !important; }

          /* World pages: stabilize legacy table layout */
          html[${DATA_ATTR}][data-gp-world="1"] #main { padding: 0 !important; max-width: 1440px; margin: 0 auto; }
          html[${DATA_ATTR}][data-gp-world="1"] center { display:block; max-width: 1440px; margin: 0 auto; }
          html[${DATA_ATTR}][data-gp-world="1"] body > table,
          html[${DATA_ATTR}][data-gp-world="1"] center > table,
          html[${DATA_ATTR}][data-gp-world="1"] #main > table {
            width: 100% !important;
            table-layout: fixed !important;
          }
          html[${DATA_ATTR}][data-gp-world="1"] body > table td,
          html[${DATA_ATTR}][data-gp-world="1"] center > table td,
          html[${DATA_ATTR}][data-gp-world="1"] #main > table td { vertical-align: top !important; padding: 0 8px !important; }
          html[${DATA_ATTR}][data-gp-world="1"] body > table > tbody > tr > td:first-child,
          html[${DATA_ATTR}][data-gp-world="1"] center > table > tbody > tr > td:first-child,
          html[${DATA_ATTR}][data-gp-world="1"] #main > table > tbody > tr > td:first-child {
            width: 210px !important; min-width: 210px !important;
          }
          html[${DATA_ATTR}][data-gp-world="1"] body > table > tbody > tr > td:nth-child(2),
          html[${DATA_ATTR}][data-gp-world="1"] center > table > tbody > tr > td:nth-child(2),
          html[${DATA_ATTR}][data-gp-world="1"] #main > table > tbody > tr > td:nth-child(2) { width: auto !important; }
          html[${DATA_ATTR}][data-gp-world="1"] body > table > tbody > tr > td:last-child,
          html[${DATA_ATTR}][data-gp-world="1"] center > table > tbody > tr > td:last-child,
          html[${DATA_ATTR}][data-gp-world="1"] #main > table > tbody > tr > td:last-child { width: 220px !important; min-width: 220px !important; }

          /* World pages: replace float-based layout with margin gutters */
          html[${DATA_ATTR}][data-gp-world="1"] .sidebar { float: left !important; width: 210px !important; }
          html[${DATA_ATTR}][data-gp-world="1"] .rhsbar { float: right !important; width: 220px !important; }
          html[${DATA_ATTR}][data-gp-world="1"] #main {
            margin-left: 230px !important;  /* sidebar 210 + gutters */
            margin-right: 240px !important; /* rhsbar 220 + gutters */
          }

          /* World pages: avoid dl/dt/dd clear rules interfering with columns */
          html[${DATA_ATTR}][data-gp-world="1"] dt { clear: none !important; }
          html[${DATA_ATTR}][data-gp-world="1"] dd { clear: none !important; }
          /* Home page: widen layout sensibly for legacy tables */
          html[${DATA_ATTR}] .home #main > table { width: 100% !important; table-layout: fixed !important; }
          html[${DATA_ATTR}] .home #main > table td { vertical-align: top !important; }
          html[${DATA_ATTR}] .home #main > table > tbody > tr > td:first-child { width: 210px !important; }
          html[${DATA_ATTR}] .home #main > table > tbody > tr > td:last-child { width: auto !important; }

          /* Boxes and cards */
          html[${DATA_ATTR}] .box-outer,
          html[${DATA_ATTR}] .box {
            background: var(--gp-surface-2) !important;
            border: 1px solid var(--gp-border) !important;
            border-radius: 12px !important;
            box-shadow: none !important;
          }
          html[${DATA_ATTR}] .box { padding: 10px 14px !important; }

          /* Readable story text blocks */
          html[${DATA_ATTR}] .story1,
          html[${DATA_ATTR}] .story1c,
          html[${DATA_ATTR}] .story5l,
          html[${DATA_ATTR}] .story6,
          html[${DATA_ATTR}] .storym,
          html[${DATA_ATTR}] .style4,
          html[${DATA_ATTR}] .styleDW,
          html[${DATA_ATTR}] .style20,
          html[${DATA_ATTR}] .style21,
          html[${DATA_ATTR}] .style22 {
            max-width: var(--gp-read-width);
            margin: 0 auto;
            padding: 0 12px;
            font-size: 17px !important;
            line-height: 1.8 !important;
          }

          html[${READING_ATTR}="wide"] { --gp-read-width: 132ch; }

          /* When in reading wide mode on story pages, hide asides and widen */
          html[${READING_ATTR}="wide"][data-gp-context="story"] #main { max-width: 1600px; }
          html[${READING_ATTR}="wide"][data-gp-context="story"] .gp-aside { display: none !important; }
          html[${READING_ATTR}="wide"][data-gp-context="story"] #main .box-outer:not(.gp-aside),
          html[${READING_ATTR}="wide"][data-gp-context="story"] #main .box:not(.gp-aside) {
            float: none !important; width: auto !important; max-width: none !important; clear: both !important;
          }

          /* Headings */
          html[${DATA_ATTR}] h1, html[${DATA_ATTR}] h2, html[${DATA_ATTR}] h3, html[${DATA_ATTR}] h4 {
            font-weight: 650 !important;
            color: var(--gp-fg) !important;
            background: transparent !important;
            border: none !important;
            margin: 1.2em 0 0.6em !important;
          }
          html[${DATA_ATTR}] h1 b, html[${DATA_ATTR}] h1 B {
            background: transparent !important;
            color: inherit !important;
            display: inline !important;
            padding: 0 !important;
            border-radius: 0 !important;
            font-weight: 700 !important;
          }
          html[${DATA_ATTR}] h1 { font-size: 1.7rem !important; }
          html[${DATA_ATTR}] h2 { font-size: 1.4rem !important; }
          html[${DATA_ATTR}] h3 { font-size: 1.15rem !important; color: var(--gp-fg-muted) !important; }

          /* Paragraphs and lists */
          html[${DATA_ATTR}] p { margin: 0.9em 0 !important; }
          html[${DATA_ATTR}] li { margin: 0.25em 0; }

          /* Links */
          html[${DATA_ATTR}] a { color: var(--gp-link) !important; }
          html[${DATA_ATTR}] a:visited { color: var(--gp-link-visited) !important; }
          html[${DATA_ATTR}] a:hover { text-decoration: underline !important; }
          html[${DATA_ATTR}] a { word-break: break-word; }

          /* Definition lists: keep simple to avoid layout breakage */
          html[${DATA_ATTR}] dl { margin: 0; padding: 0; }
          html[${DATA_ATTR}] dt { font-weight: 600; margin-top: 1em; clear: both; }
          html[${DATA_ATTR}] dd { margin: 0.4em 0 0.8em 0; color: var(--gp-fg-muted); padding: 0 !important; background: transparent !important; border: 0 !important; border-radius: 0 !important; display: block; clear: both; }
          html[${DATA_ATTR}] dd::after { content: ""; display: block; clear: both; }

          /* Taxonomy chips */
          html[${DATA_ATTR}] #main dd .bound,
          html[${DATA_ATTR}] #main dd .sb,
          html[${DATA_ATTR}] #main dd .latex,
          html[${DATA_ATTR}] #main dd .erotic,
          html[${DATA_ATTR}] #main dd .package,
          html[${DATA_ATTR}] #main dd .mummify,
          html[${DATA_ATTR}] #main dd .trash,
          html[${DATA_ATTR}] #main dd .doll,
          html[${DATA_ATTR}] #main dd .machine,
          html[${DATA_ATTR}] #main dd .buried,
          html[${DATA_ATTR}] #main dd .giant {
            display: inline-block;
            padding: 2px 6px;
            margin: 0 6px 0 0;
            border: 1px solid var(--gp-border);
            border-radius: 8px;
            background: var(--gp-chip-bg);
            color: var(--gp-chip-fg);
            font-size: 12px;
            line-height: 1.4;
            min-width: 96%
          }

          /* Color-coded taxonomy chips */
          html[${DATA_ATTR}] #main dd .bound { background: var(--chip-bound-bg) !important; color: var(--chip-bound-fg) !important; border-color: var(--chip-bound-bd) !important; }
          html[${DATA_ATTR}] #main dd .sb    { background: var(--chip-sb-bg) !important;    color: var(--chip-sb-fg) !important;    border-color: var(--chip-sb-bd) !important; }
          html[${DATA_ATTR}] #main dd .latex { background: var(--chip-latex-bg) !important; color: var(--chip-latex-fg) !important; border-color: var(--chip-latex-bd) !important; }
          html[${DATA_ATTR}] #main dd .erotic{ background: var(--chip-erotic-bg) !important;color: var(--chip-erotic-fg) !important;border-color: var(--chip-erotic-bd) !important; }
          html[${DATA_ATTR}] #main dd .package{ background: var(--chip-package-bg) !important; color: var(--chip-package-fg) !important; border-color: var(--chip-package-bd) !important; }
          html[${DATA_ATTR}] #main dd .mummify{ background: var(--chip-mummify-bg) !important; color: var(--chip-mummify-fg) !important; border-color: var(--chip-mummify-bd) !important; }
          html[${DATA_ATTR}] #main dd .trash  { background: var(--chip-trash-bg) !important;   color: var(--chip-trash-fg) !important;   border-color: var(--chip-trash-bd) !important; }
          html[${DATA_ATTR}] #main dd .doll   { background: var(--chip-doll-bg) !important;    color: var(--chip-doll-fg) !important;    border-color: var(--chip-doll-bd) !important; }
          html[${DATA_ATTR}] #main dd .machine{ background: var(--chip-machine-bg) !important; color: var(--chip-machine-fg) !important; border-color: var(--chip-machine-bd) !important; }
          html[${DATA_ATTR}] #main dd .buried { background: var(--chip-buried-bg) !important;  color: var(--chip-buried-fg) !important;  border-color: var(--chip-buried-bd) !important; }
          html[${DATA_ATTR}] #main dd .giant  { background: var(--chip-giant-bg) !important;   color: var(--chip-giant-fg) !important;   border-color: var(--chip-giant-bd) !important; }

          /* Home page: also color .newstory when category is on the container or the item */
          html[${DATA_ATTR}] .home #main dd.bound .newstory,
          html[${DATA_ATTR}] .home #main dd .newstory.bound { background: var(--chip-bound-bg) !important; color: var(--chip-bound-fg) !important; border: 1px solid var(--chip-bound-bd) !important; }
          html[${DATA_ATTR}] .home #main dd.sb .newstory,
          html[${DATA_ATTR}] .home #main dd .newstory.sb    { background: var(--chip-sb-bg) !important;    color: var(--chip-sb-fg) !important;    border: 1px solid var(--chip-sb-bd) !important; }
          html[${DATA_ATTR}] .home #main dd.latex .newstory,
          html[${DATA_ATTR}] .home #main dd .newstory.latex { background: var(--chip-latex-bg) !important; color: var(--chip-latex-fg) !important; border: 1px solid var(--chip-latex-bd) !important; }
          html[${DATA_ATTR}] .home #main dd.erotic .newstory,
          html[${DATA_ATTR}] .home #main dd .newstory.erotic{ background: var(--chip-erotic-bg) !important;color: var(--chip-erotic-fg) !important;border: 1px solid var(--chip-erotic-bd) !important; }
          html[${DATA_ATTR}] .home #main dd.package .newstory,
          html[${DATA_ATTR}] .home #main dd .newstory.package{ background: var(--chip-package-bg) !important; color: var(--chip-package-fg) !important; border: 1px solid var(--chip-package-bd) !important; }
          html[${DATA_ATTR}] .home #main dd.mummify .newstory,
          html[${DATA_ATTR}] .home #main dd .newstory.mummify{ background: var(--chip-mummify-bg) !important; color: var(--chip-mummify-fg) !important; border: 1px solid var(--chip-mummify-bd) !important; }
          html[${DATA_ATTR}] .home #main dd.trash .newstory,
          html[${DATA_ATTR}] .home #main dd .newstory.trash  { background: var(--chip-trash-bg) !important;   color: var(--chip-trash-fg) !important;   border: 1px solid var(--chip-trash-bd) !important; }
          html[${DATA_ATTR}] .home #main dd.doll .newstory,
          html[${DATA_ATTR}] .home #main dd .newstory.doll   { background: var(--chip-doll-bg) !important;    color: var(--chip-doll-fg) !important;    border: 1px solid var(--chip-doll-bd) !important; }
          html[${DATA_ATTR}] .home #main dd.machine .newstory,
          html[${DATA_ATTR}] .home #main dd .newstory.machine{ background: var(--chip-machine-bg) !important; color: var(--chip-machine-fg) !important; border: 1px solid var(--chip-machine-bd) !important; }
          html[${DATA_ATTR}] .home #main dd.buried .newstory,
          html[${DATA_ATTR}] .home #main dd .newstory.buried { background: var(--chip-buried-bg) !important;  color: var(--chip-buried-fg) !important;  border: 1px solid var(--chip-buried-bd) !important; }
          html[${DATA_ATTR}] .home #main dd.giant .newstory,
          html[${DATA_ATTR}] .home #main dd .newstory.giant  { background: var(--chip-giant-bg) !important;   color: var(--chip-giant-fg) !important;   border: 1px solid var(--chip-giant-bd) !important; }

          /* Images responsive */
          html[${DATA_ATTR}] img { max-width: 100% !important; height: auto !important; }

          /* Header/logo simplification */
          html[${DATA_ATTR}] .plaza #logo { background-image: none !important; }
          html[${DATA_ATTR}] #logo { 
            background: var(--gp-surface) !important;
            background-image: none !important;
            min-height: 64px;
            text-align: center;
            border-bottom: 3px solid var(--gp-accent);
          }

          /* Inputs */
          html[${DATA_ATTR}] input, html[${DATA_ATTR}] select, html[${DATA_ATTR}] textarea, html[${DATA_ATTR}] button {
            background: var(--gp-surface-2) !important;
            color: var(--gp-fg) !important;
            border: 1px solid var(--gp-border) !important;
            border-radius: 6px !important;
            padding: 6px 8px !important;
          }
          html[${DATA_ATTR}] #head input { font-size: 14px !important; cursor: pointer; }

          /* Tables (scoped to main content) */
          html[${DATA_ATTR}] #main table { border-color: var(--gp-border) !important; }
          html[${DATA_ATTR}] #main td, html[${DATA_ATTR}] #main th { background: transparent !important; color: var(--gp-fg) !important; }

          /* Old tags (scoped): keep header layout intact */
          html[${DATA_ATTR}] #main center { text-align: left !important; display: block; }
          html[${DATA_ATTR}] font { color: inherit !important; font: inherit !important; }

          /* Header search/input sizing so it doesn't overflow */
          html[${DATA_ATTR}] #head input[type="text"],
          html[${DATA_ATTR}] #head input[type="search"] {
            width: 220px !important;
            max-width: 60vw !important;
          }

          /* Code / pre */
          html[${DATA_ATTR}] pre, html[${DATA_ATTR}] code {
            white-space: pre-wrap; 
            word-break: break-word; 
            background: var(--gp-surface-2) !important; 
            border: 1px solid var(--gp-border) !important; 
            border-radius: 6px !important; 
            padding: 8px 10px !important; 
          }

          /* Section spacing */
          html[${DATA_ATTR}] #top, html[${DATA_ATTR}] #head-outer { margin-bottom: 8px !important; }

          /* Remove heavy gradients from skins */
          html[${DATA_ATTR}] .mummified .box-outer, 
          html[${DATA_ATTR}] .latex .box-outer, 
          html[${DATA_ATTR}] .bound .box-outer, 
          html[${DATA_ATTR}] .plaza .box-outer, 
          html[${DATA_ATTR}] .erotic .box-outer {
            background: var(--gp-surface-2) !important;
            box-shadow: none !important;
            border: 1px solid var(--gp-border) !important;
            border-radius: 12px !important;
            border-top: 2px solid var(--gp-accent) !important;
          }

          /* Selection */
          html[${DATA_ATTR}] ::selection { background: #1f6feb55; }

          /* Back to Top button */
          #gp-backtotop {
            position: fixed; bottom: 84px; right: 12px; z-index: 100000;
            padding: 8px 10px; font-size: 12px; line-height: 1;
            border-radius: 999px; cursor: pointer;
            border: 1px solid var(--gp-border);
            background: var(--gp-surface-2); color: var(--gp-fg);
            box-shadow: none; opacity: 0; pointer-events: none;
            transition: opacity .2s ease;
          }
          #gp-backtotop.visible { opacity: 1; pointer-events: auto; }

          /* Mini sticky header removed per user preference */

          /* Header links and search tidy */
          html[${DATA_ATTR}] #head p { margin: 0 !important; padding: 6px 10px !important; height: auto !important; line-height: 1.4 !important; }
          html[${DATA_ATTR}] #head p a { margin-right: 10px; }
          html[${DATA_ATTR}] #head input[type="text"],
          html[${DATA_ATTR}] #head input[type="search"] { height: 28px !important; padding: 4px 8px !important; }

          /* Home page: preserve update list rhythm */
          html[${DATA_ATTR}] .home #main dl,
          html[${DATA_ATTR}] .home #main dt,
          html[${DATA_ATTR}] .home #main dd { margin: 0 !important; }
          html[${DATA_ATTR}] .home #main dd { padding: 0 !important; display:block; width:100%; }
          html[${DATA_ATTR}] .home #main dd a { display:inline-block; max-width:100%; float:none !important; }

          /* Old fixed-width tables in home pages: relax to fluid */
          html[${DATA_ATTR}] .home #main table[width],
          html[${DATA_ATTR}] .home #main td[width],
          html[${DATA_ATTR}] .home #main table[style*="width" i] {
            width: auto !important; max-width: 100% !important; table-layout: auto !important;
          }
          /* Sidebar column width to prevent link wraps */
          html[${DATA_ATTR}] .home .sidebar { width: 210px !important; min-width: 210px !important; }
          html[${DATA_ATTR}] .home .sidebar a { white-space: normal !important; word-break: normal !important; }
          html[${DATA_ATTR}] .home .sidebar li { line-height: 1.35; }

          /* Footer back-to-top link */
          .gp-footer-backtop { text-align: center; margin: 18px 0 8px; }
          .gp-footer-backtop a { color: var(--gp-link); text-decoration: none; }
          .gp-footer-backtop a:hover { text-decoration: underline; }

          /* World pages: ensure dark-mode link and heading colors use theme tokens */
          html[${DATA_ATTR}="dark"][data-gp-world="1"] a,
          html[${DATA_ATTR}="dark"][data-gp-world="1"] #main a,
          html[${DATA_ATTR}="dark"][data-gp-world="1"] .sidebar a,
          html[${DATA_ATTR}="dark"][data-gp-world="1"] .rhsbar a {
            color: var(--gp-link) !important;
          }
          html[${DATA_ATTR}="dark"][data-gp-world="1"] a:visited,
          html[${DATA_ATTR}="dark"][data-gp-world="1"] #main a:visited,
          html[${DATA_ATTR}="dark"][data-gp-world="1"] .sidebar a:visited,
          html[${DATA_ATTR}="dark"][data-gp-world="1"] .rhsbar a:visited {
            color: var(--gp-link-visited) !important;
          }
          html[${DATA_ATTR}="dark"][data-gp-world="1"] h1,
          html[${DATA_ATTR}="dark"][data-gp-world="1"] h2,
          html[${DATA_ATTR}="dark"][data-gp-world="1"] h3,
          html[${DATA_ATTR}="dark"][data-gp-world="1"] h4,
          html[${DATA_ATTR}="dark"][data-gp-world="1"] h5,
          html[${DATA_ATTR}="dark"][data-gp-world="1"] .sidebar h5,
          html[${DATA_ATTR}="dark"][data-gp-world="1"] .rhsbar h3 {
            color: var(--gp-fg) !important;
          }

          /* Author pages: some headings use .authors > li > div with light gradients */
          html[${DATA_ATTR}="dark"] .authors div {
            background: var(--gp-surface-2) !important;
            background-image: none !important;
            color: var(--gp-fg) !important;
            border: 1px solid var(--gp-border) !important;
          }
          html[${DATA_ATTR}="dark"] .authors div a { color: var(--gp-fg) !important; }

          /* Multi-column lists on author and similar pages */
          html[${DATA_ATTR}][data-gp-mainlike="1"] ul.stories,
          html[${DATA_ATTR}][data-gp-mainlike="1"] ul.authors,
          html[${DATA_ATTR}][data-gp-world="1"] ul.stories,
          html[${DATA_ATTR}][data-gp-world="1"] ul.authors {
            margin: 0 !important;
            padding: 0 8px !important; /* add small left/right gutter so first/last columns align with inner columns */
            list-style: none !important;
            -webkit-column-count: 5 !important;
            -moz-column-count: 5 !important;
            column-count: 5 !important;
            -webkit-column-gap: 16px !important;
            -moz-column-gap: 16px !important;
            column-gap: 16px !important;
            -webkit-column-rule: 1px solid var(--gp-border) !important;
            -moz-column-rule: 1px solid var(--gp-border) !important;
            column-rule: 1px solid var(--gp-border) !important;
            background: transparent !important;
          }
          html[${DATA_ATTR}][data-gp-mainlike="1"] ul.stories li,
          html[${DATA_ATTR}][data-gp-mainlike="1"] ul.authors li,
          html[${DATA_ATTR}][data-gp-world="1"] ul.stories li,
          html[${DATA_ATTR}][data-gp-world="1"] ul.authors li {
            margin: 0 6px 12px 0 !important;
            overflow: visible !important;
          }

          /* Ensure author name blocks don't indent in the first column */
          html[${DATA_ATTR}] ul.authors li > div { margin-left: 0 !important; }

          /* Author links: normalize spacing and line-height */
          html[${DATA_ATTR}][data-gp-mainlike="1"] .authors a,
          html[${DATA_ATTR}][data-gp-world="1"] .authors a {
            font-weight: normal !important;
            display: block !important;
            margin-top: 6px !important;
            margin-left: 5px !important;
            line-height: 14px !important;
            text-decoration: none !important;
          }
          /* First link under each author: slightly tighter top margin */
          html[${DATA_ATTR}][data-gp-mainlike="1"] #main .authors a:first-of-type,
          html[${DATA_ATTR}][data-gp-world="1"] #main .authors a:first-of-type {
            margin-top: 3px !important;
          }

          /* Fix light border on chapter separators */
          html[${DATA_ATTR}][data-gp-mainlike="1"] .chN,
          html[${DATA_ATTR}][data-gp-world="1"] .chN { border-bottom: 1px solid var(--gp-border) !important; }

          /* Responsive column counts */
          @media (max-width: 1200px) {
            html[${DATA_ATTR}][data-gp-mainlike="1"] ul.stories,
            html[${DATA_ATTR}][data-gp-mainlike="1"] ul.authors,
            html[${DATA_ATTR}][data-gp-world="1"] ul.stories,
            html[${DATA_ATTR}][data-gp-world="1"] ul.authors {
              -webkit-column-count: 4 !important; -moz-column-count: 4 !important; column-count: 4 !important;
            }
          }
          @media (max-width: 900px) {
            html[${DATA_ATTR}][data-gp-mainlike="1"] ul.stories,
            html[${DATA_ATTR}][data-gp-mainlike="1"] ul.authors,
            html[${DATA_ATTR}][data-gp-world="1"] ul.stories,
            html[${DATA_ATTR}][data-gp-world="1"] ul.authors {
              -webkit-column-count: 3 !important; -moz-column-count: 3 !important; column-count: 3 !important;
            }
          }
          @media (max-width: 670px) {
            html[${DATA_ATTR}][data-gp-mainlike="1"] ul.stories,
            html[${DATA_ATTR}][data-gp-mainlike="1"] ul.authors,
            html[${DATA_ATTR}][data-gp-world="1"] ul.stories,
            html[${DATA_ATTR}][data-gp-world="1"] ul.authors {
              -webkit-column-count: 2 !important; -moz-column-count: 2 !important; column-count: 2 !important;
            }
          }
          @media (max-width: 420px) {
            html[${DATA_ATTR}][data-gp-mainlike="1"] ul.stories,
            html[${DATA_ATTR}][data-gp-mainlike="1"] ul.authors,
            html[${DATA_ATTR}][data-gp-world="1"] ul.stories,
            html[${DATA_ATTR}][data-gp-world="1"] ul.authors {
              -webkit-column-count: 1 !important; -moz-column-count: 1 !important; column-count: 1 !important;
            }
          }
          html[${DATA_ATTR}] .home #main dd .bound,
          html[${DATA_ATTR}] .home #main dd .sb,
          html[${DATA_ATTR}] .home #main dd .latex,
          html[${DATA_ATTR}] .home #main dd .erotic { border-radius: 8px; padding: 1px 6px; }

          /* Category pages: avoid over-constraining list layouts */
          html[${DATA_ATTR}] #main .categories dl,
          html[${DATA_ATTR}] #main .categories dd,
          html[${DATA_ATTR}] #main .categories dt { background: transparent !important; border: 0 !important; padding: 0 !important; border-radius: 0 !important; }

          /* Homepage-specific tweaks requested */
          /* Make newstory/category pills nearly full-width on homepage */
          html[${DATA_ATTR}] .home #main dd .bound,
          html[${DATA_ATTR}] .home #main dd .sb,
          html[${DATA_ATTR}] .home #main dd .latex,
          html[${DATA_ATTR}] .home #main dd .erotic,
          html[${DATA_ATTR}] .home #main dd .package,
          html[${DATA_ATTR}] .home #main dd .mummify,
          html[${DATA_ATTR}] .home #main dd .trash,
          html[${DATA_ATTR}] .home #main dd .doll,
          html[${DATA_ATTR}] .home #main dd .machine,
          html[${DATA_ATTR}] .home #main dd .buried,
          html[${DATA_ATTR}] .home #main dd .giant {
            display: inline-block;
            padding: 2px 6px;
            margin: 0 6px 0 0;
            border: 1px solid var(--gp-border);
            border-radius: 8px !important;
            background: var(--gp-chip-bg) !important;
            color: var(--gp-chip-fg) !important;
            font-size: 12px;
            line-height: 1.4;
            min-width: 96%;
            box-sizing: border-box;
          }

          /* Homepage header containers */
          html[${DATA_ATTR}] .home #top,
          html[${DATA_ATTR}][data-gp-mainlike="1"] #top {
            max-width: 1440px; margin: 0 auto;
            background: #E8E8E8; border-radius: 15px; padding: 5px 0; overflow: hidden;
          }
          html[${DATA_ATTR}] .home #head,
          html[${DATA_ATTR}][data-gp-mainlike="1"] #head {
            padding: 4px 12px; height: 40px; border: 1px solid #E3E3E3; border-radius: 15px;
            background: #F1F1F1; /* ie9 */
            background: linear-gradient(#FEFEFE,#D5D5D5);
          }

          /* Homepage banner strip (theme-aware) */
          html[${DATA_ATTR}] .home .banner,
          html[${DATA_ATTR}][data-gp-mainlike="1"] .banner {
            background: var(--gp-surface-2);
            color: var(--gp-fg);
            text-align: center;
            padding: 3px;
            margin-top: 5px;
          }
        `;
        (document.head || document.documentElement).appendChild(style);
    }

    // Theme toggle button
    function injectToggle() {
        if (document.getElementById('gp-toggle')) return;
        const btn = document.createElement('button');
        btn.id = 'gp-toggle';
        Object.assign(btn.style, {
            position: 'fixed',
            bottom: '12px',
            right: '12px',
            zIndex: 99999,
            padding: '6px 8px',
            fontSize: '12px',
            lineHeight: '1',
            borderRadius: '8px',
            cursor: 'pointer',
            border: '1px solid var(--gp-border)',
            background: 'var(--gp-surface-2)',
            color: 'var(--gp-fg)'
        });

        function labelFor(mode) {
            const eff = computeEffective(mode);
            const icon = eff === 'dark' ? '🌙' : '☀️';
            return `GP: ${mode[0].toUpperCase()}${mode.slice(1)} ${icon}`;
        }

        let current = getStoredMode() || 'auto';
        btn.textContent = labelFor(current);
        btn.addEventListener('click', () => {
            current = current === 'auto' ? 'dark' : current === 'dark' ? 'light' : 'auto';
            setStoredMode(current);
            applyThemeAttr(current);
            btn.textContent = labelFor(current);
        });

        document.documentElement.appendChild(btn);
    }

    // Reading mode toggle button
    function injectReadingToggle() {
        if (document.getElementById('gp-reading-toggle')) return;
        const btn = document.createElement('button');
        btn.id = 'gp-reading-toggle';
        Object.assign(btn.style, {
            position: 'fixed',
            bottom: '48px',
            right: '12px',
            zIndex: 99999,
            padding: '6px 8px',
            fontSize: '12px',
            lineHeight: '1',
            borderRadius: '8px',
            cursor: 'pointer',
            border: '1px solid var(--gp-border)',
            background: 'var(--gp-surface-2)',
            color: 'var(--gp-fg)'
        });

        function labelFor(mode) {
            return `Read: ${mode === 'wide' ? 'Wide' : 'Narrow'}`;
        }
        let current = getReadingMode();
        btn.textContent = labelFor(current);
        btn.addEventListener('click', () => {
            current = current === 'narrow' ? 'wide' : 'narrow';
            setReadingMode(current);
            applyReadingAttr(current);
            btn.textContent = labelFor(current);
        });
        document.documentElement.appendChild(btn);
    }

    // Heuristics: detect story page and tag side boxes as asides
    function markReadingContextAndAsides() {
        const storySel = '.story1, .story1c, .story5l, .story6, .storym, .style4, .styleDW, .style20, .style21, .style22';
        const isStory = !!document.querySelector(storySel);
        document.documentElement.setAttribute('data-gp-context', isStory ? 'story' : 'other');

        if (!isStory) return;
        // Likely aside boxes are generic .box-outer blocks with certain headings
        const ASIDE_HEADINGS = [
            'menu', 'premier', 'note', 'submit', 'monitor', 'search', 'rss',
            'other worlds', 'stories by author', 'authors', 'links', 'forum', 'contact'
        ];
        document.querySelectorAll('.box-outer').forEach((el) => {
            const h = el.querySelector('h4, h3, h2, h1');
            const title = (h && (h.textContent || '')).trim().toLowerCase();
            if (!title) return;
            if (ASIDE_HEADINGS.some(k => title.includes(k))) {
                el.classList.add('gp-aside');
            }
        });
    }

    // Back to top button
    function injectBackToTop() {
        if (document.getElementById('gp-backtotop')) return;
        const btn = document.createElement('button');
        btn.id = 'gp-backtotop';
        btn.textContent = 'Top ↑';
        btn.addEventListener('click', () => {
            try { window.scrollTo({ top: 0, behavior: 'smooth' }); }
            catch (_) { window.scrollTo(0, 0); }
        });
        document.documentElement.appendChild(btn);

        const onScroll = () => {
            const show = window.scrollY > 600;
            btn.classList.toggle('visible', !!show);
        };
        window.addEventListener('scroll', onScroll, { passive: true });
        onScroll();
    }

    // Footer back to top link near the bottom of #main
    function injectFooterBackTop() {
        if (document.getElementById('gp-footer-backtop')) return;
        const container = document.querySelector('#main') || document.body;
        if (!container) return;
        const wrap = document.createElement('div');
        wrap.className = 'gp-footer-backtop';
        wrap.id = 'gp-footer-backtop';
        const link = document.createElement('a');
        link.href = '#';
        link.textContent = 'back to the top ⤴';
        link.addEventListener('click', (e) => {
            e.preventDefault();
            try { window.scrollTo({ top: 0, behavior: 'smooth' }); }
            catch (_) { window.scrollTo(0, 0); }
        });
        wrap.appendChild(link);
        container.appendChild(wrap);
    }

    // Mini sticky header removed per user request

    // Initialize
    function init() {
        ensureViewport();
        injectCriticalStyles();
        injectFullStyles();
        injectToggle();
        injectReadingToggle();
        injectBackToTop();
        injectFooterBackTop();
        markReadingContextAndAsides();
        // Remove critical after full loads
        const crit = document.getElementById('gp-critical');
        if (crit && crit.parentNode) crit.parentNode.removeChild(crit);
    }

    if (document.readyState === 'loading') {
        // inject critical immediately, wait for rest
        injectCriticalStyles();
        document.addEventListener('DOMContentLoaded', init);
    } else {
        init();
    }

    // Handle bfcache restores
    window.addEventListener('pageshow', (e) => {
        if (e.persisted) {
            injectFullStyles();
        }
    });
})();