UltraWide ChatGPT

Ultra-wide ChatGPT layout with Canvas/Split View support, scoped selectors, adaptive width profiles, settings UI, import/export, SPA-safe reinjection, and safer mutation handling.

θα χρειαστεί να εγκαταστήσετε μια επέκταση όπως το Tampermonkey, το Greasemonkey ή το Violentmonkey για να εγκαταστήσετε αυτόν τον κώδικα.

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

θα χρειαστεί να εγκαταστήσετε μια επέκταση όπως το Tampermonkey ή το Violentmonkey για να εγκαταστήσετε αυτόν τον κώδικα.

θα χρειαστεί να εγκαταστήσετε μια επέκταση όπως το Tampermonkey ή το Userscripts για να εγκαταστήσετε αυτόν τον κώδικα.

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

Θα χρειαστεί να εγκαταστήσετε μια επέκταση διαχείρισης κώδικα χρήστη για να εγκαταστήσετε αυτόν τον κώδικα.

(Έχω ήδη έναν διαχειριστή κώδικα χρήστη, επιτρέψτε μου να τον εγκαταστήσω!)

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.

(Έχω ήδη έναν διαχειριστή στυλ χρήστη, επιτρέψτε μου να τον εγκαταστήσω!)

// ==UserScript==
// @name         UltraWide ChatGPT
// @namespace    https://www.instagram.com/jsm.ig/
// @version      2026.05.28.6
// @author       jsmdev
// @description  Ultra-wide ChatGPT layout with Canvas/Split View support, scoped selectors, adaptive width profiles, settings UI, import/export, SPA-safe reinjection, and safer mutation handling.
// @license      MIT
// @match        https://chatgpt.com/*
// @match        https://www.chatgpt.com/*
// @icon         https://cdn.jsdelivr.net/gh/simple-icons/simple-icons/icons/openai.svg
// @run-at       document-start
// @grant        GM_getValue
// @grant        GM_setValue
// @grant        GM_registerMenuCommand
// ==/UserScript==

/*
  UltraWide ChatGPT
  Version: 2026.05.28.6

  Shortcuts
  - Alt+O  Toggle script
  - Alt+U  Toggle ultra-wide mode
  - Alt+L  Toggle left alignment
  - Alt+M  Cycle max-width cap
  - Alt+A  Toggle auto mode
  - Alt+C  Toggle Canvas/Split View tuning
  - Alt+S  Open settings
  - Alt+R  Reset settings

  Console API
  - window.__mlUltraWide.state()
  - window.__mlUltraWide.apply()
  - window.__mlUltraWide.restart()
  - window.__mlUltraWide.openSettings()
  - window.__mlUltraWide.set({ cap: '2400', auto: false })
  - window.__mlUltraWide.reset()
*/

(() => {
  'use strict';

  const VERSION = '2026.05.28.6';
  const STYLE_ID = 'uwc-style';
  const UI_STYLE_ID = 'uwc-ui-style';
  const TOAST_ID = 'uwc-toast';
  const MODAL_ID = 'uwc-settings-modal';
  const STORAGE_KEY = 'uwc.settings.v6';
  const LEGACY_STORAGE_KEYS = Object.freeze([
    'uwc.settings.v5',
    'uwc.settings.v4',
    'uwc.settings.v3',
    'uwc.settings.v2',
    'uwc.settings.v1'
  ]);

  const CAPS = Object.freeze([
    'none',
    '1200',
    '1400',
    '1600',
    '1800',
    '2000',
    '2200',
    '2400',
    '2800',
    '3200',
    '3600',
    '4200'
  ]);

  const ATTR = Object.freeze({
    on: 'data-uwc-on',
    wide: 'data-uwc-wide',
    left: 'data-uwc-left',
    cap: 'data-uwc-cap',
    canvas: 'data-uwc-canvas',
    mounted: 'data-uwc-mounted'
  });

  const DEFAULTS = Object.freeze({
    enabled: true,
    wide: true,
    left: true,
    cap: 'none',
    auto: true,
    autoMinWidth: 1180,
    disableOnTouch: true,
    disableBelowHeight: 620,
    showToast: true,
    composerWide: true,
    codeWide: true,
    mediaSafe: true,
    canvasTuning: true,
    balancedSplitView: true,
    suppressCanvasMutations: true,
    gutterMin: 12,
    gutterVw: 1.6,
    gutterMax: 28,
    toastMs: 1400,
    repairIntervalMs: 2600,
    mutationDebounceMs: 180,
    routePollMs: 900,
    optionsCloseOnBackdrop: true
  });

  const LIMITS = Object.freeze({
    autoMinWidth: [640, 10000],
    disableBelowHeight: [0, 4000],
    gutterMin: [0, 80],
    gutterVw: [0, 12],
    gutterMax: [0, 160],
    toastMs: [300, 10000],
    repairIntervalMs: [1000, 15000],
    mutationDebounceMs: [0, 2500],
    routePollMs: [300, 10000]
  });

  const KEYS = Object.freeze({
    toggleEnabled: { alt: true, ctrl: false, shift: false, key: 'o' },
    toggleWide: { alt: true, ctrl: false, shift: false, key: 'u' },
    toggleLeft: { alt: true, ctrl: false, shift: false, key: 'l' },
    cycleCap: { alt: true, ctrl: false, shift: false, key: 'm' },
    toggleAuto: { alt: true, ctrl: false, shift: false, key: 'a' },
    toggleCanvas: { alt: true, ctrl: false, shift: false, key: 'c' },
    openSettings: { alt: true, ctrl: false, shift: false, key: 's' },
    reset: { alt: true, ctrl: false, shift: false, key: 'r' }
  });

  const CFG = Object.freeze({
    maxMutationRecordsToInspect: 40,
    maxRemovedNodesToInspect: 20,
    canvasProbeIntervalMs: 1200
  });

  const SEL = Object.freeze({
    appRoots: [
      'body',
      '#__next',
      '#root',
      'main',
      '[role="main"]',
      '[data-testid="stretched-app"]',
      '[data-testid="main-app"]',
      '[data-testid="chat-layout"]'
    ].join(','),

    conversationRoots: [
      '[data-testid="conversation-view"]',
      '[data-testid="conversation-container"]',
      '[data-testid="conversation-turns"]',
      '[data-testid="thread"]',
      'main [class*="conversation"]',
      'main [class*="thread"]'
    ].join(','),

    turns: [
      '[data-testid="conversation-turn"]',
      '[data-testid^="conversation-turn"]',
      '[data-message-author-role]',
      '[data-turn]',
      'article[data-testid]',
      'article[class*="group"]'
    ].join(','),

    turnInner: [
      '[data-testid="conversation-turn"] > div',
      '[data-testid^="conversation-turn"] > div',
      '[data-message-author-role] > div',
      '[data-turn] > div',
      'article[data-testid] > div',
      'article[class*="group"] > div'
    ].join(','),

    markdown: [
      '.markdown',
      '[class*="markdown"]',
      '[class*="prose"]',
      '[data-message-author-role] .markdown',
      '[data-message-author-role] [class*="prose"]',
      '[data-testid="conversation-turn"] .markdown',
      '[data-testid="conversation-turn"] [class*="prose"]'
    ].join(','),

    composer: [
      '[data-testid="composer"]',
      '[data-testid*="composer"]',
      '[class*="composer"]',
      'footer form',
      'footer'
    ].join(','),

    input: [
      '[data-testid="composer:input"]',
      '[data-testid="composer-input"]',
      '[data-testid*="composer"] textarea',
      '[data-testid*="composer"] [contenteditable="true"]',
      'textarea',
      '[contenteditable="true"][role="textbox"]',
      '[role="textbox"][contenteditable="true"]'
    ].join(','),

    canvasRoots: [
      '[class*="canvas"]',
      '[class*="artifact"]',
      '[data-testid*="canvas"]',
      '[data-testid*="artifact"]',
      '[aria-label*="canvas" i]',
      '[aria-label*="artifact" i]'
    ].join(','),

    editorRoots: [
      '[class*="monaco"]',
      '[class*="cm-editor"]',
      '[class*="CodeMirror"]',
      '[data-language]',
      '[data-testid*="code"]',
      '[data-testid*="editor"]'
    ].join(',')
  });

  const runtime = {
    started: false,
    href: '',
    lastCssKey: '',
    lastUiCssKey: '',
    lastEnvKey: '',
    lastCanvasState: false,
    lastCanvasProbe: 0,
    rafId: 0,
    debounceTimer: 0,
    repairTimer: 0,
    routeTimer: 0,
    toastTimer: 0,
    bodyObserver: null,
    headObserver: null,
    bootstrapObserver: null,
    origPushState: null,
    origReplaceState: null,
    handlers: Object.create(null),
    menuRegistered: false,
    suppressModalRefresh: false
  };

  const settings = { ...DEFAULTS };

  function hasGmValueApi() {
    return typeof GM_getValue === 'function' && typeof GM_setValue === 'function';
  }

  function readRawStorage(key) {
    try {
      if (hasGmValueApi()) return GM_getValue(key, null);
    } catch (_) {}

    try {
      const raw = localStorage.getItem(key);
      return raw ? JSON.parse(raw) : null;
    } catch (_) {
      return null;
    }
  }

  function writeRawStorage(key, value) {
    try {
      if (hasGmValueApi()) {
        GM_setValue(key, value);
        return true;
      }
    } catch (_) {}

    try {
      localStorage.setItem(key, JSON.stringify(value));
      return true;
    } catch (_) {
      return false;
    }
  }

  function clampNumber(value, min, max, fallback) {
    const n = Number(value);
    if (!Number.isFinite(n)) return fallback;
    return Math.min(max, Math.max(min, n));
  }

  function clampInt(value, min, max, fallback) {
    return Math.round(clampNumber(value, min, max, fallback));
  }

  function normalizeBool(value, fallback) {
    return typeof value === 'boolean' ? value : fallback;
  }

  function normalizeSettings(input) {
    const out = { ...DEFAULTS };
    if (!input || typeof input !== 'object') return out;

    out.enabled = normalizeBool(input.enabled, out.enabled);
    out.wide = normalizeBool(input.wide, out.wide);
    out.left = normalizeBool(input.left, out.left);
    out.cap = CAPS.includes(String(input.cap)) ? String(input.cap) : out.cap;
    out.auto = normalizeBool(input.auto, out.auto);
    out.autoMinWidth = clampInt(input.autoMinWidth, ...LIMITS.autoMinWidth, out.autoMinWidth);
    out.disableOnTouch = normalizeBool(input.disableOnTouch, out.disableOnTouch);
    out.disableBelowHeight = clampInt(input.disableBelowHeight, ...LIMITS.disableBelowHeight, out.disableBelowHeight);
    out.showToast = normalizeBool(input.showToast, out.showToast);
    out.composerWide = normalizeBool(input.composerWide, out.composerWide);
    out.codeWide = normalizeBool(input.codeWide, out.codeWide);
    out.mediaSafe = normalizeBool(input.mediaSafe, out.mediaSafe);
    out.canvasTuning = normalizeBool(input.canvasTuning, out.canvasTuning);
    out.balancedSplitView = normalizeBool(input.balancedSplitView, out.balancedSplitView);
    out.suppressCanvasMutations = normalizeBool(input.suppressCanvasMutations, out.suppressCanvasMutations);
    out.gutterMin = clampInt(input.gutterMin, ...LIMITS.gutterMin, out.gutterMin);
    out.gutterVw = clampNumber(input.gutterVw, ...LIMITS.gutterVw, out.gutterVw);
    out.gutterMax = clampInt(input.gutterMax, ...LIMITS.gutterMax, out.gutterMax);
    out.toastMs = clampInt(input.toastMs, ...LIMITS.toastMs, out.toastMs);
    out.repairIntervalMs = clampInt(input.repairIntervalMs, ...LIMITS.repairIntervalMs, out.repairIntervalMs);
    out.mutationDebounceMs = clampInt(input.mutationDebounceMs, ...LIMITS.mutationDebounceMs, out.mutationDebounceMs);
    out.routePollMs = clampInt(input.routePollMs, ...LIMITS.routePollMs, out.routePollMs);
    out.optionsCloseOnBackdrop = normalizeBool(input.optionsCloseOnBackdrop, out.optionsCloseOnBackdrop);

    if (out.gutterMax < out.gutterMin) out.gutterMax = out.gutterMin;
    return out;
  }

  function loadSettings() {
    const current = readRawStorage(STORAGE_KEY);
    if (current) {
      Object.assign(settings, normalizeSettings(current));
      return;
    }

    for (const key of LEGACY_STORAGE_KEYS) {
      const legacy = readRawStorage(key);
      if (legacy) {
        Object.assign(settings, normalizeSettings(legacy));
        saveSettings();
        return;
      }
    }
  }

  function saveSettings() {
    writeRawStorage(STORAGE_KEY, { ...settings });
  }

  function getHead() {
    return document.head || document.getElementsByTagName('head')[0] || null;
  }

  function getRoot() {
    return document.documentElement || null;
  }

  function isTouchLike() {
    try {
      return (
        (typeof matchMedia === 'function' && matchMedia('(pointer: coarse)').matches) ||
        Number(navigator.maxTouchPoints || 0) > 0
      );
    } catch (_) {
      return false;
    }
  }

  function hasCanvasLayout() {
    const now = Date.now();
    if (now - runtime.lastCanvasProbe < CFG.canvasProbeIntervalMs) return runtime.lastCanvasState;
    runtime.lastCanvasProbe = now;

    try {
      const canvasNode = document.querySelector(SEL.canvasRoots);
      const editorNode = document.querySelector(SEL.editorRoots);
      const bodyText = document.body?.innerText || '';
      runtime.lastCanvasState = !!(
        canvasNode ||
        editorNode ||
        bodyText.includes('Copy') && bodyText.includes('Download') && bodyText.includes('Share')
      );
      return runtime.lastCanvasState;
    } catch (_) {
      runtime.lastCanvasState = false;
      return false;
    }
  }

  function wideActive() {
    if (!settings.enabled || !settings.wide) return false;
    if (!settings.auto) return true;
    if (settings.disableOnTouch && isTouchLike()) return false;
    if (settings.disableBelowHeight > 0 && window.innerHeight > 0 && window.innerHeight < settings.disableBelowHeight) return false;
    return (window.innerWidth || 0) >= settings.autoMinWidth;
  }

  function apiStateCore() {
    return {
      enabled: settings.enabled ? 1 : 0,
      wide: settings.wide ? 1 : 0,
      left: settings.left ? 1 : 0,
      cap: settings.cap,
      auto: settings.auto ? 1 : 0,
      autoMinWidth: settings.autoMinWidth,
      disableOnTouch: settings.disableOnTouch ? 1 : 0,
      disableBelowHeight: settings.disableBelowHeight,
      showToast: settings.showToast ? 1 : 0,
      composerWide: settings.composerWide ? 1 : 0,
      codeWide: settings.codeWide ? 1 : 0,
      mediaSafe: settings.mediaSafe ? 1 : 0,
      canvasTuning: settings.canvasTuning ? 1 : 0,
      balancedSplitView: settings.balancedSplitView ? 1 : 0,
      suppressCanvasMutations: settings.suppressCanvasMutations ? 1 : 0,
      gutterMin: settings.gutterMin,
      gutterVw: settings.gutterVw,
      gutterMax: settings.gutterMax
    };
  }

  function envKey() {
    return [
      window.innerWidth || 0,
      window.innerHeight || 0,
      window.devicePixelRatio || 1,
      document.fullscreenElement ? 1 : 0,
      isTouchLike() ? 1 : 0,
      hasCanvasLayout() ? 1 : 0,
      ...Object.values(apiStateCore())
    ].join('|');
  }

  function cssKey() {
    return [VERSION, ...Object.values(apiStateCore())].join('|');
  }

  function uiCssKey() {
    return [VERSION, settings.toastMs].join('|');
  }

  function buildCapRules() {
    return CAPS.map((cap) => {
      const value = cap === 'none' ? 'none' : `${cap}px`;
      return `:root[${ATTR.on}="1"][${ATTR.cap}="${cap}"]{--uwc-cap:${value}}`;
    }).join('\n');
  }

  function buildCodeCss() {
    if (!settings.codeWide) return '';

    return `
:root[${ATTR.wide}="1"] pre,
:root[${ATTR.wide}="1"] .markdown pre,
:root[${ATTR.wide}="1"] [class*="prose"] pre{
  width:100%!important;
  max-width:100%!important;
  overflow-x:auto!important;
  overflow-y:visible!important;
  white-space:pre!important;
  box-sizing:border-box!important;
}

:root[${ATTR.wide}="1"] code,
:root[${ATTR.wide}="1"] .markdown code,
:root[${ATTR.wide}="1"] [class*="prose"] code{
  max-width:100%!important;
}

:root[${ATTR.wide}="1"] table{
  display:block!important;
  width:100%!important;
  max-width:100%!important;
  overflow-x:auto!important;
  box-sizing:border-box!important;
}`;
  }

  function buildMediaCss() {
    if (!settings.mediaSafe) return '';

    return `
:root[${ATTR.wide}="1"] img,
:root[${ATTR.wide}="1"] svg,
:root[${ATTR.wide}="1"] video,
:root[${ATTR.wide}="1"] canvas,
:root[${ATTR.wide}="1"] iframe,
:root[${ATTR.wide}="1"] figure{
  max-width:100%!important;
  height:auto!important;
}`;
  }

  function buildComposerCss() {
    if (!settings.composerWide) return '';

    return `
:root[${ATTR.wide}="1"] ${SEL.composer}{
  width:min(100%,var(--uwc-content-width))!important;
  max-width:var(--uwc-content-width)!important;
  margin-left:auto!important;
  margin-right:auto!important;
  box-sizing:border-box!important;
}

:root[${ATTR.wide}="1"][${ATTR.canvas}="1"] ${SEL.composer}{
  width:100%!important;
  max-width:100%!important;
}`;
  }

  function buildCanvasCss() {
    if (!settings.canvasTuning) return '';

    const balanced = settings.balancedSplitView ? `
:root[${ATTR.wide}="1"][${ATTR.canvas}="1"] main > div,
:root[${ATTR.wide}="1"][${ATTR.canvas}="1"] [role="main"] > div{
  min-width:0!important;
}

:root[${ATTR.wide}="1"][${ATTR.canvas}="1"] main > div:has(${SEL.conversationRoots}),
:root[${ATTR.wide}="1"][${ATTR.canvas}="1"] [role="main"] > div:has(${SEL.conversationRoots}){
  flex:1 1 48%!important;
  min-width:360px!important;
  max-width:none!important;
}

:root[${ATTR.wide}="1"][${ATTR.canvas}="1"] main > div:has(${SEL.canvasRoots}),
:root[${ATTR.wide}="1"][${ATTR.canvas}="1"] [role="main"] > div:has(${SEL.canvasRoots}),
:root[${ATTR.wide}="1"][${ATTR.canvas}="1"] main > div:has(${SEL.editorRoots}),
:root[${ATTR.wide}="1"][${ATTR.canvas}="1"] [role="main"] > div:has(${SEL.editorRoots}){
  flex:1 1 52%!important;
  min-width:420px!important;
  max-width:none!important;
}` : '';

    return `
:root[${ATTR.wide}="1"][${ATTR.canvas}="1"] body{
  overflow-x:hidden!important;
}

:root[${ATTR.wide}="1"][${ATTR.canvas}="1"] main,
:root[${ATTR.wide}="1"][${ATTR.canvas}="1"] [role="main"],
:root[${ATTR.wide}="1"][${ATTR.canvas}="1"] [data-testid="chat-layout"]{
  width:100%!important;
  max-width:none!important;
  min-width:0!important;
}

${balanced}

:root[${ATTR.wide}="1"][${ATTR.canvas}="1"] ${SEL.canvasRoots},
:root[${ATTR.wide}="1"][${ATTR.canvas}="1"] ${SEL.editorRoots}{
  min-width:0!important;
  max-width:none!important;
  box-sizing:border-box!important;
}

:root[${ATTR.wide}="1"][${ATTR.canvas}="1"] [class*="monaco"],
:root[${ATTR.wide}="1"][${ATTR.canvas}="1"] [class*="cm-editor"],
:root[${ATTR.wide}="1"][${ATTR.canvas}="1"] [class*="CodeMirror"]{
  width:100%!important;
  max-width:none!important;
}`;
  }

  function buildCss() {
    return `
:root[${ATTR.on}="1"]{
  --uwc-gutter:clamp(${settings.gutterMin}px,${settings.gutterVw}vw,${settings.gutterMax}px);
  --uwc-cap:none;
  --uwc-content-width:calc(100vw - (var(--uwc-gutter) * 2));
}

${buildCapRules()}

:root[${ATTR.on}="1"]:not([${ATTR.cap}="none"]){
  --uwc-content-width:min(calc(100vw - (var(--uwc-gutter) * 2)),var(--uwc-cap));
}

:root[${ATTR.wide}="1"] body{
  overflow-x:clip!important;
}

@supports not (overflow-x:clip){
  :root[${ATTR.wide}="1"] body{
    overflow-x:hidden!important;
  }
}

:root[${ATTR.wide}="1"] ${SEL.appRoots}{
  box-sizing:border-box!important;
  min-width:0!important;
}

:root[${ATTR.wide}="1"] ${SEL.conversationRoots}{
  width:100%!important;
  max-width:none!important;
  min-width:0!important;
  padding-left:var(--uwc-gutter)!important;
  padding-right:var(--uwc-gutter)!important;
  box-sizing:border-box!important;
}

:root[${ATTR.wide}="1"] ${SEL.turns}{
  width:100%!important;
  max-width:100%!important;
  min-width:0!important;
  margin-left:0!important;
  margin-right:0!important;
  box-sizing:border-box!important;
}

:root[${ATTR.wide}="1"] ${SEL.turnInner}{
  width:min(100%,var(--uwc-content-width))!important;
  max-width:var(--uwc-content-width)!important;
  min-width:0!important;
  margin-left:auto!important;
  margin-right:auto!important;
  box-sizing:border-box!important;
}

:root[${ATTR.wide}="1"] ${SEL.markdown}{
  width:100%!important;
  max-width:none!important;
  min-width:0!important;
  box-sizing:border-box!important;
}

:root[${ATTR.wide}="1"] ${SEL.markdown} > *{
  max-width:100%!important;
}

${buildComposerCss()}
${buildCodeCss()}
${buildMediaCss()}
${buildCanvasCss()}

:root[${ATTR.left}="1"] ${SEL.input},
:root[${ATTR.left}="1"] textarea,
:root[${ATTR.left}="1"] [contenteditable="true"][role="textbox"],
:root[${ATTR.left}="1"] ${SEL.markdown}{
  text-align:left!important;
  direction:ltr!important;
}

:root[${ATTR.left}="1"] textarea::placeholder{
  text-align:left!important;
}

@media (max-width:1179px), (max-height:619px){
  :root[${ATTR.wide}="1"]{
    --uwc-gutter:12px;
  }

  :root[${ATTR.wide}="1"] ${SEL.conversationRoots}{
    padding-left:12px!important;
    padding-right:12px!important;
  }
}

@media (max-width:900px){
  :root[${ATTR.wide}="1"][${ATTR.canvas}="1"] main > div,
  :root[${ATTR.wide}="1"][${ATTR.canvas}="1"] [role="main"] > div{
    flex:1 1 auto!important;
    min-width:0!important;
  }
}

@media print{
  :root[${ATTR.wide}="1"] ${SEL.appRoots},
  :root[${ATTR.wide}="1"] ${SEL.conversationRoots}{
    width:100%!important;
    max-width:none!important;
  }
}`.trim();
  }

  function buildUiCss() {
    return `
#${TOAST_ID}{
  position:fixed!important;
  z-index:2147483647!important;
  right:16px!important;
  bottom:16px!important;
  max-width:min(440px,calc(100vw - 32px))!important;
  padding:10px 12px!important;
  border-radius:12px!important;
  color:CanvasText!important;
  background:Canvas!important;
  border:1px solid color-mix(in srgb, CanvasText 18%, transparent)!important;
  box-shadow:0 8px 28px rgba(0,0,0,.18)!important;
  font:12px/1.35 system-ui,-apple-system,BlinkMacSystemFont,"Segoe UI",sans-serif!important;
  opacity:.96!important;
  pointer-events:none!important;
}

#${MODAL_ID}{
  position:fixed!important;
  inset:0!important;
  z-index:2147483646!important;
  display:flex!important;
  align-items:center!important;
  justify-content:center!important;
  padding:18px!important;
  background:rgba(0,0,0,.42)!important;
  color:CanvasText!important;
  font:13px/1.45 system-ui,-apple-system,BlinkMacSystemFont,"Segoe UI",sans-serif!important;
}

#${MODAL_ID} *{box-sizing:border-box!important;}

#${MODAL_ID} .uwc-panel{
  width:min(760px,100%)!important;
  max-height:min(86vh,820px)!important;
  overflow:auto!important;
  border-radius:18px!important;
  background:Canvas!important;
  color:CanvasText!important;
  border:1px solid color-mix(in srgb, CanvasText 16%, transparent)!important;
  box-shadow:0 20px 70px rgba(0,0,0,.35)!important;
}

#${MODAL_ID} .uwc-header{
  position:sticky!important;
  top:0!important;
  z-index:1!important;
  display:flex!important;
  align-items:flex-start!important;
  justify-content:space-between!important;
  gap:16px!important;
  padding:18px 18px 12px!important;
  background:Canvas!important;
  border-bottom:1px solid color-mix(in srgb, CanvasText 12%, transparent)!important;
}

#${MODAL_ID} .uwc-title{
  margin:0!important;
  font-size:18px!important;
  line-height:1.2!important;
  font-weight:700!important;
}

#${MODAL_ID} .uwc-subtitle{
  margin:5px 0 0!important;
  opacity:.72!important;
  font-size:12px!important;
}

#${MODAL_ID} .uwc-body{padding:16px 18px 18px!important;}

#${MODAL_ID} .uwc-section{
  margin:0 0 18px!important;
  padding:14px!important;
  border:1px solid color-mix(in srgb, CanvasText 12%, transparent)!important;
  border-radius:14px!important;
}

#${MODAL_ID} .uwc-section h3{
  margin:0 0 12px!important;
  font-size:13px!important;
  text-transform:uppercase!important;
  letter-spacing:.06em!important;
  opacity:.72!important;
}

#${MODAL_ID} .uwc-grid{
  display:grid!important;
  grid-template-columns:repeat(2,minmax(0,1fr))!important;
  gap:12px!important;
}

#${MODAL_ID} .uwc-field{display:flex!important;flex-direction:column!important;gap:6px!important;}
#${MODAL_ID} .uwc-check{display:flex!important;align-items:center!important;gap:9px!important;min-height:34px!important;}
#${MODAL_ID} label{font-weight:600!important;}
#${MODAL_ID} .uwc-hint{opacity:.68!important;font-size:12px!important;font-weight:400!important;}

#${MODAL_ID} input,
#${MODAL_ID} select,
#${MODAL_ID} textarea{
  width:100%!important;
  min-height:34px!important;
  padding:7px 9px!important;
  border-radius:10px!important;
  color:CanvasText!important;
  background:Canvas!important;
  border:1px solid color-mix(in srgb, CanvasText 18%, transparent)!important;
  font:13px/1.35 system-ui,-apple-system,BlinkMacSystemFont,"Segoe UI",sans-serif!important;
}

#${MODAL_ID} input[type="checkbox"]{width:16px!important;min-height:16px!important;accent-color:CanvasText!important;}
#${MODAL_ID} textarea{min-height:115px!important;resize:vertical!important;font-family:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace!important;font-size:12px!important;}
#${MODAL_ID} .uwc-actions{display:flex!important;flex-wrap:wrap!important;gap:8px!important;justify-content:flex-end!important;padding-top:4px!important;}

#${MODAL_ID} button{
  min-height:34px!important;
  padding:7px 11px!important;
  border-radius:10px!important;
  cursor:pointer!important;
  color:CanvasText!important;
  background:Canvas!important;
  border:1px solid color-mix(in srgb, CanvasText 18%, transparent)!important;
  font:600 13px/1.35 system-ui,-apple-system,BlinkMacSystemFont,"Segoe UI",sans-serif!important;
}

#${MODAL_ID} button:hover{background:color-mix(in srgb, CanvasText 8%, Canvas)!important;}
#${MODAL_ID} .uwc-primary{color:Canvas!important;background:CanvasText!important;}
#${MODAL_ID} .uwc-danger{border-color:color-mix(in srgb, red 55%, CanvasText 12%)!important;}
#${MODAL_ID} .uwc-close{width:34px!important;min-width:34px!important;padding:0!important;font-size:18px!important;}

@media (max-width:680px){
  #${MODAL_ID}{align-items:stretch!important;padding:8px!important;}
  #${MODAL_ID} .uwc-panel{max-height:100%!important;}
  #${MODAL_ID} .uwc-grid{grid-template-columns:1fr!important;}
}`.trim();
  }

  function mountStyleElement(id, css, keyProp, keyValue) {
    const head = getHead();
    if (!head) return false;

    let el = document.getElementById(id);
    if (!el) {
      el = document.createElement('style');
      el.id = id;
      el.type = 'text/css';
      head.appendChild(el);
    }

    el.setAttribute('data-version', VERSION);
    if (el.textContent !== css) el.textContent = css;
    runtime[keyProp] = keyValue;
    return true;
  }

  function styleMounted() {
    const el = document.getElementById(STYLE_ID);
    const head = getHead();
    return !!(el && head && head.contains(el));
  }

  function uiStyleMounted() {
    const el = document.getElementById(UI_STYLE_ID);
    const head = getHead();
    return !!(el && head && head.contains(el));
  }

  function mountStyle() {
    return mountStyleElement(STYLE_ID, buildCss(), 'lastCssKey', cssKey());
  }

  function mountUiStyle() {
    return mountStyleElement(UI_STYLE_ID, buildUiCss(), 'lastUiCssKey', uiCssKey());
  }

  function unmountStyle() {
    const el = document.getElementById(STYLE_ID);
    if (el?.parentNode) el.parentNode.removeChild(el);
    runtime.lastCssKey = '';
  }

  function clearAttrs() {
    const root = getRoot();
    if (!root) return;
    root.removeAttribute(ATTR.on);
    root.removeAttribute(ATTR.wide);
    root.removeAttribute(ATTR.left);
    root.removeAttribute(ATTR.cap);
    root.removeAttribute(ATTR.canvas);
    root.removeAttribute(ATTR.mounted);
  }

  function setAttrs() {
    const root = getRoot();
    if (!root) return;

    root.setAttribute(ATTR.mounted, VERSION);
    root.setAttribute(ATTR.cap, settings.cap);

    if (settings.enabled) root.setAttribute(ATTR.on, '1');
    else root.removeAttribute(ATTR.on);

    if (wideActive()) root.setAttribute(ATTR.wide, '1');
    else root.removeAttribute(ATTR.wide);

    if (settings.enabled && settings.left) root.setAttribute(ATTR.left, '1');
    else root.removeAttribute(ATTR.left);

    if (settings.enabled && settings.canvasTuning && hasCanvasLayout()) root.setAttribute(ATTR.canvas, '1');
    else root.removeAttribute(ATTR.canvas);
  }

  function apply() {
    if (!getRoot()) return;

    if (uiCssKey() !== runtime.lastUiCssKey || !uiStyleMounted()) mountUiStyle();

    if (!settings.enabled) {
      clearAttrs();
      unmountStyle();
      return;
    }

    if (cssKey() !== runtime.lastCssKey || !styleMounted()) {
      if (!mountStyle()) return;
    }

    setAttrs();
  }

  function schedule(force = false) {
    if (!force && runtime.rafId) return;
    if (runtime.rafId) cancelAnimationFrame(runtime.rafId);

    runtime.rafId = requestAnimationFrame(() => {
      runtime.rafId = 0;
      apply();
    });
  }

  function showToast(message) {
    if (!settings.showToast) return;

    try {
      mountUiStyle();
      const parent = document.body || document.documentElement;
      if (!parent) return;

      let el = document.getElementById(TOAST_ID);
      if (!el) {
        el = document.createElement('div');
        el.id = TOAST_ID;
        parent.appendChild(el);
      }

      el.textContent = String(message || 'UltraWide updated');

      if (runtime.toastTimer) clearTimeout(runtime.toastTimer);
      runtime.toastTimer = window.setTimeout(() => {
        runtime.toastTimer = 0;
        const toast = document.getElementById(TOAST_ID);
        if (toast?.parentNode) toast.parentNode.removeChild(toast);
      }, settings.toastMs);
    } catch (_) {}
  }

  function statusText() {
    return `UltraWide ${settings.enabled ? 'on' : 'off'} | wide ${wideActive() ? 'active' : 'inactive'} | canvas ${hasCanvasLayout() ? 'detected' : 'none'} | cap ${settings.cap}`;
  }

  function restartTimers() {
    if (!runtime.started) return;

    if (runtime.repairTimer) clearInterval(runtime.repairTimer);
    if (runtime.routeTimer) clearInterval(runtime.routeTimer);

    runtime.routeTimer = window.setInterval(() => {
      try { checkRouteChange(); } catch (_) {}
    }, settings.routePollMs);

    runtime.repairTimer = window.setInterval(() => {
      try { repairTick(); } catch (error) { console.error('[UltraWide] Repair tick failed:', error); }
    }, settings.repairIntervalMs);
  }

  function commit(message = statusText(), options = {}) {
    const beforeRepair = settings.repairIntervalMs;
    const beforeRoute = settings.routePollMs;

    saveSettings();
    runtime.lastCanvasProbe = 0;
    schedule(true);

    if (!runtime.suppressModalRefresh) refreshSettingsModal();
    showToast(message);

    if (options.forceTimerRestart || beforeRepair !== settings.repairIntervalMs || beforeRoute !== settings.routePollMs) {
      restartTimers();
    }
  }

  function cycleCap() {
    const i = CAPS.indexOf(settings.cap);
    settings.cap = CAPS[(i + 1 + CAPS.length) % CAPS.length] || 'none';
    commit(`UltraWide cap: ${settings.cap}`);
  }

  function resetSettings() {
    Object.assign(settings, DEFAULTS);
    commit('UltraWide settings reset', { forceTimerRestart: true });
  }

  function keyMatch(rule, event) {
    return (
      !!rule.alt === !!event.altKey &&
      !!rule.shift === !!event.shiftKey &&
      !!rule.ctrl === !!(event.ctrlKey || event.metaKey) &&
      String(rule.key).toLowerCase() === String(event.key || '').toLowerCase()
    );
  }

  function typingTarget(target) {
    if (!target) return false;
    const tag = String(target.tagName || '').toLowerCase();
    return tag === 'input' || tag === 'textarea' || !!target.isContentEditable;
  }

  function checkRouteChange() {
    if (location.href !== runtime.href) {
      runtime.href = location.href;
      runtime.lastCanvasProbe = 0;
      schedule(true);
    }
  }

  function wrapHistoryMethod(fn) {
    return function wrappedHistoryMethod(...args) {
      const out = fn.apply(this, args);
      queueMicrotask(checkRouteChange);
      return out;
    };
  }

  function installHistoryHooks() {
    try {
      if (!runtime.origPushState) runtime.origPushState = history.pushState;
      if (!runtime.origReplaceState) runtime.origReplaceState = history.replaceState;
      if (history.pushState === runtime.origPushState) history.pushState = wrapHistoryMethod(runtime.origPushState);
      if (history.replaceState === runtime.origReplaceState) history.replaceState = wrapHistoryMethod(runtime.origReplaceState);
    } catch (_) {}
  }

  function restoreHistoryHooks() {
    try {
      if (runtime.origPushState && history.pushState !== runtime.origPushState) history.pushState = runtime.origPushState;
      if (runtime.origReplaceState && history.replaceState !== runtime.origReplaceState) history.replaceState = runtime.origReplaceState;
    } catch (_) {}
  }

  function mutationRemovedManagedNode(records) {
    const count = Math.min(records.length, CFG.maxMutationRecordsToInspect);
    for (let i = 0; i < count; i += 1) {
      const removed = records[i]?.removedNodes || [];
      const removedCount = Math.min(removed.length, CFG.maxRemovedNodesToInspect);
      for (let j = 0; j < removedCount; j += 1) {
        const node = removed[j];
        if (node?.id === STYLE_ID || node?.id === UI_STYLE_ID || node?.id === MODAL_ID || node?.id === TOAST_ID) return true;
      }
    }
    return false;
  }

  function mutationIsMostlyCanvas(records) {
    if (!settings.suppressCanvasMutations || !runtime.lastCanvasState) return false;
    const list = Array.from(records || []).slice(0, CFG.maxMutationRecordsToInspect);
    if (list.length === 0) return false;

    let canvasHits = 0;
    for (const record of list) {
      const target = record?.target;
      if (target instanceof HTMLElement && target.closest(SEL.canvasRoots)) canvasHits += 1;
      else if (target instanceof HTMLElement && target.closest(SEL.editorRoots)) canvasHits += 1;
    }

    return canvasHits > 0 && canvasHits / list.length >= 0.75;
  }

  function onMutations(records) {
    if (mutationRemovedManagedNode(records || [])) {
      schedule(true);
      return;
    }

    if (mutationIsMostlyCanvas(records || [])) return;

    if (runtime.debounceTimer) clearTimeout(runtime.debounceTimer);
    runtime.debounceTimer = window.setTimeout(() => {
      runtime.debounceTimer = 0;
      checkRouteChange();
      schedule(false);
    }, settings.mutationDebounceMs);
  }

  function attachHeadObserver() {
    const head = getHead();
    if (!head) return false;

    try {
      if (runtime.headObserver) runtime.headObserver.disconnect();
      runtime.headObserver = new MutationObserver(() => {
        if (!uiStyleMounted() || (settings.enabled && !styleMounted())) schedule(true);
      });
      runtime.headObserver.observe(head, { childList: true });
      return true;
    } catch (_) {
      runtime.headObserver = null;
      return false;
    }
  }

  function installObservers() {
    try {
      const root = getRoot();
      if (root) {
        runtime.bodyObserver = new MutationObserver(onMutations);
        runtime.bodyObserver.observe(root, { childList: true, subtree: true });
      }
    } catch (_) {}

    if (!attachHeadObserver()) {
      try {
        const root = getRoot();
        if (!root) return;

        runtime.bootstrapObserver = new MutationObserver(() => {
          if (!getHead()) return;
          attachHeadObserver();
          runtime.bootstrapObserver?.disconnect();
          runtime.bootstrapObserver = null;
          schedule(true);
        });
        runtime.bootstrapObserver.observe(root, { childList: true, subtree: true });
      } catch (_) {
        runtime.bootstrapObserver = null;
      }
    }
  }

  function disconnectObservers() {
    try { runtime.bodyObserver?.disconnect(); } catch (_) {}
    try { runtime.headObserver?.disconnect(); } catch (_) {}
    try { runtime.bootstrapObserver?.disconnect(); } catch (_) {}
    runtime.bodyObserver = null;
    runtime.headObserver = null;
    runtime.bootstrapObserver = null;
  }

  function onKeydown(event) {
    if (!event || event.defaultPrevented) return;

    const key = String(event.key || '').toLowerCase();
    const ourCombo = event.altKey && ['o', 'u', 'l', 'm', 'a', 'c', 's', 'r'].includes(key);
    if (typingTarget(event.target) && !ourCombo) return;

    if (keyMatch(KEYS.toggleEnabled, event)) {
      event.preventDefault();
      settings.enabled = !settings.enabled;
      commit(`UltraWide script: ${settings.enabled ? 'on' : 'off'}`);
      return;
    }

    if (keyMatch(KEYS.toggleWide, event)) {
      event.preventDefault();
      settings.wide = !settings.wide;
      commit(`UltraWide mode: ${settings.wide ? 'on' : 'off'}`);
      return;
    }

    if (keyMatch(KEYS.toggleLeft, event)) {
      event.preventDefault();
      settings.left = !settings.left;
      commit(`UltraWide left align: ${settings.left ? 'on' : 'off'}`);
      return;
    }

    if (keyMatch(KEYS.cycleCap, event)) {
      event.preventDefault();
      cycleCap();
      return;
    }

    if (keyMatch(KEYS.toggleAuto, event)) {
      event.preventDefault();
      settings.auto = !settings.auto;
      commit(`UltraWide auto mode: ${settings.auto ? 'on' : 'off'}`);
      return;
    }

    if (keyMatch(KEYS.toggleCanvas, event)) {
      event.preventDefault();
      settings.canvasTuning = !settings.canvasTuning;
      commit(`UltraWide Canvas tuning: ${settings.canvasTuning ? 'on' : 'off'}`);
      return;
    }

    if (keyMatch(KEYS.openSettings, event)) {
      event.preventDefault();
      openSettingsModal();
      return;
    }

    if (keyMatch(KEYS.reset, event)) {
      event.preventDefault();
      resetSettings();
    }
  }

  function onResizeLike() {
    const next = envKey();
    if (next !== runtime.lastEnvKey) {
      runtime.lastEnvKey = next;
      schedule(true);
    }
  }

  function onPageShow() { schedule(true); }
  function onFocus() { schedule(true); }
  function onVisibilityChange() { if (!document.hidden) schedule(true); }

  function bind() {
    runtime.handlers.keydown = onKeydown;
    runtime.handlers.resize = onResizeLike;
    runtime.handlers.orientationchange = onResizeLike;
    runtime.handlers.pageshow = onPageShow;
    runtime.handlers.focus = onFocus;
    runtime.handlers.popstate = checkRouteChange;
    runtime.handlers.visibilitychange = onVisibilityChange;
    runtime.handlers.fullscreenchange = onResizeLike;

    window.addEventListener('keydown', runtime.handlers.keydown, true);
    window.addEventListener('resize', runtime.handlers.resize, { passive: true });
    window.addEventListener('orientationchange', runtime.handlers.orientationchange, { passive: true });
    window.addEventListener('pageshow', runtime.handlers.pageshow, { passive: true });
    window.addEventListener('focus', runtime.handlers.focus, { passive: true });
    window.addEventListener('popstate', runtime.handlers.popstate, { passive: true });
    document.addEventListener('visibilitychange', runtime.handlers.visibilitychange, { passive: true });
    document.addEventListener('fullscreenchange', runtime.handlers.fullscreenchange, { passive: true });
  }

  function unbind() {
    if (runtime.handlers.keydown) window.removeEventListener('keydown', runtime.handlers.keydown, true);
    if (runtime.handlers.resize) window.removeEventListener('resize', runtime.handlers.resize);
    if (runtime.handlers.orientationchange) window.removeEventListener('orientationchange', runtime.handlers.orientationchange);
    if (runtime.handlers.pageshow) window.removeEventListener('pageshow', runtime.handlers.pageshow);
    if (runtime.handlers.focus) window.removeEventListener('focus', runtime.handlers.focus);
    if (runtime.handlers.popstate) window.removeEventListener('popstate', runtime.handlers.popstate);
    if (runtime.handlers.visibilitychange) document.removeEventListener('visibilitychange', runtime.handlers.visibilitychange);
    if (runtime.handlers.fullscreenchange) document.removeEventListener('fullscreenchange', runtime.handlers.fullscreenchange);
    runtime.handlers = Object.create(null);
  }

  function registerMenu(label, callback) {
    try {
      if (typeof GM_registerMenuCommand === 'function') GM_registerMenuCommand(label, callback);
    } catch (_) {}
  }

  function registerMenus() {
    if (runtime.menuRegistered) return;
    runtime.menuRegistered = true;

    registerMenu('⚙️ Settings / Options', openSettingsModal);
    registerMenu('🟢 Enable Script', () => {
      settings.enabled = !settings.enabled;
      commit(`Script ${settings.enabled ? 'enabled' : 'disabled'}`);
    });
    registerMenu('🖥️ Toggle Ultra-Wide Mode', () => {
      settings.wide = !settings.wide;
      commit(`Ultra-wide mode ${settings.wide ? 'enabled' : 'disabled'}`);
    });
    registerMenu('↔️ Toggle Left Alignment', () => {
      settings.left = !settings.left;
      commit(`Left alignment ${settings.left ? 'enabled' : 'disabled'}`);
    });
    registerMenu('🎨 Toggle Canvas Optimization', () => {
      settings.canvasTuning = !settings.canvasTuning;
      commit(`Canvas optimization ${settings.canvasTuning ? 'enabled' : 'disabled'}`);
    });
    registerMenu('📏 Cycle Width Limit', cycleCap);
    registerMenu('⚡ Toggle Adaptive Mode', () => {
      settings.auto = !settings.auto;
      commit(`Adaptive mode ${settings.auto ? 'enabled' : 'disabled'}`);
    });
    registerMenu('📤 Export Configuration', exportSettingsToClipboard);
    registerMenu('♻️ Reset Configuration', resetSettings);
  }

  function setOptions(patch) {
    if (!patch || typeof patch !== 'object') return false;

    if (Object.prototype.hasOwnProperty.call(patch, 'cap') && !CAPS.includes(String(patch.cap))) {
      throw new Error(`Invalid cap. Allowed values: ${CAPS.join(', ')}`);
    }

    const beforeRepair = settings.repairIntervalMs;
    const beforeRoute = settings.routePollMs;
    const next = normalizeSettings({ ...settings, ...patch });
    Object.assign(settings, next);
    commit(statusText(), {
      forceTimerRestart: beforeRepair !== settings.repairIntervalMs || beforeRoute !== settings.routePollMs
    });
    return true;
  }

  function removeToast() {
    const toast = document.getElementById(TOAST_ID);
    if (toast?.parentNode) toast.parentNode.removeChild(toast);
  }

  function makeEl(tag, attrs = {}, children = []) {
    const el = document.createElement(tag);

    for (const [key, value] of Object.entries(attrs)) {
      if (key === 'className') el.className = value;
      else if (key === 'text') el.textContent = value;
      else if (key === 'dataset') Object.assign(el.dataset, value);
      else if (key.startsWith('on') && typeof value === 'function') el.addEventListener(key.slice(2).toLowerCase(), value);
      else if (value !== false && value !== null && value !== undefined) el.setAttribute(key, String(value));
    }

    for (const child of children) {
      if (child === null || child === undefined) continue;
      el.appendChild(typeof child === 'string' ? document.createTextNode(child) : child);
    }

    return el;
  }

  function settingInput(key, label, type = 'checkbox', hint = '') {
    const id = `uwc-field-${key}`;

    if (type === 'checkbox') {
      const input = makeEl('input', { id, type: 'checkbox' });
      input.checked = !!settings[key];
      input.addEventListener('change', () => setOptions({ [key]: input.checked }));

      return makeEl('label', { className: 'uwc-check', for: id }, [
        input,
        makeEl('span', {}, [label, hint ? makeEl('span', { className: 'uwc-hint', text: ` ${hint}` }) : null])
      ]);
    }

    const inputAttrs = {
      id,
      type,
      value: settings[key],
      min: LIMITS[key]?.[0],
      max: LIMITS[key]?.[1],
      step: key === 'gutterVw' ? '0.1' : '1'
    };

    const input = makeEl('input', inputAttrs);
    input.addEventListener('change', () => setOptions({ [key]: input.value }));

    return makeEl('div', { className: 'uwc-field' }, [
      makeEl('label', { for: id, text: label }),
      input,
      hint ? makeEl('div', { className: 'uwc-hint', text: hint }) : null
    ]);
  }

  function capSelect() {
    const select = makeEl('select', { id: 'uwc-field-cap' });

    for (const cap of CAPS) {
      const label = cap === 'none' ? 'None' : `${cap}px`;
      const option = makeEl('option', { value: cap, text: label });
      if (settings.cap === cap) option.selected = true;
      select.appendChild(option);
    }

    select.addEventListener('change', () => setOptions({ cap: select.value }));

    return makeEl('div', { className: 'uwc-field' }, [
      makeEl('label', { for: 'uwc-field-cap', text: 'Max-width cap' }),
      select,
      makeEl('div', { className: 'uwc-hint', text: 'None means full available width.' })
    ]);
  }

  function section(title, children) {
    return makeEl('section', { className: 'uwc-section' }, [
      makeEl('h3', { text: title }),
      ...children
    ]);
  }

  function currentSettingsJson() {
    return JSON.stringify({ version: VERSION, settings: { ...settings } }, null, 2);
  }

  async function copyText(text) {
    try {
      if (navigator.clipboard?.writeText) {
        await navigator.clipboard.writeText(text);
        return true;
      }
    } catch (_) {}

    try {
      const ta = makeEl('textarea');
      ta.value = text;
      ta.style.position = 'fixed';
      ta.style.left = '-9999px';
      ta.style.top = '0';
      document.body.appendChild(ta);
      ta.focus();
      ta.select();
      const ok = document.execCommand('copy');
      ta.remove();
      return ok;
    } catch (_) {
      return false;
    }
  }

  async function exportSettingsToClipboard() {
    const ok = await copyText(currentSettingsJson());
    showToast(ok ? 'UltraWide settings copied' : 'Copy failed. Open settings and copy manually.');
  }

  function parseImportedSettings(raw) {
    const parsed = JSON.parse(raw);
    const payload = parsed?.settings && typeof parsed.settings === 'object' ? parsed.settings : parsed;
    return normalizeSettings(payload);
  }

  function importSettingsFromText(raw) {
    const next = parseImportedSettings(raw);
    Object.assign(settings, next);
    commit('UltraWide settings imported', { forceTimerRestart: true });
  }

  function closeSettingsModal() {
    const modal = document.getElementById(MODAL_ID);
    if (modal?.parentNode) modal.parentNode.removeChild(modal);
  }

  function refreshSettingsModal() {
    const modal = document.getElementById(MODAL_ID);
    if (!modal) return;
    openSettingsModal(true);
  }

  function openSettingsModal(replace = false) {
    try {
      mountUiStyle();
      const existing = document.getElementById(MODAL_ID);
      if (existing && !replace) return;
      if (existing?.parentNode) existing.parentNode.removeChild(existing);

      const importBox = makeEl('textarea', {
        id: 'uwc-import-box',
        spellcheck: 'false',
        placeholder: 'Paste exported JSON settings here...'
      });

      const exportBox = makeEl('textarea', {
        id: 'uwc-export-box',
        spellcheck: 'false'
      });
      exportBox.value = currentSettingsJson();

      const modal = makeEl('div', { id: MODAL_ID, role: 'dialog', 'aria-modal': 'true' }, [
        makeEl('div', { className: 'uwc-panel' }, [
          makeEl('div', { className: 'uwc-header' }, [
            makeEl('div', {}, [
              makeEl('h2', { className: 'uwc-title', text: 'UltraWide ChatGPT settings' }),
              makeEl('p', { className: 'uwc-subtitle', text: `Version ${VERSION} | Alt+S opens this panel` })
            ]),
            makeEl('button', { className: 'uwc-close', type: 'button', text: '×', title: 'Close', onclick: closeSettingsModal })
          ]),
          makeEl('div', { className: 'uwc-body' }, [
            section('Layout', [
              makeEl('div', { className: 'uwc-grid' }, [
                settingInput('enabled', 'Enable script'),
                settingInput('wide', 'Enable ultra-wide mode'),
                settingInput('left', 'Left-align text'),
                capSelect(),
                settingInput('composerWide', 'Widen composer'),
                settingInput('codeWide', 'Widen code blocks and tables'),
                settingInput('mediaSafe', 'Constrain media safely'),
                settingInput('showToast', 'Show toast messages')
              ])
            ]),
            section('Canvas / Split View', [
              makeEl('div', { className: 'uwc-grid' }, [
                settingInput('canvasTuning', 'Enable Canvas tuning'),
                settingInput('balancedSplitView', 'Balance split view'),
                settingInput('suppressCanvasMutations', 'Reduce Canvas mutation noise')
              ])
            ]),
            section('Adaptive mode', [
              makeEl('div', { className: 'uwc-grid' }, [
                settingInput('auto', 'Enable auto mode'),
                settingInput('disableOnTouch', 'Disable on touch devices'),
                settingInput('autoMinWidth', 'Auto min viewport width', 'number', `${LIMITS.autoMinWidth[0]}-${LIMITS.autoMinWidth[1]} px`),
                settingInput('disableBelowHeight', 'Disable below height', 'number', '0 disables this guard')
              ])
            ]),
            section('Spacing', [
              makeEl('div', { className: 'uwc-grid' }, [
                settingInput('gutterMin', 'Gutter min px', 'number'),
                settingInput('gutterVw', 'Gutter vw', 'number'),
                settingInput('gutterMax', 'Gutter max px', 'number')
              ])
            ]),
            section('Runtime tuning', [
              makeEl('div', { className: 'uwc-grid' }, [
                settingInput('toastMs', 'Toast duration ms', 'number'),
                settingInput('mutationDebounceMs', 'Mutation debounce ms', 'number'),
                settingInput('repairIntervalMs', 'Repair interval ms', 'number'),
                settingInput('routePollMs', 'Route poll ms', 'number'),
                settingInput('optionsCloseOnBackdrop', 'Close settings on backdrop')
              ])
            ]),
            section('Import / Export', [
              makeEl('div', { className: 'uwc-grid' }, [
                makeEl('div', { className: 'uwc-field' }, [
                  makeEl('label', { for: 'uwc-export-box', text: 'Export JSON' }),
                  exportBox,
                  makeEl('button', { type: 'button', text: 'Copy export JSON', onclick: exportSettingsToClipboard })
                ]),
                makeEl('div', { className: 'uwc-field' }, [
                  makeEl('label', { for: 'uwc-import-box', text: 'Import JSON' }),
                  importBox,
                  makeEl('button', {
                    type: 'button',
                    text: 'Import settings',
                    onclick: () => {
                      try { importSettingsFromText(importBox.value); }
                      catch (error) { showToast(`Import failed: ${error?.message || 'invalid JSON'}`); }
                    }
                  })
                ])
              ])
            ]),
            makeEl('div', { className: 'uwc-actions' }, [
              makeEl('button', { type: 'button', text: 'Apply now', onclick: () => commit('UltraWide settings applied', { forceTimerRestart: true }) }),
              makeEl('button', { type: 'button', text: 'Copy status', onclick: () => copyText(JSON.stringify(apiState(), null, 2)).then((ok) => showToast(ok ? 'UltraWide status copied' : 'Copy failed')) }),
              makeEl('button', { className: 'uwc-danger', type: 'button', text: 'Reset', onclick: resetSettings }),
              makeEl('button', { className: 'uwc-primary', type: 'button', text: 'Close', onclick: closeSettingsModal })
            ])
          ])
        ])
      ]);

      modal.addEventListener('click', (event) => {
        if (settings.optionsCloseOnBackdrop && event.target === modal) closeSettingsModal();
      });

      modal.addEventListener('keydown', (event) => {
        if (event.key === 'Escape') {
          event.preventDefault();
          event.stopPropagation();
          closeSettingsModal();
        }
      });

      const parent = document.body || document.documentElement;
      if (!parent) {
        showToast('Unable to mount settings UI');
        return;
      }

      runtime.suppressModalRefresh = true;
      parent.appendChild(modal);
      modal.tabIndex = -1;
      modal.focus({ preventScroll: true });
      runtime.suppressModalRefresh = false;
    } catch (error) {
      runtime.suppressModalRefresh = false;
      showToast(`Settings UI failed: ${error?.message || 'unknown error'}`);
    }
  }

  function repairTick() {
    if (!settings.enabled) {
      if (styleMounted()) unmountStyle();
      return;
    }

    checkRouteChange();

    if (!uiStyleMounted() || !styleMounted()) {
      schedule(true);
      return;
    }

    const nextEnv = envKey();
    if (nextEnv !== runtime.lastEnvKey) {
      runtime.lastEnvKey = nextEnv;
      schedule(true);
    }

    if (!runtime.headObserver && getHead()) attachHeadObserver();
  }

  function start() {
    if (runtime.started) return;

    loadSettings();
    runtime.started = true;
    runtime.href = location.href;
    runtime.lastCanvasProbe = 0;
    runtime.lastEnvKey = envKey();

    installHistoryHooks();
    installObservers();
    bind();
    registerMenus();

    runtime.routeTimer = window.setInterval(checkRouteChange, settings.routePollMs);
    runtime.repairTimer = window.setInterval(repairTick, settings.repairIntervalMs);

    schedule(true);
  }

  function stop() {
    if (!runtime.started) return;

    runtime.started = false;

    if (runtime.repairTimer) clearInterval(runtime.repairTimer);
    if (runtime.routeTimer) clearInterval(runtime.routeTimer);
    if (runtime.debounceTimer) clearTimeout(runtime.debounceTimer);
    if (runtime.toastTimer) clearTimeout(runtime.toastTimer);
    if (runtime.rafId) cancelAnimationFrame(runtime.rafId);

    runtime.repairTimer = 0;
    runtime.routeTimer = 0;
    runtime.debounceTimer = 0;
    runtime.toastTimer = 0;
    runtime.rafId = 0;

    unbind();
    disconnectObservers();
    restoreHistoryHooks();
    clearAttrs();
    unmountStyle();
    removeToast();
    closeSettingsModal();
  }

  function restart() {
    stop();
    start();
  }

  function apiState() {
    return {
      version: VERSION,
      started: runtime.started,
      enabled: settings.enabled,
      wide: settings.wide,
      left: settings.left,
      cap: settings.cap,
      auto: settings.auto,
      autoMinWidth: settings.autoMinWidth,
      disableOnTouch: settings.disableOnTouch,
      disableBelowHeight: settings.disableBelowHeight,
      showToast: settings.showToast,
      composerWide: settings.composerWide,
      codeWide: settings.codeWide,
      mediaSafe: settings.mediaSafe,
      canvasTuning: settings.canvasTuning,
      balancedSplitView: settings.balancedSplitView,
      suppressCanvasMutations: settings.suppressCanvasMutations,
      gutterMin: settings.gutterMin,
      gutterVw: settings.gutterVw,
      gutterMax: settings.gutterMax,
      toastMs: settings.toastMs,
      mutationDebounceMs: settings.mutationDebounceMs,
      repairIntervalMs: settings.repairIntervalMs,
      routePollMs: settings.routePollMs,
      optionsCloseOnBackdrop: settings.optionsCloseOnBackdrop,
      activeWide: wideActive(),
      canvasDetected: hasCanvasLayout(),
      href: runtime.href,
      env: runtime.lastEnvKey
    };
  }

  function installApi() {
    try {
      Object.defineProperty(window, '__mlUltraWide', {
        configurable: true,
        value: Object.freeze({
          version: VERSION,
          start,
          stop,
          restart,
          apply: () => schedule(true),
          set: setOptions,
          reset: resetSettings,
          state: apiState,
          caps: () => [...CAPS],
          openSettings: openSettingsModal,
          closeSettings: closeSettingsModal,
          exportSettings: currentSettingsJson,
          importSettings: importSettingsFromText
        })
      });
    } catch (_) {}
  }

  installApi();
  start();
})();