const __PULSE_ROUTE_GUARD__=(()=>{const PREFIX="__pulse_route_guard__";let lastSeen="";function parse(pathname){const m=/^\/(chance|chat)(?:\/(.*))?$/i.exec(String(pathname||""));if(!m)return null;const base="/"+m[1].toLowerCase();const tail=String(m[2]||"").split("/").filter(Boolean);if(!tail.length)return{base,cleanPath:base};return{base,cleanPath:`${base}/${tail[tail.length-1]}`}}function markNewPath(path){try{const prev=sessionStorage.getItem(PREFIX+":last")||"";if(prev!==path){sessionStorage.setItem(PREFIX+":last",path);sessionStorage.removeItem(PREFIX+":reloaded")}}catch{}}function guard(){let info=parse(location.pathname);if(!info)return!1;const cleanHref=location.origin+info.cleanPath+location.search+location.hash;if(info.cleanPath!==location.pathname){try{markNewPath(info.cleanPath)}catch{}location.replace(cleanHref);return!0}markNewPath(info.cleanPath);if(info.cleanPath!==info.base)return!1;try{if(sessionStorage.getItem(PREFIX+":reloaded")!==info.cleanPath){sessionStorage.setItem(PREFIX+":reloaded",info.cleanPath);history.replaceState(history.state,"",cleanHref);window.dispatchEvent(new PopStateEvent("popstate"));window.dispatchEvent(new HashChangeEvent("hashchange"));return!0}}catch{}return!1}function onRouteEvent(){const now=location.pathname+location.search+location.hash;if(now===lastSeen)return;lastSeen=now;guard()}try{const ps=history.pushState.bind(history),rs=history.replaceState.bind(history);history.pushState=function(){const out=ps.apply(this,arguments);setTimeout(onRouteEvent,0);return out};history.replaceState=function(){const out=rs.apply(this,arguments);setTimeout(onRouteEvent,0);return out};window.addEventListener("popstate",()=>setTimeout(onRouteEvent,0),!0);window.addEventListener("hashchange",()=>setTimeout(onRouteEvent,0),!0);setInterval(onRouteEvent,400)}catch{}setTimeout(onRouteEvent,0);return{guard,navigate(url){try{const u=new URL(String(url||""),location.origin),info=parse(u.pathname);if(info){sessionStorage.setItem(PREFIX+":last",info.cleanPath);sessionStorage.removeItem(PREFIX+":reloaded");u.pathname=info.cleanPath}location.assign(u.toString())}catch{location.assign(String(url||location.href))}}}})();
const __PULSE_PRECHAT_SOFT_REFRESH__=(()=>{let lastAt=0;function fire(){const now=Date.now();if(now-lastAt<400)return;lastAt=now;try{history.replaceState(history.state,"",location.href)}catch(e){}try{window.dispatchEvent(new PopStateEvent("popstate"))}catch(e){}try{window.dispatchEvent(new HashChangeEvent("hashchange"))}catch(e){}}function isNavTarget(node){for(let el=node;el&&el!==document.documentElement;el=el.parentElement){try{const href=typeof el.getAttribute==="function"?(el.getAttribute("href")||el.getAttribute("data-href")||""):"";if(href&&/\/(?:chat|chance)(?:\/|$)/i.test(href))return!0;const onclick=typeof el.getAttribute==="function"?(el.getAttribute("onclick")||""):"";if(onclick&&/\/(?:chat|chance)(?:\/|$)/i.test(onclick))return!0;if(el.tagName==="A"){const prop=String(el.href||"");if(/\/(?:chat|chance)(?:\/|$)/i.test(prop))return!0}}catch(e){}}return!1}function onDown(ev){if(ev&&"button" in ev&&ev.button!==0)return;if(isNavTarget(ev.target))fire()}try{document.addEventListener("mousedown",onDown,!0);document.addEventListener("touchstart",onDown,!0)}catch(e){}return{fire}})();
let ahChatStop=!1,ahMailStop=!1,invSelectedImg=null,galleryCache={},port=null,timer=null;const PING_INTERVAL=25e3;let AH_BRIDGE_READY=!1;let ahOperatorEmail="";function setAhOperatorEmail(e){const t=String(e||"").trim();if(!t||t===ahOperatorEmail)return;ahOperatorEmail=t;try{chrome.storage.local.set({ahOperatorEmail:t})}catch{}try{renderOpIdEmail()}catch{}}try{chrome.storage.local.get("ahOperatorEmail",(e=>{const t=String(e.ahOperatorEmail||"").trim();t&&(ahOperatorEmail=t)}))}catch{}const PULSAR_AUTH_KEY="pulsarAuth";function getPulsarAuthFromSet(e=loadSet()){const t=String(e&&e.authKey||"").trim(),n=String(e&&e.operatorId||"").trim();return t?{token:t,authenticated:!0,operatorId:n||null}:null}function syncPulsarAuthStorage(e=loadSet()){const t=getPulsarAuthFromSet(e);try{t?chrome.storage.local.set({[PULSAR_AUTH_KEY]:t}):chrome.storage.local.remove([PULSAR_AUTH_KEY])}catch{}return!!t}function isPulsarAuthedSet(e=loadSet()){return!!getPulsarAuthFromSet(e)}function pulseHasFeatureAuth(){try{return isPulsarAuthedSet(loadSet())}catch{return!1}}function pulseRemoveQuickUi(){try{document.getElementById("pulse-quick-open-glass")?.remove()}catch{}try{document.getElementById("pulse-quick-open-reports")?.remove()}catch{}try{document.getElementById("pulse-report-editor-overlay")?.remove()}catch{}try{document.getElementById("pulse-user-detail-overlay")?.remove()}catch{}}window.addEventListener("message",(e=>{const t=e.data;if(!t||"PULSE_PAGE"!==t.src||"PULSE"!==t.app)return;"PULSE_READY"===t.type&&(AH_BRIDGE_READY=!0);if("PULSE_OPERATOR_INFO"===t.type){try{const e=String(t.email||"").trim();e&&setAhOperatorEmail(e)}catch{}}

// --- Chat limits badges (ff-style) ---
const __PULSE_CHAT_LIMITS_MAP__ = new Map();
const __PULSE_CHAT_LIST_SEL__ = '[data-testid="chat-list"]';
let __pulseChatLimitsInjectTimer__ = null;
let __pulseChatLimitsObserver__ = null;
let __pulseChatLimitsEnabled__ = true;

function __pulseRemoveAllChatLimitBadges__() {
  try {
    document.querySelectorAll('.alpha-finder-chat-limits').forEach((el) => el.remove());
  } catch (e) {}
}

function __pulseInjectChatLimitBadge__(chatUid, limits) {
  try {
    if (!__pulseChatLimitsEnabled__) return false;
    const hasLimits = !!limits;
    if (!hasLimits) return false;

    const m = (limits && (limits.messageLimit ?? limits.message_limit)) ?? 0;
    const l = (limits && (limits.letterLimit ?? limits.letter_limit)) ?? 0;

    const list = document.querySelector(__PULSE_CHAT_LIST_SEL__);
    const row = list ? list.querySelector(`[data-testid="${chatUid}"]`) : document.querySelector(`[data-testid="${chatUid}"]`);
    if (!row) return false;

    // Prefer overlaying on the avatar so the list layout never shifts (long names won't move anything).
    const nameEl = row.querySelector('[data-testid="man-name"]') || null;

    // Remove older badge injected into the name container (previous builds) to avoid duplicates
    if (nameEl) {
      const oldInName = nameEl.querySelector(".alpha-finder-chat-limits");
      if (oldInName) oldInName.remove();
      try { nameEl.style.paddingRight = ""; } catch (e) {}
      try { delete nameEl.dataset.pulseLimitsLayout; } catch (e) {}
    }

    const findAvatarAnchor = () => {
      // Known/possible selectors first
      let el =
        row.querySelector('[data-testid="man-avatar"]') ||
        row.querySelector('[data-testid="avatar-man"]') ||
        row.querySelector('[data-testid="avatar"]');

      // Fallback: the first image inside the row (usually man's avatar on the left)
      if (!el) el = row.querySelector("img");

      // Fallback: background-image avatar
      if (!el) el = row.querySelector('div[style*="background-image"]');

      if (!el) return null;

      // Use a stable container around the avatar (parent div/a) as anchor
      const anchor = el.closest("a") || el.closest("div") || el.parentElement;
      return anchor || el;
    };

    const avatarAnchor = findAvatarAnchor();
    if (!avatarAnchor) return false;

    // Ensure absolute positioning does not affect layout
    const cs = window.getComputedStyle(avatarAnchor);
    if (cs.position === "static") avatarAnchor.style.position = "relative";

    const existed = avatarAnchor.querySelector(`.alpha-finder-chat-limits[data-chat-uid="${chatUid}"]`);
    if (existed) {
      const mEl = existed.querySelector(".pulse-lim-m");
      const lEl = existed.querySelector(".pulse-lim-l");
      if (mEl) mEl.textContent = String(m);
      if (lEl) lEl.textContent = String(l);
      if (!mEl || !lEl) {
        existed.innerHTML =
          `<span class="pulse-lim-part"><span class="pulse-lim-ico">💬</span><span class="pulse-lim-num pulse-lim-m">${m}</span></span>` +
          `<span class="pulse-lim-part"><span class="pulse-lim-ico">💌</span><span class="pulse-lim-num pulse-lim-l">${l}</span></span>`;
      }
      return true;
    }

    const badge = document.createElement("span");
    badge.className = "alpha-finder-chat-limits";
    badge.dataset.chatUid = String(chatUid);
    badge.innerHTML =
      `<span class="pulse-lim-part"><span class="pulse-lim-ico">💬</span><span class="pulse-lim-num pulse-lim-m">${m}</span></span>` +
      `<span class="pulse-lim-part"><span class="pulse-lim-ico">💌</span><span class="pulse-lim-num pulse-lim-l">${l}</span></span>`;

    // Overlay on avatar (slightly over the photo) – does not change card layout.
    badge.style.cssText = `
      position:absolute;
      left:-3px;
      top:-3px;
      z-index:3;
      display:flex;
      align-items:center;
      gap:4px;
      padding:1px 4px;
      border-radius:7px;
      background:rgba(238,242,255,.92);
      border:1px solid rgba(0,0,0,.14);
      font-size:11px;
      font-weight:700;
      font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,sans-serif;
      line-height:1;
      white-space:nowrap;
      font-variant-numeric:tabular-nums;
      pointer-events:none;
      box-shadow:0 1px 3px rgba(0,0,0,.12);
    `;

    // Thin outline under icons for visibility
    const icons = badge.querySelectorAll(".pulse-lim-ico");
    icons.forEach((el) => {
      el.style.textShadow = "0 0 1px rgba(0,0,0,.75), 0 0 2px rgba(0,0,0,.25)";
      el.style.marginRight = "2px";
    });

    const parts = badge.querySelectorAll(".pulse-lim-part");
    parts.forEach((p) => {
      p.style.display = "inline-flex";
      p.style.alignItems = "center";
    });

    avatarAnchor.appendChild(badge);
    return true;
  } catch (e) {
    return false;
  }
}


function __pulseInjectAllChatLimitBadges__() {
  try {
    if (!__pulseChatLimitsEnabled__) {
      __pulseRemoveAllChatLimitBadges__();
      return;
    }
    if (__PULSE_CHAT_LIMITS_MAP__.size === 0) return;
    __PULSE_CHAT_LIMITS_MAP__.forEach((limits, chatUid) => {
      __pulseInjectChatLimitBadge__(chatUid, limits);
    });
  } catch (e) {}
}

function __pulseScheduleInjectChatLimits__() {
  try {
    if (!__pulseChatLimitsEnabled__) {
      __pulseRemoveAllChatLimitBadges__();
      return;
    }
    if (__pulseChatLimitsInjectTimer__) clearTimeout(__pulseChatLimitsInjectTimer__);
    __pulseChatLimitsInjectTimer__ = setTimeout(() => {
      __pulseChatLimitsInjectTimer__ = null;
      __pulseInjectAllChatLimitBadges__();
    }, 400);
  } catch (e) {}
}

function __pulseEnsureChatLimitsObserver__() {
  try {
    if (__pulseChatLimitsObserver__) return;
    const root = document.querySelector(__PULSE_CHAT_LIST_SEL__) || document.body;
    __pulseChatLimitsObserver__ = new MutationObserver(() => __pulseScheduleInjectChatLimits__());
    __pulseChatLimitsObserver__.observe(root, { childList: true, subtree: true });
  } catch (e) {}
}

function __pulseSetChatLimitsEnabled__(enabled) {
  __pulseChatLimitsEnabled__ = !!enabled;
  if (!__pulseChatLimitsEnabled__) {
    __pulseRemoveAllChatLimitBadges__();
    return;
  }
  __pulseEnsureChatLimitsObserver__();
  __pulseScheduleInjectChatLimits__();
  setTimeout(() => __pulseInjectAllChatLimitBadges__(), 200);
}

try {
  chrome.storage.local.get(["enableChatLimits", PULSAR_AUTH_KEY], (result) => {
    const isAuthed = !!(result && result[PULSAR_AUTH_KEY] && result[PULSAR_AUTH_KEY].authenticated && result[PULSAR_AUTH_KEY].token);
    const enabled = isAuthed && result && result.enableChatLimits !== undefined ? result.enableChatLimits === true : isAuthed;
    __pulseSetChatLimitsEnabled__(enabled);
  });
} catch (e) {}

try {
  chrome.storage.onChanged.addListener((changes, areaName) => {
    if (areaName !== "local") return;
    if (!changes.enableChatLimits && !changes[PULSAR_AUTH_KEY]) return;
    chrome.storage.local.get(["enableChatLimits", PULSAR_AUTH_KEY], (result) => {
      const isAuthed = !!(result && result[PULSAR_AUTH_KEY] && result[PULSAR_AUTH_KEY].authenticated && result[PULSAR_AUTH_KEY].token);
      __pulseSetChatLimitsEnabled__(!!isAuthed && result.enableChatLimits === true);
    });
  });
} catch (e) {}

// Listen for MAIN-world limits data (same payload/type as ff)
window.addEventListener("message", (e) => {
  try {
    const d = e && e.data;
    if (!d || d.type !== "CHAT_LIMITS_DATA") return;

    const arr = d.chatLimits;
    if (!Array.isArray(arr) || arr.length === 0) return;

    arr.forEach((x) => {
      if (!x || !x.chat_uid) return;
      if (x.message_limit === undefined && x.letter_limit === undefined && x.total_limit === undefined) return;

      __PULSE_CHAT_LIMITS_MAP__.set(x.chat_uid, {
        messageLimit: x.message_limit || 0,
        letterLimit: x.letter_limit || 0,
        totalLimit: x.total_limit || 0,
      });
    });

    if (__pulseChatLimitsEnabled__) {
      __pulseEnsureChatLimitsObserver__();
      __pulseScheduleInjectChatLimits__();
      setTimeout(() => __pulseInjectAllChatLimitBadges__(), 2000);
    }
  } catch (e2) {}
});
}));const AH_CSS_TEXTS=[],AH_BASE="Pulse v"+chrome.runtime.getManifest().version,getPulseShadow=()=>document.getElementById("pulse-root")?.shadowRoot||null,getPulseQueryRoot=()=>getPulseShadow()||document,$=e=>getPulseQueryRoot().querySelector(e)||document.querySelector(e),$$=e=>{const t=getPulseQueryRoot(),n=[...(t.querySelectorAll?t.querySelectorAll(e):[])];if(t===document)return n;const o=[...document.querySelectorAll(e)].filter((e=>!n.includes(e)));return[...n,...o]},css=e=>{AH_CSS_TEXTS.push(e);const t=document.createElement("style");t.textContent=e,document.head.appendChild(t);const n=getPulseShadow();if(n){const t=document.createElement("style");t.textContent=e,n.appendChild(t)}},byId=e=>getPulseShadow()?.getElementById(e)||document.getElementById(e);const AH_SVG_NS="http://www.w3.org/2000/svg";function elt(e,t={},...n){const o=["svg","path","circle","g","defs","linearGradient","stop"].includes(e)?document.createElementNS(AH_SVG_NS,e):document.createElement(e);for(const[k,v]of Object.entries(t))"className"===k?o.setAttribute("class",v):k in o?o[k]=v:o.setAttribute(k,v);return n.flat().forEach((e=>{null!=e&&!1!==e&&o.append(e)})),o}async function getCf(){try{return(await chrome.runtime.sendMessage("getCookies")).cf}catch{return""}}async function sha1(e){const t=(new TextEncoder).encode(e),n=await crypto.subtle.digest("SHA-1",t);return[...new Uint8Array(n)].map((e=>e.toString(16).padStart(2,"0"))).join("")}let wsKeepPort=null;chrome.runtime.onConnect.addListener((e=>{"AH_WS_KEEP"===e.name&&(wsKeepPort=e,e.onMessage.addListener((()=>{})),e.onDisconnect.addListener((()=>{try{chrome.runtime.lastError}catch{}wsKeepPort=null})))}));const AH_STORE_KEYS={set:"ahSet",invites:"ahInv",stop:"ahStop",exp:"ahExpSec",migrated:"ahMigratedV2"},AH_TMP_HEAVY=["ahStatsDaily","ahFTResume"],AH_STORE={ready:!1,readyPromise:null,mem:{set:{invProfile:null},invites:{},stop:"",exp:0}},st={get:e=>new Promise((t=>chrome.storage.local.get(e,t))),set:e=>new Promise((t=>chrome.storage.local.set(e,(()=>t(!chrome.runtime.lastError))))),remove:e=>new Promise((t=>chrome.storage.local.remove(e,(()=>t(!chrome.runtime.lastError))))),bytes:(e=null)=>new Promise((t=>chrome.storage.local.getBytesInUse(e,(e=>t(e||0)))))};function ahClone(e){try{return structuredClone(e)}catch{return JSON.parse(JSON.stringify(e))}}async function tryMigrateFromSiteLS(){let e=null,t="",n=0,o={};try{e=JSON.parse(localStorage.getItem("alphaHelperSettings")||"null")}catch{}const a=!!localStorage.getItem("alphaHelperInvites");try{t=localStorage.getItem("alphaHelperStop")||""}catch{}try{n=parseInt(localStorage.getItem("alphaHelperExpSec")||"",10)||0}catch{}try{for(const e of Object.keys(localStorage))if(e.startsWith("alphaHelperInvites")&&"alphaHelperInvites"!==e){const t=e.slice(18);try{const n=JSON.parse(localStorage.getItem(e)||"null");n&&Object.keys(n).length&&(o[String(t)]=n)}catch{}}}catch{}if(a)try{const e=JSON.parse(localStorage.getItem("alphaHelperInvites")||"null");e&&Object.keys(e).length&&(o.global=e)}catch{}if(!(e||Object.keys(o).length||t||n))return!1;await st.remove(AH_TMP_HEAVY);const i={};e&&(i[AH_STORE_KEYS.set]=e),i[AH_STORE_KEYS.invites]=o,i[AH_STORE_KEYS.stop]=String(t||""),i[AH_STORE_KEYS.exp]=Number(n)||0;if(!await st.set(i))return!1;const r=await st.get([AH_STORE_KEYS.set,AH_STORE_KEYS.invites,AH_STORE_KEYS.stop,AH_STORE_KEYS.exp]);if(!!(!r[AH_STORE_KEYS.set]&&e||Object.keys(r[AH_STORE_KEYS.invites]||{}).length!==Object.keys(o||{}).length||String(r[AH_STORE_KEYS.stop]||"")!==String(t||"")||(Number(r[AH_STORE_KEYS.exp])||0)!==(Number(n)||0)))return!1;await st.set({[AH_STORE_KEYS.migrated]:!0});try{localStorage.removeItem("alphaHelperSettings")}catch{}try{localStorage.removeItem("alphaHelperInvites")}catch{}try{localStorage.removeItem("alphaHelperStop")}catch{}try{localStorage.removeItem("alphaHelperExpSec")}catch{}try{for(const e of Object.keys(localStorage))e.startsWith("alphaHelperInvites")&&"alphaHelperInvites"!==e&&localStorage.removeItem(e)}catch{}return!0}async function tryRescueFromLastPayload(){const e=(await st.get(["ahLastPayload"])).ahLastPayload;if(!e||"string"!=typeof e)return!1;let t=null;try{t=JSON.parse(e)}catch{return!1}const n={lastLike:"lastlike",factTimeMsg:"facttimemsg",stopMaybe:"stopmaybe",stopSpecial:"stopspecial",persToMaybe:"perstomaybe",persToSpecial:"perstospecial",emptyChatsToFolder:"emptychatstofolder"},o={invProfile:null},a=!!(t.timemin||t.settings&&t.settings.timemin);if(t.settings&&"object"==typeof t.settings)for(const[e,i]of Object.entries(t.settings)){const t=n[e]??e;if("sendEvery"!==t&&"mailEvery"!==t||null==i)"timemin"!==t&&(o[t]=i);else{const e=Number(i);o[t]=Number.isFinite(e)?snapAhTimeMinutes(a?e:60*e):null}}o.timemin=!0;const i={global:t.invites||{}};for(const[e,n]of Object.entries(t)){const t=/^invites(\d+)$/.exec(e);t&&n&&"object"==typeof n&&(i[t[1]]=n)}const r={[AH_STORE_KEYS.set]:o,[AH_STORE_KEYS.invites]:i,[AH_STORE_KEYS.stop]:String(t.stopList||""),[AH_STORE_KEYS.migrated]:!0};await st.remove(AH_TMP_HEAVY);return!!await st.set(r)}async function initAhStore(){return AH_STORE.readyPromise||(AH_STORE.readyPromise=(async()=>{const e=await st.get(Object.values(AH_STORE_KEYS));AH_STORE.mem.set=e[AH_STORE_KEYS.set]||{invProfile:null},AH_STORE.mem.invites=e[AH_STORE_KEYS.invites]||{},AH_STORE.mem.stop="string"==typeof e[AH_STORE_KEYS.stop]?e[AH_STORE_KEYS.stop]:"",AH_STORE.mem.exp=Number.isFinite(e[AH_STORE_KEYS.exp])?e[AH_STORE_KEYS.exp]:0;if(e[AH_STORE_KEYS.set]||e[AH_STORE_KEYS.invites]||e[AH_STORE_KEYS.stop])return void(AH_STORE.ready=!0);if(!await tryMigrateFromSiteLS()){await tryRescueFromLastPayload()||await st.set({[AH_STORE_KEYS.migrated]:!0})}const t=await st.get(Object.values(AH_STORE_KEYS));AH_STORE.mem.set=t[AH_STORE_KEYS.set]||{invProfile:null},AH_STORE.mem.invites=t[AH_STORE_KEYS.invites]||{},AH_STORE.mem.stop="string"==typeof t[AH_STORE_KEYS.stop]?t[AH_STORE_KEYS.stop]:"",AH_STORE.mem.exp=Number.isFinite(t[AH_STORE_KEYS.exp])?t[AH_STORE_KEYS.exp]:0,AH_STORE.ready=!0})()),AH_STORE.readyPromise}initAhStore().then((()=>{try{syncVisualFeatureSettings(loadSet())}catch{}}));try{chrome.storage.onChanged.addListener(((e,t)=>{if("local"!==t)return;const n=AH_STORE_KEYS;e[n.set]&&(AH_STORE.mem.set=ahClone(e[n.set].newValue||{invProfile:null})),e[n.invites]&&(AH_STORE.mem.invites=ahClone(e[n.invites].newValue||{})),e[n.stop]&&(AH_STORE.mem.stop=String(e[n.stop].newValue||"")),e[n.exp]&&(AH_STORE.mem.exp=Number(e[n.exp].newValue)||0)}))}catch(e){}function loadSet(){return ahClone(AH_STORE.mem.set||{invProfile:null})}function saveSet(e){AH_STORE.mem.set=ahClone(e||{invProfile:null}),st.set({[AH_STORE_KEYS.set]:AH_STORE.mem.set})}function buildAhtMarkChatsSettingsFromPulseSet(e=loadSet()){const t=!!(e&&e.personalTimerEnabled),n=!!(e&&e.personalTimerSoundEnabled);let o="";try{o=chrome.runtime.getURL("sounds/pixies-meloboom.mp3")}catch{}return{features:{inactiveChatLabels:!1,personalBadge:!1,chatLimitHighlight:!1,personalTimer:t,personalTimerSound:t&&n,personalTimerSoundUrl:o},modules:{markChats:t}}}function syncPersonalTimerFeatureSettings(e=loadSet()){try{chrome.storage.local.set({aht_settings_v1:buildAhtMarkChatsSettingsFromPulseSet(e)})}catch{}}function syncVisualFeatureSettings(e=loadSet()){const n=syncPulsarAuthStorage(e),t={enableChatTypeCheck:!!n&&e.frameEnabled!==!1,enableChatLimits:!!n&&e.chatLimitsEnabled!==!1,enableChatBalance:!!n&&e.chatBalanceEnabled!==!1};try{chrome.storage.local.set(t)}catch{}try{__pulseSetChatLimitsEnabled__(t.enableChatLimits)}catch{}try{syncPersonalTimerFeatureSettings(e)}catch{}}let ahActivityTimer=null,ahActivityFrame=null;const AH_ACTIVITY_INTERVAL=11e4,AH_ACTIVITY_FRAME_ID="pulse-activity-iframe";function ahClearActivityTimer(){ahActivityTimer&&(clearTimeout(ahActivityTimer),ahActivityTimer=null)}function ahRemoveActivityFrame(){try{ahActivityFrame&&ahActivityFrame.remove()}catch{}ahActivityFrame=null;try{const e=document.getElementById(AH_ACTIVITY_FRAME_ID);e&&e.remove()}catch{}}function ahGetActivityFrameUrl(){try{return location.origin+location.pathname+location.search}catch{return location.href}}function ahRunActivityTick(){const e=loadSet();if(!e.activity)return void ahSyncActivityLoop();try{ahRemoveActivityFrame();const e=document.createElement("iframe");e.id=AH_ACTIVITY_FRAME_ID,e.src=ahGetActivityFrameUrl(),e.setAttribute("aria-hidden","true"),e.setAttribute("tabindex","-1"),e.style.cssText="position:fixed;left:-9999px;top:-9999px;width:10px;height:10px;opacity:0;pointer-events:none;border:0;z-index:-2147483647;",(document.body||document.documentElement||document.head).appendChild(e),ahActivityFrame=e}catch{}finally{ahClearActivityTimer(),ahActivityTimer=setTimeout(ahRunActivityTick,AH_ACTIVITY_INTERVAL)}}function ahStopActivityLoop(){ahClearActivityTimer(),ahRemoveActivityFrame()}function ahSyncActivityLoop(){const e=loadSet();e.activity?(ahClearActivityTimer(),ahActivityTimer=setTimeout(ahRunActivityTick,AH_ACTIVITY_INTERVAL)):ahStopActivityLoop()}function loadInv(e=null){const t=e?String(e):"global";return ahClone((AH_STORE.mem.invites||{})[t]||{})}function saveInv(e,t=null){const n=t?String(t):"global";AH_STORE.mem.invites=AH_STORE.mem.invites||{},AH_STORE.mem.invites[n]=ahClone(e||{}),st.set({[AH_STORE_KEYS.invites]:AH_STORE.mem.invites})}function loadStop(){return String(AH_STORE.mem.stop||"")}function saveStop(e){AH_STORE.mem.stop=String(e||""),st.set({[AH_STORE_KEYS.stop]:AH_STORE.mem.stop})}function getExpSecMem(){return Number(AH_STORE.mem.exp)||0}function setExpSecMem(e){AH_STORE.mem.exp=Number(e)||0,st.set({[AH_STORE_KEYS.exp]:AH_STORE.mem.exp})}async function pageFetchJson(e,{method:t="GET",headers:n={},body:o=null,timeout:a=8e3}={}){const i="ah_"+Math.random().toString(36).slice(2),r=new Promise(((e,t)=>{const n=o=>{const a=o.data;a&&"PULSE_PAGE"===a.src&&"PULSE"===a.app&&"PULSE_FETCH_RES"===a.type&&a.id===i&&(window.removeEventListener("message",n),a.ok?e(a):t(new Error(a.error||"page fetch failed")))};window.addEventListener("message",n),setTimeout((()=>{window.removeEventListener("message",n),t(new Error("timeout"))}),a)}));window.postMessage({src:"PULSE_SW",type:"PULSE_FETCH_REQ",app:"PULSE",id:i,path:e,method:t,headers:n,bodyBase64:o?btoa((new TextEncoder).encode(o).reduce(((e,t)=>e+String.fromCharCode(t)),"")):null},location.origin);const s=await r,l=(new TextDecoder).decode(Uint8Array.from(atob(s.bodyBase64),(e=>e.charCodeAt(0))));return{status:s.status,headers:s.headers,text:l,json:JSON.parse(l)}}function makeThumb(e){const t=e.split("/"),n=t.pop();return[...t,`w-250-h-250-${n}`].join("/")}async function fetchGallery(e){const t=(localStorage.getItem("token")||"").trim(),n=t?{Authorization:`Bearer ${t}`}:{},{json:o}=await pageFetchJson(`/api/files/images?external_id=${e}`,{method:"GET",headers:n});if(!o||!Array.isArray(o.images))return[];const a=new Map;return(o.images||[]).forEach((e=>a.set(e.link,e))),[...a.values()]}function sendTokenToSW(){const e=localStorage.getItem("token")||"";chrome.runtime.sendMessage({type:"token",value:e}).catch((()=>{})),st.set({ahJwt:e})}sendTokenToSW(),window.addEventListener("storage",(e=>{"token"===e.key&&sendTokenToSW()})),css(`
  #ah-overlay{position:fixed;inset:0;background:rgba(0,0,0,.55);backdrop-filter:blur(1px);
    display:flex;align-items:center;justify-content:center;z-index:9999;
    font-family:system-ui,sans-serif}
#ah-modal{
  display:flex;
  flex-direction:column;
  position:relative;
  color:#e9eef6;
  background:
    radial-gradient(circle at 18% 22%, rgba(0,255,180,.26) 0%, rgba(0,255,180,0) 45%),
    radial-gradient(circle at 62% 10%, rgba(0,180,255,.10) 0%, rgba(0,180,255,0) 55%),
    radial-gradient(circle at 50% 120%, rgba(0,0,0,.55) 0%, rgba(0,0,0,0) 60%),
    linear-gradient(135deg, #0f151c 0%, #101821 45%, #070a0e 100%);
  border:1px solid rgba(255,255,255,.06);
  box-shadow:0 18px 50px rgba(0,0,0,.65),0 0 0 1px rgba(0,0,0,.35) inset;
  padding:20px 24px;
  border-radius:8px;

  /* ÃÂÃÂ¸ÃÂÃÂ¸ÃÂ½ÃÂ° */
  min-width:350px;
  max-width:90vw;

  /* ÃÂ²ÃÂÃÂÃÂ¾ÃÂÃÂ° (ÃÂÃÂ¸ÃÂºÃÂÃÂ¸ÃÂÃÂ¾ÃÂ²ÃÂ°ÃÂ½ÃÂ½ÃÂ°ÃÂ ÃÂ¸ÃÂ»ÃÂ¸ ÃÂ¼ÃÂ¸ÃÂ½ÃÂ¸ÃÂ¼ÃÂ°ÃÂ»ÃÂÃÂ½ÃÂ°ÃÂ) */
  height:185px;        /* = ÃÂÃÂ¾ÃÂÃÂ½ÃÂ°ÃÂ ÃÂ²ÃÂÃÂÃÂ¾ÃÂÃÂ° 260 px */
  /* ÃÂ¸ÃÂ»ÃÂ¸, ÃÂµÃÂÃÂ»ÃÂ¸ ÃÂ½ÃÂÃÂ¶ÃÂ½ÃÂ¾ ÃÂ»ÃÂ¸ÃÂÃÂ ÃÂ½ÃÂ¸ÃÂ¶ÃÂ½ÃÂµÃÂµ ÃÂ¾ÃÂ³ÃÂÃÂ°ÃÂ½ÃÂ¸ÃÂÃÂµÃÂ½ÃÂ¸ÃÂµ: */
  /* min-height:260px; */

  
}
  #ah-modal h2{margin:0 0 12px;font-size:18px}

  /* ÃÂÃÂ¾ÃÂÃÂ¼ÃÂ° ÃÂºÃÂ»ÃÂÃÂÃÂ° */
  #ah-form{display:flex;gap:8px;margin-bottom:12px}
  #ah-form input{flex:1;padding:8px;border:1px solid rgba(255,255,255,.10);border-radius:6px;font-size:14px;background:rgba(255,255,255,.06);color:#e9eef6;outline:none}
  #ah-modal button{padding:10px 16px;font-size:14px;border:1px solid rgba(255,255,255,.10);background:rgba(255,255,255,.08);color:#e9eef6;border-radius:8px;cursor:pointer;backdrop-filter:blur(2px);transition:filter .15s, background .15s, border-color .15s}
  #ah-modal button:disabled{opacity:.6}
  #ah-modal button:hover{filter:brightness(1.08)}

  /* ÃÂÃÂ°ÃÂ±ÃÂ */
  #ah-tabs{display:flex;gap:6px;margin-bottom:12px}
  #ah-modal .ah-tab{min-width:88px;padding:6px 12px;border-radius:8px;cursor:pointer;background:rgba(255,255,255,.06);border:1px solid rgba(255,255,255,.07);color:rgba(233,238,246,.85);font-size:14px;font-weight:600;text-align:center;user-select:none;transition:.15s}
  #ah-modal .ah-tab:hover{background:rgba(255,255,255,.09)}
  #ah-modal .ah-tab.ah-active{background:rgba(0,255,180,.16);border-color:rgba(0,255,180,.28);color:#eafff7;box-shadow:0 0 0 1px rgba(0,255,180,.10) inset}
  #ah-modal .inv-tab{padding:6px 10px;border-radius:7px;cursor:pointer;user-select:none;background:rgba(255,255,255,.06);border:1px solid rgba(255,255,255,.08);color:#cfd7e3;font-size:12px;font-weight:600;letter-spacing:.2px;transition:.15s}
  #ah-modal .inv-tab:hover{background:rgba(255,255,255,.10)}
  #ah-modal .inv-tab.active{background:rgba(0,255,180,.18);border-color:rgba(0,255,180,.35);color:#eafff7;box-shadow:0 0 0 1px rgba(0,0,0,.25) inset,0 6px 16px rgba(0,0,0,.25)}

  /* ÃÂÃÂ°ÃÂ±ÃÂ¾ÃÂÃÂ°ÃÂ ÃÂ·ÃÂ¾ÃÂ½ÃÂ° */
  #ah-body{flex:1 1 auto;height:360px;overflow:auto;background:rgba(36,37,42,.85);
    padding:12px;font-size:14px;color:#e9eef6;border-radius:8px}

  /* scrollbar (match Pulse modal style) */
  #ah-modal *{scrollbar-width:thin;scrollbar-color:rgba(0,255,180,.38) rgba(255,255,255,.06)}
  #ah-modal *::-webkit-scrollbar{width:10px;height:10px}
  #ah-modal *::-webkit-scrollbar-track{background:rgba(255,255,255,.06);border:1px solid rgba(255,255,255,.08);border-radius:999px}
  #ah-modal *::-webkit-scrollbar-thumb{background:linear-gradient(180deg, rgba(0,255,180,.55), rgba(0,255,180,.22));border:1px solid rgba(0,255,180,.30);border-radius:999px;box-shadow:0 0 10px rgba(0,255,180,.18)}
  #ah-modal *::-webkit-scrollbar-thumb:hover{background:linear-gradient(180deg, rgba(0,255,180,.70), rgba(0,255,180,.28));border-color:rgba(0,255,180,.40)}
  #ah-modal *::-webkit-scrollbar-corner{background:transparent}


  /* Ð¿Ð¾Ð»Ñ Ð²Ð²Ð¾Ð´Ð° / ÑÐ°Ð¹Ð¼ÐµÑÑ */
  #ah-body input[type="number"],
  #ah-body input[type="text"],
  #ah-body input[type="datetime-local"],
  #ah-body select,
  #ah-body textarea{
    background:rgba(255,255,255,.06);
    color:#e9eef6;
    border:1px solid rgba(255,255,255,.12);
    border-radius:8px;
    outline:none;
  }

  /* читаемые выпадающие списки (без пересвета) */
  #inv-profile-select, #bl-profile-select{
    background:rgba(0,0,0,.18);
  }
  #inv-profile-select option, #bl-profile-select option{
    background:#0b1220;
    color:#e9eef6;
  }

  /* фильтры Block list (месяц/год) — тоже без пересвета */
  #bl-month, #bl-year{
    background:rgba(0,0,0,.18);
  }
  #bl-month option, #bl-year option{
    background:#0b1220;
    color:#e9eef6;
  }
  #ah-body input[type="number"]{text-align:center;font-variant-numeric:tabular-nums;}
  #ah-body input:focus, #ah-body textarea:focus, #ah-body select:focus{
    border-color:rgba(0,255,180,.35);
    box-shadow:0 0 0 3px rgba(0,255,180,.10);
  }

  /* ÃÂºÃÂ½ÃÂ¾ÃÂ¿ÃÂºÃÂ¸ ÃÂ² ÃÂ·ÃÂ°ÃÂ³ÃÂ¾ÃÂ»ÃÂ¾ÃÂ²ÃÂºÃÂµ */
  #ah-modal .ah-hdr{
    position:absolute;top:6px;width:30px;height:30px;
    display:flex;align-items:center;justify-content:center;
    border:none;border-radius:6px;cursor:pointer;
    background:#007aff;color:#fff;
  }
  #ah-modal .ah-hdr span{font-size:26px !important;line-height:1;}
  #ah-close{right:6px;background:#007aff;border-radius:6px}
  #ah-info {right:46px;background:#ffa200;border-radius:6px}
  #ah-help{right:86px;background:#28a745;border-radius:6px}
  #ah-close:hover{background:#0064d6} #ah-info:hover{background:#e29000} #ah-help:hover{background:#218838}

#ah-opid {
  position:absolute;
  left:12px;
  top:10px;
  font-size:12px;
  font-weight:700;
  letter-spacing:.3px;
  color:rgba(233,238,246,.85);
  padding:3px 8px;
  border-radius:8px;
  background:rgba(255,255,255,.06);
  border:1px solid rgba(255,255,255,.08);
  backdrop-filter:blur(4px);
  user-select:none;
}
#ah-act-counter{
  position:absolute;
  left:12px;
  top:42px;
  display:flex;
  align-items:center;
  gap:8px;
  font-size:23px;
  font-weight:800;
  letter-spacing:1px;
  user-select:none;
}
#ah-act-counter .ah-act-icon{
  font-size:20px;
  opacity:.85;
  filter:drop-shadow(0 0 8px rgba(0,255,180,.35));
}
#ah-act-counter #ah-act-val{
  font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono",monospace;
  background:linear-gradient(90deg, rgba(0,255,180,.95), rgba(0,180,255,.90), rgba(0,255,180,.95));
  background-size:200% 100%;
  -webkit-background-clip:text;
  background-clip:text;
  color:transparent;
  text-shadow:0 0 14px rgba(0,255,180,.25);
  animation:ahCounterShine 3.2s linear infinite;
}
#ah-act-counter.ah-bump{animation:ahCounterBump .35s ease-out;}
@keyframes ahCounterShine{0%{background-position:0% 50%}100%{background-position:200% 50%}}
@keyframes ahCounterBump{0%{transform:scale(1);filter:drop-shadow(0 0 0 rgba(0,255,180,0))}40%{transform:scale(1.06);filter:drop-shadow(0 0 16px rgba(0,255,180,.30))}100%{transform:scale(1);filter:drop-shadow(0 0 0 rgba(0,255,180,0))}}



#ah-balance{
  position:absolute;
  left:12px;
  top:70px;
  display:flex;
  align-items:baseline;
  gap:8px;
  font-size:18px;
  font-weight:800;
  letter-spacing:.2px;
  user-select:none;
}
#ah-balance #ah-bal-val{
  font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono",monospace;
  background:linear-gradient(90deg, rgba(255,200,0,0.92), rgba(0,255,180,0.92), rgba(120,180,255,0.92));
  background-size:200% 100%;
  -webkit-background-clip:text;
  background-clip:text;
  color:transparent;
  text-shadow:0 0 14px rgba(255,200,0,0.18);
  animation:ahBalShine 4.2s linear infinite;
}
@keyframes ahBalShine{0%{background-position:0% 50%}100%{background-position:200% 50%}}



#ah-exp{
  position:absolute;
  left:12px;
  top:94px;
  display:flex;
  align-items:baseline;
  gap:8px;
  font-size:17px;
  font-weight:800;
  letter-spacing:.25px;
  user-select:none;
  opacity:.92;
}
#ah-exp #ah-exp-val{
  font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono",monospace;
  background:linear-gradient(90deg, rgba(0,255,180,0.92), rgba(0,180,255,0.92), rgba(0,255,180,0.92));
  background-size:200% 100%;
  -webkit-background-clip:text;
  background-clip:text;
  color:transparent;
  text-shadow:0 0 12px rgba(0,255,180,0.18);
  animation:ahExpShine 4.2s linear infinite;
}
@keyframes ahExpShine{0%{background-position:0% 50%}100%{background-position:200% 50%}}
#ah-tg {
  position:absolute;
  top:10px;                 /* ÃÂÃÂÃÂÃÂ ÃÂ½ÃÂ¸ÃÂ¶ÃÂµ, ÃÂÃÂÃÂ¾ÃÂ±ÃÂ ÃÂÃÂµÃÂºÃÂÃÂ ÃÂ¿ÃÂ¾ ÃÂÃÂµÃÂ½ÃÂÃÂÃÂ */
  right:86px;               /* ÃÂ¿ÃÂ¾ÃÂÃÂ»ÃÂµ Ã¢ÂÂ (46 px) ÃÂ¸ ÃÂ¿ÃÂµÃÂÃÂµÃÂ´ ÃÂ (6 px) */
  font-size:14px;
  font-weight:600;
   color:rgba(0,255,180,.75);     /* Ã¢ÂÂ ÃÂÃÂ¾ÃÂ ÃÂ¶ÃÂµ ÃÂ¾ÃÂÃÂÃÂµÃÂ½ÃÂ¾ÃÂº ÃÂÃÂ¸ÃÂ½ÃÂµÃÂ³ÃÂ¾, ÃÂÃÂÃÂ¾ ÃÂ¸ ÃÂºÃÂ½ÃÂ¾ÃÂ¿ÃÂºÃÂ¸ */
  text-decoration:none;
}
#ah-tg:hover { text-decoration:underline; }


  /* ÃÂÃÂÃÂ¼ÃÂ±ÃÂ»ÃÂµÃÂ */
  #ah-modal .switch{position:relative;width:44px;height:24px}
  #ah-modal .switch input{opacity:0;width:0;height:0}
  #ah-modal .slider{position:absolute;inset:0;background:rgba(255,255,255,.14);border:1px solid rgba(255,255,255,.10);border-radius:34px;transition:.2s}
  #ah-modal .slider:before{content:"";position:absolute;height:18px;width:18px;left:3px;top:3px;background:rgba(255,255,255,.92);border-radius:50%;transition:.2s;box-shadow:0 2px 8px rgba(0,0,0,.35)}
  #ah-modal input:checked+.slider{background:#33c98c;border-color:rgba(51,201,140,.55);box-shadow:0 0 12px rgba(51,201,140,.25)}
  #ah-modal input:checked+.slider:before{transform:translateX(20px)}
  #ah-modal .switch.ah-switch-danger input:checked+.slider{background:#d32f2f;border-color:rgba(211,47,47,.58);box-shadow:0 0 12px rgba(211,47,47,.25)}
  #ah-modal .switch.ah-switch-danger .slider:before{background:#fff7f7}

  /* ÃÂ±ÃÂ¾ÃÂ»ÃÂÃÂÃÂ¸ÃÂµ ÃÂÃÂÃÂ°ÃÂÃÂ/ÃÂÃÂÃÂ¾ÃÂ¿ */
  #ah-modal .big-switch{display:flex;align-items:center;gap:12px;margin-top:18px;font-size:16px}
  #ah-modal .big-switch .slider{width:60px;height:32px}
  #ah-modal .big-switch .slider:before{height:26px;width:26px;left:3px;top:3px}
  #ah-modal .big-switch input:checked+.slider:before{transform:translateX(26px)}

  /* ÃÂºÃÂ½ÃÂ¾ÃÂ¿ÃÂºÃÂ° Start / Stop */
  #ah-body{position:relative;}
#ah-body{position:relative;}
#ah-start{
  position:static;
  padding:14px 36px !important;
  font-size:18px !important;
  font-weight:700;
  border-radius:10px;
  cursor:pointer;user-select:none;
  background:transparent !important;
  border:1px solid rgba(0,255,180,65);
  color:#eafff7;
  box-shadow:0 0 0 1px rgba(0,255,180,20) inset, 0 0 22px rgba(0,255,180,25);
  backdrop-filter:blur(6px) saturate(140%);
  overflow:hidden;
  position:relative;
}
#ah-start::before{
  content:"";
  position:absolute;
  inset:1px;
  border-radius:inherit;
  background:linear-gradient(180deg, rgba(255,255,255,0.20), rgba(255,255,255,0.02));
  opacity:0.18;
  pointer-events:none;
}
#ah-start::after{
  content:"";
  position:absolute;
  left:-20%;
  top:-60%;
  width:140%;
  height:120%;
  background:radial-gradient(circle at 30% 40%, rgba(255,255,255,0.22), rgba(255,255,255,0) 55%);
  opacity:0.12;
  pointer-events:none;
}
#ah-start:hover{
  filter:brightness(1.08);
  box-shadow:0 0 0 1px rgba(0,255,180,24) inset, 0 0 30px rgba(0,255,180,35);
}
#ah-start.stop{
  background:transparent !important;
  border-color:rgba(255,72,72,70);
  color:#ffecec;
  box-shadow:0 0 0 1px rgba(255,72,72,20) inset, 0 0 22px rgba(255,72,72,25);
}
#ah-start.stop::before{
  background:linear-gradient(180deg, rgba(255,255,255,0.18), rgba(255,72,72,0.04));
  opacity:0.16;
}
#ah-start.stop::after{
  background:radial-gradient(circle at 30% 40%, rgba(255,255,255,0.18), rgba(255,72,72,0) 55%);
  opacity:0.10;
}
#ah-start.stop:hover{
  filter:brightness(1.08);
  box-shadow:0 0 0 1px rgba(255,72,72,24) inset, 0 0 30px rgba(255,72,72,35);
}

/* Stop-List */
  #ah-stop-input{width:100%;height:320px;resize:none;padding:10px;font:14px/1.4 system-ui;border:1px solid rgba(255,255,255,.12);border-radius:8px;background:rgba(255,255,255,.06);color:#e9eef6;outline:none}

  /* Ã¢ÂÂÃ¢ÂÂÃ¢ÂÂ Invites Ã¢ÂÂÃ¢ÂÂÃ¢ÂÂ */
  #inv-tabs{display:flex;gap:4px;margin-bottom:10px;flex-wrap:wrap}
  #ah-modal .inv-tab{
    padding:6px 10px;
    border-radius:7px;
    cursor:pointer;
    user-select:none;
    background:rgba(255,255,255,.06);
    border:1px solid rgba(255,255,255,.08);
    color:rgba(233,238,246,.85);
    font-size:12px;
    font-weight:600;
    letter-spacing:.2px;
    transition:.15s;
  }
  /* ÃÂ²ÃÂµÃÂÃÂÃÂ½ÃÂÃÂ ÃÂ¿ÃÂ°ÃÂ½ÃÂµÃÂ»ÃÂ Invites: ÃÂ²ÃÂÃÂ±ÃÂ¾ÃÂ ÃÂ°ÃÂ½ÃÂºÃÂµÃÂÃÂ + refresh */
  #inv-topbar{
    display:flex;align-items:center;gap:8px;
    margin:0px 0 8px 0;          /* ÃÂ½ÃÂµÃÂ±ÃÂ¾ÃÂ»ÃÂÃÂÃÂ¾ÃÂ¹ ÃÂ¾ÃÂÃÂÃÂÃÂÃÂ¿ ÃÂÃÂ²ÃÂµÃÂÃÂÃÂ/ÃÂÃÂ½ÃÂ¸ÃÂ·ÃÂ */
  }
  #inv-profile-select{
    min-width:200px;
    padding:6px 8px;
    border:1px solid #ccc;border-radius:6px;
    font-size:14px;
  }
  #inv-refresh{
    cursor:pointer;
    font-size:18px;
    user-select:none;
  }


  #bl-topbar{
    display:flex;align-items:center;gap:8px;
    margin:0px 0 8px 0;
  }
  #bl-profile-select{
    min-width:200px;
    padding:6px 8px;
    border:1px solid #ccc;border-radius:6px;
    font-size:14px;
  }
  #bl-refresh{
    cursor:pointer;
    font-size:18px;
    user-select:none;
  }
  #al-refresh{
    cursor:pointer;
    font-size:18px;
    user-select:none;
  }
  #ah-modal .inv-tab:hover {background:#d0d0d0}
  #ah-modal .inv-tab.active{background:rgba(0,255,180,.16);border-color:rgba(0,255,180,.28);color:#eafff7;box-shadow:0 0 0 1px rgba(0,255,180,.10) inset}

  /* ÃÂÃÂµÃÂºÃÂÃÂ + ÃÂ¿ÃÂ»ÃÂÃÂÃÂ¸ÃÂº */
#inv-row{
  position:relative;
  display:flex;                 /* ÃÂ¿ÃÂ»ÃÂµÃÂ¹ÃÂÃÂÃÂ¾ÃÂ»ÃÂ´ÃÂµÃÂ + textarea = flex-ÃÂÃÂÃÂÃÂ¾ÃÂºÃÂ° */
  align-items:flex-start;
  gap:8px;
  margin-bottom:10px;
}

  #inv-input{
  flex:1;                       /* ÃÂ·ÃÂ°ÃÂ½ÃÂ¸ÃÂ¼ÃÂ°ÃÂµÃÂ ÃÂ²ÃÂÃÂ ÃÂ¾ÃÂÃÂÃÂ°ÃÂ²ÃÂÃÂµÃÂµÃÂÃÂ ÃÂ¼ÃÂµÃÂÃÂÃÂ¾ */
  height:80px;resize:none;
    padding:8px 40px 8px 8px;
    border:1px solid #ccc;border-radius:6px;font:14px/1.4 system-ui
  }
  #inv-plus{
    position:absolute;right:10px;top:10px;width:24px;height:24px;
    display:flex;align-items:center;justify-content:center;
    border-radius:50%;background:rgba(0,255,180,.18);border:1px solid rgba(0,255,180,.25);color:#eafff7;font-size:18px;box-shadow:0 0 10px rgba(0,255,180,.18);
    cursor:pointer;user-select:none;transition:filter .15s
  }
  #inv-plus:hover{filter:brightness(1.1)}

  /* ÃÂºÃÂ°ÃÂÃÂÃÂ¾ÃÂÃÂºÃÂ° ÃÂÃÂÃÂ°ÃÂ·ÃÂ */
  #ah-modal .inv-item{
    margin-top:10px;
    padding:8px 8px;
    border:1px solid rgba(255,255,255,.10);border-radius:8px;background:rgba(255,255,255,.04);color:#e9eef6;
    font-size:14px;line-height:1.3;
  
    display:flex;gap:10px;
    align-items:flex-start;
  }


/* ÃÂºÃÂ°ÃÂÃÂÃÂ¸ÃÂ½ÃÂºÃÂ° + ÃÂ¿ÃÂ¾ÃÂ´ÃÂ¿ÃÂ¸ÃÂÃÂ */
.inv-img-wrap{
  flex:none;                           /* ÃÂÃÂ¸ÃÂºÃÂ. ÃÂÃÂ¸ÃÂÃÂ¸ÃÂ½ÃÂ° */
  display:flex;flex-direction:column;align-items:center;
}
.inv-img-wrap img{width:60px;height:60px;object-fit:cover;border-radius:4px;}
.inv-img-wrap .tag{
  margin-top:4px;
  font-size:12px;
  color:#f1c40f;           /* ÃÂ±ÃÂ¾ÃÂ»ÃÂµÃÂµ ÃÂ·ÃÂ°ÃÂ¼ÃÂµÃÂÃÂ½ÃÂÃÂ¹ ÃÂ¾ÃÂÃÂÃÂµÃÂ½ÃÂ¾ÃÂº */
  user-select:none;
}

/* ÃÂÃÂµÃÂºÃÂÃÂ ÃÂ¿ÃÂ¾ÃÂ»ÃÂÃÂÃÂ°ÃÂµÃÂ ÃÂ²ÃÂÃÂ ÃÂ¾ÃÂÃÂÃÂ°ÃÂ²ÃÂÃÂµÃÂµÃÂÃÂ ÃÂ¿ÃÂÃÂ¾ÃÂÃÂÃÂÃÂ°ÃÂ½ÃÂÃÂÃÂ²ÃÂ¾ */
.inv-text{flex:1;white-space:pre-wrap;overflow-wrap:anywhere;}


/* --- ÃÂºÃÂ°ÃÂÃÂÃÂ¸ÃÂ½ÃÂºÃÂ° ÃÂ² ÃÂÃÂ¾ÃÂÃÂ¼ÃÂµ ÃÂ¸ÃÂ½ÃÂ²ÃÂ°ÃÂ¹ÃÂÃÂ° --- */
#inv-img-box{
  position:relative;
  width:60px;height:60px;border:1px dashed #555;
  display:flex;align-items:center;justify-content:center;
  cursor:pointer;margin-left:6px;user-select:none;
}
#inv-img-box .remove{
  position:absolute;top:-4px;right:-4px;         /* ÃÂÃÂÃÂÃÂ ÃÂ·ÃÂ° ÃÂ¿ÃÂÃÂµÃÂ´ÃÂµÃÂ»ÃÂ ÃÂºÃÂ°ÃÂ´ÃÂÃÂ° */
  width:20px;height:20px;
  display:flex;align-items:center;justify-content:center;
  background:rgba(0,0,0,.65);
  color:#fff;font-size:16px;font-weight:600;
  border:none;border-radius:50%;cursor:pointer;padding:0;
}
#inv-img-box .remove:hover{background:rgba(0,0,0,.85);}
#inv-img-box img{width:100%;height:100%;object-fit:cover;border-radius:4px}

/* ÃÂ¿ÃÂ¾ÃÂ´ÃÂ¿ÃÂ¸ÃÂÃÂ ÃÂ«pic firstÃÂ» */
#inv-img-box + label{
  margin-top:4px;
  font-size:12px;
  color:#ccc;
  cursor:pointer;
  user-select:none;
}
#inv-img-box + label input{margin-right:4px}

/* Ã¢ÂÂÃ¢ÂÂÃ¢ÂÂ ÃÂ¿ÃÂµÃÂÃÂµÃÂ½ÃÂ¾ÃÂÃÂ¸ÃÂ¼ ÃÂ´ÃÂ°ÃÂ¶ÃÂµ "ÃÂÃÂ»ÃÂ¸ÃÂÃÂ½ÃÂÃÂµ" ÃÂÃÂ»ÃÂ¾ÃÂ²ÃÂ° ÃÂ²ÃÂ½ÃÂÃÂÃÂÃÂ¸ ÃÂºÃÂ°ÃÂÃÂÃÂ¾ÃÂÃÂºÃÂ¸ Ã¢ÂÂÃ¢ÂÂÃ¢ÂÂ */
#ah-modal .inv-item span{
  white-space:pre-wrap;      /* ÃÂÃÂ¾ÃÂÃÂÃÂ°ÃÂ½ÃÂµÃÂ½ÃÂ¸ÃÂµ 
 ÃÂ¸ ÃÂ¾ÃÂ±ÃÂÃÂÃÂ½ÃÂÃÂ ÃÂ¿ÃÂÃÂ¾ÃÂ±ÃÂµÃÂ»ÃÂ¾ÃÂ² */
  overflow-wrap:anywhere;    /* ÃÂ¿ÃÂµÃÂÃÂµÃÂ½ÃÂ¾ÃÂÃÂ¸ÃÂÃÂ ÃÂ³ÃÂ´ÃÂµ ÃÂÃÂ³ÃÂ¾ÃÂ´ÃÂ½ÃÂ¾, ÃÂµÃÂÃÂ»ÃÂ¸ ÃÂ½ÃÂÃÂ¶ÃÂ½ÃÂ¾ */
  word-break:break-word;     /* fallback ÃÂ´ÃÂ»ÃÂ ÃÂÃÂÃÂ°ÃÂÃÂÃÂ ÃÂ±ÃÂÃÂ°ÃÂÃÂ·ÃÂµÃÂÃÂ¾ÃÂ² */
}
  #ah-modal .inv-ctrl{
    display:flex;gap:6px;align-items:center;
    margin-left:auto;           /* ÃÂÃÂÃÂ¾ÃÂ´ÃÂ¸ÃÂ ÃÂ² ÃÂÃÂ°ÃÂ¼ÃÂÃÂ¹ ÃÂ¿ÃÂÃÂ°ÃÂ²ÃÂÃÂ¹ ÃÂºÃÂÃÂ°ÃÂ¹ ÃÂÃÂÃÂÃÂ¾ÃÂºÃÂ¸ */
    font-size:12px;user-select:none;
  }

  #ah-modal .inv-del{
    cursor:pointer;color:#ff6b6b;font-weight:600;font-size:18px;
  }
  #ah-modal .inv-arrow{cursor:pointer;font-size:18px;color:rgba(0,255,180,.85)}
  #ah-modal .inv-move{cursor:pointer;color:rgba(0,255,180,.85);line-height:10px}
  #ah-modal .inv-move:hover{color:rgba(0,255,180,1)}

  /* ÃÂ¼ÃÂ¸ÃÂ½ÃÂ¸-ÃÂ¿ÃÂ°ÃÂÃÂ¿ÃÂ¾ÃÂÃÂ ÃÂ¿ÃÂ¾ ÃÂºÃÂ»ÃÂ¸ÃÂºÃÂ ÃÂ½ÃÂ° Ã¢ÂÂ */
#ah-info-box{
  position:fixed;right:20px;bottom:20px;z-index:10000;
  max-width:360px;max-height:70vh;
  padding:12px 16px 16px 16px;

  background:rgba(14,18,24,.92);color:#e9eef6;font:13px/1.45 system-ui,sans-serif;backdrop-filter:blur(6px);
  border:1px solid rgba(255,255,255,.10);border-radius:10px;
  box-shadow:0 4px 12px rgba(0,0,0,.25);

  white-space:pre-wrap;         /* ÃÂÃÂ¾ÃÂÃÂÃÂ°ÃÂ½ÃÂÃÂµÃÂ¼ 
 */
  overflow-y:auto;              /* Ã¢ÂÂ ÃÂÃÂ¾ÃÂ»ÃÂÃÂºÃÂ¾ ÃÂ²ÃÂµÃÂÃÂÃÂ¸ÃÂºÃÂ°ÃÂ»ÃÂÃÂ½ÃÂ°ÃÂ ÃÂ¿ÃÂ¾ÃÂ»ÃÂ¾ÃÂÃÂ° */
  overflow-x:hidden;            /* Ã¢ÂÂ ÃÂÃÂ±ÃÂ¸ÃÂÃÂ°ÃÂµÃÂ¼ ÃÂ³ÃÂ¾ÃÂÃÂ¸ÃÂ·ÃÂ¾ÃÂ½ÃÂÃÂ°ÃÂ»ÃÂ */
  word-break:break-word;        /* ÃÂ¿ÃÂµÃÂÃÂµÃÂ½ÃÂ¾ÃÂÃÂ¸ÃÂ¼ ÃÂÃÂ§ÃÂÃÂÃÂ¬ ÃÂ´ÃÂ»ÃÂ¸ÃÂ½ÃÂ½ÃÂÃÂµ ÃÂºÃÂÃÂÃÂºÃÂ¸ */
}

/* ÃÂ¼ÃÂ°ÃÂ»ÃÂµÃÂ½ÃÂÃÂºÃÂ¸ÃÂ¹ ÃÂºÃÂÃÂµÃÂÃÂÃÂ¸ÃÂº ÃÂ² ÃÂ¿ÃÂÃÂ°ÃÂ²ÃÂ¾ÃÂ¼-ÃÂ²ÃÂµÃÂÃÂÃÂ½ÃÂµÃÂ¼ ÃÂÃÂ³ÃÂ»ÃÂ */
#ah-info-box .close{
  position:absolute;top:6px;right:8px;
  cursor:pointer;font-size:18px;line-height:12px;
  color:#888;font-weight:600;
}
#ah-info-box .close:hover{color:#d32f2f}

/* ÃÂ¾ÃÂ±ÃÂÃÂÃÂÃÂºÃÂ° ÃÂ´ÃÂ»ÃÂ ÃÂºÃÂ½ÃÂ¾ÃÂ¿ÃÂºÃÂ¸ ÃÂ¸ ÃÂ¿ÃÂ¾ÃÂ´ÃÂ¿ÃÂ¸ÃÂÃÂ¸ */
#ah-ctrl{
  position:absolute;
  right:20px;
  bottom:20px;

  display:flex;
  flex-direction:column;   /* ÃÂ²ÃÂµÃÂÃÂÃÂ¸ÃÂºÃÂ°ÃÂ»ÃÂÃÂ½ÃÂ¾ */
  align-items:center;      /* Ã¢ÂÂ ÃÂ²ÃÂÃÂÃÂ°ÃÂ²ÃÂ½ÃÂ¸ÃÂ²ÃÂ°ÃÂµÃÂ¼ ÃÂ¿ÃÂ¾ ÃÂ¦ÃÂÃÂÃÂ¢ÃÂ ÃÂ£ */
  gap:6px;                 /* ÃÂÃÂ°ÃÂÃÂÃÂÃÂ¾ÃÂÃÂ½ÃÂ¸ÃÂµ ÃÂ¼ÃÂµÃÂ¶ÃÂ´ÃÂ ÃÂÃÂÃÂÃÂ¾ÃÂºÃÂ°ÃÂ¼ÃÂ¸ */
}


/* ÃÂ¿ÃÂ¾ÃÂ´ÃÂ¿ÃÂ¸ÃÂÃÂ ÃÂ¿ÃÂ¾ÃÂ´ ÃÂºÃÂ½ÃÂ¾ÃÂ¿ÃÂºÃÂ¾ÃÂ¹ */
#ah-status{
  font-size:14px;
  font-weight:500;
  text-align:center;       /* ÃÂ½ÃÂ° ÃÂ²ÃÂÃÂÃÂºÃÂ¸ÃÂ¹ ÃÂÃÂ»ÃÂÃÂÃÂ°ÃÂ¹ */
}



/* --- Pulse brand logo --- */
.pulse-brand{width:100%;display:flex;align-items:center;justify-content:center;margin:10px 0 12px 0;position:relative;}
.pulse-brand img{height:104px;max-width:94%;object-fit:contain;pointer-events:none;transform:scaleX(1.06);
  filter:drop-shadow(0 0 2px rgba(180,0,255,.16)) drop-shadow(0 0 10px rgba(180,0,255,.09)) drop-shadow(0 0 22px rgba(180,0,255,.05));}
.pulse-brand:before{content:"";position:absolute;inset:auto;left:50%;top:50%;transform:translate(-50%,-50%);
  width:520px;height:90px;background:radial-gradient(circle, rgba(180,0,255,.22) 0%, rgba(180,0,255,0) 70%);
  filter:blur(12px);pointer-events:none;}
#ah-modal h2{display:none !important;}
.notranslate{unicode-bidi:isolate;}

/* --- Pulse animation (runs only when bot is STARTed) --- */
#ah-pulse{
  position:absolute;
  right:12px;
  top:22px;
  width:220px;
  height:64px;
  opacity:0;
  transform:translateY(-2px) scale(1.05);
  transition:opacity .18s ease;
  pointer-events:none;
  mix-blend-mode:screen;
}
#ah-modal.ah-running #ah-pulse{opacity:.95;}
#ah-pulse svg{width:100%;height:100%;overflow:visible}
#ah-pulse .pulse-line{
  fill:none;
  stroke:rgba(0,255,210,.92);
  stroke-width:3.2;
  stroke-linecap:round;
  stroke-linejoin:round;
  filter:drop-shadow(0 0 2px rgba(0,255,210,.55)) drop-shadow(0 0 10px rgba(0,255,210,.22));
}
#ah-pulse .pulse-glow{
  fill:none;
  stroke:rgba(0,255,210,.55);
  stroke-width:7.5;
  stroke-linecap:round;
  stroke-linejoin:round;
  filter:blur(1.2px);
  opacity:.65;
}
#ah-pulse .pulse-dot{
  width:6px;height:6px;
  background:rgba(240,255,255,.95);
  border-radius:999px;
  position:absolute;
  left:0;top:0;
  box-shadow:0 0 6px rgba(0,255,210,.55), 0 0 18px rgba(0,255,210,.30);
  offset-path:path("M 6 38 L 56 38 L 68 14 L 80 58 L 92 38 L 124 38 L 136 12 L 148 60 L 160 38 L 214 38");
  offset-rotate:0deg;
  animation:ahPulseDot 1.55s linear infinite;
}
#ah-modal:not(.ah-running) #ah-pulse .pulse-dot{animation:none;}
#ah-pulse .pulse-trace{
  fill:none;
  stroke:rgba(240,255,255,.95);
  stroke-width:4.4;
  stroke-linecap:round;
  stroke-linejoin:round;
  filter:drop-shadow(0 0 2px rgba(0,255,210,.65)) drop-shadow(0 0 12px rgba(0,255,210,.28));
  stroke-dasharray:70 420;
  stroke-dashoffset:420;
  animation:ahPulseTrace 1.55s linear infinite;
}
#ah-modal:not(.ah-running) #ah-pulse .pulse-trace{animation:none;}
@keyframes ahPulseTrace{
  0%{stroke-dashoffset:420;opacity:0;}
  6%{opacity:1;}
  90%{opacity:1;}
  100%{stroke-dashoffset:0;opacity:0;}
}
@keyframes ahPulseDot{
  0%{offset-distance:0%;opacity:0;}
  6%{opacity:1;}
  100%{offset-distance:100%;opacity:0;}
}
`),chrome.storage.local.get("ahAutoBackup",(e=>{e.ahAutoBackup&&chrome.runtime.sendMessage({cmd:"toggleAutoBackup",enable:!0})}));let ui={};function show(e){ui.res.textContent=e}function validateKey(e){const t=/^[A-Za-z0-9]{16}$/.test(e.value);e.style.borderColor=t?"#ccc":"#f33",ui.ok.disabled=!t}function fmtExp(e){if(e>=86400){const t=Math.floor(e/86400);return`${t} day${1!==t?"s":""}`}if(e>=3600){const t=Math.ceil(e/3600);return`${t} hour${1!==t?"s":""}`}return`${Math.max(1,Math.ceil(e/60))} min`}function updateHeaderExp(){const e=$("#ah-modal h2"),t=loadSet(),n=AH_BASE,o=t.operatorId?`${n} • ID${t.operatorId}`:n,a=getExpSecMem();e&&(e.textContent=a>0?`${o}  •  Exp ${fmtExp(a)}`:o);const c=byId("ah-exp"),pExp=byId("ah-exp-val");c&&(c.style.display=t.authKey?"flex":"none",pExp&&(pExp.textContent=a>0?"EXP "+fmtExp(a):t.authKey&&0===a?"EXP UNLIMITED":"EXP —"));const i=byId("ah-opid"),r=byId("ah-opid-val"),s=byId("ah-op-email");function l(){if(!i)return;if(t.operatorId){i.style.display="block";r?r.textContent=`OP ID: ${t.operatorId}`:i.textContent=`OP ID: ${t.operatorId}`;if(s){s.textContent=ahOperatorEmail?` • ${ahOperatorEmail}`:"";s.style.display=ahOperatorEmail?"inline":"none"}}else{i.style.display="none";r&&(r.textContent="");s&&(s.textContent="",s.style.display="none")}}l(),window.renderOpIdEmail=l}let ahActTotal=0;function ahCalcTotalActions(e){let t=0;if(!e||"object"!=typeof e)return 0;for(const n of Object.values(e||{}))"number"==typeof n&&Number.isFinite(n)&&(t+=n);return t}function ahRenderActCounter(e){const t=byId("ah-act-val"),n=byId("ah-act-counter");if(!t)return;const o=ahActTotal;ahActTotal=Number(e)||0;const a=String(ahActTotal),i=a.length<6?a.padStart(6,"0"):a;t.textContent=i,n&&ahActTotal!==o&&(n.classList.remove("ah-bump"),void n.offsetWidth,n.classList.add("ah-bump"))}async function getStatsDaily(){return await new Promise((r=>{try{chrome.runtime.sendMessage({cmd:"getStatsDaily"},(e=>{if(chrome.runtime.lastError||!e||!e.ok)return r({});r(e.stats&&"object"==typeof e.stats?e.stats:{});}))}catch{return r({})}}))}
function calcSender2Total(e){if(!e||"object"!=typeof e)return 0;const t=Number(e.total_actions);if(Number.isFinite(t))return t;let n=0;for(const k of ["sent_chat","sent_mail","sent_media","sent_like"]) {const v=Number(e[k]);Number.isFinite(v)&&(n+=v)}return n}
function updateActionCounter(){getStatsDaily().then((e=>{ahRenderActCounter(calcSender2Total(e))})).catch((()=>ahRenderActCounter(0)))}
let ahBalanceRec=null;
function ahFmtMoney(v){
  const n=Number(v);
  if(!Number.isFinite(n)) return "—";
  return n.toFixed(2);
}
function ahRenderBalance(rec){
  const el=byId("ah-bal-val");
  if(!el) return;
  const t=rec&&typeof rec==="object"?rec:{};
  const today=("today" in t)?ahFmtMoney(t.today):"—";
  const total=("total" in t)?ahFmtMoney(t.total):"—";
  el.textContent=`${today} / ${total}`;
}
function updateBalance(){
  try{chrome.storage.local.get("ahBalance",(e=>{ahRenderBalance(e.ahBalance||null)}))}catch{ahRenderBalance(null)}
}
try{chrome.storage.onChanged.addListener(((e,t)=>{"local"===t&&e.ahBalance&&ahRenderBalance(e.ahBalance.newValue||null)}))}catch(e){}
function ensurePulseRoot(){
  let e=byId("pulse-root");
  e||(e=elt("div",{id:"pulse-root",className:"notranslate",translate:"no",lang:"en"}),e.style.position="fixed",e.style.inset="0",e.style.zIndex="2147483646",e.style.pointerEvents="none",e.style.isolation="isolate",document.body.appendChild(e));
  const t=e.shadowRoot||e.attachShadow({mode:"open"});
  if(!t.getElementById("pulse-shadow-base")){
    const e=document.createElement("style");
    e.id="pulse-shadow-base";
    e.textContent=":host{all:initial}*,*::before,*::after{box-sizing:border-box;}";
    t.appendChild(e);
    for(const e of AH_CSS_TEXTS){
      const n=document.createElement("style");
      n.textContent=e,t.appendChild(n);
    }
  }
  let n=t.getElementById("pulse-mount");
  return n||(n=document.createElement("div"),n.id="pulse-mount",n.className="notranslate",n.setAttribute("translate","no"),n.lang="en",n.style.position="fixed",n.style.inset="0",n.style.zIndex="2147483646",n.style.pointerEvents="none",n.style.isolation="isolate",t.appendChild(n)),n;
}
function cleanupPulseRoot(){
  const e=byId("pulse-root"),t=e?.shadowRoot?.getElementById("pulse-mount");
  e&&t&&!t.firstChild&&e.remove();
}
const __AH_SERVER_LOG_BUFFER__=[],AH_SERVER_LOG_STORAGE_KEY="ahServerLogBuffer";let __AH_SERVER_LOG_BUFFER_RESTORE_STARTED__=!1,__AH_SERVER_LOG_BUFFER_RESTORED__=!1,__AH_SERVER_LOG_BUFFER_SAVE_TIMER__=null;function scheduleServerLogBufferSave(){try{__AH_SERVER_LOG_BUFFER_SAVE_TIMER__&&clearTimeout(__AH_SERVER_LOG_BUFFER_SAVE_TIMER__),__AH_SERVER_LOG_BUFFER_SAVE_TIMER__=setTimeout((()=>{__AH_SERVER_LOG_BUFFER_SAVE_TIMER__=null;try{chrome.storage.local.set({[AH_SERVER_LOG_STORAGE_KEY]:__AH_SERVER_LOG_BUFFER__.slice(-300)})}catch{}}),120)}catch{}}function restoreServerLogBuffer(){if(__AH_SERVER_LOG_BUFFER_RESTORE_STARTED__)return;__AH_SERVER_LOG_BUFFER_RESTORE_STARTED__=!0;try{chrome.storage.local.get(AH_SERVER_LOG_STORAGE_KEY,(e=>{const t=e&&e[AH_SERVER_LOG_STORAGE_KEY];Array.isArray(t)&&(__AH_SERVER_LOG_BUFFER__.length=0,__AH_SERVER_LOG_BUFFER__.push(...t.map((e=>String(e||"")).filter(Boolean)).slice(-300))),__AH_SERVER_LOG_BUFFER_RESTORED__=!0,renderServerLogBuffer()}))}catch{__AH_SERVER_LOG_BUFFER_RESTORED__=!0}}function formatServerLogLine(e){try{const t=e&&e.ts?new Date(e.ts):new Date,n=Number.isNaN(t.getTime())?new Date:t,o=String(n.getHours()).padStart(2,"0"),a=String(n.getMinutes()).padStart(2,"0"),i=String(n.getSeconds()).padStart(2,"0"),r=String(e&&e.source||"server").trim()||"server",s=String(e&&e.message||"").replace(/\s+/g," ").trim();return`[${o}:${a}:${i}] [${r}] ${s}`.trim()}catch{return"[--:--:--] [server] log"}}function renderServerLogBuffer(){const e=byId("ah-workers-status");e&&(e.value=__AH_SERVER_LOG_BUFFER__.length?__AH_SERVER_LOG_BUFFER__.join("\n"):"",e.scrollTop=e.scrollHeight)}function clearServerLogBuffer(){__AH_SERVER_LOG_BUFFER__.length=0,scheduleServerLogBufferSave(),renderServerLogBuffer()}function pushServerLogEntry(e){const t=formatServerLogLine(e);__AH_SERVER_LOG_BUFFER__.push(t),__AH_SERVER_LOG_BUFFER__.length>300&&__AH_SERVER_LOG_BUFFER__.splice(0,__AH_SERVER_LOG_BUFFER__.length-300),scheduleServerLogBufferSave(),renderServerLogBuffer()}restoreServerLogBuffer()
async function buildModal(){if(await initAhStore(),$("#ah-overlay"))return;const e=loadSet(),t=!!e.authKey,n=elt("div",{id:"ah-modal",className:"notranslate",translate:"no",lang:"en"},elt("div",{id:"ah-opid",className:"notranslate",translate:"no",style:e.operatorId?"":"display:none"},e.operatorId?elt("span",{id:"ah-opid-val"},`OP ID: ${e.operatorId}`):"",elt("span",{id:"ah-op-email",style:"margin-left:8px;font-weight:600;opacity:.75;display:none;"},"")),elt("div",{id:"ah-act-counter",className:"notranslate",translate:"no",lang:"en",style:t?"":"display:none"},elt("span",{id:"ah-act-val"},"000000")),elt("div",{id:"ah-balance",className:"notranslate",translate:"no",lang:"en",style:t?"":"display:none"},elt("span",{id:"ah-bal-val"},"— / —")),elt("div",{id:"ah-exp",className:"notranslate",translate:"no",lang:"en",style:t?"":"display:none"},elt("span",{id:"ah-exp-val"},"EXP —")),elt("button",{id:"ah-help",className:"ah-hdr",title:"Modules",onclick:()=>window.open("https://site.pulsarcloud.net/modules","_blank","noopener,noreferrer")},elt("span",{},"?")),elt("button",{id:"ah-info",className:"ah-hdr",title:"Импорт / Экспорт",onclick:openStarMenu},elt("span",{},"★")),elt("button",{id:"ah-close",className:"ah-hdr",onclick:closeModal},elt("span",{},"×")),elt("h2",{className:"notranslate",translate:"no"},e.operatorId?`${AH_BASE} • ${e.operatorId}`:AH_BASE),elt("div",{className:"pulse-brand notranslate",translate:"no"},elt("img",{src:chrome.runtime.getURL("pulse_logo.png"),alt:"Pulse",draggable:false}),elt("div",{id:"ah-pulse"},elt("svg",{viewBox:"0 0 220 76",xmlns:"http://www.w3.org/2000/svg"},elt("path",{className:"pulse-glow",d:"M 6 38 L 56 38 L 68 14 L 80 58 L 92 38 L 124 38 L 136 12 L 148 60 L 160 38 L 214 38"}),elt("path",{className:"pulse-line",d:"M 6 38 L 56 38 L 68 14 L 80 58 L 92 38 L 124 38 L 136 12 L 148 60 L 160 38 L 214 38"}),elt("path",{className:"pulse-trace",d:"M 6 38 L 56 38 L 68 14 L 80 58 L 92 38 L 124 38 L 136 12 L 148 60 L 160 38 L 214 38"})),elt("div",{className:"pulse-dot"}))),...t?[]:[elt("div",{id:"ah-form",autocomplete:"off"},elt("input",{id:"ah-key",autocomplete:"off",placeholder:"Введите 16-символьный ключ",maxlength:16,oninput:e=>{e.target.value=e.target.value.replace(/[^A-Za-z0-9]/g,"").slice(0,16),validateKey(e.target)}}),elt("button",{id:"ah-send",disabled:!0,onclick:sendCmd},"OK")),elt("pre",{id:"ah-res"})]);const o=elt("div",{id:"ah-overlay",className:"notranslate",translate:"no",lang:"en"},n);o.style.pointerEvents="auto",ensurePulseRoot().append(o),updateActionCounter(),updateBalance(),t?expandModal():(ui={key:$("#ah-key"),ok:$("#ah-send"),res:$("#ah-res")},validateKey(ui.key))}async function sendCmd(){ui.ok.disabled=!0,show("…подождите…");const e=ui.key.value.trim(),t=(await sha1(e)).slice(0,16),n=Promise.race([chrome.runtime.sendMessage({cmd:"postHelper",key:t,jwt:localStorage.getItem("token")||""}),new Promise(((e,t)=>setTimeout((()=>t(new Error("Timeout (5 s)"))),5e3)))]);try{const e=await n;if(e.error)return show("Ошибка: "+e.error),void(ui.ok.disabled=!1);if(!1===e.origin)return show("Ошибка: пакет заблокирован Cloudflare"),void(ui.ok.disabled=!1);let o={};try{o=JSON.parse(e.body||"{}")}catch{}o.msg&&show(o.msg),"string"==typeof o.endpoint&&chrome.runtime.sendMessage({cmd:"saveEndpoint",ep:o.endpoint}),"number"==typeof o.exp_sec&&setExpSecMem(o.exp_sec);const a=200===e.status&&!1!==o.status,i=loadSet();if(a){i.operatorId=e.operator_id||null,i.authKey=t,saveSet(i),syncVisualFeatureSettings(i),chrome.runtime.sendMessage({cmd:"setBadge",state:"Stopped"});const n=$("#ah-modal h2");n&&e.operator_id&&(n.textContent=`${AH_BASE} • ${e.operator_id}`),expandModal(),updateHeaderExp(),cleanupAuthUI()}else delete i.authKey,delete i.operatorId,saveSet(i),syncVisualFeatureSettings(i),ui.ok.disabled=!1,o.msg||show("Ошибка: неверный ключ")}catch(e){show("Ошибка: "+e.message),ui.ok.disabled=!1}}function collectAllInvites(){const e={};e.global=CATS.reduce(((e,t)=>(e[t]=loadInv(null)[t]||[],e)),{});const t=AH_STORE.mem.invites||{};return Object.keys(t).filter((e=>"global"!==e)).forEach((t=>{const n=loadInv(t);CATS.every((e=>!(n[e]||[]).length))||(e[t]=CATS.reduce(((e,t)=>(e[t]=n[t]||[],e)),{}))})),e}async function buildPayload(e=!1){await initAhStore();try{const e=await st.get([AH_STORE_KEYS.set,AH_STORE_KEYS.invites,AH_STORE_KEYS.stop,AH_STORE_KEYS.exp]);e[AH_STORE_KEYS.set]&&(AH_STORE.mem.set=e[AH_STORE_KEYS.set]),e[AH_STORE_KEYS.invites]&&(AH_STORE.mem.invites=e[AH_STORE_KEYS.invites]),"string"==typeof e[AH_STORE_KEYS.stop]&&(AH_STORE.mem.stop=e[AH_STORE_KEYS.stop]),Number.isFinite(e[AH_STORE_KEYS.exp])&&(AH_STORE.mem.exp=e[AH_STORE_KEYS.exp])}catch{}migrateTimeToMinutesIfNeeded();const t=loadSet();let n=null;if(!e){const e=(localStorage.getItem("token")||"").trim();if(e)try{const{json:t}=await pageFetchJson("/api/operator/profiles",{method:"GET",headers:{Authorization:"Bearer "+e}});Array.isArray(t)&&t.length&&(n=new Set(t.map((e=>String(e.external_id)))))}catch{}}const o=CATS.reduce(((e,t)=>(e[t]=loadInv(null)[t]||[],e)),{}),a={settings:{timemin:!0,likes:!!t.likes,authorReplyDistance2m:!!t.authorReplyDistance2m,authorReplyLikeFirst:!!t.authorReplyLikeFirst,authorReplyDelaySec:t.authorReplyDelaySec??1,lastLike:!!t.lastlike,factTimeMsg:!!t.facttimemsg,stopMaybe:!!t.stopmaybe,stopSpecial:!!t.stopspecial,persToMaybe:!!t.perstomaybe,persToSpecial:!!t.perstospecial,emptyChatsToFolder:!!t.emptychatstofolder,sendEvery:t.sendEvery??null,mailEvery:t.mailEvery??null,letterDelay:t.letterDelay??null,autoTranslate:!!t.autoTranslate,senderMode:getSenderMode()},invites:o,stopList:(loadStop()||"").replace(/\s+/g," ").trim()},i=AH_STORE.mem.invites||{};Object.keys(i).filter((e=>"global"!==e)).filter((t=>e||!n||n.has(t))).sort(((e,t)=>Number(e)-Number(t))).forEach((e=>{const t=loadInv(e);CATS.every((e=>!(t[e]||[]).length))||(a["invites"+e]=CATS.reduce(((e,n)=>(e[n]=t[n]||[],e)),{}))}));const r=JSON.stringify(a);return{jsonStr:r,hash:await sha1(r)}}async function closeModal(){try{pulseInfoButtonsClose()}catch{}byId("star-menu")?.remove(),stopWorkersStatusLoop();const e=$("#ah-overlay");if(!e)return;const{jsonStr:t,hash:n}=await buildPayload(),o=loadSet();o.running&&o.lastHash!==n&&(chrome.runtime.sendMessage({cmd:"botAction",run:o.running?"Start":"Stop",json:t,hash:n,key:o.authKey,opId:o.operatorId}),o.lastHash=n,saveSet(o)),galleryCache={},e.remove(),cleanupPulseRoot()}function expandModal(){const e=$("#ah-modal");if(!e||$("#ah-tabs"))return;e.style.minWidth=e.style.width="930px",e.style.height="660px";const t=elt("div",{id:"ah-tabs"},...["Main","Auto-reply","Online spy","Block list","Stop List","Reports","Screenshot","Tools"].map(((e,t)=>elt("div",{className:"ah-tab"+(0===t?" ah-active":""),onclick:()=>selectTab(t)},e))));e.insertBefore(t,$("#ah-form")),e.append(elt("div",{id:"ah-body"})),selectTab(0),updateHeaderExp()}function cleanupAuthUI(){$("#ah-form")?.remove(),$("#ah-res")?.remove()}function selectTab(e){stopWorkersStatusLoop(),$$("#ah-tabs .ah-tab").forEach(((t,n)=>t.classList.toggle("ah-active",n===e)));const t=$("#ah-body");try{t&&"function"==typeof t.__pulseScreenshotCleanup__&&t.__pulseScreenshotCleanup__()}catch{}t&&(t.__pulseScreenshotCleanup__=null,t.style.overflow="auto"),t.innerHTML="",0===e&&renderMain(t),1===e&&renderInvites(t),2===e&&window.renderOnlineSpyPulse&&window.renderOnlineSpyPulse(t),3===e&&renderBlockList(t),4===e&&renderStopList(t),5===e&&renderReports(t),6===e&&renderScreenshot(t),7===e&&renderTools(t),setTimeout((()=>{try{pulseInfoButtonsRenderAll()}catch{}}),0)}const PULSE_INFO_BUTTONS=[{"tab":0,"title":"Поддерживать активность","text":"Мягкая альтернатива рефрешеру без лишних перезагрузок.\n\nАнкеты будут оставаться на месте, даже если вы переключились на другие задачи: нарезку видео, письмо или что-то ещё.\n\nДостаточно, чтобы браузер был открыт, а вкладка с Альфой оставалась загруженной.","xPct":"31.183","yPct":"35.587"},{"tab":0,"title":"Игнорировать персоналов","text":"Если опция включена, бот не берёт в работу дедов, которые сейчас находятся в wait-list.\n\nПока в wait-list остаётся хотя бы один незакрытый коннект с этим id, такой дед будет игнорироваться в шансах по всем анкетам.\n\nКогда вы закроете последний коннект в wait-list, бот подождёт время из настройки «Частота рассылки» и только потом снова сможет отправлять по этому деду.","xPct":"37.204","yPct":"40.739"},{"tab":0,"title":"Игнорировать Maybe","text":"Шансы, добавленные в выбранную папку, будут полностью игнорироваться.\n\nМожно выбрать одну папку или сразу обе.\n\nПосле этого бот не будет брать такие шансы в работу.","xPct":"32.473","yPct":"46.648"},{"tab":0,"title":"Игнорировать Special","text":"Шансы, добавленные в выбранную папку, будут полностью игнорироваться.\n\nМожно выбрать одну папку или сразу обе.\n\nПосле этого бот не будет брать такие шансы в работу.","xPct":"80.968","yPct":"47.405"},{"tab":0,"title":"Добавлять в Maybe \\ Special","text":"Если бот найдёт в шансах деда, который уже есть в wait-list персоналов, он перенесёт такой чат в папку, выбранную в настройках.\n\nЭто помогает автоматически убирать из работы шансы, которые лучше не трогать вручную.\n\nПапку для переноса можно указать в соответствующей настройке.","xPct":"83.333","yPct":"35.587"},{"tab":0,"title":"Добавлять в  Maybe \\ Special","text":"Только чистые чаты\n\nЕсли бот найдёт в шансах деда, который уже есть в wait-list персоналов, он перенесёт такой чат в папку, выбранную в настройках.\n\nЭто помогает автоматически убирать из работы шансы, которые лучше не трогать вручную.\n\nПапку для переноса можно указать в соответствующей настройке.","xPct":"94.086","yPct":"40.587"},{"tab":0,"title":"Частота рассылки","text":"Здесь задаётся интервал, через который бот будет дописывать следующий инвайт в конкретный чат из шансов.\nЧем меньше значение, тем чаще бот будет возвращаться к этому чату.\nМинимальное значение — 10 минут.\nЧтобы временно отключить рассылку для чатов, укажите 0.","xPct":"88.710","yPct":"57.860"},{"tab":0,"title":"Частота писем","text":"Здесь задаётся интервал, через который бот будет дописывать следующее письмо в конкретный чат из шансов.\nНастраивайте интервал под свой стиль работы и количество писем за смену с одной анкеты.\nМинимальное значение — 10 минут.\nЧтобы временно отключить письма, укажите 0.","xPct":"88.710","yPct":"57.860"},{"tab":0,"title":"Режим работы шанс бота","text":"Lite режим. \nПозволяет более точно выбирать инвайты и леттер для рассылки. Включаете рабочие профили в рассылку, выбираете инвайт (или несколько инвайтов/леттер) для рассылки на сайте и запускает их в работу. Если инвайтов/леттер выбрано несколько, выберет самый новый затем через интервал времени возьмет следующий текст и будет отправлять его.\nВАЖНО!!! СНАЧАЛА ВЫБИРАЕМ ТЕКСТ, ПОТОМ ЗАПУСКАЕМ БОТ!!!\n\nHard режим.\nВключаем рабочие профили в работу и просто нажимаем START в боте.\nБот сам включит самые свежие инвайты для рассылки и сам будет их менять через интервалы. ДЛЯ РАБОТЫ БУДУТ ИСПОЛЬЗОВАТЬСЯ ВСЕ ИНВАЙТЫ И ЛЕТТЕР ПОДГОТОВЛЕННЫЕ ВАМИ ЗАРАНЕЕ.\nТак же , если в ходе рассылки дед уже получил инвайт который уже стоит в очереди, бот сам подберет из вашего списка актуальный инвайт который дед еще не получал и отправит его!","xPct":"20.430","yPct":"56.648"},{"tab":1,"title":"Сналача лайк","text":"Перед ответом лайк будет отправлен впервую очередь, если доступен.","xPct":"22.258","yPct":"34.527"},{"tab":1,"title":"Дистанция 2 минуты","text":"Если после последнего ответа\\инвайта прошло меньше 2 минут, автоответчик будет игнорировать деда и не будет отвечать. ","xPct":"40.000","yPct":"34.678"},{"tab":1,"title":"Задержка","text":"Можно настроить в секундах через какое время бот ответит на минк\\лайк кандидата (в секундах)","xPct":"71.720","yPct":"39.375"},{"tab":1,"title":"Автоответчик","text":"Если опция выключена, красные чаты в шансах будут просто игнорироваться.\n\nЕсли опция включена, лайки и винки будут закрываться специальными инвайтами, которые вы укажете в настройках.","xPct":"6.989","yPct":"33.769"},{"tab":2,"title":"Отслеживание онлайн статуса деда","text":"Вводите Id деда в поле, сохраняете. включаеье флаг Трекинга и когда ваш клиент появится в сети, вы увидите уведомление в правом верхнем углу экрана (там же можно перейти в чат с ним) И есть опция звукового уведомления. ","xPct":"74.409","yPct":"36.799"},{"tab":3,"title":"Блок лист","text":"Выбираете анкету и получаете список клиентов которые ее заблокировали. Клиента можно найти по Id или по дате поиска. Так же можно перейти в чат с ним .","xPct":"37.204","yPct":"35.284"},{"tab":4,"title":"Стоп лист","text":"Добавляем Ид клиента, бот ему не пишет и не отвечает. Полный игнор.","xPct":"90.430","yPct":"86.345"},{"tab":5,"title":"ОТЧЕТЫ","text":"Здесь ваши отчеты по супер-пупер важным клиентам","xPct":"18.817","yPct":"38.314"},{"tab":6,"title":"Скриншот","text":"Вставляем скриншот, редактируем его, сохраняем и отправляем деду. Все просто","xPct":"88.925","yPct":"37.860"},{"tab":7,"title":"Инструкция","text":"Сразу переводит текст при вводе","xPct":"32.258","yPct":"35.284"},{"tab":7,"title":"Инструкция","text":"Переводит сообщения в чате и в леттер.","xPct":"31.828","yPct":"41.193"},{"tab":7,"title":"Инструкция","text":"Визаульная маркировка клиента (красный, синий, зеленый)\nВАЖНО!При использовании визуала есть доп.нагрузка на сайт","xPct":"23.118","yPct":"46.496"},{"tab":7,"title":"Инструкция","text":"Показывает рядом с карточкой клиента его лимит на чат и леттер (чат10\\леттер2)","xPct":"23.226","yPct":"52.102"},{"tab":7,"title":"Инструкция","text":"Дает возможность увидеть прямо в чате затраты деда","xPct":"23.656","yPct":"57.557"},{"tab":7,"title":"Инструкция","text":"Обратный таймер для персоналов которых нужно законектить","xPct":"26.129","yPct":"63.314"}];
function pulseInfoButtonsRefreshSoon(){setTimeout((()=>{try{pulseInfoButtonsRenderAll()}catch{}}),0)}function pulseInfoButtonsActiveTab(){const tabs=$$("#ah-tabs .ah-tab");const i=tabs.findIndex(e=>e.classList.contains("ah-active"));return i<0?0:i}
function pulseInfoButtonsClose(){try{$$(".pulse-info-popover").forEach(e=>e.remove())}catch{}}
function pulseInfoButtonsOpen(item,mark){pulseInfoButtonsClose();const r=mark.getBoundingClientRect();const left=Math.min(Math.max(12,r.left),window.innerWidth-360);const top=Math.min(r.bottom+8,window.innerHeight-260);const box=elt("div",{className:"pulse-info-popover notranslate",translate:"no",style:`position:fixed;left:${left}px;top:${top}px;width:330px;max-height:240px;overflow:auto;z-index:2147483647;background:#111827;color:#e5eefb;border:1px solid rgba(59,130,246,.60);border-radius:12px;box-shadow:0 18px 48px rgba(0,0,0,.38);padding:12px;font-family:system-ui,sans-serif;line-height:1.45;white-space:pre-wrap;`});box.append(elt("div",{style:"display:flex;align-items:center;justify-content:space-between;gap:10px;margin-bottom:8px"},elt("div",{style:"font-weight:800;color:#60a5fa"},item.title||"Инструкция"),elt("button",{style:"width:26px;height:26px;padding:0;border-radius:8px;border:1px solid #374151;background:#1f2937;color:#fff;cursor:pointer",onclick:()=>box.remove()},"×")),elt("div",{style:"font-size:13px;color:#dce6f2"},item.text||""));document.body.appendChild(box)}
function pulseInfoButtonsAnchor(item,tab){const title=String(item&&item.title||"").toLowerCase(),text=String(item&&item.text||"").toLowerCase();let sel=null;if(tab===0){if(title.includes("поддерживать"))sel="#ah-activity";else if(title.includes("персоналов")&&title.includes("игнор"))sel="#ah-persons";else if(title.includes("maybe")&&title.includes("игнор"))sel="#ah-stopmaybe";else if(title.includes("special")&&title.includes("игнор"))sel="#ah-stopspecial";else if(title.includes("добавлять")&&text.includes("только чистые"))sel="#ah-perstospecial";else if(title.includes("добавлять"))sel="#ah-perstomaybe";else if(title.includes("частота рассылки"))sel="#pulse-info-anchor-sendEvery";else if(title.includes("частота писем"))sel="#pulse-info-anchor-mailEvery";else if(title.includes("частота"))sel="#pulse-info-anchor-sendEvery";else if(title.includes("режим работы"))sel="#ah-senderModeLite"}else if(tab===1){if(title.includes("сналача")||title.includes("сначала"))sel="#ah-authorReplyLikeFirst";else if(title.includes("дистанция"))sel="#ah-authorReplyDistance2m";else if(title.includes("задерж"))sel="#pulse-info-anchor-authorReplyDelaySec";else if(title.includes("автоответ"))sel="#ah-likes"}else if(tab===2){sel="#ah-online-enabled,#online-tracking-enabled,[data-pulse-info='online-tracking']"}else if(tab===3){sel="#bl-profile-select"}else if(tab===4){sel="#ah-stop-input"}else if(tab===5){sel="#ah-body"}else if(tab===6){sel="#pulse-info-anchor-screenshot"}else if(tab===7){if(text.includes("при вводе"))sel="#ah-autoTranslate";else if(text.includes("страницы")||text.includes("чате и в леттер"))sel="#ah-pageChatTranslate";else if(text.includes("рамоч")||text.includes("визуаль")||text.includes("маркировка"))sel="#ah-frameEnabled";else if(text.includes("лимит"))sel="#ah-chatLimitsEnabled";else if(text.includes("затраты"))sel="#ah-chatBalanceEnabled";else if(text.includes("таймер"))sel="#ah-personalTimerEnabled"}let target=sel?$(sel):null;if(!target&&tab===2){target=Array.from($$("#ah-body label")).find(e=>/Tracking enabled/i.test(e.textContent||""))||null}if(!target&&tab===5)target=$("#ah-body");return target}function pulseInfoButtonsHost(target){if(!target)return null;if(target.matches&&target.matches("input[type='checkbox']")){const label=target.closest("label");if(label){const spans=[...label.querySelectorAll("span")].filter(e=>!e.classList.contains("switch")&&!e.classList.contains("slider"));return spans[spans.length-1]||label}return target.parentElement}if(target.id&&target.id.startsWith("pulse-info-anchor-")){return target.firstElementChild||target}if(target.matches&&target.matches("select,input,textarea,button"))return target.parentElement||target;return target}function pulseInfoButtonsRenderAll(){const modal=$("#ah-modal");if(!modal)return;try{$$(".pulse-info-mark,.pulse-info-popover,.pulse-info-builder-mark,.pulse-info-builder-editor").forEach(e=>e.remove())}catch{}const tab=pulseInfoButtonsActiveTab();PULSE_INFO_BUTTONS.filter(e=>(e.tab??0)===tab).forEach(item=>{const target=pulseInfoButtonsAnchor(item,tab),host=pulseInfoButtonsHost(target);if(!host)return;const m=elt("button",{className:"pulse-info-mark notranslate",translate:"no",title:item.title||"Инструкция",style:"display:inline-flex;align-items:center;justify-content:center;flex:0 0 auto;margin-left:5px;vertical-align:middle;width:14px;height:14px;border-radius:50%;border:1px solid rgba(148,163,184,.55);background:rgba(15,23,42,.35);color:rgba(203,213,225,.78);font-weight:700;font-size:10px;line-height:12px;text-align:center;z-index:9999;box-shadow:none;cursor:pointer;padding:0;position:relative;top:-1px;opacity:.72;",onclick:e=>{e.preventDefault();e.stopPropagation();pulseInfoButtonsOpen(item,m)}} ,"?");host.appendChild(m)})}
function makeSwitch(e,t,n=!1,o="",a=null,i={}){const r=loadSet(),s=e.replace("ah-","");s in r||(r[s]=n,saveSet(r));const l=i&&"danger"===i.variant?" ah-switch-danger":"";return elt("label",{style:`display:flex;align-items:center;gap:12px;
             font-size:14px;${o}`},elt("span",{className:`switch${l}`},elt("input",{type:"checkbox",id:e,checked:r[s],onchange:e=>{const t=loadSet();t[s]=e.target.checked,saveSet(t),"activity"===s&&ahSyncActivityLoop(),"function"==typeof a&&a(!!e.target.checked,t)}}),elt("span",{className:"slider"})),elt("span",{},t))}
function getSenderMode(){return loadSet().senderModeLite?"lite":"hard"}
function setSenderMode(e){const t=loadSet();t.senderModeLite="lite"===e,saveSet(t);return t}
function countEnabledItems(e){const t=Array.isArray(e)?e:[];const n=t.filter((e=>{if(!e||"object"!=typeof e)return!0;for(const t of["enabled","is_enabled","active","is_active","checked","selected","use","in_use"])if(t in e){const n=e[t],o=String(n).trim().toLowerCase();return!1!==n&&0!==n&&"0"!==o&&"false"!==o&&"off"!==o&&"disabled"!==o&&"inactive"!==o}if("status" in e){const t=String(e.status).trim().toLowerCase();return["1","true","enabled","enable","active","on","work","working"].includes(t)}return!0})).length;return{enabled:n,total:t.length}}
async function getPulseBaseHost(){try{const e=await st.get(["ahBaseHost"]),t=String(e&&e.ahBaseHost||"").trim();if(t){if(/^https?:\/\/(localhost|127\.0\.0\.1)(:\d+)?\/?$/i.test(t))return"https://pulsarcloud.net/";return t.endsWith("/")?t:t+"/"}}catch{}return"https://pulsarcloud.net/"}function getPulseOperatorId(){try{const e=loadSet(),t=String(e&&e.operatorId||"").trim();if(t)return t}catch{}try{const e=String(localStorage.getItem("operatorId")||"").trim();if(e)return e}catch{}return""}async function fetchRelevantServerLogLines(){const e=getPulseOperatorId();if(!e)throw new Error("operatorId not found");const t=await getPulseBaseHost();const n=await chrome.runtime.sendMessage({cmd:"getAdminLogs",baseHost:t,operatorId:e,limit:400});if(!n||!n.ok)throw new Error(n&&n.error?n.error:`HTTP ${n&&n.status||0}`);const o=n&&n.json||{},a=Array.isArray(o?.items)?o.items:[];return a.map((e=>String(e&&e.line||"").trim())).filter(Boolean).slice(-120)}async function fetchSenderModeProfilesFromPulse(){const e=await getPulseBaseHost(),t=new URL("api/pulse/workers-status",e).toString(),n=await fetch(t,{method:"GET",cache:"no-store"});if(!n.ok)throw new Error(`HTTP ${n.status}`);const o=await n.json(),a=Array.isArray(o?.rows)?o.rows:[];return a.map((e=>({externalId:String(e?.external_id||e?.profile_id||"").trim()||null,name:String(e?.name||e?.external_id||e?.profile_id||"NoName").trim()||"NoName",letters:{enabled:Number(e?.lettr_current||0)||0,total:Number(e?.lettr_max||0)||0},invites:{enabled:Number(e?.inv_current||0)||0,total:Number(e?.inv_max||0)||0},updatedAt:Number(e?.updated_at||0)||0}))).sort(((e,t)=>String(e?.name||"").localeCompare(String(t?.name||""),void 0,{sensitivity:"base"})))}async function fetchSenderModeProfilesFromSite(){const e=(localStorage.getItem("token")||"").trim();if(!e)throw new Error("JWT not found");const t={Authorization:"Bearer "+e,authorization:"Bearer "+e},n=await pageFetchJson("/api/operator/profiles",{method:"GET",headers:t}),o=Array.isArray(n?.json)?n.json:[],a=[];for(const n of o){const o=String(n?.external_id||"").trim();if(!o)continue;let i=[],r=[];try{const e=await pageFetchJson(`/api/sender/inviteList?external_id=${encodeURIComponent(o)}&mail_type=Chat`,{method:"GET",headers:t});i=Array.isArray(e?.json)?e.json:[]}catch{}try{const e=await pageFetchJson(`/api/sender/inviteList?external_id=${encodeURIComponent(o)}&mail_type=Mail`,{method:"GET",headers:t});r=Array.isArray(e?.json)?e.json:[]}catch{}a.push({externalId:o,name:String(n?.name||`Profile ${o}`),letters:countEnabledItems(r),invites:countEnabledItems(i)})}return a}async function fetchSenderModeProfiles(){try{const e=await fetchRelevantServerLogLines();return{mode:"logs",rows:e}}catch(e){console.warn("[Pulse] admin logs fetch failed",e)}try{const e=await fetchSenderModeProfilesFromPulse();if(e.length)return{mode:"profiles",rows:e}}catch(e){console.warn("[Pulse] workers-status fetch failed",e)}const e=await fetchSenderModeProfilesFromSite();return{mode:"profiles",rows:e}}
let ahWorkersStatusLoop=0;
function stopWorkersStatusLoop(){ahWorkersStatusLoop&&(clearTimeout(ahWorkersStatusLoop),ahWorkersStatusLoop=0)}
function formatWorkersStatusRows(e,t="profiles"){if("logs"===t){const t=Array.isArray(e)?e:[];return t.length?t.join("\n"):"No logs yet..."}const n=Array.isArray(e)?e:[];return n.length?n.map((e=>`${String(e?.name||"NoName").trim()||"NoName"}  Inv ${Number(e?.invites?.enabled||0)}/${Number(e?.invites?.total||0)}  Lettr ${Number(e?.letters?.enabled||0)}/${Number(e?.letters?.total||0)}`)).join("\n"):"No active workers yet..."}
async function renderSenderModeProfiles(e){const t=e&&e.querySelector?e.querySelector("#ah-workers-status"):null;if(!t)return;const n=t.scrollHeight-t.scrollTop-t.clientHeight<24;try{t.value="Loading...";const e=await fetchSenderModeProfiles(),o=e&&Array.isArray(e.rows)?e.rows:[],a=e&&e.mode||"profiles";t.value=formatWorkersStatusRows(o,a),n&&(t.scrollTop=t.scrollHeight)}catch(e){t.value=`Failed to load workers status${e&&e.message?`: ${e.message}`:""}`}}
function startWorkersStatusLoop(e){stopWorkersStatusLoop();const t=async()=>{const n=e&&e.isConnected&&document.body.contains(e);if(!n)return void stopWorkersStatusLoop();await renderSenderModeProfiles(e),ahWorkersStatusLoop=setTimeout(t,5e3)};t()}
function renderTools(e){let t=null,n=null,o=null,a=null,i=null,r=null,s="",l="",c=null;const p=/^https:\/\/alpha\.date\/(?:chance|chat)\/([a-z0-9-]+)$/i.exec(location.href);if(!p)return;const d=elt("div",{style:"padding:10px;font-size:14px;color:#999"},"Загрузка…");e.append(d);const m=p[1],u=localStorage.getItem("token")||"";if(!u)return d.textContent="Не найден JWT-токен. Перезайдите на сайт.",void(d.style.color="#d32f2f");const h={Accept:"application/json, text/plain, */*","Content-Type":"application/json",Authorization:"Bearer "+u};const chatId=m;const FIRST_MAX_PAGES=200;const FIRST_REAL_TYPES=new Set(["SENT_TEXT","SENT_IMAGE","SENT_VIDEO","SENT_GIF","SENT_STICKER","SENT_AUDIO","SENT_VOICE","SENT_FILE"]);const firstNonEmpty=v=>String(v||"").trim().length>0;const firstTs=o=>Date.parse(o?.date_created||o?.created_at||0)||0;function normalizeFirstText(s){let t=String(s||"").replace(/\s+/g," ").trim();return t.length>300?t.slice(0,300).trimEnd()+"…":t}async function fetchFirstClientRealMessage(){const all=[];for(let page=1;page<=FIRST_MAX_PAGES;page++){const {json}=await pageFetchJson("/api/chatList/chatHistory",{method:"POST",headers:h,body:JSON.stringify({chat_id:chatId,page})});const arr=Array.isArray(json?.response)?json.response:[];if(!arr.length)break;all.push(...arr)}if(!all.length)return null;const clientReal=all.filter(m=>Number(m?.is_male)===1).filter(m=>FIRST_REAL_TYPES.has(String(m?.message_type||"").trim())).filter(m=>{if(String(m?.message_type||"").trim()==="SENT_TEXT")return firstNonEmpty(m?.message_content);return firstNonEmpty(m?.filename)||firstNonEmpty(m?.file_name)||firstNonEmpty(m?.message_content)}).sort((a,b)=>firstTs(a)-firstTs(b));return clientReal.length?clientReal[0]:null}function extractMails(js){if(Array.isArray(js?.response?.mails))return js.response.mails;if(Array.isArray(js?.response?.mails?.data))return js.response.mails.data;if(Array.isArray(js?.response))return js.response;return []}function getMailDateStr(item){const m=item?.mail||item;return m?.ma_date_created||m?.date_created||m?.created_at||m?.date||null}function getMailDateMs(item){const s=getMailDateStr(item);const ms=s?Date.parse(s):NaN;return Number.isFinite(ms)?ms:NaN}function isMailFromClient(item,maleExt){const m=item?.mail||item;if(Number(m?.is_male)===1)return!0;const sid=m?.sender_external_id??m?.sender_id??m?.sender_internal_id??m?.from_id??m?.man_id??null;return Number(sid)==Number(maleExt)}async function fetchFirstClientLetterDate(maleExt,femaleExt){const all=[];for(let page=1;page<=200;page++){const {json}=await pageFetchJson("/api/mailbox/mails",{method:"POST",headers:h,body:JSON.stringify({user_id:femaleExt,man_id:maleExt,folder:"dialog",page})});if(!json||json.status===!1)break;const items=extractMails(json);if(!items.length)break;all.push(...items)}const fromClient=all.filter(it=>isMailFromClient(it,maleExt)).filter(it=>Number.isFinite(getMailDateMs(it)));if(!fromClient.length)return null;fromClient.sort((a,b)=>getMailDateMs(a)-getMailDateMs(b));return getMailDateStr(fromClient[0])||null}async function f(e){const o="chat"===e?i:c,a="chat"===e?c:i,p="chat"===e?"ahChatStop":"ahMailStop";if(!o.textContent.startsWith("Скачать"))return void(window[p]=!0);window[p]=!1,o.textContent="Стоп",o.style.background="#d32f2f",a.disabled=!0,a.style.opacity=.5;const d=r.value,u=d?Date.parse(d):-1/0,f=e=>Date.parse(e.date_created||e.created_at||0),g=(e,t)=>{if(e.startsWith("https://alpha.date/")){return pageFetchJson(e.replace("https://alpha.date",""),{method:"POST",headers:h,body:JSON.stringify(t)}).then((({json:e})=>e))}return fetch(e,{method:"POST",headers:h,credentials:"include",body:JSON.stringify(t)}).then((e=>e.json()))};if("chat"===e){const e=[],t=e=>g("https://alpha.date/api/chatList/chatHistory",{chat_id:m,page:e});for(let n=1;!ahChatStop;n+=2){const[o,a]=await Promise.allSettled([t(n),t(n+1)]);let i=!1,r=1/0;for(const t of[o,a])if("fulfilled"===t.status&&t.value.status){const n=t.value.response||[];i||=20===n.length;for(const t of n){const n=f(t);r=Math.min(r,n),"SENT_TEXT"===t.message_type&&(t.message_content?.trim()&&(n<u||e.push(t)))}}if(r<u||!i)break}e.sort(((e,t)=>f(e)-f(t)));const n=e.map((e=>`${e.is_male?s:l||"Someone"}\n  ${new Date(f(e)).toLocaleString()}\n  ${e.message_content.trim()}\n  \n  `));return x(n,`chat_${m}.txt`)}if("letters"===e){if(!t||!n)return alert("Профили ещё не определились; попробуйте через пару секунд."),y();const e=e=>g("https://alpha.date/api/mailbox/mails",{user_id:n,folder:"dialog",man_id:t,page:e}),o=await e(1);if(!o.status)return y();const a=o.response.pages||1,i=[...o.response.mails];for(let t=2;t<=a&&!ahMailStop;t+=2){const[n,o]=await Promise.allSettled([e(t),e(t+1)]);for(const e of[n,o])"fulfilled"===e.status&&e.value.status&&i.push(...e.value.response.mails);if(i.at(-1)&&f(i.at(-1).mail)<u)break}const r=i.map((e=>e.mail)).filter((e=>f(e)>=u)).sort(((e,t)=>f(e)-f(t))).map((e=>`${`${e.sender_name}, ${e.sender_age}`}\n${new Date(f(e)).toLocaleString()}\n${e.message_content?.trim()||"[-без текста-]"}\n`));return x(r,`letters_${n}_${t}.txt`)}function x(e,t){if(y(),!e.length)return void alert("Ничего не найдено.");const n=new Blob([e.join("\n")],{type:"text/plain;charset=utf-8"}),o=URL.createObjectURL(n);Object.assign(document.createElement("a"),{href:o,download:t}).click(),setTimeout((()=>URL.revokeObjectURL(o)),800)}function y(){ahChatStop=ahMailStop=!1,i.textContent="Скачать чат",i.style.background="rgba(0,122,255,.18)",i.disabled=!1,i.style.opacity=1,c.textContent="Скачать письма",c.style.background="rgba(0,122,255,.18)",c.disabled=!1,c.style.opacity=1}}pageFetchJson("/api/chatList/chatHistory",{method:"POST",headers:h,body:JSON.stringify({chat_id:m,page:1})}).then((({json:e})=>{if(!e.status||!Array.isArray(e.response))throw new Error("Некорректный ответ history");for(const o of e.response)if(1!==o.is_male||t||(t=o.sender_external_id,n=o.recipient_external_id),0!==o.is_male||n||(n=o.sender_external_id,t=o.recipient_external_id),t&&n)break;return t?Promise.all([pageFetchJson("/api/chatList/userDetail",{method:"POST",headers:h,body:JSON.stringify({chat_uid:[m]})}).then((({json:e})=>e)),pageFetchJson(`/api/operator/myProfile?user_id=${t}&activeProfile=false`,{method:"GET",headers:h}).then((({json:e})=>e))]).then((([e,mp])=>{if(!mp.status||!mp.user_info?.user_detail)throw new Error("Некорректный ответ myProfile");o=mp.user_info.user_detail;const ud=(e&&Array.isArray(e.response)?e.response[0]:null)||{};const si=ud.site_id??ud.man_site_id??ud.male_site_id??ud.site??o.site_id;
const DL_BTN_BG="rgba(0,122,255,.18)",DL_BTN_BD="1px solid rgba(0,122,255,.30)",DL_BTN_TX="#eaf3ff";
const photo=o.photo_link||"https://alpha.date/static/media/profile_img_empty.0b3d6665cd1c1b51de71.jpg";

s=`${o.name}, ${o.age}`,
i=elt("button",{style:`padding:8px 16px;font-size:14px;border:none;border-radius:10px;
                cursor:pointer;background:${DL_BTN_BG};border:${DL_BTN_BD};color:${DL_BTN_TX};width:180px;backdrop-filter:blur(6px) saturate(140%);`,onclick:()=>f("chat")},"Скачать чат"),
c=elt("button",{style:`padding:8px 16px;font-size:14px;border:none;border-radius:10px;
               cursor:pointer;background:${DL_BTN_BG};border:${DL_BTN_BD};color:${DL_BTN_TX};width:180px;backdrop-filter:blur(6px) saturate(140%);`,onclick:()=>f("letters")},"Скачать письма"),
r=elt("input",{type:"datetime-local",id:"ah-history-date",style:"padding:6px;border:1px solid rgba(255,255,255,.12);border-radius:8px;font-size:14px;width:180px;background:rgba(255,255,255,.06);color:#e9eef6"});

const x=elt("label",{style:"font-size:14px;color:#ccc;display:flex;flex-direction:column;gap:4px"},"До даты:",r),
      y=elt("div",{style:"display:flex;flex-direction:column;gap:12px"},i,c,x);

const S=elt("div",{style:"min-height:160px"});

d.innerHTML="",d.style.color="#e9eef6",d.appendChild(S)})):(d.textContent="Не удалось определить ID мужчины.",void(d.style.color="#d32f2f"))})).catch((e=>{d.textContent="Ошибка: "+e.message,d.style.color="#d32f2f"}))}
function renderReports(e){return window.PulseReports&&"function"==typeof window.PulseReports.renderTab?window.PulseReports.renderTab(e):void(e.append(elt("div",{style:"padding:10px;font-size:14px;color:#999"},"Reports loading…")))}

function renderScreenshot(root){
  let cropPct = null;
  let imageReady = false;
  let currentName = 'screenshot';
  let fullscreen = false;
  const baseRootOverflow = root.style.overflow || '';

  const wrap = elt('div', {
    style: 'display:flex;flex-direction:column;gap:12px;padding:10px;color:#e9eef6;height:100%;box-sizing:border-box;outline:none;'
  });
  wrap.tabIndex = 0;
  const wrapBaseStyle = wrap.style.cssText;

  const fileInput = elt('input', {
    type: 'file',
    accept: 'image/*',
    style: 'display:none',
    onchange: (event) => {
      const file = event.target && event.target.files && event.target.files[0];
      if (file) loadFile(file);
      event.target.value = '';
    }
  });

  const quality = elt('input', {
    type: 'range',
    min: '0.5',
    max: '1',
    step: '0.01',
    value: '0.92',
    style: 'width:140px;accent-color:#47d9ff;cursor:pointer;'
  });

  const qualityText = elt('div', {
    style: 'font-size:12px;opacity:.82;min-width:80px;'
  }, 'JPEG 0.92');

  const sizeText = elt('div', {
    style: 'font-size:12px;opacity:.82;min-width:110px;text-align:right;'
  }, '0 × 0');

  quality.addEventListener('input', () => {
    qualityText.textContent = `JPEG ${Number(quality.value).toFixed(2)}`;
  });

  const btnFullscreen = makeShotButton('Fullscreen', toggleFullscreen);

  const top = elt('div', {
    style: 'display:flex;flex-wrap:wrap;gap:10px;align-items:center;'
  },
    makeShotButton('Open', () => fileInput.click()),
    makeShotButton('Reset', resetCrop),
    makeShotButton('Save to Downloads', () => saveJpeg(false)),
    makeShotButton('Save As', () => saveJpeg(true)),
    makeShotButton('Clear', clearImage),
    btnFullscreen,
    qualityText,
    quality,
    sizeText
  );

  const hint = elt('div', {
    id: 'pulse-info-anchor-screenshot',
    style: 'font-size:12px;opacity:.72;line-height:1.45;display:flex;align-items:center;gap:6px;flex-wrap:wrap;'
  }, 'Click the field, press Ctrl+V to paste a screenshot, then drag the frame or pull the handles to crop. Use Fullscreen for easier editing.');

  const stage = elt('div', {
    style: 'position:relative;flex:1;min-height:430px;border:1px solid rgba(255,255,255,.12);border-radius:14px;background:rgba(255,255,255,.04);overflow:hidden;display:flex;align-items:center;justify-content:center;touch-action:none;user-select:none;outline:none;'
  });
  stage.tabIndex = 0;
  stage.title = 'Click here and press Ctrl+V';
  const stageBaseStyle = stage.style.cssText;

  const img = elt('img', {
    style: 'max-width:100%;max-height:100%;display:none;pointer-events:none;user-select:none;-webkit-user-drag:none;'
  });

  const empty = elt('div', {
    style: 'font-size:14px;opacity:.58;text-align:center;line-height:1.6;padding:18px;'
  }, 'Click here and press Ctrl+V', elt('div', { style: 'font-size:12px;opacity:.78;margin-top:6px;' }, 'or use Open'));

  const cropBox = elt('div', {
    style: 'position:absolute;display:none;box-sizing:border-box;border:2px solid #57e3ff;border-radius:4px;box-shadow:0 0 0 9999px rgba(5,10,18,.56);cursor:move;'
  });

  const badge = elt('div', {
    style: 'position:absolute;right:8px;bottom:8px;padding:3px 7px;border-radius:999px;background:rgba(5,10,18,.72);color:#fff;font-size:11px;font-weight:700;pointer-events:none;'
  }, '0 × 0');

  const v1 = elt('div', { style: 'position:absolute;top:0;bottom:0;left:33.3333%;width:1px;background:rgba(255,255,255,.42);pointer-events:none;' });
  const v2 = elt('div', { style: 'position:absolute;top:0;bottom:0;left:66.6666%;width:1px;background:rgba(255,255,255,.42);pointer-events:none;' });
  const h1 = elt('div', { style: 'position:absolute;left:0;right:0;top:33.3333%;height:1px;background:rgba(255,255,255,.42);pointer-events:none;' });
  const h2 = elt('div', { style: 'position:absolute;left:0;right:0;top:66.6666%;height:1px;background:rgba(255,255,255,.42);pointer-events:none;' });
  cropBox.append(v1, v2, h1, h2, badge);

  const handleDefs = {
    nw: 'left:-7px;top:-7px;cursor:nwse-resize;',
    n: 'left:50%;top:-7px;transform:translateX(-50%);cursor:ns-resize;',
    ne: 'right:-7px;top:-7px;cursor:nesw-resize;',
    e: 'right:-7px;top:50%;transform:translateY(-50%);cursor:ew-resize;',
    se: 'right:-7px;bottom:-7px;cursor:nwse-resize;',
    s: 'left:50%;bottom:-7px;transform:translateX(-50%);cursor:ns-resize;',
    sw: 'left:-7px;bottom:-7px;cursor:nesw-resize;',
    w: 'left:-7px;top:50%;transform:translateY(-50%);cursor:ew-resize;'
  };

  Object.entries(handleDefs).forEach(([dir, extraStyle]) => {
    const handle = elt('div', {
      style: `position:absolute;width:14px;height:14px;border-radius:999px;background:#57e3ff;border:2px solid rgba(5,10,18,.86);box-sizing:border-box;${extraStyle}`
    });
    handle.dataset.dir = dir;
    handle.addEventListener('pointerdown', (event) => startDrag(event, 'resize', dir));
    cropBox.append(handle);
  });

  cropBox.addEventListener('pointerdown', (event) => {
    if (event.target && event.target.dataset && event.target.dataset.dir) return;
    startDrag(event, 'move');
  });

  stage.addEventListener('click', () => stage.focus());
  stage.addEventListener('dblclick', () => toggleFullscreen());
  stage.addEventListener('dragover', (event) => {
    event.preventDefault();
  });
  stage.addEventListener('drop', (event) => {
    event.preventDefault();
    stage.focus();
    const files = Array.from((event.dataTransfer && event.dataTransfer.files) || []);
    const imageFile = files.find((file) => file && /^image\//i.test(file.type || ''));
    if (imageFile) loadFile(imageFile);
  });

  stage.append(img, empty, cropBox);
  wrap.append(fileInput, top, hint, stage);
  root.append(wrap);
  root.__pulseScreenshotCleanup__ = () => {
    if (window.__pulseScreenshotActiveEl__ === wrap) window.__pulseScreenshotActiveEl__ = null;
    if (fullscreen) applyFullscreenLayout(false);
    root.style.overflow = baseRootOverflow;
    window.removeEventListener('resize', renderCrop);
  };
  root.style.overflow = baseRootOverflow || 'auto';

  function makeShotButton(label, onclick) {
    return elt('button', {
      type: 'button',
      style: 'padding:8px 12px;border-radius:10px;border:1px solid rgba(255,255,255,.14);background:rgba(255,255,255,.06);color:#e9eef6;font:600 12px system-ui;cursor:pointer;box-shadow:inset 0 0 0 1px rgba(255,255,255,.02);',
      onclick
    }, label);
  }

  function clamp(value, min, max) {
    return Math.max(min, Math.min(max, value));
  }

  function sanitizeFileName(name) {
    const base = String(name || 'screenshot').replace(/\.[^.]+$/, '');
    return base.replace(/[\/:*?"<>|]+/g, '_').replace(/\s+/g, ' ').trim() || 'screenshot';
  }

  function getMetrics() {
    if (!imageReady || !img.naturalWidth || !img.naturalHeight) return null;
    const stageRect = stage.getBoundingClientRect();
    const imgRect = img.getBoundingClientRect();
    if (!imgRect.width || !imgRect.height) return null;
    return {
      left: imgRect.left - stageRect.left,
      top: imgRect.top - stageRect.top,
      width: imgRect.width,
      height: imgRect.height
    };
  }

  function getCropPx(metrics) {
    if (!cropPct || !metrics) return null;
    return {
      x: cropPct.x * metrics.width,
      y: cropPct.y * metrics.height,
      w: cropPct.w * metrics.width,
      h: cropPct.h * metrics.height
    };
  }

  function setCropPx(nextPx, metrics) {
    if (!metrics) return;
    const x = clamp(nextPx.x, 0, metrics.width);
    const y = clamp(nextPx.y, 0, metrics.height);
    const w = clamp(nextPx.w, 1, metrics.width - x);
    const h = clamp(nextPx.h, 1, metrics.height - y);
    cropPct = {
      x: x / metrics.width,
      y: y / metrics.height,
      w: w / metrics.width,
      h: h / metrics.height
    };
  }

  function updateSizeLabels() {
    if (!imageReady || !cropPct) {
      badge.textContent = '0 × 0';
      sizeText.textContent = '0 × 0';
      return;
    }
    const w = Math.max(1, Math.round(cropPct.w * img.naturalWidth));
    const h = Math.max(1, Math.round(cropPct.h * img.naturalHeight));
    const txt = `${w} × ${h}`;
    badge.textContent = txt;
    sizeText.textContent = txt;
  }

  function renderCrop() {
    const metrics = getMetrics();
    const px = getCropPx(metrics);
    if (!metrics || !px) {
      cropBox.style.display = 'none';
      updateSizeLabels();
      return;
    }
    cropBox.style.display = 'block';
    cropBox.style.left = `${metrics.left + px.x}px`;
    cropBox.style.top = `${metrics.top + px.y}px`;
    cropBox.style.width = `${px.w}px`;
    cropBox.style.height = `${px.h}px`;
    updateSizeLabels();
  }

  function resetCrop() {
    const metrics = getMetrics();
    if (!metrics) return;
    cropPct = { x: 0, y: 0, w: 1, h: 1 };
    renderCrop();
  }

  function clearImage() {
    imageReady = false;
    cropPct = null;
    img.removeAttribute('src');
    img.style.display = 'none';
    cropBox.style.display = 'none';
    empty.style.display = '';
    currentName = 'screenshot';
    updateSizeLabels();
    stage.focus();
  }

  function loadFile(file) {
    currentName = sanitizeFileName(file && file.name ? file.name : 'screenshot');
    const reader = new FileReader();
    reader.onload = () => {
      img.onload = () => {
        imageReady = true;
        img.style.display = 'block';
        empty.style.display = 'none';
        requestAnimationFrame(() => {
          resetCrop();
          stage.focus();
        });
      };
      img.src = reader.result;
    };
    reader.readAsDataURL(file);
  }

  function extractImageFromClipboard(event) {
    const items = Array.from((event.clipboardData && event.clipboardData.items) || []);
    for (const item of items) {
      if (item && /^image\//i.test(item.type || '')) {
        const file = item.getAsFile && item.getAsFile();
        if (file) return file;
      }
    }
    return null;
  }

  function handlePaste(event) {
    const file = extractImageFromClipboard(event);
    if (!file) return false;
    event.preventDefault();
    event.stopPropagation();
    loadFile(file);
    return true;
  }

  wrap.__pulseHandleClipboard__ = handlePaste;
  window.__pulseScreenshotActiveEl__ = wrap;
  if (!window.__pulseScreenshotPasteHandler__) {
    window.__pulseScreenshotPasteHandler__ = (event) => {
      const activeWrap = window.__pulseScreenshotActiveEl__;
      if (!activeWrap || !activeWrap.isConnected) return;
      const handler = activeWrap.__pulseHandleClipboard__;
      if (typeof handler === 'function') handler(event);
    };
    document.addEventListener('paste', window.__pulseScreenshotPasteHandler__, true);
  }

  stage.addEventListener('paste', handlePaste, true);
  wrap.addEventListener('paste', handlePaste, true);

  function startDrag(event, mode, dir = '') {
    if (!imageReady || !cropPct) return;
    event.preventDefault();
    event.stopPropagation();
    const metrics = getMetrics();
    const startCrop = getCropPx(metrics);
    if (!metrics || !startCrop) return;
    const minSize = 24;
    const dragState = {
      mode,
      dir,
      startX: event.clientX,
      startY: event.clientY,
      startCrop
    };

    const onMove = (moveEvent) => {
      moveEvent.preventDefault();
      const currentMetrics = getMetrics();
      if (!currentMetrics) return;
      const dx = moveEvent.clientX - dragState.startX;
      const dy = moveEvent.clientY - dragState.startY;
      let next = { ...dragState.startCrop };

      if (dragState.mode === 'move') {
        next.x = clamp(dragState.startCrop.x + dx, 0, currentMetrics.width - dragState.startCrop.w);
        next.y = clamp(dragState.startCrop.y + dy, 0, currentMetrics.height - dragState.startCrop.h);
      } else {
        let left = dragState.startCrop.x;
        let top = dragState.startCrop.y;
        let right = dragState.startCrop.x + dragState.startCrop.w;
        let bottom = dragState.startCrop.y + dragState.startCrop.h;

        if (dragState.dir.includes('w')) left = clamp(dragState.startCrop.x + dx, 0, right - minSize);
        if (dragState.dir.includes('e')) right = clamp(dragState.startCrop.x + dragState.startCrop.w + dx, left + minSize, currentMetrics.width);
        if (dragState.dir.includes('n')) top = clamp(dragState.startCrop.y + dy, 0, bottom - minSize);
        if (dragState.dir.includes('s')) bottom = clamp(dragState.startCrop.y + dragState.startCrop.h + dy, top + minSize, currentMetrics.height);

        next = {
          x: left,
          y: top,
          w: right - left,
          h: bottom - top
        };
      }

      setCropPx(next, currentMetrics);
      renderCrop();
    };

    const onUp = () => {
      document.removeEventListener('pointermove', onMove, true);
      document.removeEventListener('pointerup', onUp, true);
    };

    document.addEventListener('pointermove', onMove, true);
    document.addEventListener('pointerup', onUp, true);
  }

  function blobToDataUrl(blob) {
    return new Promise((resolve, reject) => {
      const reader = new FileReader();
      reader.onerror = () => reject(new Error('FileReader failed'));
      reader.onload = () => resolve(String(reader.result || ''));
      reader.readAsDataURL(blob);
    });
  }

  async function sendDownloadRequest(dataUrl, saveAs) {
    try {
      const response = await chrome.runtime.sendMessage({
        cmd: 'downloadDataUrl',
        url: dataUrl,
        filename: `Pulse/${sanitizeFileName(currentName)}-${Date.now()}.jpg`,
        saveAs: !!saveAs
      });
      if (!response || !response.ok) throw new Error(response && response.error ? response.error : 'Download failed');
    } catch (error) {
      throw new Error(error && error.message ? error.message : 'Download failed');
    }
  }

  async function saveJpeg(saveAs) {
    if (!imageReady || !img.naturalWidth || !img.naturalHeight) {
      alert('Paste or open an image first');
      return;
    }
    const sx = cropPct ? clamp(Math.round(cropPct.x * img.naturalWidth), 0, img.naturalWidth - 1) : 0;
    const sy = cropPct ? clamp(Math.round(cropPct.y * img.naturalHeight), 0, img.naturalHeight - 1) : 0;
    const sw = cropPct ? clamp(Math.round(cropPct.w * img.naturalWidth), 1, img.naturalWidth - sx) : img.naturalWidth;
    const sh = cropPct ? clamp(Math.round(cropPct.h * img.naturalHeight), 1, img.naturalHeight - sy) : img.naturalHeight;
    const canvas = document.createElement('canvas');
    canvas.width = sw;
    canvas.height = sh;
    const ctx = canvas.getContext('2d');
    if (!ctx) {
      alert('Canvas error');
      return;
    }
    ctx.imageSmoothingEnabled = true;
    ctx.imageSmoothingQuality = 'high';
    ctx.fillStyle = '#ffffff';
    ctx.fillRect(0, 0, sw, sh);
    ctx.drawImage(img, sx, sy, sw, sh, 0, 0, sw, sh);

    try {
      const blob = await new Promise((resolve) => canvas.toBlob(resolve, 'image/jpeg', Number(quality.value)));
      if (!blob) throw new Error('JPEG export failed');
      const dataUrl = await blobToDataUrl(blob);
      await sendDownloadRequest(dataUrl, saveAs);
    } catch (error) {
      alert(error && error.message ? error.message : 'Download failed');
    }
  }

  function applyFullscreenLayout(enabled) {
    fullscreen = !!enabled;
    if (fullscreen) {
      wrap.style.cssText = wrapBaseStyle + 'position:fixed;inset:12px;z-index:2147483647;padding:14px 16px;background:linear-gradient(135deg, #0f151c 0%, #101821 45%, #070a0e 100%);border:1px solid rgba(255,255,255,.10);border-radius:12px;box-shadow:0 24px 80px rgba(0,0,0,.72);backdrop-filter:blur(4px);';
      stage.style.cssText = stageBaseStyle + 'min-height:calc(100vh - 170px);height:calc(100vh - 170px);';
      root.style.overflow = 'visible';
      btnFullscreen.textContent = 'Exit Fullscreen';
    } else {
      wrap.style.cssText = wrapBaseStyle;
      stage.style.cssText = stageBaseStyle;
      root.style.overflow = baseRootOverflow || 'auto';
      btnFullscreen.textContent = 'Fullscreen';
    }
    requestAnimationFrame(renderCrop);
    stage.focus();
  }

  function toggleFullscreen(force) {
    const next = typeof force === 'boolean' ? force : !fullscreen;
    applyFullscreenLayout(next);
  }

  wrap.addEventListener('keydown', (event) => {
    if (event.key === 'Escape' && fullscreen) {
      event.preventDefault();
      toggleFullscreen(false);
    }
  }, true);

  window.addEventListener('resize', renderCrop);
}




function renderStats(e){
  e.append(elt("div",{style:"padding:10px;font-size:14px;color:#777"},"Загрузка статистики…"));
  getStatsDaily().then((n=>{
    e.innerHTML="";
    n=n&&"object"==typeof n?n:{};
    const labels={
      sent_chat:"Инвайтов",
      sent_mail:"Писем",
      sent_media:"Медиа (только чат)",
      sent_like:"Лайков",
      dup_chat:"Дубликаты инвайтов",
      dup_mail:"Дубликаты писем",
      bad_chat:"Инвайты с запрещёнными словами",
      bad_mail:"Письма с запрещёнными словами",
      total_actions:"Всего действий (sender2)"
    };
    const keysMain=["sent_chat","sent_mail","sent_media","sent_like"];
    const keysExtra=["dup_chat","dup_mail","bad_chat","bad_mail"];
    const hasAny=[...keysMain,...keysExtra].some(k=>Number(n[k])>0)||Number.isFinite(Number(n.total_actions));
    if(!hasAny){
      e.append(elt("div",{style:"padding:10px;font-size:14px;color:#999"},"За сегодня статистика отсутствует."));
      return;
    }
    const total=calcSender2Total(n);
    e.append(elt("h4",{style:"margin:10px 0 4px;font-size:16px;font-weight:600"},"Sender2"));
    e.append(elt("div",{style:"display:flex;align-items:baseline;gap:14px;font-size:14px"},
      elt("span",{},labels.total_actions),
      elt("b",{},total)
    ));
    e.append(elt("h4",{style:"margin:10px 0 4px;font-size:16px;font-weight:600"},"Исходящие (sender2)"));
    for(const k of keysMain){
      const v=Number(n[k])||0;
      e.append(elt("div",{style:"display:flex;align-items:baseline;gap:14px;font-size:14px"},
        elt("span",{},labels[k]||k),
        elt("b",{},v)
      ));
    }
    const extrasPresent=keysExtra.some(k=>Number(n[k])>0);
    if(extrasPresent){
      e.append(elt("h4",{style:"margin:10px 0 4px;font-size:16px;font-weight:600"},"Фильтры/ошибки (sender2)"));
      for(const k of keysExtra){
        const v=Number(n[k])||0;
        if(v<=0) continue;
        e.append(elt("div",{style:"display:flex;align-items:baseline;gap:14px;font-size:14px"},
          elt("span",{},labels[k]||k),
          elt("b",{},v)
        ));
      }
    }
  })).catch((()=>{e.innerHTML="";e.append(elt("div",{style:"padding:10px;font-size:14px;color:#999"},"Статистика недоступна (нет данных сервера)."))}));
}function renderStopList(e){const t=elt("textarea",{id:"ah-stop-input",placeholder:"Введите ID через пробел или новую строку…",value:loadStop(),oninput:e=>{e.target.value=e.target.value.replace(/[^\d\s]/g,""),saveStop(e.target.value)}});e.append(t)}function renderTools(e){
  const t=elt("div",{style:"display:flex;flex-direction:column;gap:12px;max-width:520px"},
    makeSwitch("ah-autoTranslate","Авто-перевод при вводе",!1),
    makeSwitch("ah-pageChatTranslate","Перевод страницы и чата",!1),
    makeSwitch("ah-frameEnabled","Рамочка",!0,"",(()=>syncVisualFeatureSettings())),
    makeSwitch("ah-chatLimitsEnabled","Чат лимиты",!0,"",(()=>syncVisualFeatureSettings())),
    makeSwitch("ah-chatBalanceEnabled","Чат баланс",!0,"",(()=>syncVisualFeatureSettings())),
    makeSwitch("ah-customEmojiPicker","Pulse emoji",!1),
    makeSwitch("ah-personalTimerEnabled","Персонал таймер",!1,"",(()=>syncPersonalTimerFeatureSettings(loadSet()))),
    makeSwitch("ah-personalTimerSoundEnabled","Звук персонал таймера",!1,"",(()=>syncPersonalTimerFeatureSettings(loadSet())))
  );
  e.append(t)
}

function renderMain(e){
  const r="hard"===getSenderMode(),
        s=elt("div",{style:"display:flex;flex-direction:column;gap:10px;margin-top:2px"},
          elt("div",{style:"font-size:13px;font-weight:700;letter-spacing:.02em;text-transform:uppercase;opacity:.9"},"Chance бот режим"),
          elt("label",{style:"display:flex;align-items:center;gap:12px;font-size:14px;"},
            elt("span",{style:`font-size:13px;font-weight:700;letter-spacing:.03em;color:${r?"rgba(233,238,246,.72)":"#e9eef6"}`},"Lite"),
            elt("span",{className:"switch ah-switch-danger"},
              elt("input",{type:"checkbox",id:"ah-senderModeLite",checked:r,onchange:e=>{setSenderMode(e.target.checked?"hard":"lite");const t=$("#ah-body");t&&(t.innerHTML="",renderMain(t),pulseInfoButtonsRefreshSoon())}}),
              elt("span",{className:"slider"})
            ),
            elt("span",{style:`font-size:13px;font-weight:700;letter-spacing:.03em;color:${r?"#ff6b6b":"rgba(255,180,180,.72)"}`},"Hard")
          )
        );

  // left column
  const t=elt("div",{style:"display:flex;flex-direction:column;gap:12px;flex:1"},
    makeSwitch("ah-activity","Поддерживать активность",!0),
    makeSwitch("ah-persons","Игнорировать персоналов (wait-list)",!0),
    makeSwitch("ah-stopmaybe","Игнорировать папку Maybe",!1),
    s
  );

  // right column
  const n=elt("div",{style:"display:flex;flex-direction:column;gap:12px;flex:1"},
    makeSwitch("ah-perstomaybe","Добавлять персоналов в Maybe",!1),
    makeSwitch("ah-perstospecial","Добавлять персоналов в Special (только пустые)",!1),
    makeSwitch("ah-stopspecial","Игнорировать папку Special",!1),
    elt("div",{style:"display:flex;flex-wrap:wrap;gap:20px;margin-top:8px"},
      timeInput("sendEvery","Частота рассылки",4),
      timeInput("mailEvery","Частота писем",12)
    )
  );

  const o=elt("div",{style:"display:flex;gap:40px;margin-bottom:12px"},t,n);
  e.append(o),renderSenderModeProfiles(e);
  const l=elt("button",{id:"ah-start",onclick:toggleStart},"START"),
        c=elt("div",{id:"ah-status"}),
        p=elt("div",{id:"ah-ctrl"},l,c);
  e.append(p);
  const d=elt("div",{id:"ah-story",style:"padding-right:160px;box-sizing:border-box"});
  e.append(d);
  const m=loadSet();
  syncVisualFeatureSettings(m);
  m.running?(l.classList.add("stop"),l.textContent="STOP"):(l.classList.remove("stop"),l.textContent="START"),setStatus(m.running)
}
const CATS=["Like","View","Wink","Tell me about yourself","How your day going?","Dont you mind talking bit?","What are you up to?","Post"];function renderInvites(e){loadSet();const settingsBox=elt("div",{style:"display:flex;flex-wrap:wrap;gap:20px;margin-bottom:10px;align-items:flex-end"},makeSwitch("ah-likes","Старт/Стоп",!1),makeSwitch("ah-authorReplyLikeFirst","Сначала лайк",!1),makeSwitch("ah-authorReplyDistance2m","Дистанция 2 минуты",!1),authorReplyDelayInput("authorReplyDelaySec","Задержка автоответа",1));let t=null,n=loadInv(t),o=0;function a(){$$("#inv-profile-select option").forEach((e=>{const t=e.value||null;e.style.color=function(e=null){const t=loadInv(e);return CATS.some((e=>(t[e]||[]).length>0))}(t)?"#4caf50":"#d32f2f"}))}const i=elt("select",{id:"inv-profile-select",onchange:e=>{return o=e.target.value||null,t=o||null,n=loadInv(t),m(null),p.style.display=t?"flex":"none",h.style.display=t?"flex":"none",v(),a(),void x();var o},style:"min-width:220px;padding:4px"});i.append(elt("option",{value:""},"Global")),a();const r=elt("span",{id:"inv-refresh",title:"Обновить список анкет",style:"cursor:pointer;font-size:18px;margin-left:6px;user-select:none",onclick:y},"↻"),s=elt("div",{id:"inv-topbar"},i,r),l=elt("div",{id:"inv-tabs"},...CATS.map(((e,t)=>elt("div",{className:"inv-tab"+(0===t?" active":""),onclick:()=>function(e){o=e,$$("#inv-tabs .inv-tab").forEach(((t,n)=>t.classList.toggle("active",n===e))),v(),x()}(t)},e)))),c=elt("textarea",{id:"inv-input",maxlength:300,placeholder:"Введите текст … (до 300 симв.)",oninput:e=>{e.target.value=e.target.value.replace(/[\u0400-\u052F]/gi,"").slice(0,300)}}),p=elt("div",{id:"inv-img-box",onclick:async function(){if(!t)return;galleryCache[t]||(galleryCache[t]=await fetchGallery(t));const e=galleryCache[t];if(!e.length)return void alert("Для этой анкеты фотографии не найдены.");const n=elt("div",{className:"notranslate",translate:"no",lang:"en",style:"position:fixed;inset:0;background:rgba(0,0,0,.7);\n            z-index:2147483647;display:flex;justify-content:center;align-items:center;pointer-events:auto;",onclick:()=>n.remove()}),o=elt("div",{style:"background:#2b2b2b;border-radius:8px;padding:20px;\n            width:80vw;max-width:900px;max-height:80vh;\n            display:flex;flex-direction:column;",onclick:e=>e.stopPropagation()});o.append(elt("div",{style:"display:flex;justify-content:space-between;align-items:center;margin-bottom:12px;"},elt("h3",{style:"margin:0;font-size:18px;color:#fff"},"Выберите фото"),elt("button",{onclick:()=>n.remove(),style:"background:none;border:none;font-size:24px;color:#fff;cursor:pointer;line-height:1;"},"×")));const a=elt("div",{style:"flex:1 1 auto;overflow:auto;\n           display:grid;gap:6px;\n           grid-template-columns:repeat(auto-fill,minmax(120px,1fr));"});e.forEach((e=>{const t=makeThumb(e.link);a.append(elt("img",{src:t,style:"width:100%;aspect-ratio:1/1;object-fit:cover;cursor:pointer;",onclick:()=>{m(e.link),n.remove()}}))})),o.append(a),n.append(o),ensurePulseRoot().append(n)},title:"Выбрать фото",style:"display:"+(t?"flex":"none")},elt("span",{style:"font-size:24px;color:#777"},"📷")),d=elt("label",{style:"display:flex;align-items:center;"},elt("input",{type:"checkbox",id:"pic-first"}),"pic first");function m(e){p.innerHTML="",invSelectedImg=e,e?p.append(elt("img",{src:makeThumb(e)}),elt("button",{className:"remove",onclick:e=>{e.stopPropagation(),m(null)}},"×")):p.append(elt("span",{style:"font-size:24px;color:#777"},"📷"))}m(null);const u=elt("div",{id:"inv-plus",onclick:function(){const e=c.value.trim();if(!e)return;const i=n[CATS[o]]=n[CATS[o]]||[];t?i.push({text:e,image:invSelectedImg,picFirst:d.firstChild.checked}):i.push(e);saveInv(n,t),a(),c.value="",m(null),d.firstChild.checked=!1,v(),x()}},"＋"),h=elt("div",{style:"display:flex;flex-direction:column;align-items:center;"},p,d);h.style.display=t?"flex":"none";const f=elt("div",{id:"inv-row"},h,c,u),g=elt("div");function x(){$$("#inv-tabs .inv-tab").forEach(((e,t)=>{if(e.classList.contains("active"))return void(e.style.color="");const o=(a=CATS[t],(n[a]||[]).length>0);var a;e.style.color=o?"#4caf50":"#d32f2f"}))}async function y(){const e=localStorage.getItem("token")||"";if(!e)return[];try{const{json:t}=await pageFetchJson("/api/operator/profiles",{method:"GET",headers:{authorization:"Bearer "+e}});return i.replaceChildren(i.firstChild),(Array.isArray(t)?t:[]).forEach((e=>{i.append(elt("option",{value:e.external_id},`${e.name||"NoName"}, ${e.age??"?"} (${e.external_id})`)),a()})),t}catch{return[]}}function S(e,a){const i=n[CATS[o]],r=e+a;r<0||r>=i.length||([i[e],i[r]]=[i[r],i[e]],saveInv(n,t),v())}function v(){g.innerHTML="",(n[CATS[o]]||[]).forEach(((e,i)=>{const r="object"==typeof e&&null!==e,s=r?e.text??"":e,l=r&&e.image||null,c=!!r&&!!e.picFirst,p=elt("div",{className:"inv-item"},l&&elt("div",{className:"inv-img-wrap"},elt("img",{src:makeThumb(l)}),elt("span",{className:"tag"},c?"pic first":"text first")),elt("span",{className:"inv-text"},s),elt("div",{className:"inv-ctrl"},elt("span",{className:"inv-move",title:"вверх",onclick:()=>S(i,-1)},"▲"),elt("span",{className:"inv-move",title:"вниз",onclick:()=>S(i,1)},"▼"),elt("span",{className:"inv-del",title:"удалить",onclick:()=>function(e){n[CATS[o]].splice(e,1),saveInv(n,t),v(),a(),x()}(i)},"×")));g.append(p)}))}e.append(settingsBox,s,l,f,g),y().then((()=>{i.value=t||"",v(),x()}))}
function renderBlockList(e){
  loadSet();
  const t=loadSet();
  let n=t.blockListProfile||null;
  const now=new Date();
  let blMonth=Number.isFinite(t.blockListMonth)?t.blockListMonth:now.getMonth()+1;
  let blYear=Number.isFinite(t.blockListYear)?t.blockListYear:now.getFullYear();
  let blManId=(t.blockListManId||"").toString();
  const o=elt("select",{id:"bl-profile-select",onchange:async e=>{
    n=e.target.value||null;
    const t=loadSet();
    t.blockListProfile=n,saveSet(t);
    try{await u(n)}catch{}
  },style:"min-width:220px;padding:4px"});
  o.append(elt("option",{value:""},"Global"));
  const a=elt("span",{id:"bl-refresh",title:"Обновить список анкет",style:"cursor:pointer;font-size:18px;margin-left:6px;user-select:none",onclick:i},"↻"),
        r=elt("div",{id:"bl-topbar"},o,a);

  // filters: man id + month/year
  const yearMin=now.getFullYear()-4,yearMax=now.getFullYear()+1;
  const monthSel=elt("select",{id:"bl-month",style:"min-width:92px;padding:4px"});
  [1,2,3,4,5,6,7,8,9,10,11,12].forEach((m=>monthSel.append(elt("option",{value:String(m)},String(m).padStart(2,"0")))));
  monthSel.value=String(blMonth);
  const yearSel=elt("select",{id:"bl-year",style:"min-width:98px;padding:4px"});
  for(let y=yearMax;y>=yearMin;y--)yearSel.append(elt("option",{value:String(y)},String(y)));
  yearSel.value=String(blYear);
  const idInp=elt("input",{id:"bl-manid",type:"text",inputmode:"numeric",placeholder:"Man ID…",value:blManId,style:"width:140px;padding:6px 8px"});
  const filters=elt("div",{id:"bl-filters",style:"display:flex;flex-wrap:wrap;gap:10px;align-items:center;margin-top:8px"},
    elt("div",{style:"font-size:12px;opacity:.75;font-weight:700"},"Фильтр"),
    idInp,
    elt("div",{style:"display:flex;gap:8px;align-items:center"},
      elt("span",{style:"font-size:12px;opacity:.75"},"Месяц"),
      monthSel,
      elt("span",{style:"font-size:12px;opacity:.75"},"Год"),
      yearSel
    )
  );

  const s=elt("div",{id:"bl-results",style:"margin-top:10px;padding:10px;border:1px solid rgba(255,255,255,.08);border-radius:8px;background:rgba(255,255,255,.04)"}),
        l=elt("div",{style:"font-size:12px;font-weight:700;letter-spacing:.2px;color:rgba(233,238,246,.85);margin-bottom:8px"},"Blocked this month"),
        c=elt("div",{id:"bl-results-body",style:"font-size:13px;line-height:1.35"},elt("div",{style:"opacity:.75"},"Выберите рабочий профиль."));
  s.append(l,c);
  e.append(r,filters,s);

  const d=new Map; // key(womanId:YYYY-MM) -> {ts, rows}

  function p(e,t,n){
    if(!e)return!1;
    const o=new Date(e);
    return !Number.isNaN(o.getTime())&&o>=t&&o<n
  }

  function gRows(rows){
    let out=rows||[];
    const q=(idInp.value||"").trim();
    if(q)out=out.filter((e=>String(e.external_id||"").includes(q)));
    return out;
  }

  function f(e,t){
    const rows=gRows(e);
    const mm=String(blMonth).padStart(2,"0");
    l.textContent=`Blocked: ${mm}.${blYear}`;
    if(!rows||!rows.length){
      const msg=e&&e.length&&(idInp.value||"").trim()?`Ничего не найдено по фильтру ID. (woman ${t})`:`Ничего не найдено за выбранный месяц. (woman ${t})`;
      return void c.replaceChildren(elt("div",{style:"opacity:.8"},msg));
    }
    const n=elt("div",{style:"display:flex;justify-content:space-between;align-items:center;margin-bottom:8px"},
      elt("div",{style:"opacity:.85"},`Найдено: ${rows.length}`),
      elt("button",{style:"padding:6px 10px;font-size:12px;border-radius:8px;cursor:pointer",onclick:()=>{
        try{
          const t=rows.map((e=>`${e.name}\t${e.external_id}\t${e.last_message}`)).join("\n");
          navigator.clipboard?.writeText(t).catch((()=>{}))
        }catch{}
      }},"Copy")
    );
    const o=elt("div",{style:"display:flex;flex-direction:column;gap:6px"});
    rows.forEach((e=>{
      // fixed layout so the action button/date stay in one clear line
      o.append(
        elt("div",{style:"display:grid;grid-template-columns:minmax(0,1fr) 140px 170px;gap:10px;align-items:center;"+
          "padding:6px 8px;border:1px solid rgba(255,255,255,.08);border-radius:8px;background:rgba(0,0,0,.12)"},
          elt("div",{style:"display:flex;flex-direction:column;gap:2px;min-width:0"},
            // name: readable and NOT bold
            elt("div",{style:"font-weight:400;font-size:18px;line-height:1.15;color:rgba(245,249,255,.98);white-space:nowrap;overflow:hidden;text-overflow:ellipsis"},e.name||"(no name)"),
            elt("div",{style:"font-size:12px;opacity:.82;font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,\"Liberation Mono\",monospace"},e.external_id)
          ),
          elt("div",{style:"display:flex;justify-content:center"},
            elt("button",{
              disabled:!e.chat_uid,
              title:e.chat_uid?"Открыть чат":"chat_uid не найден",
              // blue glass button (stable width)
              style:"min-width:116px;padding:6px 12px;font-size:12px;white-space:nowrap;"+
                "background:rgba(80,170,255,.12);"+
                "border:1px solid rgba(120,200,255,.38);"+
                "box-shadow:0 0 16px rgba(80,170,255,.22);"+
                "border-radius:10px;"+
                "color:rgba(235,248,255,.98);"+
                "backdrop-filter:blur(6px);-webkit-backdrop-filter:blur(6px);"+
                "cursor:pointer;",
              onclick:async ev=>{
                ev.stopPropagation();
                if(!e.chat_uid) return;
                const url=`https://alpha.date/chat/${e.chat_uid}`;
                try{ await closeModal(); }catch{}
                __PULSE_ROUTE_GUARD__.navigate(url);
              }
            },"Открыть чат")
          ),
          elt("div",{style:"font-size:12px;opacity:.78;white-space:nowrap;text-align:right"},e.last_message?new Date(e.last_message).toLocaleString():"")
        )
      )
    }));
    c.replaceChildren(n,o)
  }

  async function u(e){
    if(!e)return void c.replaceChildren(elt("div",{style:"opacity:.75"},"Выберите рабочий профиль (не Global), чтобы увидеть список блокировок за текущий месяц."));
    const t=String(e);
    const key=`${t}:${blYear}-${String(blMonth).padStart(2,"0")}`;
    const n=Date.now(),o=d.get(key);
    if(o&&n-o.ts<6e4&&Array.isArray(o.rows))return void f(o.rows,t);
    c.replaceChildren(elt("div",{style:"opacity:.8"},"Загрузка…"));
    const a=(localStorage.getItem("token")||"").trim();
    if(!a)return void c.replaceChildren(elt("div",{style:"color:#ff6b6b"},"Не найден token. Перезайдите на сайт."));
    const r=new Date(blYear,blMonth-1,1),
          s=new Date(blYear,blMonth,1);
    const {json:l}=await pageFetchJson("/api/chat/blockListByUserID",{method:"POST",headers:{authorization:"Bearer "+a,"content-type":"application/json"},body:JSON.stringify({male_block:0,female_block:1}),timeout:12e3});
    const c1=Array.isArray(l?.chats)?l.chats:[],
          u1=c1
            .filter((e=>e&&1===Number(e.female_block)))
            .filter((e=>String(e.woman_external_id??"")===t))
            .filter((e=>p(e.last_message,r,s)))
            .map((e=>({
              name:String(e.man_name||"").trim(),
              external_id:String(e.man_external_id??"").trim(),
              chat_uid:String(e.chat_uid||"").trim(),
              last_message:e.last_message||""
            })))
            .filter((e=>e.external_id))
            .sort(((e,t)=>new Date(t.last_message)-new Date(e.last_message)));
    d.set(key,{ts:n,rows:u1}),f(u1,t)
  }

  // react on filters
  const onFilters=async()=>{
    const set=loadSet();
    set.blockListMonth=blMonth=Number(monthSel.value)||blMonth;
    set.blockListYear=blYear=Number(yearSel.value)||blYear;
    set.blockListManId=blManId=(idInp.value||"").trim();
    saveSet(set);
    try{await u(n)}catch{}
  };
  monthSel.onchange=onFilters;
  yearSel.onchange=onFilters;
  let idTimer=null;
  idInp.oninput=()=>{clearTimeout(idTimer),idTimer=setTimeout(onFilters,250)};

  async function i(){
    const e=localStorage.getItem("token")||"";
    if(!e)return[];
    try{
      const{json:t}=await pageFetchJson("/api/operator/profiles",{method:"GET",headers:{authorization:"Bearer "+e}});
      return o.replaceChildren(o.firstChild),(Array.isArray(t)?t:[]).forEach((e=>{o.append(elt("option",{value:e.external_id},`${e.name||"NoName"}, ${e.age??"?"} (${e.external_id})`))})),n&&(o.value=String(n)),t
    }catch{
      return[]
    }
  }
  i().then((()=>{try{onFilters()}catch{}}))
}function setPulseRunning(e){const t=byId("ah-modal");t&&t.classList.toggle("ah-running",!!e)}function setStatus(e){const t=byId("ah-status");t&&(t.textContent=e?"Бот запущен":"Бот остановлен",t.style.color=e?"#4caf50":"#d32f2f"),setPulseRunning(e)}async function toggleStart(){const e=$("#ah-start"),t=loadSet();e.classList.toggle("stop");const n=e.classList.contains("stop");t.running=n,saveSet(t);const{jsonStr:o,hash:a}=await buildPayload();chrome.runtime.sendMessage({cmd:"botAction",run:n?"Start":"Stop",json:o,hash:a,key:t.authKey,opId:t.operatorId}),t.lastHash=a,saveSet(t),e.textContent=n?"STOP":"START",setStatus(n)}function snapAhTimeMinutes(e){let t=Number(e);return Number.isFinite(t)||(t=0),t=Math.trunc(t),t<0&&(t=0),t>2880&&(t=2880),0===t||t<10?0:t<30?t<15?10:t<20?15:t<25?20:25:t<60?10*Math.floor(t/10):60*Math.floor(t/60)}function migrateTimeToMinutesIfNeeded(){const e=loadSet();let t=!1;if(!0!==e.timemin){for(const n of["sendEvery","mailEvery"]){if(null===e[n]||void 0===e[n])continue;const o=Number(e[n]);Number.isFinite(o)?(e[n]=snapAhTimeMinutes(60*Math.trunc(o)),t=!0):(e[n]=null,t=!0)}e.timemin=!0,t=!0,t&&saveSet(e)}else{for(const n of["sendEvery","mailEvery"]){if(null===e[n]||void 0===e[n])continue;const o=snapAhTimeMinutes(e[n]);o!==e[n]&&(e[n]=o,t=!0)}t&&saveSet(e)}}function ahTimeIsHours(e){return Number(e)>=60}function ahTimeUnit(e){return ahTimeIsHours(e)?"часы":"минуты"}function ahTimeDisplay(e){const t=Number(e)||0;return ahTimeIsHours(t)?String(Math.trunc(t/60)):String(Math.trunc(t))}function ahTimeStep(e,t){let n=snapAhTimeMinutes(e);return"up"===t?n>=60?n+=60:n>=50?n=60:n>=30?n+=10:n=25===n?30:20===n?25:15===n?20:10===n?15:10:n>60?n-=60:60===n?n=50:n>30?n-=10:30===n?n=25:n>10?n-=5:n=0,snapAhTimeMinutes(n)}function timeInput(e,t,n){migrateTimeToMinutesIfNeeded();const o=loadSet();e in o||(o[e]=snapAhTimeMinutes(60*Number(n)),o.timemin=!0,saveSet(o));let a=snapAhTimeMinutes(o[e]);if(a!==o[e]||!0!==o.timemin){const t=loadSet();t[e]=a,t.timemin=!0,saveSet(t)}const i=elt("span",{style:"font-weight:600"},""),r=elt("span",{},t+" (",i,"):"),s=elt("input",{type:"number",value:0,min:0,inputMode:"none",autocomplete:"off",style:"width:80px;padding:6px;border:1px solid #ccc;border-radius:4px;margin-top:4px"});function l(){i.textContent=ahTimeUnit(a),s.value=ahTimeDisplay(a),s.dataset.prev=s.value}function c(t){const n=ahTimeStep(a,t);n!==a?(a=n,function(){const t=loadSet();t[e]=a,t.timemin=!0,saveSet(t)}(),l()):l()}return s.addEventListener("keydown",(e=>{const t=e.key;if("ArrowUp"===t)return e.preventDefault(),void c("up");if("ArrowDown"===t)return e.preventDefault(),void c("down");new Set(["Tab","Shift","Escape","Enter","Home","End","ArrowLeft","ArrowRight"]).has(t)||e.ctrlKey||e.metaKey||e.preventDefault()})),s.addEventListener("paste",(e=>e.preventDefault())),s.addEventListener("drop",(e=>e.preventDefault())),s.addEventListener("input",(()=>{const e=Number(s.dataset.prev),t=Number(s.value);Number.isFinite(e)&&Number.isFinite(t)?t>e?c("up"):t<e?c("down"):l():l()})),s.addEventListener("blur",l),l(),elt("div",{id:"pulse-info-anchor-"+e,style:"display:flex;flex-direction:column;font-size:14px"},r,s)}const AH_AUTHOR_REPLY_DELAY_STEPS=[1,5,10,15,20,25,30,35,40,45,50];function snapAhAuthorReplyDelaySec(e){let t=Number(e);if(!Number.isFinite(t)||(t=Math.trunc(t))<=1)return 1;if(t>=50)return 50;let n=AH_AUTHOR_REPLY_DELAY_STEPS[0],o=Math.abs(t-n);for(const a of AH_AUTHOR_REPLY_DELAY_STEPS){const i=Math.abs(t-a);i<o&&(n=a,o=i)}return n}function ahAuthorReplyDelayStep(e,t){const n=snapAhAuthorReplyDelaySec(e);let o=AH_AUTHOR_REPLY_DELAY_STEPS.indexOf(n);return o<0&&(o=0),"up"===t&&o<AH_AUTHOR_REPLY_DELAY_STEPS.length-1?o+=1:"down"===t&&o>0&&(o-=1),AH_AUTHOR_REPLY_DELAY_STEPS[o]}function authorReplyDelayInput(e,t,n){const o=loadSet();e in o||(o[e]=snapAhAuthorReplyDelaySec(n),saveSet(o));let a=snapAhAuthorReplyDelaySec(o[e]);a!==o[e]&&(o[e]=a,saveSet(o));const i=elt("span",{style:"font-weight:600"},"сек"),r=elt("span",{},t+" (",i,"):"),s=elt("input",{type:"number",value:a,min:1,max:50,inputMode:"none",autocomplete:"off",style:"width:80px;padding:6px;border:1px solid #ccc;border-radius:4px;margin-top:4px"});function l(){s.value=String(a),s.dataset.prev=s.value}function c(t){const n=ahAuthorReplyDelayStep(a,t);n!==a?(a=n,function(){const t=loadSet();t[e]=a,saveSet(t)}(),l()):l()}return s.addEventListener("keydown",(e=>{const t=e.key;if("ArrowUp"===t)return e.preventDefault(),void c("up");if("ArrowDown"===t)return e.preventDefault(),void c("down");new Set(["Tab","Shift","Escape","Enter","Home","End","ArrowLeft","ArrowRight"]).has(t)||e.ctrlKey||e.metaKey||e.preventDefault()})),s.addEventListener("paste",(e=>e.preventDefault())),s.addEventListener("drop",(e=>e.preventDefault())),s.addEventListener("input",(()=>{const e=Number(s.dataset.prev),t=Number(s.value);Number.isFinite(e)&&Number.isFinite(t)?t>e?c("up"):t<e?c("down"):l():l()})),s.addEventListener("blur",l),l(),elt("div",{id:"pulse-info-anchor-"+e,style:"display:flex;flex-direction:column;font-size:14px"},r,s)}function numberInput(e,t,n){const o=loadSet();e in o||(o[e]=n,saveSet(o));const a=o[e];return elt("div",{style:"display:flex;flex-direction:column;font-size:14px"},elt("span",{},t),elt("input",{type:"number",value:a,min:0,style:"width:80px;padding:6px;border:1px solid #ccc;border-radius:4px;margin-top:4px",onchange:t=>{const o=loadSet(),a=parseInt(t.target.value,10);o[e]=isNaN(a)?n:a,saveSet(o)}}))}function resetAuthUI(){const e=loadSet();delete e.authKey,delete e.operatorId,delete e.running,delete e.lastHash,saveSet(e),syncVisualFeatureSettings(e),setExpSecMem(0),byId("ah-overlay")?.remove(),chrome.runtime.sendMessage({cmd:"setBadge",state:"None"}).catch((()=>{}))}function openStarMenu(e){if(byId("star-menu"))return void byId("star-menu").remove();const t=e.currentTarget.getBoundingClientRect(),n=elt("div",{id:"star-menu",className:"notranslate",translate:"no",lang:"en",style:`position:fixed;left:${t.left-20}px;top:${t.bottom+4}px;
            color:rgba(233,238,246,.94);
            background:
              radial-gradient(circle at 18% 22%, rgba(0,255,180,.22) 0%, rgba(0,255,180,0) 55%),
              radial-gradient(circle at 70% 10%, rgba(0,255,180,.10) 0%, rgba(0,255,180,0) 60%),
              rgba(14,18,24,.92);
            border:1px solid rgba(0,255,180,.22);border-radius:10px;backdrop-filter:blur(6px);
            box-shadow:0 2px 10px rgba(0,0,0,.28), 0 0 18px rgba(0,255,180,.14);z-index:2147483647;
            display:flex;flex-direction:column;min-width:120px;`});n.append(elt("button",{style:"padding:6px 10px;border:none;background:none;text-align:left;\n           font:14px system-ui;cursor:pointer;color:inherit;",onclick:async()=>{const{jsonStr:e}=await buildPayload(!0),t=new Blob([e],{type:"application/json"}),o=URL.createObjectURL(t);Object.assign(document.createElement("a"),{href:o,download:"pulse_backup.json"}).click(),setTimeout((()=>URL.revokeObjectURL(o)),800),n.remove()}},"Сохранить"));const o=elt("input",{type:"file",accept:"application/json",style:"display:none",onchange:async e=>{const t=e.target.files[0];if(t)try{const e=await t.text();applyImportedPayload(JSON.parse(e));const n=$$("#ah-tabs .ah-tab").findIndex((e=>e.classList.contains("ah-active")));-1!==n&&(selectTab(0),0!==n&&selectTab(n)),alert("Настройки загружены ✓")}catch(e){alert("Ошибка импорта: "+e.message)}finally{n.remove()}}});n.append(elt("button",{style:"padding:6px 10px;border:none;background:none;text-align:left;\n           font:14px system-ui;cursor:pointer;color:inherit;",onclick:()=>o.click()},"Загрузить"),o);loadSet();const a=elt("label",{style:"padding:6px 10px;display:flex;align-items:center;gap:8px;\n           font:14px system-ui;cursor:pointer;user-select:none;color:inherit"},(()=>{const e=elt("input",{type:"checkbox"});return chrome.storage.local.get("ahAutoBackup",(t=>{e.checked=!!t.ahAutoBackup})),e.onchange=e=>{chrome.storage.local.set({ahAutoBackup:e.target.checked}),chrome.runtime.sendMessage({cmd:"toggleAutoBackup",enable:e.target.checked})},e})(),"Автосохранение (24 ч)");n.append(a),n.append(elt("button",{style:"padding:6px 10px;border:none;background:none;text-align:left;\n              font:14px system-ui;cursor:pointer;color:#ff6b6b;",onclick:async()=>{const e=loadSet();if(e.running)try{const{jsonStr:t,hash:n}=await buildPayload();await chrome.runtime.sendMessage({cmd:"botAction",run:"Stop",json:t,hash:n,key:e.authKey,opId:e.operatorId})}catch(e){}resetAuthUI(),chrome.runtime.sendMessage({cmd:"resetAuth"}).catch((()=>{})),n.remove(),buildModal()}},"Log out"));const i=e=>{n.contains(e.target)||(n.remove(),document.removeEventListener("mousedown",i))};document.addEventListener("mousedown",i),document.body.append(n)}function applyImportedPayload(e){if(e.settings&&"object"==typeof e.settings){const t=loadSet(),n={lastLike:"lastlike",factTimeMsg:"facttimemsg",stopMaybe:"stopmaybe",stopSpecial:"stopspecial",persToMaybe:"perstomaybe",persToSpecial:"perstospecial",emptyChatsToFolder:"emptychatstofolder"},o=!!(e.timemin||e.settings&&e.settings.timemin);for(const[a,i]of Object.entries(e.settings)){const e=n[a]??a;if("sendEvery"!==e&&"mailEvery"!==e||null==i)"timemin"!==e&&(t[e]=i);else{const n=Number(i);t[e]=Number.isFinite(n)?snapAhTimeMinutes(o?n:60*n):null}}t.timemin=!0,saveSet(t)}"string"==typeof e.stopList&&saveStop(e.stopList),e.invites&&saveInv(e.invites,null),Object.keys(e).forEach((t=>{const n=/^invites(\d+)$/.exec(t);n&&"object"==typeof e[t]&&saveInv(e[t],n[1])}))}function waitBridgeReady(e=2e3){return AH_BRIDGE_READY?Promise.resolve(!0):new Promise((t=>{const n=Date.now(),o=()=>{try{window.postMessage({src:"PULSE_SW",type:"PULSE_PING",app:"PULSE"},location.origin)}catch{}if(AH_BRIDGE_READY||Date.now()-n>=e)return t(AH_BRIDGE_READY);setTimeout(o,100)};o()}))}function openPort(){if(!port){try{port=chrome.runtime.connect({name:"KEEP_ALIVE_AH"})}catch(e){return void setTimeout(openPort,1e3)}finally{chrome.runtime.lastError}port?(port.onDisconnect.addListener((()=>{chrome.runtime.lastError,clearInterval(timer),port=null,setTimeout(openPort,1e3)})),timer=setInterval((()=>{if(port)try{port.postMessage({ping:Date.now()})}catch{clearInterval(timer),port=null,setTimeout(openPort,1e3)}}),25e3)):setTimeout(openPort,1e3)}}chrome.runtime.onMessage.addListener(((e,t,n)=>{if("PULSAR_SERVER_LOG"===e?.type)return pushServerLogEntry(e.payload||e),void(n&&n({ok:!0}));if("saveExp"!==e?.cmd)if("openModal"!==e){if("resetAuth"!==e?.cmd)return"getPayload"===e?.cmd?(buildPayload().then((({jsonStr:e,hash:t})=>{n({ok:!0,json:e,hash:t})})).catch((e=>n({ok:!1,err:String(e)}))),!0):"fetchViaPage"===e?.cmd?((async()=>{try{const t="number"==typeof e.bridgeTimeout?e.bridgeTimeout:2e3;AH_BRIDGE_READY||await waitBridgeReady(t);const o="ah_"+Math.random().toString(36).slice(2),a=Math.max(500,e.timeout||5e3),i=new Promise(((e,t)=>{const n=a=>{const r=a.data;r&&"PULSE_PAGE"===r.src&&"PULSE"===r.app&&"PULSE_FETCH_RES"===r.type&&r.id===o&&(window.removeEventListener("message",n),clearTimeout(i),r.ok?e(r):t(new Error(r.error||"page fetch failed")))};window.addEventListener("message",n);var i=setTimeout((()=>{window.removeEventListener("message",n);try{window.postMessage({src:"PULSE_SW",type:"PULSE_FETCH_CANCEL",app:"PULSE",id:o},location.origin)}catch{}t(new Error("timeout"))}),a)}));window.postMessage({src:"PULSE_SW",type:"PULSE_FETCH_REQ",app:"PULSE",id:o,path:e.path,method:e.method||"GET",headers:e.headers||{},bodyBase64:e.bodyBase64||null,timeoutMs:a,referer:e.referer||null},location.origin);const r=await i;n({ok:!0,status:r.status,headers:r.headers,bodyBase64:r.bodyBase64})}catch(e){n({ok:!1,error:String(e&&e.message||e)})}})(),!0):"ah_ping"===e?.cmd?((async()=>{const t=await waitBridgeReady(500);n({ok:!0,bridge:!!t})})(),!0):void 0;resetAuthUI()}else buildModal();else"number"==typeof e.exp_sec&&(setExpSecMem(e.exp_sec),updateHeaderExp())})),openPort(),ahSyncActivityLoop();

;(()=>{
  if(window.__PULSE_AUTO_TRANSLATE_INIT__)return;
  window.__PULSE_AUTO_TRANSLATE_INIT__=!0;

  const AUTO_TRANSLATE_DEBOUNCE_MS=600;
  let autoTranslateEnabled=!1;
  let autoTranslateObserver=null;
  let autoTranslateTimer=null;
  let autoTranslateTextarea=null;

  const getChatTranslateBtn=()=>document.querySelector('[data-testid="translate-btn"]');
  const getRealTextBlock=()=>document.querySelector('[data-testid="real-text-block"]');
  const getChatTextarea=()=>{
    const e=getRealTextBlock();
    return e?.querySelector('[data-testid="text"]')||null;
  };
  const getLetterActions=()=>document.querySelector('[data-testid="letter-actions"]');
  const getLetterSourceTextarea=()=>{
    const e=getLetterActions(),t=e?.querySelectorAll('textarea');
    return t?.[0]||null;
  };
  const getLetterTranslateBtn=()=>{
    const e=getLetterActions(),t=e?.querySelector('[data-testid="ArrowForwardIcon"]');
    return t?.parentElement||null;
  };
  const getTranslateBtn=()=>getLetterTranslateBtn()||getChatTranslateBtn();
  const getTextarea=()=>getLetterSourceTextarea()||getChatTextarea();

  function clearAutoTranslateTimer(){
    if(autoTranslateTimer){clearTimeout(autoTranslateTimer);autoTranslateTimer=null}
  }
  function triggerTranslate(){
    const e=getTranslateBtn();
    e&&!e.disabled&&e.click();
  }
  function detachAutoTranslate(){
    clearAutoTranslateTimer();
    if(autoTranslateTextarea){
      if(autoTranslateTextarea.__pulseAutoTranslateHandler__){
        autoTranslateTextarea.removeEventListener('input',autoTranslateTextarea.__pulseAutoTranslateHandler__);
        autoTranslateTextarea.removeEventListener('paste',autoTranslateTextarea.__pulseAutoTranslateHandler__);
        delete autoTranslateTextarea.__pulseAutoTranslateHandler__;
      }
      delete autoTranslateTextarea.dataset.pulseAutoTranslateAttached;
      autoTranslateTextarea=null;
    }
  }
  function attachAutoTranslate(e){
    if(autoTranslateTextarea===e)return;
    detachAutoTranslate();
    autoTranslateTextarea=e;
    const t=()=>{
      clearAutoTranslateTimer();
      autoTranslateTimer=setTimeout((()=>{
        autoTranslateTimer=null;
        const e=getTranslateBtn(),t=getTextarea();
        if(!autoTranslateEnabled||!e||!t||!t.value?.trim())return;
        triggerTranslate();
      }),AUTO_TRANSLATE_DEBOUNCE_MS);
    };
    e.addEventListener('input',t);
    e.addEventListener('paste',t);
    e.__pulseAutoTranslateHandler__=t;
    e.dataset.pulseAutoTranslateAttached='true';
  }
  function scanAutoTranslate(){
    if(!autoTranslateEnabled)return;
    const e=getTranslateBtn(),t=getTextarea();
    if(e&&t&&!t.dataset.pulseAutoTranslateAttached)attachAutoTranslate(t);
    e||!autoTranslateTextarea||detachAutoTranslate();
  }
  function setAutoTranslateEnabled(e){
    autoTranslateEnabled=!!e;
    if(!autoTranslateEnabled){
      detachAutoTranslate();
      return;
    }
    scanAutoTranslate();
    autoTranslateObserver||(autoTranslateObserver=new MutationObserver((()=>{autoTranslateEnabled&&scanAutoTranslate()})),autoTranslateObserver.observe(document.body,{childList:!0,subtree:!0}));
  }
  function syncAutoTranslateFromSettings(){
    let e=!1;
    try{e=!!loadSet().autoTranslate}catch{}
    setAutoTranslateEnabled(e);
    try{syncVisualFeatureSettings()}catch{}
  }

  try{chrome.storage.onChanged.addListener(((e,t)=>{
    if('local'!==t||!e[AH_STORE_KEYS.set])return;
    const n=e[AH_STORE_KEYS.set].newValue||{};
    setAutoTranslateEnabled(!!n.autoTranslate);
    syncVisualFeatureSettings(n);
  }))}catch{}

  async function bootAutoTranslate(){
    try{await initAhStore()}catch{}
    syncAutoTranslateFromSettings();
  }

  if(document.readyState==='loading')document.addEventListener('DOMContentLoaded',bootAutoTranslate,{once:!0});
  else bootAutoTranslate();
})();


;(()=>{
  if (window.__PULSE_PLACE_LOCAL_TIME_INIT__) return;
  window.__PULSE_PLACE_LOCAL_TIME_INIT__ = true;

  const TIMEAPI_BASE = 'https://timeapi.io/api/v1/time';
  const GEOCODING_BASE = 'https://geocoding-api.open-meteo.com/v1';
  const MAX_ZONES_FOR_NOT_SPECIFIED = 6;
  const CLOCK_STYLE = 'margin-left:6px;font-size:11px;color:#fff;font-weight:500;font-family:-apple-system,BlinkMacSystemFont,\'Segoe UI\',Roboto,sans-serif;';
  const CLOCK_ATTR = 'data-alpha-finder-place-time';
  const CLOCK_KEY_ATTR = 'data-alpha-finder-place-key';
  const OBSERVED_ATTR = 'data-alpha-finder-place-observed';
  const DEBOUNCE_MS = 400;
  const MAX_USER_DETAILS_CACHE = 250;
  const MAX_PLACE_TIME_CACHE = 200;

  let userDetailsByChatUid = Object.create(null);
  let scanTimer = null;

  function pruneUserDetailsStore(preferredChatUid = null) {
    try {
      const keys = Object.keys(userDetailsByChatUid || {});
      if (keys.length <= MAX_USER_DETAILS_CACHE) return;
      const keep = new Set(keys.slice(-MAX_USER_DETAILS_CACHE));
      const preferred = String(preferredChatUid || '').trim();
      if (preferred && userDetailsByChatUid[preferred]) keep.add(preferred);
      const next = Object.create(null);
      for (const key of keys) {
        if (keep.has(key) && userDetailsByChatUid[key]) next[key] = userDetailsByChatUid[key];
      }
      userDetailsByChatUid = next;
    } catch {}
  }

  function upsertUserDetail(chatUid, item) {
    if (!chatUid || !item) return;
    try { delete userDetailsByChatUid[chatUid]; } catch {}
    userDetailsByChatUid[chatUid] = item;
    pruneUserDetailsStore(getCurrentChatUid() || chatUid);
  }

  function mergeUserDetailsStore(userDetails) {
    if (!userDetails || typeof userDetails !== 'object') return;
    const entries = Object.entries(userDetails);
    if (!entries.length) return;
    for (const [chatUid, item] of entries) {
      if (!chatUid || !item) continue;
      try { delete userDetailsByChatUid[chatUid]; } catch {}
      userDetailsByChatUid[chatUid] = item;
    }
    pruneUserDetailsStore(getCurrentChatUid());
  }

  const COUNTRY_TIMEZONES = {
    US: ['America/New_York', 'America/Los_Angeles'],
    CA: ['America/Toronto', 'America/Vancouver'],
    AU: ['Australia/Sydney', 'Australia/Perth'],
    RU: ['Europe/Moscow', 'Asia/Vladivostok'],
    BR: ['America/Sao_Paulo', 'America/Manaus'],
    MX: ['America/Mexico_City'],
    IN: ['Asia/Kolkata'],
    CN: ['Asia/Shanghai'],
    JP: ['Asia/Tokyo'],
    GB: ['Europe/London'],
    UA: ['Europe/Kyiv'],
    DE: ['Europe/Berlin'],
    FR: ['Europe/Paris'],
    ES: ['Europe/Madrid'],
    IT: ['Europe/Rome'],
    PL: ['Europe/Warsaw'],
    TR: ['Europe/Istanbul'],
    KZ: ['Asia/Almaty', 'Asia/Aqtobe'],
    ID: ['Asia/Jakarta', 'Asia/Makassar'],
    AR: ['America/Argentina/Buenos_Aires'],
    CL: ['America/Santiago'],
    CO: ['America/Bogota'],
    PE: ['America/Lima'],
    PH: ['Asia/Manila'],
    TH: ['Asia/Bangkok'],
    VN: ['Asia/Ho_Chi_Minh'],
    KR: ['Asia/Seoul'],
    NZ: ['Pacific/Auckland'],
    ZA: ['Africa/Johannesburg'],
    EG: ['Africa/Cairo'],
    NG: ['Africa/Lagos'],
    PK: ['Asia/Karachi'],
    BD: ['Asia/Dhaka'],
    MY: ['Asia/Kuala_Lumpur'],
    SG: ['Asia/Singapore']
  };

  function getCurrentChatUid() {
    const segments = String(location.pathname || '').split('/').filter(Boolean);
    if (segments.length < 2) return null;
    const last = segments[segments.length - 1];
    return last && /^[a-z0-9-]+$/i.test(last) ? last : null;
  }

  function getCurrentChatHeader() {
    const chatList = document.querySelector('[data-testid="chat-list"]');
    const all = document.querySelectorAll('[data-testid="chat-header"]');
    for (const el of all) {
      if (chatList && chatList.contains(el)) continue;
      return el;
    }
    return all[0] || document.querySelector('[data-testid="chat-header"]');
  }

  function getOpenChatPlaceElements() {
    const chatHeader = getCurrentChatHeader();
    const chatList = document.querySelector('[data-testid="chat-list"]');
    const scope = chatHeader?.parentElement ?? chatHeader ?? document.body;
    let manPlace = chatHeader?.querySelector('[data-testid="man-place"]') ?? scope.querySelector('[data-testid="man-place"]');
    let womanPlace = chatHeader?.querySelector('[data-testid="woman-place"]') ?? scope.querySelector('[data-testid="woman-place"]');
    if (!womanPlace) womanPlace = document.querySelector('[data-testid="woman-place"]');
    if (chatList) {
      if (manPlace && chatList.contains(manPlace)) manPlace = null;
      if (womanPlace && chatList.contains(womanPlace)) womanPlace = null;
    }
    return { manPlace: manPlace ?? null, womanPlace: womanPlace ?? null };
  }

  function getWomanExternalIdFromDom() {
    const header = getCurrentChatHeader();
    const el = header?.querySelector('[data-testid="woman-external_id"]');
    if (!el || !el.textContent) return null;
    const match = (el.textContent || '').match(/\d+/);
    return match ? match[0] : null;
  }

  function getCountryCodeFromFlag(placeEl) {
    try {
      const img = placeEl?.querySelector('img');
      const src = String(img?.getAttribute('src') || '');
      const m = src.match(/\/flags\/([a-z]{2})\./i) || src.match(/\/([a-z]{2})\.(?:svg|png|webp)(?:\?|$)/i);
      return m ? m[1].toUpperCase() : null;
    } catch {
      return null;
    }
  }

  function getZonesForCountry(countryCode) {
    const code = String(countryCode || '').toUpperCase();
    const zones = COUNTRY_TIMEZONES[code];
    if (zones && zones.length) return zones;
    const fallbacks = {
      AT: ['Europe/Vienna'], BE: ['Europe/Brussels'], CH: ['Europe/Zurich'], CZ: ['Europe/Prague'], GR: ['Europe/Athens'],
      HU: ['Europe/Budapest'], PT: ['Europe/Lisbon'], RO: ['Europe/Bucharest'], SE: ['Europe/Stockholm'], NO: ['Europe/Oslo'],
      DK: ['Europe/Copenhagen'], FI: ['Europe/Helsinki'], IE: ['Europe/Dublin'], IL: ['Asia/Jerusalem'], SA: ['Asia/Riyadh'],
      AE: ['Asia/Dubai'], NL: ['Europe/Amsterdam'], SK: ['Europe/Bratislava'], BG: ['Europe/Sofia'], RS: ['Europe/Belgrade'],
      HR: ['Europe/Zagreb'], SI: ['Europe/Ljubljana'], LT: ['Europe/Vilnius'], LV: ['Europe/Riga'], EE: ['Europe/Tallinn']
    };
    return fallbacks[code] || [];
  }

  function getWomanPlaceFromProfiles() {
    return new Promise((resolve) => {
      try {
        const womanExternalId = getWomanExternalIdFromDom();
        if (!womanExternalId || !chrome?.storage?.local?.get) return resolve(null);
        chrome.storage.local.get(['profiles'], (result) => {
          const profiles = Array.isArray(result?.profiles) ? result.profiles : [];
          const profile = profiles.find((p) => p && String(p.external_id) === String(womanExternalId));
          if (!profile) return resolve(null);
          const country = (profile.country_code && String(profile.country_code).toUpperCase()) || null;
          const city = (profile.city && String(profile.city).trim()) || null;
          if (!country && !city) return resolve(null);
          resolve({ country, city });
        });
      } catch {
        resolve(null);
      }
    });
  }

  const cache = new Map();
  function cacheKey(role, country, city) {
    return `${role}:${country || ''}:${String(city || '').toLowerCase()}`;
  }

  function setPlaceTimeCache(key, value) {
    if (!key) return;
    try {
      if (cache.has(key)) cache.delete(key);
      cache.set(key, value);
      while (cache.size > MAX_PLACE_TIME_CACHE) {
        const oldestKey = cache.keys().next().value;
        if (oldestKey == null) break;
        cache.delete(oldestKey);
      }
    } catch {}
  }

  function fetchViaBackground(url) {
    return new Promise((resolve, reject) => {
      try {
        chrome.runtime.sendMessage({ type: 'PLACE_TIME_FETCH', url }, (response) => {
          if (chrome.runtime.lastError) return reject(new Error(chrome.runtime.lastError.message));
          if (response?.error) return reject(new Error(response.error));
          resolve(response?.data ?? null);
        });
      } catch (e) {
        reject(e);
      }
    });
  }

  async function geocodeCity(cityName) {
    const name = encodeURIComponent(String(cityName || '').trim());
    const url = `${GEOCODING_BASE}/search?name=${name}&count=1`;
    const data = await fetchViaBackground(url);
    const r = data?.results?.[0];
    return r ? { lat: r.latitude, lng: r.longitude } : null;
  }

  async function timeByCoordinate(lat, lng) {
    const url = `${TIMEAPI_BASE}/current/coordinate?latitude=${lat}&longitude=${lng}`;
    const data = await fetchViaBackground(url);
    return data?.time ? data.time : null;
  }

  async function timeByZone(zoneName) {
    const zoneEnc = encodeURIComponent(zoneName);
    const url = `${TIMEAPI_BASE}/current/zone?timezone=${zoneEnc}`;
    const data = await fetchViaBackground(url);
    return data?.time ? data.time : null;
  }

  function timeStringToMinutes(timeStr) {
    const m = String(timeStr || '').match(/^(\d{1,2}):(\d{2})/);
    return m ? parseInt(m[1], 10) * 60 + parseInt(m[2], 10) : 0;
  }

  function formatTimeShort(timeStr) {
    const m = String(timeStr || '').match(/^(\d{1,2}):(\d{2})/);
    return m ? `${m[1].padStart(2, '0')}:${m[2]}` : '';
  }

  async function getLocalTimeForPlace(role, country, city) {
    const key = cacheKey(role, country, city);
    if (cache.has(key)) return cache.get(key);

    let result = null;
    const cityText = String(city || '').trim();
    const hasCity = cityText && !/^not\s+specified$/i.test(cityText);

    if (hasCity) {
      const coords = await geocodeCity(cityText);
      if (coords?.lat != null && coords?.lng != null) {
        const t = await timeByCoordinate(coords.lat, coords.lng);
        if (t) result = formatTimeShort(t);
      }
    }

    if (!result && country) {
      const zones = getZonesForCountry(country).slice(0, MAX_ZONES_FOR_NOT_SPECIFIED);
      const times = [];
      for (const zn of zones) {
        const t2 = await timeByZone(zn);
        if (t2) times.push(t2);
      }
      if (times.length === 1) {
        result = formatTimeShort(times[0]);
      } else if (times.length > 1) {
        times.sort((a, b) => timeStringToMinutes(a) - timeStringToMinutes(b));
        result = `${formatTimeShort(times[0])} - ${formatTimeShort(times[times.length - 1])}`;
      }
    }

    setPlaceTimeCache(key, result);
    return result;
  }

  function upsertClock(placeEl, currentKey, text) {
    if (!placeEl || !text) return;
    const displayedKey = placeEl.getAttribute(CLOCK_KEY_ATTR) || '';
    if (displayedKey === currentKey) return;
    let clock = placeEl.querySelector(`[${CLOCK_ATTR}]`);
    if (!clock) {
      clock = document.createElement('span');
      clock.setAttribute(CLOCK_ATTR, '1');
      clock.setAttribute('style', CLOCK_STYLE);
      placeEl.appendChild(clock);
    }
    clock.textContent = text;
    placeEl.setAttribute(CLOCK_KEY_ATTR, currentKey);
  }


  const manDetailFetches = new Map();

  async function ensureManDetailForChatUid(chatUid) {
    if (!chatUid) return null;
    if (userDetailsByChatUid[chatUid]) return userDetailsByChatUid[chatUid];
    if (manDetailFetches.has(chatUid)) return manDetailFetches.get(chatUid);
    const task = (async () => {
      try {
        const token = String(localStorage.getItem('token') || '').trim();
        if (!token) return null;
        const { json } = await pageFetchJson('/api/chatList/userDetail', {
          method: 'POST',
          headers: {
            Accept: 'application/json, text/plain, */*',
            'Content-Type': 'application/json',
            Authorization: 'Bearer ' + token
          },
          body: JSON.stringify({ chat_uid: [chatUid] }),
          timeout: 10000
        });
        const item = Array.isArray(json?.response) ? (json.response[0] || null) : null;
        if (item) {
          upsertUserDetail(chatUid, item);
          return item;
        }
      } catch {}
      return null;
    })().finally(() => { manDetailFetches.delete(chatUid); });
    manDetailFetches.set(chatUid, task);
    return task;
  }

  async function injectForMan() {
    const { manPlace } = getOpenChatPlaceElements();
    if (!manPlace) return;
    const chatUid = getCurrentChatUid();
    let ud = chatUid ? userDetailsByChatUid[chatUid] : null;
    if (!ud && chatUid) ud = await ensureManDetailForChatUid(chatUid);
    const city = String(ud?.city || '').trim() || null;
    const country = getCountryCodeFromFlag(manPlace) || String(ud?.country_image || ud?.country_code || '').trim().toUpperCase() || null;
    if (!country && !city) return;
    const text = await getLocalTimeForPlace('man', country, city);
    if (!text) return;
    upsertClock(manPlace, cacheKey('man', country, city), text);
  }

  async function injectForWoman() {
    const { womanPlace } = getOpenChatPlaceElements();
    if (!womanPlace) return;
    const place = await getWomanPlaceFromProfiles();
    const city = String(place?.city || '').trim() || null;
    const country = String(place?.country || '').trim().toUpperCase() || getCountryCodeFromFlag(womanPlace) || null;
    if (!country && !city) return;
    const text = await getLocalTimeForPlace('woman', country, city);
    if (!text) return;
    upsertClock(womanPlace, cacheKey('woman', country, city), text);
  }

  async function scanAndInjectNow() {
    try { await injectForMan(); } catch {}
    try { await injectForWoman(); } catch {}
  }

  function scanAndInject() {
    clearTimeout(scanTimer);
    scanTimer = setTimeout(scanAndInjectNow, DEBOUNCE_MS);
  }

  function setupMessageListener() {
    window.addEventListener('message', (event) => {
      if (!event.data || event.data.type !== 'USER_DETAILS_DATA') return;
      const userDetails = event.data.userDetails;
      if (userDetails && typeof userDetails === 'object') {
        mergeUserDetailsStore(userDetails);
        scanAndInject();
      }
    });
  }

  function requestStoredUserDetails() {
    try {
      window.postMessage({ type: 'REQUEST_USER_DETAILS_DATA' }, location.origin);
    } catch {}
  }

  function observePlaceDiv(div) {
    if (!div || div.hasAttribute(OBSERVED_ATTR)) return;
    div.setAttribute(OBSERVED_ATTR, '1');
    const observer = new MutationObserver(() => { scanAndInject(); });
    observer.observe(div, { childList: true, subtree: true, characterData: true, attributes: true });
  }

  function run() {
    setupMessageListener();
    requestStoredUserDetails();
    scanAndInject();
    setTimeout(requestStoredUserDetails, 500);
    const observer = new MutationObserver(() => {
      scanAndInject();
      const { manPlace, womanPlace } = getOpenChatPlaceElements();
      if (manPlace) observePlaceDiv(manPlace);
      if (womanPlace) observePlaceDiv(womanPlace);
    });
    observer.observe(document.body, { childList: true, subtree: true });
  }

  if (location.href.includes('alpha.date')) {
    if (document.readyState === 'loading') document.addEventListener('DOMContentLoaded', run);
    else run();
  }
})();


(() => {
  const PULSE_QUICK_ID = 'pulse-quick-open-glass';
  const PULSE_QUICK_STYLE_ID = 'pulse-quick-open-glass-style';
  const PULSE_QUICK_ICON = chrome.runtime.getURL('pulse_quick_icon.png');
  const PULSE_REPORTS_QUICK_ID = 'pulse-quick-open-reports';
  const PULSE_REPORTS_QUICK_ICON = chrome.runtime.getURL('pulse_reports_icon.png');

  function ensurePulseQuickStyle() {
    if (document.getElementById(PULSE_QUICK_STYLE_ID)) return;
    const style = document.createElement('style');
    style.id = PULSE_QUICK_STYLE_ID;
    style.textContent = `
      #${PULSE_QUICK_ID}{
        width:48px;
        height:48px;
        min-width:48px;
        border:none;
        border-radius:18px;
        align-self:center !important;
        justify-self:start;
        margin:0 14px 0 10px !important;
        transform:translateY(-1px);
        display:inline-flex;
        align-items:center;
        justify-content:center;
        cursor:pointer;
        position:relative;
        overflow:hidden;
        isolation:isolate;
        padding:0;
        background:linear-gradient(145deg, rgba(192,120,255,.88), rgba(121,55,255,.92) 58%, rgba(85,34,214,.96) 100%);
        box-shadow:
          inset 0 1px 0 rgba(255,255,255,.28),
          inset 0 -1px 0 rgba(40,12,96,.16),
          0 0 0 1px rgba(255,255,255,.12);
        transition:transform .18s ease, box-shadow .18s ease, filter .18s ease;
        margin:0 12px 0 0;
        vertical-align:middle;
        flex:0 0 auto;
      }
      #${PULSE_QUICK_ID}::before{
        content:none;
      }
      #${PULSE_QUICK_ID}::after{
        content:"";
        position:absolute;
        inset:1px;
        border-radius:17px;
        border:1px solid rgba(255,255,255,.14);
        pointer-events:none;
      }
      #${PULSE_QUICK_ID}:hover{
        transform:translateY(-1px) scale(1.03);
        box-shadow:
          inset 0 1px 0 rgba(255,255,255,.34),
          inset 0 -1px 0 rgba(40,12,96,.18),
          0 0 0 1px rgba(255,255,255,.16);
        filter:brightness(1.04);
      }
      #${PULSE_QUICK_ID}:active{
        transform:translateY(0) scale(.98);
      }
      #${PULSE_QUICK_ID} .pulse-quick-bg{
        position:absolute;
        inset:3px;
        border-radius:15px;
        background:linear-gradient(180deg, rgba(255,255,255,.10), rgba(255,255,255,.03));
        box-shadow:none;
        pointer-events:none;
      }
      #${PULSE_QUICK_ID} img{
        position:relative;
        z-index:1;
        width:28px;
        height:28px;
        object-fit:contain;
        border-radius:8px;
        filter:none;
      }
      #${PULSE_REPORTS_QUICK_ID}{
        width:48px;
        height:48px;
        min-width:48px;
        border:none;
        border-radius:18px;
        align-self:center !important;
        justify-self:start;
        margin:0 12px 0 0 !important;
        transform:translateY(-1px);
        display:inline-flex;
        align-items:center;
        justify-content:center;
        cursor:pointer;
        position:relative;
        overflow:hidden;
        isolation:isolate;
        padding:0;
        background:linear-gradient(145deg, rgba(126,207,255,.96) 0%, rgba(63,156,255,.96) 48%, rgba(20,101,255,.98) 100%);
        box-shadow:
          inset 0 1px 0 rgba(255,255,255,.28),
          inset 0 -1px 0 rgba(9,45,126,.20),
          0 0 0 1px rgba(255,255,255,.12);
        transition:transform .18s ease, box-shadow .18s ease, filter .18s ease;
        vertical-align:middle;
        flex:0 0 auto;
      }
      #${PULSE_REPORTS_QUICK_ID}::before{
        content:none;
      }
      #${PULSE_REPORTS_QUICK_ID}::after{
        content:"";
        position:absolute;
        inset:1px;
        border-radius:17px;
        border:1px solid rgba(255,255,255,.14);
        pointer-events:none;
      }
      #${PULSE_REPORTS_QUICK_ID}:hover{
        transform:translateY(-1px) scale(1.03);
        box-shadow:
          inset 0 1px 0 rgba(255,255,255,.34),
          inset 0 -1px 0 rgba(9,45,126,.24),
          0 0 0 1px rgba(255,255,255,.16);
        filter:brightness(1.04);
      }
      #${PULSE_REPORTS_QUICK_ID}:active{
        transform:translateY(0) scale(.98);
      }
      #${PULSE_REPORTS_QUICK_ID} .pulse-quick-bg{
        position:absolute;
        inset:3px;
        border-radius:15px;
        background:linear-gradient(180deg, rgba(255,255,255,.10), rgba(255,255,255,.03));
        box-shadow:none;
        pointer-events:none;
      }
      #${PULSE_REPORTS_QUICK_ID} img{
        position:relative;
        z-index:1;
        width:32px;
        height:32px;
        object-fit:contain;
        display:block;
        filter:none;
      }
    `;
    document.head.appendChild(style);
  }

  function isVisible(el) {
    if (!el) return false;
    const style = window.getComputedStyle(el);
    if (style.display === 'none' || style.visibility === 'hidden' || style.opacity === '0') return false;
    const rect = el.getBoundingClientRect();
    return rect.width > 0 && rect.height > 0;
  }

  function findByText(rx) {
    const walker = document.createTreeWalker(document.body, NodeFilter.SHOW_ELEMENT);
    while (walker.nextNode()) {
      const el = walker.currentNode;
      if (!isVisible(el)) continue;
      const txt = (el.textContent || '').replace(/\s+/g, ' ').trim();
      if (!txt || txt.length > 40) continue;
      if (rx.test(txt)) return el;
    }
    return null;
  }

  function findToolbarHost() {
    const textareas = [...document.querySelectorAll('textarea')].filter(isVisible);
    const area = textareas.sort((a, b) => b.getBoundingClientRect().top - a.getBoundingClientRect().top)[0];

    function scoreRow(el) {
      if (!el || !isVisible(el)) return -1;
      const rect = el.getBoundingClientRect();
      if (rect.width < 360 || rect.height < 24 || rect.height > 90) return -1;
      const text = (el.textContent || '').replace(/\s+/g, ' ').trim();
      const hasTranslate = /ПЕРЕВОДИТЬ|TRANSLATE/i.test(text);
      const hasSend = /Отправлят|Отправить|Send/i.test(text);
      const icons = el.querySelectorAll('svg, img, button, [role="button"], input[type="checkbox"]').length;
      let score = icons * 4;
      if (hasTranslate) score += 18;
      if (hasSend) score += 18;
      score -= Math.abs(rect.height - 42);
      return score;
    }

    if (area) {
      let composeRoot = area.parentElement;
      for (let i = 0; i < 8 && composeRoot; i++, composeRoot = composeRoot.parentElement) {
        if (!composeRoot || !isVisible(composeRoot)) continue;
        const rootRect = composeRoot.getBoundingClientRect();
        if (rootRect.width < 500 || rootRect.height < 100) continue;
        const areaRect = area.getBoundingClientRect();
        const rows = [composeRoot, ...composeRoot.querySelectorAll('div, section, form')]
          .filter((el) => {
            if (!isVisible(el)) return false;
            const r = el.getBoundingClientRect();
            return r.top >= areaRect.bottom - 12 && r.bottom <= rootRect.bottom + 8;
          })
          .map((el) => ({ el, score: scoreRow(el) }))
          .filter((x) => x.score > 0)
          .sort((a, b) => b.score - a.score || a.el.getBoundingClientRect().top - b.el.getBoundingClientRect().top);

        if (rows[0]) {
          const row = rows[0].el;
          const iconAnchor = [...row.children].find((child) => {
            if (!isVisible(child)) return false;
            const r = child.getBoundingClientRect();
            if (r.width > 80 || r.height > 80) return false;
            return child.querySelector('svg, img') || /^(BUTTON|IMG|SVG)$/i.test(child.tagName);
          }) || [...row.children].find(isVisible) || null;
          return { host: row, anchor: iconAnchor };
        }
      }
    }

    const translateEl = findByText(/^(ПЕРЕВОДИТЬ|TRANSLATE)$/i) || findByText(/ПЕРЕВОДИТЬ|TRANSLATE/i);
    if (translateEl) {
      let row = translateEl;
      for (let i = 0; i < 6 && row; i++, row = row.parentElement) {
        if (!row || !isVisible(row)) continue;
        if (scoreRow(row) > 0) {
          const iconAnchor = [...row.children].find((child) => {
            if (!isVisible(child)) return false;
            const r = child.getBoundingClientRect();
            return r.width <= 80 && r.height <= 80;
          }) || [...row.children].find(isVisible) || translateEl;
          return { host: row, anchor: iconAnchor };
        }
      }
      return { host: translateEl.parentElement || translateEl, anchor: translateEl };
    }

    const sendEl = findByText(/^(Отправлят|Отправить|Send)/i);
    if (sendEl) {
      let row = sendEl.parentElement;
      for (let i = 0; i < 6 && row; i++, row = row.parentElement) {
        if (!row || !isVisible(row)) continue;
        if (scoreRow(row) > 0) {
          const iconAnchor = [...row.children].find((child) => {
            if (!isVisible(child)) return false;
            const r = child.getBoundingClientRect();
            return r.width <= 80 && r.height <= 80;
          }) || [...row.children].find(isVisible) || sendEl;
          return { host: row, anchor: iconAnchor };
        }
      }
    }

    return null;
  }


  const PULSE_USER_DETAIL_MODAL_ID = 'pulse-user-detail-modal-overlay';

  const PULSE_USER_DETAIL_TEXTS = {
    buttonTitle: 'Информация',
    modalTitle: 'Информация',
    loading: 'Загрузка...',
    error: 'Не удалось загрузить данные',
    close: '×',
    noUserId: 'ID пользователя не найден. Откройте чат.',
    noToken: 'Сначала войдите в alpha.date.',
    onlineStatus: 'Онлайн',
    offlineStatus: 'Оффлайн',
    sectionDetail: 'Основная информация',
    sectionReference: 'Справка',
    sectionMatch: 'Предпочтения поиска',
    sectionHobbies: 'Хобби',
    sectionHobbyMatch: 'Совпадение хобби',
    sectionContent: 'Фото и контент',
  };

  const PULSE_USER_DETAIL_LABELS = {
    external_id: 'Внешний ID',
    name: 'Имя',
    age: 'Возраст',
    country_name: 'Страна',
    b_year: 'Год рождения',
    b_month: 'Месяц рождения',
    b_day: 'День рождения',
    online: 'Онлайн',
    last_online: 'Последний онлайн',
    city_name: 'Город',
    height: 'Рост',
    body: 'Телосложение',
    hair: 'Волосы',
    eye: 'Глаза',
    zodiac: 'Знак зодиака',
    alcohol: 'Алкоголь',
    smoke: 'Курение',
    education: 'Образование',
    occupation: 'Род занятий',
    religion: 'Религия',
    marital: 'Семейное положение',
    children: 'Дети',
    morechildren: 'Ещё дети',
    reason: 'Причина',
    summary: 'О себе',
    looking: 'Ищу',
    girls_age_from: 'Возраст от',
    girls_age_to: 'Возраст до',
    girls_height_from_: 'Рост от',
    girls_height_to_: 'Рост до',
    hobbie: 'Хобби',
    content_type: 'Тип',
    link: 'Ссылка',
  };

  function pulseFieldLabel(key) {
    return PULSE_USER_DETAIL_LABELS[key] || key;
  }

  function getCurrentChatHeader() {
    const chatList = document.querySelector('[data-testid="chat-list"]');
    const all = document.querySelectorAll('[data-testid="chat-header"]');
    for (const el of all) {
      if (chatList && chatList.contains(el)) continue;
      return el;
    }
    return all[0] || document.querySelector('[data-testid="chat-header"]');
  }

  function getMaleIdFromPage() {
    const chatHeader = getCurrentChatHeader();
    const manIdElement = chatHeader
      ? chatHeader.querySelector('[data-testid="man-external_id"]')
      : document.querySelector('[data-testid="man-external_id"]');
    if (!manIdElement?.textContent) return null;
    const match = manIdElement.textContent.match(/\d+/);
    return match ? match[0] : null;
  }

  async function fetchFullUserProfile(userId) {
    try {
      const token = localStorage.getItem('token');
      if (!token) return { error: 'no_token' };
      const { json } = await pageFetchJson(`/api/operator/myProfile?user_id=${encodeURIComponent(userId)}&activeProfile=true`, {
        method: 'GET',
        headers: {
          Authorization: `Bearer ${token}`,
          'Content-Type': 'application/json',
        },
        timeout: 12000,
      });
      if (json && json.status && json.user_info) return json.user_info;
      return { error: 'invalid_response' };
    } catch (err) {
      console.error('PulseUserDetail: fetch error', err);
      return { error: 'network_error' };
    }
  }

  function formatTimestamp(ts) {
    if (ts == null || ts === 0) return '—';
    try {
      const d = new Date(ts * 1000);
      return d.toLocaleString();
    } catch {
      return String(ts);
    }
  }

  function formatDisplayValue(key, val) {
    if (val == null || val === '') return '';
    if (key === 'online') return Number(val) === 1 ? PULSE_USER_DETAIL_TEXTS.onlineStatus : PULSE_USER_DETAIL_TEXTS.offlineStatus;
    if (key === 'last_online') return formatTimestamp(val);
    return val;
  }

  function createPulseFieldHandle(label, value) {
    const row = document.createElement('div');
    row.style.cssText = 'display:flex;gap:12px;margin-bottom:6px;font-size:13px;';
    const lbl = document.createElement('span');
    lbl.style.cssText = 'min-width:132px;color:#6b7280;';
    const labelWrap = document.createElement('span');
    labelWrap.style.cssText = 'display:inline-flex;align-items:center;gap:6px;position:relative;flex-wrap:wrap;';
    const labelText = document.createElement('span');
    labelText.textContent = label + ':';
    labelWrap.appendChild(labelText);
    lbl.appendChild(labelWrap);
    const val = document.createElement('span');
    val.style.cssText = 'flex:1;color:#111827;word-break:break-word;';
    val.textContent = String(value ?? '');
    row.append(lbl, val);
    return { row, lbl, val };
  }

  function renderPulseField(parent, label, value) {
    if (value == null || value === '') return;
    const field = createPulseFieldHandle(label, value);
    parent.appendChild(field.row);
    return field;
  }

  function renderPulseSection(parent, title, data, keys) {
    if (!data) return;
    const hasAny = keys.some((k) => data[k] != null && data[k] !== '');
    if (!hasAny) return;
    const section = document.createElement('div');
    section.style.cssText = 'margin-bottom:20px;';
    const h3 = document.createElement('h3');
    h3.style.cssText = 'font-size:14px;font-weight:600;color:#374151;margin:0 0 10px 0;border-bottom:1px solid #e5e7eb;padding-bottom:6px;';
    h3.textContent = title;
    section.appendChild(h3);
    const content = document.createElement('div');
    content.style.cssText = 'padding-left:8px;';
    for (const key of keys) {
      const val = formatDisplayValue(key, data[key]);
      renderPulseField(content, pulseFieldLabel(key), val);
    }
    section.appendChild(content);
    parent.appendChild(section);
  }

  function closePulseUserDetailModal() {
    document.getElementById(PULSE_USER_DETAIL_MODAL_ID)?.remove();
  }

  function createPulseUserDetailModal() {
    closePulseUserDetailModal();
    const overlay = document.createElement('div');
    overlay.id = PULSE_USER_DETAIL_MODAL_ID;
    overlay.style.cssText = 'position:fixed;inset:0;background:rgba(0,0,0,.52);display:flex;align-items:center;justify-content:center;z-index:2147483646;font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,sans-serif;';
    const modal = document.createElement('div');
    modal.style.cssText = 'background:#fff;border-radius:14px;box-shadow:0 20px 60px rgba(0,0,0,.32);max-width:640px;width:min(92vw,640px);max-height:86vh;overflow:hidden;display:flex;flex-direction:column;';
    const header = document.createElement('div');
    header.style.cssText = 'padding:18px 22px;border-bottom:1px solid #e5e7eb;display:flex;align-items:center;justify-content:space-between;gap:12px;flex-shrink:0;';
    const titleEl = document.createElement('h2');
    titleEl.style.cssText = 'margin:0;font-size:18px;font-weight:700;color:#111827;';
    titleEl.textContent = PULSE_USER_DETAIL_TEXTS.modalTitle;
    const closeBtn = document.createElement('button');
    closeBtn.type = 'button';
    closeBtn.textContent = PULSE_USER_DETAIL_TEXTS.close;
    closeBtn.style.cssText = 'padding:8px 14px;font-size:13px;font-weight:600;color:#374151;background:#f3f4f6;border:none;border-radius:8px;cursor:pointer;';
    closeBtn.addEventListener('click', closePulseUserDetailModal);
    header.append(titleEl, closeBtn);
    const body = document.createElement('div');
    body.style.cssText = 'padding:22px;overflow-y:auto;flex:1;background:#fff;';
    modal.append(header, body);
    overlay.appendChild(modal);
    overlay.addEventListener('click', (e) => {
      if (e.target === overlay) closePulseUserDetailModal();
    });
    document.body.appendChild(overlay);
    return { overlay, body, titleEl, closeBtn };
  }


  function pulseMapSiteName(siteId) {
    return ({
      1:'SofiaDate.com',2:'MySpecialDates.com',5:'LoveForHeart.com',6:'AmourMeet.com',7:'OkAmour.com',8:'Avodate.com',
      9:'DateMpire.com',10:'FeelFlame.com',11:'LatiDate.com',12:'SakuraDate.com',13:'LatiDreams.com',14:'NaomiDate.com',
      15:'AmorPulse.com',16:'NikaDate.com',32:'MagnoliaDate.com'
    })[Number(siteId)] || (siteId ? `site_id: ${siteId}` : '—');
  }

  function pulseFormatDateOnly(value) {
    if (!value) return '—';
    const d = new Date(value);
    if (Number.isNaN(d.getTime())) return String(value);
    const dd = String(d.getDate()).padStart(2, '0');
    const mm = String(d.getMonth() + 1).padStart(2, '0');
    const yyyy = d.getFullYear();
    const hh = String(d.getHours()).padStart(2, '0');
    const mi = String(d.getMinutes()).padStart(2, '0');
    const ss = String(d.getSeconds()).padStart(2, '0');
    return `${dd}.${mm}.${yyyy}, ${hh}:${mi}:${ss}`;
  }

  function pulseExtractChatUidFromLocation() {
    const m = /^https:\/\/alpha\.date\/(?:chance|chat)\/([a-z0-9-]+)$/i.exec(location.href);
    return m ? m[1] : null;
  }

  function pulseExtractMails(js) {
    if (Array.isArray(js?.response?.mails)) return js.response.mails;
    if (Array.isArray(js?.response?.mails?.data)) return js.response.mails.data;
    if (Array.isArray(js?.response)) return js.response;
    return [];
  }

  function pulseGetMailDateStr(item) {
    const m = item?.mail || item;
    return m?.ma_date_created || m?.date_created || m?.created_at || m?.date || null;
  }

  function pulseGetMailDateMs(item) {
    const s = pulseGetMailDateStr(item);
    const ms = s ? Date.parse(s) : NaN;
    return Number.isFinite(ms) ? ms : NaN;
  }

  function pulseIsMailFromClient(item, maleExt) {
    const m = item?.mail || item;
    if (Number(m?.is_male) === 1) return true;
    const sid = m?.sender_external_id ?? m?.sender_id ?? m?.sender_internal_id ?? m?.from_id ?? m?.man_id ?? null;
    return Number(sid) === Number(maleExt);
  }

  const PULSE_CLIENT_META_CACHE_TTL = 10 * 60 * 1000;
  const pulseClientMetaMemCache = new Map();

  function pulseGetClientMetaCacheKey(chatUid, maleId) {
    return `${chatUid || ''}::${maleId || ''}`;
  }

  function pulseReadClientMetaCache(chatUid, maleId) {
    const key = pulseGetClientMetaCacheKey(chatUid, maleId);
    const now = Date.now();
    const mem = pulseClientMetaMemCache.get(key);
    if (mem && mem.data && (now - Number(mem.ts || 0) < PULSE_CLIENT_META_CACHE_TTL)) return mem.data;
    try {
      const raw = sessionStorage.getItem(`pulseClientMeta:${key}`);
      if (!raw) return null;
      const parsed = JSON.parse(raw);
      if (!parsed || !parsed.data || (now - Number(parsed.ts || 0) >= PULSE_CLIENT_META_CACHE_TTL)) {
        sessionStorage.removeItem(`pulseClientMeta:${key}`);
        return null;
      }
      pulseClientMetaMemCache.set(key, parsed);
      return parsed.data;
    } catch {
      return null;
    }
  }

  function pulseWriteClientMetaCache(chatUid, maleId, data) {
    if (!data) return;
    const key = pulseGetClientMetaCacheKey(chatUid, maleId);
    const payload = { ts: Date.now(), data };
    pulseClientMetaMemCache.set(key, payload);
    try { sessionStorage.setItem(`pulseClientMeta:${key}`, JSON.stringify(payload)); } catch {}
  }

  function pulseExtractFemaleExt(rows) {
    if (!Array.isArray(rows)) return null;
    for (const row of rows) {
      if (Number(row?.is_male) === 1) return row?.recipient_external_id ?? row?.sender_external_id ?? null;
      if (Number(row?.is_male) === 0) return row?.sender_external_id ?? row?.recipient_external_id ?? null;
    }
    return null;
  }

  function pulseGetValidHistoryTs(row) {
    const raw = row?.date_created || row?.created_at || null;
    const ts = raw ? Date.parse(raw) : NaN;
    return Number.isFinite(ts) && ts > 0 ? ts : NaN;
  }

  function pulseGetEarliestHistoryRaw(rows) {
    if (!Array.isArray(rows) || !rows.length) return null;
    let bestRaw = null;
    let bestTs = Infinity;
    for (const row of rows) {
      const ts = pulseGetValidHistoryTs(row);
      if (!Number.isFinite(ts)) continue;
      if (ts < bestTs) {
        bestTs = ts;
        bestRaw = row?.date_created || row?.created_at || null;
      }
    }
    return bestRaw;
  }

  async function pulseFetchHistoryPage(headers, chatUid, page) {
    const { json } = await pageFetchJson('/api/chatList/chatHistory', {
      method: 'POST',
      headers,
      body: JSON.stringify({ chat_id: chatUid, page }),
      timeout: 12000,
    });
    return Array.isArray(json?.response) ? json.response : [];
  }

  async function pulseFindLastNonEmptyHistoryPage(headers, chatUid, maxPage = 200) {
    let rows = await pulseFetchHistoryPage(headers, chatUid, 1).catch(() => []);
    if (!rows.length) return { page: 0, rows: [] };

    let lastNonEmptyPage = 1;
    let lastNonEmptyRows = rows;
    let prev = 1;
    let curr = 2;

    while (curr <= maxPage) {
      rows = await pulseFetchHistoryPage(headers, chatUid, curr).catch(() => []);
      if (!rows.length) break;
      lastNonEmptyPage = curr;
      lastNonEmptyRows = rows;
      prev = curr;
      curr = Math.min(curr * 2, maxPage + 1);
    }

    let left = Math.min(prev + 1, maxPage);
    let right = Math.min(curr - 1, maxPage);
    while (left <= right) {
      const mid = Math.floor((left + right) / 2);
      rows = await pulseFetchHistoryPage(headers, chatUid, mid).catch(() => []);
      if (rows.length) {
        lastNonEmptyPage = mid;
        lastNonEmptyRows = rows;
        left = mid + 1;
      } else {
        right = mid - 1;
      }
    }

    return { page: lastNonEmptyPage, rows: lastNonEmptyRows };
  }

  function pulseGetMailboxPages(json) {
    const pages = Number(json?.response?.pages ?? json?.pages ?? 0);
    return Number.isFinite(pages) && pages > 0 ? pages : 1;
  }

  async function pulseFindFirstLetterRaw(headers, femaleExt, maleId) {
    if (!femaleExt || !maleId) return null;
    const firstResp = await pageFetchJson('/api/mailbox/mails', {
      method: 'POST',
      headers,
      body: JSON.stringify({ user_id: femaleExt, man_id: maleId, folder: 'dialog', page: 1 }),
      timeout: 12000,
    }).then(({ json }) => json).catch(() => null);
    if (!firstResp || firstResp.status === false) return null;

    const totalPages = Math.min(200, pulseGetMailboxPages(firstResp));
    const checked = new Set();
    for (let page = totalPages; page >= 1; page--) {
      if (checked.has(page)) continue;
      checked.add(page);
      const json = page === 1
        ? firstResp
        : await pageFetchJson('/api/mailbox/mails', {
            method: 'POST',
            headers,
            body: JSON.stringify({ user_id: femaleExt, man_id: maleId, folder: 'dialog', page }),
            timeout: 12000,
          }).then(({ json }) => json).catch(() => null);
      if (!json || json.status === false) continue;
      const items = pulseExtractMails(json);
      if (!items.length) continue;
      const first = items
        .filter((it) => pulseIsMailFromClient(it, maleId))
        .filter((it) => Number.isFinite(pulseGetMailDateMs(it)))
        .sort((a, b) => pulseGetMailDateMs(a) - pulseGetMailDateMs(b))[0];
      if (first) return pulseGetMailDateStr(first) || null;
    }
    return null;
  }

  async function pulseFetchClientMeta() {
    const token = localStorage.getItem('token') || '';
    const chatUid = pulseExtractChatUidFromLocation();
    const maleId = getMaleIdFromPage();
    if (!token || !chatUid || !maleId) return null;

    const cached = pulseReadClientMetaCache(chatUid, maleId);
    if (cached) return cached;

    const headers = {
      Accept: 'application/json, text/plain, */*',
      'Content-Type': 'application/json',
      Authorization: `Bearer ${token}`,
    };

    const firstPageReq = pulseFetchHistoryPage(headers, chatUid, 1).catch(() => []);
    const userDetailReq = pageFetchJson('/api/chatList/userDetail', {
      method: 'POST',
      headers,
      body: JSON.stringify({ chat_uid: [chatUid] }),
      timeout: 12000,
    }).then(({ json }) => json).catch(() => null);

    const firstPageRows = await firstPageReq;
    if (!firstPageRows.length) return null;
    const femaleExt = pulseExtractFemaleExt(firstPageRows);

    const historyLastReq = pulseFindLastNonEmptyHistoryPage(headers, chatUid, 200).catch(() => ({ page: 1, rows: firstPageRows }));
    const firstLetterReq = femaleExt ? pulseFindFirstLetterRaw(headers, femaleExt, maleId).catch(() => null) : Promise.resolve(null);

    const [historyLast, userDetailJson, firstLetterRaw] = await Promise.all([historyLastReq, userDetailReq, firstLetterReq]);
    const lastRows = Array.isArray(historyLast?.rows) && historyLast.rows.length ? historyLast.rows : firstPageRows;
    const firstChatRaw = pulseGetEarliestHistoryRaw(lastRows) || pulseGetEarliestHistoryRaw(firstPageRows) || null;

    const ud = (userDetailJson && Array.isArray(userDetailJson.response) ? userDetailJson.response[0] : null) || {};
    const siteName = pulseMapSiteName(ud.site_id ?? ud.man_site_id ?? ud.male_site_id ?? ud.site ?? null);

    const startMsCandidates = [firstChatRaw, firstLetterRaw].map((v) => v ? Date.parse(v) : NaN).filter((v) => Number.isFinite(v));
    const startedRaw = startMsCandidates.length ? new Date(Math.min(...startMsCandidates)).toISOString() : null;

    const meta = {
      siteName,
      maleId,
      femaleExt,
      chatUid,
      firstChat: firstChatRaw ? pulseFormatDateOnly(firstChatRaw) : '—',
      firstLetter: firstLetterRaw ? pulseFormatDateOnly(firstLetterRaw) : 'no letters',
      started: startedRaw ? pulseFormatDateOnly(startedRaw) : (firstChatRaw ? pulseFormatDateOnly(firstChatRaw) : (firstLetterRaw ? pulseFormatDateOnly(firstLetterRaw) : '—')),
    };

    pulseWriteClientMetaCache(chatUid, maleId, meta);
    return meta;
  }

  function createPulseClientMetaBlock() {
    const wrap = document.createElement('div');
    wrap.style.cssText = 'margin-top:8px;padding:10px 12px;border-radius:10px;background:#f8fafc;border:1px solid #e5e7eb;';
    const title = document.createElement('div');
    title.style.cssText = 'font-size:12px;font-weight:700;color:#374151;margin:0 0 8px 0;text-transform:uppercase;letter-spacing:.04em;';
    title.textContent = 'Дополнительная информация';
    wrap.appendChild(title);
    const content = document.createElement('div');
    content.style.cssText = 'display:flex;flex-direction:column;gap:6px;';
    wrap.appendChild(content);
    renderPulseField(content, 'Сайт регистрации', 'Загрузка...');
    return { wrap, content };
  }

  async function populatePulseClientMeta(content) {
    const renderFallback = () => {
      content.innerHTML = '';
      renderPulseField(content, 'Сайт регистрации', '—');
      renderPulseField(content, 'Начало общения', '—');
      renderPulseField(content, 'Первый леттер', '—');
      renderPulseField(content, 'Первый чат', '—');
    };
    try {
      const meta = await pulseFetchClientMeta();
      content.innerHTML = '';
      if (!meta) {
        renderFallback();
        return null;
      }
      renderPulseField(content, 'Сайт регистрации', meta.siteName || '—');
      renderPulseField(content, 'Начало общения', meta.started || '—');
      renderPulseField(content, 'Первый леттер', meta.firstLetter || '—');
      renderPulseField(content, 'Первый чат', meta.firstChat || '—');
      return meta;
    } catch {
      renderFallback();
      return null;
    }
  }

  function pulseDownloadBlob(lines, filename) {
    if (!Array.isArray(lines) || !lines.length) {
      alert('Ничего не найдено.');
      return;
    }
    const blob = new Blob([lines.join('\n')], { type: 'text/plain;charset=utf-8' });
    const url = URL.createObjectURL(blob);
    Object.assign(document.createElement('a'), { href: url, download: filename }).click();
    setTimeout(() => URL.revokeObjectURL(url), 800);
  }

  function pulseSetDownloadButtonState(button, busy) {
    if (!button) return;
    button.textContent = busy ? 'Стоп' : (button.dataset.defaultLabel || 'Скачать');
    button.style.background = busy ? '#d32f2f' : 'rgba(0,122,255,.08)';
    button.style.borderColor = busy ? '#d32f2f' : '#d1d5db';
    button.style.color = busy ? '#fff' : '#1f2937';
  }

  async function pulseDownloadHistory(kind, ctx) {
    if (!ctx?.chatUid || !ctx?.token) return;
    const stopKey = kind === 'chat' ? '__pulseStopChatDownload' : '__pulseStopLettersDownload';
    const button = kind === 'chat' ? ctx.chatButton : ctx.lettersButton;
    const otherButton = kind === 'chat' ? ctx.lettersButton : ctx.chatButton;
    if (window[stopKey] === true) return;
    if (button?.dataset.busy === '1') {
      window[stopKey] = true;
      return;
    }
    window[stopKey] = false;
    if (button) button.dataset.busy = '1';
    pulseSetDownloadButtonState(button, true);
    if (otherButton) otherButton.disabled = true;
    const headers = {
      Accept: 'application/json, text/plain, */*',
      'Content-Type': 'application/json',
      Authorization: `Bearer ${ctx.token}`,
    };
    const cutoff = ctx.dateInput?.value ? Date.parse(ctx.dateInput.value) : -Infinity;
    const getTs = (item) => Date.parse(item?.date_created || item?.created_at || item?.ma_date_created || item?.date || 0);
    const finish = () => {
      window[stopKey] = false;
      if (button) button.dataset.busy = '0';
      pulseSetDownloadButtonState(button, false);
      if (otherButton) otherButton.disabled = false;
    };
    try {
      if (kind === 'chat') {
        const collected = [];
        for (let page = 1; !window[stopKey]; page += 2) {
          const results = await Promise.allSettled([1, 2].map((offset) => pageFetchJson('/api/chatList/chatHistory', {
            method: 'POST',
            headers,
            body: JSON.stringify({ chat_id: ctx.chatUid, page: page + offset - 1 }),
            timeout: 15000,
          }).then(({ json }) => json)));
          let hasFullPage = false;
          let minTs = Infinity;
          for (const result of results) {
            if (result.status !== 'fulfilled' || !result.value?.status) continue;
            const rows = Array.isArray(result.value.response) ? result.value.response : [];
            if (rows.length === 20) hasFullPage = true;
            for (const row of rows) {
              const ts = getTs(row);
              if (Number.isFinite(ts)) minTs = Math.min(minTs, ts);
              if (String(row?.message_type || '').trim() === 'SENT_TEXT' && String(row?.message_content || '').trim()) {
                if (ts < cutoff) continue;
                collected.push(row);
              }
            }
          }
          if (minTs < cutoff || !hasFullPage) break;
        }
        finish();
        const lines = collected
          .sort((a, b) => getTs(a) - getTs(b))
          .map((row) => `${Number(row?.is_male) === 1 ? 'Client' : 'Operator'}\n${new Date(getTs(row)).toLocaleString()}\n${String(row?.message_content || '').trim()}\n`);
        pulseDownloadBlob(lines, `chat_${ctx.chatUid}.txt`);
        return;
      }
      if (!ctx.femaleExt || !ctx.maleId) {
        finish();
        alert('Не удалось определить профили для писем.');
        return;
      }
      const firstPage = await pageFetchJson('/api/mailbox/mails', {
        method: 'POST',
        headers,
        body: JSON.stringify({ user_id: ctx.femaleExt, man_id: ctx.maleId, folder: 'dialog', page: 1 }),
        timeout: 15000,
      }).then(({ json }) => json);
      if (!firstPage?.status) {
        finish();
        return;
      }
      const totalPages = firstPage?.response?.pages || 1;
      const all = [...(firstPage?.response?.mails || [])];
      for (let page = 2; page <= totalPages && !window[stopKey]; page += 2) {
        const results = await Promise.allSettled([page, page + 1].map((current) => current <= totalPages ? pageFetchJson('/api/mailbox/mails', {
          method: 'POST',
          headers,
          body: JSON.stringify({ user_id: ctx.femaleExt, man_id: ctx.maleId, folder: 'dialog', page: current }),
          timeout: 15000,
        }).then(({ json }) => json) : Promise.resolve(null)));
        for (const result of results) {
          if (result.status === 'fulfilled' && result.value?.status && Array.isArray(result.value?.response?.mails)) {
            all.push(...result.value.response.mails);
          }
        }
        const last = all.at(-1)?.mail;
        if (last && getTs(last) < cutoff) break;
      }
      finish();
      const lines = all
        .map((item) => item?.mail || item)
        .filter((mail) => getTs(mail) >= cutoff)
        .sort((a, b) => getTs(a) - getTs(b))
        .map((mail) => `${mail?.sender_name || 'Unknown'}, ${mail?.sender_age || '?'}\n${new Date(getTs(mail)).toLocaleString()}\n${String(mail?.message_content || '[-без текста-]').trim()}\n`);
      pulseDownloadBlob(lines, `letters_${ctx.femaleExt}_${ctx.maleId}.txt`);
    } catch (err) {
      finish();
      alert('Ошибка скачивания: ' + (err?.message || err));
    }
  }

  function createPulseDownloadPanel(meta) {
    const wrap = document.createElement('div');
    wrap.style.cssText = 'display:flex;flex-direction:column;gap:10px;min-width:210px;align-self:flex-start;';
    const btnStyle = 'padding:8px 12px;border:1px solid #d1d5db;background:rgba(0,122,255,.08);color:#1f2937;border-radius:10px;font-size:13px;font-weight:600;cursor:pointer;text-align:center;';
    const chatButton = document.createElement('button');
    chatButton.type = 'button';
    chatButton.dataset.defaultLabel = 'Скачать чат';
    chatButton.textContent = 'Скачать чат';
    chatButton.style.cssText = btnStyle;
    const lettersButton = document.createElement('button');
    lettersButton.type = 'button';
    lettersButton.dataset.defaultLabel = 'Скачать письма';
    lettersButton.textContent = 'Скачать письма';
    lettersButton.style.cssText = btnStyle;
    const dateWrap = document.createElement('label');
    dateWrap.style.cssText = 'display:flex;flex-direction:column;gap:4px;font-size:12px;color:#6b7280;';
    dateWrap.append('До даты:');
    const dateInput = document.createElement('input');
    dateInput.type = 'datetime-local';
    dateInput.style.cssText = 'padding:7px 8px;border:1px solid #d1d5db;border-radius:10px;font-size:13px;color:#111827;background:#fff;';
    dateWrap.appendChild(dateInput);
    const ctx = {
      token: localStorage.getItem('token') || '',
      chatUid: pulseExtractChatUidFromLocation(),
      maleId: getMaleIdFromPage(),
      femaleExt: meta?.femaleExt || null,
      dateInput,
      chatButton,
      lettersButton,
    };
    chatButton.addEventListener('click', () => pulseDownloadHistory('chat', ctx));
    lettersButton.addEventListener('click', () => pulseDownloadHistory('letters', ctx));
    wrap.append(chatButton, lettersButton, dateWrap);
    return wrap;
  }

  function renderPulseUserInfo(body, userInfo) {
    body.innerHTML = '';
    const detail = userInfo?.user_detail;
    const ref = userInfo?.user_reference;
    const match = userInfo?.user_match;
    const hobbies = userInfo?.user_hobby;
    const hobbyMatch = userInfo?.user_hobby_match;
    const content = userInfo?.user_content;

    if (detail) {
      const section = document.createElement('div');
      section.style.cssText = 'margin-bottom:20px;';
      const h3 = document.createElement('h3');
      h3.style.cssText = 'font-size:14px;font-weight:600;color:#374151;margin:0 0 10px 0;border-bottom:1px solid #e5e7eb;padding-bottom:6px;';
      h3.textContent = PULSE_USER_DETAIL_TEXTS.sectionDetail;
      section.appendChild(h3);

      const topRow = document.createElement('div');
      topRow.style.cssText = 'display:flex;gap:16px;align-items:flex-start;margin-bottom:16px;';
      if (detail.photo_link) {
        const img = document.createElement('img');
        img.src = detail.photo_link;
        img.alt = detail.name || 'Photo';
        img.style.cssText = 'width:88px;height:88px;object-fit:cover;border-radius:10px;flex:0 0 auto;background:#f3f4f6;';
        topRow.appendChild(img);
      }
      const infoCol = document.createElement('div');
      infoCol.style.cssText = 'flex:1;min-width:0;';
      const detailKeys = ['external_id', 'name', 'age', 'country_name', 'b_year', 'b_month', 'b_day', 'online', 'last_online'];
      for (const key of detailKeys) {
        const val = formatDisplayValue(key, detail[key]);
        renderPulseField(infoCol, pulseFieldLabel(key), val);
      }
      topRow.appendChild(infoCol);
      const actionsCol = document.createElement('div');
      actionsCol.style.cssText = 'display:flex;flex-direction:column;gap:10px;align-self:flex-start;';
      topRow.appendChild(actionsCol);
      section.appendChild(topRow);
      const clientMeta = createPulseClientMetaBlock();
      section.appendChild(clientMeta.wrap);
      body.appendChild(section);
      populatePulseClientMeta(clientMeta.content).then((meta) => {
        actionsCol.replaceChildren(createPulseDownloadPanel(meta));
      }).catch(() => {
        actionsCol.replaceChildren(createPulseDownloadPanel(null));
      });
    }

    renderPulseSection(body, PULSE_USER_DETAIL_TEXTS.sectionReference, ref, [
      'city_name', 'height', 'body', 'hair', 'eye', 'zodiac', 'alcohol', 'smoke',
      'education', 'occupation', 'religion', 'marital', 'children', 'morechildren', 'reason', 'summary', 'looking',
    ]);

    renderPulseSection(body, PULSE_USER_DETAIL_TEXTS.sectionMatch, match, [
      'girls_age_from', 'girls_age_to', 'girls_height_from_', 'girls_height_to_',
      'body', 'hair', 'eye', 'education', 'occupation', 'religion', 'children', 'morechildren', 'alcohol', 'smoke',
    ]);

    if (Array.isArray(hobbies) && hobbies.length) {
      const section = document.createElement('div');
      section.style.cssText = 'margin-bottom:20px;';
      const h3 = document.createElement('h3');
      h3.style.cssText = 'font-size:14px;font-weight:600;color:#374151;margin:0 0 10px 0;border-bottom:1px solid #e5e7eb;padding-bottom:6px;';
      h3.textContent = PULSE_USER_DETAIL_TEXTS.sectionHobbies;
      section.appendChild(h3);
      const list = document.createElement('div');
      list.style.cssText = 'display:flex;flex-wrap:wrap;gap:6px;';
      for (const item of hobbies) {
        const tag = document.createElement('span');
        tag.style.cssText = 'background:#ede9fe;color:#5b21b6;padding:4px 10px;border-radius:999px;font-size:12px;';
        tag.textContent = item?.hobbie || item;
        list.appendChild(tag);
      }
      section.appendChild(list);
      body.appendChild(section);
    }

    if (Array.isArray(hobbyMatch) && hobbyMatch.length) {
      const section = document.createElement('div');
      section.style.cssText = 'margin-bottom:20px;';
      const h3 = document.createElement('h3');
      h3.style.cssText = 'font-size:14px;font-weight:600;color:#374151;margin:0 0 10px 0;border-bottom:1px solid #e5e7eb;padding-bottom:6px;';
      h3.textContent = PULSE_USER_DETAIL_TEXTS.sectionHobbyMatch;
      section.appendChild(h3);
      const list = document.createElement('div');
      list.style.cssText = 'display:flex;flex-wrap:wrap;gap:6px;';
      for (const item of hobbyMatch) {
        const tag = document.createElement('span');
        tag.style.cssText = 'background:#dcfce7;color:#166534;padding:4px 10px;border-radius:999px;font-size:12px;';
        tag.textContent = item?.hobbie || item;
        list.appendChild(tag);
      }
      section.appendChild(list);
      body.appendChild(section);
    }

    if (Array.isArray(content) && content.length) {
      const imageItems = content.filter((item) => item?.content_type === 'image' && item?.link);
      if (imageItems.length) {
        const section = document.createElement('div');
        section.style.cssText = 'margin-bottom:20px;';
        const h3 = document.createElement('h3');
        h3.style.cssText = 'font-size:14px;font-weight:600;color:#374151;margin:0 0 10px 0;border-bottom:1px solid #e5e7eb;padding-bottom:6px;';
        h3.textContent = PULSE_USER_DETAIL_TEXTS.sectionContent;
        section.appendChild(h3);
        const grid = document.createElement('div');
        grid.style.cssText = 'display:grid;grid-template-columns:repeat(auto-fill,minmax(88px,1fr));gap:8px;';
        for (const item of imageItems) {
          const wrap = document.createElement('a');
          wrap.href = item.link;
          wrap.target = '_blank';
          wrap.rel = 'noopener noreferrer';
          const img = document.createElement('img');
          img.src = item.link;
          img.style.cssText = 'width:100%;aspect-ratio:1;object-fit:cover;border-radius:8px;background:#f3f4f6;';
          wrap.appendChild(img);
          grid.appendChild(wrap);
        }
        section.appendChild(grid);
        body.appendChild(section);
      }
    }
  }

  async function openPulseUserDetail() {
    if (!pulseHasFeatureAuth()) {
      pulseRemoveQuickUi();
      return;
    }
    const userId = getMaleIdFromPage();
    const token = localStorage.getItem('token');
    const { body } = createPulseUserDetailModal();
    if (!userId) {
      body.innerHTML = `<p style="color:#6b7280;margin:0;">${PULSE_USER_DETAIL_TEXTS.noUserId}</p>`;
      return;
    }
    if (!token) {
      body.innerHTML = `<p style="color:#6b7280;margin:0;">${PULSE_USER_DETAIL_TEXTS.noToken}</p>`;
      return;
    }
    body.innerHTML = `<p style="color:#6b7280;margin:0;">${PULSE_USER_DETAIL_TEXTS.loading}</p>`;
    const result = await fetchFullUserProfile(userId);
    if (result?.error) {
      body.innerHTML = `<p style="color:#dc2626;margin:0;">${PULSE_USER_DETAIL_TEXTS.error}</p>`;
      return;
    }
    renderPulseUserInfo(body, result);
  }

  function createQuickButton() {
    const btn = document.createElement('button');
    btn.id = PULSE_QUICK_ID;
    btn.type = 'button';
    btn.title = PULSE_USER_DETAIL_TEXTS.buttonTitle;
    btn.setAttribute('aria-label', PULSE_USER_DETAIL_TEXTS.buttonTitle);
    btn.innerHTML = `<span class="pulse-quick-bg"></span><img src="${PULSE_QUICK_ICON}" alt="Pulse">`;
    btn.addEventListener('click', async (event) => {
      event.preventDefault();
      event.stopPropagation();
      await openPulseUserDetail();
    });
    return btn;
  }

  function createReportsQuickButton() {
    const btn = document.createElement('button');
    btn.id = PULSE_REPORTS_QUICK_ID;
    btn.type = 'button';
    btn.title = 'Reports';
    btn.setAttribute('aria-label', 'Reports');
    btn.innerHTML = `<span class="pulse-quick-bg"></span><img src="${PULSE_REPORTS_QUICK_ICON}" alt="Reports">`;
    btn.addEventListener('click', (event) => {
      event.preventDefault();
      event.stopPropagation();
      if (!pulseHasFeatureAuth()) {
        pulseRemoveQuickUi();
        return;
      }
      console.log('Pulse Reports button clicked');
    });
    return btn;
  }

  function getPreferredQuickButtonAnchor(host, button, fallbackAnchor) {
    if (!host) return fallbackAnchor || null;

    const children = [...host.children].filter((child) => child !== button && isVisible(child));
    if (!children.length) return fallbackAnchor || null;

    const textPriority = [
      /^(?:\d+\s*)?символ/i,
      /^symbols?$/i,
      /ПЕРЕВОДИТЬ|TRANSLATE/i,
      /Отправлят|Отправить|Send/i,
    ];

    for (const rx of textPriority) {
      const match = children.find((child) => rx.test((child.textContent || '').replace(/\s+/g, ' ').trim()));
      if (match) return match;
    }

    const switchLike = children.find((child) => {
      const text = (child.textContent || '').replace(/\s+/g, ' ').trim();
      if (/ПЕРЕВОДИТЬ|TRANSLATE/i.test(text)) return true;
      return !!child.querySelector('input[type="checkbox"], input[type="radio"], .el-switch, .switch, [role="switch"]');
    });
    if (switchLike) return switchLike;

    if (fallbackAnchor && fallbackAnchor !== button && fallbackAnchor.parentNode === host) {
      const idx = children.indexOf(fallbackAnchor);
      if (idx > 0) {
        const prev = children[idx - 1];
        const prevRect = prev.getBoundingClientRect();
        const anchorRect = fallbackAnchor.getBoundingClientRect();
        if (prevRect.right <= anchorRect.left + 24) return fallbackAnchor;
      }
    }

    return fallbackAnchor || null;
  }

  function isPulseRealChatContext() {
    const chatUid = pulseExtractChatUidFromLocation();
    if (!chatUid) return false;

    if (!/^\/(?:chance|chat)\/[a-z0-9-]+$/i.test(location.pathname)) return false;

    const header = typeof getCurrentChatHeaderSafe === 'function'
      ? getCurrentChatHeaderSafe()
      : getCurrentChatHeader();
    if (!header || !isVisible(header)) return false;

    const chatList = document.querySelector('[data-testid="chat-list"]');
    if (chatList && chatList.contains(header)) return false;

    const manIdEl = header.querySelector('[data-testid="man-external_id"]');
    const womanIdEl = header.querySelector('[data-testid="woman-external_id"]');
    if (!manIdEl || !womanIdEl) return false;

    const composer = [...document.querySelectorAll('textarea')].find(isVisible)
      || document.querySelector('[data-testid="chat-message-input"]')
      || document.querySelector('[contenteditable="true"]');
    if (!composer) return false;

    return true;
  }

  function injectPulseQuickButton() {
    const existing = document.getElementById(PULSE_QUICK_ID);
    const existingReports = document.getElementById(PULSE_REPORTS_QUICK_ID);
    if (!pulseHasFeatureAuth() || !isPulseRealChatContext()) {
      if (existing) existing.remove();
      if (existingReports) existingReports.remove();
      return;
    }
    ensurePulseQuickStyle();
    const target = findToolbarHost();
    if (!target || !target.host || !isVisible(target.host)) {
      if (existing) existing.remove();
      if (existingReports) existingReports.remove();
      return;
    }

    const button = existing || createQuickButton();
    const reportsButton = existingReports || createReportsQuickButton();
    if (target.host) {
      try {
        const hostStyle = getComputedStyle(target.host);
        if (hostStyle.display.includes('flex')) {
          target.host.style.alignItems = 'center';
          target.host.style.gap = target.host.style.gap || '8px';
        }
      } catch {}
    }

    button.style.alignSelf = 'center';
    button.style.marginLeft = '10px';
    button.style.marginRight = '0';
    reportsButton.style.alignSelf = 'center';
    reportsButton.style.marginLeft = '0';
    reportsButton.style.marginRight = '14px';

    const fallbackAnchor = target.anchor && target.anchor !== button && target.anchor !== reportsButton && target.anchor.parentNode === target.host
      ? target.anchor
      : [...target.host.children].find((child) => child !== button && child !== reportsButton && isVisible(child));
    const anchor = getPreferredQuickButtonAnchor(target.host, button, fallbackAnchor);

    if (anchor) {
      if (button.parentNode !== target.host || button.nextSibling !== reportsButton || reportsButton.nextSibling !== anchor) {
        target.host.insertBefore(button, anchor);
        target.host.insertBefore(reportsButton, anchor);
      }
    } else {
      if (button.parentNode !== target.host) target.host.appendChild(button);
      if (reportsButton.parentNode !== target.host || reportsButton.previousSibling !== button) target.host.appendChild(reportsButton);
    }
  }

  function initPulseQuickButton() {
    let timer = null;
    const schedule = () => {
      clearTimeout(timer);
      timer = setTimeout(injectPulseQuickButton, 120);
    };
    schedule();
    const observer = new MutationObserver(schedule);
    observer.observe(document.body, { childList: true, subtree: true, characterData: true });
    window.addEventListener('resize', schedule, { passive: true });
    window.addEventListener('hashchange', schedule, { passive: true });
    window.addEventListener('popstate', schedule, { passive: true });
    try {
      chrome.storage.onChanged.addListener((changes, area) => {
        if (area !== 'local') return;
        if (changes.pulsarAuth || changes.ahSet) schedule();
      });
    } catch {}
  }

  if (location.href.includes('alpha.date')) {
    if (document.readyState === 'loading') document.addEventListener('DOMContentLoaded', initPulseQuickButton, { once: true });
    else initPulseQuickButton();
  }
})();;


(() => {
  const REPORTS_KEY = 'ahReportsV1';
  const REPORT_MODAL_ID = 'pulse-report-editor-overlay';
  const REPORT_ROW_SNIP = 120;
  const REPORTS_BTN_ID = 'pulse-quick-open-reports';

  function escHtml(v) {
    return String(v ?? '').replace(/[&<>"']/g, (m) => ({ '&':'&amp;', '<':'&lt;', '>':'&gt;', '"':'&quot;', "'":'&#39;' }[m]));
  }

  function todayKey() {
    const d = new Date();
    const y = d.getFullYear();
    const m = String(d.getMonth() + 1).padStart(2, '0');
    const day = String(d.getDate()).padStart(2, '0');
    return `${y}-${m}-${day}`;
  }

  function formatHumanDate(dateKey) {
    if (!dateKey) return '—';
    const parts = String(dateKey).split('-');
    if (parts.length !== 3) return dateKey;
    return `${parts[2]}.${parts[1]}.${parts[0]}`;
  }

  function getCurrentChatUidSafe() {
    const segments = String(location.pathname || '').split('/').filter(Boolean);
    const last = segments[segments.length - 1] || '';
    return /^[a-z0-9-]+$/i.test(last) ? last : null;
  }

  function getCurrentChatHeaderSafe() {
    const chatList = document.querySelector('[data-testid="chat-list"]');
    const all = document.querySelectorAll('[data-testid="chat-header"]');
    for (const el of all) {
      if (chatList && chatList.contains(el)) continue;
      return el;
    }
    return all[0] || document.querySelector('[data-testid="chat-header"]');
  }

  function extractNumberFromEl(selector, root) {
    const el = (root || document).querySelector(selector);
    const txt = String(el?.textContent || '');
    const m = txt.match(/\d+/);
    return m ? m[0] : null;
  }

  function textFromEl(selector, root) {
    const el = (root || document).querySelector(selector);
    return String(el?.textContent || '').replace(/\s+/g, ' ').trim() || null;
  }

  function placeTextFromEl(selector, root) {
    const el = (root || document).querySelector(selector);
    if (!el) return null;
    const clone = el.cloneNode(true);
    try { clone.querySelector(`[${CLOCK_ATTR}]`)?.remove(); } catch {}
    return String(clone.textContent || '').replace(/\s+/g, ' ').trim() || null;
  }

  function stripLocalTimeFromPlace(text) {
    let s = String(text || '').replace(/\s+/g, ' ').trim();
    if (!s) return '';
    s = s.replace(/\s*\d{1,2}:\d{2}\s*-\s*\d{1,2}:\d{2}\s*$/g, '');
    s = s.replace(/\s*[\(\[]?\d{1,2}:\d{2}[\)\]]?\s*$/g, '');
    s = s.replace(/\s+/g, ' ').trim();
    return s;
  }

  function cleanPlaceText(text) {
    return stripLocalTimeFromPlace(String(text || '').replace(/\s+/g, ' ').trim()) || null;
  }

  async function getWomanProfileFromStorage(womanId) {
    return new Promise((resolve) => {
      try {
        chrome.storage.local.get(['profiles'], (result) => {
          const profiles = Array.isArray(result?.profiles) ? result.profiles : [];
          resolve(profiles.find((p) => p && String(p.external_id) === String(womanId)) || null);
        });
      } catch {
        resolve(null);
      }
    });
  }

  async function fetchChatContext() {
    const header = getCurrentChatHeaderSafe();
    const chatUid = getCurrentChatUidSafe();
    const manId = extractNumberFromEl('[data-testid="man-external_id"]', header) || extractNumberFromEl('[data-testid="man-external_id"]', document);
    const womanId = extractNumberFromEl('[data-testid="woman-external_id"]', header) || extractNumberFromEl('[data-testid="woman-external_id"]', document);
    const manName = textFromEl('[data-testid="man-name"]', header) || textFromEl('[data-testid="man-name"]', document) || 'Unknown';
    const womanNameDom = textFromEl('[data-testid="woman-name"]', header) || textFromEl('[data-testid="woman-name"]', document);
    const manPlaceDom = cleanPlaceText(placeTextFromEl('[data-testid="man-place"]', header) || placeTextFromEl('[data-testid="man-place"]', document));
    const womanPlaceDom = cleanPlaceText(placeTextFromEl('[data-testid="woman-place"]', header) || placeTextFromEl('[data-testid="woman-place"]', document));

    let womanName = womanNameDom || 'Unknown';
    let womanPlace = womanPlaceDom || null;
    if (womanId) {
      const profile = await getWomanProfileFromStorage(womanId);
      if (profile) {
        womanName = String(profile.name || womanName || 'Unknown').trim() || 'Unknown';
        if (!womanPlace) {
          const city = String(profile.city || '').trim();
          const country = String(profile.country_name || profile.country_code || '').trim();
          womanPlace = [city, country].filter(Boolean).join(', ') || null;
        }
      }
    }

    let manPlace = manPlaceDom || null;
    if (!manPlace && chatUid && typeof ensureManDetailForChatUid === 'function') {
      try {
        const ud = await ensureManDetailForChatUid(chatUid);
        const city = String(ud?.city || '').trim();
        const country = String(ud?.country_name || ud?.country_code || '').trim();
        manPlace = [city, country].filter(Boolean).join(', ') || null;
      } catch {}
    }

    return {
      chatUid,
      dateKey: todayKey(),
      manName,
      manId: manId || '',
      manPlace: manPlace || '—',
      womanName,
      womanId: womanId || '',
      womanPlace: womanPlace || '—'
    };
  }

  async function readReports() {
    const data = await st.get([REPORTS_KEY]);
    return Array.isArray(data?.[REPORTS_KEY]) ? data[REPORTS_KEY] : [];
  }

  async function writeReports(items) {
    await st.set({ [REPORTS_KEY]: Array.isArray(items) ? items : [] });
  }

  function reportSort(a, b) {
    return String(b.updatedAt || '').localeCompare(String(a.updatedAt || '')) || String(b.dateKey || '').localeCompare(String(a.dateKey || ''));
  }

  function buildReportTitle(item) {
    return `${item?.manName || 'Unknown'} и ${item?.womanName || 'Unknown'}`;
  }

  function buildReportId(chatUid, dateKey) {
    return `${chatUid || 'nochat'}__${dateKey || todayKey()}`;
  }

  function stripReportHeaderHtml(html) {
    const div = document.createElement('div');
    div.innerHTML = html || '';
    div.querySelectorAll('[data-report-header="1"]').forEach((node) => node.remove());
    return div.innerHTML;
  }

  function plainFromHtml(html) {
    const div = document.createElement('div');
    div.innerHTML = html || '';
    return String(div.textContent || '').replace(/\s+/g, ' ').trim();
  }

  function reportBodyTextFromHtml(html) {
    const div = document.createElement('div');
    div.innerHTML = stripReportHeaderHtml(html);
    return normalizeReportBodyText(String(div.textContent || ''));
  }

  function normalizeReportBodyText(text) {
    return String(text || '').replace(/\r\n?/g, '\n').replace(/\u00a0/g, ' ').replace(/[ \t]+\n/g, '\n').replace(/\n{3,}/g, '\n\n').trim();
  }

  function escapeHtmlPreservingLines(text) {
    return escHtml(String(text || '')).replace(/\n/g, '<br>');
  }

  function buildReportHeaderText(item) {
    return [
      `${item?.manName || 'Unknown'}`,
      `ID: ${item?.manId || '—'}`,
      `Местожительства: ${stripLocalTimeFromPlace(item?.manPlace || '—')}`,
      '',
      `${item?.womanName || 'Unknown'}`,
      `ID: ${item?.womanId || '—'}`,
      `Местожительства: ${stripLocalTimeFromPlace(item?.womanPlace || '—')}`,
      '',
      `Дата: ${formatHumanDate(item?.dateKey)}`
    ].join('\n');
  }

  async function getOrCreateTodayReport() {

    const ctx = await fetchChatContext();
    if (!ctx.chatUid) throw new Error('Не удалось определить chat_uid текущего чата.');
    const all = await readReports();
    const existing = all.find((x) => String(x.chatUid) === String(ctx.chatUid) && String(x.dateKey) === String(ctx.dateKey));
    if (existing) {
      return {
        item: {
          ...existing,
          manName: existing.manName || ctx.manName,
          manId: existing.manId || ctx.manId,
          manPlace: existing.manPlace || ctx.manPlace,
          womanName: existing.womanName || ctx.womanName,
          womanId: existing.womanId || ctx.womanId,
          womanPlace: existing.womanPlace || ctx.womanPlace,
        },
        isNew: false,
      };
    }
    const now = new Date().toISOString();
    return {
      isNew: true,
      item: {
        id: buildReportId(ctx.chatUid, ctx.dateKey),
        chatUid: ctx.chatUid,
        dateKey: ctx.dateKey,
        createdAt: now,
        updatedAt: now,
        manName: ctx.manName,
        manId: ctx.manId,
        manPlace: ctx.manPlace,
        womanName: ctx.womanName,
        womanId: ctx.womanId,
        womanPlace: ctx.womanPlace,
        headerText: buildReportHeaderText(ctx),
        contentHtml: buildReportHeaderHtml(ctx) + buildReportBodyStarterHtml(),
        contentRawText: '',
        contentText: ''
      }
    };
  }

  async function saveReport(item, bodyText) {
    const all = await readReports();
    const now = new Date().toISOString();
    const normalizedBody = normalizeReportBodyText(bodyText);
    const headerText = buildReportHeaderText(item);
    const next = {
      ...item,
      updatedAt: now,
      headerText,
      contentRawText: normalizedBody,
      contentText: normalizedBody,
      contentHtml: buildReportHeaderHtml(item) + (normalizedBody ? `<p>${escapeHtmlPreservingLines(normalizedBody)}</p>` : buildReportBodyStarterHtml())
    };
    const idx = all.findIndex((x) => String(x.id) === String(next.id));
    if (idx >= 0) all[idx] = { ...all[idx], ...next };
    else all.push(next);
    all.sort(reportSort);
    await writeReports(all);
    window.dispatchEvent(new CustomEvent('pulse-reports-updated'));
    return next;
  }

  async function deleteReportById(id) {
    const all = await readReports();
    const next = all.filter((x) => String(x.id) !== String(id));
    await writeReports(next);
    window.dispatchEvent(new CustomEvent('pulse-reports-updated'));
  }

  function closeReportModal() {
    document.getElementById(REPORT_MODAL_ID)?.remove();
  }

  function buildEditorToolbar() {
    const wrap = document.createElement('div');
    wrap.className = 'pulse-report-toolbar';
    wrap.textContent = 'Plain text mode';
    return wrap;
  }

  function buildReportBodyStarterHtml() {
    return '<p><br></p>';
  }

  function buildReportHeaderHtml(item) {
    return `
      <div class="pulse-report-inline-header notranslate" data-report-header="1" spellcheck="false" translate="no" lang="ru">${escapeHtmlPreservingLines(buildReportHeaderText(item))}</div>
      <p><br></p>`;
  }

  function ensureReportHeaderInHtml(item, html) {
    const raw = String(html || '').trim();
    if (!raw) return buildReportHeaderHtml(item) + buildReportBodyStarterHtml();
    if (/data-report-header=["']1["']/.test(raw)) return raw;
    return buildReportHeaderHtml(item) + raw;
  }

  function editorHtmlToView(item, html) {
    return ensureReportHeaderInHtml(item, html);
  }

  function createReportModalShell(item) {
    closeReportModal();
    const overlay = document.createElement('div');
    overlay.id = REPORT_MODAL_ID;
    overlay.innerHTML = `
      <div class="pulse-report-modal notranslate" translate="no" lang="ru">
        <div class="pulse-report-header">
          <div>
            <div class="pulse-report-title notranslate" translate="no">Report notebook</div>
            <div class="pulse-report-subtitle">${escHtml(buildReportTitle(item))} · ${escHtml(formatHumanDate(item.dateKey))}</div>
          </div>
          <button type="button" class="pulse-report-close">×</button>
        </div>
        <div class="pulse-report-editor-wrap"></div>
        <div class="pulse-report-actions">
          <div class="pulse-report-status"></div>
          <div class="pulse-report-actions-right">
            <button type="button" class="pulse-report-delete">Delete</button>
            <button type="button" class="pulse-report-save">Save</button>
          </div>
        </div>
      </div>`;
    document.body.appendChild(overlay);
    overlay.addEventListener('click', (e) => { if (e.target === overlay) closeReportModal(); });
    overlay.querySelector('.pulse-report-close')?.addEventListener('click', closeReportModal);
    return overlay;
  }

  async function openReportEditor(input) {
    const payload = input?.item ? input : { item: input, isNew: false };
    let item = payload.item;
    const liveCtx = await fetchChatContext().catch(() => null);
    if (!item) {
      payload.item = (await getOrCreateTodayReport()).item;
      item = payload.item;
    }
    if (liveCtx && (!item.chatUid || String(item.chatUid) === String(liveCtx.chatUid))) {
      item = {
        ...item,
        manName: item.manName || liveCtx.manName,
        manId: item.manId || liveCtx.manId,
        manPlace: item.manPlace || liveCtx.manPlace,
        womanName: item.womanName || liveCtx.womanName,
        womanId: item.womanId || liveCtx.womanId,
        womanPlace: item.womanPlace || liveCtx.womanPlace,
      };
      payload.item = item;
    }
    const overlay = createReportModalShell(item);
    const editorWrap = overlay.querySelector('.pulse-report-editor-wrap');
    const statusEl = overlay.querySelector('.pulse-report-status');
    const toolbar = buildEditorToolbar();
    const editor = document.createElement('div');
    editor.className = 'pulse-report-editor notranslate';
    editor.contentEditable = 'true';
    editor.setAttribute('translate', 'no');
    editor.setAttribute('lang', 'ru');
    editor.setAttribute('autocapitalize', 'off');
    editor.setAttribute('autocorrect', 'off');
    editor.setAttribute('autocomplete', 'off');
    editor.spellcheck = false;
    const headerBox = document.createElement('div');
    headerBox.className = 'pulse-report-inline-header notranslate';
    headerBox.setAttribute('data-report-header', '1');
    headerBox.setAttribute('translate', 'no');
    headerBox.setAttribute('lang', 'ru');
    headerBox.setAttribute('spellcheck', 'false');
    headerBox.setAttribute('contenteditable', 'true');
    headerBox.textContent = item.headerText || buildReportHeaderText(item);
    const isSelectionInsideHeader = () => {
      try {
        const sel = window.getSelection();
        if (!sel) return false;
        const anchorNode = sel.anchorNode;
        const focusNode = sel.focusNode;
        return !!((anchorNode && headerBox.contains(anchorNode)) || (focusNode && headerBox.contains(focusNode)));
      } catch {
        return false;
      }
    };
    const preventHeaderEditing = (event) => {
      if (!isSelectionInsideHeader()) return false;
      event?.preventDefault?.();
      return true;
    };
    const bodyBox = document.createElement('div');
    bodyBox.className = 'pulse-report-body notranslate';
    bodyBox.setAttribute('translate', 'no');
    bodyBox.setAttribute('lang', 'ru');
    bodyBox.setAttribute('autocapitalize', 'off');
    bodyBox.setAttribute('autocorrect', 'off');
    bodyBox.setAttribute('autocomplete', 'off');
    bodyBox.spellcheck = false;
    bodyBox.textContent = normalizeReportBodyText(item.contentRawText || item.contentText || reportBodyTextFromHtml(item.contentHtml || ''));
    editor.append(headerBox, bodyBox);
    editorWrap.append(toolbar, editor);

    const saveBtn = overlay.querySelector('.pulse-report-save');
    const delBtn = overlay.querySelector('.pulse-report-delete');
    const setStatus = (text, ok = true) => {
      const raw = String(text || '').trim();
      const isNewReport = /^new report$/i.test(raw);
      statusEl.textContent = isNewReport ? 'Новый отчёт' : raw;
      statusEl.dataset.state = isNewReport ? 'new' : (ok ? 'ok' : 'error');
      statusEl.style.color = isNewReport ? '#3b2500' : (ok ? '#08233b' : '#4a0910');
    };

    saveBtn?.addEventListener('click', async () => {
      try {
        item = await saveReport(item, bodyBox.textContent || '');
        headerBox.textContent = item.headerText || buildReportHeaderText(item);
        setStatus('Saved');
      } catch (e) {
        setStatus(e?.message || 'Save error', false);
      }
    });

    delBtn?.addEventListener('click', async () => {
      if (!item?.id) return closeReportModal();
      const ok = confirm('Удалить этот отчёт?');
      if (!ok) return;
      await deleteReportById(item.id);
      closeReportModal();
    });

    editor.addEventListener('beforeinput', (event) => {
      if (preventHeaderEditing(event)) return;
    });
    editor.addEventListener('keydown', (event) => {
      if (!(event.ctrlKey || event.metaKey || event.altKey)) {
        if (event.key && event.key.length === 1) {
          if (preventHeaderEditing(event)) return;
        }
      }
      if (['Backspace', 'Delete', 'Enter'].includes(event.key)) {
        if (preventHeaderEditing(event)) return;
      }
      if ((event.ctrlKey || event.metaKey) && ['v', 'x'].includes(String(event.key || '').toLowerCase())) {
        if (preventHeaderEditing(event)) return;
      }
    });
    editor.addEventListener('paste', (event) => {
      try {
        if (preventHeaderEditing(event)) return;
        event.preventDefault();
        const text = event.clipboardData?.getData('text/plain') || '';
        document.execCommand('insertText', false, text);
      } catch {}
    });
    editor.addEventListener('drop', (event) => {
      if (preventHeaderEditing(event)) return;
    });
    editor.addEventListener('input', () => setStatus('Unsaved changes'));
    setStatus(payload.isNew ? 'New report' : 'Loaded');
    setTimeout(() => {
      try {
        editor.focus();
        const range = document.createRange();
        range.selectNodeContents(editor);
        range.collapse(false);
        const sel = window.getSelection();
        sel?.removeAllRanges();
        sel?.addRange(range);
      } catch {}
    }, 30);
  }

  async function openReportFromCurrentChat() {
    if (!pulseHasFeatureAuth()) {
      pulseRemoveQuickUi();
      return;
    }
    try {
      const payload = await getOrCreateTodayReport();
      await openReportEditor(payload);
    } catch (e) {
      alert(e?.message || 'Не удалось открыть report.');
    }
  }

  async function renderReportsTab(root) {
    root.innerHTML = '';
    const wrap = elt('div', { className: 'pulse-reports-tab' });
    const head = elt('div', { className: 'pulse-reports-head' },
      elt('div', { className: 'pulse-reports-tab-title' }, 'Reports'),
      elt('button', {
        type: 'button',
        className: 'pulse-reports-refresh',
        onclick: () => renderReportsTab(root)
      }, 'Refresh')
    );
    const search = elt('input', {
      type: 'search',
      className: 'pulse-reports-search',
      placeholder: 'Поиск по мужчине, женщине или тексту…'
    });
    const list = elt('div', { className: 'pulse-reports-list' });
    wrap.append(head, search, list);
    root.append(wrap);

    const renderList = async () => {
      const q = String(search.value || '').trim().toLowerCase();
      const items = (await readReports()).sort(reportSort).filter((item) => {
        if (!q) return true;
        const hay = [item.manName, item.womanName, buildReportTitle(item), item.contentText, item.manId, item.womanId].join(' ').toLowerCase();
        return hay.includes(q);
      });
      list.innerHTML = '';
      if (!items.length) {
        list.append(elt('div', { className: 'pulse-reports-empty' }, q ? 'Ничего не найдено.' : 'Сохранённых отчётов пока нет.'));
        return;
      }
      items.forEach((item) => {
        const row = elt('div', { className: 'pulse-reports-row' },
          elt('div', { className: 'pulse-reports-row-main' },
            elt('div', { className: 'pulse-reports-row-top' },
              elt('span', { className: 'pulse-reports-row-date' }, formatHumanDate(item.dateKey))
            ),
            elt('div', { className: 'pulse-reports-row-pair' }, buildReportTitle(item)),
            elt('div', { className: 'pulse-reports-row-ids' },
              elt('div', { className: 'pulse-reports-row-idline' }, `Мужчина ID: ${item.manId || '—'}`),
              elt('div', { className: 'pulse-reports-row-idline' }, `Женщина ID: ${item.womanId || '—'}`)
            )
          ),
          elt('div', { className: 'pulse-reports-row-actions' },
            elt('button', {
              className: 'pulse-reports-open-btn',
              type: 'button',
              style: 'appearance:none;-webkit-appearance:none;background:linear-gradient(135deg,#00c6ff 0%,#0072ff 100%);background-image:linear-gradient(135deg,#00c6ff 0%,#0072ff 100%);color:#fff;border:1px solid rgba(255,255,255,.18);box-shadow:0 4px 12px rgba(0,140,255,.35);',
              onmouseenter: (e) => { e.currentTarget.style.background = 'linear-gradient(135deg,#1ad1ff 0%,#2b7cff 100%)'; e.currentTarget.style.backgroundImage = 'linear-gradient(135deg,#1ad1ff 0%,#2b7cff 100%)'; },
              onmouseleave: (e) => { e.currentTarget.style.background = 'linear-gradient(135deg,#00c6ff 0%,#0072ff 100%)'; e.currentTarget.style.backgroundImage = 'linear-gradient(135deg,#00c6ff 0%,#0072ff 100%)'; },
              onclick: () => openReportEditor(item)
            }, 'Open'),
            elt('button', {
              className: 'pulse-reports-delete-btn',
              type: 'button',
              style: 'appearance:none;-webkit-appearance:none;background:linear-gradient(135deg,#ff4d4d 0%,#b31217 100%);background-image:linear-gradient(135deg,#ff4d4d 0%,#b31217 100%);color:#fff;border:1px solid rgba(255,255,255,.18);box-shadow:0 4px 12px rgba(255,50,50,.35);',
              onmouseenter: (e) => { e.currentTarget.style.background = 'linear-gradient(135deg,#ff6666 0%,#d4141a 100%)'; e.currentTarget.style.backgroundImage = 'linear-gradient(135deg,#ff6666 0%,#d4141a 100%)'; },
              onmouseleave: (e) => { e.currentTarget.style.background = 'linear-gradient(135deg,#ff4d4d 0%,#b31217 100%)'; e.currentTarget.style.backgroundImage = 'linear-gradient(135deg,#ff4d4d 0%,#b31217 100%)'; },
              onclick: async () => { if (confirm('Удалить отчёт?')) { await deleteReportById(item.id); renderList(); } }
            }, 'Delete')
          )
        );
        list.append(row);
      });
    };

    search.addEventListener('input', () => { renderList(); });
    window.addEventListener('pulse-reports-updated', () => { renderList(); }, { once: true });
    renderList();
  }

  function ensureReportsCss() {
    if (document.getElementById('pulse-reports-style')) return;
    const style = document.createElement('style');
    style.id = 'pulse-reports-style';
    style.textContent = `
      #${REPORT_MODAL_ID}{position:fixed;inset:0;background:rgba(7,12,22,.36);display:flex;align-items:center;justify-content:center;z-index:2147483647;padding:16px;font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,sans-serif}
      #${REPORT_MODAL_ID} .pulse-report-modal{position:relative;isolation:isolate;width:min(640px,94vw);max-height:92vh;min-height:760px;overflow:hidden;display:flex;flex-direction:column;border-radius:18px;background:linear-gradient(180deg,rgba(205,216,235,.46),rgba(171,187,213,.42));box-shadow:0 28px 80px rgba(0,0,0,.28), inset 0 1px 0 rgba(255,255,255,.40);color:#f4f8ff;border:1px solid rgba(255,255,255,.22)}
      #${REPORT_MODAL_ID} .pulse-report-modal::before{content:"";position:absolute;inset:-18px;background:radial-gradient(circle at 18% 14%, rgba(255,255,255,.58), transparent 32%),radial-gradient(circle at 82% 18%, rgba(168,197,255,.34), transparent 30%),radial-gradient(circle at 50% 120%, rgba(120,154,219,.24), transparent 45%),linear-gradient(180deg, rgba(255,255,255,.34), rgba(195,208,231,.18) 45%, rgba(128,149,190,.22));filter:blur(22px) saturate(135%);transform:scale(1.02);z-index:0;pointer-events:none}
      #${REPORT_MODAL_ID} .pulse-report-modal > *{position:relative;z-index:1}
      #${REPORT_MODAL_ID} .pulse-report-header{display:flex;justify-content:space-between;align-items:flex-start;gap:12px;padding:18px 20px 14px;background:linear-gradient(180deg, rgba(255,255,255,.06), rgba(255,255,255,.02))}
      #${REPORT_MODAL_ID} .pulse-report-title{font-size:20px;font-weight:800;display:inline-block;padding:3px 10px;border-radius:10px;background:rgba(255,255,255,.34);color:#223046;text-shadow:none;box-shadow:inset 0 0 0 1px rgba(255,255,255,.26)}
      #${REPORT_MODAL_ID} .pulse-report-subtitle{display:inline-block;font-size:13px;color:#2f3c50;margin-top:4px;padding:3px 10px;border-radius:10px;background:rgba(255,255,255,.30);text-shadow:none;box-shadow:inset 0 0 0 1px rgba(255,255,255,.22)}
      #${REPORT_MODAL_ID} .pulse-report-close{width:38px;height:38px;border:none;border-radius:12px;background:rgba(88,102,128,.34);color:#223046;font-size:24px;cursor:pointer;box-shadow:inset 0 0 0 1px rgba(255,255,255,.16), inset 0 10px 18px rgba(255,255,255,.08)}
      #${REPORT_MODAL_ID} .pulse-report-meta{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:12px;padding:16px 20px}
      #${REPORT_MODAL_ID} .pulse-report-meta-card{padding:12px 14px;border-radius:14px;background:rgba(255,255,255,.05);font-size:13px;line-height:1.5;border:1px solid rgba(255,255,255,.07)}
      #${REPORT_MODAL_ID} .pulse-report-meta-title{font-size:12px;text-transform:uppercase;letter-spacing:.08em;color:#8fb7ff;margin-bottom:6px}
      #${REPORT_MODAL_ID} .pulse-report-editor-wrap{padding:0 20px 0;display:flex;flex-direction:column;gap:10px;min-height:0;flex:1}
      #${REPORT_MODAL_ID} .pulse-report-toolbar{display:flex;gap:8px;flex-wrap:wrap;font-size:12px;font-weight:800;color:#42546d;text-transform:uppercase;letter-spacing:.08em}
      #${REPORT_MODAL_ID} .pulse-report-editor{position:relative;flex:1;min-height:520px;max-height:none;overflow:auto;padding:16px;border-radius:14px;background:linear-gradient(180deg,rgba(244,247,252,.82),rgba(236,241,249,.76));color:#102038;outline:none;line-height:1.6;font-size:15px;box-shadow:none;border:none;white-space:pre-wrap;word-break:break-word;unicode-bidi:plaintext;user-select:text}
      #${REPORT_MODAL_ID} .pulse-report-inline-header{padding:14px 16px;border-radius:12px;background:rgba(255,255,255,.44);border:1px solid rgba(120,136,165,.20);margin-bottom:4px;line-height:1.6;color:#102038;user-select:text;box-shadow:inset 0 1px 0 rgba(255,255,255,.50);white-space:pre-wrap;word-break:break-word;font-weight:600}
      #${REPORT_MODAL_ID} .pulse-report-body{min-height:320px;white-space:pre-wrap;word-break:break-word;outline:none;user-select:text}
      #${REPORT_MODAL_ID} .pulse-report-actions{display:flex;justify-content:space-between;align-items:center;gap:12px;padding:12px 20px 18px;background:linear-gradient(180deg, rgba(255,255,255,.02), rgba(255,255,255,.05))}
      #${REPORT_MODAL_ID} .pulse-report-status{font-size:14px;font-weight:800;letter-spacing:.01em;color:#ffffff;padding:8px 14px;border-radius:12px;background:linear-gradient(135deg,rgba(255,255,255,.50),rgba(255,255,255,.24));text-shadow:none;box-shadow:inset 0 0 0 1px rgba(255,255,255,.28),0 8px 18px rgba(19,34,58,.10);min-height:18px;display:flex;align-items:center}
      #${REPORT_MODAL_ID} .pulse-report-status[data-state="new"]{background:linear-gradient(135deg,#ffe88a 0%,#ffb347 100%);color:#4a2a00;box-shadow:0 10px 22px rgba(255,179,71,.32), inset 0 0 0 1px rgba(255,255,255,.38)}
      #${REPORT_MODAL_ID} .pulse-report-status[data-state="ok"]{background:linear-gradient(135deg,#78f0d8 0%,#35b7ff 100%);color:#08233b;box-shadow:0 10px 22px rgba(53,183,255,.26), inset 0 0 0 1px rgba(255,255,255,.34)}
      #${REPORT_MODAL_ID} .pulse-report-status[data-state="error"]{background:linear-gradient(135deg,#ff9a9e 0%,#ff5f6d 100%);color:#4a0910;box-shadow:0 10px 22px rgba(255,95,109,.30), inset 0 0 0 1px rgba(255,255,255,.28)}
      #${REPORT_MODAL_ID} .pulse-report-actions-right{display:flex;gap:10px}
      #${REPORT_MODAL_ID} .pulse-report-save,#${REPORT_MODAL_ID} .pulse-report-delete{position:relative;overflow:hidden;padding:11px 18px;border:1px solid rgba(255,255,255,.26);border-radius:12px;cursor:pointer;font-weight:900;letter-spacing:.02em;color:#102038;backdrop-filter:blur(14px) saturate(170%);-webkit-backdrop-filter:blur(14px) saturate(170%);transition:transform .18s ease,box-shadow .18s ease,background .18s ease,filter .18s ease;filter:saturate(1.18) brightness(1.08)}
      #${REPORT_MODAL_ID} .pulse-report-save{background:linear-gradient(135deg,#72ffd8 0%,#00c6ff 52%,#0072ff 100%);box-shadow:0 14px 30px rgba(0,140,255,.34),0 0 26px rgba(0,220,255,.28),inset 0 1px 0 rgba(255,255,255,.42),inset 0 0 0 1px rgba(255,255,255,.24);text-shadow:none}
      #${REPORT_MODAL_ID} .pulse-report-save:hover{transform:translateY(-1px);background:linear-gradient(135deg,#8bffe1 0%,#1ad1ff 52%,#2b7cff 100%);box-shadow:0 16px 34px rgba(0,140,255,.40),0 0 30px rgba(0,220,255,.34),inset 0 1px 0 rgba(255,255,255,.46),inset 0 0 0 1px rgba(255,255,255,.28)}
      #${REPORT_MODAL_ID} .pulse-report-delete{background:linear-gradient(135deg,#ff8a8a 0%,#ff4d6d 55%,#c9184a 100%);box-shadow:0 14px 30px rgba(255,64,96,.32),0 0 24px rgba(255,64,96,.24),inset 0 1px 0 rgba(255,255,255,.36),inset 0 0 0 1px rgba(255,255,255,.22);text-shadow:none}
      #${REPORT_MODAL_ID} .pulse-report-delete:hover{transform:translateY(-1px);background:linear-gradient(135deg,#ff9e9e 0%,#ff5e7d 55%,#db1f54 100%);box-shadow:0 16px 34px rgba(255,64,96,.38),0 0 28px rgba(255,64,96,.30),inset 0 1px 0 rgba(255,255,255,.40),inset 0 0 0 1px rgba(255,255,255,.26)}
      .pulse-reports-tab{display:flex;flex-direction:column;gap:12px;padding:8px 4px;color:#e9eef6;height:100%}
      .pulse-reports-head{display:flex;justify-content:space-between;align-items:center;gap:12px}
      .pulse-reports-tab-title{font-size:16px;font-weight:800;color:rgba(233,238,246,.95)}
      .pulse-reports-refresh{padding:8px 12px;border:none;border-radius:10px;background:rgba(255,255,255,.08);color:#fff;cursor:pointer;box-shadow:inset 0 0 14px rgba(167,90,255,.30), inset 0 0 0 1px rgba(191,128,255,.16)}
      .pulse-reports-search{width:100%;padding:12px 14px;border-radius:12px;border:1px solid rgba(255,255,255,.10);background:rgba(255,255,255,.06);color:#fff;outline:none}
      .pulse-reports-list{display:flex;flex-direction:column;gap:16px;max-height:460px;overflow:auto;padding:4px 6px 10px 2px}
      .pulse-reports-row{display:flex;justify-content:space-between;align-items:flex-start;gap:16px;padding:16px 16px 18px;border-radius:16px;background:rgba(255,255,255,.05);border:1px solid rgba(255,255,255,.06);box-shadow:0 8px 24px rgba(0,0,0,.14)}
      .pulse-reports-row-main{min-width:0;display:flex;flex-direction:column;gap:10px}
      .pulse-reports-row-top{display:flex;gap:10px;flex-wrap:wrap;align-items:center;margin-bottom:2px}
      .pulse-reports-row-date{font-size:12px;color:#8fb7ff;font-weight:700;letter-spacing:.02em}
      .pulse-reports-row-pair{font-size:15px;font-weight:800;color:#fff;line-height:1.45}
      .pulse-reports-row-ids{display:flex;flex-direction:column;gap:4px;margin-top:2px}
      .pulse-reports-row-idline{font-size:12px;color:rgba(233,238,246,.70);line-height:1.45}
            .pulse-reports-row-actions{display:flex;gap:8px;flex-shrink:0;align-self:center}
      .pulse-reports-row-actions button{appearance:none;-webkit-appearance:none;position:relative;overflow:hidden;padding:8px 14px;border:1px solid rgba(255,255,255,.16);border-radius:12px;background:linear-gradient(135deg, rgba(255,255,255,.16), rgba(255,255,255,.05));color:#f8feff;cursor:pointer;font-weight:800;letter-spacing:.02em;backdrop-filter:blur(14px) saturate(150%);-webkit-backdrop-filter:blur(14px) saturate(150%);text-shadow:0 0 10px rgba(255,255,255,.16);transition:box-shadow .18s ease, transform .18s ease, background .18s ease, border-color .18s ease}
      .pulse-reports-open-btn{background:linear-gradient(135deg,#00c6ff 0%,#0072ff 100%)!important;color:#fff!important;border:1px solid rgba(255,255,255,.18)!important;box-shadow:0 4px 12px rgba(0,140,255,.35)!important}
      .pulse-reports-open-btn:hover{background:linear-gradient(135deg,#1ad1ff 0%,#2b7cff 100%)!important;transform:translateY(-1px)}
      .pulse-reports-delete-btn{background:linear-gradient(135deg,#ff4d4d 0%,#b31217 100%)!important;color:#fff!important;border:1px solid rgba(255,255,255,.18)!important;box-shadow:0 4px 12px rgba(255,50,50,.35)!important}
      .pulse-reports-delete-btn:hover{background:linear-gradient(135deg,#ff6666 0%,#d4141a 100%)!important;transform:translateY(-1px)}
      .pulse-reports-empty{padding:20px 8px;color:rgba(233,238,246,.62);font-size:14px}
      @media (max-width: 820px){#${REPORT_MODAL_ID} .pulse-report-modal{width:min(96vw,640px);min-height:72vh} #${REPORT_MODAL_ID} .pulse-report-meta{grid-template-columns:1fr} #${REPORT_MODAL_ID} .pulse-report-editor{min-height:46vh} #${REPORT_MODAL_ID} .pulse-report-actions{flex-direction:column;align-items:stretch} #${REPORT_MODAL_ID} .pulse-report-actions-right{justify-content:stretch} #${REPORT_MODAL_ID} .pulse-report-actions-right button{flex:1}}
    `;
    document.head.appendChild(style);
  }

  function initReportsButtonInterceptor() {
    document.addEventListener('click', (event) => {
      const btn = event.target && (event.target.closest ? event.target.closest(`#${REPORTS_BTN_ID}`) : null);
      if (!btn) return;
      event.preventDefault();
      event.stopPropagation();
      if (typeof event.stopImmediatePropagation === 'function') event.stopImmediatePropagation();
      if (!pulseHasFeatureAuth()) {
        pulseRemoveQuickUi();
        return;
      }
      openReportFromCurrentChat();
    }, true);
  }

  ensureReportsCss();
  initReportsButtonInterceptor();
  window.PulseReports = {
    openFromCurrentChat: openReportFromCurrentChat,
    openById: async (id) => {
      if (!pulseHasFeatureAuth()) {
        pulseRemoveQuickUi();
        return;
      }
      const item = (await readReports()).find((x) => String(x.id) === String(id));
      if (item) openReportEditor(item);
    },
    renderTab: renderReportsTab,
  };
})();


/* top-left main logo replacement only */
(function(){
  const PULSE_TOP_LEFT_LOGO_URL = chrome.runtime.getURL("top_left_logo.png");
  const TARGET_SELECTOR = '[data-testid="main-logo"] img';
  const MARK_ATTR = 'data-pulse-top-left-logo-applied';
  const ORIG_ATTR = 'data-pulse-top-left-logo-orig-src';
  const ORIG_WIDTH_ATTR = 'data-pulse-top-left-logo-orig-width';
  const ORIG_HEIGHT_ATTR = 'data-pulse-top-left-logo-orig-height';
  const SCALE = 1.19;

  function rememberOriginalSize(img){
    if (img.hasAttribute(ORIG_WIDTH_ATTR) && img.hasAttribute(ORIG_HEIGHT_ATTR)) return;
    const rect = img.getBoundingClientRect();
    const width = rect.width || parseFloat(getComputedStyle(img).width) || img.width || img.naturalWidth || 0;
    const height = rect.height || parseFloat(getComputedStyle(img).height) || img.height || img.naturalHeight || 0;
    if (width > 0) img.setAttribute(ORIG_WIDTH_ATTR, String(width));
    if (height > 0) img.setAttribute(ORIG_HEIGHT_ATTR, String(height));
  }

  function applyScaledSize(img){
    const baseWidth = parseFloat(img.getAttribute(ORIG_WIDTH_ATTR) || '0');
    const baseHeight = parseFloat(img.getAttribute(ORIG_HEIGHT_ATTR) || '0');
    if (baseWidth > 0) img.style.width = `${baseWidth}px`;
    if (baseHeight > 0) img.style.height = `${baseHeight}px`;
    img.style.maxWidth = 'none';
    img.style.maxHeight = 'none';
    img.style.transform = `scale(${SCALE})`;
    img.style.transformOrigin = 'center center';
    img.style.display = 'block';
    img.style.margin = '0 auto';
    img.style.willChange = 'transform';
    const parent = img.parentElement;
    if (parent) {
      if (!parent.style.position) parent.style.position = 'relative';
      parent.style.overflow = 'visible';
      parent.style.display = parent.style.display || 'flex';
      parent.style.alignItems = parent.style.alignItems || 'center';
      parent.style.justifyContent = parent.style.justifyContent || 'center';
    }
  }

  function applyTopLeftLogo(root=document){
    const img = root.querySelector ? root.querySelector(TARGET_SELECTOR) : document.querySelector(TARGET_SELECTOR);
    if (!img) return;
    const current = img.getAttribute('src') || '';
    if (!img.hasAttribute(ORIG_ATTR)) {
      img.setAttribute(ORIG_ATTR, current);
    }
    rememberOriginalSize(img);
    if (current !== PULSE_TOP_LEFT_LOGO_URL) {
      img.src = PULSE_TOP_LEFT_LOGO_URL;
    }
    applyScaledSize(img);
    img.setAttribute(MARK_ATTR, '1');
    img.removeAttribute('srcset');
  }

  if (document.readyState === 'loading') {
    document.addEventListener('DOMContentLoaded', () => applyTopLeftLogo(), { once:true });
  } else {
    applyTopLeftLogo();
  }

  const mo = new MutationObserver(() => applyTopLeftLogo());
  mo.observe(document.documentElement || document, { childList:true, subtree:true, attributes:true, attributeFilter:['src','srcset'] });
})();


(() => {
  const STORAGE_KEY = 'pulseMediaBlurClickMode';
  const ACTIVE_ATTR = 'data-pulse-media-blur-active';
  const PREV_FILTER_ATTR = 'data-pulse-media-prev-filter';
  const PREV_TRANSITION_ATTR = 'data-pulse-media-prev-transition';
  const PREV_CLIP_PATH_ATTR = 'data-pulse-media-prev-clip-path';
  const PREV_WEBKIT_CLIP_PATH_ATTR = 'data-pulse-media-prev-webkit-clip-path';
  const PREV_OVERFLOW_ATTR = 'data-pulse-media-prev-overflow';
  let blurModeEnabled = false;
  const blurredElements = new Set();

  function hasBackgroundMedia(el) {
    try {
      const inline = String(el.getAttribute('style') || '');
      if (/background-image\s*:/i.test(inline) && /url\s*\(/i.test(inline)) return true;
      const bg = String(getComputedStyle(el).backgroundImage || '');
      return bg.includes('url(');
    } catch {
      return false;
    }
  }

  function isMediaElement(el) {
    if (!(el instanceof Element)) return false;
    const tag = String(el.tagName || '').toUpperCase();
    if (tag === 'IMG' || tag === 'VIDEO') return true;
    if (el.hasAttribute('poster')) return true;
    return hasBackgroundMedia(el);
  }

  function findMediaElement(target) {
    let el = target instanceof Element ? target : null;
    while (el && el !== document.documentElement) {
      if (isMediaElement(el)) return el;
      el = el.parentElement;
    }
    return null;
  }

  function getClipPathValue(el) {
    try {
      const radius = String(getComputedStyle(el).borderRadius || '').trim();
      if (radius && radius !== '0px' && radius !== '0px 0px 0px 0px') {
        return `inset(0 round ${radius})`;
      }
    } catch {}
    return 'inset(0)';
  }

  function setBlur(el) {
    if (!el || !(el instanceof HTMLElement)) return;
    if (!el.hasAttribute(PREV_FILTER_ATTR)) el.setAttribute(PREV_FILTER_ATTR, el.style.filter || '');
    if (!el.hasAttribute(PREV_TRANSITION_ATTR)) el.setAttribute(PREV_TRANSITION_ATTR, el.style.transition || '');
    if (!el.hasAttribute(PREV_CLIP_PATH_ATTR)) el.setAttribute(PREV_CLIP_PATH_ATTR, el.style.clipPath || '');
    if (!el.hasAttribute(PREV_WEBKIT_CLIP_PATH_ATTR)) el.setAttribute(PREV_WEBKIT_CLIP_PATH_ATTR, el.style.webkitClipPath || '');
    if (!el.hasAttribute(PREV_OVERFLOW_ATTR)) el.setAttribute(PREV_OVERFLOW_ATTR, el.style.overflow || '');
    const clipPathValue = getClipPathValue(el);
    el.style.transition = 'filter 0.15s ease';
    el.style.overflow = 'hidden';
    el.style.clipPath = clipPathValue;
    el.style.webkitClipPath = clipPathValue;
    el.style.filter = 'blur(30px)';
    el.setAttribute(ACTIVE_ATTR, '1');
    blurredElements.add(el);
  }

  function removeBlur(el) {
    if (!el || !(el instanceof HTMLElement)) return;
    el.style.filter = el.getAttribute(PREV_FILTER_ATTR) || '';
    el.style.transition = el.getAttribute(PREV_TRANSITION_ATTR) || '';
    el.style.clipPath = el.getAttribute(PREV_CLIP_PATH_ATTR) || '';
    el.style.webkitClipPath = el.getAttribute(PREV_WEBKIT_CLIP_PATH_ATTR) || '';
    el.style.overflow = el.getAttribute(PREV_OVERFLOW_ATTR) || '';
    el.removeAttribute(PREV_FILTER_ATTR);
    el.removeAttribute(PREV_TRANSITION_ATTR);
    el.removeAttribute(PREV_CLIP_PATH_ATTR);
    el.removeAttribute(PREV_WEBKIT_CLIP_PATH_ATTR);
    el.removeAttribute(PREV_OVERFLOW_ATTR);
    el.removeAttribute(ACTIVE_ATTR);
    blurredElements.delete(el);
  }

  function clearAllBlurred() {
    for (const el of Array.from(blurredElements)) removeBlur(el);
  }

  function toggleBlur(el) {
    if (!el) return;
    if (el.getAttribute(ACTIVE_ATTR) === '1') removeBlur(el);
    else setBlur(el);
  }

  function setMode(enabled) {
    blurModeEnabled = !!enabled;
    if (!blurModeEnabled) clearAllBlurred();
  }

  function shouldHandlePointer(event) {
    if (!blurModeEnabled) return false;
    if (event.defaultPrevented) return false;
    if ('button' in event && event.button !== 0) return false;
    return !!findMediaElement(event.target);
  }

  function stopNativeOpen(event) {
    if (!shouldHandlePointer(event)) return;
    event.preventDefault();
    event.stopPropagation();
    event.stopImmediatePropagation();
  }

  function onClick(event) {
    if (!shouldHandlePointer(event)) return;
    const media = findMediaElement(event.target);
    event.preventDefault();
    event.stopPropagation();
    event.stopImmediatePropagation();
    toggleBlur(media);
  }

  try {
    chrome.storage.local.get([STORAGE_KEY], (data) => {
      setMode(!!(data && data[STORAGE_KEY]));
    });
  } catch {}

  try {
    chrome.storage.onChanged.addListener((changes, area) => {
      if (area !== 'local' || !changes[STORAGE_KEY]) return;
      setMode(!!changes[STORAGE_KEY].newValue);
    });
  } catch {}

  try {
    chrome.runtime.onMessage.addListener((message, sender, sendResponse) => {
      if (!message || message.cmd !== 'pulseSetMediaBlurMode') return;
      setMode(!!message.enabled);
      if (typeof sendResponse === 'function') sendResponse({ ok: true });
      return true;
    });
  } catch {}

  document.addEventListener('mousedown', stopNativeOpen, true);
  document.addEventListener('click', onClick, true);
})();
