cC~

tts streaming respose for chatgpt. Hide UI bloat on chatgpt, gemini, claude, mistral.

// ==UserScript==
// @name         cC~
// @homepageURL  https://github.com/happyf-weallareeuropean/cC
// @namespace    https://github.com/happyf-weallareeuropean
// @version      2025.08.26
// @author       felixy happyfceleste & Johannes Thyroff(https://github.com/JThyroff/WideGPT)
// @description  tts streaming respose for chatgpt. Hide UI bloat on chatgpt, gemini, claude, mistral.
// @match     *://chatgpt.com/*
// @match     *://gemini.google.com/*
// @match     *://claude.ai/*
// @match     *://mistral.ai/*
// @icon         https://www.google.com/s2/favicons?sz=64&domain=openai.com
// @connect      localhost
// @grant        GM_xmlhttpRequest
// @run-at       document-body
// @license MIT 
// ==/UserScript==

(() => {
 'use strict';
  /* Use page context for hooks
  const uW = typeof unsafeWindow !== 'undefined' ? unsafeWindow : window;
  // Lower-level stream hook: intercept fetch streaming tokens directly
  const origFetch = uW.fetch;
  uW.fetch = async (...args) => {
    console.log("[fetch-hook] invoked, url:", args[0]);
    const response = await origFetch(...args);
    const contentType = response.headers.get("Content-Type");
    console.log("[fetch-hook] content-type:", contentType);

    if (args[0].includes("/backend-api/conversation") && contentType?.includes("text/event-stream")) {
      console.log("[fetch-hook] matched conversation endpoint and stream confirmed");

      const reader = response.body.getReader();
      const decoder = new TextDecoder("utf-8");

      let buffer = '';
      (async () => {
        while (true) {
          const { done, value } = await reader.read();
          if (done) break;

          console.log("[fetch-hook] stream chunk (first 100 bytes):", value && value.slice ? value.slice(0, 100) : value);
          buffer += decoder.decode(value, { stream: true });
          const lines = buffer.split('\n');
          buffer = lines.pop();

          for (const line of lines) {
            if (line.startsWith("data: ")) {
              const json = line.slice(6);
              try {
                const msg = JSON.parse(json);
                const delta = msg.choices?.[0]?.delta;
                if (delta?.content) {
                  GM_xmlhttpRequest({
                    method: "POST",
                    url: "http://localhost:65535/speak",
                    headers: { "Content-Type": "application/json" },
                    data: JSON.stringify({ text: delta.content })
                  });
                }
              } catch (err) {
                console.warn("Streaming parse failed", err);
              }
            }
          }
        }
      })();
    } else {
      console.log("[fetch-hook] no match conversation endpoint:", args[0], contentType);
    }

    return response;
  };*/
  /* Monkey-patch EventSource to intercept raw ChatGPT token stream
  const _OrigEventSource = uW.EventSource;
  uW.EventSource = function(url, ...args) {
    console.log("[SSE-hook] EventSource intercepted, url:", url);
    const es = new _OrigEventSource(url, ...args);
    if (typeof url === 'string' && url.includes("/backend-api/conversation")) {
      es.addEventListener('message', e => {
        if (!e.data || e.data === '[DONE]') return;
        // split lines in case multiple data: entries
        e.data.split('\n').forEach(line => {
          if (line.startsWith('data: ')) {
            const jsonStr = line.slice(6);
            try {
              const msg = JSON.parse(jsonStr);
              const delta = msg.choices?.[0]?.delta;
              if (delta?.content) {
                // send each raw token to TTS server
                GM_xmlhttpRequest({
                  method: "POST",
                  url: "http://localhost: 65535/speak",
                  headers: { "Content-Type": "application/json" },
                  data: JSON.stringify({ text: delta.content })
                });
              }
            } catch (err) {
              console.error('SSE parse error', err);
            }
          }
        });
      });
    }
    return es;
  };
  uW.EventSource.prototype = _OrigEventSource.prototype;*/
  // -------------------------------------------------------------------
  /* ==== CSS TRIMS ==== */
  const host = location.host;
  function insCss(cssText) {
    console.log("inscss: entered func");
    const head = document.head || document.documentElement;
    let styleNode = document.getElementById("vwide-css-top");
    console.log("inscss: it readyed");
    if (!styleNode) {
      styleNode = document.createElement("style");
      styleNode.id = "vwide-css-top";
      //styleNode.type = "text/css";
      head.append(styleNode);
      console.log("inscss: created");
    }
    styleNode.textContent = cssText;
    console.log("inscss: done");
  }

  // dom way
  if (host === "chatgpt.com") {
    let euok = false;
    const port = 65535; //8080
    const sel_resp = 'div[class~="markdown"][class~="prose"]';
    const sel_realroman = '[data-message-author-role="assistant"]' + ':not([data-message-id*="placeholder-request" i])' + ":not(:has(.result-thinking, .placeholder-request))";
    const sel_chatlist = ["main .flex.flex-col.text-sm"];
    const sel_scrolbut = "button.cursor-pointer.absolute.z-10.rounded-full.bg-clip-padding.border.text-token-text-secondary.border-token-border-default";

    const USER_PREFIX = "";
    const USER_SUFFIX = "";
    const SYSTEM_PROMPT = ``;
      let pinof = false;

    function ttsend({ text, flushQueue = false, onSuccess = null }) {
      const payload = flushQueue ? { flushQueue: true, text: text } : { text: text };
      GM_xmlhttpRequest({
        method: "POST",
        url: `http://localhost:${port}/speak`,
        headers: { "Content-Type": "application/json; charset=utf-8" },
        data: JSON.stringify(payload),
        onload(response) {
          if (response.status === 200) {
            if (onSuccess) onSuccess();
          } else {
            console.error("❌ ttsend failed:", response.status, response.statusText, response.responseText);
          }
        },
        onerror(err) {
          console.error("❌ ttsend network error", err);
        },
      });
    }
    
    //skip deeper spans
    function getCleanText(node) {
      let txt = "";
      node.childNodes.forEach((child) => {
        if (child.nodeType === Node.TEXT_NODE) {
          // direct text
          txt += child.textContent;
        } else if (child.nodeType === Node.ELEMENT_NODE) {
          if (child.tagName === "SPAN") {
            // include only immediate text children of this span
            child.childNodes.forEach((inner) => {
              if (inner.nodeType === Node.TEXT_NODE) {
                txt += inner.textContent;
              }
            });
          } else {
            // for other elements, recurse to capture structured content
            txt += getCleanText(child);
          }
        }
      });
      return txt;
    }
    function romangonorth() {
      const STEP = 20; // px up
      const isScrollEl = (el) => {
        const s = getComputedStyle(el);
        return (s.overflowY === "auto" || s.overflowY === "scroll") && el.scrollHeight > el.clientHeight + 1;
      };
      const scroller =
        [...document.querySelectorAll("*")].filter(isScrollEl).sort((a, b) => b.scrollHeight - b.clientHeight - (a.scrollHeight - a.clientHeight))[0] ||
        document.scrollingElement;
      scroller.scrollBy(0, -STEP);
    }
    function romanempireview() {
      romangonorth();
      setTimeout(() => {
        const scb = document.querySelector(sel_scrolbut);
        if (scb) {
          const { x, y, width, height, top, left } = scb.getBoundingClientRect();
          const gapFromBottom = window.innerHeight - (y + height);
          const q1 = window.innerHeight * 0.25;
          console.log(
            `⤵ scroll-scb pos → x=${x.toFixed(1)}, y=${y.toFixed(1)}, ` +
              `w=${width.toFixed(1)}, h=${height.toFixed(1)}, ` +
              `top=${top.toFixed(1)}, left=${left.toFixed(1)}`
          );
          scb.click();
        }
        console.log("nahanah");
      }, 100);
    }

    function sendEU(cmd) {
      // Map command to payload -----------------------------
      let payload;
      switch (cmd) {
        case "play":
          payload = { playEU: true };
          break;
        case "stop":
          payload = { stopEU: true };
          euok = true;
          break;
        case "lp":
          if (euok) return;
          payload = { lpEU: true };
          break;
        case "ds":
          payload = { dsEU: true };
          break;
        default:
          console.warn("sendEU: unknown cmd ▶", cmd);
          return;
      }

      const body = JSON.stringify(payload);
      console.log("sendEU ▶", cmd, "body =", body);

      // POST to local TTS server ----------------------------
      GM_xmlhttpRequest({
        method: "POST",
        url: `http://localhost:${port}/speak`,
        headers: {
          "Content-Type": "application/json; charset=utf-8",
          Accept: "text/plain",
        },
        data: body,
        onload(res) {
          if (res.status === 200) {
            console.log(`✅ sendEU(${cmd}) → 200 OK`);
          } else {
            console.error(`❌ sendEU(${cmd}) → ${res.status}`, res.statusText, res.responseText.trim());
          }
        },
        onerror(err) {
          console.error("❌ sendEU network error", err);
        },
      });
    }

    /*
    function watchBtnY(duration = 5000, every = 1000) {
      const scb = document.querySelector(sel_scrolbut);
      if (!scb) {
        console.warn("⚪ watchBtnPosition: button not found");
        return;
      }

      let last = scb.getBoundingClientRect();
      console.log(`📌 start   y=${last.y.toFixed(1)}, gap=${(window.innerHeight - (last.y + last.height)).toFixed(1)}`);

      const id = setInterval(() => {
        const cur = scb.getBoundingClientRect();
        const gap = window.innerHeight - (cur.y + cur.height);

        if (cur.y !== last.y || cur.height !== last.height) {
          console.log(`📍 change  y=${cur.y.toFixed(1)}, gap=${gap.toFixed(1)}`);
          last = cur;
        }
      }, every);

      setTimeout(() => {
        clearInterval(id);
        console.log("⏹️ watchBtnPosition done");
      }, duration);
    }
    */
    // -------------------------------------------------------------------

    let lastKnownFullText = "";
    // let wordBuf = ""; // (disabled) rolling buffer removed

    // ---- Global key event blocker ----
    /*let blockKeys = false;
    function keyBlocker(ev) {
      // Allow the “f” keyup that turns the block off to pass through.
      if (blockKeys && !(ev.key === "f" && ev.type === "keyup")) {
        ev.stopImmediatePropagation();
        ev.preventDefault();
      }
    }
    // Capture‑phase listeners ensure we cancel events before anyone else.
    document.addEventListener("keydown", keyBlocker, true);
    document.addEventListener("keyup", keyBlocker, true);
    */
    let detailObserver = null;
    let currentTargetNode = null;
    let listObserver = null;
    let lastromanid = null;
    let uareromanbefore = false;
    // 1) Patch the history methods so we can detect in-app route changes
    //    (pushState, replaceState) and the popstate event
    function onRouteChange() {
      console.log("🔁 Route changed → re-initializing observers...");
      // Disconnect old observer if any
      if (listObserver) {
        listObserver.disconnect();
        listObserver = null;
      }
      waitc(() => {
        h();
        s();
        startListObserver();
      });
    }

    const originalPushState = history.pushState; //when u go from chatgpt.com to chatgpt.com/c
    history.pushState = function (...args) {
      const ret = originalPushState.apply(history, args);
      onRouteChange();
      return ret;
    };

    const originalReplaceState = history.replaceState; // cmd shift o back to main page n posible more. so ps we need both
    history.replaceState = function (...args) {
      const ret = originalReplaceState.apply(history, args);
      onRouteChange();
      return ret;
    };

    window.addEventListener("popstate", onRouteChange, {passive: true});

    // 3) Observers for new messages + partial tokens
    function processLatestMessage() {
      const bublist = document.querySelectorAll(sel_realroman);
      const lastbub = bublist[bublist.length - 1];

      const targetNode = lastbub?.querySelector(sel_resp) ?? null;
      if (!targetNode) return;
    // if (!targetNode) { setTimeout(processLatestMessage, 300); console.log("no lastbub. retry"); return; }
      const initialCleanText = getCleanText(targetNode);
      const romanid = lastbub.getAttribute("data-message-id") ?? null;
      /*console.log("🔎 Initial latestnode:", lastbub);
      console.log("🔎 Initial token tree:", targetNode);
      console.log("🔎 Initial romanid:", romanid);
      */
      if (targetNode !== currentTargetNode || romanid !== lastromanid) {
        console.log("✅ New assistant message content node detected. Attaching detail observer. c:");
        lastKnownFullText = "";
        currentTargetNode = targetNode;
        detailObserver?.disconnect();

        if (!uareromanbefore) lastromanid = romanid;

        const initialText = initialCleanText;
        if ((initialText && typeof GM_xmlhttpRequest === "function") || (uareromanbefore && initialText)) {
          console.log("flushing queue");
          if (uareromanbefore) {console.warn("are u roman")};
          uareromanbefore = false;
          ttsend({
            text: getCleanText(targetNode),
            flushQueue: true,
            onSuccess: () => {
              console.log("✅ flushQueue + initialText sent successfully");
              /*
              if (wordBuf.trim()) {
                ttsend({ text: wordBuf });
                // wordBuf = "";
              }
              */
              //sendEU("stop");
            },
          });
          sendEU("play");
          lastKnownFullText = initialCleanText;
        } else {
          uareromanbefore = true;
          console.log("nextime roman");
        }
        // (partial tokens logic below)
        detailObserver = new MutationObserver(() => {
          const currentCleanText = getCleanText(currentTargetNode);

          // Case 1 — text grew
          if (currentCleanText.length > lastKnownFullText.length) {
            const newPortion = currentCleanText.slice(lastKnownFullText.length);
            console.log("🟢 Partial tokens:", newPortion);
           
             if (uareromanbefore) {ttsend({ flushQueue: true})};

            if (newPortion) {
              // direct send without buffering
              ttsend({ text: newPortion });
            }

            lastKnownFullText = currentCleanText;
            /*
            if (currentCleanText.endsWith(".") || currentCleanText.endsWith("!") || currentCleanText.endsWith("?")) {
              if (wordBuf.trim()) {
                ttsend({ text: wordBuf });
                // wordBuf = "";
              }
            }
            */
          }
          // Case 2 — editor rewrote text (rare but happens while streaming)
          else if (currentCleanText.length < lastKnownFullText.length && lastKnownFullText !== "") {
            console.log("🔄 Text reset or changed significantly.");
            lastKnownFullText = currentCleanText;
          }
        });

        detailObserver.observe(currentTargetNode, {
          childList: true,
          subtree: true,
          //characterData: true,
          //attributes: true, //not add, it would break
        });

        lastKnownFullText = initialCleanText;
        if (lastKnownFullText) {
          console.log("🟢 Initial content:", lastKnownFullText);
        }
      }
    }

    function handleMutation(mutation) {
      if (mutation.addedNodes.length > 0) {
        for (const node of mutation.addedNodes) {
          if (node.nodeType === Node.ELEMENT_NODE && node.matches(sel_chatlist)) {
            return true; // found a new assistant message
          }
        }
      }
      return false;
    }

    function findElement(selectors) {
      for (const selector of selectors) {
        const element = document.querySelector(selector);
        if (element) {
          const firstTurn = element.closest("article")?.parentElement || element.closest('[data-testid^="conversation-turn-"]')?.parentElement || element;
          console.log(`Using container found by selector: "${selector}", actual element:`, firstTurn);
          return firstTurn;
        }
      }
      console.warn("Could not find chat list container using selectors:", sel_chatlist);
      return null;
    }

    function startListObserver() {
      
      const chatListContainer = findElement(sel_chatlist);
      if (chatListContainer && chatListContainer instanceof Node) {
        listObserver = new MutationObserver((mutations) => {
                //sendEU("play");
            console.log("chatlist obs");
            setTimeout(processLatestMessage, 150);
          });

        listObserver.observe(chatListContainer, {
          childList: true,
          //attributes: true,
          subtree: true,
          //attributeFilter: ["data-start"],
        });
        console.log("✅ Chat list observer started on:", chatListContainer);
        setTimeout(processLatestMessage, 100);
      } else {
        waitc(() => {
          h();
          console.warn("⏳ Waiting for chat list container... Retrying in 1s");
          setTimeout(startListObserver, 1000);
        });
      }
    }
    
    

    function reloadObservers() {
      if (detailObserver) {
        detailObserver.disconnect();
        detailObserver = null;
      }
      currentTargetNode = null;
      //lastKnownFullText = "";
      //lastromanid = null;
      processLatestMessage();
    }

    function waitc(callback) {
      if (location.pathname.includes("/c/")) {
        console.log("✅ Detected /c/ route, starting logic.");
        callback();
      } else {
        console.log("⏳ Waiting for /c/ route...");
       
      }
    }

    /*
    sendEU("lp");
    const ds_interval = setInterval(() => {
      if (euok) {
        clearInterval(ds_interval);
        return;
      }
      sendEU("ds");
    }, 1000);*/ 
    
    
    let ts = {};
    const l = 40;
    const L = 650;
    let rDownTime = null;
    let pressTimerS = null;
    let uistate = false;
    let sstate = false;
    let stt = "a";

    function s() {
      if (sstate) return;
      sstate = true;
      let pressTimer = null;
      let shown = false;
      const mods = (e) => !e.metaKey && !e.altKey && !e.shiftKey && !e.ctrlKey && !e.fnKey && !e.capsLockKey;
      const dt = (duration) => duration <= 70;

      document.addEventListener("keydown", (e) => {
        if (e.key === "f" && pressTimer === null && !uistate) {
          pressTimer = performance.now();
        } else if (uistate && mods(e)) {
          ["a", "b", "c", "d"].forEach((id) => g(id, "display", "none", "important"));
          uistate = false;
        }
        /*if (e.key === "r" && rDownTime === null) {
          rDownTime = performance.now();
          //console.log(`r‑tap detected ( ${rDownTime.toFixed(0)} ms )`);
        }*/
        /*  if (e.fnKey) {
          console.log("asf");
           const label = stt === "a" ? "Dictate button" : "Submit dictation";
           const btn = document.querySelector(`button[aria-label="${label}"]`);
           if (btn) btn.click();
           stt = stt === "a" ? "b" : "a";
        }*/
        // Reload on CapsLock + R (no Fn dependency)
        if (e.key.toLowerCase() === "r" && e.getModifierState("CapsLock")) {
          reloadObservers();
        }
        if (e.key === "s" && e.getModifierState("CapsLock")) {
          const label = stt === "a" ? "Dictate button" : "Submit dictation";
          const btn = document.querySelector(`button[aria-label="${label}"]`);
          if (btn) btn.click();
          stt = stt === "a" ? "b" : "a";
        }
        if (e.key === "Enter" && !e.shiftKey && !e.ctrlKey && !e.altKey && !e.metaKey && !e.fnKey && !e.capsLockKey) {
          window.addEventListener("blur", () => {return;}, {once: true});
           const n = document.querySelector(".z-50.max-w-xs.rounded-2xl");
           const m = document.querySelector(".popover.border-token-border-default.bg-token-main-surface-primary.rounded-2xl.border.p-2.shadow-lg");

           if (!n && !m) {
            const btn = document.getElementById("composer-submit-button");
            if (!pinof) {
            const textarea = document.getElementById(TARGET_ID);
            const content = textarea.textContent || "";
            if (!hasInjected(content)) {
              textarea.textContent = wrapMessage(content);
              pinof = true;
            }
            }
             //const sel = document.getElementById("prompt-textarea");
             //const t = sel.innerText;       
                if (btn) { e.stopImmediatePropagation(); e.preventDefault(); requestAnimationFrame(() => { btn.click(); setTimeout(romanempireview, 100); }); } else {
                 romanempireview(); 
                }

             /*if (t) {
            //await new Promise(resolve => setTimeout(resolve, 500));
            const p = window.location.href + "/?model=o4-mini";
            window.open(p, "_blank");
            //GM_openInTab(p, { active: true });
            sel.value = t; // paste text back
            sel.dispatchEvent(new Event("input", { bubbles: true }));
            btn.click();
          }*/
          }
        }
        /*  if (e.key === "v" && e.metaKey) {
          e.preventDefault();
          e.stopPropagation();
         document.dispatchEvent(new KeyboardEvent('keydown', { key: 's', ctrlKey: true, shiftKey: false, altKey: false, metaKey: false }));
         document.dispatchEvent(new KeyboardEvent('keyup', { key: 's', ctrlKey: true, shiftKey: false, altKey: false, metaKey: false }));
         document.dispatchEvent(new KeyboardEvent('keydown', { key: 'v', metaKey: true, shiftKey: false, altKey: false, ctrlKey: false }));
         document.dispatchEvent(new KeyboardEvent('keyup', { key: 'v', metaKey: true, shiftKey: false, altKey: false, ctrlKey: false }));

        }*/
       if (e.key === "b") {
        
       }

      }, true);

      document.addEventListener("keyup", (e) => {
        if (e.key === "f") {
          const duration = performance.now() - (pressTimer ?? 0);
          if (dt(duration)) {
            ["a", "b", "c", "d"].forEach((id) => g(id, "display", "flex", "important"));
            uistate = true;
          }
          pressTimer = null;
        }
        /*if (e.key === "r") {
          const duration = performance.now() - (rDownTime ?? 0);
          if (dt(duration)) {
            reloadObservers();
          }
          rDownTime = null;
        }*/
        /*
        if (e.key === "s") {
          const duration = performance.now() - (pressTimerS ?? 0);
          if (dt(duration)) {
            console.log(`s‑tap detected ( ${duration.toFixed(0)} ms )`);
            const label = stt === "a" ? "Dictate button" : "Submit dictation";
            const btn = document.querySelector(`button[aria-label="${label}"]`);
            if (btn) btn.click();
            stt = stt === "a" ? "b" : "a";
          }
          pressTimerS = null;
        }*/
      });

      /*document.addEventListener("mousemove", (e) => {
        if (!shown) {
          const y = e.clientY;
          //more sug to use f hotkey to show, delete didnot none so juterfy like this for now
          g("a", "display", y < l ? "none" : "none", "important");
          g("b", "display", y < l ? "none" : "none", "important");
          /*const Ł = y > L;
        g("b", "display", Ł ? "flex" : "none", "important");
        g("c", "display", Ł ? "flex" : "none", "important");
        }
      });*/
    }
    
    function g(target, prop, val, important) {
      // When a key string is passed, dereference inside ts first.
      const nodeOrList = typeof target === "string" ? ts[target] : target;

      if (!nodeOrList) return;

      // Apply style to one or many elements transparently.
      if (nodeOrList instanceof NodeList || Array.isArray(nodeOrList)) {
        nodeOrList.forEach((el) => el?.style?.setProperty(prop, val, important));
      } else {
        nodeOrList.style.setProperty(prop, val, important);
      }
    }

    function h() {
      ts = T();
      g("all", "display", "none", "important");
    }

    function T() {
      const selectors = `
      #page-header,
      form[data-type="unified-composer"] .flex-auto.flex-col>div[style*="height:48px"],
      .bg-primary-surface-primary,
      #stage-slideover-sidebar,
      #thread-bottom-container .text-token-text-secondary
    `;
      const [a, b, c, d, e] = document.querySelectorAll(selectors);
      return { a, b, c, d, e, all: document.querySelectorAll(selectors) };
    }

    const TARGET_ID = "prompt-textarea";
    function hasInjected(content) {
      return content.includes("<|system|>") || content.includes("<|userinput|>");
    }
    function wrapMessage(text) {
       const clean = text.trim();
       return USER_PREFIX + clean + USER_SUFFIX + SYSTEM_PROMPT;
     }


    waitc(() => {
      ts = T();
      startListObserver();
      s();
      h();
    });

    //vh wide css
    insCss(`/* force that div taller */
    div.grow.overflow-y-auto {
    min-height: 680px !important;
//  margin: auto !important;
}
/* force a thinner cut */
body,
[data-message-author-role="assistant"],
[data-message-author-role="user"] {
  /* try the light/thin PostScript name first */
  font-weight: 300 !important;    /* very light */
}

/* very important to remove the botom padding. Remove bottom margin from the composer's wrapper */
main div.isolate.w-full.basis-auto.mb-4 {
    margin-bottom: 0 !important;
}
main div.sticky.top-0.max-md\:hidden.h-header-height {
  /* Hide the elements completely */
  display: none !important;
}
div.isolate.w-full.basis-auto.flex.flex-col {
  padding: 0 !important;
}
div.text-base.mx-auto {
  padding-left: 0 !important;
  padding-right: 0 !important;
  --thread-content-margin: 0px !important;
}
div[class*="@thread-xl"] {
  margin-top: 0 !important;
  padding-bottom: 0 !important;
}

/* 1. Target the container setting the overall width and margin */
/* Overrides pl-2 (padding-left) */
div[style*="max-width: 100%"] {
  padding: 0 !important;
  /* Optionally remove the horizontal padding variable if needed, though mx-auto centers it */
  /* padding-right: 0 !important; */
}

/* 2. Target the inner container holding the input grid and buttons */


/* 3. Target the container specifically around the input field */
/* Overrides ps-2 pt-0.5 (padding-start, padding-top) */
form[data-type="unified-composer"] div[class*="ps-2 pt-0.5"] {
  padding: 0 !important;
}

/* 4. Target the main container div holding the ProseMirror editor */
/* Overrides pe-3 (padding-end) */
._prosemirror-parent_1e8bb_2 {
  padding: 0 !important;
  /* Optional: Override min-height if it causes unwanted space */
  /* min-height: auto !important; */
}

/* 5. Target the hidden textarea */
/* Overrides py-2 (padding-top/bottom) */
._prosemirror-parent_1e8bb_2 textarea {
  padding: 0 !important;
  /* Ensure height doesn't add space if it becomes visible */
  height: auto !important;
  min-height: 0 !important;
}

/* 6. Target the actual contenteditable input area (ProseMirror div) */
/* Remove any default or library-added padding/margin */
#prompt-textarea {
  padding: 0 !important;
  margin: 0 !important;
  /* Ensure it can shrink vertically if needed */
   min-height: 0 !important;
}

/* 7. Target the paragraph element often used inside the input area */
/* Remove default browser margins for paragraphs */
#prompt-textarea p {
  margin: 0 !important;
  padding: 0 !important;
}

/* 8. Target the grid container holding the input area */
/* Overrides ms-1.5 (margin-start) */
form[data-type="unified-composer"] div[class*="ms-1.5 grid"] {
  margin: 0 !important; /* Use margin: 0 to reset all margins */
}

/* 9. Target the container for potential elements after the input grid */
/* Overrides ms-2 (margin-start) */
form[data-type="unified-composer"] div[class*="ms-2 flex"] {
  margin: 0 !important; /* Use margin: 0 to reset all margins */
}

/* 10. Optional: Adjust absolute positioned buttons container */
/* If removing padding makes buttons overlap or look wrong, adjust their position. */
/* Example: Resetting left offset */
/*
.bg-primary-surface-primary.absolute.right-0.bottom-\[9px\].left-\[17px\] {
    left: 0 !important;
    bottom: 0 !important; /* Maybe adjust bottom too */
/* } */
/* Target any element whose class contains "prosemirror-parent_" */
div[class*="prosemirror-parent_"] {
  padding: 0 !important;
  margin: 0 !important;
  box-sizing: border-box !important;
  padding-inline-end: 0 !important; /* removes right-side padding from pe-3 */
  padding-right: 0 !important;       /* extra safety */
}

/* Target the actual contenteditable input area (ProseMirror div) */
/* Remove any default or library-added padding/margin */
#prompt-textarea {
  padding: 0 !important;
  margin: 0 !important;
}

/* Target the paragraph element often used inside the input area */
/* Remove default browser margins for paragraphs */
#prompt-textarea p {
  margin: 0 !important;
  padding: 0 !important; /* Less likely needed, but safe */
}
div[class^="prosemirror-parent"] .ProseMirror,
div[class^="prosemirror-parent"] .ProseMirror * {
  padding: 0 !important;
  margin: 0 !important;
  border: none !important;
}
/* 1. Target the direct container holding the input area and buttons */
/* This div has px-3 py-3 which creates the main internal padding */
form[data-type="unified-composer"] > div > div.relative.flex.w-full.items-end {
  padding: 0!important;
}


/* 2. Target the container specifically around the input field */
/* This div has ps-2 pt-0.5 (padding-start, padding-top) */
form[data-type="unified-composer"] div.relative.flex-auto.bg-transparent {
  padding: 0 !important;
}

/*very improtant*/
#prompt-textarea {
  padding: 9.1px !important;
}

/* 4. Target the hidden textarea (might still influence layout slightly) */
/* It has py-2 (padding-top/bottom) */
form[data-type="unified-composer"] textarea[placeholder="Ask anything"] {
  padding: 0 !important;
}

/* 5. Target the grid container holding the input area */
/* It has ms-1.5 (margin-start) */
form[data-type="unified-composer"] div[class*="ms-1.5 grid"] {
  margin: 0 !important;
}

/* 6. Target the container for potential elements after the input grid */
/* It has ms-2 (margin-start) */
form[data-type="unified-composer"] div[class*="ms-2 flex"] {
  margin: 0 !important;
}

/* 7. Optional: Adjust the absolute positioned buttons container if needed */
/* Removing padding might make these overlap; this resets its position slightly */
/*
form[data-type="unified-composer"] .absolute.right-3.bottom-0 {
    right: 0 !important;
    bottom: 0 !important;
}
*/
/* Target the container around the typing area */
.prosemirror-parent, /* If there's a class for that container */
.prose { /* Or a more general prose container */
  padding: 0 !important;
  margin: 0 !important;
  border: none !important;
}

    /*Target the actual surrounding bar*/
.bg-token-main-surface-primary{
    padding: 0 !important;
    margin: 0 !important;
    border: none !important;
}
.bg-clip-padding{
     padding: 0 !important;
    margin: 0 !important;
    border: none !important;
}
.px-3 {
    padding-left: 0 !important;
    padding-right: 0 !important;
}
.py-3{
    padding-top: 4px !important;
    padding-bottom: 6px !important;
}
/*this owuld impect to something not needed*/
/*Extra precaution and get to the children*/

.absolute > * {
    padding: 0 !important;
    margin: 0 !important;
    border: none !important;
}
/* Optional: Kill vertical gaps from container tokens */
div[class*="text-primary"] > div {
  margin: 0 !important;
  padding: 0 !important;
}


div.text-base.my-auto.mx-auto.py-5 {
  padding-left: 1px !important;
  padding-right: 0 !important;
}
/* Main content container */
main.relative.h-full.w-full.flex-1 {
  padding: 0 !important;
  width: 100% !important;
  max-width: none !important;
  box-sizing: border-box !important;
}

/* Conversation turn block */
div[class*="conversation-turn"].relative.flex.w-full.min-w-0.flex-col {
  padding-left: 0px !important;
  padding-right: 0px !important;
}

/* Inside message: user + assistant full zero padding */
[data-message-author-role="user"] *,
[data-message-author-role="assistant"] * {
//  padding: 0 !important;
}

/* Remove padding from markdown wrapper */
article div.text-base.mx-auto.px-6 {
  padding-left: 0px !important;
  padding-right: 0px !important;
}

/* Max width unlock for bubble containers */
[data-message-author-role="user"] div[class*="max-w-"],
[data-message-author-role="user"] .relative.max-w-\[var\(--user-chat-width\,70\%\)\],
[data-message-author-role="user"] .whitespace-pre-wrap {
  width: 100% !important; /* currently not working but in arc but would work with 'boost' */
  max-width: none !important;
  text-align: right !important;
  box-sizing: border-box !important;
}

/* currently doesn't work but in arc would work with 'boost'
[data-message-author-role="user"] .relative.max-w-\[var\(--user-chat-width\,70\%\)\] {
  border: 0.01px solid rgb(151, 148, 148) !important; 
  border-radius: 15px !important;
}
[data-message-author-role="user"] .relative {
  display: inline-block !important;
  max-width: 90% !important;       
  padding: 5px 5px !important;   
  margin: 6px 0 !important;
  background-color: #000 !important; 

}
body {
  line-height: 1.275 !important;
font-stretch: condensed !important;  
margin-block-start: 0 !important; Remove space before blocks 
    }*/
//---credit to 'wide gpt' start---
@media (min-width: 1280px) {
            .xl\\:max-w-\\[48rem\\],
            .xl\\:px-5 {
                max-width: 100% !important;
                padding-left: 1.25rem;
                padding-right: 1.25rem;
            }
        }

        @media (min-width: 768px) {
            .md\\:max-w-3xl {
                max-width: 100% !important;
            }
        }

        @container (width >= 64rem) {
            .\\@\\[64rem\\]\\:\\[--thread-content-max-width\\:48rem\\] {
                --thread-content-max-width: 100% !important;
            }
        }

        @container (width >= 34rem) {
            .\\@\\[34rem\\]\\:\\[--thread-content-max-width\\:40rem\\] {
                --thread-content-max-width: 100% !important;
            }
        }

        /* Extra: override fallback static styles if exist */
        [style*="max-width"] {
            max-width: 100% !important;
        } 
//---credit to 'wide gpt' end---
`);
  } else if (host === "gemini.google.com") {
    insCss(`/* === General Layout Widening === */

/* Make the main application container take full width */
chat-app,
body,
html {
  width: 100% !important;
  max-width: none !important;
}

/* Target the container holding sidebar AND content */
mat-sidenav-container.mat-drawer-container {
  width: 100% !important;
}

/* Target the main content area NEXT TO the sidebar */
mat-sidenav-content.mat-drawer-content {
  width: 100% !important; /* Allow content area to take available width */
  margin-left: 0 !important; /* Override default margin when sidebar is closed */
  margin-right: 0 !important;
  padding-inline: 0px !important; /* Add some padding back for breathing room */
  box-sizing: border-box; /* Include padding in width calculation */
}

/* Ensure the chat window itself fills the content area */
chat-window[_nghost-ng-c1777261061] {
  width: 100% !important;
}

/* Adjust the chat history container padding */
chat-window-content .chat-history {
  padding-inline: 0px !important; /* Keep this 0 if you want edge-to-edge content */
  /* or use 16px for some spacing: padding-inline: 16px !important; */
}


/* === Central Content Widening (Keep previous rules) === */

/* Target the main chat conversation area */
.conversation-container {
  max-width: 1400px !important; /* Increased further, adjust as needed */
}

/* Target the input area container at the bottom */
input-container {
   max-width: 1400px !important; /* Match the conversation width */
   padding-inline: 0px !important; /* Keep this 0 if you want edge-to-edge input */
   /* or use 16px: padding-inline: 16px !important; */
}

/* Target the initial "zero state" screen container */
.zero-state-container {
   max-width: 1400px !important; /* Match the conversation width */
 }

/* Ensure the container *within* input-container fills it */
.input-area-container {
   max-width: 100% !important;
}


/* === User Prompt Widening === */

/* Target the specific container for the user prompt bubble's background/layout */
user-query .user-query-bubble-with-background {
  max-width: none !important; /* Remove the max-width restriction */
  width: 100% !important;     /* Allow it to take full available width */
  box-sizing: border-box; /* Include padding/border in the width */
}

/* Ensure the parent container allows full width */
user-query .query-content {
  width: 100% !important;
}

/* === Optional: Adjust Immersive Mode === */
.immersives-mode[_nghost-ng-c1777261061]:not(.mobile-device) {
    max-width: 100% !important; /* Adjust as needed, e.g., 1800px, none */
    margin: 0 auto !important; /* Center it if not 100% width */
}

/* === Your Line Height Rule (Keep it) === */
.markdown p, .markdown li {
  line-height: 1.5 !important;
}

/* === Sidebar Adjustments (Optional - might break things) === */
/* Hide the collapsed sidebar visually and remove its width influence */
/* Use with caution, might hide the toggle button */
/*
bard-sidenav-container mat-sidenav.mat-drawer-closed {
  width: 0 !important;
  min-width: 0 !important;
  visibility: hidden !important;
  border: none !important;
}
*/
`);
  } else if (host === "mistral.ai" || host === "claude.ai") {
    insCss(`
    .max-w-3xl {
        max-width: 200ch;
    }
    .max-w-\[75ch\] {
        max-width: 200ch;
    }
`);
  }
})();