ChatGPT — UltraWide Pro

Expands ChatGPT’s conversation layout to fully utilize wide screens by removing restrictive width clamps and enabling an ultra-wide, full-viewport reading experience. Includes adaptive auto-mode, adjustable maximum width caps, left-alignment normalization, resilient SPA navigation handling, self-healing stylesheet injection, and native Tampermonkey settings.

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

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

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

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

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

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

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

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

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

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

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

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

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

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

// ==UserScript==
// @name         ChatGPT — UltraWide Pro
// @namespace    https://www.instagram.com/jsm.ig/
// @version      2026.03.13
// @author       Jonas
// @description  Expands ChatGPT’s conversation layout to fully utilize wide screens by removing restrictive width clamps and enabling an ultra-wide, full-viewport reading experience. Includes adaptive auto-mode, adjustable maximum width caps, left-alignment normalization, resilient SPA navigation handling, self-healing stylesheet injection, and native Tampermonkey settings.
// @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
// @grant        GM_addValueChangeListener
// @grant        GM_removeValueChangeListener
// ==/UserScript==

(() => {
'use strict';

const VERSION = '2026.03.12-Settings.2';
const STYLE_ID = 'ml-ultrawide-pro-style';
const STORAGE_KEY = 'ml_ultrawide_pro_v7';

const ATTR = Object.freeze({
  active: 'data-ml-active',
  unclamp: 'data-ml-unclamp',
  left: 'data-ml-left',
  cap: 'data-ml-cap',
  auto: 'data-ml-auto',
  touch: 'data-ml-touch'
});

const CONFIG = Object.freeze({
  gutters: { vw: 2, px: 22 },
  throttleMs: 100,
  idleTimeoutMs: 220,
  pollMs: 2600,
  headGuardMs: 1800,
  moDebounceMs: 80,
  moBurstMax: 18,
  moBurstWindowMs: 1400,
  auto: {
    enabled: true,
    minWidth: 1180,
    disableOnTouch: true,
    disableOnSmallHeight: 620
  },
  caps: ['none', '1600', '2000', '2400', '3000', '3600'],
  keys: {
    toggleAll:     { alt: true, shift: false, ctrl: false, key: 'o' },
    toggleUnclamp: { alt: true, shift: false, ctrl: false, key: 'u' },
    toggleLeft:    { alt: true, shift: false, ctrl: false, key: 'l' },
    cycleCap:      { alt: true, shift: false, ctrl: false, key: 'm' },
    toggleAuto:    { alt: true, shift: false, ctrl: false, key: 'a' }
  }
});

const DEFAULT_PREFS = Object.freeze({
  active: true,
  unclamp: true,
  left: true,
  cap: 'none',
  auto: CONFIG.auto.enabled,
  autoMinWidth: CONFIG.auto.minWidth,
  autoDisableOnTouch: CONFIG.auto.disableOnTouch,
  autoDisableOnSmallHeight: CONFIG.auto.disableOnSmallHeight
});

const SELECTORS = Object.freeze({
  appShell: [
    'html',
    'body',
    '#__next',
    'main',
    '[role="main"]',
    '[data-testid="stretched-app"]',
    '[data-testid="main-app"]',
    '[data-testid="app-root"]',
    '[data-testid="chat-layout"]',
    '[data-testid="conversation-container"]',
    '[data-testid="conversation-view"]'
  ],
  unclampContainers: [
    'main [class*="max-w"]',
    'main .container',
    'main .prose',
    'main .markdown',
    'main .content',
    'main .layout',
    'main .chat',
    'main .conversation-turns',
    '[data-testid="conversation-turns"]',
    '[data-testid="conversation-view"]',
    '[data-testid="conversation-content"]',
    '[data-testid="conversation-container"]',
    '[class*="max-w-"]',
    '[class*="max-w-screen"]'
  ],
  conversationTurns: [
    '[data-testid="conversation-turn"]',
    '[data-message-author-role]',
    '.message',
    '.chat-message',
    '.chat-entry',
    '.bubble',
    '.text-message'
  ],
  conversationTurnInner: [
    '[data-testid="conversation-turn"] > div',
    '[data-message-author-role] > div'
  ],
  markdownBlocks: [
    '[data-message-author-role] .markdown',
    '[data-message-author-role] [class*="prose"]',
    '[data-testid="conversation-turn"] .markdown',
    '[data-testid="conversation-turn"] [class*="prose"]',
    '.chat-message .markdown'
  ],
  composerInputs: [
    '[data-testid="composer:input"]',
    'form textarea',
    'form [contenteditable="true"][role="textbox"]',
    '[aria-label*="message" i]',
    '[aria-label*="prompt" i]',
    '[aria-label*="send a message" i]'
  ],
  sidebarLike: [
    '[aria-label*="sidebar" i]',
    '[data-testid*="sidebar" i]'
  ]
});

const state = {
  started: false,
  ready: false,

  active: DEFAULT_PREFS.active,
  unclamp: DEFAULT_PREFS.unclamp,
  left: DEFAULT_PREFS.left,
  cap: DEFAULT_PREFS.cap,
  auto: DEFAULT_PREFS.auto,
  autoMinWidth: DEFAULT_PREFS.autoMinWidth,
  autoDisableOnTouch: DEFAULT_PREFS.autoDisableOnTouch,
  autoDisableOnSmallHeight: DEFAULT_PREFS.autoDisableOnSmallHeight,

  href: '',
  lastApplyTs: 0,
  lastCssKey: '',
  lastEnvKey: '',
  lastMountedTs: 0,

  scheduled: false,
  idleId: null,
  rafId: 0,
  resizeRaf: 0,
  moTimer: 0,
  moBurstStart: 0,
  moBurstCount: 0,

  sheet: null,
  docMo: null,
  headMo: null,
  bootstrapMo: null,

  pollTimer: 0,
  guardTimer: 0,

  originalPushState: null,
  originalReplaceState: null,

  handlers: Object.create(null),
  valueListeners: []
};

const now = () => performance.now();

function getStoreKey(key) {
  return `${STORAGE_KEY}.${key}`;
}

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

function joinSelectors(list) {
  return list.join(',');
}

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

function envKey() {
  const w = window.innerWidth || 0;
  const h = window.innerHeight || 0;
  const dpr = window.devicePixelRatio || 1;
  const touch = isTouchLike() ? 't' : 'd';
  const full = document.fullscreenElement ? 'fs1' : 'fs0';
  return `${w}x${h}@${dpr}:${touch}:${full}:${state.auto ? 'a1' : 'a0'}:${state.autoMinWidth}:${state.autoDisableOnTouch ? 1 : 0}:${state.autoDisableOnSmallHeight}`;
}

function cssKey() {
  return [
    state.active ? 1 : 0,
    state.unclamp ? 1 : 0,
    state.left ? 1 : 0,
    state.cap,
    state.auto ? 1 : 0,
    state.autoMinWidth,
    state.autoDisableOnTouch ? 1 : 0,
    state.autoDisableOnSmallHeight
  ].join('|');
}

function normalizeCap(v) {
  const s = String(v ?? '').trim().toLowerCase();
  return CONFIG.caps.includes(s) ? s : DEFAULT_PREFS.cap;
}

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

function normalizeInt(v, fallback, min, max) {
  const n = Number(v);
  if (!Number.isFinite(n)) return fallback;
  const clamped = Math.min(Math.max(Math.round(n), min), max);
  return clamped;
}

function loadPrefs() {
  try {
    state.active = normalizeBool(GM_getValue(getStoreKey('active'), DEFAULT_PREFS.active), DEFAULT_PREFS.active);
    state.unclamp = normalizeBool(GM_getValue(getStoreKey('unclamp'), DEFAULT_PREFS.unclamp), DEFAULT_PREFS.unclamp);
    state.left = normalizeBool(GM_getValue(getStoreKey('left'), DEFAULT_PREFS.left), DEFAULT_PREFS.left);
    state.auto = normalizeBool(GM_getValue(getStoreKey('auto'), DEFAULT_PREFS.auto), DEFAULT_PREFS.auto);
    state.cap = normalizeCap(GM_getValue(getStoreKey('cap'), DEFAULT_PREFS.cap));
    state.autoMinWidth = normalizeInt(GM_getValue(getStoreKey('autoMinWidth'), DEFAULT_PREFS.autoMinWidth), DEFAULT_PREFS.autoMinWidth, 640, 5000);
    state.autoDisableOnTouch = normalizeBool(GM_getValue(getStoreKey('autoDisableOnTouch'), DEFAULT_PREFS.autoDisableOnTouch), DEFAULT_PREFS.autoDisableOnTouch);
    state.autoDisableOnSmallHeight = normalizeInt(GM_getValue(getStoreKey('autoDisableOnSmallHeight'), DEFAULT_PREFS.autoDisableOnSmallHeight), DEFAULT_PREFS.autoDisableOnSmallHeight, 0, 3000);
  } catch {}
}

function savePref(key, value) {
  try {
    GM_setValue(getStoreKey(key), value);
  } catch {}
}

function saveAllPrefs() {
  savePref('active', state.active);
  savePref('unclamp', state.unclamp);
  savePref('left', state.left);
  savePref('auto', state.auto);
  savePref('cap', state.cap);
  savePref('autoMinWidth', state.autoMinWidth);
  savePref('autoDisableOnTouch', state.autoDisableOnTouch);
  savePref('autoDisableOnSmallHeight', state.autoDisableOnSmallHeight);
}

function reloadPage() {
  try {
    window.location.reload();
  } catch {
    location.href = location.href;
  }
}

function resetPrefs() {
  state.active = DEFAULT_PREFS.active;
  state.unclamp = DEFAULT_PREFS.unclamp;
  state.left = DEFAULT_PREFS.left;
  state.cap = DEFAULT_PREFS.cap;
  state.auto = DEFAULT_PREFS.auto;
  state.autoMinWidth = DEFAULT_PREFS.autoMinWidth;
  state.autoDisableOnTouch = DEFAULT_PREFS.autoDisableOnTouch;
  state.autoDisableOnSmallHeight = DEFAULT_PREFS.autoDisableOnSmallHeight;
  saveAllPrefs();
}

function shouldEnableWide() {
  if (!state.active) return false;
  if (!state.unclamp) return false;
  if (!state.auto) return true;

  const w = window.innerWidth || 0;
  const h = window.innerHeight || 0;

  if (state.autoDisableOnTouch && isTouchLike()) return false;
  if (state.autoDisableOnSmallHeight > 0 && h > 0 && h < state.autoDisableOnSmallHeight) return false;

  return w >= state.autoMinWidth;
}

function clearRootFlags() {
  const root = document.documentElement;
  if (!root) return;
  root.removeAttribute(ATTR.active);
  root.removeAttribute(ATTR.unclamp);
  root.removeAttribute(ATTR.left);
  root.removeAttribute(ATTR.cap);
  root.removeAttribute(ATTR.auto);
  root.removeAttribute(ATTR.touch);
}

function setRootFlags() {
  const root = document.documentElement;
  if (!root) return;

  if (state.active) root.setAttribute(ATTR.active, '1');
  else root.removeAttribute(ATTR.active);

  if (state.active) root.setAttribute(ATTR.cap, state.cap);
  else root.removeAttribute(ATTR.cap);

  if (state.active && state.left) root.setAttribute(ATTR.left, '1');
  else root.removeAttribute(ATTR.left);

  if (state.auto) root.setAttribute(ATTR.auto, '1');
  else root.removeAttribute(ATTR.auto);

  if (isTouchLike()) root.setAttribute(ATTR.touch, '1');
  else root.removeAttribute(ATTR.touch);

  if (shouldEnableWide()) root.setAttribute(ATTR.unclamp, '1');
  else root.removeAttribute(ATTR.unclamp);
}

function buildCss() {
  const appShell = joinSelectors(SELECTORS.appShell);
  const unclampContainers = joinSelectors(SELECTORS.unclampContainers);
  const conversationTurns = joinSelectors(SELECTORS.conversationTurns);
  const conversationTurnInner = joinSelectors(SELECTORS.conversationTurnInner);
  const markdownBlocks = joinSelectors(SELECTORS.markdownBlocks);
  const composerInputs = joinSelectors(SELECTORS.composerInputs);
  const sidebarLike = joinSelectors(SELECTORS.sidebarLike);

  return String.raw`
:root[${ATTR.active}="1"]{
  --ml-gutter:min(${CONFIG.gutters.vw}vw,${CONFIG.gutters.px}px);
  --ml-cap:none;
}

:root[${ATTR.active}="1"][${ATTR.cap}="none"]{--ml-cap:none}
:root[${ATTR.active}="1"][${ATTR.cap}="1600"]{--ml-cap:1600px}
:root[${ATTR.active}="1"][${ATTR.cap}="2000"]{--ml-cap:2000px}
:root[${ATTR.active}="1"][${ATTR.cap}="2400"]{--ml-cap:2400px}
:root[${ATTR.active}="1"][${ATTR.cap}="3000"]{--ml-cap:3000px}
:root[${ATTR.active}="1"][${ATTR.cap}="3600"]{--ml-cap:3600px}

:root[${ATTR.unclamp}="1"] html,
:root[${ATTR.unclamp}="1"] body{
  width:100% !important;
  max-width:none !important;
  overflow-x:visible !important;
}

:root[${ATTR.unclamp}="1"] ${appShell}{
  max-width:none !important;
}

:root[${ATTR.unclamp}="1"] #__next,
:root[${ATTR.unclamp}="1"] main,
:root[${ATTR.unclamp}="1"] [role="main"],
:root[${ATTR.unclamp}="1"] [data-testid="stretched-app"],
:root[${ATTR.unclamp}="1"] [data-testid="main-app"],
:root[${ATTR.unclamp}="1"] [data-testid="app-root"],
:root[${ATTR.unclamp}="1"] [data-testid="chat-layout"],
:root[${ATTR.unclamp}="1"] [data-testid="conversation-container"],
:root[${ATTR.unclamp}="1"] [data-testid="conversation-view"]{
  width:100% !important;
  max-width:100vw !important;
  margin:0 !important;
  padding-left:var(--ml-gutter) !important;
  padding-right:var(--ml-gutter) !important;
  box-sizing:border-box !important;
}

:root[${ATTR.unclamp}="1"] ${unclampContainers}{
  width:100% !important;
  max-width:none !important;
  margin-left:0 !important;
  margin-right:0 !important;
  box-sizing:border-box !important;
}

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

:root[${ATTR.unclamp}="1"] ${conversationTurnInner}{
  width:100% !important;
  max-width:var(--ml-cap) !important;
  margin-left:auto !important;
  margin-right:auto !important;
  box-sizing:border-box !important;
}

:root[${ATTR.unclamp}="1"][${ATTR.cap}="none"] ${conversationTurnInner}{
  max-width:none !important;
}

:root[${ATTR.unclamp}="1"] ${markdownBlocks}{
  max-width:none !important;
}

:root[${ATTR.unclamp}="1"] pre,
:root[${ATTR.unclamp}="1"] .markdown pre{
  width:100% !important;
  max-width:100% !important;
  max-height:none !important;
  overflow-x:auto !important;
  overflow-y:visible !important;
  white-space:pre !important;
  box-sizing:border-box !important;
}

:root[${ATTR.unclamp}="1"] code,
:root[${ATTR.unclamp}="1"] .markdown code{
  white-space:pre !important;
}

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

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

:root[${ATTR.unclamp}="1"] ${sidebarLike}{
  max-width:none !important;
}

:root[${ATTR.left}="1"] ${composerInputs}{
  text-align:left !important;
  direction:ltr !important;
  justify-content:flex-start !important;
  align-items:flex-start !important;
}

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

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

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

@media print{
  :root[${ATTR.unclamp}="1"] html,
  :root[${ATTR.unclamp}="1"] body,
  :root[${ATTR.unclamp}="1"] #__next,
  :root[${ATTR.unclamp}="1"] main,
  :root[${ATTR.unclamp}="1"] [role="main"]{
    width:100% !important;
    max-width:none !important;
    text-align:left !important;
  }
}
`.trim();
}

function isStyleMounted() {
  try {
    if (state.sheet && Array.isArray(document.adoptedStyleSheets) && document.adoptedStyleSheets.includes(state.sheet)) {
      return true;
    }
  } catch {}
  const head = getHead();
  const el = document.getElementById(STYLE_ID);
  return !!(head && el && head.contains(el));
}

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

  const css = buildCss();

  try {
    if ('adoptedStyleSheets' in Document.prototype && 'replaceSync' in CSSStyleSheet.prototype) {
      if (!state.sheet) state.sheet = new CSSStyleSheet();
      state.sheet.replaceSync(css);

      const sheets = document.adoptedStyleSheets || [];
      if (!sheets.includes(state.sheet)) {
        document.adoptedStyleSheets = [...sheets, state.sheet];
      }

      const fallback = document.getElementById(STYLE_ID);
      if (fallback && fallback.parentNode) fallback.parentNode.removeChild(fallback);

      state.lastCssKey = cssKey();
      state.lastMountedTs = now();
      return true;
    }
  } catch {}

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

  state.lastCssKey = cssKey();
  state.lastMountedTs = now();
  return true;
}

function unmountCss() {
  try {
    if (state.sheet && Array.isArray(document.adoptedStyleSheets) && document.adoptedStyleSheets.includes(state.sheet)) {
      document.adoptedStyleSheets = document.adoptedStyleSheets.filter(s => s !== state.sheet);
    }
  } catch {}

  const el = document.getElementById(STYLE_ID);
  if (el && el.parentNode) el.parentNode.removeChild(el);
}

function cleanupVisuals() {
  clearRootFlags();
  unmountCss();
}

function apply() {
  if (!document.documentElement) return;

  if (!state.active) {
    cleanupVisuals();
    state.lastApplyTs = now();
    state.ready = true;
    return;
  }

  const nextCssKey = cssKey();
  if (nextCssKey !== state.lastCssKey || !isStyleMounted()) {
    if (!mountCss()) return;
  }

  setRootFlags();

  state.lastApplyTs = now();
  state.ready = true;
}

function cancelScheduled() {
  state.scheduled = false;

  if (state.rafId) {
    cancelAnimationFrame(state.rafId);
    state.rafId = 0;
  }

  if (state.idleId != null && typeof cancelIdleCallback === 'function') {
    try { cancelIdleCallback(state.idleId); } catch {}
    state.idleId = null;
  }
}

function schedule(force = false) {
  const t = now();
  if (!force && t - state.lastApplyTs < CONFIG.throttleMs) return;
  if (state.scheduled) return;

  state.scheduled = true;

  const run = () => {
    state.scheduled = false;
    state.rafId = 0;
    state.idleId = null;
    apply();
  };

  if (typeof requestIdleCallback === 'function') {
    try {
      state.idleId = requestIdleCallback(run, { timeout: CONFIG.idleTimeoutMs });
      return;
    } catch {}
  }

  state.rafId = requestAnimationFrame(() => Promise.resolve().then(run));
}

function relevantMutation(mutations) {
  for (let i = 0; i < mutations.length; i++) {
    const m = mutations[i];
    if (!m) continue;
    if (m.type === 'childList') {
      if (m.addedNodes && m.addedNodes.length) return true;
      if (m.removedNodes && m.removedNodes.length) return true;
    }
    if (m.type === 'attributes') return true;
  }
  return false;
}

function burstGuardedSchedule() {
  const t = now();
  if (!state.moBurstStart || t - state.moBurstStart > CONFIG.moBurstWindowMs) {
    state.moBurstStart = t;
    state.moBurstCount = 0;
  }
  state.moBurstCount++;
  if (state.moBurstCount > CONFIG.moBurstMax) return;
  schedule(false);
}

function onMutations(mutations) {
  if (!relevantMutation(mutations)) return;
  if (state.moTimer) return;
  state.moTimer = window.setTimeout(() => {
    state.moTimer = 0;
    burstGuardedSchedule();
  }, CONFIG.moDebounceMs);
}

function onHrefMaybeChanged() {
  const href = location.href;
  if (href !== state.href) {
    state.href = href;
    schedule(true);
  } else {
    schedule(false);
  }
}

function wrapHistoryMethod(original) {
  return function wrappedHistoryMethod(...args) {
    const out = original.apply(this, args);
    Promise.resolve().then(onHrefMaybeChanged);
    return out;
  };
}

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

  if (state.headMo) {
    try { state.headMo.disconnect(); } catch {}
  }

  try {
    state.headMo = new MutationObserver(() => {
      if (!isStyleMounted()) schedule(true);
    });
    state.headMo.observe(head, { childList: true, subtree: true, attributes: false });
    return true;
  } catch {
    state.headMo = null;
    return false;
  }
}

function initObservers() {
  try {
    if (document.documentElement) {
      state.docMo = new MutationObserver(onMutations);
      state.docMo.observe(document.documentElement, {
        childList: true,
        subtree: true,
        attributes: false
      });
    }
  } catch {}

  connectHeadObserver();

  if (!getHead() && document.documentElement) {
    try {
      state.bootstrapMo = new MutationObserver(() => {
        if (getHead()) {
          connectHeadObserver();
          if (state.bootstrapMo) {
            try { state.bootstrapMo.disconnect(); } catch {}
            state.bootstrapMo = null;
          }
          schedule(true);
        }
      });
      state.bootstrapMo.observe(document.documentElement, {
        childList: true,
        subtree: true,
        attributes: false
      });
    } catch {}
  }
}

function disconnectObservers() {
  try { if (state.docMo) state.docMo.disconnect(); } catch {}
  try { if (state.headMo) state.headMo.disconnect(); } catch {}
  try { if (state.bootstrapMo) state.bootstrapMo.disconnect(); } catch {}
  state.docMo = null;
  state.headMo = null;
  state.bootstrapMo = null;
}

function initNavHooks() {
  try {
    if (!state.originalPushState) state.originalPushState = history.pushState;
    if (!state.originalReplaceState) state.originalReplaceState = history.replaceState;

    if (history.pushState === state.originalPushState) {
      history.pushState = wrapHistoryMethod(state.originalPushState);
    }
    if (history.replaceState === state.originalReplaceState) {
      history.replaceState = wrapHistoryMethod(state.originalReplaceState);
    }
  } catch {}
}

function restoreNavHooks() {
  try {
    if (state.originalPushState && history.pushState !== state.originalPushState) {
      history.pushState = state.originalPushState;
    }
  } catch {}
  try {
    if (state.originalReplaceState && history.replaceState !== state.originalReplaceState) {
      history.replaceState = state.originalReplaceState;
    }
  } catch {}
}

function clearTimers() {
  if (state.pollTimer) {
    clearInterval(state.pollTimer);
    state.pollTimer = 0;
  }
  if (state.guardTimer) {
    clearInterval(state.guardTimer);
    state.guardTimer = 0;
  }
  if (state.moTimer) {
    clearTimeout(state.moTimer);
    state.moTimer = 0;
  }
  if (state.resizeRaf) {
    cancelAnimationFrame(state.resizeRaf);
    state.resizeRaf = 0;
  }
  cancelScheduled();
}

function isMatch(mods, e) {
  if (!!mods.alt !== !!e.altKey) return false;
  if (!!mods.shift !== !!e.shiftKey) return false;
  if (!!mods.ctrl !== !!(e.ctrlKey || e.metaKey)) return false;
  return String(e.key || '').toLowerCase() === String(mods.key || '').toLowerCase();
}

function toggleAll() {
  state.active = !state.active;
  savePref('active', state.active);
  schedule(true);
}

function toggleUnclamp() {
  state.unclamp = !state.unclamp;
  savePref('unclamp', state.unclamp);
  schedule(true);
}

function toggleLeft() {
  state.left = !state.left;
  savePref('left', state.left);
  schedule(true);
}

function toggleAuto() {
  state.auto = !state.auto;
  savePref('auto', state.auto);
  schedule(true);
}

function cycleCap() {
  const idx = CONFIG.caps.indexOf(state.cap);
  state.cap = CONFIG.caps[(idx + 1 + CONFIG.caps.length) % CONFIG.caps.length] || 'none';
  savePref('cap', state.cap);
  schedule(true);
}

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

  const tag = e.target && e.target.tagName ? String(e.target.tagName).toLowerCase() : '';
  const isTyping = tag === 'textarea' || tag === 'input' || !!(e.target && e.target.isContentEditable);
  const k = String(e.key || '').toLowerCase();
  const isOurCombo = e.altKey && (k === 'o' || k === 'u' || k === 'l' || k === 'm' || k === 'a');

  if (isTyping && !isOurCombo) return;

  if (isMatch(CONFIG.keys.toggleAll, e)) { e.preventDefault(); toggleAll(); return; }
  if (isMatch(CONFIG.keys.toggleUnclamp, e)) { e.preventDefault(); toggleUnclamp(); return; }
  if (isMatch(CONFIG.keys.toggleLeft, e)) { e.preventDefault(); toggleLeft(); return; }
  if (isMatch(CONFIG.keys.cycleCap, e)) { e.preventDefault(); cycleCap(); return; }
  if (isMatch(CONFIG.keys.toggleAuto, e)) { e.preventDefault(); toggleAuto(); return; }
}

function onResize() {
  if (state.resizeRaf) cancelAnimationFrame(state.resizeRaf);
  state.resizeRaf = requestAnimationFrame(() => {
    state.resizeRaf = 0;
    const k = envKey();
    if (k !== state.lastEnvKey) {
      state.lastEnvKey = k;
      schedule(true);
    }
  });
}

function syncFromStorage() {
  const before = `${state.active}|${state.unclamp}|${state.left}|${state.cap}|${state.auto}|${state.autoMinWidth}|${state.autoDisableOnTouch}|${state.autoDisableOnSmallHeight}`;
  loadPrefs();
  const after = `${state.active}|${state.unclamp}|${state.left}|${state.cap}|${state.auto}|${state.autoMinWidth}|${state.autoDisableOnTouch}|${state.autoDisableOnSmallHeight}`;
  if (before !== after) {
    state.lastEnvKey = envKey();
    schedule(true);
  }
}

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

function onPageShow() {
  schedule(true);
}

function onPageHide() {
  if (state.moTimer) {
    clearTimeout(state.moTimer);
    state.moTimer = 0;
  }
  cancelScheduled();
}

function onFocus() {
  schedule(true);
}

function onPopState() {
  onHrefMaybeChanged();
}

function onOrientationChange() {
  schedule(true);
}

function onFullscreenChange() {
  const k = envKey();
  if (k !== state.lastEnvKey) state.lastEnvKey = k;
  schedule(true);
}

function bindListeners() {
  state.handlers.keydown = onKeydown;
  state.handlers.resize = onResize;
  state.handlers.visibilitychange = onVisibilityChange;
  state.handlers.pageshow = onPageShow;
  state.handlers.pagehide = onPageHide;
  state.handlers.focus = onFocus;
  state.handlers.popstate = onPopState;
  state.handlers.orientationchange = onOrientationChange;
  state.handlers.fullscreenchange = onFullscreenChange;

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

function unbindListeners() {
  if (state.handlers.keydown) window.removeEventListener('keydown', state.handlers.keydown, true);
  if (state.handlers.resize) window.removeEventListener('resize', state.handlers.resize, { passive: true });
  if (state.handlers.visibilitychange) document.removeEventListener('visibilitychange', state.handlers.visibilitychange, { passive: true });
  if (state.handlers.pageshow) window.removeEventListener('pageshow', state.handlers.pageshow, { passive: true });
  if (state.handlers.pagehide) window.removeEventListener('pagehide', state.handlers.pagehide, { passive: true });
  if (state.handlers.focus) window.removeEventListener('focus', state.handlers.focus, { passive: true });
  if (state.handlers.popstate) window.removeEventListener('popstate', state.handlers.popstate, { passive: true });
  if (state.handlers.orientationchange) window.removeEventListener('orientationchange', state.handlers.orientationchange, { passive: true });
  if (state.handlers.fullscreenchange) document.removeEventListener('fullscreenchange', state.handlers.fullscreenchange, { passive: true });

  state.handlers = Object.create(null);
}

function initGuards() {
  state.guardTimer = window.setInterval(() => {
    if (!state.started || !state.ready) return;

    const currentEnv = envKey();
    if (currentEnv !== state.lastEnvKey) {
      state.lastEnvKey = currentEnv;
      schedule(true);
      return;
    }

    if (state.active && !isStyleMounted()) {
      schedule(true);
      return;
    }

    if (!state.headMo && getHead()) {
      connectHeadObserver();
      schedule(true);
    }
  }, CONFIG.headGuardMs);
}

function menuLabelBool(label, value) {
  return `${value ? '✅' : '❌'} ${label}`;
}

function menuLabelValue(label, value) {
  return `⚙️ ${label}: ${value}`;
}

function promptCap() {
  const current = state.cap;
  const input = prompt(`Set max width cap.\nAllowed: ${CONFIG.caps.join(', ')}\n\nCurrent: ${current}`, current);
  if (input == null) return;
  state.cap = normalizeCap(input);
  savePref('cap', state.cap);
  reloadPage();
}

function promptAutoMinWidth() {
  const current = state.autoMinWidth;
  const input = prompt('Set auto-mode minimum viewport width in pixels.', String(current));
  if (input == null) return;
  state.autoMinWidth = normalizeInt(input, current, 640, 5000);
  savePref('autoMinWidth', state.autoMinWidth);
  state.lastEnvKey = envKey();
  reloadPage();
}

function promptSmallHeightCutoff() {
  const current = state.autoDisableOnSmallHeight;
  const input = prompt('Set auto-mode small-height cutoff in pixels.\nUse 0 to disable.', String(current));
  if (input == null) return;
  state.autoDisableOnSmallHeight = normalizeInt(input, current, 0, 3000);
  savePref('autoDisableOnSmallHeight', state.autoDisableOnSmallHeight);
  state.lastEnvKey = envKey();
  reloadPage();
}

function registerMenu() {
  GM_registerMenuCommand(menuLabelBool('Script enabled', state.active), () => {
    state.active = !state.active;
    savePref('active', state.active);
    reloadPage();
  });

  GM_registerMenuCommand(menuLabelBool('Unclamp enabled', state.unclamp), () => {
    state.unclamp = !state.unclamp;
    savePref('unclamp', state.unclamp);
    reloadPage();
  });

  GM_registerMenuCommand(menuLabelBool('Left alignment enabled', state.left), () => {
    state.left = !state.left;
    savePref('left', state.left);
    reloadPage();
  });

  GM_registerMenuCommand(menuLabelBool('Auto mode enabled', state.auto), () => {
    state.auto = !state.auto;
    savePref('auto', state.auto);
    reloadPage();
  });

  GM_registerMenuCommand(menuLabelValue('Max width cap', state.cap), () => {
    promptCap();
  });

  GM_registerMenuCommand(menuLabelValue('Auto min width', `${state.autoMinWidth}px`), () => {
    promptAutoMinWidth();
  });

  GM_registerMenuCommand(menuLabelBool('Disable on touch', state.autoDisableOnTouch), () => {
    state.autoDisableOnTouch = !state.autoDisableOnTouch;
    savePref('autoDisableOnTouch', state.autoDisableOnTouch);
    state.lastEnvKey = envKey();
    reloadPage();
  });

  GM_registerMenuCommand(menuLabelValue('Small-height cutoff', `${state.autoDisableOnSmallHeight}px`), () => {
    promptSmallHeightCutoff();
  });

  GM_registerMenuCommand('🔄 Cycle max width cap', () => {
    const idx = CONFIG.caps.indexOf(state.cap);
    state.cap = CONFIG.caps[(idx + 1 + CONFIG.caps.length) % CONFIG.caps.length] || 'none';
    savePref('cap', state.cap);
    reloadPage();
  });

  GM_registerMenuCommand('♻️ Reset all settings', () => {
    const ok = confirm('Reset all ChatGPT — UltraWide Pro settings to defaults?');
    if (!ok) return;
    resetPrefs();
    state.lastEnvKey = envKey();
    reloadPage();
  });
}

function initValueSync() {
  const keys = [
    'active',
    'unclamp',
    'left',
    'auto',
    'cap',
    'autoMinWidth',
    'autoDisableOnTouch',
    'autoDisableOnSmallHeight'
  ];

  for (const key of keys) {
    try {
      const id = GM_addValueChangeListener(getStoreKey(key), () => {
        syncFromStorage();
      });
      state.valueListeners.push(id);
    } catch {}
  }
}

function removeValueSync() {
  for (const id of state.valueListeners) {
    try {
      GM_removeValueChangeListener(id);
    } catch {}
  }
  state.valueListeners = [];
}

function initSettings() {
  loadPrefs();
  registerMenu();
  initValueSync();
}

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

  initSettings();
  state.href = location.href;
  state.lastEnvKey = envKey();

  initNavHooks();
  initObservers();
  bindListeners();
  initGuards();

  state.pollTimer = window.setInterval(onHrefMaybeChanged, CONFIG.pollMs);

  schedule(true);

  state.started = true;
}

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

  clearTimers();
  unbindListeners();
  disconnectObservers();
  restoreNavHooks();
  removeValueSync();
  cleanupVisuals();

  state.started = false;
  state.ready = false;
}

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

start();

Object.defineProperty(window, '__mlUltraWide', {
  value: Object.freeze({
    version: VERSION,
    start,
    stop,
    restart,
    apply: () => schedule(true),
    state: () => ({
      active: state.active,
      unclamp: state.unclamp,
      left: state.left,
      cap: state.cap,
      auto: state.auto,
      autoMinWidth: state.autoMinWidth,
      autoDisableOnTouch: state.autoDisableOnTouch,
      autoDisableOnSmallHeight: state.autoDisableOnSmallHeight,
      started: state.started,
      ready: state.ready,
      href: state.href,
      env: state.lastEnvKey
    }),
    defaults: () => ({ ...DEFAULT_PREFS })
  }),
  configurable: true
});

})();