// Kronaxis in-page toolbar: a horizontal strip across the top of every page.
// Rendered inside a Shadow DOM so the host page's CSS cannot touch it. Three surfaces:
//   1) the strip            — Authority, Topicality, the 8 DYNAMICS-WEB character bars
//   2) a character modal    — hover the bars to learn what each axis means (+ this page's value)
//   3) a "Reader fit" panel — pick an audience, see the free verdict + direction, and (Premium)
//                             get the cure: specific changes and a rewrite of the page text.
// Page scoring happens on-device; fit/cure go through the background worker to the server,
// where the mapping M lives. The client never sees M, only verdicts/directions/the rewrite.
(async () => {
  try {
    if (window.top !== window) return;
    if (!/^https?:$/.test(location.protocol)) return;
    if (document.getElementById("kx-host")) return;

    const cfg = await new Promise(r => chrome.storage.local.get({ toolbar: true }, r));
    if (!cfg.toolbar) return;

    const title = (document.title || "").slice(0, 300);
    const text = ((document.body && document.body.innerText) || "").replace(/\s+/g, " ").trim().slice(0, 4000);
    const s = await new Promise(res =>
      chrome.runtime.sendMessage({ type: "scorePageWithText", url: location.href, title, text }, res));
    if (!s || (!s.dynamics_web && !s.page_dynamics_web && s.authority_score == null && (!s.ttf || !s.ttf.length))) return;

    const AX = ["rigour", "depth", "originality", "candour", "affect", "commercial_drive", "stance", "register"];
    const ABBR = { rigour: "RIG", depth: "DPT", originality: "ORG", candour: "CND", affect: "AFF", commercial_drive: "COM", stance: "STN", register: "REG" };
    const DESC = {
      rigour: "How evidence led and carefully argued the page is — citations, precision, formal structure.",
      depth: "How deeply it analyses — reasoning, technical detail, joining ideas across domains.",
      originality: "How novel or synthetic the thinking is, rather than restating the familiar.",
      candour: "How straight and informational it is — direct and instructive, not spin.",
      affect: "How emotionally warm or charged the tone is, rather than flat and neutral.",
      commercial_drive: "How much it is selling — persuasion, transactional framing, buy now language.",
      stance: "How authoritative and assertive the voice is, rather than deferential and consensus seeking.",
      register: "How casual and conversational the language is, rather than formal and specialist.",
    };
    const NICE = { rigour: "Rigour", depth: "Depth", originality: "Originality", candour: "Candour", affect: "Warmth", commercial_drive: "Commercial drive", stance: "Authority", register: "Casual tone" };
    const web = s.page_dynamics_web || s.dynamics_web || {};
    const scope = s.page_in_corpus ? "page" : "domain";

    const host = document.createElement("div");
    host.id = "kx-host";
    host.style.cssText = "all:initial;position:fixed!important;top:0!important;left:0!important;right:0!important;z-index:2147483647!important;height:30px!important;margin:0!important;overflow:visible!important;";
    const sh = host.attachShadow({ mode: "open" });

    const style = document.createElement("style");
    style.textContent = `
      *{box-sizing:border-box;font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",system-ui,sans-serif;}
      .bar{display:flex;align-items:center;gap:16px;height:30px;padding:0 14px;
        background:#fff;border-bottom:1px solid #d9dde2;box-shadow:0 1px 6px rgba(20,24,40,.12);font:12px/1;color:#232733;}
      .brand{font-weight:800;color:#6d28d9;letter-spacing:.02em;}
      .auth{display:inline-flex;align-items:center;gap:6px;white-space:nowrap;} .auth b{font-size:14px;color:#111827;} .auth small{color:#8a8f98;}
      .a-track{width:64px;height:9px;background:#ccd1d9;border-radius:5px;overflow:hidden;}
      .a-fill{display:block;height:9px;background:#16a34a;border-radius:5px;min-width:2px;}
      .topic{color:#4b5563;max-width:220px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;}
      .topic b{color:#6d28d9;font-weight:600;}
      .axes{display:flex;gap:11px;margin-left:auto;align-items:flex-end;cursor:help;}
      .ax{display:flex;flex-direction:column;align-items:center;gap:3px;}
      .lbl{font-size:9px;font-weight:700;color:#4b5563;letter-spacing:.02em;white-space:nowrap;}
      .track{width:50px;height:9px;background:#ccd1d9;border-radius:5px;overflow:hidden;}
      .fill{display:block;height:9px;background:#6d28d9;border-radius:5px;min-width:2px;}
      .scope{font-size:8px;color:#b6bac2;text-transform:uppercase;}
      .fitbtn{cursor:pointer;border:1px solid #d9cffb;background:#f3f0fd;color:#5b21b6;border-radius:12px;padding:3px 10px;font-size:11px;font-weight:600;white-space:nowrap;}
      .fitbtn:hover{background:#ece7fb;}
      .x{cursor:pointer;color:#9aa0aa;font-size:15px;line-height:1;}.x:hover{color:#ef4444;}
      .pop{position:absolute;top:34px;background:#fff;border:1px solid #e4e7ec;border-radius:10px;
        box-shadow:0 8px 28px rgba(20,24,40,.22);padding:13px 15px;font:12px/1.5;color:#232733;display:none;}
      .modal{right:120px;width:430px;}
      .panel{right:14px;width:340px;}
      .pop h4{margin:0 0 9px;font-size:12px;color:#6d28d9;letter-spacing:.03em;text-transform:uppercase;}
      .dwrow{display:flex;gap:9px;padding:5px 0;border-top:1px solid #f3f4f6;}
      .dwrow:first-of-type{border-top:0;}
      .dwname{width:96px;font-weight:700;color:#374151;flex:none;}
      .dwval{width:34px;flex:none;text-align:right;color:#6d28d9;font-weight:700;}
      .dwtxt{color:#5b6270;}
      .mini{width:100%;height:6px;background:#edeff2;border-radius:3px;margin-top:3px;overflow:hidden;}
      .mini i{display:block;height:6px;background:#a78bfa;border-radius:3px;}
      select{width:100%;padding:6px;border:1px solid #d9dde2;border-radius:6px;font:12px;color:#232733;background:#fff;}
      .verdict{display:flex;align-items:center;gap:8px;margin-top:9px;}
      .badge{font-weight:700;font-size:12px;padding:3px 9px;border-radius:8px;}
      .pass{background:#dcfce7;color:#166534;}.fail{background:#fee2e2;color:#991b1b;}.unk{background:#f1f5f9;color:#64748b;}
      .dir{font-size:11px;color:#4b5563;margin-top:7px;}.dir b{color:#6d28d9;}
      .cta{width:100%;margin-top:10px;padding:8px;border:0;border-radius:7px;background:#6d28d9;color:#fff;font-weight:600;cursor:pointer;font-size:12px;}
      .cta:disabled{opacity:.55;cursor:default;}
      .sug{margin:8px 0 0;padding-left:18px;font-size:12px;color:#374151;}.sug li{margin:3px 0;}
      .rw{margin-top:8px;padding:8px;background:#faf8ff;border:1px solid #ece7fb;border-radius:6px;font-size:12px;white-space:pre-wrap;max-height:150px;overflow:auto;}
      .rw.blur{filter:blur(4px);user-select:none;}
      .upsell{margin-top:8px;padding:8px;background:#fffbeb;border:1px solid #fde68a;border-radius:6px;font-size:11px;color:#92400e;}
      .copy{margin-top:6px;font-size:11px;color:#6d28d9;cursor:pointer;}
      .note{font-size:10px;color:#9aa0aa;margin-top:6px;}
      .rwctl{position:fixed;bottom:18px;right:18px;display:flex;align-items:center;gap:12px;
        background:#6d28d9;color:#fff;padding:10px 14px;border-radius:10px;font:12px/1;
        box-shadow:0 6px 24px rgba(109,40,217,.4);z-index:2147483647;}
      .rwundo{cursor:pointer;background:rgba(255,255,255,.18);padding:5px 10px;border-radius:7px;font-weight:600;}
      .rwundo:hover{background:rgba(255,255,255,.3);}
      .tabs{display:flex;gap:6px;margin-bottom:9px;}
      .tab{cursor:pointer;font-size:11px;font-weight:600;color:#6b7280;padding:4px 10px;border-radius:14px;background:#f1f5f9;}
      .tab.on{background:#6d28d9;color:#fff;}
      .srow{display:flex;align-items:center;gap:8px;margin:5px 0;}
      .sname{width:88px;font-size:11px;color:#4b5563;}
      .srng{flex:1;accent-color:#6d28d9;}
      .sval{width:26px;text-align:right;font-size:10px;color:#6d28d9;font-weight:700;}
      .shapebtn{width:100%;margin-top:9px;padding:8px;border:0;border-radius:7px;background:#6d28d9;color:#fff;font-weight:600;cursor:pointer;font-size:12px;}
      .shapebtn:disabled{opacity:.55;cursor:default;}
      .advcard{position:fixed;bottom:18px;right:18px;width:330px;max-height:55vh;overflow:auto;
        background:#fff;border:1px solid #e4e7ec;border-radius:11px;box-shadow:0 8px 28px rgba(20,24,40,.22);
        padding:12px 14px;font:12px/1.5;color:#232733;z-index:2147483647;}
      .advh{font-weight:700;color:#6d28d9;display:flex;justify-content:space-between;align-items:center;gap:8px;}
      .advx{cursor:pointer;color:#9aa0aa;font-size:15px;}.advx:hover{color:#ef4444;}
      .advreader{font-size:10px;color:#9aa0aa;margin:3px 0 6px;}
      .advul{margin:6px 0 0;padding-left:17px;}.advul li{margin:6px 0;color:#374151;}
      .advdir{font-size:12px;color:#4b5563;margin:6px 0;}.advdir b{color:#6d28d9;}
      .advup{margin-top:8px;font-size:11px;}.advup a{color:#92400e;font-weight:700;}`;
    sh.appendChild(style);

    const mk = (cls, txt) => { const e = document.createElement("div"); if (cls) e.className = cls; if (txt != null) e.textContent = txt; return e; };
    const bar = mk("bar");
    bar.appendChild(mk("brand", "Kronaxis"));

    if (s.authority_score != null) {
      const a = mk("auth");
      a.append("Authority ", Object.assign(document.createElement("b"), { textContent: s.authority_score }), "/10");
      const at = mk("a-track"); const af = mk("a-fill"); af.style.width = (s.authority_score / 10 * 100) + "%";
      at.appendChild(af); a.appendChild(at);
      if (s.pr_rank != null) a.append(Object.assign(document.createElement("small"), { textContent: "#" + s.pr_rank.toLocaleString() }));
      bar.appendChild(a);
    }
    if (s.ttf && s.ttf[0] && s.ttf_confident) {
      const t = mk("topic"); t.append("Topic: ", Object.assign(document.createElement("b"), { textContent: s.ttf[0].topic }));
      if (s.ttf_score != null) t.append(" ", Object.assign(document.createElement("b"), { textContent: s.ttf_score }), "/10");
      bar.appendChild(t);
    }
    const axes = mk("axes");
    for (const a of AX) {
      const v = Math.max(0, Math.min(1, web[a] ?? 0));
      const item = mk("ax"); item.title = `${NICE[a]}: ${DESC[a]}`;
      item.appendChild(mk("lbl", `${ABBR[a]} ${Math.round(v * 100)}`));
      const track = mk("track"); const fill = mk("fill");
      fill.style.width = Math.round(v * 100) + "%";
      track.appendChild(fill); item.appendChild(track);
      axes.appendChild(item);
    }
    bar.appendChild(axes);

    const fitBtn = document.createElement("div"); fitBtn.className = "fitbtn"; fitBtn.textContent = "Reader fit ▾";
    bar.appendChild(fitBtn);
    bar.appendChild(mk("scope", scope));
    const x = mk("x", "✕"); x.title = "hide";
    x.addEventListener("click", () => { host.remove(); if (document.body) document.body.style.marginTop = ""; });
    bar.appendChild(x);
    sh.appendChild(bar);

    // --- DYNAMICS-WEB explanation modal (hover the bars) ---
    const modal = mk("pop modal");
    modal.appendChild(Object.assign(document.createElement("h4"), { textContent: "DYNAMICS-WEB — the character of this " + scope }));
    for (const a of AX) {
      const v = Math.max(0, Math.min(1, web[a] ?? 0));
      const row = mk("dwrow");
      row.appendChild(mk("dwname", NICE[a]));
      const mid = mk(""); mid.style.flex = "1";
      mid.appendChild(mk("dwtxt", DESC[a]));
      const mini = mk("mini"); const i = document.createElement("i"); i.style.width = Math.round(v * 100) + "%"; mini.appendChild(i); mid.appendChild(mini);
      row.appendChild(mid);
      row.appendChild(mk("dwval", Math.round(v * 100)));
      modal.appendChild(row);
    }
    sh.appendChild(modal);
    let mt = null;
    const showModal = () => { clearTimeout(mt); modal.style.display = "block"; };
    const hideModal = () => { mt = setTimeout(() => { modal.style.display = "none"; }, 220); };
    axes.addEventListener("mouseenter", showModal);
    axes.addEventListener("mouseleave", hideModal);
    modal.addEventListener("mouseenter", showModal);
    modal.addEventListener("mouseleave", hideModal);

    // --- Reader fit / cure panel ---
    const panel = mk("pop panel");
    panel.innerHTML = `<h4>Reader fit</h4>
      <div class="tabs"><span class="tab on" data-m="aud">Audience</span><span class="tab" data-m="custom">Custom ✨</span></div>
      <div class="mode-aud">
        <select class="aud"><option value="">Choose an audience…</option></select>
        <div class="verdict" style="display:none"><span class="badge"></span><span class="rate" style="font-size:11px;color:#6b7280"></span></div>
        <div class="dir"></div>
        <button class="cta" style="display:none">Fix this page for the reader</button>
      </div>
      <div class="mode-custom" style="display:none">
        <div class="advreader">Set the eight dials to the character your ideal reader rewards, then save them as your own reader.</div>
        <div class="sliders"></div>
        <input class="cname" placeholder="Name this reader…" style="width:100%;padding:6px;border:1px solid #d9dde2;border-radius:6px;margin-top:8px;font:12px;color:#232733;">
        <button class="shapebtn">Save as a reader</button>
      </div>
      <div class="out"></div><div class="note"></div>
      <div class="uknote" style="font-size:9px;color:#b6bac2;margin-top:8px;text-align:center">UK English only · request your language in the toolbar menu</div>`;
    sh.appendChild(panel);
    const $ = sel => panel.querySelector(sel);
    let TIER = "free";

    fitBtn.addEventListener("click", () => {
      panel.style.display = panel.style.display === "block" ? "none" : "block";
    });

    const renderFit = res => {
      const v = $(".verdict"), badge = $(".badge"), rate = $(".rate"), dir = $(".dir"), btn = $(".cta");
      $(".out").innerHTML = ""; $(".note").textContent = "";
      if (!res) { v.style.display = "none"; dir.textContent = ""; btn.style.display = "none"; return; }
      if (res.status === 429) { v.style.display = "none"; dir.textContent = "Easy there — try again shortly."; btn.style.display = "none"; return; }
      const b = res.body || {};
      if (res.status === 402) { v.style.display = "flex"; badge.className = "badge unk"; badge.textContent = "Premium"; rate.textContent = "audience"; dir.textContent = "This reader is in the premium set."; btn.style.display = "none"; return; }
      if (b.verdict == null) { v.style.display = "flex"; badge.className = "badge unk"; badge.textContent = "—"; rate.textContent = b.reason || "not scored yet"; dir.textContent = ""; btn.style.display = "none"; return; }
      v.style.display = "flex";
      badge.className = "badge " + (b.verdict === "pass" ? "pass" : "fail");
      badge.textContent = b.verdict === "pass" ? "Good fit" : "Poor fit";
      rate.textContent = b.rating ? `(${b.rating})` : "";
      dir.innerHTML = (b.direction && b.direction.length) ? "To fit better: " + b.direction.map(d => `<b>${d}</b>`).join(", ") : "Well aligned for this reader.";
      btn.style.display = "block";
      btn.textContent = "Advise paragraph by paragraph";
    };

    const renderCure = res => {
      const out = $(".out"), note = $(".note"); out.innerHTML = ""; note.textContent = "";
      if (res && res.status === 402) {
        out.innerHTML = `<div class="upsell"><b>Premium unlocks the cure.</b> Free shows that the page misses and the direction to move. Premium gives the exact changes and a ready rewrite. <a href="https://toolbar.kronaxis.com/upgrade" target="_blank" style="color:#92400e;font-weight:700;">Get Premium →</a></div><div class="rw blur">Your rewritten passage, tuned for this reader, keeping every fact, appears here with Premium.</div>`;
        return;
      }
      const b = (res && res.body) || {};
      if (b.suggestions && b.suggestions.length) { const ul = document.createElement("ul"); ul.className = "sug"; b.suggestions.forEach(t => { const li = document.createElement("li"); li.textContent = t; ul.appendChild(li); }); out.appendChild(ul); }
      if (b.rewrite) {
        const rw = mk("rw", b.rewrite); out.appendChild(rw);
        const cp = mk("copy", "Copy rewrite"); cp.addEventListener("click", () => { navigator.clipboard.writeText(b.rewrite).catch(() => {}); cp.textContent = "Copied"; }); out.appendChild(cp);
        note.textContent = "Keeps your facts; signed + watermarked to your account.";
      } else if (b.note) { note.textContent = b.note; }
      else if (!b.suggestions) { out.innerHTML = `<span style="color:#9aa0aa">${(b && b.error) || "no rewrite available"}</span>`; }
    };

    $(".aud").addEventListener("change", async e => {
      const audience = e.target.value; $(".out").innerHTML = ""; $(".note").textContent = "";
      if (!audience) { $(".verdict").style.display = "none"; $(".dir").textContent = ""; $(".cta").style.display = "none"; return; }
      $(".dir").textContent = "Checking…";
      renderFit(await chrome.runtime.sendMessage({ type: "kxFit", url: location.href, audience }));
    });
    // Locate the main readable content: the element with the densest paragraph text,
    // then its leading paragraphs (so the rewrite matches what we replace on the page).
    const findMainParas = () => {
      const cands = [...document.querySelectorAll("article, main, [role=main]")];
      const dense = el => [...el.querySelectorAll("p")].reduce((n, p) => n + ((p.innerText || "").length), 0);
      let root = document.body, best = 0;
      (cands.length ? cands : [document.body]).forEach(el => { const d = dense(el); if (d > best) { best = d; root = el; } });
      const ps = [...root.querySelectorAll("p")].filter(p => (p.innerText || "").trim().length > 40);
      const paras = []; let acc = 0;
      for (const p of ps) { paras.push(p); acc += p.innerText.length; if (acc >= 1400) break; }
      return { paras, text: paras.map(p => p.innerText.trim()).join("\n\n") };
    };

    let undoStore = null;
    const undoRewrite = () => {
      if (!undoStore) return;
      undoStore.forEach(u => { u.node.innerHTML = u.html; u.node.style.display = u.display; u.node.classList.remove("kx-rw"); });
      undoStore = null;
      const c = sh.getElementById && sh.getElementById("kx-rwctl"); if (c) c.remove();
      const ctl = sh.querySelector(".rwctl"); if (ctl) ctl.remove();
    };
    const applyRewriteToPage = (paras, rewrite, label) => {
      if (!paras || !paras.length || !rewrite) return false;
      undoRewrite();
      if (!document.getElementById("kx-rw-style")) {
        const st = document.createElement("style"); st.id = "kx-rw-style";
        st.textContent = "@keyframes kxglow{0%{background:#fde68a;box-shadow:0 0 0 4px #fef08a}60%{background:#fef9c3}100%{background:#faf5ff;box-shadow:0 0 0 0 rgba(0,0,0,0)}}" +
          ".kx-rw{animation:kxglow 2.4s ease-out forwards;border-left:4px solid #6d28d9 !important;padding:10px 14px !important;border-radius:8px !important;}";
        document.documentElement.appendChild(st);
      }
      undoStore = paras.map(p => ({ node: p, html: p.innerHTML, display: p.style.display }));
      const first = paras[0];
      first.classList.add("kx-rw");
      first.innerHTML = rewrite.split(/\n+/).map(t => t.trim()).filter(Boolean).map(t => `<span>${t.replace(/[&<>]/g, c => ({ "&": "&amp;", "<": "&lt;", ">": "&gt;" }[c]))}</span>`).join("<br><br>");
      for (let i = 1; i < paras.length; i++) paras[i].style.display = "none";
      try { first.scrollIntoView({ behavior: "smooth", block: "center" }); } catch (e) {}
      // floating control (in the shadow DOM, fixed to the viewport)
      const ctl = mk("rwctl");
      const lab = mk(""); lab.style.cssText = "font-weight:600;"; lab.textContent = "✨ Rewritten for " + label;
      const undoB = mk("rwundo", "Undo"); undoB.addEventListener("click", undoRewrite);
      ctl.append(lab, undoB);
      sh.appendChild(ctl);
      return true;
    };

    // ---- Advise (not rewrite): click a paragraph, it highlights, advice appears ----
    const findContentRoot = () => {
      const cands = [...document.querySelectorAll("article, main, [role=main]")];
      const dense = el => [...el.querySelectorAll("p")].reduce((n, p) => n + ((p.innerText || "").length), 0);
      let root = document.body, best = 0;
      (cands.length ? cands : [document.body]).forEach(el => { const d = dense(el); if (d > best) { best = d; root = el; } });
      return root;
    };
    let adviseParas = null, adviseCard = null;
    const clearAdvise = () => {
      if (adviseParas) adviseParas.forEach(p => { p.classList.remove("kx-advisable", "kx-advising"); p.onclick = null; });
      adviseParas = null;
      if (adviseCard) { adviseCard.remove(); adviseCard = null; }
    };
    const adviseStyle = () => {
      if (document.getElementById("kx-advise-style")) return;
      const st = document.createElement("style"); st.id = "kx-advise-style";
      st.textContent = ".kx-advisable{cursor:pointer !important;border-left:3px solid #ddd6fe !important;padding-left:10px !important;transition:border-color .15s,background .15s;}" +
        ".kx-advisable:hover{border-left-color:#a78bfa !important;background:#faf8ff !important;}" +
        ".kx-advising{border-left:4px solid #6d28d9 !important;background:#faf5ff !important;}";
      document.documentElement.appendChild(st);
    };
    const adviceCard = (o) => {
      if (!adviseCard) { adviseCard = mk("advcard"); sh.appendChild(adviseCard); }
      adviseCard.innerHTML = "";
      const h = mk("advh"); h.append(o.title || ""); const x = mk("advx", "✕"); x.addEventListener("click", clearAdvise); h.appendChild(x);
      adviseCard.appendChild(h);
      if (o.reader) adviseCard.appendChild(mk("advreader", "for " + o.reader));
      if (o.direction) { const d = mk("advdir"); d.innerHTML = o.direction; adviseCard.appendChild(d); }
      if (o.tips && o.tips.length) {
        const ul = document.createElement("ul"); ul.className = "advul"; o.tips.forEach(t => { const li = document.createElement("li"); li.textContent = t; ul.appendChild(li); }); adviseCard.appendChild(ul);
        if (o.tips.length > 1 || (o.tips[0] && o.tips[0].length > 20)) {
          const cp = mk("copy", "Copy advice"); cp.addEventListener("click", () => { navigator.clipboard.writeText((o.reader ? "For " + o.reader + ":\n" : "") + o.tips.map(t => "- " + t).join("\n")).catch(() => {}); cp.textContent = "Copied"; }); adviseCard.appendChild(cp);
        }
      }
      if (o.upsell) { const u = mk("advup"); u.innerHTML = o.upsell; adviseCard.appendChild(u); }
    };
    const adviseParagraph = async (p, audience) => {
      adviseParas.forEach(x => x.classList.remove("kx-advising"));
      p.classList.add("kx-advising");
      try { p.scrollIntoView({ behavior: "smooth", block: "center" }); } catch (e) {}
      const txt = (p.innerText || "").trim();
      adviceCard({ title: "Reading this paragraph…" });
      // 1) directional advice, computed from the paragraph's OWN axes scored on device (content stays local)
      let direction = "", reader = "";
      const axes = await chrome.runtime.sendMessage({ type: "kxScoreText", text: txt });
      if (axes) {
        const fit = await chrome.runtime.sendMessage({ type: "kxFitAxes", axes, audience });
        if (fit) {
          reader = fit.label || "";
          direction = (fit.direction && fit.direction.length)
            ? `This paragraph rates <b>${fit.rating}</b> for the reader. To improve: ` + fit.direction.map(d => `<b>${d}</b>`).join(", ")
            : `This paragraph is a <b>${fit.rating || "good"}</b> fit for this reader.`;
        }
      }
      if (TIER !== "premium") {
        adviceCard({ title: "Advice for this paragraph", reader, direction,
          upsell: '<a href="https://toolbar.kronaxis.com/upgrade" target="_blank">Get specific, line by line advice with Premium →</a>' });
        return;
      }
      // 2) premium: specific advice (sends the paragraph text to the model)
      adviceCard({ title: "Advice for this paragraph", reader, direction, tips: ["Looking closely…"] });
      const res = await chrome.runtime.sendMessage({ type: "kxAdvise", url: location.href, audience, text: txt });
      const b = (res && res.body) || {};
      if (res && res.status === 429) return adviceCard({ title: "Advice for this paragraph", reader, direction, upsell: "Easy there, try again shortly." });
      adviceCard({ title: "Advice for this paragraph", reader, direction, tips: (b.advice && b.advice.length ? b.advice : ["No further specifics for this one."]) });
    };
    const enableAdvise = audience => {
      clearAdvise(); adviseStyle();
      const root = findContentRoot();
      adviseParas = [...root.querySelectorAll("p")].filter(p => (p.innerText || "").trim().length > 60);
      if (!adviseParas.length) { adviseParas = null; $(".note").textContent = "Could not find readable paragraphs on this page."; return; }
      adviseParas.forEach(p => { p.classList.add("kx-advisable"); p.title = "Click for advice for this reader"; p.onclick = e => { e.preventDefault(); e.stopPropagation(); adviseParagraph(p, audience); }; });
      adviceCard({ title: "Click any highlighted paragraph", tips: ["The readable paragraphs are outlined. Click one for advice for this reader."] });
    };
    $(".cta").addEventListener("click", () => {
      const audience = $(".aud").value; if (!audience) return;
      enableAdvise(audience);
      $(".note").textContent = "Advice mode on. Click a highlighted paragraph.";
    });

    // mode tabs (Audience presets vs Custom sliders). Sliders start from THIS page's own
    // axes — never pre-filled from an audience, so a preset's target profile (M) is never shown.
    const NICE2 = { rigour: "Rigour", depth: "Depth", originality: "Originality", candour: "Candour", affect: "Warmth", commercial_drive: "Commercial", stance: "Authority", register: "Casual tone" };
    let slidersBuilt = false;
    const buildSliders = () => {
      if (slidersBuilt) return; slidersBuilt = true;
      const box = panel.querySelector(".sliders");
      for (const a of AX) {
        const v = Math.round(Math.max(0, Math.min(1, web[a] ?? 0.5)) * 100);
        const row = mk("srow");
        row.appendChild(mk("sname", NICE2[a]));
        const rng = document.createElement("input"); rng.type = "range"; rng.min = "0"; rng.max = "100"; rng.value = v; rng.className = "srng"; rng.dataset.ax = a;
        const val = mk("sval", v);
        rng.addEventListener("input", () => { val.textContent = rng.value; });
        row.appendChild(rng); row.appendChild(val);
        box.appendChild(row);
      }
    };
    panel.querySelectorAll(".tab").forEach(t => t.addEventListener("click", () => {
      panel.querySelectorAll(".tab").forEach(x => x.classList.toggle("on", x === t));
      const custom = t.dataset.m === "custom";
      panel.querySelector(".mode-aud").style.display = custom ? "none" : "";
      panel.querySelector(".mode-custom").style.display = custom ? "" : "none";
      $(".out").innerHTML = ""; $(".note").textContent = "";
      if (custom) buildSliders();
    }));
    panel.querySelector(".shapebtn").addEventListener("click", async () => {
      if (TIER !== "premium") { $(".note").textContent = "Saving your own readers is a Premium feature."; return; }
      const name = (panel.querySelector(".cname").value || "").trim();
      if (!name) { panel.querySelector(".cname").focus(); return; }
      const target = {}; panel.querySelectorAll(".srng").forEach(r => { target[r.dataset.ax] = (+r.value) / 100; });
      const btn = panel.querySelector(".shapebtn"); btn.disabled = true; const old = btn.textContent; btn.textContent = "Saving…";
      const res = await chrome.runtime.sendMessage({ type: "kxSaveAudience", name, target });
      const b = (res && res.body) || {};
      if (b.key_aid) {
        const sel = $(".aud"); const o = document.createElement("option"); o.value = b.key_aid; o.textContent = b.name + " ✎"; sel.appendChild(o); sel.value = b.key_aid;
        panel.querySelector(".tab[data-m='aud']").click();
        $(".note").textContent = `Saved "${b.name}". It is now in your reader list.`;
        runFit();
      } else { $(".note").textContent = (b && b.error) || "Could not save the reader."; }
      btn.disabled = false; btn.textContent = old;
    });

    // load audiences + tier (lazily, after the strip is up)
    chrome.runtime.sendMessage({ type: "kxState" }).then(st => {
      TIER = (st && st.tier) || "free";
      const sel = $(".aud");
      ((st && st.audiences) || []).forEach(a => { const o = document.createElement("option"); o.value = a.key; o.textContent = a.label + (a.tier === "premium" ? " ★" : a.tier === "custom" ? " ✎" : ""); sel.appendChild(o); });
    }).catch(() => {});

    document.documentElement.appendChild(host);
    if (document.body) {
      const cur = parseFloat(getComputedStyle(document.body).marginTop) || 0;
      document.body.style.marginTop = (cur + 30) + "px";
    }
  } catch (e) { /* never break the host page */ }
})();
