(function () {
  // ---- Config from PHP ----
  if (!window.TRACKSHARP_TRACKER) return;
  var CFG = window.TRACKSHARP_TRACKER || {};
  // Optional server-side consent bridge
  var SERVER_OK =
    typeof TRACKSHARP_SERVER_CONSENT !== "undefined"
      ? TRACKSHARP_SERVER_CONSENT
      : { meta: true, ga4: true };

  // ---- Debug logger (toggle with localStorage.WS_DEBUG='1') ----
  var DBG = (function () {
    function enabled() {
      try {
        return localStorage.WS_DEBUG === "1";
      } catch (_) {
        return false;
      }
    }
    function log() {
      if (!enabled()) return;
      try {
        console.debug.apply(console, arguments);
      } catch (_) {}
    }
    log.enabled = enabled;
    log.clone = function (o) {
      try {
        return JSON.parse(JSON.stringify(o));
      } catch (_) {
        return o;
      }
    };
    return log;
  })();
  DBG("[WS] boot", { cfg: DBG.clone(CFG) });

  // ---- Referral Preservation (TAGGRS-inspired) ----
  (function () {
    try {
      var ref = document.referrer;
      var host = location.hostname;
      // If we have a referrer and it's not from our own site, store it as the initial referrer
      if (ref && ref.indexOf(host) === -1) {
        if (!sessionStorage.getItem("ws_initial_referrer")) {
          sessionStorage.setItem("ws_initial_referrer", ref);
          setCookie("ws_initial_referrer", ref, 30); // 30 days
          DBG("[WS] stored initial referrer:", ref);
        }
      }
    } catch (_) {}
  })();

  // ---- Utils ----
  var uuid = function () {
    return ([1e7] + -1e3 + -4e3 + -8e3 + -1e11).replace(/[018]/g, function (c) {
      return (
        c ^
        (crypto.getRandomValues(new Uint8Array(1))[0] & (15 >> (c / 4)))
      ).toString(16);
    });
  };
  function getCookie(name) {
    var m = document.cookie.match(new RegExp("(?:^|; )" + name + "=([^;]+)"));
    return m ? decodeURIComponent(m[1]) : "";
  }
  function setCookie(name, value, days) {
    var exp = new Date(Date.now() + (days || 365) * 864e5).toUTCString();
    document.cookie =
      name +
      "=" +
      encodeURIComponent(value) +
      "; path=/; expires=" +
      exp +
      "; SameSite=Lax";
  }
  function getGaClientId(mid) {
    return new Promise(function (res) {
      if (!window.gtag || !mid) return res(null);
      try {
        window.gtag("get", mid, "client_id", function (cid) {
          res(cid || null);
        });
      } catch (e) {
        res(null);
      }
    });
  }
  function getGaClientIdWithTimeout(mid, timeoutMs) {
    try {
      return Promise.race([
        getGaClientId(mid),
        new Promise(function (res) {
          setTimeout(function () {
            res(null);
          }, timeoutMs || 1000);
        }),
      ]);
    } catch (_) {
      return Promise.resolve(null);
    }
  }

  // --- GA4 sender bootstrap (for GTM-only Google Tag setups) ---
  var __WS_GTAG_BOOTSTRAP__ = { p: null, mid: null };

  function loadExternalScript(src, timeoutMs) {
    return new Promise(function (resolve) {
      try {
        var script = document.createElement("script");
        script.async = true;
        script.src = src;

        var done = false;
        var t = setTimeout(function () {
          if (done) return;
          done = true;
          resolve(false);
        }, timeoutMs || 2500);

        script.onload = function () {
          if (done) return;
          done = true;
          clearTimeout(t);
          resolve(true);
        };
        script.onerror = function () {
          if (done) return;
          done = true;
          clearTimeout(t);
          resolve(false);
        };

        (document.head || document.documentElement).appendChild(script);
      } catch (_) {
        resolve(false);
      }
    });
  }

  async function ensureGtagForMid(mid) {
    if (!mid) return false;

    // If there's already a working gtag instance configured for this MID, use it.
    try {
      if (typeof window.gtag === "function") {
        var cidExisting = await getGaClientIdWithTimeout(mid, 1000);
        if (cidExisting) return true;
      }
    } catch (_) {}

    // De-dupe concurrent loads.
    if (__WS_GTAG_BOOTSTRAP__.p && __WS_GTAG_BOOTSTRAP__.mid === mid) {
      try {
        return await __WS_GTAG_BOOTSTRAP__.p;
      } catch (_) {
        return false;
      }
    }

    __WS_GTAG_BOOTSTRAP__.mid = mid;
    __WS_GTAG_BOOTSTRAP__.p = (async function () {
      // Set up the standard gtag shim (safe even if GTM is present).
      try {
        window.dataLayer = window.dataLayer || [];
        if (typeof window.gtag !== "function") {
          window.gtag = function () {
            window.dataLayer.push(arguments);
          };
        }
        window.gtag("js", new Date());
        window.gtag("config", mid, { send_page_view: false });
      } catch (_) {}

      var src =
        "https://www.googletagmanager.com/gtag/js?id=" + encodeURIComponent(mid);
      var ok = await loadExternalScript(src, 2500);
      if (!ok) return false;

      // Best-effort verification (some setups may not respond, but events can still send).
      try {
        var cidLoaded = await getGaClientIdWithTimeout(mid, 1000);
        if (cidLoaded) {
          try {
            // Keep TrackSharp's first-party CID aligned with the GA cookie CID.
            setCookie("ws_ga_cid", cidLoaded, 730);
          } catch (_) {}
        }
      } catch (_) {}
      return true;
    })();

    try {
      return await __WS_GTAG_BOOTSTRAP__.p;
    } catch (_) {
      return false;
    }
  }
  // --- GA4 session helpers (GS1 + GS2) ---
  function getGaCookieName(mid) {
    try {
      if (!mid) return null;
      // GA4 uses _ga_<MEASUREMENT_ID without "G-">
      var id = String(mid).replace(/^G-/, "");
      var name = "_ga_" + id;
      if (document.cookie.indexOf(name + "=") !== -1) return name;

      // fallback: first _ga_ cookie we can see
      var m = document.cookie.match(/(?:^|;\s)(_ga_[^=]+)=/);
      return m ? m[1] : null;
    } catch (_) {
      return null;
    }
  }

  function parseGaSessionFromCookie(val) {
    try {
      if (!val) return null;
      // GS1.1.<sid>.<sno>....
      var p = String(val).split(".");
      if (p.length >= 4 && p[0] === "GS1" && p[1] === "1") {
        var sid = parseInt(p[2], 10),
          sno = parseInt(p[3], 10);
        if (sid && sno) return { sid: sid, sno: sno };
      }

      // GS2.1.s<sid>$...$j<sno>$...
      // Split on '$' to be robust to ordering
      var core = String(val);
      // quick guard to avoid false positives
      if (core.indexOf("GS2.1") === 0) {
        var tokens = core.split("$");
        var sid = null,
          sno = null;
        for (var i = 0; i < tokens.length; i++) {
          var t = tokens[i];
          if (!t) continue;
          if (sid === null) {
            var ms = t.match(/(?:^|[\.\$])s(\d{6,})\b/);
            if (ms) sid = parseInt(ms[1], 10);
          }
          if (sno === null) {
            var mj = t.match(/(?:^|[\.\$])j(\d{1,})\b/);
            if (mj) sno = parseInt(mj[1], 10);
          }
          if (sid && sno) break;
        }
        if (sid && sno) return { sid: sid, sno: sno };
      }

      return null;
    } catch (_) {
      return null;
    }
  }

  async function getGaSessionInfo(mid) {
    try {
      var name = getGaCookieName(mid);
      if (!name) return null;
      var val = getCookie(name);
      return parseGaSessionFromCookie(val);
    } catch (_) {
      return null;
    }
  }
  // --- Fallback: derive GA4 client_id from the _ga cookie (works with GTM)
  function getGaClientIdFromCookie() {
    try {
      var v = (document.cookie.match(/(?:^|;\s)_ga=([^;]+)/) || [])[1];
      if (!v) return null;

      v = decodeURIComponent(v);
      var parts = v.split(".");

      if (
        parts.length >= 4 &&
        /^GA\d\.\d$/i.test(parts.slice(0, 2).join("."))
      ) {
        var p1 = parts[2],
          p2 = parts[3];
        if (p1 && p2) return p1 + "." + p2; // GA4 client_id format
      }
      return null;
    } catch (_) {
      return null;
    }
  }

  function metaEventName(name) {
    switch (name) {
      case "view_item":
        return "ViewContent";
      case "view_cart":
        return "ViewContent";
      case "add_to_cart":
        return "AddToCart";
      case "begin_checkout":
        return "InitiateCheckout";
      case "add_shipping_info":
        return "AddShippingInfo";
      case "add_payment_info":
        return "AddPaymentInfo";
      case "purchase":
        return "Purchase";
      default:
        return "CustomEvent";
    }
  }
  function getQueryParam(name) {
    var m = location.search.match(new RegExp("[?&]" + name + "=([^&]+)"));
    return m ? decodeURIComponent(m[1]) : null;
  }
  async function wsPostJSON(url, body, nonce) {
  const json = JSON.stringify(body);

 
  try {
    if (navigator.sendBeacon) {
      const ok = navigator.sendBeacon(
        url,
        new Blob([json], { type: "application/json" })
      );
      if (ok) return true;   
    
    }
  } catch (_) { /* fall through */ }

  // 2) Fallback: fetch (works for add_to_cart, not blocked by $beacon rules)
  try {
    await fetch(url, {
      method: "POST",
      headers: {
        "content-type": "application/json",
        ...(nonce ? { "X-WP-Nonce": nonce } : {}),
      },
      body: json,
      credentials: "same-origin",
      keepalive: true,
      cache: "no-store",
    });
    return true;
  } catch (_) { /* fall through */ }

  // 3) Last resort: XHR (some blockers allow this path)
  try {
    return await new Promise((resolve) => {
      const xhr = new XMLHttpRequest();
      xhr.open("POST", url, true);
      xhr.withCredentials = true;
      xhr.setRequestHeader("content-type", "application/json");
      if (nonce) xhr.setRequestHeader("X-WP-Nonce", nonce);
      xhr.onreadystatechange = () => {
        if (xhr.readyState === 4) resolve(xhr.status >= 200 && xhr.status < 500);
      };
      xhr.send(json);
    });
  } catch (_) {
    return false;
  }
}

  // --- WS audit helper (browser -> PHP logger) ---
  function wsGetAuditQueue() {
    try {
      if (!window.localStorage) return [];
      var raw = window.localStorage.getItem("tracksharp_audit_queue");
      if (!raw) return [];
      var parsed = JSON.parse(raw);
      return Array.isArray(parsed) ? parsed : [];
    } catch (_) {
      return [];
    }
  }

  function wsSetAuditQueue(items) {
    try {
      if (!window.localStorage) return;
      window.localStorage.setItem(
        "tracksharp_audit_queue",
        JSON.stringify(items.slice(-20))
      );
    } catch (_) {}
  }

  async function wsFlushAuditQueue() {
    var q = wsGetAuditQueue();
    if (!q.length) return;
    var remain = [];
    for (var i = 0; i < q.length; i++) {
      try {
        var ok = await wsPostJSON(CFG.rest_url, q[i], CFG.nonce);
        if (!ok) remain.push(q[i]);
      } catch (_) {
        remain.push(q[i]);
      }
    }
    wsSetAuditQueue(remain);
  }

  // Fire-and-forget flush on page load.
  try {
    wsFlushAuditQueue();
  } catch (_) {}

  async function wsAuditBrowser(channel, eventName, eventId, txid, extra) {
    try {
      if (!txid) return false;
      var audit = {
        audit_only: true,
        channel: channel, // 'ga4' or 'meta'
        source: "browser",
        event: eventName, // 'purchase' (ga4) or 'Purchase' (meta)
        event_id: eventId,
        ecom: { transaction_id: txid },
      };

      if (extra && typeof extra === "object") {
        try {
          for (var k in extra) {
            if (Object.prototype.hasOwnProperty.call(extra, k)) audit[k] = extra[k];
          }
        } catch (_) {}
      }

      var okSend = await wsPostJSON(CFG.rest_url, audit, CFG.nonce);
      if (!okSend) {
        var q2 = wsGetAuditQueue();
        q2.push(audit);
        wsSetAuditQueue(q2);
      }
      return okSend;
    } catch (_) {
      try {
        var q3 = wsGetAuditQueue();
        q3.push({
          audit_only: true,
          channel: channel,
          source: "browser",
          event: eventName,
          event_id: eventId,
          ecom: { transaction_id: txid },
        });
        wsSetAuditQueue(q3);
      } catch (_) {}
      return false;
    }
  }

  // ---- Consent Resolver (TCF + Consent Mode + adapters + fallback) ----
  var DEFAULT = {
    ad_storage: "denied",
    ad_user_data: "denied",
    ad_personalization: "denied",
  };
  var consent = CFG.consent || DEFAULT;
  var tcString = null,
    resolved = false,
    listeners = [];

  function granted(c) {
    return (
      c &&
      c.ad_storage === "granted" &&
      c.ad_user_data === "granted" &&
      c.ad_personalization === "granted"
    );
  }
  function setConsent(c, meta) {
    consent = c || DEFAULT;
    if (meta && meta.tcString) tcString = meta.tcString;
    resolved = true;
    while (listeners.length) {
      try {
        listeners.shift()(consent);
      } catch (e) {}
    }
  }
  function onConsent(fn) {
    if (granted(consent)) fn(consent);
    else listeners.push(fn);
  }

  // Testing override: ?ws_consent=granted|denied
  (function () {
    var ov = (getQueryParam("ws_consent") || "").toLowerCase();
    if (ov === "granted")
      setConsent({
        ad_storage: "granted",
        ad_user_data: "granted",
        ad_personalization: "granted",
      });
    if (ov === "denied") setConsent(DEFAULT);
  })();

  // Google Consent Mode v2 (generic, brand-agnostic)
  (function () {
    var dl = (window.dataLayer = window.dataLayer || []);
    var orig = dl.push;

    function handle(o) {
      if (!o) return;
      var a = o.ad_storage,
        u = o.ad_user_data,
        p = o.ad_personalization;
      if (a && u && p) {
        setConsent({ ad_storage: a, ad_user_data: u, ad_personalization: p });
      }
    }

    dl.push = function () {
      handle(arguments[0]);
      return orig.apply(this, arguments);
    };

    for (var i = 0; i < dl.length; i++) handle(dl[i]);
  })();

  // IAB TCF v2 (generic, brand-agnostic)
  (function waitTCF(i) {
    i = i || 0;
    if (typeof __tcfapi === "function") {
      __tcfapi("addEventListener", 2, function (tcData, ok) {
        if (!ok || !tcData) return;
        var p = (tcData.purpose && tcData.purpose.consents) || {};
        var ad_storage = p[1] ? "granted" : "denied"; // storage/access
        var ad_personalization = p[4] && p[1] ? "granted" : "denied";
        var ad_user_data =
          (p[3] || p[4] || p[7]) && p[1] ? "granted" : "denied";
        setConsent(
          { ad_storage, ad_user_data, ad_personalization },
          { tcString: tcData.tcString }
        );
      });
      return;
    }
    if (i < 40)
      setTimeout(function () {
        waitTCF(i + 1);
      }, 250);
  })();
  function qp(name) {
    var m = location.search.match(new RegExp("[?&]" + name + "=([^&]+)"));
    return m ? decodeURIComponent(m[1]) : null;
  }
  function stashClickIds() {
    try {
      var ids = {
        gclid: qp("gclid"),
        gbraid: qp("gbraid"),
        wbraid: qp("wbraid"),
      };
      Object.keys(ids).forEach(function (k) {
        var v = ids[k];
        if (v && v.length) setCookie("ws_" + k, v, 90); // 90 days
      });
    } catch (_) {}
  }
  stashClickIds();
  function getGaLegacyCookieName() {
    try {
      // Plain Universal/GA4 client cookie (not the _ga_<MID>)
      return document.cookie.indexOf("_ga=") !== -1 ? "_ga" : null;
    } catch (_) {
      return null;
    }
  }
  function parseGaClientIdFromGaCookie(val) {
    try {
      // GA*.1.<cidA>.<cidB>  → client_id = "<cidA>.<cidB>"
      var m = String(val || "").match(/^GA\d\.\d\.([0-9]+)\.([0-9]+)$/i);
      return m ? m[1] + "." + m[2] : null;
    } catch (_) {
      return null;
    }
  }

  // === First-party GA identifiers (gtag optional) ==========================
  (function ensureLocalGAIds() {
    var TWO_YEARS_DAYS = 730;
    var NINETY_DAYS = 90;
    var SESSION_TIMEOUT_MS = 30 * 60 * 1000;

    function nowSec() {
      return Math.floor(Date.now() / 1000);
    }
    function cidLike() {
      return nowSec() + "." + Math.floor(1e9 + Math.random() * 1e9);
    }
    function cmpHash() {
      var u = new URL(location.href);
      var keys = [
        "gclid",
        "gbraid",
        "wbraid",
        "utm_source",
        "utm_medium",
        "utm_campaign",
        "utm_id",
        "utm_term",
        "utm_content",
      ];
      return keys.map((k) => u.searchParams.get(k) || "").join("|");
    }

    // 1) CLIENT ID:
    (async function () {
      var cid = null;
      // Prefer the real GA cookie first (works even when gtag is absent / polyfilled).
      cid = getGaClientIdFromCookie();
      try {
        if (!cid) cid = await getGaClientId(CFG.ga4_mid);
      } catch (_) {}
      // Fall back to existing TrackSharp cookie only if we can't read GA's client_id.
      if (!cid) cid = getCookie("ws_ga_cid");
      if (!cid) {
        cid = cidLike();
      }
      setCookie("ws_ga_cid", cid, TWO_YEARS_DAYS);
    })();

    // 2) SESSION (sid/sno) with campaign reset
    (function () {
      var sid = parseInt(getCookie("ws_ga_sid") || "0", 10) || 0;
      var sno = parseInt(getCookie("ws_ga_sno") || "0", 10) || 0;
      var last = parseInt(getCookie("ws_ga_last") || "0", 10) || 0;
      var ch = getCookie("ws_ga_cmp") || "";

      var now = Date.now();
      var hnow = cmpHash();

      // Prefer the real GA4 session cookie when it exists, so server-side MP events
      // can attach to the same browser session (important for attribution + dedupe).
      var gaSess = null;
      try {
        var gaName = getGaCookieName(CFG.ga4_mid);
        if (gaName) gaSess = parseGaSessionFromCookie(getCookie(gaName));
      } catch (_) {
        gaSess = null;
      }

      if (gaSess && gaSess.sid && gaSess.sno) {
        sid = gaSess.sid;
        sno = gaSess.sno;
      } else {
        var needNew = false;
        if (!sid || !sno) needNew = true;
        else if (!last || now - last > SESSION_TIMEOUT_MS) needNew = true;
        else if (hnow !== ch && hnow.replace(/\|/g, "") !== "") needNew = true; // campaign change with any value

        if (needNew) {
          sid = nowSec();
          sno = sno > 0 ? sno + 1 : 1;
        }
      }

      setCookie("ws_ga_sid", String(sid), NINETY_DAYS);
      setCookie("ws_ga_sno", String(sno), NINETY_DAYS);
      setCookie("ws_ga_last", String(now), NINETY_DAYS);
      setCookie("ws_ga_cmp", hnow, NINETY_DAYS);
    })();
  })();

  // --- WP Consent API (brand-agnostic) ----------------------------
  (function () {
      function snapshotFromWPConsent() {
      try {
        if (typeof window.wp_has_consent !== "function") return false;

        var stats =
          !!window.wp_has_consent("statistics") ||
          !!window.wp_has_consent("statistics-anonymous");
        var marketing = !!window.wp_has_consent("marketing");

        // For Meta/advertising: all ad_* signals should require MARKETING consent
        // ad_storage specifically controls whether advertising cookies can be set
        setConsent({
          ad_storage: marketing ? "granted" : "denied",
          ad_user_data: marketing ? "granted" : "denied",
          ad_personalization: marketing ? "granted" : "denied",
        });
        return true;
      } catch (_) {
        return false;
      }
    }

    // Initial snapshot (if CMP already set categories) - run immediately so fallback knows if CMP exists
    snapshotFromWPConsent();

    // React when region/consent type is defined later in the pageload
    document.addEventListener("wp_consent_type_defined", function () {
      snapshotFromWPConsent();
    });

    // React to category changes (accept/revoke/toggle)
    document.addEventListener("wp_listen_for_consent_change", function () {
      snapshotFromWPConsent();
    });
  })();

  // Fallback (configurable) - ONLY applies if no CMP/WP Consent API resolved consent
  (function () {
    if (resolved) return;  // WP Consent API already set consent, don't override
    var mode = CFG.consent_fallback || "deny";
    if (mode === "grant_immediately") {
      setConsent({
        ad_storage: "granted",
        ad_user_data: "granted",
        ad_personalization: "granted",
      });
      return;
    }
    if (mode === "grant_if_absent") {
      var t = Number(CFG.consent_timeout_ms || 4000);
      setTimeout(function () {
        if (!resolved)
          setConsent({
            ad_storage: "granted",
            ad_user_data: "granted",
            ad_personalization: "granted",
          });
      }, t);
    }
  })();

  // Public consent API
  window.__WS_CONSENT__ = {
    onConsent: onConsent,
    get: function () {
      return consent;
    },
    tcString: function () {
      return tcString;
    },
  };
  function ws_collectUPD() {
    try {
      var c =
        window.__WS_CONSENT__ &&
        window.__WS_CONSENT__.get &&
        window.__WS_CONSENT__.get();
      if (!c || c.ad_user_data !== "granted") return null;

      function val(sel) {
        var el = document.querySelector(sel);
        return el && el.value ? String(el.value).trim() : "";
      }

      var email = val("#billing_email");
      var phone = val("#billing_phone") || val('input[name="billing_phone"]');
      var fn =
        val("#billing_first_name") || val('input[name="billing_first_name"]');
      var ln =
        val("#billing_last_name") || val('input[name="billing_last_name"]');
      var addr1 =
        val("#billing_address_1") || val('input[name="billing_address_1"]');
      var addr2 =
        val("#billing_address_2") || val('input[name="billing_address_2"]');
      var city = val("#billing_city") || val('input[name="billing_city"]');
      var state =
        val("#billing_state") ||
        val('select[name="billing_state"] option:checked') ||
        val("#billing_state");
      var zip =
        val("#billing_postcode") || val('input[name="billing_postcode"]');
      var country =
        val("#billing_country") ||
        val('select[name="billing_country"] option:checked') ||
        val("#billing_country");

      // Minimal signal: require at least one strong identifier
      if (!email && !phone) return null;

      return {
        email: email || undefined,
        phone: phone || undefined,
        first_name: fn || undefined,
        last_name: ln || undefined,
        address: {
          address1: addr1 || undefined,
          address2: addr2 || undefined,
          city: city || undefined,
          region: state || undefined,
          postal: zip || undefined,
          country: country || undefined,
        },
      };
    } catch (_) {
      return null;
    }
  }

  // ---- Session ID (first-party) ----
  // Let PHP set this only after the right consent category is granted.
  // If it's not there yet, we proceed without it; server still dedupes with event_id.
  var SID = getCookie(CFG.session_cookie_name) || null;

  // ---- Cart snapshot helpers (for view_cart/begin_checkout/shipping/payment) ----
  async function fetchCartSnapshot() {
    try {
      if (!window.fetch) throw new Error("no fetch");
      var resp = await fetch("/wp-json/wc/store/cart", {
        credentials: "same-origin",
      });
      if (!resp.ok) throw new Error("bad status " + resp.status);
      var data = await resp.json();

      var currency = (data && data.currency_code) || CFG.currency || "EUR";

      var items = [];
      try {
        if (Array.isArray(data.items)) {
          items = data.items.map(function (it) {
            var id =
              it.variation && it.variation.length ? it.variation_id : it.id;
            var price =
              it.prices && typeof it.prices.price === "number"
                ? it.prices.price / 100
                : undefined;
            return {
              item_id: String(id || it.id),
              item_name: it.name,
              quantity: it.quantity,
              price: price,
            };
          });
        }
      } catch (_) {}

      var value = 0;
      try {
        if (
          data.totals &&
          typeof data.totals.total_price === "number" &&
          data.totals.total_price > 0
        ) {
          value = data.totals.total_price / 100;
        } else if (items.length) {
          value = items.reduce(function (sum, i) {
            var p = typeof i.price === "number" ? i.price : 0;
            var q = parseInt(i.quantity || 1, 10) || 1;
            return sum + p * q;
          }, 0);
        }
      } catch (_) {}

      return { ecom: { currency: currency, value: value, items: items } };
    } catch (_) {
      return { ecom: { currency: CFG.currency || "EUR" } };
    }
  }
  async function fetchCartSnapshotStable(maxTries) {
    maxTries = maxTries || 3;
    var snap;
    for (var i = 0; i < maxTries; i++) {
      snap = await fetchCartSnapshot();
      if (snap && snap.ecom && snap.ecom.value && snap.ecom.value > 0)
        return snap;
      await new Promise((r) => setTimeout(r, 250));
    }
    return snap || { ecom: { currency: CFG.currency || "EUR" } };
  }


  async function postEvent(name, payload) {
    // ---- Robust consent waiting (handles slow CMPs like Complianz) ----
    // Poll for up to 5s for consent to be granted, not just for wp_has_consent to exist.
    // This fixes attribution loss on slow sites where CMP restores consent after page load.
    var consentWaitStart = Date.now();
    var consentTimeout = 5000; // 5 seconds for slow sites
    var marketingGranted = false;
    var statsGranted = false;

    // Helper to check Complianz cookies directly as fallback
    function checkComplianzCookies() {
      try {
        // Complianz stores consent in cmplz_* cookies
        var statsCookie = getCookie("cmplz_statistics");
        var marketingCookie = getCookie("cmplz_marketing");
        
        var statsGranted = (statsCookie === "allow" || statsCookie === "yes" || statsCookie === "1");
        var marketingGranted = (marketingCookie === "allow" || marketingCookie === "yes" || marketingCookie === "1");
        
        if (statsGranted || marketingGranted) {
          return { stats: statsGranted, marketing: marketingGranted };
        }
        
        // Fallback: check banner status
        var bannerStatus = getCookie("cmplz_banner-status");
        if (bannerStatus === "dismissed" || bannerStatus === "set") {
          return { stats: false, marketing: false }; // Banner dismissed but no explicit consent
        }
      } catch (_) {}
      return null;
    }

    // Helper to check Cookiebot cookies directly as fallback
    function checkCookiebotCookies() {
      try {
        // Cookiebot stores consent in CookieConsent cookie
        var consent = getCookie("CookieConsent");
        if (!consent) return null;
        
        // Format: {stamp:'...',necessary:true,preferences:true,statistics:true,marketing:true,...}
        var statsGranted = consent.includes("statistics:true") || consent.includes("statistics%3Atrue");
        var marketingGranted = consent.includes("marketing:true") || consent.includes("marketing%3Atrue");
        
        if (statsGranted || marketingGranted) {
          return { stats: statsGranted, marketing: marketingGranted };
        }
      } catch (_) {}
      return null;
    }

    // Poll for consent with fallback
    while ((Date.now() - consentWaitStart) < consentTimeout) {
      // First try WP Consent API
      if (typeof window.wp_has_consent === "function") {
        marketingGranted = !!window.wp_has_consent("marketing");
        statsGranted = !!window.wp_has_consent("statistics") || !!window.wp_has_consent("statistics-anonymous");
        if (statsGranted || marketingGranted) {
          DBG("[WS] consent resolved via WP Consent API", { stats: statsGranted, marketing: marketingGranted });
          break;
        }
      }
      // Fallback: check Complianz cookies directly
      var complianzConsent = checkComplianzCookies();
      if (complianzConsent) {
        statsGranted = complianzConsent.stats;
        marketingGranted = complianzConsent.marketing;
        DBG("[WS] consent resolved via Complianz cookies", complianzConsent);
        break;
      }
      // Fallback: check Cookiebot cookies directly
      var cookiebotConsent = checkCookiebotCookies();
      if (cookiebotConsent) {
        statsGranted = cookiebotConsent.stats;
        marketingGranted = cookiebotConsent.marketing;
        DBG("[WS] consent resolved via Cookiebot cookies", cookiebotConsent);
        break;
      }
      await new Promise(r => setTimeout(r, 100));
    }

    // Final fallback after timeout
    if (!statsGranted && !marketingGranted) {
      // One more WP Consent API check
      if (typeof window.wp_has_consent === "function") {
        marketingGranted = !!window.wp_has_consent("marketing");
        statsGranted = !!window.wp_has_consent("statistics") || !!window.wp_has_consent("statistics-anonymous");
      }
      // One more Complianz cookie check
      if (!statsGranted && !marketingGranted) {
        var finalComplianz = checkComplianzCookies();
        if (finalComplianz) { 
          statsGranted = finalComplianz.stats; 
          marketingGranted = finalComplianz.marketing; 
        }
      }
      // One more Cookiebot cookie check
      if (!statsGranted && !marketingGranted) {
        var finalCookiebot = checkCookiebotCookies();
        if (finalCookiebot) { 
          statsGranted = finalCookiebot.stats; 
          marketingGranted = finalCookiebot.marketing; 
        }
      }
      // Ultimate fallback: configured fallback mode (only if no CMP detected)
      if (!statsGranted && !marketingGranted && typeof window.wp_has_consent !== "function") {
        if (CFG.consent_fallback === "grant_immediately") {
          marketingGranted = true;
          statsGranted = true;
          DBG("[WS] consent granted via fallback (no CMP detected)");
        }
      }
    }

    // Keep legacy consent object for Meta signals (marketing-gated)
    consent = {
      ad_storage: marketingGranted ? "granted" : "denied",
      ad_user_data: marketingGranted ? "granted" : "denied",
      ad_personalization: marketingGranted ? "granted" : "denied",
    };


    var c = consent; // current snapshot (marketing)
    var allowMetaBrowser = granted(c); // Meta requires marketing consent
    var ga4AttributionMode =
      (CFG && CFG.ga4_attribution_mode) || "ads_first";
    // GA4 browser purchase should only fire in reporting-first mode.
    // In ads-first mode, TrackSharp relies on the server-side purchase as canonical.
    var allowGa4Browser =
      !!statsGranted && ga4AttributionMode === "reporting_first";


    var allowServer = true;

    if (!allowMetaBrowser && !allowGa4Browser && !allowServer) {
      DBG("[WS] blocked by consent (browser+server say no):", name, {
        consent: DBG.clone(c),
      });
      return;
    }

    var eventId = (payload && payload.__event_id) || uuid();
    var fbp = getCookie("_fbp") || undefined;
    var fbc = getCookie("_fbc") || undefined;
    var gaClientId = null;
    try {
      gaClientId = await getGaClientId(CFG.ga4_mid);
    } catch (_) {}
    if (!gaClientId) gaClientId = getGaClientIdFromCookie() || null;
    if (!gaClientId) gaClientId = getCookie("ws_ga_cid") || null;
    if (gaClientId) {
      try {
        if (getCookie("ws_ga_cid") !== gaClientId) {
          setCookie("ws_ga_cid", gaClientId, 730);
        }
      } catch (_) {}
    }

    var metaConfigured = !!(CFG && CFG.meta_pixel_id && String(CFG.meta_pixel_id).trim());
    var hasFbq = typeof fbq === "function";
    var fbqLoaded = hasFbq && typeof fbq.callMethod === "function";
    var hasGtag = typeof gtag === "function" && !!CFG.ga4_mid;
    var skipServer = !!(payload && payload.__skip_server === true);

    DBG("[WS] post:start", name, {
      eventId,
      allowMetaBrowser,
      allowGa4Browser,
      allowServer,
      ga4AttributionMode,
      metaConfigured,
      hasFbq, fbqLoaded,
      hasGtag,
      fbp,
      fbc,
      gaClientId,
      payload: DBG.clone(payload),
    });

    // 1) Browser tags ONLY if consent granted
    var metaBrowserFired = false;
    try {
      if (allowMetaBrowser && metaConfigured && hasFbq) {
        var fbPayload = {};
        if (payload && payload.ecom && payload.ecom.currency)
          fbPayload.currency = payload.ecom.currency;
        if (
          payload &&
          payload.ecom &&
          typeof payload.ecom.value !== "undefined"
        )
          fbPayload.value = payload.ecom.value;
        if (payload && payload.ecom && payload.ecom.items) {
          fbPayload.content_type = "product";
          fbPayload.contents = payload.ecom.items.map(function (i) {
            return {
              id: i.item_id,
              quantity: i.quantity || 1,
              item_price: i.price,
            };
          });
        }
        if (payload && payload.meta_params) {
          try {
            Object.assign(fbPayload, payload.meta_params);
          } catch (_) {}
        }
        fbq("track", metaEventName(name), fbPayload, { eventID: eventId });
        if (name === "purchase") {
          if (fbqLoaded) {
            metaBrowserFired = true; // real pixel live now
          } else {
            try {
              var txidDefer =
                payload && payload.ecom && payload.ecom.transaction_id
                  ? payload.ecom.transaction_id
                  : undefined;
              if (txidDefer) {
                setTimeout(function () {
                  try {
                    if (
                      typeof fbq === "function" &&
                      typeof fbq.callMethod === "function"
                    ) {
                      wsAuditBrowser(
                        "meta",
                        "Purchase",
                        eventId,
                        txidDefer
                      );
                    }
                  } catch (_) {}
                }, 1500);
              }
            } catch (_) {}
          }
        }
      }
    } catch (e) {
      DBG("[WS] fbq error:", e && (e.stack || e.message || e));
    }

    if (metaBrowserFired) {
      try {
        var txidM =
          payload && payload.ecom && payload.ecom.transaction_id
            ? payload.ecom.transaction_id
            : undefined;
        if (txidM) {
          wsAuditBrowser("meta", "Purchase", eventId, txidM); // Meta capitalized
        }
      } catch (_) {}
    }

    // GA4 browser branch (purchase only):
    // Purpose: ensure a browser-side purchase can be sent without requiring a GTM purchase tag.
    // This helps GA4 attribute purchases to the existing browser session and enables deduplication
    // with the server-side MP purchase (same event_id + transaction_id).
    var gaBrowserFired = false;
    try {
      var isPurchase = name === "purchase";
      var isEcommerce = isPurchase || ["view_item", "add_to_cart", "begin_checkout", "view_item_list", "select_item", "remove_from_cart", "view_cart", "add_shipping_info", "add_payment_info"].indexOf(name) !== -1;

      // Keep browser + server GA4 event names aligned for deduplication and dashboard metrics.
      // When comparison mode is enabled, server purchases are sent as "purchase_sst".
      var gaEventName = isPurchase ? ((CFG && CFG.ga4_purchase_event_name) || "purchase") : name;
      if (isPurchase && gaEventName !== "purchase" && gaEventName !== "purchase_sst") {
        gaEventName = "purchase";
      }

      var txidAudit =
        payload && payload.ecom && payload.ecom.transaction_id
          ? payload.ecom.transaction_id
          : undefined;

      if (isEcommerce && allowGa4Browser && CFG.ga4_mid) {
        if (gaEventName === "purchase_sst") {
          DBG("[WS] GA4 browser purchase suppressed (purchase_sst comparison mode)", {
            mid: CFG.ga4_mid,
          });
        } else {
        var okGtag = false;
        try {
          okGtag = await ensureGtagForMid(CFG.ga4_mid);
        } catch (_) {
          okGtag = false;
        }
        if (!okGtag || typeof window.gtag !== "function") {
          DBG("[WS] GA4 browser send skipped (no gtag)", name, {
            mid: CFG.ga4_mid,
          });
        } else {
        var gaParams = { event_id: eventId };
        if (payload && payload.ecom && payload.ecom.currency)
          gaParams.currency = payload.ecom.currency;
        if (
          payload &&
          payload.ecom &&
          typeof payload.ecom.value !== "undefined"
        )
          gaParams.value = payload.ecom.value;
        if (payload && payload.ecom && payload.ecom.items)
          gaParams.items = payload.ecom.items;
        // Add transaction_id for purchase events (required for GA4 deduplication)
        if (name === "purchase" && payload && payload.ecom && payload.ecom.transaction_id) {
          gaParams.transaction_id = payload.ecom.transaction_id;
        }
        if (payload && payload.ga_params) {
          try {
            Object.assign(gaParams, payload.ga_params);
          } catch (_) {}
        }
        
        // Attribution enrichment: ensure the original referrer is never lost in browser hits
        try {
          var preservedRef = sessionStorage.getItem("ws_initial_referrer");
          if (preservedRef) gaParams.page_referrer = preservedRef;
          gaParams.page_location = location.href;
        } catch (_) {}

        gaParams.send_to = CFG.ga4_mid;
          try {
            window.gtag("event", gaEventName, gaParams);
            DBG("[WS] GA4 browser event sent:", gaEventName, CFG.ga4_mid, gaParams);
            if (isEcommerce) {
              gaBrowserFired = true;
            }
          } catch (e2) {
            DBG("[WS] GA4 browser purchase send error:", e2 && (e2.stack || e2.message || e2));
          }
        }
        }
      }

      // Always log a GA4 browser receipt (audit-only) for ecommerce events.
      // This powers the Dashboard breakdown and lets the server decide whether a server-side
      // fallback is needed. The receipt includes whether TrackSharp actually sent the browser hit.
      // We audit all ecommerce events in reporting_first mode to ensure the dashboard remains accurate.
      var shouldAudit = isPurchase || (ga4AttributionMode === "reporting_first" && isEcommerce);
      if (shouldAudit && !!statsGranted && gaEventName !== "purchase_sst") {
        try {
          // Use txidAudit for purchases, or eventId for other ecommerce events to ensure uniqueness in log if needed
          var auditId = txidAudit || eventId;
          await wsAuditBrowser("ga4", gaEventName, eventId, auditId, {
            ga4_browser_sent: gaBrowserFired ? 1 : 0,
            ga4_attribution_mode: ga4AttributionMode,
          });
        } catch (_) {}
      }
    } catch (e) {
      DBG("[WS] gtag/dataLayer error:", e && (e.stack || e.message || e));
    }
    // 2) Server send even if browser consent isn't granted (server enforces WP Consent API)
    if (!skipServer && allowServer) {
      var upd = ws_collectUPD();
      var userPayload = (function () {
        // If the caller already passed user data, prefer that; else take our snapshot
        if (payload && payload.user) return payload.user;
        return upd || undefined;
      })();
      var pageUrl =
        typeof location !== "undefined" && location.href
          ? location.href
          : undefined;
      var gclid = getCookie("ws_gclid") || qp("gclid") || undefined;
      var gbraid = getCookie("ws_gbraid") || qp("gbraid") || undefined;
      var wbraid = getCookie("ws_wbraid") || qp("wbraid") || undefined;
      // before building body:
      var gaSess = null;
      try {
        gaSess = await getGaSessionInfo(CFG.ga4_mid);
      } catch (_) {
        gaSess = null;
      }
      var sid =
        gaSess && gaSess.sid
          ? gaSess.sid
          : parseInt(getCookie("ws_ga_sid") || "0", 10) || undefined;
      var sno =
        gaSess && gaSess.sno
          ? gaSess.sno
          : parseInt(getCookie("ws_ga_sno") || "0", 10) || undefined;
      var body = {
        event: name,
        event_id: eventId,
        ts: new Date().toISOString(),
        ids: {
          session_id: SID,
          ga4_client_id: gaClientId,
          ga_session_id: sid,
          ga_session_number: sno,
          fbp: fbp,
          fbc: fbc,
          gclid: gclid,
          gbraid: gbraid,
          wbraid: wbraid,
        },
        page_url: pageUrl,
        page_referrer:
          sessionStorage.getItem("ws_initial_referrer") ||
          document.referrer ||
          undefined,
        user_agent: navigator.userAgent,
        consent: (function () {
          var tc =
            window.__WS_CONSENT__ && window.__WS_CONSENT__.tcString
              ? window.__WS_CONSENT__.tcString()
              : null;
          var cnow =
            window.__WS_CONSENT__ && window.__WS_CONSENT__.get
              ? window.__WS_CONSENT__.get()
              : null;
          if (!cnow) return undefined;
          var out = {
            ad_storage: cnow.ad_storage,
            ad_user_data: cnow.ad_user_data,
            ad_personalization: cnow.ad_personalization,
          };
          if (tc) out.tc_string = tc;
          return out;
        })(),
        ecom: payload && payload.ecom ? payload.ecom : undefined,
        user: userPayload,
        ga4_browser_sent: gaBrowserFired ? 1 : 0,
        ga4_attribution_mode: ga4AttributionMode,
      };

      try {
       wsPostJSON(CFG.rest_url, body, CFG.nonce);

      } catch (e) {
        DBG("[WS] server send error:", e && (e.stack || e.message || e));
      }
    }

    DBG("[WS] post:done", name, {
      eventId: eventId,
      allowMetaBrowser: allowMetaBrowser,
      allowGa4Browser: allowGa4Browser,
      allowServer: allowServer,
    });
  }

  // Public API
  window.TrackSharpTracker = window.TrackSharpTracker || {};
  window.TrackSharpTracker.postEvent = function (name, payload) {
    // Fire immediately. Browser tags will only run if consent is granted.
    // Server will enforce WP Consent API either way.
    postEvent(name, payload || {});
  };

  // ---- Auto: VIEW ITEM (once per PDP) ----
  (function () {
    var sent = false;

    if (sent) return;
    if (!CFG.is_product) return;
    var payload = null;

    if (CFG.product && CFG.product.item_id) {
      payload = {
        ecom: {
          currency: CFG.currency || "EUR",
          items: [
            {
              item_id: CFG.product.item_id,
              item_name: CFG.product.item_name || undefined,
              price:
                typeof CFG.product.price !== "undefined"
                  ? CFG.product.price
                  : undefined,
              quantity: 1,
            },
          ],
        },
      };
    } else {
      try {
        var ld = document.querySelector('script[type="application/ld+json"]');
        if (ld && ld.textContent.indexOf('"@type":"Product"') > -1) {
          var data = JSON.parse(ld.textContent);
          var price =
            data && data.offers && data.offers.price
              ? Number(data.offers.price)
              : undefined;
          payload = {
            ecom: {
              currency: CFG.currency || "EUR",
              items: [
                {
                  item_id:
                    (data && (data.sku || data.productID || data.url)) ||
                    location.pathname,
                  item_name: data ? data.name : undefined,
                  price: price,
                  quantity: 1,
                },
              ],
            },
          };
        }
      } catch (_) {}
    }

    if (payload) {
      sent = true;
      postEvent("view_item", payload);
    }
  })();

  // ---- Add to Cart capture (AJAX + non-AJAX + Store API + links) ----
  (function () {
    var lastATC = { pid: null, ts: 0 };

    function fireATC(pid, qty, name) {
      if (!pid) return;
      qty = parseInt(qty || "1", 10) || 1;
      var now = Date.now();
      if (lastATC.pid === String(pid) && now - lastATC.ts < 1500) return; // local dedupe
      lastATC = { pid: String(pid), ts: now };

      try {
        // Mark to suppress cookie replay on next page load
        sessionStorage.setItem(
          "ws_atc_sent_" + String(pid),
          String(Date.now())
        );
        document.cookie =
          "ws_atc_noreplay=1; path=/; max-age=" + 5 * 60 + "; SameSite=Lax";
      } catch (_) {}

      var data = {
        ecom: {
          currency: CFG.currency,
          items: [
            {
              item_id: String(pid),
              item_name: name || undefined,
              quantity: qty,
            },
          ],
        },
      };

      postEvent("add_to_cart", data);
    }

    function readFromForm(form) {
      if (!form) return null;
      var vidEl = form.querySelector('input[name="variation_id"]');
      var vid = vidEl && parseInt(vidEl.value || "0", 10);
      var idEl = form.querySelector(
        'input[name="add-to-cart"], button[name="add-to-cart"]'
      );
      var pid =
        vid && vid > 0
          ? vid
          : idEl
          ? idEl.value || idEl.getAttribute("value")
          : null;
      var qtyEl = form.querySelector('input[name="quantity"]');
      var qty = qtyEl ? qtyEl.value : 1;
      var nameEl = document.querySelector(".product_title, h1.product_title");
      var name = nameEl ? nameEl.textContent.trim() : undefined;
      return pid ? { pid: pid, qty: qty, name: name } : null;
    }

    // 1) Woo jQuery hook
    if (window.jQuery && jQuery.fn && jQuery.fn.on) {
      jQuery(document.body).on(
        "added_to_cart",
        function (ev, fragments, cart_hash, $button) {
          try {
            var pid =
              $button &&
              ($button.data("product_id") || $button.attr("data-product_id"));
            var qty =
              ($button &&
                ($button.data("quantity") || $button.attr("data-quantity"))) ||
              1;
            fireATC(pid, qty);
          } catch (_) {}
        }
      );
    }

    // 2) Intercept XHR (admin-ajax.php?wc-ajax=add_to_cart)
    (function () {
      var XHR = window.XMLHttpRequest;
      if (!XHR) return;
      var _open = XHR.prototype.open,
        _send = XHR.prototype.send;
      XHR.prototype.open = function (method, url) {
        try {
          this.__ws_url = typeof url === "string" ? url : url && url.toString();
        } catch (_) {}
        return _open.apply(this, arguments);
      };
      XHR.prototype.send = function (body) {
        try {
          this.addEventListener("load", function () {
            try {
              var u = String(this.__ws_url || "");
              var isATC =
                u.indexOf("wc-ajax=add_to_cart") > -1 ||
                u.indexOf("action=woocommerce_ajax_add_to_cart") > -1;
              if (!isATC || this.status !== 200) return;
              var json = null;
              try {
                json = JSON.parse(this.responseText);
              } catch (_) {}
              var pid =
                json &&
                json.data &&
                (json.data.product_id || json.data.product);
              var qty = json && json.data && (json.data.quantity || 1);
              var name = json && json.data && json.data.product_name;
              fireATC(pid, qty, name);
            } catch (_) {}
          });
        } catch (_) {}
        return _send.apply(this, arguments);
      };
    })();

    // 3) Intercept Store API fetch
    (function () {
      if (!window.fetch) return;
      var _fetch = window.fetch;
      window.fetch = function (input, init) {
        var url =
          (typeof input === "string" ? input : input && input.url) || "";
        var method = (init && init.method) || (input && input.method) || "GET";
        var looksLikeStoreATC =
          method.toUpperCase() === "POST" &&
          /\/wp-json\/wc\/store\/v\d+\/cart\/(add-item|add)/.test(url);
        if (!looksLikeStoreATC) return _fetch.apply(this, arguments);

        var pid = null,
          qty = 1;
        try {
          if (init && init.body) {
            var b =
              typeof init.body === "string" ? JSON.parse(init.body) : init.body;
            pid = b && (b.id || b.product_id || b.product);
            qty = (b && (b.quantity || b.qty)) || 1;
          }
        } catch (_) {}

        return _fetch.apply(this, arguments).then(function (resp) {
          try {
            if (resp && resp.ok && pid) fireATC(pid, qty);
          } catch (_) {}
          return resp;
        });
      };
    })();

    // 4) Non-AJAX form submit/button click
    document.addEventListener(
      "submit",
      function (e) {
        try {
          var f = e.target;
          if (!f || !f.matches || !f.matches("form.cart")) return;
          var info = readFromForm(f);
          if (!info) return;
          if (navigator.sendBeacon) fireATC(info.pid, info.qty, info.name);
          else {
            // fallback: PHP sets ws_atc cookie and replay (see block below)
            sessionStorage.setItem(
              "ws_atc_pending",
              JSON.stringify({
                pid: String(info.pid),
                qty: parseInt(info.qty || "1", 10) || 1,
                name: info.name || undefined,
                ts: Date.now(),
              })
            );
          }
        } catch (_) {}
      },
      true
    );

    document.addEventListener(
      "click",
      function (e) {
        try {
          var btn =
            e.target &&
            e.target.closest &&
            e.target.closest(".single_add_to_cart_button");
          if (!btn) return;
          var form = btn.closest && btn.closest("form.cart");
          var info = readFromForm(form);
          if (!info) return;
          if (navigator.sendBeacon) fireATC(info.pid, info.qty, info.name);
          else {
            sessionStorage.setItem(
              "ws_atc_pending",
              JSON.stringify({
                pid: String(info.pid),
                qty: parseInt(info.qty || "1", 10) || 1,
                name: info.name || undefined,
                ts: Date.now(),
              })
            );
          }
        } catch (_) {}
      },
      true
    );

    // 5) Links like ?add-to-cart=ID
    document.addEventListener(
      "click",
      function (e) {
        try {
          var a =
            e.target &&
            e.target.closest &&
            e.target.closest('a[href*="add-to-cart="]');
          if (!a) return;
          var m = a.getAttribute("href").match(/[?&]add-to-cart=(\d+)/);
          if (!m) return;
          var pid = m[1];
          var qty =
            a.getAttribute("data-quantity") ||
            a.getAttribute("aria-quantity") ||
            1;
          if (navigator.sendBeacon) fireATC(pid, qty);
          else {
            sessionStorage.setItem(
              "ws_atc_pending",
              JSON.stringify({
                pid: String(pid),
                qty: parseInt(qty || "1", 10) || 1,
                ts: Date.now(),
              })
            );
          }
        } catch (_) {}
      },
      true
    );
  })();

  // ---- ATC server-flag replay (non-AJAX POST + redirects or 200 renders) ----
  (function () {
    function clearATC() {
      document.cookie =
        "ws_atc=; path=/; expires=Thu, 01 Jan 1970 00:00:00 GMT; SameSite=Lax";
    }
    function clearNoReplayFlag() {
      document.cookie =
        "ws_atc_noreplay=; path=/; expires=Thu, 01 Jan 1970 00:00:00 GMT; SameSite=Lax";
    }
    try {
      // Skip replay on order-received (thank-you) pages - purchase already completed
      if (/[?&]key=wc_order/.test(location.search) || /\/order-received\//.test(location.pathname)) {
        DBG && DBG("[WS] atc:replay skipped (order-received page)");
        clearATC();
        clearNoReplayFlag();
        return;
      }
      
      var raw = getCookie("ws_atc");
      if (!raw) return;

      var data = null;
      try {
        data = JSON.parse(raw);
      } catch (_) {}

      var pid = data && (data.pid || data.product_id);
      var qty = (data && (data.qty || data.quantity)) || 1;
      if (!pid) {
        clearATC();
        clearNoReplayFlag();
        return;
      }

      // ⛔ NEW: skip replay if we just sent the immediate beacon
      var recent = 0;
      try {
        recent = parseInt(
          sessionStorage.getItem("ws_atc_sent_" + String(pid)) || "0",
          10
        );
      } catch (_) {}
      if (recent && Date.now() - recent < 6000) {
        DBG && DBG("[WS] atc:replay skipped (recent immediate send)");
        clearATC();
        clearNoReplayFlag();
        return;
      }

      // ⛔ NEW: skip once if noreplay flag present (full page navs)
      if (getCookie("ws_atc_noreplay") === "1") {
        DBG && DBG("[WS] atc:replay skipped (noreplay flag)");
        clearATC();
        clearNoReplayFlag();
        return;
      }

      // Legit replay (only when the page POST didn’t allow an immediate beacon)

      postEvent("add_to_cart", {
        ecom: {
          currency: CFG.currency,
          items: [{ item_id: String(pid), quantity: parseInt(qty, 10) || 1 }],
        },
      });
      clearATC();
      clearNoReplayFlag();
      DBG &&
        DBG("[WS] atc:replay →", {
          pid: String(pid),
          qty: parseInt(qty, 10) || 1,
        });
    } catch (e) {
      clearATC();
      clearNoReplayFlag();
    }
  })();

  // ---- VIEW CART (once per cart page load) ----
  (async function () {
    function isCartPage() {
      var b = document.body && document.body.classList;
      return (
        (b && b.contains("woocommerce-cart")) ||
        /(^|\/)cart(\/|$)/.test(location.pathname)
      );
    }
    if (!isCartPage()) return;
    var fired = false;

    if (fired) return;
    fired = true;
    var snap = await fetchCartSnapshot();
    snap.meta_params = { content_category: "cart" }; // helps separate from PDP ViewContent
    postEvent("view_cart", snap);
  })();

  // ---- BEGIN CHECKOUT (cart->checkout click OR first load on checkout) ----
  (function () {
    const CART_KEY = (window.wc && wc.cart_hash) || ""; // optional, empty is fine
    const KEY = "ws_begin_checkout_once_" + CART_KEY;

    function already() {
      try {
        return sessionStorage.getItem(KEY) === "1";
      } catch (_) {
        return false;
      }
    }
    function mark() {
      try {
        sessionStorage.setItem(KEY, "1");
      } catch (_) {}
    }

    function isCheckoutPage() {
      const b = document.body && document.body.classList;
      return (
        (b && b.contains("woocommerce-checkout")) ||
        /(^|\/)checkout(\/|$)/.test(location.pathname)
      );
    }

    // Fire immediately with minimal payload (safe during navigation)
    function fireFast() {
      if (already()) return;
      mark();
      postEvent("begin_checkout", {
        ecom: { currency: CFG.currency || "EUR" },
      });
    }

    // Fire with a full cart snapshot (only when we are already on checkout)
    async function fireRich() {
      if (already()) return;
      mark();
      const snap = await fetchCartSnapshotStable();
      postEvent("begin_checkout", snap);
    }

    // Case 1: we landed on the checkout page directly
    if (isCheckoutPage()) {
      fireRich();
    }

    // Case 2: we click "Proceed to checkout" on the cart page
    document.addEventListener(
      "click",
      function (e) {
        const el =
          e.target &&
          e.target.closest &&
          e.target.closest(
            ".checkout-button, a.checkout-button, .wc-proceed-to-checkout a, a.wc-forward.checkout-button"
          );
        if (!el) return;
        // Fire immediately; don't await a snapshot that will be aborted by navigation
        fireFast();
      },
      true
    );
  })();

  // ---- ADD SHIPPING INFO (on method change) ----
  (function () {
    var last = { method: null, ts: 0 };
    function dedupe(method) {
      var now = Date.now();
      if (last.method === method && now - last.ts < 3000) return true;
      last = { method: method, ts: now };
      return false;
    }
    function getSelectedShipping() {
      var input = document.querySelector(
        'input[name^="shipping_method"]:checked'
      );
      if (!input) return null;
      var label = input.closest("label")
        ? input.closest("label").innerText.trim()
        : input.value;
      return label || input.value || "unknown";
    }
    async function handler() {
      var method = getSelectedShipping();
      if (!method || dedupe(method)) return;

      var snap = await fetchCartSnapshot();
      snap.ga_params = { shipping_tier: method };
      postEvent("add_shipping_info", snap);
    }
    document.addEventListener(
      "change",
      function (e) {
        var t = e.target;
        if (!t) return;
        if (t.matches('input[name^="shipping_method"]')) handler();
      },
      true
    );
    window.addEventListener("load", function () {
      setTimeout(handler, 1500);
    });
  })();

  // ---- ADD PAYMENT INFO (on method change) ----
  (function () {
    var last = { method: null, ts: 0 };
    function dedupe(method) {
      var now = Date.now();
      if (last.method === method && now - last.ts < 3000) return true;
      last = { method: method, ts: now };
      return false;
    }
    function getPaymentMethod() {
      var input = document.querySelector(
        'input[name="payment_method"]:checked'
      );
      if (!input) return null;
      var label =
        input.closest("li") && input.closest("li").querySelector("label");
      var name =
        (label && label.textContent && label.textContent.trim()) || input.value;
      return name || input.value || "unknown";
    }
    async function handler() {
      var method = getPaymentMethod();
      if (!method || dedupe(method)) return;

      var snap = await fetchCartSnapshot();
      snap.ga_params = { payment_type: method };
      postEvent("add_payment_info", snap);
    }
    document.addEventListener(
      "change",
      function (e) {
        var t = e.target;
        if (!t) return;
        if (t.matches('input[name="payment_method"]')) handler();
      },
      true
    );
    window.addEventListener("load", function () {
      setTimeout(handler, 1500);
    });
  })();
})();









