/******/ (function() { // webpackBootstrap
/******/ 	"use strict";
/******/ 	// The require scope
/******/ 	var __webpack_require__ = {};
/******/ 	
/************************************************************************/
/******/ 	/* webpack/runtime/compat get default export */
/******/ 	!function() {
/******/ 		// getDefaultExport function for compatibility with non-harmony modules
/******/ 		__webpack_require__.n = function(module) {
/******/ 			var getter = module && module.__esModule ?
/******/ 				function() { return module['default']; } :
/******/ 				function() { return module; };
/******/ 			__webpack_require__.d(getter, { a: getter });
/******/ 			return getter;
/******/ 		};
/******/ 	}();
/******/ 	
/******/ 	/* webpack/runtime/define property getters */
/******/ 	!function() {
/******/ 		// define getter functions for harmony exports
/******/ 		__webpack_require__.d = function(exports, definition) {
/******/ 			for(var key in definition) {
/******/ 				if(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) {
/******/ 					Object.defineProperty(exports, key, { enumerable: true, get: definition[key] });
/******/ 				}
/******/ 			}
/******/ 		};
/******/ 	}();
/******/ 	
/******/ 	/* webpack/runtime/hasOwnProperty shorthand */
/******/ 	!function() {
/******/ 		__webpack_require__.o = function(obj, prop) { return Object.prototype.hasOwnProperty.call(obj, prop); }
/******/ 	}();
/******/ 	
/************************************************************************/

;// external "wp.element"
var external_wp_element_namespaceObject = wp.element;
;// ./vendor/carticy/admin-ui/js/src/mount.js
/**
 * Mount-root helper.
 *
 * Every token and global reset in this design system is scoped to the
 * `.cv-root` class so multiple Carticy plugins (and versions) can coexist
 * on one site without leaking styles into general wp-admin. Call this on
 * your plugin's mount element before rendering the React app.
 */

/**
 * Mark an element as the design-system root.
 *
 * @param {HTMLElement|null} element  Mount element (e.g. document.getElementById('root')).
 * @param {Object}           options  Optional flags.
 * @param {string}           options.page  Optional data-page attribute value.
 * @return {HTMLElement|null} The same element, for chaining into render().
 */
function adminUiRoot(element, options = {}) {
  if (!element || !element.classList) {
    return element;
  }
  element.classList.add('cv-root');
  if (options.page) {
    element.setAttribute('data-page', options.page);
  }
  return element;
}
;// ./vendor/carticy/admin-ui/js/src/components/Field.jsx
/* unused harmony import specifier */ var useId;
function _extends() { return _extends = Object.assign ? Object.assign.bind() : function (n) { for (var e = 1; e < arguments.length; e++) { var t = arguments[e]; for (var r in t) ({}).hasOwnProperty.call(t, r) && (n[r] = t[r]); } return n; }, _extends.apply(null, arguments); }
/**
 * Form fields — wrap .cv-label / .cv-input / .cv-select / .cv-textarea
 * with .cv-help and .cv-error-msg.
 */

function FieldShell({
  id,
  label,
  help,
  error,
  children
}) {
  return wp.element.createElement("div", {
    className: "cv-field"
  }, label && wp.element.createElement("label", {
    className: "cv-label",
    htmlFor: id
  }, label), children, help && !error && wp.element.createElement("p", {
    className: "cv-help"
  }, help), error && wp.element.createElement("span", {
    className: "cv-error-msg"
  }, error));
}
function TextField({
  label,
  help,
  error,
  className = '',
  ...rest
}) {
  const id = useId();
  const classes = ['cv-input', error ? 'cv-input--invalid' : '', className].filter(Boolean).join(' ');
  return wp.element.createElement(FieldShell, {
    id: id,
    label: label,
    help: help,
    error: error
  }, wp.element.createElement("input", _extends({
    id: id,
    className: classes,
    "aria-invalid": error ? 'true' : undefined
  }, rest)));
}
function TextareaField({
  label,
  help,
  error,
  className = '',
  ...rest
}) {
  const id = useId();
  const classes = ['cv-textarea', error ? 'cv-textarea--invalid' : '', className].filter(Boolean).join(' ');
  return wp.element.createElement(FieldShell, {
    id: id,
    label: label,
    help: help,
    error: error
  }, wp.element.createElement("textarea", _extends({
    id: id,
    className: classes,
    "aria-invalid": error ? 'true' : undefined
  }, rest)));
}
function SelectField({
  label,
  help,
  error,
  options = [],
  className = '',
  children,
  ...rest
}) {
  const id = useId();
  const classes = ['cv-select', className].filter(Boolean).join(' ');
  return wp.element.createElement(FieldShell, {
    id: id,
    label: label,
    help: help,
    error: error
  }, wp.element.createElement("select", _extends({
    id: id,
    className: classes,
    "aria-invalid": error ? 'true' : undefined
  }, rest), options.map(option => wp.element.createElement("option", {
    key: option.value,
    value: option.value,
    disabled: option.disabled
  }, option.label)), children));
}
;// ./vendor/carticy/admin-ui/js/src/components/Modal.jsx
/**
 * Modal — wraps .cv-scrim + .cv-modal (sm/md/lg/xl) with header/body/footer.
 *
 * Escape and scrim-click close by default; pass dismissible={false} for
 * confirm-style modals that must resolve through their actions.
 */

function Modal({
  open,
  onClose,
  title,
  size = 'md',
  footer = null,
  dismissible = true,
  children
}) {
  (0,external_wp_element_namespaceObject.useEffect)(() => {
    if (!open || !dismissible) {
      return undefined;
    }
    const onKey = event => {
      if ('Escape' === event.key && onClose) {
        onClose();
      }
    };
    document.addEventListener('keydown', onKey);
    return () => document.removeEventListener('keydown', onKey);
  }, [open, dismissible, onClose]);
  if (!open) {
    return null;
  }
  return wp.element.createElement("div", {
    className: "cv-scrim",
    onClick: dismissible && onClose ? onClose : undefined
  }, wp.element.createElement("div", {
    className: `cv-modal cv-modal--${size}`,
    role: "dialog",
    "aria-modal": "true",
    "aria-label": 'string' === typeof title ? title : undefined,
    onClick: event => event.stopPropagation()
  }, title && wp.element.createElement("div", {
    className: "cv-modal__header"
  }, wp.element.createElement("h2", {
    className: "cv-modal__title"
  }, title), dismissible && onClose && wp.element.createElement("button", {
    type: "button",
    className: "cv-icon-btn",
    "aria-label": "Close",
    onClick: onClose
  }, wp.element.createElement("svg", {
    viewBox: "0 0 24 24",
    width: "16",
    height: "16",
    "aria-hidden": "true"
  }, wp.element.createElement("path", {
    d: "M6 6l12 12M18 6L6 18",
    stroke: "currentColor",
    strokeWidth: "2",
    fill: "none",
    strokeLinecap: "round"
  })))), wp.element.createElement("div", {
    className: "cv-modal__body"
  }, children), footer && wp.element.createElement("div", {
    className: "cv-modal__footer"
  }, footer)));
}
;// ./vendor/carticy/admin-ui/js/src/onboarding/Stepper.jsx
/* unused harmony import specifier */ var Fragment;
function Stepper_extends() { return Stepper_extends = Object.assign ? Object.assign.bind() : function (n) { for (var e = 1; e < arguments.length; e++) { var t = arguments[e]; for (var r in t) ({}).hasOwnProperty.call(t, r) && (n[r] = t[r]); } return n; }, Stepper_extends.apply(null, arguments); }
/**
 * Stepper — wraps .cv-stepper (numbered steps, accent active, success done).
 *
 * steps: [ { id, label } ]; activeId marks the current step; every step
 * before it renders as done.
 */

function Stepper({
  steps = [],
  activeId,
  className = '',
  ...rest
}) {
  const activeIndex = steps.findIndex(step => step.id === activeId);
  return wp.element.createElement("div", Stepper_extends({
    className: ['cv-stepper', className].filter(Boolean).join(' ')
  }, rest), steps.map((step, index) => {
    const stateClass = index === activeIndex ? 'is-active' : index < activeIndex ? 'is-done' : '';
    return wp.element.createElement(Fragment, {
      key: step.id
    }, index > 0 && wp.element.createElement("span", {
      className: "cv-stepper__connector",
      "aria-hidden": "true"
    }), wp.element.createElement("div", {
      className: ['cv-stepper__step', stateClass].filter(Boolean).join(' ')
    }, wp.element.createElement("span", {
      className: "cv-stepper__num"
    }, index < activeIndex ? '✓' : index + 1), wp.element.createElement("span", {
      className: "cv-stepper__label"
    }, step.label)));
  }));
}
;// external "wp.apiFetch"
var external_wp_apiFetch_namespaceObject = wp.apiFetch;
var external_wp_apiFetch_default = /*#__PURE__*/__webpack_require__.n(external_wp_apiFetch_namespaceObject);
;// ./vendor/carticy/admin-ui/js/src/onboarding/useServerOnboarding.js
/**
 * useServerOnboarding — the server-validated onboarding state machine client.
 *
 * Generalized from the SiteVitals onboarding pattern: the SERVER owns the
 * state string and validates every transition; the client only renders the
 * current state and requests transitions. Reaching a "complete" state must
 * mean the server verified it (e.g. a wire-confirmed test purchase), never
 * that the client clicked through — components must not invent local
 * progress the server would reject.
 *
 * Contract expected from the REST endpoint (path is plugin-specific):
 *   GET  {path}            -> { state: string, ...context }
 *   POST {path}/transition -> body { to: string, ...payload }
 *                             200 { state: string, ...context } on success,
 *                             4xx { message } when the transition is invalid.
 */


function useServerOnboarding(path, {
  autoFetch = true
} = {}) {
  const [data, setData] = (0,external_wp_element_namespaceObject.useState)(null);
  const [loading, setLoading] = (0,external_wp_element_namespaceObject.useState)(Boolean(autoFetch));
  const [submitting, setSubmitting] = (0,external_wp_element_namespaceObject.useState)(false);
  const [error, setError] = (0,external_wp_element_namespaceObject.useState)(null);
  const mounted = (0,external_wp_element_namespaceObject.useRef)(true);
  (0,external_wp_element_namespaceObject.useEffect)(() => {
    mounted.current = true;
    return () => {
      mounted.current = false;
    };
  }, []);
  const refetch = (0,external_wp_element_namespaceObject.useCallback)(async () => {
    setLoading(true);
    setError(null);
    try {
      const response = await external_wp_apiFetch_default()({
        path
      });
      if (mounted.current) {
        setData(response);
      }
      return response;
    } catch (err) {
      if (mounted.current) {
        setError(err);
      }
      throw err;
    } finally {
      if (mounted.current) {
        setLoading(false);
      }
    }
  }, [path]);
  (0,external_wp_element_namespaceObject.useEffect)(() => {
    if (autoFetch) {
      refetch().catch(() => {});
    }
  }, [autoFetch, refetch]);
  const transition = (0,external_wp_element_namespaceObject.useCallback)(async (to, payload = {}) => {
    setSubmitting(true);
    setError(null);
    try {
      const response = await external_wp_apiFetch_default()({
        path: `${path}/transition`,
        method: 'POST',
        data: {
          to,
          ...payload
        }
      });
      if (mounted.current) {
        setData(response);
      }
      return response;
    } catch (err) {
      if (mounted.current) {
        setError(err);
      }
      throw err;
    } finally {
      if (mounted.current) {
        setSubmitting(false);
      }
    }
  }, [path]);
  return {
    state: data ? data.state : null,
    data,
    loading,
    submitting,
    error,
    refetch,
    transition
  };
}
;// ./vendor/carticy/admin-ui/js/src/index.js
/**
 * @carticy/admin-ui — unified Carticy admin design system.
 *
 * Ship-shape: JSX source compiled by the consuming plugin's
 * @wordpress/scripts (webpack/babel) build; CSS in css/ is prebuilt and
 * scoped to the .cv-root mount (see mount.js).
 */















;// external "wp.i18n"
var external_wp_i18n_namespaceObject = wp.i18n;
;// ./assets/js/src/admin/api/endpoints.js
/**
 * Every REST path the admin app touches, in one place.
 *
 * Paths are relative to the plugin namespace; the client prefixes them with
 * the namespace from the boot object so a namespace change is a one-line edit.
 */
const ENDPOINTS = {
  settings: '/settings',
  consent: '/consent',
  consentAudit: orderId => `/consent/audit/${orderId}`,
  noCmpGuidance: '/consent/no-cmp-guidance',
  serverProviders: '/server-providers',
  providerStatus: '/provider-status',
  onboarding: '/onboarding',
  accuracy: days => `/diagnostics/accuracy?days=${days}`,
  recentEvents: '/diagnostics/recent-events',
  verification: '/verification',
  verificationRun: '/verification/run',
  detection: '/detection',
  detectionResolution: '/detection/resolution',
  gtmImport: '/gtm/import-package',
  status: '/status'
};
;// ./assets/js/src/admin/api/client.js
/**
 * REST client: thin apiFetch wrappers that prefix the plugin namespace and
 * normalize WP_Error responses into a consistent {code, message, status, data}
 * shape the screens can render without guessing.
 */


const boot = () => window.carticyConversionsAdmin || {};
const namespacePath = path => `/${boot().restNamespace || 'carticy-conversions/v1'}${path}`;
function normalizeRestError(error) {
  if (error && typeof error === 'object') {
    return {
      code: error.code || 'unknown_error',
      message: error.message || (0,external_wp_i18n_namespaceObject.__)('Something went wrong talking to your site. Please try again.', 'carticy-conversions-for-woocommerce'),
      status: error.data && error.data.status || 0,
      data: error.data || {}
    };
  }
  return {
    code: 'unknown_error',
    message: (0,external_wp_i18n_namespaceObject.__)('Something went wrong talking to your site. Please try again.', 'carticy-conversions-for-woocommerce'),
    status: 0,
    data: {}
  };
}
async function apiGet(path) {
  try {
    return await external_wp_apiFetch_default()({
      path: namespacePath(path)
    });
  } catch (error) {
    throw normalizeRestError(error);
  }
}
async function apiPost(path, data) {
  try {
    return await external_wp_apiFetch_default()({
      path: namespacePath(path),
      method: 'POST',
      data
    });
  } catch (error) {
    throw normalizeRestError(error);
  }
}

;// ./assets/js/src/admin/hooks/useResource.js
/**
 * Shared GET/POST hooks: every screen renders the same
 * loading / error / data triple, so the fetch lifecycle lives here once.
 */


const resourceCache = new Map();
const DEFAULT_CACHE_TTL = 120000;
function readCachedResource(path, cacheTtl) {
  const cached = path ? resourceCache.get(path) : null;
  if (!cached) {
    return null;
  }
  return Date.now() - cached.fetchedAt <= cacheTtl ? cached.data : null;
}
function useResource(path, {
  enabled = true,
  cacheTtl = DEFAULT_CACHE_TTL
} = {}) {
  const cachedData = enabled ? readCachedResource(path, cacheTtl) : null;
  const [data, setDataState] = (0,external_wp_element_namespaceObject.useState)(cachedData);
  const [loading, setLoading] = (0,external_wp_element_namespaceObject.useState)(!!enabled && null === cachedData);
  const [error, setError] = (0,external_wp_element_namespaceObject.useState)(null);
  const mounted = (0,external_wp_element_namespaceObject.useRef)(true);
  const dataRef = (0,external_wp_element_namespaceObject.useRef)(cachedData);
  (0,external_wp_element_namespaceObject.useEffect)(() => {
    mounted.current = true;
    return () => {
      mounted.current = false;
    };
  }, []);
  const setData = (0,external_wp_element_namespaceObject.useCallback)(nextData => {
    dataRef.current = nextData;
    if (path) {
      resourceCache.set(path, {
        data: nextData,
        fetchedAt: Date.now()
      });
    }
    setDataState(nextData);
  }, [path]);
  const refetch = (0,external_wp_element_namespaceObject.useCallback)(async ({
    force = false
  } = {}) => {
    if (!path) {
      return null;
    }
    const cached = readCachedResource(path, cacheTtl);
    if (!force && null !== cached) {
      dataRef.current = cached;
      setDataState(cached);
      setLoading(false);
      setError(null);
      return cached;
    }
    setLoading(null === dataRef.current);
    setError(null);
    try {
      const response = await apiGet(path);
      resourceCache.set(path, {
        data: response,
        fetchedAt: Date.now()
      });
      if (mounted.current) {
        dataRef.current = response;
        setDataState(response);
      }
      return response;
    } catch (err) {
      if (mounted.current) {
        setError(err);
      }
      return null;
    } finally {
      if (mounted.current) {
        setLoading(false);
      }
    }
  }, [cacheTtl, path]);
  (0,external_wp_element_namespaceObject.useEffect)(() => {
    if (enabled) {
      refetch();
    }
  }, [enabled, refetch]);
  return {
    data,
    loading,
    error,
    refetch,
    setData
  };
}
function useMutation(path) {
  const [saving, setSaving] = (0,external_wp_element_namespaceObject.useState)(false);
  const [error, setError] = (0,external_wp_element_namespaceObject.useState)(null);
  const mounted = (0,external_wp_element_namespaceObject.useRef)(true);
  (0,external_wp_element_namespaceObject.useEffect)(() => {
    mounted.current = true;
    return () => {
      mounted.current = false;
    };
  }, []);
  const mutate = (0,external_wp_element_namespaceObject.useCallback)(async (body, {
    path: overridePath
  } = {}) => {
    setSaving(true);
    setError(null);
    try {
      return await apiPost(overridePath || path, body);
    } catch (err) {
      if (mounted.current) {
        setError(err);
      }
      throw err;
    } finally {
      if (mounted.current) {
        setSaving(false);
      }
    }
  }, [path]);
  return {
    mutate,
    saving,
    error,
    setError
  };
}
;// ./assets/js/src/admin/router.js
/**
 * Hash router. Four top-level routes plus settings tabs do not justify a
 * routing dependency; the hash survives reloads and makes notices linkable.
 *
 * Routes are dash-separated (#home-events, #settings-platforms), NOT
 * slash-style ("#/home/events"): wp-admin core runs jQuery over
 * window.location.hash and a slash makes it an invalid selector that throws
 * a console error on every navigation.
 *
 *   #home             - tracking status
 *   #home-accuracy    - payment gateway accuracy
 *   #home-events      - recent events
 *   #settings-:tab    - settings (platforms|delivery|events|consent|privacy|server|advanced)
 */

function parseHash() {
  const raw = window.location.hash.replace(/^#/, '');
  const parts = raw.split('-').filter(Boolean);
  if ('settings' === parts[0]) {
    return {
      page: 'settings',
      tab: parts[1] || 'platforms'
    };
  }
  if ('home' === parts[0] && parts[1]) {
    return {
      page: 'home',
      view: parts[1]
    };
  }
  return {
    page: 'home',
    view: ''
  };
}
function useHashRoute() {
  const [route, setRoute] = (0,external_wp_element_namespaceObject.useState)(parseHash);
  (0,external_wp_element_namespaceObject.useEffect)(() => {
    const onChange = () => setRoute(parseHash());
    window.addEventListener('hashchange', onChange);
    return () => window.removeEventListener('hashchange', onChange);
  }, []);
  const navigate = (0,external_wp_element_namespaceObject.useCallback)(hash => {
    window.location.hash = hash;
  }, []);
  return {
    route,
    navigate
  };
}
;// ./assets/js/src/admin/components/Icons.jsx
function Icons_extends() { return Icons_extends = Object.assign ? Object.assign.bind() : function (n) { for (var e = 1; e < arguments.length; e++) { var t = arguments[e]; for (var r in t) ({}).hasOwnProperty.call(t, r) && (n[r] = t[r]); } return n; }, Icons_extends.apply(null, arguments); }
/**
 * Inline Lucide-style SVG icons used by the plugin-specific admin screens.
 */

const icon = (children, props = {}) => wp.element.createElement("svg", Icons_extends({
  viewBox: "0 0 24 24",
  "aria-hidden": "true",
  focusable: "false"
}, props), children);
const IconCheck = props => icon(wp.element.createElement("polyline", {
  points: "20 6 9 17 4 12"
}), props);
const IconCheckCircle = props => icon(wp.element.createElement(wp.element.Fragment, null, wp.element.createElement("path", {
  d: "M22 11.08V12a10 10 0 1 1-5.93-9.14"
}), wp.element.createElement("polyline", {
  points: "22 4 12 14.01 9 11.01"
})), props);
const IconHelp = props => icon(wp.element.createElement(wp.element.Fragment, null, wp.element.createElement("circle", {
  cx: "12",
  cy: "12",
  r: "10"
}), wp.element.createElement("path", {
  d: "M9.1 9a3 3 0 0 1 5.8 1c0 2-3 3-3 3"
}), wp.element.createElement("line", {
  x1: "12",
  y1: "17",
  x2: "12.01",
  y2: "17"
})), props);
const IconChat = props => icon(wp.element.createElement("path", {
  d: "M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z"
}), props);
const IconInfo = props => icon(wp.element.createElement(wp.element.Fragment, null, wp.element.createElement("circle", {
  cx: "12",
  cy: "12",
  r: "10"
}), wp.element.createElement("line", {
  x1: "12",
  y1: "16",
  x2: "12",
  y2: "12"
}), wp.element.createElement("line", {
  x1: "12",
  y1: "8",
  x2: "12.01",
  y2: "8"
})), props);
const IconAlertCircle = props => icon(wp.element.createElement(wp.element.Fragment, null, wp.element.createElement("circle", {
  cx: "12",
  cy: "12",
  r: "10"
}), wp.element.createElement("line", {
  x1: "12",
  y1: "8",
  x2: "12",
  y2: "12"
}), wp.element.createElement("line", {
  x1: "12",
  y1: "16",
  x2: "12.01",
  y2: "16"
})), props);
const IconAlertTriangle = props => icon(wp.element.createElement(wp.element.Fragment, null, wp.element.createElement("path", {
  d: "M10.29 3.86 1.82 18a2 2 0 0 0 1.71 3h16.94a2 2 0 0 0 1.71-3L13.71 3.86a2 2 0 0 0-3.42 0z"
}), wp.element.createElement("line", {
  x1: "12",
  y1: "9",
  x2: "12",
  y2: "13"
}), wp.element.createElement("line", {
  x1: "12",
  y1: "17",
  x2: "12.01",
  y2: "17"
})), props);
const IconCross = props => icon(wp.element.createElement(wp.element.Fragment, null, wp.element.createElement("circle", {
  cx: "12",
  cy: "12",
  r: "10"
}), wp.element.createElement("line", {
  x1: "15",
  y1: "9",
  x2: "9",
  y2: "15"
}), wp.element.createElement("line", {
  x1: "9",
  y1: "9",
  x2: "15",
  y2: "15"
})), props);
const IconLock = props => icon(wp.element.createElement(wp.element.Fragment, null, wp.element.createElement("rect", {
  x: "3",
  y: "11",
  width: "18",
  height: "11",
  rx: "2",
  ry: "2"
}), wp.element.createElement("path", {
  d: "M7 11V7a5 5 0 0 1 10 0v4"
})), props);
const IconPlay = props => icon(wp.element.createElement("polygon", {
  points: "5 3 19 12 5 21 5 3"
}), props);
const IconRefresh = props => icon(wp.element.createElement(wp.element.Fragment, null, wp.element.createElement("polyline", {
  points: "1 4 1 10 7 10"
}), wp.element.createElement("path", {
  d: "M3.51 15a9 9 0 1 0 2.13-9.36L1 10"
})), props);
const IconChevronDown = props => icon(wp.element.createElement("polyline", {
  points: "6 9 12 15 18 9"
}), props);
const IconCart = props => icon(wp.element.createElement(wp.element.Fragment, null, wp.element.createElement("circle", {
  cx: "9",
  cy: "21",
  r: "1"
}), wp.element.createElement("circle", {
  cx: "20",
  cy: "21",
  r: "1"
}), wp.element.createElement("path", {
  d: "M1 1h4l2.68 13.39a2 2 0 0 0 2 1.61h9.72a2 2 0 0 0 2-1.61L23 6H6"
})), props);
const IconShield = props => icon(wp.element.createElement("path", {
  d: "M12 22s8-4 8-10V5l-8-3-8 3v7c0 6 8 10 8 10z"
}), props);
const IconCode = props => icon(wp.element.createElement(wp.element.Fragment, null, wp.element.createElement("polyline", {
  points: "16 18 22 12 16 6"
}), wp.element.createElement("polyline", {
  points: "8 6 2 12 8 18"
})), props);
;// ./assets/js/src/admin/components/Topbar.jsx
/**
 * App top bar: brand, plan chip, help link. The plan chip renders the
 * server-reported plan only - never a client guess: while the plan is still
 * unknown (boot/onboarding, isPremium = null) no chip renders at all, so a
 * Pro site never flashes "Free plan".
 */


const HELP_URL = 'https://carticy.com/plugins/carticy-conversions-for-woocommerce/';
function Topbar({
  isPremium,
  tabs = []
}) {
  return wp.element.createElement("header", {
    className: "topbar"
  }, wp.element.createElement("div", {
    className: "topbar__left"
  }, wp.element.createElement("div", {
    className: "topbar__brand"
  }, wp.element.createElement("span", {
    className: "brandmark"
  }, wp.element.createElement(IconCheck, null)), wp.element.createElement("span", {
    className: "topbar__name"
  }, (0,external_wp_i18n_namespaceObject.__)('Carticy Conversions', 'carticy-conversions-for-woocommerce'))), tabs.length > 0 && wp.element.createElement("nav", {
    className: "topbar-tabs",
    "aria-label": (0,external_wp_i18n_namespaceObject.__)('Sections', 'carticy-conversions-for-woocommerce')
  }, tabs.map(tab => wp.element.createElement("button", {
    key: tab.id,
    type: "button",
    className: tab.active ? 'topbar-tabs__btn is-active' : 'topbar-tabs__btn',
    onClick: tab.onClick,
    "aria-current": tab.active ? 'page' : undefined
  }, tab.label)))), wp.element.createElement("div", {
    className: "topbar__right"
  }, 'boolean' === typeof isPremium && wp.element.createElement("span", {
    className: isPremium ? 'chip-free chip-pro' : 'chip-free'
  }, isPremium ? (0,external_wp_i18n_namespaceObject.__)('Pro plan', 'carticy-conversions-for-woocommerce') : (0,external_wp_i18n_namespaceObject.__)('Free plan', 'carticy-conversions-for-woocommerce')), wp.element.createElement("a", {
    className: "help-link",
    href: HELP_URL,
    target: "_blank",
    rel: "noreferrer noopener"
  }, wp.element.createElement(IconChat, null), (0,external_wp_i18n_namespaceObject.__)('Help', 'carticy-conversions-for-woocommerce'))));
}
;// ./assets/js/src/admin/onboarding/screens/Welcome.jsx
/**
 * Welcome. A local pre-state of `platforms`: "Get started" reveals
 * the first wizard screen (there is no server state before `platforms`).
 */


function Welcome({
  onStart
}) {
  return wp.element.createElement("div", {
    className: "cv-card cv-card--lg welcome-card welcome"
  }, wp.element.createElement("span", {
    className: "welcome__eyebrow"
  }, (0,external_wp_i18n_namespaceObject.__)('Setup - 2 minutes', 'carticy-conversions-for-woocommerce')), wp.element.createElement("h2", {
    className: "welcome__h"
  }, (0,external_wp_i18n_namespaceObject.__)('Stop losing sales to', 'carticy-conversions-for-woocommerce'), ' ', wp.element.createElement("em", null, (0,external_wp_i18n_namespaceObject.__)('broken', 'carticy-conversions-for-woocommerce')), ' ', (0,external_wp_i18n_namespaceObject.__)('tracking.', 'carticy-conversions-for-woocommerce')), wp.element.createElement("p", {
    className: "welcome__sub"
  }, (0,external_wp_i18n_namespaceObject.__)("Carticy Conversions tracks purchases from your orders - not a fragile thank-you page - so Google and Meta get accurate data even when redirect checkouts, Safari, or consent banners get in the way. No developer needed. And if you've never touched Tag Manager, we handle that part.", 'carticy-conversions-for-woocommerce')), wp.element.createElement("div", {
    className: "welcome__cta"
  }, wp.element.createElement("button", {
    type: "button",
    className: "cv-btn cv-btn--primary cv-btn--lg",
    onClick: onStart
  }, (0,external_wp_i18n_namespaceObject.__)('Get started', 'carticy-conversions-for-woocommerce'))), wp.element.createElement("div", {
    className: "trust"
  }, wp.element.createElement("span", {
    className: "trust__item"
  }, wp.element.createElement(IconCart, null), (0,external_wp_i18n_namespaceObject.__)('Classic & block checkout', 'carticy-conversions-for-woocommerce')), wp.element.createElement("span", {
    className: "trust__item"
  }, wp.element.createElement(IconShield, null), (0,external_wp_i18n_namespaceObject.__)('GDPR consent-aware', 'carticy-conversions-for-woocommerce')), wp.element.createElement("span", {
    className: "trust__item"
  }, wp.element.createElement(IconCode, null), (0,external_wp_i18n_namespaceObject.__)('No code', 'carticy-conversions-for-woocommerce'))));
}
;// ./assets/js/src/admin/api/settingsMapper.js
/**
 * The ONLY place the /settings flat-vs-nested quirk exists.
 *
 * GET /settings returns the normalized NESTED shape (clientTracking.providers.*),
 * but POST /settings stores the FLAT option shape the server normalizer reads
 * (ga4_measurement_id, ga4_mode, ...). Forms work on the flat shape; this module
 * hydrates it from a GET response and the form posts it verbatim.
 */

function flattenClientTracking(settings) {
  const tracking = settings && settings.clientTracking || {};
  const providers = tracking.providers || {};
  const ga4 = providers.ga4 || {};
  const ads = providers.google_ads || {};
  const meta = providers.meta || {};
  const gtm = tracking.gtm || {};
  return {
    ga4_measurement_id: ga4.measurementId || '',
    ga4_mode: ga4.mode || 'off',
    google_ads_conversion_id: ads.conversionId || '',
    google_ads_conversion_label: ads.conversionLabel || '',
    google_ads_mode: ads.mode || 'off',
    meta_pixel_id: meta.pixelId || '',
    meta_mode: meta.mode || 'off',
    gtm_container_id: gtm.containerId || '',
    // GET nests this flag under the same snake_case key as the flat option
    // (ClientTrackingSettings::normalize) - the camelCase variant exists only
    // in the storefront config payload, which the admin app never receives.
    allow_duplicate_client_destinations: !!tracking.allow_duplicate_client_destinations
  };
}

/**
 * Read the normalized (server-validated) provider config back out of a
 * /settings response - the echo is the source of truth after a save, because
 * the normalizer DROPS malformed ids rather than storing them.
 */
function providerEcho(settings) {
  const tracking = settings && settings.clientTracking || {};
  return {
    providers: tracking.providers || {},
    gtm: tracking.gtm || {},
    conflicts: tracking.conflicts || []
  };
}
;// ./assets/js/src/admin/onboarding/screens/Platforms.jsx
/**
 * Step 1 - Platforms. The selection persists as the provider modes
 * (selected to direct, unselected to off) so a reload rehydrates it from
 * GET /settings; the Delivery step may rewrite the mode to gtm.
 */







function Platforms({
  goTo,
  settings,
  step,
  transitionError,
  onBackToWelcome
}) {
  const [selected, setSelected] = (0,external_wp_element_namespaceObject.useState)({
    google: true,
    meta: true
  });
  const [hydrated, setHydrated] = (0,external_wp_element_namespaceObject.useState)(false);
  const save = useMutation(ENDPOINTS.settings);
  (0,external_wp_element_namespaceObject.useEffect)(() => {
    if (hydrated || !settings.data) {
      return;
    }
    const flat = flattenClientTracking(settings.data);
    const anyConfigured = 'off' !== flat.ga4_mode || 'off' !== flat.google_ads_mode || 'off' !== flat.meta_mode;
    if (anyConfigured) {
      setSelected({
        google: 'off' !== flat.ga4_mode || 'off' !== flat.google_ads_mode,
        meta: 'off' !== flat.meta_mode
      });
    }
    setHydrated(true);
  }, [settings.data, hydrated]);
  const toggle = key => setSelected(prev => ({
    ...prev,
    [key]: !prev[key]
  }));
  const onContinue = async () => {
    const flat = flattenClientTracking(settings.data || {});
    const mode = (wanted, currentMode) => {
      if (!wanted) {
        return 'off';
      }
      return 'off' === currentMode ? 'direct' : currentMode;
    };
    try {
      const response = await save.mutate({
        clientTracking: {
          ...flat,
          ga4_mode: mode(selected.google, flat.ga4_mode),
          google_ads_mode: mode(selected.google, flat.google_ads_mode),
          meta_mode: mode(selected.meta, flat.meta_mode)
        }
      });
      settings.setData(response);
      await goTo('delivery');
    } catch (error) {
      // Rendered by WizError below.
    }
  };
  const card = (key, name, desc) => wp.element.createElement("button", {
    type: "button",
    className: selected[key] ? 'sel-card is-selected' : 'sel-card',
    onClick: () => toggle(key),
    "aria-pressed": selected[key]
  }, selected[key] && wp.element.createElement("span", {
    className: "sel-card__check"
  }, wp.element.createElement(IconCheck, null)), wp.element.createElement("span", {
    className: "wordmark"
  }, name), wp.element.createElement("p", {
    className: "sel-card__desc"
  }, desc));
  return wp.element.createElement("div", {
    className: "cv-card cv-card--lg wiz wiz--wide"
  }, wp.element.createElement("div", {
    className: "wiz__head"
  }, wp.element.createElement("h2", {
    className: "wiz__title"
  }, (0,external_wp_i18n_namespaceObject.__)('Where do you run ads?', 'carticy-conversions-for-woocommerce')), wp.element.createElement("p", {
    className: "wiz__sub"
  }, (0,external_wp_i18n_namespaceObject.__)('Pick the platforms you want to track. You can change this later.', 'carticy-conversions-for-woocommerce'))), wp.element.createElement("div", {
    className: "sel-grid"
  }, card('google', 'Google', (0,external_wp_i18n_namespaceObject.__)('GA4 analytics + Google Ads conversions', 'carticy-conversions-for-woocommerce')), card('meta', 'Meta', (0,external_wp_i18n_namespaceObject.__)('Meta Pixel conversions, with Conversions API on Pro', 'carticy-conversions-for-woocommerce'))), wp.element.createElement("p", {
    className: "sel-note"
  }, (0,external_wp_i18n_namespaceObject.__)("Using both? We'll set them up together and keep them in sync.", 'carticy-conversions-for-woocommerce')), wp.element.createElement(WizError, {
    error: save.error || transitionError
  }), wp.element.createElement(WizFoot, {
    step: step,
    onBack: onBackToWelcome,
    onContinue: onContinue,
    busy: save.saving,
    continueDisabled: !selected.google && !selected.meta
  }));
}
;// ./assets/js/src/admin/onboarding/screens/Delivery.jsx
/**
 * Step 2 - Delivery method. Prefetched detection feeds the
 * "we found a Pixel" banner; a foreign GTM container makes the GTM card the
 * natural attach point. With zero foreign tags the `detect` interstitial is
 * skipped by chaining the two server transitions.
 */







function Delivery({
  goTo,
  settings,
  detection,
  step,
  transitionError
}) {
  const flat = flattenClientTracking(settings.data || {});
  const initialChoice = [flat.ga4_mode, flat.google_ads_mode, flat.meta_mode].includes('gtm') || '' !== flat.gtm_container_id ? 'gtm' : 'direct';
  const [choice, setChoice] = (0,external_wp_element_namespaceObject.useState)(initialChoice);
  const save = useMutation(ENDPOINTS.settings);
  const found = detection.data && detection.data.found || [];
  const foreign = found.filter(item => !item.ownedByPlugin);
  const foreignPixel = foreign.find(item => 'meta' === item.type && item.id);
  const foreignGtm = foreign.find(item => 'gtm' === item.type && item.id);
  const onContinue = async () => {
    const toMode = currentMode => {
      if ('off' === currentMode) {
        return 'off';
      }
      return 'gtm' === choice ? 'gtm' : 'direct';
    };
    try {
      const response = await save.mutate({
        clientTracking: {
          ...flat,
          ga4_mode: toMode(flat.ga4_mode),
          google_ads_mode: toMode(flat.google_ads_mode),
          meta_mode: toMode(flat.meta_mode),
          gtm_container_id: 'gtm' === choice ? flat.gtm_container_id || (foreignGtm ? foreignGtm.id : '') : ''
        }
      });
      settings.setData(response);
      await goTo('detect');
      if (0 === foreign.length && !detection.loading) {
        // Nothing to decide - skip the interstitial with a second
        // server-validated transition.
        await goTo('connect');
      }
    } catch (error) {
      // Rendered below.
    }
  };
  return wp.element.createElement("div", {
    className: "cv-card cv-card--lg wiz"
  }, wp.element.createElement("div", {
    className: "wiz__head"
  }, wp.element.createElement("h2", {
    className: "wiz__title"
  }, (0,external_wp_i18n_namespaceObject.__)('How should we install your tags?', 'carticy-conversions-for-woocommerce')), wp.element.createElement("p", {
    className: "wiz__sub"
  }, (0,external_wp_i18n_namespaceObject.__)('Not sure? Direct tags work for most stores.', 'carticy-conversions-for-woocommerce'))), wp.element.createElement("fieldset", {
    className: "conn-stack",
    style: {
      border: 0,
      padding: 0,
      margin: 0,
      minWidth: 0
    }
  }, wp.element.createElement("legend", {
    className: "screen-reader-text",
    style: {
      position: 'absolute',
      width: '1px',
      height: '1px',
      overflow: 'hidden',
      clipPath: 'inset(50%)'
    }
  }, (0,external_wp_i18n_namespaceObject.__)('Delivery method', 'carticy-conversions-for-woocommerce')), wp.element.createElement("label", {
    className: 'direct' === choice ? 'cv-radio-card is-selected' : 'cv-radio-card'
  }, wp.element.createElement("input", {
    type: "radio",
    className: "cv-radio",
    name: "delivery",
    checked: 'direct' === choice,
    onChange: () => setChoice('direct'),
    style: {
      marginTop: '2px'
    }
  }), wp.element.createElement("span", {
    className: "cv-radio-card__main"
  }, wp.element.createElement("span", {
    className: "cv-radio-card__title"
  }, (0,external_wp_i18n_namespaceObject.__)('Direct tags', 'carticy-conversions-for-woocommerce'), ' ', !foreignGtm && wp.element.createElement("span", {
    className: "pill-rec"
  }, (0,external_wp_i18n_namespaceObject.__)('Recommended', 'carticy-conversions-for-woocommerce'))), wp.element.createElement("span", {
    className: "cv-radio-card__desc"
  }, (0,external_wp_i18n_namespaceObject.__)('Carticy Conversions adds and manages the browser tags for you. No Tag Manager needed.', 'carticy-conversions-for-woocommerce')))), wp.element.createElement("label", {
    className: 'gtm' === choice ? 'cv-radio-card is-selected' : 'cv-radio-card'
  }, wp.element.createElement("input", {
    type: "radio",
    className: "cv-radio",
    name: "delivery",
    checked: 'gtm' === choice,
    onChange: () => setChoice('gtm'),
    style: {
      marginTop: '2px'
    }
  }), wp.element.createElement("span", {
    className: "cv-radio-card__main"
  }, wp.element.createElement("span", {
    className: "cv-radio-card__title"
  }, (0,external_wp_i18n_namespaceObject.__)('Google Tag Manager', 'carticy-conversions-for-woocommerce'), ' ', foreignGtm && wp.element.createElement("span", {
    className: "pill-rec"
  }, (0,external_wp_i18n_namespaceObject.__)('Recommended', 'carticy-conversions-for-woocommerce'))), wp.element.createElement("span", {
    className: "cv-radio-card__desc"
  }, (0,external_wp_i18n_namespaceObject.__)("Use this if you already run a GTM container. We'll prepare a ready-made container file for you to download and import.", 'carticy-conversions-for-woocommerce'))))), foreignPixel && wp.element.createElement("div", {
    className: "cv-banner cv-banner--info-blue",
    role: "status",
    style: {
      marginTop: '16px'
    }
  }, wp.element.createElement("span", {
    className: "cv-banner__icon"
  }, wp.element.createElement(IconInfo, null)), wp.element.createElement("div", {
    className: "cv-banner__body"
  }, wp.element.createElement("p", {
    className: "cv-banner__desc"
  }, (0,external_wp_i18n_namespaceObject.sprintf)(/* translators: %s: detected Meta Pixel id. */
  (0,external_wp_i18n_namespaceObject.__)("We found a Meta Pixel already on your site (ID %s). You'll choose what to do with it next - we never add a duplicate without asking.", 'carticy-conversions-for-woocommerce'), foreignPixel.id)))), wp.element.createElement(WizError, {
    error: save.error || transitionError
  }), wp.element.createElement(WizFoot, {
    step: step,
    onBack: () => goTo('platforms'),
    onContinue: onContinue,
    busy: save.saving
  }));
}
;// ./assets/js/src/admin/onboarding/screens/DetectExisting.jsx
/**
 * Existing tracking detected (server state `detect`).
 *
 * Each detected foreign tag gets an attach/replace/keep-both decision. The
 * server's recommendation preselects the safe option; decisions persist via
 * POST /detection/resolution, and "attach" also writes the found id into the
 * settings so the engine genuinely uses the existing tag. With nothing
 * detected the screen auto-forwards (reload safety for the skip path).
 */






const TYPE_LABELS = {
  ga4: {
    title: (0,external_wp_i18n_namespaceObject.__)('Existing GA4 tag', 'carticy-conversions-for-woocommerce'),
    sub: (0,external_wp_i18n_namespaceObject.__)('Added outside Carticy Conversions', 'carticy-conversions-for-woocommerce')
  },
  google_ads: {
    title: (0,external_wp_i18n_namespaceObject.__)('Existing Google Ads tag', 'carticy-conversions-for-woocommerce'),
    sub: (0,external_wp_i18n_namespaceObject.__)('Added outside Carticy Conversions', 'carticy-conversions-for-woocommerce')
  },
  meta: {
    title: (0,external_wp_i18n_namespaceObject.__)('Existing Meta Pixel', 'carticy-conversions-for-woocommerce'),
    sub: (0,external_wp_i18n_namespaceObject.__)('Added outside Carticy Conversions', 'carticy-conversions-for-woocommerce')
  },
  gtm: {
    title: (0,external_wp_i18n_namespaceObject.__)('Google Tag Manager container', 'carticy-conversions-for-woocommerce'),
    sub: (0,external_wp_i18n_namespaceObject.__)('Found on your site', 'carticy-conversions-for-woocommerce')
  }
};
function optionCopy(type) {
  if ('gtm' === type) {
    return {
      attach: (0,external_wp_i18n_namespaceObject.__)('We prepare a container file for you to download and import into it. No second container is added.', 'carticy-conversions-for-woocommerce'),
      replace: (0,external_wp_i18n_namespaceObject.__)('We install tags directly and leave the container alone.', 'carticy-conversions-for-woocommerce'),
      keep_both: (0,external_wp_i18n_namespaceObject.__)('Fire through the container and direct tags. May double-count.', 'carticy-conversions-for-woocommerce')
    };
  }
  return {
    attach: (0,external_wp_i18n_namespaceObject.__)("Use the tag that's already there. No second tag is added.", 'carticy-conversions-for-woocommerce'),
    replace: (0,external_wp_i18n_namespaceObject.__)('We manage tracking ourselves; remove the old tag from its plugin.', 'carticy-conversions-for-woocommerce'),
    keep_both: (0,external_wp_i18n_namespaceObject.__)('Leave the existing tag in place. May double-count.', 'carticy-conversions-for-woocommerce')
  };
}
function DetectExisting({
  goTo,
  settings,
  detection,
  step,
  transitionError
}) {
  const found = detection.data && detection.data.found || [];
  const foreign = found.filter(item => !item.ownedByPlugin && item.id);
  const recommended = detection.data && detection.data.recommendation && detection.data.recommendation.action || 'attach';
  const [choices, setChoices] = (0,external_wp_element_namespaceObject.useState)({});
  const saveResolution = useMutation(ENDPOINTS.detectionResolution);
  const saveSettings = useMutation(ENDPOINTS.settings);

  // Reload safety: landing on `detect` with nothing to decide forwards on.
  (0,external_wp_element_namespaceObject.useEffect)(() => {
    if (!detection.loading && detection.data && 0 === foreign.length) {
      goTo('connect').catch(() => {});
    }
  }, [detection.loading, detection.data, foreign.length, goTo]);
  const choiceFor = item => choices[item.type + '|' + item.id] || ('none' === recommended ? 'attach' : recommended);
  const onContinue = async () => {
    try {
      await saveResolution.mutate({
        resolutions: foreign.map(item => ({
          type: item.type,
          id: item.id,
          action: choiceFor(item)
        }))
      });

      // "Attach" adopts the existing id so the engine fires the SAME tag
      // (events dedup against it by order id / eventID). Google Ads is the
      // exception: the conversion LABEL is not detectable, so attach just
      // leaves the existing Ads tag alone.
      const flat = flattenClientTracking(settings.data || {});
      const patch = {
        ...flat
      };
      let changed = false;
      foreign.forEach(item => {
        if ('attach' !== choiceFor(item)) {
          return;
        }
        if ('ga4' === item.type) {
          patch.ga4_measurement_id = item.id;
          changed = true;
        }
        if ('meta' === item.type) {
          patch.meta_pixel_id = item.id;
          changed = true;
        }
        if ('gtm' === item.type) {
          patch.gtm_container_id = item.id;
          changed = true;
        }
      });
      if (changed) {
        const response = await saveSettings.mutate({
          clientTracking: patch
        });
        settings.setData(response);
      }
      await goTo('connect');
    } catch (error) {
      // Rendered below.
    }
  };
  if (detection.loading) {
    return wp.element.createElement("div", {
      className: "cv-card cv-card--lg wiz"
    }, wp.element.createElement("div", {
      className: "app-loading",
      role: "status"
    }, (0,external_wp_i18n_namespaceObject.__)('Checking your store for existing tracking...', 'carticy-conversions-for-woocommerce')));
  }
  return wp.element.createElement("div", {
    className: "cv-card cv-card--lg wiz wiz--wide"
  }, wp.element.createElement("div", {
    className: "wiz__head"
  }, wp.element.createElement("h2", {
    className: "wiz__title"
  }, (0,external_wp_i18n_namespaceObject.__)('We found tracking already on your store', 'carticy-conversions-for-woocommerce')), wp.element.createElement("p", {
    className: "wiz__sub"
  }, (0,external_wp_i18n_namespaceObject.__)("We've selected the safe option for each, so nothing gets double-counted. Change it only if you need to.", 'carticy-conversions-for-woocommerce'))), wp.element.createElement("div", {
    className: "conn-stack"
  }, foreign.map(item => {
    const labels = TYPE_LABELS[item.type] || {
      title: item.type,
      sub: ''
    };
    const copy = optionCopy(item.type);
    const key = item.type + '|' + item.id;
    // The badge follows the SERVER's recommendation (the same
    // action the radio preselects) - badging "Attach" while
    // preselecting "Replace" would be contradictory guidance.
    const recommendedAction = 'none' === recommended ? 'attach' : recommended;
    return wp.element.createElement("div", {
      className: "conn-card detect-item",
      key: key
    }, wp.element.createElement("div", {
      className: "detect-item__head"
    }, wp.element.createElement("div", null, wp.element.createElement("p", {
      className: "detect-item__title"
    }, labels.title), wp.element.createElement("p", {
      className: "detect-item__sub"
    }, labels.sub)), wp.element.createElement("span", {
      className: "id-chip"
    }, item.id)), wp.element.createElement("fieldset", {
      className: "detect-options",
      style: {
        border: 0,
        padding: 0,
        margin: 0,
        minWidth: 0
      }
    }, wp.element.createElement("legend", {
      className: "screen-reader-text",
      style: {
        position: 'absolute',
        width: '1px',
        height: '1px',
        overflow: 'hidden',
        clipPath: 'inset(50%)'
      }
    }, labels.title), ['attach', 'replace', 'keep_both'].map(action => wp.element.createElement("label", {
      className: choiceFor(item) === action ? 'cv-radio-card is-selected' : 'cv-radio-card',
      key: action
    }, wp.element.createElement("input", {
      type: "radio",
      className: "cv-radio",
      name: key,
      checked: choiceFor(item) === action,
      onChange: () => setChoices(prev => ({
        ...prev,
        [key]: action
      })),
      style: {
        marginTop: '2px'
      }
    }), wp.element.createElement("span", {
      className: "cv-radio-card__main"
    }, wp.element.createElement("span", {
      className: "cv-radio-card__title"
    }, 'attach' === action && (0,external_wp_i18n_namespaceObject.__)('Attach to it', 'carticy-conversions-for-woocommerce'), 'replace' === action && (0,external_wp_i18n_namespaceObject.__)('Replace with Carticy Conversions', 'carticy-conversions-for-woocommerce'), 'keep_both' === action && (0,external_wp_i18n_namespaceObject.__)('Keep both', 'carticy-conversions-for-woocommerce'), ' ', recommendedAction === action && wp.element.createElement("span", {
      className: "pill-rec"
    }, (0,external_wp_i18n_namespaceObject.__)('Recommended', 'carticy-conversions-for-woocommerce'))), wp.element.createElement("span", {
      className: "cv-radio-card__desc"
    }, copy[action]))))));
  })), wp.element.createElement("p", {
    className: "footnote"
  }, (0,external_wp_i18n_namespaceObject.__)('Carticy Conversions never adds a second pixel for a platform that already has one without your say-so.', 'carticy-conversions-for-woocommerce')), wp.element.createElement(WizError, {
    error: saveResolution.error || saveSettings.error || transitionError
  }), wp.element.createElement(WizFoot, {
    step: step,
    onBack: () => goTo('delivery'),
    onContinue: onContinue,
    busy: saveResolution.saving || saveSettings.saving
  }));
}
;// ./assets/js/src/admin/data/guides.js
/**
 * "Where do I find this?" guide content.
 *
 * Each guide walks the merchant through the FULL journey from a recognizable
 * landing page to the exact field - a stable "Open ..." link first, numbered
 * steps verified against the live platform UIs (2026-06), and real,
 * redacted screenshots captured from those UIs (assets/images/guide/).
 *
 * Client-ID guides render in the Connect step; the server-credential guides
 * (GA4 API secret, Meta CAPI token) render only on the Pro Server-side
 * settings surface - each lives in the area where its field lives.
 */

const shot = (file, caption) => ({
  file,
  caption
});
const GUIDES = {
  ga4_measurement_id: {
    title: (0,external_wp_i18n_namespaceObject.__)('Where do you find your GA4 Measurement ID?', 'carticy-conversions-for-woocommerce'),
    openUrl: 'https://analytics.google.com/',
    openLabel: (0,external_wp_i18n_namespaceObject.__)('Open Google Analytics', 'carticy-conversions-for-woocommerce'),
    steps: [(0,external_wp_i18n_namespaceObject.__)('Open Google Analytics and sign in.', 'carticy-conversions-for-woocommerce'), (0,external_wp_i18n_namespaceObject.__)('Click Admin (the gear, bottom of the left sidebar).', 'carticy-conversions-for-woocommerce'), (0,external_wp_i18n_namespaceObject.__)('Under "Data collection and modification", click Data streams.', 'carticy-conversions-for-woocommerce'), (0,external_wp_i18n_namespaceObject.__)('Click your web stream, then copy the Measurement ID at the top right.', 'carticy-conversions-for-woocommerce')],
    shots: [shot('ga4-admin-nav.png', (0,external_wp_i18n_namespaceObject.__)('Admin - Data streams, highlighted.', 'carticy-conversions-for-woocommerce')), shot('ga4-data-streams.png', (0,external_wp_i18n_namespaceObject.__)('The Data streams list - click your web stream.', 'carticy-conversions-for-woocommerce')), shot('ga4-measurement-id.png', (0,external_wp_i18n_namespaceObject.__)('The Measurement ID on your web stream.', 'carticy-conversions-for-woocommerce'))],
    hint: (0,external_wp_i18n_namespaceObject.__)('It looks like G-XXXXXXX.', 'carticy-conversions-for-woocommerce')
  },
  google_ads_conversion: {
    title: (0,external_wp_i18n_namespaceObject.__)('Where do you find your Conversion ID and label?', 'carticy-conversions-for-woocommerce'),
    openUrl: 'https://ads.google.com/',
    openLabel: (0,external_wp_i18n_namespaceObject.__)('Open Google Ads', 'carticy-conversions-for-woocommerce'),
    steps: [(0,external_wp_i18n_namespaceObject.__)('Open Google Ads and sign in to your ads account.', 'carticy-conversions-for-woocommerce'), (0,external_wp_i18n_namespaceObject.__)('In the left rail, click Goals, then Conversions, then Summary.', 'carticy-conversions-for-woocommerce'), (0,external_wp_i18n_namespaceObject.__)("No conversion action yet? Click Create conversion action and add a website Purchase action first.", 'carticy-conversions-for-woocommerce'), (0,external_wp_i18n_namespaceObject.__)('Open your purchase conversion action, then Tag setup.', 'carticy-conversions-for-woocommerce'), (0,external_wp_i18n_namespaceObject.__)('Choose "Use Google Tag Manager" - the Conversion ID (AW-...) and Conversion label are listed there.', 'carticy-conversions-for-woocommerce')],
    shots: [shot('ads-goals-nav.png', (0,external_wp_i18n_namespaceObject.__)('Goals - Conversions - Summary in Google Ads.', 'carticy-conversions-for-woocommerce')), shot('ads-create-action.png', (0,external_wp_i18n_namespaceObject.__)('Creating a Purchase conversion action.', 'carticy-conversions-for-woocommerce'))],
    hint: (0,external_wp_i18n_namespaceObject.__)('They look like AW-XXXXXXXXX and a short label like aBcD1efGhIjkLM.', 'carticy-conversions-for-woocommerce')
  },
  meta_pixel_id: {
    title: (0,external_wp_i18n_namespaceObject.__)('Where do you find your Meta Pixel ID?', 'carticy-conversions-for-woocommerce'),
    openUrl: 'https://www.facebook.com/events_manager2/',
    openLabel: (0,external_wp_i18n_namespaceObject.__)('Open Meta Events Manager', 'carticy-conversions-for-woocommerce'),
    steps: [(0,external_wp_i18n_namespaceObject.__)('Open Meta Events Manager (from facebook.com: Ads Manager, then All tools, then Events Manager).', 'carticy-conversions-for-woocommerce'), (0,external_wp_i18n_namespaceObject.__)('In the left rail, click Datasets.', 'carticy-conversions-for-woocommerce'), (0,external_wp_i18n_namespaceObject.__)('Your pixel is listed with its ID right under the name.', 'carticy-conversions-for-woocommerce'), (0,external_wp_i18n_namespaceObject.__)('Meta now calls it a "Dataset ID" - it is the same number as your Pixel ID.', 'carticy-conversions-for-woocommerce')],
    shots: [shot('meta-datasets-list.png', (0,external_wp_i18n_namespaceObject.__)('The dataset list - the ID sits under each name.', 'carticy-conversions-for-woocommerce')), shot('meta-dataset-id.png', (0,external_wp_i18n_namespaceObject.__)('The Dataset ID panel with its copy button.', 'carticy-conversions-for-woocommerce'))],
    hint: (0,external_wp_i18n_namespaceObject.__)('A 15 to 16 digit number.', 'carticy-conversions-for-woocommerce')
  },
  gtm_container_id: {
    title: (0,external_wp_i18n_namespaceObject.__)('Where do you find your GTM container ID?', 'carticy-conversions-for-woocommerce'),
    openUrl: 'https://tagmanager.google.com/',
    openLabel: (0,external_wp_i18n_namespaceObject.__)('Open Tag Manager', 'carticy-conversions-for-woocommerce'),
    steps: [(0,external_wp_i18n_namespaceObject.__)('Open Google Tag Manager and sign in.', 'carticy-conversions-for-woocommerce'), (0,external_wp_i18n_namespaceObject.__)('Your containers are listed on the home screen - the Container ID column shows the GTM-... ID.', 'carticy-conversions-for-woocommerce')],
    shots: [shot('gtm-container-id.png', (0,external_wp_i18n_namespaceObject.__)('The Container ID column on the Tag Manager home screen.', 'carticy-conversions-for-woocommerce'))],
    hint: (0,external_wp_i18n_namespaceObject.__)('It looks like GTM-XXXXXXX.', 'carticy-conversions-for-woocommerce')
  },
  gtm_import: {
    title: (0,external_wp_i18n_namespaceObject.__)('How do you import the container file?', 'carticy-conversions-for-woocommerce'),
    openUrl: 'https://tagmanager.google.com/',
    openLabel: (0,external_wp_i18n_namespaceObject.__)('Open Tag Manager', 'carticy-conversions-for-woocommerce'),
    steps: [(0,external_wp_i18n_namespaceObject.__)('Download the ready-made container file below.', 'carticy-conversions-for-woocommerce'), (0,external_wp_i18n_namespaceObject.__)('In Tag Manager, open your container, then the Admin tab.', 'carticy-conversions-for-woocommerce'), (0,external_wp_i18n_namespaceObject.__)('Click Import Container, choose the downloaded file, pick your workspace, and select Merge.', 'carticy-conversions-for-woocommerce'), (0,external_wp_i18n_namespaceObject.__)('Review the changes and publish your container.', 'carticy-conversions-for-woocommerce')],
    shots: [shot('gtm-import.png', (0,external_wp_i18n_namespaceObject.__)('Admin - Import Container in your GTM container.', 'carticy-conversions-for-woocommerce'))],
    hint: ''
  },
  ga4_api_secret: {
    title: (0,external_wp_i18n_namespaceObject.__)('Where do you create a GA4 Measurement Protocol API secret?', 'carticy-conversions-for-woocommerce'),
    openUrl: 'https://analytics.google.com/',
    openLabel: (0,external_wp_i18n_namespaceObject.__)('Open Google Analytics', 'carticy-conversions-for-woocommerce'),
    steps: [(0,external_wp_i18n_namespaceObject.__)('Open Google Analytics, click Admin, then Data streams, then your web stream.', 'carticy-conversions-for-woocommerce'), (0,external_wp_i18n_namespaceObject.__)('Scroll down and click "Measurement Protocol API secrets".', 'carticy-conversions-for-woocommerce'), (0,external_wp_i18n_namespaceObject.__)('Click Create, give it a nickname (for example "Carticy server events"), and create it.', 'carticy-conversions-for-woocommerce'), (0,external_wp_i18n_namespaceObject.__)('Copy the Secret value from the table and paste it here.', 'carticy-conversions-for-woocommerce')],
    shots: [shot('ga4-api-secret.png', (0,external_wp_i18n_namespaceObject.__)('The API secrets panel - Create button and Secret value.', 'carticy-conversions-for-woocommerce'))],
    hint: (0,external_wp_i18n_namespaceObject.__)('The secret never touches the browser of your shoppers - it is stored on your server only.', 'carticy-conversions-for-woocommerce')
  },
  meta_capi_token: {
    title: (0,external_wp_i18n_namespaceObject.__)('Where do you generate a Meta Conversions API token?', 'carticy-conversions-for-woocommerce'),
    openUrl: 'https://www.facebook.com/events_manager2/',
    openLabel: (0,external_wp_i18n_namespaceObject.__)('Open Meta Events Manager', 'carticy-conversions-for-woocommerce'),
    steps: [(0,external_wp_i18n_namespaceObject.__)('Open Meta Events Manager, click Datasets, then your pixel.', 'carticy-conversions-for-woocommerce'), (0,external_wp_i18n_namespaceObject.__)('Open the Settings tab and scroll to "Conversions API".', 'carticy-conversions-for-woocommerce'), (0,external_wp_i18n_namespaceObject.__)('Under "Set up direct integration", click Generate access token.', 'carticy-conversions-for-woocommerce'), (0,external_wp_i18n_namespaceObject.__)('Copy the token and paste it here. Meta shows it only once - generate a new one if you lose it.', 'carticy-conversions-for-woocommerce')],
    shots: [shot('meta-capi-token.png', (0,external_wp_i18n_namespaceObject.__)('The Conversions API section with Generate access token.', 'carticy-conversions-for-woocommerce'))],
    hint: (0,external_wp_i18n_namespaceObject.__)('The token never touches the browser of your shoppers - it is stored on your server only.', 'carticy-conversions-for-woocommerce')
  }
};
;// ./assets/js/src/admin/data/copy.js
/**
 * Binding copy, keyed by SERVER state/reason codes - the frontend never
 * invents a verdict, it looks the server's verdict up here.
 *
 * Copy invariants enforced by the admin experience:
 * - GTM is always "download and import a ready-made container file" - never
 *   "we configure/publish your container".
 * - No "GDPR compliant" claims; "GDPR consent-aware" only.
 * - Pro copy never implies free server-side delivery.
 */

function healthCopy(state, reasonCode, lastTracked) {
  switch (state) {
    case 'healthy':
      return {
        title: (0,external_wp_i18n_namespaceObject.__)('Tracking healthy', 'carticy-conversions-for-woocommerce'),
        sub: lastTracked ? (0,external_wp_i18n_namespaceObject.sprintf)(/* translators: %s: humanized time, e.g. "2 minutes". */
        (0,external_wp_i18n_namespaceObject.__)('Last purchase tracked %s ago.', 'carticy-conversions-for-woocommerce'), lastTracked) : (0,external_wp_i18n_namespaceObject.__)('Tracking is configured and live.', 'carticy-conversions-for-woocommerce'),
        tone: 'healthy'
      };
    case 'paused_consent':
      return {
        title: (0,external_wp_i18n_namespaceObject.__)('Tracking paused, waiting for consent', 'carticy-conversions-for-woocommerce'),
        sub: (0,external_wp_i18n_namespaceObject.__)('Orders are recorded, but nothing is sent to Google or Meta until a visitor grants consent.', 'carticy-conversions-for-woocommerce'),
        tone: 'warning'
      };
    case 'needs_attention':
      return {
        title: (0,external_wp_i18n_namespaceObject.__)('Tracking needs attention', 'carticy-conversions-for-woocommerce'),
        sub: 'permanent_send_failures' === reasonCode ? (0,external_wp_i18n_namespaceObject.__)('Some events permanently failed to deliver. Review recent events and re-check your setup.', 'carticy-conversions-for-woocommerce') : (0,external_wp_i18n_namespaceObject.__)('Something needs a closer look. Review recent events and re-check your setup.', 'carticy-conversions-for-woocommerce'),
        tone: 'critical'
      };
    case 'awaiting_first_purchase':
      return {
        title: (0,external_wp_i18n_namespaceObject.__)('Waiting for your first tracked purchase', 'carticy-conversions-for-woocommerce'),
        sub: (0,external_wp_i18n_namespaceObject.__)('Everything is configured. Your next paid order will show up here.', 'carticy-conversions-for-woocommerce'),
        tone: 'neutral'
      };
    case 'not_configured':
      return {
        title: (0,external_wp_i18n_namespaceObject.__)("Tracking isn't configured yet", 'carticy-conversions-for-woocommerce'),
        sub: (0,external_wp_i18n_namespaceObject.__)('Add your tracking IDs under Settings - Platforms to start tracking.', 'carticy-conversions-for-woocommerce'),
        tone: 'neutral'
      };
    case 'disabled':
      return {
        title: (0,external_wp_i18n_namespaceObject.__)('Tracking is turned off', 'carticy-conversions-for-woocommerce'),
        sub: (0,external_wp_i18n_namespaceObject.__)('Nothing is captured or sent while tracking is off.', 'carticy-conversions-for-woocommerce'),
        tone: 'neutral'
      };
    default:
      return {
        title: state,
        sub: '',
        tone: 'neutral'
      };
  }
}
const COPY = {
  gtmImportAction: (0,external_wp_i18n_namespaceObject.__)('Download container file', 'carticy-conversions-for-woocommerce'),
  gtmImportHint: (0,external_wp_i18n_namespaceObject.__)("Download the ready-made container file, then import it in Tag Manager under Admin, then Import Container.", 'carticy-conversions-for-woocommerce'),
  upsellHeadline: (0,external_wp_i18n_namespaceObject.__)('Recover the 20 to 40% of conversions browser tracking misses.', 'carticy-conversions-for-woocommerce'),
  upgradeCta: (0,external_wp_i18n_namespaceObject.__)('Upgrade to Pro', 'carticy-conversions-for-woocommerce'),
  dataFootnote: (0,external_wp_i18n_namespaceObject.__)("Your customers' data never touches us. Events go straight from your store to the platforms.", 'carticy-conversions-for-woocommerce')
};
function relativeTime(utcString) {
  if (!utcString) {
    return '';
  }

  // Stored timestamps are UTC "Y-m-d H:i:s" (or ISO); normalize for Date.
  const iso = utcString.includes('T') ? utcString : utcString.replace(' ', 'T') + 'Z';
  const then = new Date(iso).getTime();
  if (Number.isNaN(then)) {
    return '';
  }
  const seconds = Math.max(0, Math.floor((Date.now() - then) / 1000));
  if (seconds < 60) {
    return (0,external_wp_i18n_namespaceObject.__)('moments', 'carticy-conversions-for-woocommerce');
  }
  const minutes = Math.floor(seconds / 60);
  if (minutes < 60) {
    /* translators: %d: number of minutes. */
    return (0,external_wp_i18n_namespaceObject.sprintf)((0,external_wp_i18n_namespaceObject._n)('%d minute', '%d minutes', minutes, 'carticy-conversions-for-woocommerce'), minutes);
  }
  const hours = Math.floor(minutes / 60);
  if (hours < 24) {
    /* translators: %d: number of hours. */
    return (0,external_wp_i18n_namespaceObject.sprintf)((0,external_wp_i18n_namespaceObject._n)('%d hour', '%d hours', hours, 'carticy-conversions-for-woocommerce'), hours);
  }
  const days = Math.floor(hours / 24);

  /* translators: %d: number of days. */
  return (0,external_wp_i18n_namespaceObject.sprintf)((0,external_wp_i18n_namespaceObject._n)('%d day', '%d days', days, 'carticy-conversions-for-woocommerce'), days);
}
function relativeTimeUntil(utcString) {
  if (!utcString) {
    return '';
  }
  const iso = utcString.includes('T') ? utcString : utcString.replace(' ', 'T') + 'Z';
  const then = new Date(iso).getTime();
  if (Number.isNaN(then)) {
    return '';
  }
  const seconds = Math.max(0, Math.floor((then - Date.now()) / 1000));
  if (seconds < 60) {
    return (0,external_wp_i18n_namespaceObject.__)('moments', 'carticy-conversions-for-woocommerce');
  }
  const minutes = Math.floor(seconds / 60);
  if (minutes < 60) {
    /* translators: %d: number of minutes. */
    return (0,external_wp_i18n_namespaceObject.sprintf)((0,external_wp_i18n_namespaceObject._n)('%d minute', '%d minutes', minutes, 'carticy-conversions-for-woocommerce'), minutes);
  }
  const hours = Math.floor(minutes / 60);

  /* translators: %d: number of hours. */
  return (0,external_wp_i18n_namespaceObject.sprintf)((0,external_wp_i18n_namespaceObject._n)('%d hour', '%d hours', hours, 'carticy-conversions-for-woocommerce'), hours);
}
function relativeTimeShort(utcString) {
  const long = relativeTime(utcString);
  if (!long) {
    return '';
  }

  /* translators: %s: humanized time, e.g. "2 minutes". */
  return (0,external_wp_i18n_namespaceObject.sprintf)((0,external_wp_i18n_namespaceObject.__)('%s ago', 'carticy-conversions-for-woocommerce'), long);
}
;// ./assets/js/src/admin/components/Guide.jsx
/**
 * The "Where do I find this?" surfaces:
 * - <Walkthrough/> - the inline expandable under a Connect field (native
 *   <details>, keyboard-free interaction).
 * - <GuideDrawer/> - the side panel beside the active field; focus moves to
 *   its heading on open, Escape closes and returns focus to the trigger.
 *
 * Content (steps + real redacted screenshots) comes from data/guides.js; the
 * screenshots ship in assets/images/guide/ and load from the plugin URL.
 */




function GuideSteps({
  guide
}) {
  const assetsBase = boot().assetsBase || '';
  const [lightboxShot, setLightboxShot] = (0,external_wp_element_namespaceObject.useState)(null);
  const closeLightbox = () => setLightboxShot(null);
  return wp.element.createElement(wp.element.Fragment, null, wp.element.createElement("ol", {
    className: "guide-steps"
  }, guide.steps.map((step, index) => wp.element.createElement("li", {
    key: index
  }, step))), guide.openUrl && wp.element.createElement("p", {
    className: "guide-hint"
  }, wp.element.createElement("a", {
    href: guide.openUrl,
    target: "_blank",
    rel: "noreferrer noopener"
  }, guide.openLabel)), (guide.shots || []).map(shotItem => wp.element.createElement("div", {
    className: "shot",
    key: shotItem.file,
    style: {
      marginTop: '12px'
    }
  }, wp.element.createElement("button", {
    type: "button",
    className: "shot__button",
    onClick: () => setLightboxShot(shotItem),
    "aria-label": (0,external_wp_i18n_namespaceObject.__)('Open screenshot full size', 'carticy-conversions-for-woocommerce')
  }, wp.element.createElement("img", {
    className: "shot__img",
    src: assetsBase + shotItem.file,
    alt: shotItem.caption,
    loading: "lazy"
  })), wp.element.createElement("p", {
    className: "shot__cap"
  }, shotItem.caption))), lightboxShot && wp.element.createElement("div", {
    className: "shot-lightbox",
    role: "dialog",
    "aria-modal": "true",
    "aria-label": lightboxShot.caption,
    onClick: closeLightbox
  }, wp.element.createElement("button", {
    type: "button",
    className: "shot-lightbox__close",
    onClick: closeLightbox,
    "aria-label": (0,external_wp_i18n_namespaceObject.__)('Close screenshot', 'carticy-conversions-for-woocommerce')
  }, wp.element.createElement(IconCross, null)), wp.element.createElement("img", {
    className: "shot-lightbox__img",
    src: assetsBase + lightboxShot.file,
    alt: lightboxShot.caption
  }), wp.element.createElement("p", {
    className: "shot-lightbox__cap"
  }, lightboxShot.caption)), guide.hint && wp.element.createElement("p", {
    className: "guide-hint"
  }, guide.hint));
}
function Walkthrough({
  guide
}) {
  return wp.element.createElement("details", {
    className: "walkthrough"
  }, wp.element.createElement("summary", {
    className: "walkthrough__trigger"
  }, wp.element.createElement(IconHelp, {
    className: "wt-help"
  }), (0,external_wp_i18n_namespaceObject.__)('Where do I find this?', 'carticy-conversions-for-woocommerce'), wp.element.createElement("span", {
    className: "walkthrough__chev"
  }, wp.element.createElement(IconChevronDown, null))), wp.element.createElement("div", {
    className: "walkthrough__body"
  }, wp.element.createElement("div", null, wp.element.createElement(GuideSteps, {
    guide: guide
  }))));
}
function GuideDrawer({
  guide,
  onClose,
  returnFocusRef
}) {
  const headingRef = (0,external_wp_element_namespaceObject.useRef)(null);
  (0,external_wp_element_namespaceObject.useEffect)(() => {
    if (headingRef.current) {
      headingRef.current.focus();
    }
    const onKey = event => {
      if ('Escape' === event.key) {
        onClose();
        if (returnFocusRef && returnFocusRef.current) {
          returnFocusRef.current.focus();
        }
      }
    };
    document.addEventListener('keydown', onKey);
    return () => document.removeEventListener('keydown', onKey);
  }, [onClose, returnFocusRef]);
  const close = () => {
    onClose();
    if (returnFocusRef && returnFocusRef.current) {
      returnFocusRef.current.focus();
    }
  };
  return wp.element.createElement("aside", {
    className: "guide-drawer",
    role: "complementary",
    "aria-label": guide.title
  }, wp.element.createElement("button", {
    type: "button",
    className: "guide-drawer__close",
    onClick: close,
    "aria-label": (0,external_wp_i18n_namespaceObject.__)('Close guide', 'carticy-conversions-for-woocommerce')
  }, wp.element.createElement(IconCross, null)), wp.element.createElement("p", {
    className: "guide-drawer__title",
    tabIndex: -1,
    ref: headingRef
  }, wp.element.createElement(IconHelp, null), guide.title), wp.element.createElement(GuideSteps, {
    guide: guide
  }), wp.element.createElement("p", {
    className: "guide-secret"
  }, wp.element.createElement(IconLock, null), (0,external_wp_i18n_namespaceObject.__)("Your secret keys never touch the browser. They're stored safely on your server.", 'carticy-conversions-for-woocommerce')));
}
;// ./assets/js/src/admin/onboarding/screens/Connect.jsx
/**
 * Step 3 - Connect.
 *
 * Substate `form`: paste-first fields with the guided drawer.
 * Substate `review`: the "You're connected" echo. The review renders the SERVER's normalized echo - a malformed id
 * is dropped by the normalizer and surfaces as an inline field error instead
 * of a fake Connected state.
 */










function Field({
  id,
  label,
  help,
  value,
  onChange,
  placeholder,
  error,
  onGuide,
  guideActive,
  inputRef
}) {
  return wp.element.createElement("div", {
    className: "mfield"
  }, wp.element.createElement("label", {
    className: "cv-label",
    htmlFor: id
  }, label), wp.element.createElement("input", {
    id: id,
    ref: inputRef,
    className: guideActive ? 'cv-input field-active' : 'cv-input',
    type: "text",
    placeholder: placeholder,
    value: value,
    onChange: event => onChange(event.target.value),
    "aria-invalid": error ? 'true' : undefined,
    "aria-describedby": error ? id + '-error' : undefined
  }), help && wp.element.createElement("p", {
    className: "cv-help"
  }, help), error && wp.element.createElement("p", {
    className: "cv-help",
    id: id + '-error',
    style: {
      color: 'var(--cv-critical)'
    }
  }, error), wp.element.createElement("button", {
    type: "button",
    className: "find-link",
    onClick: onGuide
  }, wp.element.createElement(IconHelp, null), (0,external_wp_i18n_namespaceObject.__)('Where do I find this?', 'carticy-conversions-for-woocommerce')));
}
function Connect({
  goTo,
  settings,
  step,
  transitionError
}) {
  const flat = flattenClientTracking(settings.data || {});
  const [form, setForm] = (0,external_wp_element_namespaceObject.useState)({
    ga4: flat.ga4_measurement_id,
    adsId: flat.google_ads_conversion_id,
    adsLabel: flat.google_ads_conversion_label,
    pixel: flat.meta_pixel_id,
    gtm: flat.gtm_container_id
  });
  const [view, setView] = (0,external_wp_element_namespaceObject.useState)('form');
  const [fieldErrors, setFieldErrors] = (0,external_wp_element_namespaceObject.useState)({});
  const [guide, setGuide] = (0,external_wp_element_namespaceObject.useState)(null);
  const save = useMutation(ENDPOINTS.settings);
  const guideTriggerRef = (0,external_wp_element_namespaceObject.useRef)(null);
  const googleSelected = 'off' !== flat.ga4_mode || 'off' !== flat.google_ads_mode;
  const metaSelected = 'off' !== flat.meta_mode;
  const gtmMode = [flat.ga4_mode, flat.google_ads_mode, flat.meta_mode].includes('gtm');
  const set = key => value => setForm(prev => ({
    ...prev,
    [key]: value
  }));

  // Remember which "Where do I find this?" button opened the drawer so
  // closing it (Esc/Close) returns keyboard focus to that trigger.
  const openGuide = key => event => {
    guideTriggerRef.current = event.currentTarget;
    setGuide(key);
  };
  const onContinueForm = async () => {
    setFieldErrors({});
    try {
      const response = await save.mutate({
        clientTracking: {
          ...flat,
          ga4_measurement_id: form.ga4.trim(),
          google_ads_conversion_id: form.adsId.trim(),
          google_ads_conversion_label: form.adsLabel.trim(),
          meta_pixel_id: form.pixel.trim(),
          gtm_container_id: gtmMode ? form.gtm.trim() : flat.gtm_container_id
        }
      });
      settings.setData(response);

      // The normalizer DROPS malformed ids; a posted value missing from
      // the echo is a validation failure, surfaced inline.
      const echo = providerEcho(response);
      const errors = {};
      if (form.ga4.trim() && !(echo.providers.ga4 || {}).measurementId) {
        errors.ga4 = (0,external_wp_i18n_namespaceObject.__)("That doesn't look like a GA4 Measurement ID (G-XXXXXXX).", 'carticy-conversions-for-woocommerce');
      }
      if (form.adsId.trim() && !(echo.providers.google_ads || {}).conversionId) {
        errors.adsId = (0,external_wp_i18n_namespaceObject.__)("That doesn't look like a Conversion ID (AW-XXXXXXXXX).", 'carticy-conversions-for-woocommerce');
      }
      if (form.adsLabel.trim() && !(echo.providers.google_ads || {}).conversionLabel) {
        errors.adsLabel = (0,external_wp_i18n_namespaceObject.__)("That doesn't look like a conversion label.", 'carticy-conversions-for-woocommerce');
      }
      if (form.pixel.trim() && !(echo.providers.meta || {}).pixelId) {
        errors.pixel = (0,external_wp_i18n_namespaceObject.__)("That doesn't look like a Pixel ID (15 to 16 digits).", 'carticy-conversions-for-woocommerce');
      }
      if (gtmMode && form.gtm.trim() && !(echo.gtm || {}).containerId) {
        errors.gtm = (0,external_wp_i18n_namespaceObject.__)("That doesn't look like a container ID (GTM-XXXXXXX).", 'carticy-conversions-for-woocommerce');
      }
      if (Object.keys(errors).length > 0) {
        setFieldErrors(errors);
        return;
      }
      setView('review');
    } catch (error) {
      // Rendered below.
    }
  };
  if ('review' === view) {
    const echo = providerEcho(settings.data || {});
    const ga4 = echo.providers.ga4 || {};
    const ads = echo.providers.google_ads || {};
    const meta = echo.providers.meta || {};
    const gtm = echo.gtm || {};
    return wp.element.createElement("div", {
      className: "cv-card cv-card--lg wiz wiz--wide"
    }, wp.element.createElement("div", {
      className: "wiz__head"
    }, wp.element.createElement("h2", {
      className: "wiz__title"
    }, (0,external_wp_i18n_namespaceObject.__)("You're connected", 'carticy-conversions-for-woocommerce')), wp.element.createElement("p", {
      className: "wiz__sub"
    }, (0,external_wp_i18n_namespaceObject.__)("Here's what we'll use. You can edit any of it later in Settings.", 'carticy-conversions-for-woocommerce'))), !gtm.enabled && wp.element.createElement("div", {
      className: "cv-banner cv-banner--info-blue",
      role: "status",
      style: {
        marginBottom: '16px'
      }
    }, wp.element.createElement("span", {
      className: "cv-banner__icon"
    }, wp.element.createElement(IconInfo, null)), wp.element.createElement("div", {
      className: "cv-banner__body"
    }, wp.element.createElement("p", {
      className: "cv-banner__desc"
    }, (0,external_wp_i18n_namespaceObject.__)("Direct tags. We'll add the browser tags to your site, with no Tag Manager container.", 'carticy-conversions-for-woocommerce')))), wp.element.createElement("div", {
      className: "conn-stack"
    }, googleSelected && wp.element.createElement("div", {
      className: "conn-row"
    }, wp.element.createElement("div", {
      className: "conn-row__left"
    }, wp.element.createElement("span", {
      className: "wordmark"
    }, "Google")), wp.element.createElement("div", {
      className: "conn-row__right"
    }, (ga4.enabled || ads.enabled) && wp.element.createElement("span", {
      className: "cv-status cv-status--connected"
    }, (0,external_wp_i18n_namespaceObject.__)('Connected', 'carticy-conversions-for-woocommerce')), ga4.measurementId && wp.element.createElement("span", {
      className: "id-chip"
    }, "GA4 ", ga4.measurementId), ads.conversionId && wp.element.createElement("span", {
      className: "id-chip"
    }, "Ads ", ads.conversionId), ads.conversionLabel && wp.element.createElement("span", {
      className: "id-chip"
    }, (0,external_wp_i18n_namespaceObject.__)('Label', 'carticy-conversions-for-woocommerce'), " ", ads.conversionLabel))), metaSelected && wp.element.createElement("div", {
      className: "conn-row"
    }, wp.element.createElement("div", {
      className: "conn-row__left"
    }, wp.element.createElement("span", {
      className: "wordmark"
    }, "Meta")), wp.element.createElement("div", {
      className: "conn-row__right"
    }, meta.enabled && wp.element.createElement("span", {
      className: "cv-status cv-status--connected"
    }, (0,external_wp_i18n_namespaceObject.__)('Connected', 'carticy-conversions-for-woocommerce')), meta.pixelId && wp.element.createElement("span", {
      className: "id-chip"
    }, "Pixel ", meta.pixelId))), gtm.enabled && wp.element.createElement("div", {
      className: "conn-row"
    }, wp.element.createElement("div", {
      className: "conn-row__left"
    }, wp.element.createElement("div", null, wp.element.createElement("p", {
      className: "conn-row__title"
    }, (0,external_wp_i18n_namespaceObject.__)('Tag Manager container', 'carticy-conversions-for-woocommerce')), wp.element.createElement("p", {
      className: "conn-row__sub"
    }, (0,external_wp_i18n_namespaceObject.__)("We'll prepare a ready-to-import container file for it.", 'carticy-conversions-for-woocommerce')))), wp.element.createElement("div", {
      className: "conn-row__right"
    }, wp.element.createElement("span", {
      className: "id-chip"
    }, gtm.containerId)))), wp.element.createElement("p", {
      className: "footnote"
    }, COPY.dataFootnote), wp.element.createElement(WizError, {
      error: transitionError
    }), wp.element.createElement(WizFoot, {
      step: step,
      onBack: () => setView('form'),
      onContinue: () => goTo('consent').catch(() => {})
    }));
  }
  const fields = wp.element.createElement("div", {
    className: "mfields"
  }, googleSelected && wp.element.createElement(wp.element.Fragment, null, wp.element.createElement(Field, {
    id: "cc-ga4",
    label: (0,external_wp_i18n_namespaceObject.__)('GA4 Measurement ID', 'carticy-conversions-for-woocommerce'),
    placeholder: "G-XXXXXXXXXX",
    help: (0,external_wp_i18n_namespaceObject.__)('In Google Analytics: Admin, then Data streams. The ID begins with G-.', 'carticy-conversions-for-woocommerce'),
    value: form.ga4,
    onChange: set('ga4'),
    error: fieldErrors.ga4,
    onGuide: openGuide('ga4_measurement_id'),
    guideActive: 'ga4_measurement_id' === guide
  }), wp.element.createElement(Field, {
    id: "cc-ads-id",
    label: (0,external_wp_i18n_namespaceObject.__)('Google Ads Conversion ID', 'carticy-conversions-for-woocommerce'),
    placeholder: "AW-XXXXXXXXX",
    value: form.adsId,
    onChange: set('adsId'),
    error: fieldErrors.adsId,
    onGuide: openGuide('google_ads_conversion'),
    guideActive: 'google_ads_conversion' === guide
  }), wp.element.createElement(Field, {
    id: "cc-ads-label",
    label: (0,external_wp_i18n_namespaceObject.__)('Google Ads conversion label', 'carticy-conversions-for-woocommerce'),
    placeholder: "aBcD1efGhIjkLM",
    value: form.adsLabel,
    onChange: set('adsLabel'),
    error: fieldErrors.adsLabel,
    onGuide: openGuide('google_ads_conversion'),
    guideActive: false
  })), metaSelected && wp.element.createElement(Field, {
    id: "cc-pixel",
    label: (0,external_wp_i18n_namespaceObject.__)('Meta Pixel ID', 'carticy-conversions-for-woocommerce'),
    placeholder: (0,external_wp_i18n_namespaceObject.__)('15 to 16 digit ID', 'carticy-conversions-for-woocommerce'),
    help: (0,external_wp_i18n_namespaceObject.__)("In Events Manager, it's shown under your dataset name.", 'carticy-conversions-for-woocommerce'),
    value: form.pixel,
    onChange: set('pixel'),
    error: fieldErrors.pixel,
    onGuide: openGuide('meta_pixel_id'),
    guideActive: 'meta_pixel_id' === guide
  }), gtmMode && wp.element.createElement(Field, {
    id: "cc-gtm",
    label: (0,external_wp_i18n_namespaceObject.__)('GTM container ID', 'carticy-conversions-for-woocommerce'),
    placeholder: "GTM-XXXXXXX",
    value: form.gtm,
    onChange: set('gtm'),
    error: fieldErrors.gtm,
    onGuide: openGuide('gtm_container_id'),
    guideActive: 'gtm_container_id' === guide
  }));
  return wp.element.createElement("div", {
    className: guide ? 'cv-card cv-card--lg wiz wiz--drawer' : 'cv-card cv-card--lg wiz wiz--wide'
  }, wp.element.createElement("div", {
    className: "wiz__head"
  }, wp.element.createElement("h2", {
    className: "wiz__title"
  }, (0,external_wp_i18n_namespaceObject.__)('Add your tracking IDs', 'carticy-conversions-for-woocommerce')), wp.element.createElement("p", {
    className: "wiz__sub"
  }, (0,external_wp_i18n_namespaceObject.__)('Paste them in. Each tricky field has step-by-step help right here, with no developer needed.', 'carticy-conversions-for-woocommerce'))), guide ? wp.element.createElement("div", {
    className: "connect-drawer-grid"
  }, fields, wp.element.createElement(GuideDrawer, {
    guide: GUIDES[guide],
    onClose: () => setGuide(null),
    returnFocusRef: guideTriggerRef
  })) : fields, wp.element.createElement("div", {
    className: "locked-row"
  }, wp.element.createElement("span", {
    className: "locked-row__icon"
  }, wp.element.createElement(IconLock, null)), wp.element.createElement("div", {
    className: "locked-row__body"
  }, wp.element.createElement("p", {
    className: "locked-row__title"
  }, (0,external_wp_i18n_namespaceObject.__)('Server-side delivery', 'carticy-conversions-for-woocommerce'), " ", wp.element.createElement("span", {
    className: "cv-required-tag"
  }, "Pro")), wp.element.createElement("p", {
    className: "locked-row__sub"
  }, (0,external_wp_i18n_namespaceObject.__)('CAPI, Measurement Protocol, and Enhanced Conversions. Unlocks with Pro.', 'carticy-conversions-for-woocommerce'))), wp.element.createElement("a", {
    className: "cv-btn cv-btn--primary cv-btn--sm locked-row__action",
    href: "https://carticy.com/plugins/carticy-conversions-for-woocommerce/",
    target: "_blank",
    rel: "noreferrer noopener"
  }, COPY.upgradeCta)), wp.element.createElement(WizError, {
    error: save.error || transitionError
  }), wp.element.createElement(WizFoot, {
    step: step,
    onBack: () => goTo('detect').catch(() => {}),
    onContinue: onContinueForm,
    busy: save.saving
  }));
}
;// ./assets/js/src/admin/components/LoadError.jsx
/**
 * Shared failed-GET state: a screen whose backing resource failed must say so
 * and offer a retry - rendering defaults instead would assert facts ("Not
 * configured", "No consent platform detected") off the back of an error.
 */

function LoadError({
  error,
  onRetry
}) {
  return wp.element.createElement("div", {
    className: "cv-banner cv-banner--critical",
    role: "alert"
  }, wp.element.createElement("div", {
    className: "cv-banner__body"
  }, wp.element.createElement("p", {
    className: "cv-banner__desc"
  }, error && error.message || (0,external_wp_i18n_namespaceObject.__)('Something went wrong talking to your site. Please try again.', 'carticy-conversions-for-woocommerce')), onRetry && wp.element.createElement("button", {
    type: "button",
    className: "cv-btn cv-btn--secondary cv-btn--sm",
    onClick: onRetry,
    style: {
      marginTop: '12px'
    }
  }, (0,external_wp_i18n_namespaceObject.__)('Retry', 'carticy-conversions-for-woocommerce'))));
}
;// ./assets/js/src/admin/onboarding/screens/ConsentStep.jsx
/**
 * Step 4 - Consent.
 *
 * Branches on the server's `detected` consent platforms (GET /consent):
 * detected to the calm cmp_driven path; none to the posture decision. Continue
 * never silently weakens the gate: the default branch posts `required`
 * (fail-closed), and `not_required` only via the explicit confirm button -
 * the server records the attestation (who + when).
 */






function ConsentStep({
  goTo,
  step,
  transitionError
}) {
  const consent = useResource(ENDPOINTS.consent);
  const guidance = useResource(ENDPOINTS.noCmpGuidance, {
    enabled: false
  });
  const save = useMutation(ENDPOINTS.consent);
  const [cmpToggle, setCmpToggle] = (0,external_wp_element_namespaceObject.useState)(true);
  const [showGuidance, setShowGuidance] = (0,external_wp_element_namespaceObject.useState)(false);
  if (consent.loading && !consent.data) {
    return wp.element.createElement("div", {
      className: "cv-card cv-card--lg wiz"
    }, wp.element.createElement("div", {
      className: "app-loading",
      role: "status"
    }, (0,external_wp_i18n_namespaceObject.__)('Checking for a consent platform...', 'carticy-conversions-for-woocommerce')));
  }

  // A failed detection request must NOT render the posture decision as if
  // detection ran and found nothing - a merchant could record a
  // `not_required` attestation off the back of an error.
  if (consent.error && !consent.data) {
    return wp.element.createElement("div", {
      className: "cv-card cv-card--lg wiz"
    }, wp.element.createElement(LoadError, {
      error: consent.error,
      onRetry: consent.refetch
    }));
  }
  const detected = consent.data && consent.data.detected || [];
  const postTo = async posture => {
    try {
      await save.mutate({
        posture
      });
      await goTo('verify');
    } catch (error) {
      // Rendered below.
    }
  };
  if (detected.length > 0) {
    const source = detected[0];
    return wp.element.createElement("div", {
      className: "cv-card cv-card--lg wiz"
    }, wp.element.createElement("div", {
      className: "wiz__head",
      style: {
        display: 'flex',
        alignItems: 'center',
        justifyContent: 'space-between',
        gap: '16px'
      }
    }, wp.element.createElement("h2", {
      className: "wiz__title"
    }, (0,external_wp_i18n_namespaceObject.__)('Respect visitor consent', 'carticy-conversions-for-woocommerce')), wp.element.createElement("span", {
      className: "cv-status cv-status--connected"
    }, (0,external_wp_i18n_namespaceObject.sprintf)(/* translators: %s: consent platform name. */
    (0,external_wp_i18n_namespaceObject.__)('%s detected', 'carticy-conversions-for-woocommerce'), source.label))), wp.element.createElement("div", {
      className: "source-row"
    }, wp.element.createElement("span", {
      className: "dot dot--green"
    }), (0,external_wp_i18n_namespaceObject.sprintf)(/* translators: 1: consent platform name, 2: connection channel. */
    (0,external_wp_i18n_namespaceObject.__)('Consent source: %1$s, connected via %2$s', 'carticy-conversions-for-woocommerce'), source.label, 'wp-consent-api' === source.channel ? 'WP Consent API' : source.channel)), wp.element.createElement("div", {
      className: "toggle-row"
    }, wp.element.createElement("div", null, wp.element.createElement("p", {
      className: "toggle-row__title"
    }, (0,external_wp_i18n_namespaceObject.__)('Follow my consent platform', 'carticy-conversions-for-woocommerce')), wp.element.createElement("p", {
      className: "toggle-row__sub"
    }, (0,external_wp_i18n_namespaceObject.__)("Adjust tracking automatically based on your visitor's choice.", 'carticy-conversions-for-woocommerce'))), wp.element.createElement("label", {
      className: "cv-toggle cv-toggle--lg"
    }, wp.element.createElement("input", {
      type: "checkbox",
      className: "cv-toggle__input",
      checked: cmpToggle,
      onChange: event => setCmpToggle(event.target.checked),
      "aria-label": (0,external_wp_i18n_namespaceObject.__)('Follow my consent platform', 'carticy-conversions-for-woocommerce')
    }), wp.element.createElement("span", {
      className: "cv-toggle__track",
      "aria-hidden": "true"
    }, wp.element.createElement("span", {
      className: "cv-toggle__thumb"
    })))), wp.element.createElement("p", {
      className: "consent-quiet"
    }, (0,external_wp_i18n_namespaceObject.__)('Meta, Google Ads, and GA4 each wait for their own consent, gated independently.', 'carticy-conversions-for-woocommerce')), wp.element.createElement("p", {
      className: "footnote"
    }, (0,external_wp_i18n_namespaceObject.__)('No personal data is sent without consent.', 'carticy-conversions-for-woocommerce')), wp.element.createElement(WizError, {
      error: save.error || transitionError
    }), wp.element.createElement(WizFoot, {
      step: step,
      onBack: () => goTo('connect').catch(() => {}),
      onContinue: () => postTo(cmpToggle ? 'cmp_driven' : 'required'),
      busy: save.saving
    }));
  }
  return wp.element.createElement("div", {
    className: "cv-card cv-card--lg wiz wiz--wide"
  }, wp.element.createElement("div", {
    className: "wiz__head"
  }, wp.element.createElement("h2", {
    className: "wiz__title"
  }, (0,external_wp_i18n_namespaceObject.__)('Does your store need cookie consent?', 'carticy-conversions-for-woocommerce')), wp.element.createElement("p", {
    className: "wiz__sub"
  }, (0,external_wp_i18n_namespaceObject.__)("We didn't detect a consent platform. Choose how Carticy Conversions should handle consent. You can change this anytime.", 'carticy-conversions-for-woocommerce'))), wp.element.createElement("div", {
    className: "choice-grid"
  }, wp.element.createElement("div", {
    className: "cv-card choice-card"
  }, wp.element.createElement("p", {
    className: "choice-card__head"
  }, (0,external_wp_i18n_namespaceObject.__)('Yes, I sell to the EU, UK, or California', 'carticy-conversions-for-woocommerce'), ' ', wp.element.createElement("span", {
    className: "pill-rec"
  }, (0,external_wp_i18n_namespaceObject.__)('Recommended', 'carticy-conversions-for-woocommerce'))), wp.element.createElement("p", {
    className: "choice-card__body"
  }, (0,external_wp_i18n_namespaceObject.__)("Carticy Conversions stays paused until your consent banner grants permission. We'll help you connect one.", 'carticy-conversions-for-woocommerce')), wp.element.createElement("button", {
    type: "button",
    className: "cv-btn cv-btn--primary",
    onClick: () => {
      setShowGuidance(true);
      guidance.refetch();
    }
  }, (0,external_wp_i18n_namespaceObject.__)('Connect a consent platform', 'carticy-conversions-for-woocommerce'))), wp.element.createElement("div", {
    className: "cv-card choice-card"
  }, wp.element.createElement("p", {
    className: "choice-card__head"
  }, (0,external_wp_i18n_namespaceObject.__)("No, consent isn't required for my store", 'carticy-conversions-for-woocommerce')), wp.element.createElement("p", {
    className: "choice-card__body"
  }, (0,external_wp_i18n_namespaceObject.__)('You confirm your store operates outside cookie-consent law. Carticy Conversions will track every order.', 'carticy-conversions-for-woocommerce')), wp.element.createElement("button", {
    type: "button",
    className: "cv-btn cv-btn--secondary",
    onClick: () => postTo('not_required'),
    disabled: save.saving
  }, (0,external_wp_i18n_namespaceObject.__)('I confirm, start tracking', 'carticy-conversions-for-woocommerce')))), showGuidance && guidance.data && wp.element.createElement("div", {
    className: "cv-card",
    style: {
      marginTop: '16px'
    }
  }, wp.element.createElement("p", {
    className: "toggle-row__sub",
    style: {
      margin: '0 0 12px'
    }
  }, guidance.data.message), wp.element.createElement("div", {
    className: "conn-stack"
  }, (guidance.data.platforms || []).map(platform => wp.element.createElement("div", {
    className: "conn-row",
    key: platform.slug
  }, wp.element.createElement("div", {
    className: "conn-row__left"
  }, wp.element.createElement("p", {
    className: "conn-row__title"
  }, platform.name)), wp.element.createElement("div", {
    className: "conn-row__right"
  }, wp.element.createElement("a", {
    className: "cv-btn cv-btn--secondary cv-btn--sm",
    href: platform.install_url
  }, (0,external_wp_i18n_namespaceObject.__)('Install', 'carticy-conversions-for-woocommerce'))))))), wp.element.createElement("p", {
    className: "footnote"
  }, (0,external_wp_i18n_namespaceObject.__)('Carticy Conversions never decides this for you. Your choice is recorded with the date and your account.', 'carticy-conversions-for-woocommerce')), wp.element.createElement(WizError, {
    error: save.error || transitionError
  }), wp.element.createElement(WizFoot, {
    step: step,
    onBack: () => goTo('connect').catch(() => {}),
    onContinue: () => postTo('required'),
    busy: save.saving
  }));
}
;// ./assets/js/src/admin/onboarding/screens/Verify.jsx
/**
 * Step 5 - Verify. Every checkmark is real evidence from
 * GET /verification (a recorded purchase with its actual value, an accepted
 * server send); "Check again" kicks the queue and polls. Finish requests the
 * `complete` transition - a 409 renders the server's blockers, never a local
 * green check.
 */







const POLL_INTERVAL_MS = 5000;
const POLL_MAX = 24;
const BLOCKER_COPY = {
  no_destination_configured: (0,external_wp_i18n_namespaceObject.__)('No tracking destination is configured yet. Go back to Connect and add your IDs.', 'carticy-conversions-for-woocommerce'),
  no_recorded_purchase: (0,external_wp_i18n_namespaceObject.__)('No purchase has been recorded yet. Place a test order in your store, then check again.', 'carticy-conversions-for-woocommerce'),
  no_accepted_server_send: (0,external_wp_i18n_namespaceObject.__)("No server send has been accepted yet. After a test order, check again - queued sends retry automatically.", 'carticy-conversions-for-woocommerce')
};
function Row({
  ok,
  children
}) {
  return wp.element.createElement("div", {
    className: ok ? 'verify-row' : 'verify-row is-pending'
  }, wp.element.createElement(IconCheckCircle, null), children);
}
function Verify({
  goTo,
  step,
  transitionError
}) {
  const verification = useResource(ENDPOINTS.verification);
  const run = useMutation(ENDPOINTS.verificationRun);
  const [polling, setPolling] = (0,external_wp_element_namespaceObject.useState)(false);
  const pollCount = (0,external_wp_element_namespaceObject.useRef)(0);
  const pollTimer = (0,external_wp_element_namespaceObject.useRef)(null);
  const shopUrl = boot().shopUrl || '';

  // Cancel the poll chain on unmount - leaving the step must stop the
  // background GET /verification requests, not just their setState.
  (0,external_wp_element_namespaceObject.useEffect)(() => {
    return () => {
      if (pollTimer.current) {
        clearTimeout(pollTimer.current);
        pollTimer.current = null;
      }
    };
  }, []);
  const data = verification.data || {};
  const client = data.client || {};
  const server = data.server || {};
  const evidence = data.evidence || {};
  const purchase = evidence.purchase || null;
  const serverSends = evidence.serverSends || [];
  const blockers = data.blockers || [];
  const checkAgain = async () => {
    setPolling(true);
    pollCount.current = 0;
    try {
      await run.mutate({});
    } catch (error) {
      // The poll below still refreshes the real state.
    }
    const poll = async () => {
      const fresh = await verification.refetch();
      pollCount.current += 1;
      if (fresh && fresh.canComplete) {
        setPolling(false);
        return;
      }
      if (pollCount.current >= POLL_MAX) {
        setPolling(false);
        return;
      }
      pollTimer.current = setTimeout(poll, POLL_INTERVAL_MS);
    };
    pollTimer.current = setTimeout(poll, POLL_INTERVAL_MS);
  };
  if (verification.loading && !verification.data) {
    return wp.element.createElement("div", {
      className: "cv-card cv-card--lg wiz"
    }, wp.element.createElement("div", {
      className: "app-loading",
      role: "status"
    }, (0,external_wp_i18n_namespaceObject.__)('Checking your tracking evidence...', 'carticy-conversions-for-woocommerce')));
  }
  return wp.element.createElement("div", {
    className: "cv-card cv-card--lg wiz"
  }, wp.element.createElement("div", {
    className: "wiz__head"
  }, wp.element.createElement("h2", {
    className: "wiz__title"
  }, (0,external_wp_i18n_namespaceObject.__)("Let's make sure it actually works", 'carticy-conversions-for-woocommerce'))), wp.element.createElement("div", {
    className: "verify-list"
  }, wp.element.createElement(Row, {
    ok: !!client.configured
  }, client.configured ? (0,external_wp_i18n_namespaceObject.__)('Tags installed', 'carticy-conversions-for-woocommerce') : (0,external_wp_i18n_namespaceObject.__)('Tags not configured yet', 'carticy-conversions-for-woocommerce')), wp.element.createElement(Row, {
    ok: !!purchase
  }, purchase ? wp.element.createElement("span", null, (0,external_wp_i18n_namespaceObject.sprintf)(/* translators: %d: order number. */
  (0,external_wp_i18n_namespaceObject.__)('Purchase recorded on order #%d:', 'carticy-conversions-for-woocommerce'), purchase.orderId), ' ', wp.element.createElement("span", {
    className: "mono"
  }, purchase.value, " ", purchase.currency)) : (0,external_wp_i18n_namespaceObject.__)('No purchase recorded yet', 'carticy-conversions-for-woocommerce')), server.available && (serverSends.length > 0 ? serverSends.map((send, index) => wp.element.createElement(Row, {
    ok: true,
    key: index
  }, wp.element.createElement("span", null, (0,external_wp_i18n_namespaceObject.sprintf)(/* translators: 1: destination name, 2: event type. */
  (0,external_wp_i18n_namespaceObject.__)('%1$s - %2$s accepted by the platform.', 'carticy-conversions-for-woocommerce'), send.destination, send.eventType)))) : wp.element.createElement(Row, {
    ok: false
  }, (0,external_wp_i18n_namespaceObject.__)('No server send accepted yet', 'carticy-conversions-for-woocommerce')))), data.canComplete ? wp.element.createElement("div", {
    className: "success-panel"
  }, wp.element.createElement(IconCheckCircle, null), (0,external_wp_i18n_namespaceObject.__)('Tracking is live and accurate.', 'carticy-conversions-for-woocommerce')) : wp.element.createElement("div", {
    className: "cv-banner cv-banner--info-blue",
    role: "status",
    style: {
      marginTop: '20px'
    }
  }, wp.element.createElement("div", {
    className: "cv-banner__body"
  }, blockers.map(blocker => wp.element.createElement("p", {
    className: "cv-banner__desc",
    key: blocker.reason
  }, BLOCKER_COPY[blocker.reason] || blocker.reason)), shopUrl && wp.element.createElement("a", {
    className: "cv-btn cv-btn--secondary cv-btn--sm",
    href: shopUrl,
    target: "_blank",
    rel: "noreferrer noopener",
    style: {
      marginTop: '12px'
    }
  }, (0,external_wp_i18n_namespaceObject.__)('Open your store', 'carticy-conversions-for-woocommerce')))), wp.element.createElement(WizError, {
    error: transitionError
  }), wp.element.createElement("div", {
    style: {
      display: 'flex',
      justifyContent: 'space-between',
      alignItems: 'center',
      marginTop: '22px',
      gap: '10px'
    }
  }, wp.element.createElement("button", {
    type: "button",
    className: "cv-btn cv-btn--secondary",
    onClick: () => goTo('consent').catch(() => {})
  }, (0,external_wp_i18n_namespaceObject.__)('Back', 'carticy-conversions-for-woocommerce')), wp.element.createElement("div", {
    style: {
      display: 'flex',
      gap: '10px'
    }
  }, wp.element.createElement("button", {
    type: "button",
    className: "cv-btn cv-btn--secondary",
    onClick: checkAgain,
    disabled: polling,
    "aria-busy": polling ? 'true' : undefined
  }, polling ? (0,external_wp_i18n_namespaceObject.__)('Checking...', 'carticy-conversions-for-woocommerce') : (0,external_wp_i18n_namespaceObject.__)('Check again', 'carticy-conversions-for-woocommerce')), wp.element.createElement("button", {
    type: "button",
    className: "cv-btn cv-btn--primary",
    onClick: () => goTo('complete').catch(() => {}),
    disabled: !data.canComplete
  }, (0,external_wp_i18n_namespaceObject.__)('Finish', 'carticy-conversions-for-woocommerce')))));
}
;// ./assets/js/src/admin/onboarding/OnboardingApp.jsx
function OnboardingApp_extends() { return OnboardingApp_extends = Object.assign ? Object.assign.bind() : function (n) { for (var e = 1; e < arguments.length; e++) { var t = arguments[e]; for (var r in t) ({}).hasOwnProperty.call(t, r) && (n[r] = t[r]); } return n; }, OnboardingApp_extends.apply(null, arguments); }
/**
 * The onboarding wizard shell.
 *
 * The SERVER owns the position: screens render `data.current` from the
 * onboarding contract and request transitions; an invalid transition (400)
 * resyncs by refetching - the server always wins. The visible "Step X of 5"
 * counts USER-facing steps; the `detect` interstitial belongs to step 3.
 */













const STEP_NUMBERS = {
  platforms: 1,
  delivery: 2,
  detect: 3,
  connect: 3,
  consent: 4,
  verify: 5
};
function WizFoot({
  step,
  onBack,
  onContinue,
  continueLabel,
  busy,
  backDisabled,
  continueDisabled
}) {
  return wp.element.createElement("div", {
    className: "wiz__foot"
  }, wp.element.createElement("span", {
    className: "wiz__step"
  }, (0,external_wp_i18n_namespaceObject.sprintf)(/* translators: %d: current step number. */
  (0,external_wp_i18n_namespaceObject.__)('Step %d of 5', 'carticy-conversions-for-woocommerce'), step)), wp.element.createElement("div", {
    className: "wiz__btns"
  }, onBack && wp.element.createElement("button", {
    type: "button",
    className: "cv-btn cv-btn--secondary",
    onClick: onBack,
    disabled: busy || backDisabled
  }, (0,external_wp_i18n_namespaceObject.__)('Back', 'carticy-conversions-for-woocommerce')), onContinue && wp.element.createElement("button", {
    type: "button",
    className: "cv-btn cv-btn--primary",
    onClick: onContinue,
    disabled: busy || continueDisabled,
    "aria-busy": busy ? 'true' : undefined
  }, continueLabel || (0,external_wp_i18n_namespaceObject.__)('Continue', 'carticy-conversions-for-woocommerce'))));
}
function WizError({
  error
}) {
  if (!error) {
    return null;
  }
  return wp.element.createElement("div", {
    className: "cv-banner cv-banner--critical",
    role: "alert",
    style: {
      marginTop: '16px'
    }
  }, wp.element.createElement("div", {
    className: "cv-banner__body"
  }, wp.element.createElement("p", {
    className: "cv-banner__desc"
  }, error.message)));
}
function OnboardingApp({
  onComplete
}) {
  const path = `/${boot().restNamespace || 'carticy-conversions/v1'}${ENDPOINTS.onboarding}`;
  const onboarding = useServerOnboarding(path);
  const [started, setStarted] = (0,external_wp_element_namespaceObject.useState)(false);
  const [transitionError, setTransitionError] = (0,external_wp_element_namespaceObject.useState)(null);

  // Settings are shared across steps (platform selection, connect form,
  // review) so a reload mid-wizard rehydrates every screen from the API.
  const settings = useResource(ENDPOINTS.settings);
  const detection = useResource(ENDPOINTS.detection);
  const current = onboarding.data ? onboarding.data.current || onboarding.data.state : null;
  const goTo = (0,external_wp_element_namespaceObject.useMemo)(() => async target => {
    setTransitionError(null);
    try {
      const response = await onboarding.transition(target);
      if ('complete' === (response.current || response.state)) {
        onComplete();
      }
      return response;
    } catch (error) {
      if (error && 'carticy_invalid_transition' === error.code) {
        // The client drifted from the server position - resync.
        onboarding.refetch().catch(() => {});
      }
      setTransitionError(error);
      throw error;
    }
  }, [onboarding, onComplete]);

  // The error branch must come FIRST: the vendor hook resolves a failed GET
  // to { loading: false, data: null }, so checking the spinner branch first
  // would trap a failed load on a generic loading state forever with no retry.
  if (onboarding.error && !onboarding.data) {
    return wp.element.createElement("div", {
      className: "canvas canvas--center"
    }, wp.element.createElement("div", {
      className: "cv-card cv-card--lg wiz"
    }, wp.element.createElement(WizError, {
      error: onboarding.error
    }), wp.element.createElement("div", {
      style: {
        marginTop: '16px'
      }
    }, wp.element.createElement("button", {
      type: "button",
      className: "cv-btn cv-btn--secondary",
      onClick: () => onboarding.refetch().catch(() => {})
    }, (0,external_wp_i18n_namespaceObject.__)('Retry', 'carticy-conversions-for-woocommerce')))));
  }
  if (onboarding.loading || !current) {
    return wp.element.createElement("div", {
      className: "canvas canvas--app"
    }, wp.element.createElement("div", {
      className: "app-loading app-loading--screen",
      role: "status"
    }, (0,external_wp_i18n_namespaceObject.__)('Loading', 'carticy-conversions-for-woocommerce')));
  }
  const shared = {
    onboarding,
    goTo,
    settings,
    detection,
    step: STEP_NUMBERS[current] || 1,
    transitionError
  };
  let screen = null;
  if ('platforms' === current && !started && 0 === (onboarding.data.completed || []).length) {
    screen = wp.element.createElement(Welcome, {
      onStart: () => setStarted(true)
    });
  } else if ('platforms' === current) {
    screen = wp.element.createElement(Platforms, OnboardingApp_extends({}, shared, {
      onBackToWelcome: () => setStarted(false)
    }));
  } else if ('delivery' === current) {
    screen = wp.element.createElement(Delivery, shared);
  } else if ('detect' === current) {
    screen = wp.element.createElement(DetectExisting, shared);
  } else if ('connect' === current) {
    screen = wp.element.createElement(Connect, shared);
  } else if ('consent' === current) {
    screen = wp.element.createElement(ConsentStep, shared);
  } else if ('verify' === current) {
    screen = wp.element.createElement(Verify, shared);
  }
  return wp.element.createElement("div", {
    className: "canvas canvas--center"
  }, wp.element.createElement("div", {
    "aria-live": "polite",
    className: "screen-reader-text",
    style: {
      position: 'absolute',
      width: '1px',
      height: '1px',
      overflow: 'hidden',
      clipPath: 'inset(50%)'
    }
  }, (0,external_wp_i18n_namespaceObject.sprintf)(/* translators: %d: current step number. */
  (0,external_wp_i18n_namespaceObject.__)('Step %d of 5', 'carticy-conversions-for-woocommerce'), STEP_NUMBERS[current] || 1)), screen);
}
;// ./assets/js/src/admin/components/NoticeArea.jsx
/**
 * Page-level notices rendered from /status.notices - the server decides WHAT
 * to announce; this component only maps notice types to compact banner
 * banner shapes (duplicate-pixel warning, needs-attention critical,
 * consent-paused info). Acknowledging a duplicate persists via
 * POST /detection/resolution so it stays resolved.
 */





const PROVIDER_LABELS = {
  ga4: 'GA4',
  google_ads: 'Google Ads',
  meta: 'Meta Pixel'
};
function DuplicateNotice({
  notice,
  onResolved
}) {
  const {
    mutate,
    saving
  } = useMutation(ENDPOINTS.detectionResolution);
  const [done, setDone] = (0,external_wp_element_namespaceObject.useState)(false);
  const provider = PROVIDER_LABELS[notice.context.provider] || notice.context.provider;
  const acknowledge = async () => {
    try {
      await mutate({
        resolutions: [{
          type: notice.context.provider,
          id: notice.context.foreignId,
          action: 'keep_both'
        }]
      });
      setDone(true);
      onResolved();
    } catch (error) {
      // The banner stays; the next click retries.
    }
  };
  if (done) {
    return null;
  }
  return wp.element.createElement("div", {
    className: "cv-banner cv-banner--warning",
    role: "status"
  }, wp.element.createElement("span", {
    className: "cv-banner__icon"
  }, wp.element.createElement(IconAlertTriangle, null)), wp.element.createElement("div", {
    className: "cv-banner__body"
  }, wp.element.createElement("p", {
    className: "cv-banner__desc"
  }, (0,external_wp_i18n_namespaceObject.sprintf)(/* translators: %s: ad platform name. */
  (0,external_wp_i18n_namespaceObject.__)('Duplicate %s detected. Another plugin is firing the same pixel. Fix this to avoid double-counting.', 'carticy-conversions-for-woocommerce'), provider)), wp.element.createElement("div", {
    style: {
      display: 'flex',
      gap: '8px'
    }
  }, wp.element.createElement("a", {
    className: "cv-btn cv-btn--secondary cv-btn--sm",
    href: "#settings-platforms",
    style: {
      marginTop: '12px'
    }
  }, (0,external_wp_i18n_namespaceObject.__)('Review', 'carticy-conversions-for-woocommerce')), wp.element.createElement("button", {
    type: "button",
    className: "cv-btn cv-btn--secondary cv-btn--sm",
    onClick: acknowledge,
    disabled: saving
  }, (0,external_wp_i18n_namespaceObject.__)('Keep both anyway', 'carticy-conversions-for-woocommerce')))));
}
function NoticeArea({
  notices,
  onRefresh
}) {
  if (!notices || 0 === notices.length) {
    return null;
  }
  return wp.element.createElement("div", {
    className: "notice-area"
  }, notices.map(notice => {
    if ('duplicate_pixel' === notice.type) {
      return wp.element.createElement(DuplicateNotice, {
        key: notice.id,
        notice: notice,
        onResolved: onRefresh
      });
    }
    if ('needs_attention' === notice.type) {
      return wp.element.createElement("div", {
        className: "cv-banner cv-banner--critical",
        key: notice.id,
        role: "alert"
      }, wp.element.createElement("span", {
        className: "cv-banner__icon"
      }, wp.element.createElement(IconCross, null)), wp.element.createElement("div", {
        className: "cv-banner__body"
      }, wp.element.createElement("p", {
        className: "cv-banner__desc"
      }, (0,external_wp_i18n_namespaceObject.__)("Some tracking events permanently failed to deliver. Purchases may be missing on your ad platforms. Re-check your setup.", 'carticy-conversions-for-woocommerce')), wp.element.createElement("button", {
        type: "button",
        className: "cv-btn cv-btn--secondary cv-btn--sm",
        onClick: onRefresh
      }, wp.element.createElement(IconRefresh, null), (0,external_wp_i18n_namespaceObject.__)('Re-check', 'carticy-conversions-for-woocommerce'))));
    }
    if ('consent_paused' === notice.type) {
      return wp.element.createElement("div", {
        className: "cv-banner cv-banner--info-blue",
        key: notice.id,
        role: "status"
      }, wp.element.createElement("span", {
        className: "cv-banner__icon"
      }, wp.element.createElement(IconInfo, null)), wp.element.createElement("div", {
        className: "cv-banner__body"
      }, wp.element.createElement("p", {
        className: "cv-banner__desc"
      }, (0,external_wp_i18n_namespaceObject.__)('Tracking paused, waiting for visitor consent.', 'carticy-conversions-for-woocommerce'))));
    }
    return null;
  }));
}
;// ./assets/js/src/admin/screens/TestPurchaseModal.jsx
/**
 * "Run a test purchase" - the honest version. The plugin cannot fabricate an
 * order, so the modal gives the real procedure (place a test order in the
 * store) and re-checks the live verification evidence, reusing the Verify
 * evidence semantics. POST /verification/run nudges queued server sends.
 */







function TestPurchaseModal({
  onClose
}) {
  const verification = useResource(ENDPOINTS.verification);
  const run = useMutation(ENDPOINTS.verificationRun);
  const [checking, setChecking] = (0,external_wp_element_namespaceObject.useState)(false);
  const shopUrl = boot().shopUrl || '';
  const data = verification.data || {};
  const purchase = (data.evidence || {}).purchase || null;
  const checkAgain = async () => {
    setChecking(true);
    try {
      await run.mutate({});
    } catch (error) {
      // The refetch below still reports the real state.
    }
    await verification.refetch();
    setChecking(false);
  };
  return wp.element.createElement(Modal, {
    open: true,
    onClose: onClose,
    title: (0,external_wp_i18n_namespaceObject.__)('Run a test purchase', 'carticy-conversions-for-woocommerce'),
    footer: wp.element.createElement(wp.element.Fragment, null, wp.element.createElement("button", {
      type: "button",
      className: "cv-btn cv-btn--secondary",
      onClick: onClose
    }, (0,external_wp_i18n_namespaceObject.__)('Close', 'carticy-conversions-for-woocommerce')), wp.element.createElement("button", {
      type: "button",
      className: "cv-btn cv-btn--primary",
      onClick: checkAgain,
      disabled: checking,
      "aria-busy": checking ? 'true' : undefined
    }, checking ? (0,external_wp_i18n_namespaceObject.__)('Checking...', 'carticy-conversions-for-woocommerce') : (0,external_wp_i18n_namespaceObject.__)('Check again', 'carticy-conversions-for-woocommerce')))
  }, wp.element.createElement("ol", {
    className: "guide-steps"
  }, wp.element.createElement("li", null, (0,external_wp_i18n_namespaceObject.__)('Place a small order in your own store (any cheap product, any gateway).', 'carticy-conversions-for-woocommerce')), wp.element.createElement("li", null, (0,external_wp_i18n_namespaceObject.__)('Mark it paid (most gateways do this automatically).', 'carticy-conversions-for-woocommerce')), wp.element.createElement("li", null, (0,external_wp_i18n_namespaceObject.__)('Come back here and click "Check again" - the purchase shows up below once it is recorded.', 'carticy-conversions-for-woocommerce'))), shopUrl && wp.element.createElement("p", {
    style: {
      marginTop: '12px'
    }
  }, wp.element.createElement("a", {
    className: "cv-btn cv-btn--secondary cv-btn--sm",
    href: shopUrl,
    target: "_blank",
    rel: "noreferrer noopener"
  }, (0,external_wp_i18n_namespaceObject.__)('Open your store', 'carticy-conversions-for-woocommerce'))), wp.element.createElement("div", {
    style: {
      marginTop: '16px'
    }
  }, purchase ? wp.element.createElement("div", {
    className: "success-panel",
    style: {
      marginTop: 0
    }
  }, wp.element.createElement(IconCheckCircle, null), (0,external_wp_i18n_namespaceObject.sprintf)(/* translators: 1: order number, 2: order value, 3: currency code. */
  (0,external_wp_i18n_namespaceObject.__)('Purchase recorded: order #%1$d, %2$s %3$s.', 'carticy-conversions-for-woocommerce'), purchase.orderId, purchase.value, purchase.currency)) : wp.element.createElement("p", {
    className: "health-sub",
    style: {
      margin: 0
    }
  }, verification.loading ? (0,external_wp_i18n_namespaceObject.__)('Checking...', 'carticy-conversions-for-woocommerce') : (0,external_wp_i18n_namespaceObject.__)('No purchase recorded yet.', 'carticy-conversions-for-woocommerce'))));
}
;// ./assets/js/src/admin/screens/Home.jsx
/**
 * Tracking status. Renders /status verbatim: the health
 * state, the four tiles, the accuracy trust-builder, the Pro upsell (free
 * plan only - with the server-provided upgrade URL), and the actions row.
 * Needs-attention state hides the accuracy card so the failure recovery stays focused.
 */






function HealthHead({
  health
}) {
  const copy = healthCopy(health.state, health.reasonCode, health.lastTrackedPurchase ? relativeTime(health.lastTrackedPurchase.occurredAt) : '');
  return wp.element.createElement("div", {
    className: "health-head"
  }, wp.element.createElement("span", {
    className: 'critical' === copy.tone ? 'health-check health-check--critical' : 'healthy' === copy.tone ? 'health-check' : 'health-check health-check--warning'
  }, 'critical' === copy.tone ? wp.element.createElement(IconAlertCircle, null) : wp.element.createElement(IconCheckCircle, null)), wp.element.createElement("div", null, wp.element.createElement("h2", {
    className: "health-title"
  }, copy.title), wp.element.createElement("p", {
    className: "health-sub"
  }, copy.sub)));
}
function Tile({
  label,
  status,
  text,
  locked,
  icon,
  action,
  help
}) {
  const dotClass = {
    connected: 'dot dot--green',
    attention: 'dot dot--critical',
    not_configured: 'dot dot--neutral',
    neutral: 'dot dot--neutral'
  }[status] || 'dot dot--neutral';
  return wp.element.createElement("div", {
    className: locked ? 'tile tile--locked' : 'attention' === status ? 'tile tile--alert' : 'tile'
  }, wp.element.createElement("div", {
    className: "tile__head"
  }, wp.element.createElement("span", {
    className: "tile__label"
  }, icon, label, help && wp.element.createElement("span", {
    className: "tile-help",
    tabIndex: "0",
    title: help,
    "aria-label": help
  }, wp.element.createElement(IconInfo, null))), action && wp.element.createElement("span", {
    className: "tile__actions"
  }, action)), wp.element.createElement("span", {
    className: "tile__val"
  }, !locked && wp.element.createElement("span", {
    className: dotClass
  }), text));
}
function Home({
  status,
  refreshStatus,
  navigate
}) {
  const [testOpen, setTestOpen] = (0,external_wp_element_namespaceObject.useState)(false);
  const health = status.health || {};
  const tiles = status.tiles || {};
  const accuracy = status.accuracy || {};
  const plan = status.plan || {};
  const google = tiles.google || {};
  const meta = tiles.meta || {};
  const delivery = tiles.delivery || {};
  const serverSide = tiles.serverSide || {};
  const tileText = (tile, connectedText) => {
    if ('attention' === tile.status) {
      return (0,external_wp_i18n_namespaceObject.__)('Delivery failing', 'carticy-conversions-for-woocommerce');
    }
    return 'connected' === tile.status ? connectedText : (0,external_wp_i18n_namespaceObject.__)('Not configured', 'carticy-conversions-for-woocommerce');
  };
  const googleParts = (google.parts || []).map(part => 'ga4' === part ? 'GA4' : 'Ads').join(' + ');
  const deliveryText = delivery.pausedForConsent ? (0,external_wp_i18n_namespaceObject.__)('Waiting for consent banner', 'carticy-conversions-for-woocommerce') : 'gtm' === delivery.mode ? (0,external_wp_i18n_namespaceObject.__)('Google Tag Manager', 'carticy-conversions-for-woocommerce') : 'direct' === delivery.mode ? (0,external_wp_i18n_namespaceObject.__)('Direct tags', 'carticy-conversions-for-woocommerce') : (0,external_wp_i18n_namespaceObject.__)('Off', 'carticy-conversions-for-woocommerce');
  const recheckAction = () => wp.element.createElement("button", {
    type: "button",
    className: "cv-icon-btn tile__action",
    onClick: refreshStatus,
    title: (0,external_wp_i18n_namespaceObject.__)('Re-check', 'carticy-conversions-for-woocommerce'),
    "aria-label": (0,external_wp_i18n_namespaceObject.__)('Re-check', 'carticy-conversions-for-woocommerce')
  }, wp.element.createElement(IconRefresh, null));
  const accuracySub = 'all_matched' === accuracy.summary ? (0,external_wp_i18n_namespaceObject.__)('Browser events firing correctly across all payment gateways. No purchases missed.', 'carticy-conversions-for-woocommerce') : 'gaps' === accuracy.summary ? (0,external_wp_i18n_namespaceObject.sprintf)(/* translators: 1: number of missed orders, 2: number of days. */
  (0,external_wp_i18n_namespaceObject.__)('%1$d purchases were not tracked in the last %2$d days. Check payment gateways.', 'carticy-conversions-for-woocommerce'), accuracy.gapOrders, accuracy.windowDays) : (0,external_wp_i18n_namespaceObject.sprintf)(/* translators: %d: number of days. */
  (0,external_wp_i18n_namespaceObject.__)('No paid orders in the last %d days yet.', 'carticy-conversions-for-woocommerce'), accuracy.windowDays);
  return wp.element.createElement("div", {
    className: "app"
  }, wp.element.createElement(NoticeArea, {
    notices: (status.notices || []).filter(notice => !('needs_attention' === health.state && 'needs_attention' === notice.type)),
    onRefresh: refreshStatus
  }), wp.element.createElement(HealthHead, {
    health: health
  }), wp.element.createElement("div", {
    className: "tiles"
  }, wp.element.createElement(Tile, {
    label: "Google",
    status: google.status,
    text: tileText(google, (0,external_wp_i18n_namespaceObject.sprintf)(/* translators: %s: connected Google products, e.g. "GA4 + Ads". */
    (0,external_wp_i18n_namespaceObject.__)('Connected - %s', 'carticy-conversions-for-woocommerce'), googleParts || 'GA4')),
    action: 'attention' === google.status && recheckAction()
  }), wp.element.createElement(Tile, {
    label: "Meta",
    status: meta.status,
    text: tileText(meta, (0,external_wp_i18n_namespaceObject.__)('Connected - Pixel', 'carticy-conversions-for-woocommerce')),
    action: 'attention' === meta.status && recheckAction()
  }), wp.element.createElement(Tile, {
    label: (0,external_wp_i18n_namespaceObject.__)('Browser tracking', 'carticy-conversions-for-woocommerce'),
    status: "neutral",
    text: deliveryText,
    help: (0,external_wp_i18n_namespaceObject.__)('Shows how browser events are sent: direct tags managed by Carticy Conversions, or a Google Tag Manager container you import.', 'carticy-conversions-for-woocommerce')
  }), serverSide.available ? wp.element.createElement(Tile, {
    label: (0,external_wp_i18n_namespaceObject.__)('Server-side', 'carticy-conversions-for-woocommerce'),
    status: "connected",
    text: (0,external_wp_i18n_namespaceObject.__)('Active', 'carticy-conversions-for-woocommerce')
  }) : wp.element.createElement(Tile, {
    label: (0,external_wp_i18n_namespaceObject.__)('Server-side recovery', 'carticy-conversions-for-woocommerce'),
    locked: true,
    icon: wp.element.createElement(IconLock, null),
    text: (0,external_wp_i18n_namespaceObject.__)('Upgrade to recover lost conversions', 'carticy-conversions-for-woocommerce')
  })), 'needs_attention' !== health.state && wp.element.createElement("div", {
    className: "acc-tile"
  }, wp.element.createElement("span", {
    className: "acc-tile__icon"
  }, wp.element.createElement(IconCheckCircle, null)), wp.element.createElement("div", null, wp.element.createElement("p", {
    className: "acc-tile__title"
  }, (0,external_wp_i18n_namespaceObject.__)('Tracking accuracy', 'carticy-conversions-for-woocommerce')), wp.element.createElement("p", {
    className: "acc-tile__sub"
  }, accuracySub)), wp.element.createElement("button", {
    type: "button",
    className: "app-link",
    onClick: () => navigate('#home-accuracy')
  }, (0,external_wp_i18n_namespaceObject.__)('Check payment gateways', 'carticy-conversions-for-woocommerce'))), !plan.isPremium && wp.element.createElement("div", {
    className: "highlight-card"
  }, wp.element.createElement("p", {
    className: "highlight-card__text"
  }, COPY.upsellHeadline), wp.element.createElement("a", {
    className: "cv-btn cv-btn--primary",
    href: plan.upgradeUrl,
    target: "_blank",
    rel: "noreferrer noopener"
  }, COPY.upgradeCta)), wp.element.createElement("div", {
    className: "app-actions"
  }, wp.element.createElement("button", {
    type: "button",
    className: "cv-btn cv-btn--secondary",
    onClick: () => setTestOpen(true)
  }, wp.element.createElement(IconPlay, null), (0,external_wp_i18n_namespaceObject.__)('Run a test purchase', 'carticy-conversions-for-woocommerce')), wp.element.createElement("button", {
    type: "button",
    className: "app-link",
    onClick: () => navigate('#home-events')
  }, (0,external_wp_i18n_namespaceObject.__)('View recent events', 'carticy-conversions-for-woocommerce'))), testOpen && wp.element.createElement(TestPurchaseModal, {
    onClose: () => setTestOpen(false)
  }), health.lastTrackedPurchase && wp.element.createElement("p", {
    className: "footnote"
  }, (0,external_wp_i18n_namespaceObject.sprintf)(/* translators: 1: order number, 2: humanized time ago. */
  (0,external_wp_i18n_namespaceObject.__)('Latest tracked purchase: order #%1$d, %2$s.', 'carticy-conversions-for-woocommerce'), health.lastTrackedPurchase.orderId, relativeTimeShort(health.lastTrackedPurchase.occurredAt))));
}
;// ./assets/js/src/admin/screens/Accuracy.jsx
/**
 * Payment gateway accuracy. A straight render of
 * GET /diagnostics/accuracy: per-gateway paid vs tracked with the missed
 * order numbers the server names (gapOrderIds).
 */



const WINDOW_DAYS = 30;
function Accuracy({
  navigate
}) {
  const report = useResource(ENDPOINTS.accuracy(WINDOW_DAYS));
  const data = report.data || {};
  const rows = data.byGateway || [];
  const totals = data.totals || {};
  return wp.element.createElement("div", {
    className: "app"
  }, wp.element.createElement("div", {
    className: "health-head",
    style: {
      marginBottom: '24px'
    }
  }, wp.element.createElement("div", null, wp.element.createElement("h2", {
    className: "health-title"
  }, (0,external_wp_i18n_namespaceObject.__)('Payment gateway accuracy', 'carticy-conversions-for-woocommerce')), wp.element.createElement("p", {
    className: "health-sub"
  }, (0,external_wp_i18n_namespaceObject.__)('We compared your paid orders to tracked purchases, gateway by gateway.', 'carticy-conversions-for-woocommerce')))), report.error && wp.element.createElement("div", {
    className: "cv-banner cv-banner--critical",
    role: "alert"
  }, wp.element.createElement("div", {
    className: "cv-banner__body"
  }, wp.element.createElement("p", {
    className: "cv-banner__desc"
  }, report.error.message))), wp.element.createElement("div", {
    className: "cv-card"
  }, report.loading ? wp.element.createElement("div", {
    className: "app-loading",
    role: "status"
  }, (0,external_wp_i18n_namespaceObject.__)('Comparing orders...', 'carticy-conversions-for-woocommerce')) : 0 === rows.length ? wp.element.createElement("p", {
    className: "health-sub",
    style: {
      margin: 0
    }
  }, (0,external_wp_i18n_namespaceObject.sprintf)(/* translators: %d: number of days. */
  (0,external_wp_i18n_namespaceObject.__)('No paid orders in the last %d days yet. This report fills in as orders come in.', 'carticy-conversions-for-woocommerce'), WINDOW_DAYS)) : wp.element.createElement("div", {
    className: "table-wrap"
  }, wp.element.createElement("table", {
    className: "consent-table"
  }, wp.element.createElement("thead", null, wp.element.createElement("tr", null, wp.element.createElement("th", {
    scope: "col"
  }, (0,external_wp_i18n_namespaceObject.__)('Gateway', 'carticy-conversions-for-woocommerce')), wp.element.createElement("th", {
    scope: "col"
  }, (0,external_wp_i18n_namespaceObject.__)('Paid orders', 'carticy-conversions-for-woocommerce')), wp.element.createElement("th", {
    scope: "col"
  }, (0,external_wp_i18n_namespaceObject.__)('Tracked', 'carticy-conversions-for-woocommerce')), wp.element.createElement("th", {
    scope: "col"
  }, (0,external_wp_i18n_namespaceObject.__)('Status', 'carticy-conversions-for-woocommerce')))), wp.element.createElement("tbody", null, rows.map(row => wp.element.createElement("tr", {
    key: row.gateway
  }, wp.element.createElement("td", null, row.title), wp.element.createElement("td", {
    className: "cv-numeric"
  }, row.paidOrders), wp.element.createElement("td", {
    className: "cv-numeric"
  }, row.trackedOrders), wp.element.createElement("td", null, row.gapOrders > 0 ? wp.element.createElement("span", {
    className: "decision decision--missed"
  }, wp.element.createElement("span", {
    className: "dot dot--warning"
  }), (0,external_wp_i18n_namespaceObject.sprintf)(/* translators: %d: number of missed orders. */
  (0,external_wp_i18n_namespaceObject.__)('%d missed, order', 'carticy-conversions-for-woocommerce'), row.gapOrders), ' ', (row.gapOrderLinks && row.gapOrderLinks.length > 0 ? row.gapOrderLinks : (row.gapOrderIds || []).map(id => ({
    id,
    url: ''
  }))).map((order, index) => wp.element.createElement("span", {
    key: order.id
  }, index > 0 && ', ', order.url ? wp.element.createElement("a", {
    className: "app-link",
    href: order.url
  }, "#", order.id) : wp.element.createElement(wp.element.Fragment, null, "#", order.id)))) : wp.element.createElement("span", {
    className: "decision decision--matched"
  }, wp.element.createElement("span", {
    className: "dot dot--green"
  }), (0,external_wp_i18n_namespaceObject.__)('All matched', 'carticy-conversions-for-woocommerce')))))))), data.capped && wp.element.createElement("p", {
    className: "table-cap"
  }, (0,external_wp_i18n_namespaceObject.__)('Large store: this report scanned the most recent paid orders and may not cover the whole window.', 'carticy-conversions-for-woocommerce')), data.window && data.window.clampedToActivation && wp.element.createElement("p", {
    className: "table-cap"
  }, (0,external_wp_i18n_namespaceObject.__)('This report starts at plugin activation. Orders paid before then are not counted as missed.', 'carticy-conversions-for-woocommerce'))), wp.element.createElement("div", {
    className: "app-actions"
  }, totals.gapOrders > 0 && wp.element.createElement("span", {
    className: "health-sub",
    style: {
      margin: 0
    }
  }, (0,external_wp_i18n_namespaceObject.sprintf)(/* translators: %d: number of missed orders. */
  (0,external_wp_i18n_namespaceObject.__)("%d purchases weren't tracked in this window.", 'carticy-conversions-for-woocommerce'), totals.gapOrders)), wp.element.createElement("button", {
    type: "button",
    className: "cv-btn cv-btn--secondary",
    style: {
      marginLeft: 'auto'
    },
    onClick: () => report.refetch()
  }, (0,external_wp_i18n_namespaceObject.__)('Re-check', 'carticy-conversions-for-woocommerce')), wp.element.createElement("button", {
    type: "button",
    className: "app-link",
    onClick: () => navigate('#home')
  }, (0,external_wp_i18n_namespaceObject.__)('Back to status', 'carticy-conversions-for-woocommerce'))));
}
;// ./assets/js/src/admin/screens/RecentEvents.jsx
/**
 * Recent events. Renders /diagnostics/recent-events
 * verbatim: the server's uiStatus per destination drives the status cell
 * (06R semantics - waiting_for_consent is a neutral paused state, only a
 * permanent failure is red), and the Platforms column comes from the
 * server-resolved clientDestinations / dispatch destinations.
 */






const EVENT_LABELS = {
  purchase: (0,external_wp_i18n_namespaceObject.__)('Purchase', 'carticy-conversions-for-woocommerce'),
  refund: (0,external_wp_i18n_namespaceObject.__)('Refund', 'carticy-conversions-for-woocommerce'),
  renewal: (0,external_wp_i18n_namespaceObject.__)('Renewal', 'carticy-conversions-for-woocommerce')
};
const DESTINATION_LABELS = {
  ga4: 'GA4',
  ga4_mp: 'GA4',
  google_ads: 'Google Ads',
  meta: 'Meta',
  meta_capi: 'Meta',
  internal: ''
};
function statusCell(event) {
  const destinations = event.destinations || [];
  if (destinations.some(row => 'failed' === row.uiStatus)) {
    return wp.element.createElement("span", {
      className: "decision decision--denied"
    }, wp.element.createElement("span", {
      className: "dot dot--critical"
    }), (0,external_wp_i18n_namespaceObject.__)('Failed', 'carticy-conversions-for-woocommerce'));
  }
  if (destinations.some(row => 'waiting_for_consent' === row.uiStatus)) {
    return wp.element.createElement("span", {
      className: "decision decision--waiting"
    }, wp.element.createElement("span", {
      className: "dot dot--neutral"
    }), (0,external_wp_i18n_namespaceObject.__)('Waiting for consent', 'carticy-conversions-for-woocommerce'));
  }
  if (destinations.some(row => 'waiting_for_config' === row.uiStatus || 'waiting_for_identity' === row.uiStatus)) {
    return wp.element.createElement("span", {
      className: "decision decision--waiting"
    }, wp.element.createElement("span", {
      className: "dot dot--neutral"
    }), (0,external_wp_i18n_namespaceObject.__)('Waiting for setup', 'carticy-conversions-for-woocommerce'));
  }
  if (destinations.some(row => 'delivered' === row.uiStatus)) {
    return wp.element.createElement("span", {
      className: "decision decision--sent"
    }, wp.element.createElement("span", {
      className: "dot dot--green"
    }), (0,external_wp_i18n_namespaceObject.__)('Sent', 'carticy-conversions-for-woocommerce'));
  }
  if (destinations.some(row => 'pending' === row.uiStatus || 'retrying' === row.uiStatus)) {
    return wp.element.createElement("span", {
      className: "decision decision--waiting"
    }, wp.element.createElement("span", {
      className: "dot dot--neutral"
    }), (0,external_wp_i18n_namespaceObject.__)('Sending...', 'carticy-conversions-for-woocommerce'));
  }
  if (event.clientTracked) {
    return wp.element.createElement("span", {
      className: "decision decision--sent"
    }, wp.element.createElement("span", {
      className: "dot dot--green"
    }), (0,external_wp_i18n_namespaceObject.__)('Recorded', 'carticy-conversions-for-woocommerce'));
  }
  return wp.element.createElement("span", {
    className: "decision decision--waiting"
  }, wp.element.createElement("span", {
    className: "dot dot--neutral"
  }), (0,external_wp_i18n_namespaceObject.__)('Pending', 'carticy-conversions-for-woocommerce'));
}
function platformsCell(event) {
  const names = new Set();
  (event.clientDestinations || []).forEach(key => {
    if (DESTINATION_LABELS[key]) {
      names.add(DESTINATION_LABELS[key]);
    }
  });
  (event.destinations || []).forEach(row => {
    const label = DESTINATION_LABELS[row.destination];
    if (label) {
      names.add(label);
    }
  });
  return names.size > 0 ? Array.from(names).join(' - ') : (0,external_wp_i18n_namespaceObject.__)('None', 'carticy-conversions-for-woocommerce');
}

// The stored per-destination "why" (attempts, HTTP status, redacted error,
// next retry) - without it a merchant cannot tell an invalid token from a
// platform outage (the atamember inspectable-row lesson).
function destinationDetail(row) {
  const parts = [];
  if (row.attempts > 0) {
    parts.push((0,external_wp_i18n_namespaceObject.sprintf)(/* translators: %d: number of delivery attempts. */
    (0,external_wp_i18n_namespaceObject.__)('attempt %d', 'carticy-conversions-for-woocommerce'), row.attempts));
  }
  if (row.lastHttpStatus) {
    parts.push('HTTP ' + row.lastHttpStatus);
  }
  if (row.lastErrorCode) {
    parts.push(row.lastErrorCode);
  }
  if ('retrying' === row.uiStatus && row.nextAttemptAt) {
    parts.push((0,external_wp_i18n_namespaceObject.sprintf)(/* translators: %s: humanized time, e.g. "15 minutes". */
    (0,external_wp_i18n_namespaceObject.__)('next try in about %s', 'carticy-conversions-for-woocommerce'), relativeTimeUntil(row.nextAttemptAt) || (0,external_wp_i18n_namespaceObject.__)('moments', 'carticy-conversions-for-woocommerce')));
  }
  return parts.join(' - ');
}

// The internal bookkeeping sink is not a merchant-facing platform; hide it
// from the delivery detail like the Platforms column already does.
const INTERNAL_DESTINATIONS = ['internal', 'internal_log', 'canonical_event_store'];
function EventRow({
  event: rawEvent
}) {
  const [expanded, setExpanded] = (0,external_wp_element_namespaceObject.useState)(false);
  const destinations = (rawEvent.destinations || []).filter(row => !INTERNAL_DESTINATIONS.includes(row.destination));
  const event = {
    ...rawEvent,
    destinations
  };
  const expandable = destinations.length > 0;
  return wp.element.createElement(wp.element.Fragment, null, wp.element.createElement("tr", null, wp.element.createElement("td", {
    className: "col-when"
  }, relativeTimeShort(event.occurredAt)), wp.element.createElement("td", null, EVENT_LABELS[event.eventType] || event.eventType), wp.element.createElement("td", {
    className: "col-order"
  }, expandable && wp.element.createElement("button", {
    type: "button",
    className: "expand-caret",
    onClick: () => setExpanded(value => !value),
    "aria-expanded": expanded,
    "aria-label": (0,external_wp_i18n_namespaceObject.sprintf)(/* translators: %d: order number. */
    (0,external_wp_i18n_namespaceObject.__)('Show delivery detail for order #%d', 'carticy-conversions-for-woocommerce'), event.orderId)
  }, wp.element.createElement(IconChevronDown, null)), event.orderUrl ? wp.element.createElement("a", {
    className: "app-link",
    href: event.orderUrl
  }, "#", event.orderId) : wp.element.createElement(wp.element.Fragment, null, "#", event.orderId)), wp.element.createElement("td", null, platformsCell(event)), wp.element.createElement("td", null, statusCell(event))), expanded && wp.element.createElement("tr", {
    className: "audit-subrow"
  }, wp.element.createElement("td", {
    colSpan: 5
  }, wp.element.createElement("div", {
    className: "audit-detail"
  }, destinations.map((row, index) => {
    const detail = destinationDetail(row);
    return wp.element.createElement("span", {
      className: 'failed' === row.uiStatus ? 'audit-detail__line is-decided' : 'audit-detail__line',
      key: index
    }, DESTINATION_LABELS[row.destination] || row.destination, ": ", row.uiStatus, detail && ` (${detail})`, row.lastErrorMessage && ` - ${row.lastErrorMessage}`);
  })))));
}
function RecentEvents({
  navigate
}) {
  const events = useResource(ENDPOINTS.recentEvents);
  const rows = (events.data && events.data.events || []).slice().sort((a, b) => a.occurredAt < b.occurredAt ? 1 : -1);
  return wp.element.createElement("div", {
    className: "app"
  }, wp.element.createElement("div", {
    className: "health-head",
    style: {
      marginBottom: '24px'
    }
  }, wp.element.createElement("div", null, wp.element.createElement("h2", {
    className: "health-title"
  }, (0,external_wp_i18n_namespaceObject.__)('Recent events', 'carticy-conversions-for-woocommerce')))), events.error && wp.element.createElement("div", {
    className: "cv-banner cv-banner--critical",
    role: "alert"
  }, wp.element.createElement("div", {
    className: "cv-banner__body"
  }, wp.element.createElement("p", {
    className: "cv-banner__desc"
  }, events.error.message))), wp.element.createElement("div", {
    className: "cv-card"
  }, events.loading && !events.data ? wp.element.createElement("div", {
    className: "app-loading",
    role: "status"
  }, (0,external_wp_i18n_namespaceObject.__)('Loading', 'carticy-conversions-for-woocommerce')) : 0 === rows.length ? wp.element.createElement("p", {
    className: "health-sub",
    style: {
      margin: 0
    }
  }, (0,external_wp_i18n_namespaceObject.__)('No tracked events yet. Your next paid order shows up here.', 'carticy-conversions-for-woocommerce')) : wp.element.createElement("div", {
    className: "table-wrap"
  }, wp.element.createElement("table", {
    className: "consent-table"
  }, wp.element.createElement("thead", null, wp.element.createElement("tr", null, wp.element.createElement("th", {
    scope: "col"
  }, (0,external_wp_i18n_namespaceObject.__)('Time', 'carticy-conversions-for-woocommerce')), wp.element.createElement("th", {
    scope: "col"
  }, (0,external_wp_i18n_namespaceObject.__)('Event', 'carticy-conversions-for-woocommerce')), wp.element.createElement("th", {
    scope: "col"
  }, (0,external_wp_i18n_namespaceObject.__)('Order', 'carticy-conversions-for-woocommerce')), wp.element.createElement("th", {
    scope: "col"
  }, (0,external_wp_i18n_namespaceObject.__)('Platforms', 'carticy-conversions-for-woocommerce')), wp.element.createElement("th", {
    scope: "col"
  }, (0,external_wp_i18n_namespaceObject.__)('Status', 'carticy-conversions-for-woocommerce')))), wp.element.createElement("tbody", null, rows.map(event => wp.element.createElement(EventRow, {
    event: event,
    key: event.orderId + '|' + event.eventId
  }))))), wp.element.createElement("p", {
    className: "table-cap"
  }, (0,external_wp_i18n_namespaceObject.__)('Every event here is a real recorded delivery state. Nothing is assumed.', 'carticy-conversions-for-woocommerce'))), wp.element.createElement("div", {
    className: "app-actions"
  }, wp.element.createElement("button", {
    type: "button",
    className: "app-link",
    onClick: () => navigate('#home')
  }, (0,external_wp_i18n_namespaceObject.__)('Back to status', 'carticy-conversions-for-woocommerce'))));
}
;// ./assets/js/src/admin/screens/settings/PlatformsTab.jsx
/**
 * Settings - Platforms. Connected cards render the server's
 * normalized echo; Edit IDs reuses the same flat-shape form + guide content
 * as onboarding Connect; Disconnect sets the provider mode to off and clears
 * its ids (a real action, confirmed by the echo).
 */










function EditField({
  id,
  label,
  placeholder,
  value,
  onChange,
  guide
}) {
  return wp.element.createElement("div", {
    className: "mfield"
  }, wp.element.createElement("label", {
    className: "cv-label",
    htmlFor: id
  }, label), wp.element.createElement("input", {
    id: id,
    className: "cv-input",
    type: "text",
    placeholder: placeholder,
    value: value,
    onChange: event => onChange(event.target.value)
  }), guide && wp.element.createElement(Walkthrough, {
    guide: guide
  }));
}
function PlatformsTab({
  status
}) {
  const settings = useResource(ENDPOINTS.settings);
  const save = useMutation(ENDPOINTS.settings);
  const [editing, setEditing] = (0,external_wp_element_namespaceObject.useState)(null);
  const [form, setForm] = (0,external_wp_element_namespaceObject.useState)({});
  if (settings.loading && !settings.data) {
    return wp.element.createElement("div", {
      className: "app-loading",
      role: "status"
    }, (0,external_wp_i18n_namespaceObject.__)('Loading', 'carticy-conversions-for-woocommerce'));
  }
  if (settings.error && !settings.data) {
    return wp.element.createElement(LoadError, {
      error: settings.error,
      onRetry: settings.refetch
    });
  }
  const flat = flattenClientTracking(settings.data || {});
  const echo = providerEcho(settings.data || {});
  const ga4 = echo.providers.ga4 || {};
  const ads = echo.providers.google_ads || {};
  const meta = echo.providers.meta || {};
  const upgradeUrl = status && status.plan && status.plan.upgradeUrl || 'https://carticy.com/plugins/carticy-conversions-for-woocommerce/';
  const startEdit = which => {
    setForm({
      ...flat
    });
    setEditing(which);
  };
  const persist = async patch => {
    const response = await save.mutate({
      clientTracking: {
        ...flat,
        ...patch
      }
    });
    settings.setData(response);
  };
  const saveEdit = async () => {
    try {
      await persist(form);
      setEditing(null);
    } catch (error) {
      // save.error renders below.
    }
  };
  const disconnect = async which => {
    const patch = 'google' === which ? {
      ga4_mode: 'off',
      google_ads_mode: 'off',
      ga4_measurement_id: '',
      google_ads_conversion_id: '',
      google_ads_conversion_label: ''
    } : {
      meta_mode: 'off',
      meta_pixel_id: ''
    };
    try {
      await persist(patch);
    } catch (error) {
      // save.error renders below.
    }
  };
  const card = (which, name, metaLabel, connected, chips, editFields) => wp.element.createElement("div", {
    className: "conn-card"
  }, wp.element.createElement("div", {
    className: "conn-card__head"
  }, wp.element.createElement("span", {
    className: "wordmark"
  }, name, ' ', wp.element.createElement("span", {
    className: "conn-group__meta",
    style: {
      marginLeft: '6px'
    }
  }, metaLabel)), connected ? wp.element.createElement("span", {
    className: "cv-status cv-status--connected"
  }, (0,external_wp_i18n_namespaceObject.__)('Connected', 'carticy-conversions-for-woocommerce')) : wp.element.createElement("span", {
    className: "cv-status cv-status--disconnected"
  }, (0,external_wp_i18n_namespaceObject.__)('Not configured', 'carticy-conversions-for-woocommerce'))), editing === which ? wp.element.createElement(wp.element.Fragment, null, wp.element.createElement("div", {
    className: "mfields"
  }, editFields), wp.element.createElement("div", {
    className: "conn-card__foot"
  }, wp.element.createElement("button", {
    type: "button",
    className: "cv-btn cv-btn--primary cv-btn--sm",
    onClick: saveEdit,
    disabled: save.saving
  }, (0,external_wp_i18n_namespaceObject.__)('Save', 'carticy-conversions-for-woocommerce')), wp.element.createElement("button", {
    type: "button",
    className: "cv-btn cv-btn--secondary cv-btn--sm",
    onClick: () => setEditing(null)
  }, (0,external_wp_i18n_namespaceObject.__)('Cancel', 'carticy-conversions-for-woocommerce')))) : wp.element.createElement(wp.element.Fragment, null, chips.length > 0 && wp.element.createElement("div", {
    className: "conn-card__ids"
  }, chips), wp.element.createElement("div", {
    className: "conn-card__foot"
  }, wp.element.createElement("button", {
    type: "button",
    className: "cv-btn cv-btn--secondary cv-btn--sm",
    onClick: () => startEdit(which)
  }, (0,external_wp_i18n_namespaceObject.__)('Edit IDs', 'carticy-conversions-for-woocommerce')), connected && wp.element.createElement("button", {
    type: "button",
    className: "cv-btn cv-btn--secondary cv-btn--sm",
    onClick: () => disconnect(which),
    disabled: save.saving
  }, (0,external_wp_i18n_namespaceObject.__)('Disconnect', 'carticy-conversions-for-woocommerce')))));
  return wp.element.createElement(wp.element.Fragment, null, save.error && wp.element.createElement("div", {
    className: "cv-banner cv-banner--critical",
    role: "alert"
  }, wp.element.createElement("div", {
    className: "cv-banner__body"
  }, wp.element.createElement("p", {
    className: "cv-banner__desc"
  }, save.error.message))), card('google', 'Google', 'GA4 + Ads', !!(ga4.enabled || ads.enabled), [ga4.measurementId && wp.element.createElement("span", {
    className: "id-chip",
    key: "ga4"
  }, "GA4 ", ga4.measurementId), ads.conversionId && wp.element.createElement("span", {
    className: "id-chip",
    key: "ads"
  }, "Ads ", ads.conversionId), ads.conversionLabel && wp.element.createElement("span", {
    className: "id-chip",
    key: "label"
  }, (0,external_wp_i18n_namespaceObject.__)('Label', 'carticy-conversions-for-woocommerce'), " ", ads.conversionLabel)].filter(Boolean), wp.element.createElement(wp.element.Fragment, null, wp.element.createElement(EditField, {
    id: "set-ga4",
    label: (0,external_wp_i18n_namespaceObject.__)('GA4 Measurement ID', 'carticy-conversions-for-woocommerce'),
    placeholder: "G-XXXXXXXXXX",
    value: form.ga4_measurement_id || '',
    onChange: value => setForm(prev => ({
      ...prev,
      ga4_measurement_id: value,
      ga4_mode: 'off' === prev.ga4_mode ? 'direct' : prev.ga4_mode
    })),
    guide: GUIDES.ga4_measurement_id
  }), wp.element.createElement(EditField, {
    id: "set-ads-id",
    label: (0,external_wp_i18n_namespaceObject.__)('Google Ads Conversion ID', 'carticy-conversions-for-woocommerce'),
    placeholder: "AW-XXXXXXXXX",
    value: form.google_ads_conversion_id || '',
    onChange: value => setForm(prev => ({
      ...prev,
      google_ads_conversion_id: value,
      google_ads_mode: 'off' === prev.google_ads_mode ? 'direct' : prev.google_ads_mode
    })),
    guide: GUIDES.google_ads_conversion
  }), wp.element.createElement(EditField, {
    id: "set-ads-label",
    label: (0,external_wp_i18n_namespaceObject.__)('Google Ads conversion label', 'carticy-conversions-for-woocommerce'),
    placeholder: "aBcD1efGhIjkLM",
    value: form.google_ads_conversion_label || '',
    onChange: value => setForm(prev => ({
      ...prev,
      google_ads_conversion_label: value
    }))
  }))), card('meta', 'Meta', 'Pixel', !!meta.enabled, [meta.pixelId && wp.element.createElement("span", {
    className: "id-chip",
    key: "pixel"
  }, "Pixel ", meta.pixelId)].filter(Boolean), wp.element.createElement(EditField, {
    id: "set-pixel",
    label: (0,external_wp_i18n_namespaceObject.__)('Meta Pixel ID', 'carticy-conversions-for-woocommerce'),
    placeholder: (0,external_wp_i18n_namespaceObject.__)('15 to 16 digit ID', 'carticy-conversions-for-woocommerce'),
    value: form.meta_pixel_id || '',
    onChange: value => setForm(prev => ({
      ...prev,
      meta_pixel_id: value,
      meta_mode: 'off' === prev.meta_mode ? 'direct' : prev.meta_mode
    })),
    guide: GUIDES.meta_pixel_id
  })), wp.element.createElement("div", {
    className: "locked-row",
    style: {
      marginTop: 0
    }
  }, wp.element.createElement("span", {
    className: "locked-row__icon"
  }, wp.element.createElement(IconLock, null)), wp.element.createElement("div", {
    className: "locked-row__body"
  }, wp.element.createElement("p", {
    className: "locked-row__title"
  }, (0,external_wp_i18n_namespaceObject.__)('Server-side delivery', 'carticy-conversions-for-woocommerce'), " ", wp.element.createElement("span", {
    className: "cv-required-tag"
  }, "Pro")), wp.element.createElement("p", {
    className: "locked-row__sub"
  }, (0,external_wp_i18n_namespaceObject.__)('CAPI, Measurement Protocol, and Enhanced Conversions. Unlocks with Pro.', 'carticy-conversions-for-woocommerce'))), wp.element.createElement("a", {
    className: "cv-btn cv-btn--primary cv-btn--sm locked-row__action",
    href: upgradeUrl,
    target: "_blank",
    rel: "noreferrer noopener"
  }, COPY.upgradeCta)));
}
;// ./assets/js/src/admin/screens/settings/DeliveryTab.jsx
/**
 * Settings - Delivery. Switching the mode rewrites the provider
 * modes (the same persistence as onboarding); the GTM card's only automation
 * claim is the honest one - download and import a ready-made container file
 * (GET /gtm/import-package to client-side file download).
 */










function DeliveryTab() {
  const settings = useResource(ENDPOINTS.settings);
  const save = useMutation(ENDPOINTS.settings);
  const [gtmInput, setGtmInput] = (0,external_wp_element_namespaceObject.useState)(null);
  const [downloading, setDownloading] = (0,external_wp_element_namespaceObject.useState)(false);
  const [downloadError, setDownloadError] = (0,external_wp_element_namespaceObject.useState)(null);
  if (settings.loading && !settings.data) {
    return wp.element.createElement("div", {
      className: "app-loading",
      role: "status"
    }, (0,external_wp_i18n_namespaceObject.__)('Loading', 'carticy-conversions-for-woocommerce'));
  }
  if (settings.error && !settings.data) {
    return wp.element.createElement(LoadError, {
      error: settings.error,
      onRetry: settings.refetch
    });
  }
  const flat = flattenClientTracking(settings.data || {});
  const echo = providerEcho(settings.data || {});
  const gtm = echo.gtm || {};
  const isGtm = !!gtm.enabled;
  const switchMode = async (target, containerId) => {
    const toMode = currentMode => 'off' === currentMode ? 'off' : target;
    try {
      const response = await save.mutate({
        clientTracking: {
          ...flat,
          ga4_mode: toMode(flat.ga4_mode),
          google_ads_mode: toMode(flat.google_ads_mode),
          meta_mode: toMode(flat.meta_mode),
          gtm_container_id: 'gtm' === target ? containerId : ''
        }
      });
      settings.setData(response);
      setGtmInput(null);
    } catch (error) {
      // save.error renders below.
    }
  };
  const download = async () => {
    setDownloading(true);
    setDownloadError(null);
    try {
      const pkg = await apiGet(ENDPOINTS.gtmImport);
      const blob = new Blob([JSON.stringify(pkg.container, null, 2)], {
        type: 'application/json'
      });
      const url = URL.createObjectURL(blob);
      const link = document.createElement('a');
      link.href = url;
      link.download = 'carticy-conversions-gtm-container.json';
      document.body.appendChild(link);
      link.click();
      link.remove();
      URL.revokeObjectURL(url);
    } catch (error) {
      setDownloadError(error);
    } finally {
      setDownloading(false);
    }
  };
  return wp.element.createElement(wp.element.Fragment, null, (save.error || downloadError) && wp.element.createElement("div", {
    className: "cv-banner cv-banner--critical",
    role: "alert"
  }, wp.element.createElement("div", {
    className: "cv-banner__body"
  }, wp.element.createElement("p", {
    className: "cv-banner__desc"
  }, (save.error || downloadError).message))), wp.element.createElement("div", {
    className: "choice-2"
  }, wp.element.createElement("div", {
    className: "cv-card choice-card"
  }, wp.element.createElement("div", {
    className: "conn-card__head"
  }, wp.element.createElement("p", {
    className: "choice-card__head"
  }, (0,external_wp_i18n_namespaceObject.__)('Direct tags (recommended)', 'carticy-conversions-for-woocommerce')), !isGtm && wp.element.createElement("span", {
    className: "cv-status cv-status--connected"
  }, (0,external_wp_i18n_namespaceObject.__)('Active', 'carticy-conversions-for-woocommerce'))), wp.element.createElement("p", {
    className: "choice-card__body"
  }, (0,external_wp_i18n_namespaceObject.__)('Carticy Conversions installs and fires the tags for you. No Tag Manager needed.', 'carticy-conversions-for-woocommerce')), isGtm && wp.element.createElement("button", {
    type: "button",
    className: "cv-btn cv-btn--secondary cv-btn--sm",
    onClick: () => switchMode('direct', ''),
    disabled: save.saving
  }, (0,external_wp_i18n_namespaceObject.__)('Switch to direct', 'carticy-conversions-for-woocommerce'))), wp.element.createElement("div", {
    className: "cv-card choice-card"
  }, wp.element.createElement("div", {
    className: "conn-card__head"
  }, wp.element.createElement("p", {
    className: "choice-card__head"
  }, (0,external_wp_i18n_namespaceObject.__)('Google Tag Manager', 'carticy-conversions-for-woocommerce')), isGtm && wp.element.createElement("span", {
    className: "cv-status cv-status--connected"
  }, (0,external_wp_i18n_namespaceObject.__)('Active', 'carticy-conversions-for-woocommerce'))), wp.element.createElement("p", {
    className: "choice-card__body"
  }, isGtm ? (0,external_wp_i18n_namespaceObject.sprintf)(/* translators: %s: GTM container id. */
  (0,external_wp_i18n_namespaceObject.__)('Attached to %s.', 'carticy-conversions-for-woocommerce'), gtm.containerId) : COPY.gtmImportHint), isGtm ? wp.element.createElement("div", {
    className: "detect-card__foot"
  }, wp.element.createElement("button", {
    type: "button",
    className: "cv-btn cv-btn--secondary cv-btn--sm",
    onClick: download,
    disabled: downloading,
    "aria-busy": downloading ? 'true' : undefined
  }, COPY.gtmImportAction)) : null === gtmInput ? wp.element.createElement("button", {
    type: "button",
    className: "cv-btn cv-btn--secondary cv-btn--sm",
    onClick: () => setGtmInput(flat.gtm_container_id || '')
  }, (0,external_wp_i18n_namespaceObject.__)('Switch to Tag Manager', 'carticy-conversions-for-woocommerce')) : wp.element.createElement("div", {
    className: "mfields"
  }, wp.element.createElement("div", {
    className: "mfield"
  }, wp.element.createElement("label", {
    className: "cv-label",
    htmlFor: "delivery-gtm-id"
  }, (0,external_wp_i18n_namespaceObject.__)('GTM container ID', 'carticy-conversions-for-woocommerce')), wp.element.createElement("input", {
    id: "delivery-gtm-id",
    className: "cv-input",
    type: "text",
    placeholder: "GTM-XXXXXXX",
    value: gtmInput,
    onChange: event => setGtmInput(event.target.value)
  }), wp.element.createElement(Walkthrough, {
    guide: GUIDES.gtm_container_id
  })), wp.element.createElement("div", {
    className: "detect-card__foot"
  }, wp.element.createElement("button", {
    type: "button",
    className: "cv-btn cv-btn--primary cv-btn--sm",
    onClick: () => switchMode('gtm', gtmInput.trim()),
    disabled: save.saving || !gtmInput.trim()
  }, (0,external_wp_i18n_namespaceObject.__)('Save', 'carticy-conversions-for-woocommerce')), wp.element.createElement("button", {
    type: "button",
    className: "cv-btn cv-btn--secondary cv-btn--sm",
    onClick: () => setGtmInput(null)
  }, (0,external_wp_i18n_namespaceObject.__)('Cancel', 'carticy-conversions-for-woocommerce')))))), isGtm && wp.element.createElement(Walkthrough, {
    guide: GUIDES.gtm_import
  }), wp.element.createElement("p", {
    className: "delivery-note"
  }, (0,external_wp_i18n_namespaceObject.__)('Whichever you choose, every order is counted once per platform, deduplicated by order ID.', 'carticy-conversions-for-woocommerce')));
}
;// ./assets/js/src/admin/screens/settings/EventsTab.jsx
/**
 * Settings - Events. The toggles persist via
 * POST /settings { events } and the order-event engine honors them at
 * canonical-event creation. The renewal row only renders as a control when
 * the server reports a subscriptions engine (renewalAvailable).
 */





const ROWS = [{
  key: 'purchase',
  title: () => (0,external_wp_i18n_namespaceObject.__)('Purchase', 'carticy-conversions-for-woocommerce'),
  sub: () => (0,external_wp_i18n_namespaceObject.__)('Tracked on every paid order.', 'carticy-conversions-for-woocommerce')
}, {
  key: 'refund',
  title: () => (0,external_wp_i18n_namespaceObject.__)('Refund', 'carticy-conversions-for-woocommerce'),
  sub: () => (0,external_wp_i18n_namespaceObject.__)('Sent when you refund an order.', 'carticy-conversions-for-woocommerce')
}, {
  key: 'renewal',
  title: () => (0,external_wp_i18n_namespaceObject.__)('Subscription renewal', 'carticy-conversions-for-woocommerce'),
  sub: () => (0,external_wp_i18n_namespaceObject.__)('Tracked for recurring payments. Needs WooCommerce Subscriptions.', 'carticy-conversions-for-woocommerce')
}];
function EventsTab() {
  const settings = useResource(ENDPOINTS.settings);
  const save = useMutation(ENDPOINTS.settings);
  const [pendingEvents, setPendingEvents] = (0,external_wp_element_namespaceObject.useState)(null);
  if (settings.loading && !settings.data) {
    return wp.element.createElement("div", {
      className: "app-loading",
      role: "status"
    }, (0,external_wp_i18n_namespaceObject.__)('Loading', 'carticy-conversions-for-woocommerce'));
  }
  if (settings.error && !settings.data) {
    return wp.element.createElement(LoadError, {
      error: settings.error,
      onRetry: settings.refetch
    });
  }
  const events = pendingEvents || settings.data && settings.data.events || {};
  const renewalAvailable = !!(settings.data && settings.data.eventsTaxonomy && settings.data.eventsTaxonomy.renewalAvailable);
  const toggle = async (key, enabled) => {
    // The DOM checkbox is the truth for the requested state - computing
    // `!events[key]` from the render closure double-flips when a label
    // click and the input change race a re-render.
    try {
      setPendingEvents({
        ...events,
        [key]: enabled
      });
      const response = await save.mutate({
        events: {
          [key]: enabled
        }
      });
      settings.setData(response);
    } catch (error) {
      // save.error renders below.
    } finally {
      setPendingEvents(null);
    }
  };
  return wp.element.createElement(wp.element.Fragment, null, save.error && wp.element.createElement("div", {
    className: "cv-banner cv-banner--critical",
    role: "alert"
  }, wp.element.createElement("div", {
    className: "cv-banner__body"
  }, wp.element.createElement("p", {
    className: "cv-banner__desc"
  }, save.error.message))), wp.element.createElement("span", {
    className: "screen-reader-text",
    role: "status",
    "aria-live": "polite"
  }, save.saving ? (0,external_wp_i18n_namespaceObject.__)('Saving', 'carticy-conversions-for-woocommerce') : ''), wp.element.createElement("div", {
    className: "cv-card",
    style: {
      display: 'flex',
      flexDirection: 'column'
    }
  }, ROWS.map((row, index) => {
    const isRenewal = 'renewal' === row.key;
    const style = {};
    if (0 === index) {
      style.paddingTop = 0;
    }
    if (index === ROWS.length - 1) {
      style.paddingBottom = 0;
    }
    return wp.element.createElement("div", {
      className: save.saving ? 'priv-row is-saving' : 'priv-row',
      style: style,
      key: row.key
    }, wp.element.createElement("div", null, wp.element.createElement("p", {
      className: "toggle-row__title"
    }, row.title()), wp.element.createElement("p", {
      className: "toggle-row__sub"
    }, row.sub(), isRenewal && !renewalAvailable && ' ' + (0,external_wp_i18n_namespaceObject.__)('Not detected on this store.', 'carticy-conversions-for-woocommerce'))), (!isRenewal || renewalAvailable) && wp.element.createElement("label", {
      className: "cv-toggle cv-toggle--lg"
    }, wp.element.createElement("input", {
      type: "checkbox",
      className: "cv-toggle__input",
      checked: !!events[row.key],
      onChange: event => toggle(row.key, event.target.checked),
      disabled: save.saving,
      "aria-label": row.title()
    }), wp.element.createElement("span", {
      className: "cv-toggle__track",
      "aria-hidden": "true"
    }, wp.element.createElement("span", {
      className: "cv-toggle__thumb"
    }))));
  })), wp.element.createElement("p", {
    className: "events-note"
  }, (0,external_wp_i18n_namespaceObject.__)('Each event carries the order ID, so Google and Meta never count it twice.', 'carticy-conversions-for-woocommerce')));
}
;// ./assets/js/src/admin/screens/settings/ConsentTab.jsx
/**
 * Settings - Consent: detected source header, the posture radios
 * (the server records the attestation for not_required), then only renders
 * per-service intake and extra consent sources when the selected posture can
 * use consent signals. Service "off" disables a platform's consent intake
 * entirely; the send-time gate itself stays an explicit-grant allow-list.
 */






const SERVICE_LABELS = {
  meta: 'Meta',
  'google-ads': 'Google Ads',
  ga4: 'GA4'
};

// Mirrors GenericConsentPresetRegistry: GA4 gates on the statistics category,
// the ad platforms on marketing - saying "marketing" for all three would
// contradict what the gate actually does on a statistics-only grant.
const SERVICE_GATE_COPY = {
  meta: () => (0,external_wp_i18n_namespaceObject.__)('Waits for marketing consent.', 'carticy-conversions-for-woocommerce'),
  'google-ads': () => (0,external_wp_i18n_namespaceObject.__)('Waits for marketing consent.', 'carticy-conversions-for-woocommerce'),
  ga4: () => (0,external_wp_i18n_namespaceObject.__)('Waits for statistics consent.', 'carticy-conversions-for-woocommerce')
};
const SNIPPET = "carticyConsent.set('granted')";
function ConsentTab() {
  const consent = useResource(ENDPOINTS.consent);
  const save = useMutation(ENDPOINTS.consent);
  const [copied, setCopied] = (0,external_wp_element_namespaceObject.useState)(false);
  const [pendingPosture, setPendingPosture] = (0,external_wp_element_namespaceObject.useState)(null);
  const [pendingServices, setPendingServices] = (0,external_wp_element_namespaceObject.useState)(null);
  if (consent.loading && !consent.data) {
    return wp.element.createElement("div", {
      className: "app-loading",
      role: "status"
    }, (0,external_wp_i18n_namespaceObject.__)('Loading', 'carticy-conversions-for-woocommerce'));
  }
  if (consent.error && !consent.data) {
    return wp.element.createElement(LoadError, {
      error: consent.error,
      onRetry: consent.refetch
    });
  }
  const data = consent.data || {};
  const detected = data.detected || [];
  const posture = pendingPosture || data.posture || 'required';
  const config = data.config || {};
  const services = pendingServices || config.services || {};
  const presets = data.presets || [];
  const attestation = data.attestation || {};
  const usesConsentSignals = 'not_required' !== posture;
  const post = async (body, clearPending) => {
    try {
      const response = await save.mutate(body);
      consent.setData(response);
    } catch (error) {
      // save.error renders below.
    } finally {
      if (clearPending) {
        clearPending();
      }
    }
  };
  const setPosture = value => {
    if (save.saving) {
      return;
    }
    setPendingPosture(value);
    post({
      posture: value
    }, () => setPendingPosture(null));
  };
  const setService = (service, gated) => {
    if (save.saving) {
      return;
    }
    const nextServices = {
      ...services,
      [service]: gated ? 'auto' : 'off'
    };
    setPendingServices(nextServices);
    post({
      config: {
        ...config,
        services: nextServices
      }
    }, () => setPendingServices(null));
  };
  const copySnippet = async () => {
    try {
      await navigator.clipboard.writeText(SNIPPET);
      setCopied(true);
      setTimeout(() => setCopied(false), 2000);
    } catch (error) {
      // Clipboard may be blocked; the snippet stays selectable.
    }
  };
  const radio = (value, title, desc) => wp.element.createElement("label", {
    className: ['cv-radio-card', posture === value ? 'is-selected' : '', save.saving ? 'is-saving' : ''].filter(Boolean).join(' ')
  }, wp.element.createElement("input", {
    type: "radio",
    className: "cv-radio",
    name: "consent-mode",
    checked: posture === value,
    onChange: () => setPosture(value),
    disabled: save.saving,
    style: {
      marginTop: '2px'
    }
  }), wp.element.createElement("span", {
    className: "cv-radio-card__main"
  }, wp.element.createElement("span", {
    className: "cv-radio-card__title"
  }, title), desc && wp.element.createElement("span", {
    className: "cv-radio-card__desc"
  }, desc)));
  return wp.element.createElement(wp.element.Fragment, null, save.error && wp.element.createElement("div", {
    className: "cv-banner cv-banner--critical",
    role: "alert"
  }, wp.element.createElement("div", {
    className: "cv-banner__body"
  }, wp.element.createElement("p", {
    className: "cv-banner__desc"
  }, save.error.message))), wp.element.createElement("div", {
    className: "conn-card"
  }, wp.element.createElement("div", {
    className: "conn-card__head"
  }, wp.element.createElement("span", {
    style: {
      fontSize: '14px',
      fontWeight: 600,
      color: 'var(--cv-fg-1)'
    }
  }, detected.length > 0 ? (0,external_wp_i18n_namespaceObject.sprintf)(/* translators: 1: consent platform name, 2: channel. */
  (0,external_wp_i18n_namespaceObject.__)('Consent source: %1$s, via %2$s', 'carticy-conversions-for-woocommerce'), detected[0].label, 'wp-consent-api' === detected[0].channel ? 'WP Consent API' : detected[0].channel) : (0,external_wp_i18n_namespaceObject.__)('No consent platform detected', 'carticy-conversions-for-woocommerce')), detected.length > 0 ? wp.element.createElement("span", {
    className: "cv-status cv-status--connected"
  }, (0,external_wp_i18n_namespaceObject.__)('Connected', 'carticy-conversions-for-woocommerce')) : wp.element.createElement("span", {
    className: "cv-status cv-status--disconnected"
  }, (0,external_wp_i18n_namespaceObject.__)('None', 'carticy-conversions-for-woocommerce')))), wp.element.createElement("span", {
    className: "screen-reader-text",
    role: "status",
    "aria-live": "polite"
  }, save.saving ? (0,external_wp_i18n_namespaceObject.__)('Saving', 'carticy-conversions-for-woocommerce') : ''), wp.element.createElement("fieldset", {
    className: "cv-fieldset",
    style: {
      border: 0,
      padding: 0,
      margin: 0,
      minWidth: 0
    }
  }, wp.element.createElement("legend", {
    className: "cv-micro",
    style: {
      padding: 0,
      marginBottom: '10px'
    }
  }, (0,external_wp_i18n_namespaceObject.__)('How Carticy Conversions handles consent', 'carticy-conversions-for-woocommerce')), wp.element.createElement("div", {
    className: "conn-stack"
  }, radio('cmp_driven', (0,external_wp_i18n_namespaceObject.__)('Follow my consent platform', 'carticy-conversions-for-woocommerce')), radio('required', (0,external_wp_i18n_namespaceObject.__)('Consent required, pause until granted', 'carticy-conversions-for-woocommerce')), radio('not_required', (0,external_wp_i18n_namespaceObject.__)('Consent not required', 'carticy-conversions-for-woocommerce'), attestation.attested_at ? (0,external_wp_i18n_namespaceObject.sprintf)(/* translators: %s: attestation date. */
  (0,external_wp_i18n_namespaceObject.__)('Attested by you on %s', 'carticy-conversions-for-woocommerce'), attestation.attested_at) : (0,external_wp_i18n_namespaceObject.__)('Records a dated attestation under your account.', 'carticy-conversions-for-woocommerce')))), !usesConsentSignals ? wp.element.createElement("div", {
    className: "cv-banner cv-banner--info consent-posture-note",
    role: "status"
  }, wp.element.createElement("div", {
    className: "cv-banner__body"
  }, wp.element.createElement("p", {
    className: "cv-banner__desc"
  }, (0,external_wp_i18n_namespaceObject.__)('Consent gates are off for this store. Platform-specific consent controls and extra consent sources are hidden until you choose a consent-required mode.', 'carticy-conversions-for-woocommerce')))) : wp.element.createElement(wp.element.Fragment, null, wp.element.createElement("details", {
    className: "disclose"
  }, wp.element.createElement("summary", {
    className: "disclose__sum"
  }, wp.element.createElement("span", {
    className: "disclose__sum-text"
  }, wp.element.createElement("span", {
    className: "disclose__sum-title"
  }, (0,external_wp_i18n_namespaceObject.__)('Platform consent intake', 'carticy-conversions-for-woocommerce')), wp.element.createElement("span", {
    className: "disclose__sum-hint"
  }, (0,external_wp_i18n_namespaceObject.__)('Optional. Only change this if a platform should ignore consent signals entirely.', 'carticy-conversions-for-woocommerce'))), wp.element.createElement("span", {
    className: "disclose__chev"
  }, wp.element.createElement(IconChevronDown, null))), wp.element.createElement("div", {
    className: "disclose__body"
  }, wp.element.createElement("div", {
    className: "gate-rows"
  }, ['meta', 'google-ads', 'ga4'].map(service => wp.element.createElement("div", {
    className: save.saving ? 'gate-row is-saving' : 'gate-row',
    key: service
  }, wp.element.createElement("div", null, wp.element.createElement("p", {
    className: "gate-row__title"
  }, SERVICE_LABELS[service]), wp.element.createElement("p", {
    className: "gate-row__sub"
  }, 'off' === services[service] ? (0,external_wp_i18n_namespaceObject.__)('Ignores consent signals for this platform.', 'carticy-conversions-for-woocommerce') : SERVICE_GATE_COPY[service]())), wp.element.createElement("label", {
    className: "cv-toggle"
  }, wp.element.createElement("input", {
    type: "checkbox",
    className: "cv-toggle__input",
    checked: 'off' !== services[service],
    onChange: event => setService(service, event.target.checked),
    disabled: save.saving,
    "aria-label": SERVICE_LABELS[service]
  }), wp.element.createElement("span", {
    className: "cv-toggle__track",
    "aria-hidden": "true"
  }, wp.element.createElement("span", {
    className: "cv-toggle__thumb"
  })))))))), wp.element.createElement("details", {
    className: "disclose"
  }, wp.element.createElement("summary", {
    className: "disclose__sum"
  }, wp.element.createElement("span", {
    className: "disclose__sum-text"
  }, wp.element.createElement("span", {
    className: "disclose__sum-title"
  }, (0,external_wp_i18n_namespaceObject.__)('Add another consent source', 'carticy-conversions-for-woocommerce')), wp.element.createElement("span", {
    className: "disclose__sum-hint"
  }, (0,external_wp_i18n_namespaceObject.__)('For a second cookie banner or a custom setup.', 'carticy-conversions-for-woocommerce'))), wp.element.createElement("span", {
    className: "disclose__chev"
  }, wp.element.createElement(IconChevronDown, null))), wp.element.createElement("div", {
    className: "disclose__body"
  }, wp.element.createElement("div", {
    style: {
      display: 'flex',
      flexDirection: 'column',
      gap: '14px',
      paddingTop: '12px'
    }
  }, wp.element.createElement("div", {
    className: "mfield"
  }, wp.element.createElement("label", {
    className: "cv-label",
    htmlFor: "consent-preset"
  }, (0,external_wp_i18n_namespaceObject.__)('Preset', 'carticy-conversions-for-woocommerce')), wp.element.createElement("select", {
    id: "consent-preset",
    className: "cv-select",
    value: config.selected_preset || '',
    onChange: event => post({
      config: {
        ...config,
        selected_preset: event.target.value
      }
    }),
    disabled: save.saving
  }, wp.element.createElement("option", {
    value: ""
  }, (0,external_wp_i18n_namespaceObject.__)('Automatic (all presets active)', 'carticy-conversions-for-woocommerce')), presets.map(preset => wp.element.createElement("option", {
    key: preset.source,
    value: preset.source
  }, preset.source, " (", preset.channel, ")"))), wp.element.createElement("p", {
    className: "cv-help"
  }, (0,external_wp_i18n_namespaceObject.__)('Presets are data-driven cookie and JS-global readers. Automatic works for the supported platforms out of the box.', 'carticy-conversions-for-woocommerce'))), wp.element.createElement("div", null, wp.element.createElement("div", {
    className: "code-row"
  }, wp.element.createElement("span", {
    className: "code-row__code"
  }, SNIPPET), wp.element.createElement("button", {
    type: "button",
    className: "cv-btn cv-btn--secondary cv-btn--sm",
    onClick: copySnippet
  }, copied ? (0,external_wp_i18n_namespaceObject.__)('Copied', 'carticy-conversions-for-woocommerce') : (0,external_wp_i18n_namespaceObject.__)('Copy', 'carticy-conversions-for-woocommerce'))), wp.element.createElement("p", {
    className: "cv-help"
  }, (0,external_wp_i18n_namespaceObject.__)('First-party hook for custom setups.', 'carticy-conversions-for-woocommerce')))))), wp.element.createElement("p", {
    className: "footnote"
  }, (0,external_wp_i18n_namespaceObject.__)('If two sources disagree, a clear "no" always wins.', 'carticy-conversions-for-woocommerce'))));
}
;// ./assets/js/src/admin/screens/settings/PrivacyTab.jsx
/**
 * Settings - Privacy & data: IP anonymization + retention from
 * /settings.privacy (constraints from its schema), and the per-order consent
 * audit - rows seeded from recent events, each expandable to the contributing
 * signal trail from GET /consent/audit/{order}.
 */








const MAX_AUDIT_ROWS = 10;
function decisionCell(state) {
  if ('granted' === state) {
    return wp.element.createElement("span", {
      className: "decision decision--granted"
    }, wp.element.createElement("span", {
      className: "dot dot--green"
    }), (0,external_wp_i18n_namespaceObject.__)('Granted', 'carticy-conversions-for-woocommerce'));
  }
  if ('denied' === state) {
    return wp.element.createElement("span", {
      className: "decision decision--denied"
    }, wp.element.createElement("span", {
      className: "dot dot--muted"
    }), (0,external_wp_i18n_namespaceObject.__)('Denied', 'carticy-conversions-for-woocommerce'));
  }
  return wp.element.createElement("span", {
    className: "decision decision--waiting"
  }, wp.element.createElement("span", {
    className: "dot dot--neutral"
  }), (0,external_wp_i18n_namespaceObject.__)('Waiting', 'carticy-conversions-for-woocommerce'));
}
function AuditRow({
  orderId,
  occurredAt
}) {
  const [expanded, setExpanded] = (0,external_wp_element_namespaceObject.useState)(false);
  const [audit, setAudit] = (0,external_wp_element_namespaceObject.useState)(null);
  const [failed, setFailed] = (0,external_wp_element_namespaceObject.useState)(null);

  // The decision/source render inline for every listed order (the audit
  // list is bounded to MAX_AUDIT_ROWS, so this stays a handful of reads).
  (0,external_wp_element_namespaceObject.useEffect)(() => {
    let mounted = true;
    apiGet(ENDPOINTS.consentAudit(orderId)).then(response => {
      if (mounted) {
        setAudit(response);
      }
    }).catch(error => {
      if (mounted) {
        setFailed(error || {});
      }
    });
    return () => {
      mounted = false;
    };
  }, [orderId]);
  const toggle = () => setExpanded(value => !value);
  const sources = audit && audit.sources || [];
  const decidedIndex = sources.length - 1;
  return wp.element.createElement(wp.element.Fragment, null, wp.element.createElement("tr", null, wp.element.createElement("td", {
    className: "col-order"
  }, wp.element.createElement("button", {
    type: "button",
    className: "expand-caret",
    onClick: toggle,
    "aria-expanded": expanded,
    "aria-label": (0,external_wp_i18n_namespaceObject.sprintf)(/* translators: %d: order number. */
    (0,external_wp_i18n_namespaceObject.__)('Show consent signals for order #%d', 'carticy-conversions-for-woocommerce'), orderId)
  }, wp.element.createElement(IconChevronDown, null)), "#", orderId), wp.element.createElement("td", null, audit ? decisionCell(audit.state) : wp.element.createElement("span", {
    className: "decision decision--waiting"
  }, expanded ? (0,external_wp_i18n_namespaceObject.__)('Fetching', 'carticy-conversions-for-woocommerce') : '-')), wp.element.createElement("td", null, audit && sources.length > 0 ? sources[decidedIndex].source : '-'), wp.element.createElement("td", {
    className: "col-when"
  }, relativeTimeShort(occurredAt))), expanded && wp.element.createElement("tr", {
    className: "audit-subrow"
  }, wp.element.createElement("td", {
    colSpan: 4
  }, wp.element.createElement("div", {
    className: "audit-detail"
  }, failed && (404 === failed.status ? wp.element.createElement("span", {
    className: "audit-detail__line"
  }, (0,external_wp_i18n_namespaceObject.__)('No consent record stored for this order.', 'carticy-conversions-for-woocommerce')) :
  // A failed request is not evidence of an absent record.
  wp.element.createElement("span", {
    className: "audit-detail__line"
  }, (0,external_wp_i18n_namespaceObject.__)("Couldn't load the consent record. Reload the page to try again.", 'carticy-conversions-for-woocommerce'))), !failed && !audit && wp.element.createElement("span", {
    className: "audit-detail__line"
  }, (0,external_wp_i18n_namespaceObject.__)('Fetching consent signals', 'carticy-conversions-for-woocommerce')), audit && 0 === sources.length && wp.element.createElement("span", {
    className: "audit-detail__line"
  }, (0,external_wp_i18n_namespaceObject.__)('No contributing signals were captured.', 'carticy-conversions-for-woocommerce')), audit && sources.map((source, index) => wp.element.createElement("span", {
    className: index === decidedIndex ? 'audit-detail__line is-decided' : 'audit-detail__line',
    key: index
  }, index === decidedIndex ? wp.element.createElement("b", null, source.source, ": ", audit.state, " (", (0,external_wp_i18n_namespaceObject.__)('decided', 'carticy-conversions-for-woocommerce'), ")") : `${source.source} (${source.source_version || ''})`))))));
}
function PrivacyTab() {
  const settings = useResource(ENDPOINTS.settings);
  const recent = useResource(ENDPOINTS.recentEvents);
  const save = useMutation(ENDPOINTS.settings);
  const [pendingPrivacy, setPendingPrivacy] = (0,external_wp_element_namespaceObject.useState)(null);
  const maskedMode = (0,external_wp_element_namespaceObject.useRef)('anonymize');
  if (settings.loading && !settings.data) {
    return wp.element.createElement("div", {
      className: "app-loading",
      role: "status"
    }, (0,external_wp_i18n_namespaceObject.__)('Loading', 'carticy-conversions-for-woocommerce'));
  }
  if (settings.error && !settings.data) {
    return wp.element.createElement(LoadError, {
      error: settings.error,
      onRetry: settings.refetch
    });
  }
  const privacy = pendingPrivacy || settings.data && settings.data.privacy || {};
  const schema = settings.data && settings.data.schema || {};
  const retentionSchema = schema.retentionDays || {
    min: 1,
    max: 3650
  };

  // The toggle collapses anonymize/omit into "masked"; remember which masked
  // mode was stored so toggling off and back on never rewrites `omit` (a
  // valid schema option) to `anonymize`.
  if ('omit' === privacy.ipMode || 'anonymize' === privacy.ipMode) {
    maskedMode.current = privacy.ipMode;
  }
  const saveBody = async body => {
    try {
      if (body.privacy) {
        setPendingPrivacy({
          ...privacy,
          ...body.privacy
        });
      }
      const response = await save.mutate(body);
      settings.setData(response);
    } catch (error) {
      // save.error renders below.
    } finally {
      setPendingPrivacy(null);
    }
  };
  const orders = [];
  const seen = new Set();
  (recent.data && recent.data.events || []).slice().sort((a, b) => a.occurredAt < b.occurredAt ? 1 : -1).forEach(event => {
    if (!seen.has(event.orderId) && orders.length < MAX_AUDIT_ROWS) {
      seen.add(event.orderId);
      orders.push(event);
    }
  });
  return wp.element.createElement(wp.element.Fragment, null, save.error && wp.element.createElement("div", {
    className: "cv-banner cv-banner--critical",
    role: "alert"
  }, wp.element.createElement("div", {
    className: "cv-banner__body"
  }, wp.element.createElement("p", {
    className: "cv-banner__desc"
  }, save.error.message))), wp.element.createElement("span", {
    className: "screen-reader-text",
    role: "status",
    "aria-live": "polite"
  }, save.saving ? (0,external_wp_i18n_namespaceObject.__)('Saving', 'carticy-conversions-for-woocommerce') : ''), wp.element.createElement("div", {
    className: "cv-card",
    style: {
      display: 'flex',
      flexDirection: 'column',
      maxWidth: '640px'
    }
  }, wp.element.createElement("div", {
    className: save.saving ? 'priv-row is-saving' : 'priv-row',
    style: {
      paddingTop: 0
    }
  }, wp.element.createElement("div", null, wp.element.createElement("p", {
    className: "toggle-row__title"
  }, (0,external_wp_i18n_namespaceObject.__)('Anonymize visitor IP addresses', 'carticy-conversions-for-woocommerce')), wp.element.createElement("p", {
    className: "toggle-row__sub"
  }, (0,external_wp_i18n_namespaceObject.__)('Store a masked IP instead of the full address.', 'carticy-conversions-for-woocommerce'))), wp.element.createElement("label", {
    className: "cv-toggle cv-toggle--lg"
  }, wp.element.createElement("input", {
    type: "checkbox",
    className: "cv-toggle__input",
    checked: 'store' !== privacy.ipMode,
    onChange: event => saveBody({
      privacy: {
        ipMode: event.target.checked ? maskedMode.current : 'store'
      }
    }),
    disabled: save.saving,
    "aria-label": (0,external_wp_i18n_namespaceObject.__)('Anonymize visitor IP addresses', 'carticy-conversions-for-woocommerce')
  }), wp.element.createElement("span", {
    className: "cv-toggle__track",
    "aria-hidden": "true"
  }, wp.element.createElement("span", {
    className: "cv-toggle__thumb"
  })))), wp.element.createElement("div", {
    className: "priv-row"
  }, wp.element.createElement("div", null, wp.element.createElement("p", {
    className: "toggle-row__title"
  }, (0,external_wp_i18n_namespaceObject.__)('Delete old tracking data automatically', 'carticy-conversions-for-woocommerce')), wp.element.createElement("p", {
    className: "toggle-row__sub"
  }, (0,external_wp_i18n_namespaceObject.sprintf)(/* translators: %d: retention window in days. */
  (0,external_wp_i18n_namespaceObject.__)('Event and consent records older than %d days are purged automatically.', 'carticy-conversions-for-woocommerce'), privacy.retentionDays))), wp.element.createElement("input", {
    className: "cv-input retention-input",
    type: "number",
    min: retentionSchema.min,
    max: retentionSchema.max,
    defaultValue: privacy.retentionDays,
    disabled: save.saving,
    "aria-label": (0,external_wp_i18n_namespaceObject.__)('Retention window in days', 'carticy-conversions-for-woocommerce'),
    onBlur: event => {
      const days = parseInt(event.target.value, 10);
      if (days > 0 && days !== privacy.retentionDays) {
        saveBody({
          privacy: {
            retentionDays: days
          }
        });
      }
    }
  })), wp.element.createElement("div", {
    className: "priv-row",
    style: {
      paddingBottom: 0
    }
  }, wp.element.createElement("p", {
    className: "toggle-row__sub",
    style: {
      margin: 0
    }
  }, (0,external_wp_i18n_namespaceObject.__)('Customer data export and erasure run through WordPress: Tools, then Export or Erase Personal Data.', 'carticy-conversions-for-woocommerce')))), wp.element.createElement("div", {
    className: "cv-card"
  }, wp.element.createElement("p", {
    className: "cv-micro",
    style: {
      margin: '0 0 14px'
    }
  }, (0,external_wp_i18n_namespaceObject.__)('Consent audit', 'carticy-conversions-for-woocommerce')), recent.loading && !recent.data ? wp.element.createElement("div", {
    className: "app-loading",
    role: "status"
  }, (0,external_wp_i18n_namespaceObject.__)('Loading', 'carticy-conversions-for-woocommerce')) : 0 === orders.length ? wp.element.createElement("p", {
    className: "health-sub",
    style: {
      margin: 0
    }
  }, (0,external_wp_i18n_namespaceObject.__)('No tracked orders yet. Each order keeps a consent record you can audit here.', 'carticy-conversions-for-woocommerce')) : wp.element.createElement("div", {
    className: "table-wrap"
  }, wp.element.createElement("table", {
    className: "consent-table"
  }, wp.element.createElement("thead", null, wp.element.createElement("tr", null, wp.element.createElement("th", {
    scope: "col"
  }, (0,external_wp_i18n_namespaceObject.__)('Order', 'carticy-conversions-for-woocommerce')), wp.element.createElement("th", {
    scope: "col"
  }, (0,external_wp_i18n_namespaceObject.__)('Decision', 'carticy-conversions-for-woocommerce')), wp.element.createElement("th", {
    scope: "col"
  }, (0,external_wp_i18n_namespaceObject.__)('Source', 'carticy-conversions-for-woocommerce')), wp.element.createElement("th", {
    scope: "col"
  }, (0,external_wp_i18n_namespaceObject.__)('Captured', 'carticy-conversions-for-woocommerce')))), wp.element.createElement("tbody", null, orders.map(event => wp.element.createElement(AuditRow, {
    key: event.orderId,
    orderId: event.orderId,
    occurredAt: event.occurredAt
  }))))), wp.element.createElement("p", {
    className: "table-cap"
  }, (0,external_wp_i18n_namespaceObject.__)('Every order keeps a record of which consent signals we saw, and which decision won.', 'carticy-conversions-for-woocommerce'))));
}
;// ./assets/js/src/admin/screens/settings/ServerSideTab.jsx
/**
 * Settings - Server-side.
 *
 * Free build (/server-providers to {available:false}): the honest Pro upsell -
 * feature checklist, the real upgrade URL, and locked field shells with NO
 * inputs. Pro build: the credential form with {set, masked} secrets that are
 * write-only (an empty field preserves the stored secret), plus the guided
 * walkthroughs for generating each credential where the field lives.
 */









function ProUpsell({
  upgradeUrl
}) {
  return wp.element.createElement(wp.element.Fragment, null, wp.element.createElement("div", {
    className: "highlight-card",
    style: {
      display: 'block',
      marginTop: 0,
      maxWidth: '640px'
    }
  }, wp.element.createElement("p", {
    className: "highlight-card__text",
    style: {
      maxWidth: 'none'
    }
  }, COPY.upsellHeadline), wp.element.createElement("div", {
    className: "pro-checklist"
  }, wp.element.createElement("div", {
    className: "pro-check"
  }, wp.element.createElement(IconCheckCircle, null), (0,external_wp_i18n_namespaceObject.__)('Meta Conversions API', 'carticy-conversions-for-woocommerce')), wp.element.createElement("div", {
    className: "pro-check"
  }, wp.element.createElement(IconCheckCircle, null), (0,external_wp_i18n_namespaceObject.__)('GA4 Measurement Protocol', 'carticy-conversions-for-woocommerce')), wp.element.createElement("div", {
    className: "pro-check"
  }, wp.element.createElement(IconCheckCircle, null), (0,external_wp_i18n_namespaceObject.__)("Fires from your server. 0 KB added, can't be blocked by ad blockers, and still respects consent.", 'carticy-conversions-for-woocommerce')), wp.element.createElement("div", {
    className: "pro-check"
  }, wp.element.createElement(IconCheckCircle, null), (0,external_wp_i18n_namespaceObject.__)('Automatic retries with a visible delivery log.', 'carticy-conversions-for-woocommerce'))), wp.element.createElement("a", {
    className: "cv-btn cv-btn--primary",
    href: upgradeUrl,
    target: "_blank",
    rel: "noreferrer noopener"
  }, COPY.upgradeCta)), wp.element.createElement("div", {
    className: "pro-locked-fields",
    style: {
      maxWidth: '640px'
    }
  }, wp.element.createElement("div", {
    className: "pro-field"
  }, wp.element.createElement("span", {
    className: "pro-field__label"
  }, wp.element.createElement(IconLock, null), (0,external_wp_i18n_namespaceObject.__)('Meta CAPI token', 'carticy-conversions-for-woocommerce')), wp.element.createElement("div", {
    className: "pro-field__box"
  }, wp.element.createElement("span", {
    className: "cv-required-tag"
  }, (0,external_wp_i18n_namespaceObject.__)('Unlocks with Pro', 'carticy-conversions-for-woocommerce')))), wp.element.createElement("div", {
    className: "pro-field"
  }, wp.element.createElement("span", {
    className: "pro-field__label"
  }, wp.element.createElement(IconLock, null), (0,external_wp_i18n_namespaceObject.__)('GA4 Measurement Protocol secret', 'carticy-conversions-for-woocommerce')), wp.element.createElement("div", {
    className: "pro-field__box"
  }, wp.element.createElement("span", {
    className: "cv-required-tag"
  }, (0,external_wp_i18n_namespaceObject.__)('Unlocks with Pro', 'carticy-conversions-for-woocommerce'))))));
}
function ProForm({
  providers,
  onSaved
}) {
  const save = useMutation(ENDPOINTS.serverProviders);
  const [saved, setSaved] = (0,external_wp_element_namespaceObject.useState)(false);
  const ga4 = providers.ga4 || {};
  const meta = providers.meta || {};
  const [form, setForm] = (0,external_wp_element_namespaceObject.useState)({
    ga4_enabled: !!ga4.enabled,
    ga4_measurement_id: ga4.measurement_id || '',
    ga4_api_secret: '',
    meta_enabled: !!meta.enabled,
    meta_pixel_id: meta.pixel_id || '',
    meta_access_token: '',
    meta_test_event_code: meta.test_event_code || ''
  });
  (0,external_wp_element_namespaceObject.useEffect)(() => {
    setSaved(false);
  }, [form]);
  const set = key => value => setForm(prev => ({
    ...prev,
    [key]: value
  }));
  const submit = async () => {
    try {
      const response = await save.mutate({
        providers: {
          ga4: {
            enabled: form.ga4_enabled,
            measurement_id: form.ga4_measurement_id.trim(),
            // Write-only: blank means "keep the stored secret".
            api_secret: form.ga4_api_secret.trim()
          },
          meta: {
            enabled: form.meta_enabled,
            pixel_id: form.meta_pixel_id.trim(),
            access_token: form.meta_access_token.trim(),
            test_event_code: form.meta_test_event_code.trim()
          }
        }
      });
      setForm(prev => ({
        ...prev,
        ga4_api_secret: '',
        meta_access_token: ''
      }));
      setSaved(true);
      onSaved(response);
    } catch (error) {
      // save.error renders below.
    }
  };
  const secretPlaceholder = secret => secret && secret.set ? secret.masked || '********' : (0,external_wp_i18n_namespaceObject.__)('Paste the secret', 'carticy-conversions-for-woocommerce');
  return wp.element.createElement("div", {
    className: "cv-card",
    style: {
      maxWidth: '640px'
    }
  }, save.error && wp.element.createElement("div", {
    className: "cv-banner cv-banner--critical",
    role: "alert",
    style: {
      marginBottom: '14px'
    }
  }, wp.element.createElement("div", {
    className: "cv-banner__body"
  }, wp.element.createElement("p", {
    className: "cv-banner__desc"
  }, save.error.message))), saved && wp.element.createElement("div", {
    className: "success-panel",
    style: {
      marginTop: 0,
      marginBottom: '14px'
    }
  }, wp.element.createElement(IconCheckCircle, null), (0,external_wp_i18n_namespaceObject.__)('Saved. Pending server sends retry with the new credentials.', 'carticy-conversions-for-woocommerce')), wp.element.createElement("div", {
    className: "conn-group"
  }, wp.element.createElement("div", {
    className: "conn-group__head"
  }, wp.element.createElement("span", {
    className: "wordmark"
  }, "GA4"), wp.element.createElement("span", {
    className: "conn-group__meta"
  }, (0,external_wp_i18n_namespaceObject.__)('Measurement Protocol', 'carticy-conversions-for-woocommerce')), wp.element.createElement("label", {
    className: "cv-toggle",
    style: {
      marginLeft: 'auto'
    }
  }, wp.element.createElement("input", {
    type: "checkbox",
    className: "cv-toggle__input",
    checked: form.ga4_enabled,
    onChange: event => set('ga4_enabled')(event.target.checked),
    "aria-label": (0,external_wp_i18n_namespaceObject.__)('Enable GA4 Measurement Protocol', 'carticy-conversions-for-woocommerce')
  }), wp.element.createElement("span", {
    className: "cv-toggle__track",
    "aria-hidden": "true"
  }, wp.element.createElement("span", {
    className: "cv-toggle__thumb"
  })))), wp.element.createElement("div", {
    className: "mfields"
  }, wp.element.createElement("div", {
    className: "mfield"
  }, wp.element.createElement("label", {
    className: "cv-label",
    htmlFor: "srv-ga4-id"
  }, (0,external_wp_i18n_namespaceObject.__)('GA4 Measurement ID', 'carticy-conversions-for-woocommerce')), wp.element.createElement("input", {
    id: "srv-ga4-id",
    className: "cv-input",
    type: "text",
    placeholder: "G-XXXXXXXXXX",
    value: form.ga4_measurement_id,
    onChange: event => set('ga4_measurement_id')(event.target.value)
  })), wp.element.createElement("div", {
    className: "mfield"
  }, wp.element.createElement("label", {
    className: "cv-label",
    htmlFor: "srv-ga4-secret"
  }, (0,external_wp_i18n_namespaceObject.__)('API secret', 'carticy-conversions-for-woocommerce')), wp.element.createElement("input", {
    id: "srv-ga4-secret",
    className: "cv-input",
    type: "password",
    autoComplete: "off",
    placeholder: secretPlaceholder(ga4.api_secret),
    value: form.ga4_api_secret,
    onChange: event => set('ga4_api_secret')(event.target.value)
  }), wp.element.createElement("p", {
    className: "cv-help"
  }, (0,external_wp_i18n_namespaceObject.__)('Leave blank to keep the stored secret.', 'carticy-conversions-for-woocommerce')), wp.element.createElement(Walkthrough, {
    guide: GUIDES.ga4_api_secret
  })))), wp.element.createElement("div", {
    className: "conn-group"
  }, wp.element.createElement("div", {
    className: "conn-group__head"
  }, wp.element.createElement("span", {
    className: "wordmark"
  }, "Meta"), wp.element.createElement("span", {
    className: "conn-group__meta"
  }, (0,external_wp_i18n_namespaceObject.__)('Conversions API', 'carticy-conversions-for-woocommerce')), wp.element.createElement("label", {
    className: "cv-toggle",
    style: {
      marginLeft: 'auto'
    }
  }, wp.element.createElement("input", {
    type: "checkbox",
    className: "cv-toggle__input",
    checked: form.meta_enabled,
    onChange: event => set('meta_enabled')(event.target.checked),
    "aria-label": (0,external_wp_i18n_namespaceObject.__)('Enable Meta Conversions API', 'carticy-conversions-for-woocommerce')
  }), wp.element.createElement("span", {
    className: "cv-toggle__track",
    "aria-hidden": "true"
  }, wp.element.createElement("span", {
    className: "cv-toggle__thumb"
  })))), wp.element.createElement("div", {
    className: "mfields"
  }, wp.element.createElement("div", {
    className: "mfield"
  }, wp.element.createElement("label", {
    className: "cv-label",
    htmlFor: "srv-pixel"
  }, (0,external_wp_i18n_namespaceObject.__)('Pixel ID', 'carticy-conversions-for-woocommerce')), wp.element.createElement("input", {
    id: "srv-pixel",
    className: "cv-input",
    type: "text",
    placeholder: (0,external_wp_i18n_namespaceObject.__)('15 to 16 digit ID', 'carticy-conversions-for-woocommerce'),
    value: form.meta_pixel_id,
    onChange: event => set('meta_pixel_id')(event.target.value)
  })), wp.element.createElement("div", {
    className: "mfield"
  }, wp.element.createElement("label", {
    className: "cv-label",
    htmlFor: "srv-token"
  }, (0,external_wp_i18n_namespaceObject.__)('Access token', 'carticy-conversions-for-woocommerce')), wp.element.createElement("input", {
    id: "srv-token",
    className: "cv-input",
    type: "password",
    autoComplete: "off",
    placeholder: secretPlaceholder(meta.access_token),
    value: form.meta_access_token,
    onChange: event => set('meta_access_token')(event.target.value)
  }), wp.element.createElement("p", {
    className: "cv-help"
  }, (0,external_wp_i18n_namespaceObject.__)('Leave blank to keep the stored token.', 'carticy-conversions-for-woocommerce')), wp.element.createElement(Walkthrough, {
    guide: GUIDES.meta_capi_token
  })), wp.element.createElement("div", {
    className: "mfield"
  }, wp.element.createElement("label", {
    className: "cv-label",
    htmlFor: "srv-test-code"
  }, (0,external_wp_i18n_namespaceObject.__)('Test event code (optional)', 'carticy-conversions-for-woocommerce')), wp.element.createElement("input", {
    id: "srv-test-code",
    className: "cv-input",
    type: "text",
    placeholder: "TEST12345",
    value: form.meta_test_event_code,
    onChange: event => set('meta_test_event_code')(event.target.value)
  })))), wp.element.createElement("div", {
    style: {
      marginTop: '18px'
    }
  }, wp.element.createElement("button", {
    type: "button",
    className: "cv-btn cv-btn--primary",
    onClick: submit,
    disabled: save.saving,
    "aria-busy": save.saving ? 'true' : undefined
  }, (0,external_wp_i18n_namespaceObject.__)('Save server settings', 'carticy-conversions-for-woocommerce'))));
}
function ServerSideTab({
  status
}) {
  const providers = useResource(ENDPOINTS.serverProviders);
  if (providers.loading && !providers.data) {
    return wp.element.createElement("div", {
      className: "app-loading",
      role: "status"
    }, (0,external_wp_i18n_namespaceObject.__)('Loading', 'carticy-conversions-for-woocommerce'));
  }

  // A transient failure must never render the Pro upsell with locked fields
  // to a paying Pro customer - say what happened and retry instead.
  if (providers.error && !providers.data) {
    return wp.element.createElement(LoadError, {
      error: providers.error,
      onRetry: providers.refetch
    });
  }
  const data = providers.data || {};
  if (!data.available) {
    const upgradeUrl = status && status.plan && status.plan.upgradeUrl || 'https://carticy.com/plugins/carticy-conversions-for-woocommerce/';
    return wp.element.createElement(ProUpsell, {
      upgradeUrl: upgradeUrl
    });
  }
  return wp.element.createElement(ProForm, {
    providers: data.providers || {},
    onSaved: response => providers.setData(response)
  });
}
;// ./assets/js/src/admin/screens/settings/AdvancedTab.jsx
/**
 * Settings - Advanced. The performance readout (rows 1 and 3 are
 * architectural facts of how the plugin is built; the cache row renders the
 * server's actual cache-plugin detection) plus the debug-logging control:
 * the toggle persists via POST /settings { debugLogging } and the log link
 * goes to WooCommerce's own log viewer (source carticy-conversions).
 */







function AdvancedTab({
  status
}) {
  const cache = status && status.advanced && status.advanced.cachePlugin || {
    detected: false,
    name: ''
  };
  const settings = useResource(ENDPOINTS.settings);
  const save = useMutation(ENDPOINTS.settings);
  const [pendingDebugLogging, setPendingDebugLogging] = (0,external_wp_element_namespaceObject.useState)(null);
  const adminUrl = boot().adminUrl || '';
  const logsUrl = adminUrl ? adminUrl + 'admin.php?page=wc-status&tab=logs' : '';
  const debugLogging = null !== pendingDebugLogging ? pendingDebugLogging : !!(settings.data && settings.data.debugLogging);
  const debugDisabled = save.saving || settings.loading && !settings.data;
  const toggleDebug = async enabled => {
    if (save.saving) {
      return;
    }
    try {
      setPendingDebugLogging(enabled);
      const response = await save.mutate({
        debugLogging: enabled
      });
      settings.setData(response);
    } catch (error) {
      // save.error renders below.
    } finally {
      setPendingDebugLogging(null);
    }
  };
  return wp.element.createElement(wp.element.Fragment, null, save.error && wp.element.createElement("div", {
    className: "cv-banner cv-banner--critical",
    role: "alert"
  }, wp.element.createElement("div", {
    className: "cv-banner__body"
  }, wp.element.createElement("p", {
    className: "cv-banner__desc"
  }, save.error.message))), wp.element.createElement("span", {
    className: "screen-reader-text",
    role: "status",
    "aria-live": "polite"
  }, save.saving ? (0,external_wp_i18n_namespaceObject.__)('Saving', 'carticy-conversions-for-woocommerce') : ''), wp.element.createElement("div", {
    className: "cv-card",
    style: {
      maxWidth: '560px'
    }
  }, wp.element.createElement("p", {
    className: "cv-micro",
    style: {
      margin: '0 0 4px'
    }
  }, (0,external_wp_i18n_namespaceObject.__)('Performance', 'carticy-conversions-for-woocommerce')), wp.element.createElement("p", {
    className: "perf-intro"
  }, (0,external_wp_i18n_namespaceObject.__)("Carticy Conversions is built to stay out of your site's way. Nothing to configure here.", 'carticy-conversions-for-woocommerce')), wp.element.createElement("div", {
    className: "perf-row"
  }, wp.element.createElement(IconCheckCircle, null), (0,external_wp_i18n_namespaceObject.__)('No render-blocking scripts - the storefront script loads deferred.', 'carticy-conversions-for-woocommerce')), wp.element.createElement("div", {
    className: "perf-row"
  }, wp.element.createElement(IconCheckCircle, null), cache.detected ? (0,external_wp_i18n_namespaceObject.sprintf)(/* translators: %s: cache plugin name. */
  (0,external_wp_i18n_namespaceObject.__)('Runs alongside %s - tracking happens on real order events, not cached pages.', 'carticy-conversions-for-woocommerce'), cache.name) : (0,external_wp_i18n_namespaceObject.__)('Cache-friendly - tracking happens on real order events, not cached pages.', 'carticy-conversions-for-woocommerce')), wp.element.createElement("div", {
    className: "perf-row"
  }, wp.element.createElement(IconCheckCircle, null), (0,external_wp_i18n_namespaceObject.__)('Server events add 0 KB to page weight.', 'carticy-conversions-for-woocommerce'))), wp.element.createElement("div", {
    className: "cv-card",
    style: {
      maxWidth: '560px'
    }
  }, settings.error && !settings.data ? wp.element.createElement(LoadError, {
    error: settings.error,
    onRetry: settings.refetch
  }) : wp.element.createElement("div", {
    className: save.saving ? 'priv-row is-saving' : 'priv-row',
    style: {
      paddingTop: 0,
      paddingBottom: 0
    }
  }, wp.element.createElement("div", {
    className: "priv-row__body"
  }, wp.element.createElement("p", {
    className: "toggle-row__title"
  }, (0,external_wp_i18n_namespaceObject.__)('Debug logging', 'carticy-conversions-for-woocommerce')), wp.element.createElement("p", {
    className: "toggle-row__sub"
  }, (0,external_wp_i18n_namespaceObject.__)('Records capture and delivery decisions for troubleshooting. Secrets and customer data are never logged.', 'carticy-conversions-for-woocommerce'), logsUrl && wp.element.createElement(wp.element.Fragment, null, ' ', wp.element.createElement("a", {
    className: "app-link",
    href: logsUrl
  }, (0,external_wp_i18n_namespaceObject.__)('View logs', 'carticy-conversions-for-woocommerce'))))), wp.element.createElement("label", {
    className: "cv-toggle cv-toggle--lg"
  }, wp.element.createElement("input", {
    type: "checkbox",
    className: "cv-toggle__input",
    checked: debugLogging,
    onChange: event => toggleDebug(event.target.checked),
    disabled: debugDisabled,
    "aria-label": (0,external_wp_i18n_namespaceObject.__)('Debug logging', 'carticy-conversions-for-woocommerce')
  }), wp.element.createElement("span", {
    className: "cv-toggle__track",
    "aria-hidden": "true"
  }, wp.element.createElement("span", {
    className: "cv-toggle__thumb"
  }))))));
}
;// ./assets/js/src/admin/screens/settings/Settings.jsx
/**
 * Settings shell: the horizontal tab strip with hash-synced
 * tabs (back button works, notices can deep-link a tab).
 */









const TABS = [{
  id: 'platforms',
  label: () => (0,external_wp_i18n_namespaceObject.__)('Platforms', 'carticy-conversions-for-woocommerce')
}, {
  id: 'delivery',
  label: () => (0,external_wp_i18n_namespaceObject.__)('Delivery', 'carticy-conversions-for-woocommerce')
}, {
  id: 'events',
  label: () => (0,external_wp_i18n_namespaceObject.__)('Events', 'carticy-conversions-for-woocommerce')
}, {
  id: 'consent',
  label: () => (0,external_wp_i18n_namespaceObject.__)('Consent', 'carticy-conversions-for-woocommerce')
}, {
  id: 'privacy',
  label: () => (0,external_wp_i18n_namespaceObject.__)('Privacy & data', 'carticy-conversions-for-woocommerce')
}, {
  id: 'server',
  label: () => (0,external_wp_i18n_namespaceObject.__)('Server-side', 'carticy-conversions-for-woocommerce'),
  lock: true
}, {
  id: 'advanced',
  label: () => (0,external_wp_i18n_namespaceObject.__)('Advanced', 'carticy-conversions-for-woocommerce')
}];
function Settings({
  tab,
  navigate,
  status,
  refreshStatus
}) {
  const active = TABS.some(item => item.id === tab) ? tab : 'platforms';
  const isPremium = !!(status && status.plan && status.plan.isPremium);

  // Complete the ARIA tabs pattern: id/aria-controls linkage plus the
  // arrow-key navigation the role contract implies.
  const onTablistKeyDown = event => {
    if ('ArrowRight' !== event.key && 'ArrowLeft' !== event.key) {
      return;
    }
    event.preventDefault();
    const index = TABS.findIndex(item => item.id === active);
    const next = 'ArrowRight' === event.key ? (index + 1) % TABS.length : (index - 1 + TABS.length) % TABS.length;
    navigate('#settings-' + TABS[next].id);
    const button = document.getElementById('cv-settings-tab-' + TABS[next].id);
    if (button) {
      button.focus();
    }
  };
  return wp.element.createElement("div", {
    className: "settings"
  }, wp.element.createElement("div", {
    className: "cv-tabs",
    role: "tablist",
    "aria-label": (0,external_wp_i18n_namespaceObject.__)('Settings', 'carticy-conversions-for-woocommerce'),
    onKeyDown: onTablistKeyDown
  }, TABS.map(item => wp.element.createElement("button", {
    key: item.id,
    type: "button",
    role: "tab",
    id: 'cv-settings-tab-' + item.id,
    "aria-selected": active === item.id,
    "aria-controls": "cv-settings-panel",
    tabIndex: active === item.id ? 0 : -1,
    className: active === item.id ? 'cv-tabs__tab is-active' : 'cv-tabs__tab',
    onClick: () => navigate('#settings-' + item.id)
  }, item.label(), " ", item.lock && !isPremium && wp.element.createElement(IconLock, null)))), wp.element.createElement("div", {
    className: "settings__panel",
    id: "cv-settings-panel",
    role: "tabpanel",
    "aria-labelledby": 'cv-settings-tab-' + active
  }, 'platforms' === active && wp.element.createElement(PlatformsTab, {
    status: status
  }), 'delivery' === active && wp.element.createElement(DeliveryTab, null), 'events' === active && wp.element.createElement(EventsTab, null), 'consent' === active && wp.element.createElement(ConsentTab, null), 'privacy' === active && wp.element.createElement(PrivacyTab, null), 'server' === active && wp.element.createElement(ServerSideTab, {
    status: status,
    refreshStatus: refreshStatus
  }), 'advanced' === active && wp.element.createElement(AdvancedTab, {
    status: status
  })));
}
;// ./assets/js/src/admin/App.jsx
/**
 * App root. Boot order: GET /onboarding decides onboarding-vs-app (the server
 * owns the position - `current !== 'complete'` renders the wizard); the
 * running app then boots from GET /status, the single composed Home contract.
 */











function MainApp() {
  const status = useResource(ENDPOINTS.status);
  const {
    route,
    navigate
  } = useHashRoute();
  const topbarTabs = [{
    id: 'status',
    label: (0,external_wp_i18n_namespaceObject.__)('Status', 'carticy-conversions-for-woocommerce'),
    active: 'settings' !== route.page,
    onClick: () => navigate('#home')
  }, {
    id: 'settings',
    label: (0,external_wp_i18n_namespaceObject.__)('Settings', 'carticy-conversions-for-woocommerce'),
    active: 'settings' === route.page,
    onClick: () => navigate('#settings-platforms')
  }];
  if (status.loading && !status.data) {
    return wp.element.createElement(wp.element.Fragment, null, wp.element.createElement(Topbar, {
      isPremium: null
    }), wp.element.createElement("div", {
      className: "canvas canvas--app"
    }, wp.element.createElement("div", {
      className: "app-loading app-loading--screen",
      role: "status"
    }, (0,external_wp_i18n_namespaceObject.__)('Loading', 'carticy-conversions-for-woocommerce'))));
  }
  if (status.error && !status.data) {
    return wp.element.createElement(wp.element.Fragment, null, wp.element.createElement(Topbar, {
      isPremium: null
    }), wp.element.createElement("div", {
      className: "canvas canvas--app"
    }, wp.element.createElement("div", {
      className: "app"
    }, wp.element.createElement("div", {
      className: "cv-banner cv-banner--critical",
      role: "alert"
    }, wp.element.createElement("div", {
      className: "cv-banner__body"
    }, wp.element.createElement("p", {
      className: "cv-banner__desc"
    }, status.error.message), wp.element.createElement("button", {
      type: "button",
      className: "cv-btn cv-btn--secondary cv-btn--sm",
      onClick: () => status.refetch(),
      style: {
        marginTop: '12px'
      }
    }, (0,external_wp_i18n_namespaceObject.__)('Retry', 'carticy-conversions-for-woocommerce')))))));
  }
  const data = status.data || {};
  const isPremium = !!(data.plan && data.plan.isPremium);
  let screen = null;
  if ('settings' === route.page) {
    screen = wp.element.createElement(Settings, {
      tab: route.tab,
      navigate: navigate,
      status: data,
      refreshStatus: status.refetch
    });
  } else if ('accuracy' === route.view) {
    screen = wp.element.createElement(Accuracy, {
      navigate: navigate
    });
  } else if ('events' === route.view) {
    screen = wp.element.createElement(RecentEvents, {
      navigate: navigate
    });
  } else {
    screen = wp.element.createElement(Home, {
      status: data,
      refreshStatus: status.refetch,
      navigate: navigate
    });
  }
  return wp.element.createElement(wp.element.Fragment, null, wp.element.createElement(Topbar, {
    isPremium: isPremium,
    tabs: topbarTabs
  }), wp.element.createElement("div", {
    className: "canvas canvas--app"
  }, screen));
}
function App() {
  const onboarding = useResource(ENDPOINTS.onboarding);
  const [completedNow, setCompletedNow] = (0,external_wp_element_namespaceObject.useState)(false);
  if (onboarding.loading && !onboarding.data) {
    return wp.element.createElement(wp.element.Fragment, null, wp.element.createElement(Topbar, {
      isPremium: null
    }), wp.element.createElement("div", {
      className: "canvas canvas--app"
    }, wp.element.createElement("div", {
      className: "app-loading app-loading--screen",
      role: "status"
    }, (0,external_wp_i18n_namespaceObject.__)('Loading', 'carticy-conversions-for-woocommerce'))));
  }
  if (onboarding.error && !onboarding.data) {
    return wp.element.createElement(wp.element.Fragment, null, wp.element.createElement(Topbar, {
      isPremium: null
    }), wp.element.createElement("div", {
      className: "canvas canvas--center"
    }, wp.element.createElement("div", {
      className: "cv-card cv-card--lg wiz"
    }, wp.element.createElement("div", {
      className: "cv-banner cv-banner--critical",
      role: "alert"
    }, wp.element.createElement("div", {
      className: "cv-banner__body"
    }, wp.element.createElement("p", {
      className: "cv-banner__desc"
    }, onboarding.error.message))), wp.element.createElement("div", {
      style: {
        marginTop: '16px'
      }
    }, wp.element.createElement("button", {
      type: "button",
      className: "cv-btn cv-btn--secondary",
      onClick: () => onboarding.refetch()
    }, (0,external_wp_i18n_namespaceObject.__)('Retry', 'carticy-conversions-for-woocommerce'))))));
  }
  const current = onboarding.data && onboarding.data.current || 'platforms';
  if ('complete' !== current && !completedNow) {
    return wp.element.createElement(wp.element.Fragment, null, wp.element.createElement(Topbar, {
      isPremium: null
    }), wp.element.createElement(OnboardingApp, {
      onComplete: () => setCompletedNow(true)
    }));
  }
  return wp.element.createElement(MainApp, null);
}
;// ./assets/js/src/admin/index.jsx
/**
 * Bundle entry: mark the mount as the design-system root (cv-root scoping
 * doctrine) plus the full-page takeover modifier, then render the app.
 */



const admin_boot = window.carticyConversionsAdmin || {};
const admin_element = document.getElementById(admin_boot.mountId || 'carticy-conversions-admin-root');
if (admin_element) {
  adminUiRoot(admin_element, {
    page: 'carticy-conversions'
  });
  admin_element.classList.add('cv-root--app');
  if (typeof external_wp_element_namespaceObject.createRoot === 'function') {
    (0,external_wp_element_namespaceObject.createRoot)(admin_element).render(wp.element.createElement(App, null));
  } else {
    (0,external_wp_element_namespaceObject.render)(wp.element.createElement(App, null), admin_element);
  }
}
/******/ })()
;