/**
 * AgentForms Embed SDK
 * @version 2.0.0
 * @license MIT
 *
 * Usage:
 *   <script src="https://agentforms.io/embed.js"></script>
 *   <div id="my-form"></div>
 *   <script>
 *     AF.render('my-form', {
 *       token: 'abc123',
 *       theme: 'light',
 *       successMessage: "Thanks! We'll be in touch.",
 *       onSubmit: function(data) { /* analytics hook */ }
 *     });
 *   </script>
 */
(function (window, document) {
  "use strict";

  var BASE = location.protocol + "//" + location.host;

  var DEFAULTS = {
    token: "",
    theme: "light",
    successMessage: "Thank you! Your submission was received.",
    errorMessage: "Something went wrong. Please try again.",
    submitLabel: "Submit",
    nextLabel: "Next",
    prevLabel: "Back",
    stepLabel: "Step {current} of {total}",
    colors: {},
    onSubmit: null,
    onError: null,
  };

  var THEMES = {
    light: {
      bg: "#ffffff",
      text: "#333333",
      label: "#555555",
      inputBg: "#ffffff",
      inputBorder: "#cccccc",
      inputText: "#333333",
      primary: "#1a1a2e",
      primaryText: "#ffffff",
      error: "#dc3545",
      errorBg: "#f8d7da",
      success: "#155724",
      successBg: "#d4edda",
      placeholder: "#999999",
    },
    dark: {
      bg: "#1a1a2e",
      text: "#e0e0e0",
      label: "#cccccc",
      inputBg: "#2d2d44",
      inputBorder: "#444466",
      inputText: "#e0e0e0",
      primary: "#4a9eff",
      primaryText: "#ffffff",
      error: "#ff6b6b",
      errorBg: "#3d2020",
      success: "#51cf66",
      successBg: "#1d3d20",
      placeholder: "#777777",
    },
    transparent: {
      bg: "transparent",
      text: "#333333",
      label: "#555555",
      inputBg: "rgba(255,255,255,0.9)",
      inputBorder: "#cccccc",
      inputText: "#333333",
      primary: "#1a1a2e",
      primaryText: "#ffffff",
      error: "#dc3545",
      errorBg: "rgba(248,215,218,0.8)",
      success: "#155724",
      successBg: "rgba(212,237,218,0.8)",
      placeholder: "#999999",
    },
  };

  var instances = {};

  function deepMerge(base, override) {
    var result = {};
    for (var key in base) {
      if (base.hasOwnProperty(key)) {
        result[key] = base[key];
      }
    }
    for (var key in override) {
      if (override.hasOwnProperty(key)) {
        result[key] = override[key];
      }
    }
    return result;
  }

  function escapeHtml(str) {
    var div = document.createElement("div");
    div.appendChild(document.createTextNode(str));
    return div.innerHTML;
  }

  function generateId() {
    return "af_" + Math.random().toString(36).substr(2, 9);
  }

  // Track impression via sendBeacon
  function trackImpression(token) {
    if (!token || typeof navigator.sendBeacon !== "function") return;
    var data = JSON.stringify({
      token: token,
      event: "impression",
      timestamp: Date.now(),
      referrer: document.referrer || "",
    });
    navigator.sendBeacon(BASE + "/api/beacon", data);
  }

  // Fetch field config
  function fetchConfig(token, callback) {
    var xhr = new XMLHttpRequest();
    xhr.open("GET", BASE + "/api/v2/forms/" + token + "/config", true);
    xhr.timeout = 10000;
    xhr.onreadystatechange = function () {
      if (xhr.readyState === 4) {
        if (xhr.status === 200) {
          try {
            callback(null, JSON.parse(xhr.responseText));
          } catch (e) {
            callback(new Error("Invalid response from server"));
          }
        } else {
          callback(new Error("Failed to load form (" + xhr.status + ")"));
        }
      }
    };
    xhr.onerror = function () {
      callback(new Error("Network error"));
    };
    xhr.ontimeout = function () {
      callback(new Error("Request timed out"));
    };
    xhr.send();
  }

  // ─── Session Tracking (Phase 10) ───────────────────────────────────────────

  var _sessionState = {};

  function getSessionId() {
    try {
      var existing = localStorage.getItem("af_session_id");
      if (existing) return existing;
    } catch (e) {}
    var id = 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) {
      var r = Math.random() * 16 | 0;
      return (c === 'x' ? r : (r & 0x3 | 0x8)).toString(16);
    });
    try { localStorage.setItem("af_session_id", id); } catch (e) {}
    return id;
  }

  function getVisitorId(token) {
    var key = "af_visitor_" + token;
    try {
      var existing = localStorage.getItem(key);
      if (existing) return existing;
    } catch (e) {}
    var id = 'visitor_' + Date.now().toString(36) + '_' + Math.random().toString(36).substr(2, 8);
    try { localStorage.setItem(key, id); } catch (e) {}
    return id;
  }

  function initSessionTracking(token, variantKey) {
    _sessionState = {
      token: token,
      sessionId: getSessionId(),
      visitorId: getVisitorId(token),
      fieldsViewed: [],
      lastFieldReached: "",
      stepReached: 0,
      startTime: Date.now(),
      variantKey: variantKey || null,
      tracking: true,
      debounceTimer: null,
    };
    // Fire session_start
    sendSessionEvent("session_start");
  }

  function sendSessionEvent(event, data) {
    if (!_sessionState || !_sessionState.tracking) return;
    var payload = {
      token: _sessionState.token,
      session_id: _sessionState.sessionId,
      visitor_id: _sessionState.visitorId,
      event: event,
      fields_viewed: _sessionState.fieldsViewed.slice(),
      last_field_reached: _sessionState.lastFieldReached,
      step_reached: _sessionState.stepReached,
      referrer: document.referrer || "",
      timestamp: Date.now(),
    };
    // Include variant info in metadata
    if (_sessionState.variantKey) {
      payload.variant_key = _sessionState.variantKey;
    }
    if (data) {
      for (var k in data) {
        if (data.hasOwnProperty(k)) payload[k] = data[k];
      }
    }
    try {
      navigator.sendBeacon(BASE + "/api/sessions", JSON.stringify(payload));
    } catch (e) {}
  }

  function trackFieldInteraction(fieldKey) {
    if (!_sessionState || !_sessionState.tracking || !fieldKey) return;
    // Track if not already seen
    if (_sessionState.fieldsViewed.indexOf(fieldKey) === -1) {
      _sessionState.fieldsViewed.push(fieldKey);
    }
    // Update last field reached
    _sessionState.lastFieldReached = fieldKey;
    // Debounced update (fire after 2s of no activity)
    if (_sessionState.debounceTimer) clearTimeout(_sessionState.debounceTimer);
    _sessionState.debounceTimer = setTimeout(function () {
      sendSessionEvent("session_update");
      _sessionState.debounceTimer = null;
    }, 2000);
  }

  function trackStepChange(stepIndex) {
    if (!_sessionState) return;
    _sessionState.stepReached = stepIndex + 1;
  }

  function completeSession() {
    if (!_sessionState) return;
    sendSessionEvent("session_complete");
    _sessionState.tracking = false;
    if (_sessionState.debounceTimer) clearTimeout(_sessionState.debounceTimer);
    // Clear session ID so next visit starts fresh
    try { localStorage.removeItem("af_session_id"); } catch (e) {}
  }

  // ─── A/B Testing (Phase 10.9) ───────────────────────────────────────────

  function fetchVariant(token, visitorId, callback) {
    var xhr = new XMLHttpRequest();
    xhr.open("GET", BASE + "/api/v1/variants?token=" + encodeURIComponent(token) + "&visitor_id=" + encodeURIComponent(visitorId), true);
    xhr.timeout = 5000;
    xhr.onreadystatechange = function () {
      if (xhr.readyState === 4) {
        if (xhr.status === 200) {
          try {
            var resp = JSON.parse(xhr.responseText);
            callback(null, resp);
          } catch (e) {
            callback(new Error("Invalid variant response"));
          }
        } else {
          callback(null, { has_active_test: false, assigned_variant: null });
        }
      }
    };
    xhr.onerror = function () {
      callback(null, { has_active_test: false, assigned_variant: null });
    };
    xhr.ontimeout = function () {
      callback(null, { has_active_test: false, assigned_variant: null });
    };
    xhr.send();
  }

  // ─── Field Rendering ───────────────────────────────────────────────────────

  function renderField(field, formId) {
    var wrapper = document.createElement("div");
    wrapper.className = "af-field";
    wrapper.setAttribute("data-af-field", field.key || field.name);

    var fieldId = formId + "_" + (field.key || field.name);

    // Label
    var label = document.createElement("label");
    label.className = "af-label";
    label.setAttribute("for", fieldId);
    label.textContent = field.label || field.key || field.name;
    if (field.required) {
      var req = document.createElement("span");
      req.className = "af-required";
      req.textContent = " *";
      label.appendChild(req);
    }
    wrapper.appendChild(label);

    // Input element based on type
    var input = null;
    var type = field.type || "text";

    switch (type) {
      case "textarea":
        input = document.createElement("textarea");
        input.rows = 4;
        break;
      case "select":
        input = document.createElement("select");
        if (field.options && field.options.length > 0) {
          var defaultOpt = document.createElement("option");
          defaultOpt.value = "";
          defaultOpt.textContent = field.placeholder || "Select...";
          input.appendChild(defaultOpt);
          for (var i = 0; i < field.options.length; i++) {
            var opt = document.createElement("option");
            opt.value = field.options[i];
            opt.textContent = field.options[i];
            input.appendChild(opt);
          }
        }
        break;
      case "checkbox":
        input = document.createElement("input");
        input.type = "checkbox";
        input.value = "1";
        break;
      case "radio":
        var radioGroup = document.createElement("div");
        radioGroup.className = "af-radio-group";
        if (field.options && field.options.length > 0) {
          for (var j = 0; j < field.options.length; j++) {
            var radioWrapper = document.createElement("label");
            radioWrapper.className = "af-radio-label";
            var radio = document.createElement("input");
            radio.type = "radio";
            radio.name = field.key || field.name;
            radio.value = field.options[j];
            radio.id = fieldId + "_" + j;
            var radioSpan = document.createElement("span");
            radioSpan.textContent = field.options[j];
            radioWrapper.appendChild(radio);
            radioWrapper.appendChild(radioSpan);
            radioGroup.appendChild(radioWrapper);
          }
        }
        wrapper.appendChild(radioGroup);
        input = document.createElement("span");
        input.style.display = "none";
        input.className = "af-input";
        input.id = fieldId;
        input.setAttribute("name", field.key || field.name);
        wrapper.appendChild(input);
        return wrapper;
      case "number":
        input = document.createElement("input");
        input.type = "number";
        input.step = "any";
        break;
      case "email":
        input = document.createElement("input");
        input.type = "email";
        break;
      case "phone":
        input = document.createElement("input");
        input.type = "tel";
        break;
      case "file":
        input = document.createElement("input");
        input.type = "file";
        break;
      default:
        input = document.createElement("input");
        input.type = "text";
    }

    input.className = "af-input";
    input.id = fieldId;
    input.setAttribute("name", field.key || field.name);
    if (field.placeholder) {
      input.placeholder = field.placeholder;
    }
    if (field.required) {
      input.setAttribute("required", "required");
    }
    if (field.min) input.setAttribute("min", field.min);
    if (field.max) input.setAttribute("max", field.max);
    if (field.minLength) input.setAttribute("minlength", field.minLength);
    if (field.maxLength) input.setAttribute("maxlength", field.maxLength);

    // Session tracking: track field interaction
    var fieldKey = field.key || field.name;
    input.addEventListener("focus", function () { trackFieldInteraction(fieldKey); }, { once: true });
    input.addEventListener("change", function () { trackFieldInteraction(fieldKey); });

    wrapper.appendChild(input);
    return wrapper;
  }

  // ─── Conditional field rendering ──────────────────────────────────────────

  function _evaluateSingleCondition(condition, formData) {
    if (!condition || !condition.field || !condition.operator) return true;
    var targetValue = formData[condition.field] || "";
    targetValue = String(targetValue).trim();

    // Boolean operators
    if (condition.operator === "filled") return targetValue !== "";
    if (condition.operator === "empty") return targetValue === "";

    var compareValue = String(condition.value || "").trim();

    // Numeric comparisons
    if (["gt", "lt", "gte", "lte"].indexOf(condition.operator) !== -1) {
      var t = parseFloat(targetValue);
      var c = parseFloat(compareValue);
      if (isNaN(t) || isNaN(c)) return false;
      if (condition.operator === "gt") return t > c;
      if (condition.operator === "lt") return t < c;
      if (condition.operator === "gte") return t >= c;
      if (condition.operator === "lte") return t <= c;
    }

    // String comparisons
    if (condition.operator === "eq") return targetValue === compareValue;
    if (condition.operator === "neq") return targetValue !== compareValue;
    if (condition.operator === "contains") return targetValue.indexOf(compareValue) !== -1;
    if (condition.operator === "not_contains") return targetValue.indexOf(compareValue) === -1;

    // Set membership
    if (condition.operator === "in") {
      var values = compareValue.split(",").map(function(v){ return v.trim(); });
      return values.indexOf(targetValue) !== -1;
    }
    if (condition.operator === "not_in") {
      var values2 = compareValue.split(",").map(function(v){ return v.trim(); });
      return values2.indexOf(targetValue) === -1;
    }

    return true; // Unknown operator = visible (fail open)
  }

  // ─── Compute field value from config (Phase 3) ────────────────────────────

  function _computeFieldValue(fieldDef, formData) {
    // Method 1: calculation.formula (legacy)
    var calc = fieldDef && fieldDef.calculation;
    if (calc && calc.formula) {
      var formula = calc.formula;
      var keys = calc.keys || [];
      var result = formula;
      for (var k = 0; k < keys.length; k++) {
        var key = keys[k];
        var val = formData[key] || "";
        result = result.replace(new RegExp('\\{' + key + '\\}', 'g'), val);
      }
      // Try to parse as number
      var num = parseFloat(result);
      return isNaN(num) ? result : num;
    }

    // Method 2: computed_method: 'map'
    if (fieldDef && fieldDef.computed_method === 'map') {
      var source = fieldDef.computed_from || "";
      var mapping = fieldDef.computed_map || {};
      var sourceValue = String(formData[source] || "").trim();
      return mapping[sourceValue] !== undefined ? mapping[sourceValue] : (fieldDef.default || "");
    }

    // Method 3: computed_method: 'expression'
    if (fieldDef && fieldDef.computed_method === 'expression') {
      try {
        var expr = fieldDef.computed_expression || "";
        // Replace {key} with values (numeric coercion)
        var safeExpr = expr;
        var fieldKeys = fieldDef.computed_from || [];
        if (!Array.isArray(fieldKeys)) fieldKeys = [fieldKeys];
        for (var fk = 0; fk < fieldKeys.length; fk++) {
          var kv = fieldKeys[fk];
          var rawVal = formData[kv];
          var numVal = parseFloat(rawVal);
          safeExpr = safeExpr.replace(new RegExp('\\{' + kv + '\\}', 'g'), isNaN(numVal) ? 0 : numVal);
        }
        // Safety: only allow math operators, parentheses, whitespace, dots, minus
        if (/^[\d\s\+\-\*\/\(\)\.,]+$/.test(safeExpr)) {
          var evalResult = Function('"use strict"; return (' + safeExpr + ')')();
          return evalResult;
        }
      } catch (e) { /* silent fail */ }
      return fieldDef.default || "";
    }

    return formData[fieldDef.key] || fieldDef.default || "";
  }

  function _extractComputedFields(fieldDef) {
    var refs = [];
    var calc = fieldDef.calculation;
    if (calc && calc.keys) {
      for (var i = 0; i < calc.keys.length; i++) {
        refs.push(calc.keys[i]);
      }
      return refs;
    }
    if (fieldDef.computed_method === 'map' && fieldDef.computed_from) {
      refs.push(fieldDef.computed_from);
    }
    if (fieldDef.computed_method === 'expression') {
      var expr = fieldDef.computed_expression || "";
      var match;
      var re = /\{(\w+)\}/g;
      while ((match = re.exec(expr)) !== null) {
        refs.push(match[1]);
      }
    }
    return refs;
  }

  function _applyComputedFields(form, formData, fieldConfig) {
    var fields = fieldConfig.fields || [];
    for (var i = 0; i < fields.length; i++) {
      var field = fields[i];
      var isComputed = field.calculation || field.computed_method;
      if (!isComputed) continue;

      var key = field.key || field.name;
      var wrapper = form.querySelector('[data-af-field="' + key + '"]');
      if (!wrapper) continue;

      var inputs = wrapper.querySelectorAll('input[name="' + key + '"], textarea[name="' + key + '"], select[name="' + key + '"]');
      if (inputs.length === 0) continue;

      var computedValue = _computeFieldValue(field, formData);
      inputs[0].value = computedValue !== undefined ? computedValue : "";
      inputs[0].setAttribute('readonly', 'readonly');
      inputs[0].style.backgroundColor = '#f0f0f0';
    }
  }

  function evaluateCondition(condition, formData) {
    if (!condition) return true;

    // AND group — all sub-conditions must be true
    if (condition.all && condition.all.length > 0) {
      for (var i = 0; i < condition.all.length; i++) {
        if (!evaluateCondition(condition.all[i], formData)) return false;
      }
      return true;
    }

    // OR group — at least one sub-condition must be true
    if (condition.any && condition.any.length > 0) {
      for (var j = 0; j < condition.any.length; j++) {
        if (evaluateCondition(condition.any[j], formData)) return true;
      }
      return false;
    }

    // Legacy single condition
    return _evaluateSingleCondition(condition, formData);
  }

  // ─── Client-side validation (real-time feedback) ────────────────────────

  function validateField(field, form, theme) {
    var errors = [];
    var key = field.key || field.name;
    var wrapper = form.querySelector('[data-af-field="' + key + '"]');
    if (!wrapper) return errors;

    // Check if field is hidden by condition
    if (wrapper.style.display === "none") return errors;

    // Get input element(s)
    var inputs = wrapper.querySelectorAll('input[name="' + key + '"], textarea[name="' + key + '"], select[name="' + key + '"]');
    if (inputs.length === 0) return errors;

    var value = "";
    if (field.type === "radio") {
      var checked = form.querySelector('input[name="' + key + '"]:checked');
      value = checked ? checked.value : "";
    } else if (field.type === "checkbox") {
      value = inputs[0].checked ? "1" : "";
    } else {
      value = inputs[0].value || "";
    }

    // Required check
    if (field.required && !value) {
      errors.push(field.errorMessage || (field.label || key) + " is required.");
      return errors;
    }

    if (!value) return errors; // Skip other checks on empty non-required

    var validation = field.validation || {};
    var vtype = validation.type || field.type || "";

    // Pattern check (regex)
    var pattern = validation.pattern || field.pattern || "";
    if (pattern) {
      try {
        if (!new RegExp(pattern).test(value)) {
          errors.push(validation.patternMessage || "Please enter a valid value.");
        }
      } catch (e) { /* skip invalid regex */ }
    }

    // Built-in email validation
    if (vtype === "email" || field.type === "email") {
      if (!/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(value)) {
        if (errors.length === 0) {
          errors.push(validation.message || "Please enter a valid email address.");
        }
      }
    }

    // Min/max for numbers
    if (field.type === "number" || vtype === "number") {
      var num = parseFloat(value);
      if (!isNaN(num)) {
        if (validation.min !== undefined && num < parseFloat(validation.min)) {
          errors.push(validation.minMessage || "Value must be at least " + validation.min + ".");
        }
        if (validation.max !== undefined && num > parseFloat(validation.max)) {
          errors.push(validation.maxMessage || "Value must be at most " + validation.max + ".");
        }
      }
    }

    // Min/max length for text
    if (validation.minLength !== undefined && value.length < parseInt(validation.minLength)) {
      errors.push(validation.minLengthMessage || "Please enter at least " + validation.minLength + " characters.");
    }
    if (validation.maxLength !== undefined && value.length > parseInt(validation.maxLength)) {
      errors.push(validation.maxLengthMessage || "Please enter no more than " + validation.maxLength + " characters.");
    }

    return errors;
  }

  function showFieldError(wrapper, message, theme) {
    // Clear previous
    var prev = wrapper.querySelector(".af-field-error");
    if (prev) prev.remove();

    var err = document.createElement("div");
    err.className = "af-field-error";
    err.style.cssText = "color:" + theme.error + ";font-size:12px;margin-top:4px;";
    err.textContent = message;
    wrapper.appendChild(err);

    // Highlight input
    var inp = wrapper.querySelector(".af-input");
    if (inp) {
      inp.setAttribute("data-af-error", "true");
      inp.style.borderColor = theme.error;
    }
  }

  function clearFieldError(wrapper, inp) {
    var prev = wrapper.querySelector(".af-field-error");
    if (prev) prev.remove();
    if (inp) {
      inp.removeAttribute("data-af-error");
      inp.style.borderColor = "";
    }
  }

  function wireRealTimeValidation(form, fieldConfig, theme) {
    var fields = fieldConfig.fields || [];
    var steps = fieldConfig.steps;
    if (steps) {
      var stepKeys = Object.keys(steps);
      for (var sk = 0; sk < stepKeys.length; sk++) {
        fields = fields.concat(steps[stepKeys[sk]]);
      }
    }

    for (var i = 0; i < fields.length; i++) {
      (function(fieldDef) {
        var wrapper = form.querySelector('[data-af-field="' + (fieldDef.key || fieldDef.name) + '"]');
        if (!wrapper) return;

        var inputs = wrapper.querySelectorAll("input, textarea, select");
        var events = fieldDef.type === "radio" ? ["change"] : ["blur", "input"];

        for (var e = 0; e < events.length; e++) {
          (function(evt, fDef, w, inpEls) {
            wrapper.addEventListener(evt, function() {
              var errs = validateField(fDef, form, theme);
              if (errs.length > 0) {
                showFieldError(w, errs[0], theme);
              } else {
                for (var ii = 0; ii < inpEls.length; ii++) {
                  clearFieldError(w, inpEls[ii]);
                }
              }
            });
          })(events[e], fieldDef, wrapper, inputs);
        }
      })(fields[i]);
    }
  }

  function getFormData(form) {
    var data = {};
    var inputs = form.querySelectorAll("input, select, textarea");
    for (var i = 0; i < inputs.length; i++) {
      var el = inputs[i];
      if (el.name && el.type !== "submit" && el.type !== "button" && el.id.indexOf("af_") !== 0) {
        if (el.type === "checkbox" || el.type === "radio") {
          if (el.checked) data[el.name] = el.value;
        } else {
          data[el.name] = el.value;
        }
      }
    }
    return data;
  }

  // Extract all field names referenced by a condition (recursive for groups)
  function _extractConditionFields(condition) {
    if (!condition) return [];
    var refs = [];
    if (condition.field) {
      refs.push(condition.field);
    }
    if (condition.all) {
      for (var i = 0; i < condition.all.length; i++) {
        refs = refs.concat(_extractConditionFields(condition.all[i]));
      }
    }
    if (condition.any) {
      for (var j = 0; j < condition.any.length; j++) {
        refs = refs.concat(_extractConditionFields(condition.any[j]));
      }
    }
    return refs;
  }

  function _getConditionalState(fieldDef, formData, visibleFields) {
    var key = fieldDef.key || fieldDef.name;
    var state = {
      visible: true,
      required: !!fieldDef.required,
      default: fieldDef.default || "",
      validationOverrides: {},
    };

    // Visibility
    if (fieldDef.condition) {
      state.visible = evaluateCondition(fieldDef.condition, formData);
    }

    // Cascade: if any referenced field is hidden, this field is hidden
    if (state.visible) {
      var refs = _extractConditionFields(fieldDef.condition);
      for (var r = 0; r < refs.length; r++) {
        if (!visibleFields[refs[r]]) {
          state.visible = false;
          break;
        }
      }
    }

    // Conditional required
    if (fieldDef.conditional_required) {
      if (_evaluateSingleCondition(fieldDef.conditional_required, formData)) {
        state.required = true;
      }
    }

    // Conditional default
    if (fieldDef.conditional_default && fieldDef.conditional_default.condition) {
      if (_evaluateSingleCondition(fieldDef.conditional_default.condition, formData)) {
        state.default = fieldDef.conditional_default.value || "";
      }
    }

    // Conditional validation
    if (fieldDef.conditional_validation) {
      for (var v = 0; v < fieldDef.conditional_validation.length; v++) {
        var cv = fieldDef.conditional_validation[v];
        if (cv.condition && _evaluateSingleCondition(cv.condition, formData)) {
          state.validationOverrides = {};
          var overrideKeys = ["pattern", "errorMessage", "minLength", "maxLength", "min", "max"];
          for (var k = 0; k < overrideKeys.length; k++) {
            if (cv[overrideKeys[k]] !== undefined) {
              state.validationOverrides[overrideKeys[k]] = cv[overrideKeys[k]];
            }
          }
          break; // First matching rule wins
        }
      }
    }

    return state;
  }

  function _evaluateAllClientConditions(form, fields) {
    var formData = getFormData(form);
    var states = {};
    var visibleFields = {};

    for (var iter = 0; iter < 3; iter++) {
      var newStates = {};
      for (var i = 0; i < fields.length; i++) {
        var key = fields[i].key || fields[i].name;
        newStates[key] = _getConditionalState(fields[i], formData, visibleFields);
      }

      // Check if stable
      var stable = true;
      for (var k in newStates) {
        if (newStates[k].visible !== states[k].visible) {
          stable = false;
          break;
        }
      }
      if (stable && Object.keys(states).length > 0) break;

      states = newStates;
      for (var fk in states) {
        visibleFields[fk] = states[fk].visible;
      }
    }

    return states;
  }

  function updateFieldVisibility(form, fieldConfig) {
    var fields = fieldConfig.fields || [];
    var steps = fieldConfig.steps;
    if (steps) {
      var stepKeys = Object.keys(steps);
      for (var sk = 0; sk < stepKeys.length; sk++) {
        fields = fields.concat(steps[stepKeys[sk]]);
      }
    }

    var states = _evaluateAllClientConditions(form, fields);

    for (var i = 0; i < fields.length; i++) {
      var field = fields[i];
      var fieldKey = field.key || field.name;
      var state = states[fieldKey];
      if (!state) continue;

      var wrapper = form.querySelector('[data-af-field="' + fieldKey + '"]');
      if (!wrapper) continue;

      // Visibility
      if (state.visible) {
        wrapper.style.display = "";
        wrapper.style.visibility = "";
      } else {
        wrapper.style.display = "none";
        wrapper.style.visibility = "hidden";
      }

      // Apply conditional required
      var label = wrapper.querySelector(".af-label .af-required");
      var input = wrapper.querySelector(".af-input");
      if (state.required) {
        if (input) input.setAttribute("required", "required");
        if (!label) {
          // Add required indicator if not present
          var parentLabel = wrapper.querySelector(".af-label");
          if (parentLabel) {
            var req = document.createElement("span");
            req.className = "af-required";
            req.textContent = " *";
            parentLabel.appendChild(req);
          }
        }
      } else {
        if (input && !field.required) {
          input.removeAttribute("required");
        }
        // Remove dynamic required indicator
        if (label && !field.required) {
          label.remove();
        }
      }

      // Apply conditional default (only if field is empty)
      if (state.default && input && !input.value) {
        input.value = state.default;
      }
    }
  }

  function wireConditionListeners(form, fieldConfig) {
    var fields = fieldConfig.fields || [];
    var steps = fieldConfig.steps;
    if (steps) {
      var stepKeys = Object.keys(steps);
      for (var sk = 0; sk < stepKeys.length; sk++) {
        fields = fields.concat(steps[stepKeys[sk]]);
      }
    }
    // Find all target fields that conditions depend on (recursive for groups)
    var targetFields = {};
    for (var i = 0; i < fields.length; i++) {
      var field = fields[i];
      // Extract from condition (visibility)
      if (field.condition) {
        var refs = _extractConditionFields(field.condition);
        for (var r = 0; r < refs.length; r++) {
          targetFields[refs[r]] = true;
        }
      }
      // Extract from conditional_required
      if (field.conditional_required && field.conditional_required.field) {
        targetFields[field.conditional_required.field] = true;
      }
      // Extract from conditional_default
      if (field.conditional_default && field.conditional_default.condition) {
        var defRefs = _extractConditionFields(field.conditional_default.condition);
        for (var d = 0; d < defRefs.length; d++) {
          targetFields[defRefs[d]] = true;
        }
      }
      // Extract from conditional_validation
      if (field.conditional_validation) {
        for (var v = 0; v < field.conditional_validation.length; v++) {
          var cvRefs = _extractConditionFields(field.conditional_validation[v].condition);
          for (var c = 0; c < cvRefs.length; c++) {
            targetFields[cvRefs[c]] = true;
          }
        }
      }
      // Extract from computed fields (map/expression/formula)
      var computedRefs = _extractComputedFields(field);
      for (var cr = 0; cr < computedRefs.length; cr++) {
        targetFields[computedRefs[cr]] = true;
      }
    }
    // Wire up listeners on target fields
    var inputs = form.querySelectorAll("input, select, textarea");
    for (var j = 0; j < inputs.length; j++) {
      var el = inputs[j];
      if (targetFields[el.name]) {
        (function(elem) {
          var events = ["change", "input"];
          for (var e = 0; e < events.length; e++) {
            elem.addEventListener(events[e], function() {
              var currentData = getFormData(form);
              updateFieldVisibility(form, fieldConfig);
              _applyComputedFields(form, currentData, fieldConfig);
            });
          }
        })(el);
      }
    }
    // Initial visibility + computed fields pass
    updateFieldVisibility(form, fieldConfig);
    _applyComputedFields(form, getFormData(form), fieldConfig);
  }

  // Honeypot field
  function createHoneypot() {
    var wrapper = document.createElement("div");
    wrapper.className = "af-honeypot";
    wrapper.style.display = "none";
    wrapper.style.visibility = "hidden";
    wrapper.style.height = "0";
    wrapper.style.overflow = "hidden";

    var label = document.createElement("label");
    label.setAttribute("for", "af_website");
    label.textContent = "Website (leave empty)";

    var input = document.createElement("input");
    input.type = "text";
    input.name = "af_website";
    input.id = "af_website";
    input.tabIndex = -1;
    input.autocomplete = "off";

    wrapper.appendChild(label);
    wrapper.appendChild(input);
    return wrapper;
  }

  // Submit button
  function createButton(type, label) {
    var btn = document.createElement("button");
    btn.type = type;
    btn.className = "af-submit";

    var btnText = document.createElement("span");
    btnText.className = "af-btn-text";
    btnText.textContent = label;
    btn.appendChild(btnText);

    var spinner = document.createElement("span");
    spinner.className = "af-spinner";
    btn.appendChild(spinner);

    return btn;
  }

  // Message container
  function createMessage() {
    var msg = document.createElement("div");
    msg.className = "af-message";
    return msg;
  }

  // Build CSS with multi-step support
  function buildCss(theme) {
    var c = theme;
    return (
      ".af-form{font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,sans-serif;" +
      "background:" + c.bg + ";color:" + c.text + ";padding:24px;border-radius:8px;max-width:600px;margin:0 auto;" +
      "box-sizing:border-box}.af-form *{box-sizing:border-box}.af-field{margin-bottom:16px}.af-label{" +
      "display:block;margin-bottom:6px;font-weight:600;color:" + c.label + ";" +
      "font-size:14px;line-height:1.4}.af-required{color:" + c.error + "}.af-input{" +
      "width:100%;padding:10px 12px;border:1px solid " + c.inputBorder + ";border-radius:6px;" +
      "background:" + c.inputBg + ";color:" + c.inputText + ";font-size:15px;line-height:1.5;" +
      "transition:border-color 0.2s,box-shadow 0.2s}.af-input:focus{" +
      "outline:none;border-color:" + c.primary + ";box-shadow:0 0 0 3px " + c.primary + "22}.af-input::placeholder{color:" + c.placeholder +
      "}.af-input:disabled{opacity:0.6;cursor:not-allowed}.af-radio-group{" +
      "display:flex;flex-direction:column;gap:8px}.af-radio-label{" +
      "display:flex;align-items:center;gap:8px;cursor:pointer;font-weight:400}.af-radio-label input{" +
      "width:auto;flex-shrink:0}.af-submit{display:inline-flex;align-items:center;justify-content:center;" +
      "gap:8px;padding:12px 24px;background:" + c.primary + ";color:" + c.primaryText +
      ";border:none;border-radius:6px;font-size:15px;font-weight:600;cursor:pointer;" +
      "transition:opacity 0.2s,transform 0.1s;width:100%;margin-top:8px}" +
      ".af-submit:hover{opacity:0.9}.af-submit:active{transform:scale(0.98)}" +
      ".af-submit:disabled{opacity:0.6;cursor:not-allowed;transform:none}.af-submit.af-prev{" +
      "background:transparent;color:" + c.text + ";border:1px solid " + c.inputBorder + "}" +
      ".af-spinner{" +
      "display:none;width:16px;height:16px;border:2px solid " + c.primaryText + "33;" +
      "border-top-color:" + c.primaryText + ";border-radius:50%;animation:af-spin 0.6s linear infinite}." +
      "af-submit.loading .af-spinner{display:inline-block}.af-submit.loading .af-btn-text{" +
      "visibility:hidden}.af-message{padding:12px 16px;border-radius:6px;margin-top:16px;" +
      "font-size:14px;display:none;text-align:center}@keyframes af-spin{" +
      "to{transform:rotate(360deg)}}.af-honeypot{position:absolute;left:-9999px!important}" +
      ".af-progress{margin-bottom:24px}.af-progress-bar{display:flex;gap:6px;margin-bottom:8px}" +
      ".af-progress-segment{flex:1;height:4px;border-radius:2px;background:" + c.inputBorder + ";" +
      "transition:background 0.3s ease}.af-progress-segment.active{background:" + c.primary +
      "}.af-progress-segment.done{background:" + c.success +
      "}.af-progress-label{font-size:12px;color:" + c.label + ";text-align:center;font-weight:600}" +
      ".af-step-nav{display:flex;gap:8px;margin-top:16px}.af-step-nav .af-submit{width:auto;flex:1}" +
      ".af-step{display:none}.af-step.active{display:block}" +
      "@media(max-width:480px){.af-form{padding:16px}.af-input{padding:12px;font-size:16px}" +
      ".af-submit{padding:14px;font-size:16px}}"
    );
  }

  // Client-side validation for a step's fields
  function validateStepFields(stepFields, form) {
    var errors = [];
    for (var i = 0; i < stepFields.length; i++) {
      var fld = stepFields[i];
      var key = fld.key || fld.name;
      var wrapper = form.querySelector('[data-af-field="' + key + '"]');
      if (!wrapper) continue;

      // Required check
      if (fld.required) {
        if (fld.type === "radio") {
          var checked = form.querySelector('input[name="' + key + '"]:checked');
          if (!checked) {
            errors.push({ field: key, message: (fld.errorMessage || (fld.label || key) + " is required."), rule: "required" });
          }
        } else {
          var input = wrapper.querySelector('input[name="' + key + '"], textarea[name="' + key + '"], select[name="' + key + '"]');
          if (input) {
            var val = input.type === "checkbox" ? (input.checked ? "1" : "") : input.value;
            if (!val || val === "") {
              errors.push({ field: key, message: (fld.errorMessage || (fld.label || key) + " is required."), rule: "required" });
            }
          }
        }
      }
    }
    return errors;
  }

  // Show field-level error highlights
  function showFieldErrors(errors, form, theme) {
    // Clear previous errors
    var prevErrors = form.querySelectorAll(".af-field-error");
    for (var k = 0; k < prevErrors.length; k++) {
      prevErrors[k].remove();
    }
    var prevHighlights = form.querySelectorAll("[data-af-error]");
    for (var m = 0; m < prevHighlights.length; m++) {
      prevHighlights[m].removeAttribute("data-af-error");
      var inp = prevHighlights[m].querySelector(".af-input");
      if (inp) inp.style.borderColor = "";
    }

    // Show new errors
    for (var i = 0; i < errors.length; i++) {
      var err = errors[i];
      var wrapper = form.querySelector('[data-af-field="' + err.field + '"]');
      if (!wrapper) continue;

      // Highlight input
      var inp = wrapper.querySelector(".af-input");
      if (inp) {
        inp.setAttribute("data-af-error", "true");
        inp.style.borderColor = theme.error;
      }

      // Error message
      var errEl = document.createElement("div");
      errEl.className = "af-field-error";
      errEl.style.color = theme.error;
      errEl.style.fontSize = "12px";
      errEl.style.marginTop = "4px";
      errEl.textContent = err.message;
      wrapper.appendChild(errEl);
    }

    // Focus first error
    var firstError = form.querySelector('[data-af-field="' + errors[0].field + '"] .af-input');
    if (firstError) firstError.focus();
  }

  // Main render function
  function render(containerId, options) {
    var opts = deepMerge(DEFAULTS, options || {});
    if (!opts.token) {
      console.error("AF.render: token is required");
      return;
    }

    var container =
      typeof containerId === "string"
        ? document.getElementById(containerId)
        : containerId;

    if (!container) {
      console.error("AF.render: container not found (" + containerId + ")");
      return;
    }

    // Track impression
    trackImpression(opts.token);

    // Initialize session tracking
    var visitorId = getVisitorId(opts.token);

    // Show loading state
    var formId = generateId();
    container.innerHTML =
      '<div class="af-loading" style="text-align:center;padding:40px;color:#999;">Loading form...</div>';

    // Fetch and render
    fetchConfig(opts.token, function (err, config) {
      if (err) {
        container.innerHTML =
          '<div style="text-align:center;padding:40px;color:#dc3545;">' +
          escapeHtml("Could not load form: " + err.message) +
          "</div>";
        if (typeof opts.onError === "function") opts.onError(err);
        return;
      }

      // Check for A/B test variants
      fetchVariant(opts.token, visitorId, function (vErr, vResp) {
        var assignedVariant = vResp && vResp.assigned_variant;

        // Initialize session tracking with variant info
        initSessionTracking(opts.token, assignedVariant ? assignedVariant.variant_key : null);

        // If variant assigned, use variant's field_config
        if (assignedVariant && assignedVariant.field_config && assignedVariant.field_config.length > 0) {
          // Deep merge: variant config overrides base config fields
          config = deepMerge(config, {
            fields: assignedVariant.field_config,
            success_message: assignedVariant.success_message || config.success_message,
          });
          // Also merge multi-step if present
          if (assignedVariant.field_config.steps) {
            config.steps = assignedVariant.field_config.steps;
          }
          console.log("[AF] A/B Test: Assigned variant", assignedVariant.variant_key);
        }

        // Build theme
      var baseTheme =
        THEMES[opts.theme] || THEMES.light;
      var theme = deepMerge(baseTheme, opts.colors || {});

      // Create form
      var form = document.createElement("form");
      form.className = "af-form";
      form.id = formId;
      form.setAttribute("data-af-token", opts.token);
      form.noValidate = true;

      // Inject CSS
      var style = document.createElement("style");
      style.id = "af-style-" + formId;
      style.textContent = buildCss(theme);
      document.head.appendChild(style);

      // Multi-step support
      var isMultiStep = config.multi_step && config.steps && Object.keys(config.steps).length > 1;
      var stepKeys = isMultiStep ? Object.keys(config.steps).sort(function(a, b) { return parseInt(a) - parseInt(b); }) : [];
      var currentStep = 0;
      var totalSteps = stepKeys.length;

      // Progress bar
      var progressEl = null;
      var progressLabel = null;
      if (isMultiStep) {
        progressEl = document.createElement("div");
        progressEl.className = "af-progress";

        var progressBar = document.createElement("div");
        progressBar.className = "af-progress-bar";
        for (var s = 0; s < totalSteps; s++) {
          var segment = document.createElement("div");
          segment.className = "af-progress-segment";
          segment.setAttribute("data-step", s);
          progressBar.appendChild(segment);
        }
        progressEl.appendChild(progressBar);

        progressLabel = document.createElement("div");
        progressLabel.className = "af-progress-label";
        progressEl.appendChild(progressLabel);
        form.appendChild(progressEl);
      }

      function updateProgress() {
        if (!progressEl || !progressLabel) return;
        var segments = progressBar.querySelectorAll(".af-progress-segment");
        for (var i = 0; i < segments.length; i++) {
          segments[i].className = "af-progress-segment";
          if (i < currentStep) segments[i].classList.add("done");
          if (i === currentStep) segments[i].classList.add("active");
        }
        progressLabel.textContent = opts.stepLabel.replace("{current}", currentStep + 1).replace("{total}", totalSteps);
      }

      // Create step containers
      var stepContainers = {};
      if (isMultiStep) {
        for (var sk = 0; sk < stepKeys.length; sk++) {
          var stepDiv = document.createElement("div");
          stepDiv.className = "af-step";
          stepDiv.setAttribute("data-step", sk);
          form.appendChild(stepDiv);
          stepContainers[stepKeys[sk]] = stepDiv;
        }
        // Render fields into their step containers
        for (var sk2 = 0; sk2 < stepKeys.length; sk2++) {
          var stepKey = stepKeys[sk2];
          var stepFields = config.steps[stepKey];
          if (stepFields && stepFields.length > 0) {
            for (var fi = 0; fi < stepFields.length; fi++) {
              var fieldEl = renderField(stepFields[fi], formId);
              stepContainers[stepKey].appendChild(fieldEl);
            }
          }
        }
      } else {
        // Single-step: render all fields directly
        if (config.fields && config.fields.length > 0) {
          for (var i = 0; i < config.fields.length; i++) {
            var fieldEl = renderField(config.fields[i], formId);
            form.appendChild(fieldEl);
          }
        }
      }

      // Conditional field rendering - wire up listeners after all fields are rendered
      wireConditionListeners(form, config);
      // Real-time validation feedback
      wireRealTimeValidation(form, config, theme);

      // Honeypot (hidden, always present)
      if (config.honeypot_enabled !== false) {
        form.appendChild(createHoneypot());
      }

      // Message area
      var messageEl = createMessage();
      form.appendChild(messageEl);

      // Navigation container
      var navEl = document.createElement("div");
      navEl.className = isMultiStep ? "af-step-nav" : "";

      // Previous button (multi-step only)
      var prevBtn = null;
      if (isMultiStep) {
        prevBtn = createButton("button", opts.prevLabel);
        prevBtn.className += " af-prev";
        prevBtn.style.display = "none";
        navEl.appendChild(prevBtn);
      }

      // Next/Submit button
      var nextBtn = null;
      var submitBtn = null;
      if (isMultiStep) {
        nextBtn = createButton("button", opts.nextLabel);
        navEl.appendChild(nextBtn);
      }

      submitBtn = createButton("submit", opts.submitLabel);
      if (isMultiStep) {
        submitBtn.style.display = "none";
      }
      navEl.appendChild(submitBtn);
      form.appendChild(navEl);

      // Show/hide current step
      function showStep(index) {
        trackStepChange(index);
        var allSteps = form.querySelectorAll(".af-step");
        for (var i = 0; i < allSteps.length; i++) {
          allSteps[i].classList.remove("active");
        }
        if (stepKeys[index]) {
          stepContainers[stepKeys[index]].classList.add("active");
        }
        // Update buttons
        if (prevBtn) {
          prevBtn.style.display = index > 0 ? "" : "none";
        }
        if (nextBtn) {
          nextBtn.style.display = index < totalSteps - 1 ? "" : "none";
          if (nextBtn.querySelector(".af-btn-text")) {
            nextBtn.querySelector(".af-btn-text").textContent = opts.nextLabel;
          }
        }
        if (submitBtn) {
          submitBtn.style.display = index === totalSteps - 1 ? "" : "none";
        }
        updateProgress();
        // Clear step message
        messageEl.style.display = "none";
      }

      // Collect form data
      function collectData() {
        var data = {};
        var formData = new FormData(form);
        for (var entry of formData.entries()) {
          data[entry[0]] = entry[1];
        }
        return data;
      }

      // Show message
      function showMessage(text, type) {
        messageEl.textContent = text;
        messageEl.style.display = "block";
        messageEl.style.background = type === "error" ? theme.errorBg : theme.successBg;
        messageEl.style.color = type === "error" ? theme.error : theme.success;
        messageEl.style.border = "1px solid " + (type === "error" ? theme.error : theme.success);
      }

      // Disable form
      function disableForm() {
        var inputs = form.querySelectorAll("input, textarea, select, button");
        for (var i = 0; i < inputs.length; i++) {
          inputs[i].disabled = true;
        }
      }

      // Previous button handler
      if (prevBtn) {
        prevBtn.addEventListener("click", function () {
          if (currentStep > 0) {
            currentStep--;
            showStep(currentStep);
          }
        });
      }

      // Next button handler
      if (nextBtn) {
        nextBtn.addEventListener("click", function () {
          var stepKey = stepKeys[currentStep];
          var stepFields = config.steps[stepKey] || [];
          var errors = validateStepFields(stepFields, form);
          if (errors.length > 0) {
            showFieldErrors(errors, form, theme);
            showMessage(errors[0].message, "error");
            return;
          }
          if (currentStep < totalSteps - 1) {
            currentStep++;
            showStep(currentStep);
          }
        });
      }

      // Submit handler
      form.addEventListener("submit", function (e) {
        e.preventDefault();

        // Honeypot check
        var honeypot = form.querySelector('[name="af_website"]');
        if (honeypot && honeypot.value !== "") {
          return; // Bot detected, silently drop
        }

        // If multi-step, validate all steps
        if (isMultiStep) {
          var allErrors = [];
          for (var v = 0; v < stepKeys.length; v++) {
            var sKey = stepKeys[v];
            var sFields = config.steps[sKey] || [];
            var stepErrors = validateStepFields(sFields, form);
            allErrors = allErrors.concat(stepErrors);
          }
          if (allErrors.length > 0) {
            showFieldErrors(allErrors, form, theme);
            // Go to step with first error
            var errorStepIdx = 0;
            for (var es = 0; es < stepKeys.length; es++) {
              var skk = stepKeys[es];
              var skFields = config.steps[skk] || [];
              for (var ef = 0; ef < skFields.length; ef++) {
                if (skFields[ef].key === allErrors[0].field || skFields[ef].name === allErrors[0].field) {
                  errorStepIdx = es;
                  break;
                }
              }
              if (errorStepIdx === es) break;
            }
            currentStep = errorStepIdx;
            showStep(currentStep);
            return;
          }
        } else {
          // Single-step validation
          var requiredFields = form.querySelectorAll("[required]");
          for (var i = 0; i < requiredFields.length; i++) {
            var field = requiredFields[i];
            if (!field.value || (field.type === "checkbox" && !field.checked)) {
              field.focus();
              showMessage(field.dataset.label || "Please fill in this field.", "error");
              return;
            }
          }

          // Radio group validation
          var radioGroups = form.querySelectorAll(".af-radio-group");
          for (var j = 0; j < radioGroups.length; j++) {
            var group = radioGroups[j];
            var checked = group.querySelector('input[type="radio"]:checked');
            if (!checked) {
              showMessage("Please select an option.", "error");
              return;
            }
          }
        }

        // Loading state
        submitBtn.classList.add("loading");
        submitBtn.disabled = true;
        messageEl.style.display = "none";

        // Build FormData
        var formData = new FormData();
        var fields = form.querySelectorAll('input[name], textarea[name], select[name]');
        for (var k = 0; k < fields.length; k++) {
          var f = fields[k];
          if (f.name === "af_website") continue; // skip honeypot
          if (f.type === "checkbox" && !f.checked) continue;
          if (f.type === "radio" && !f.checked) continue;
          formData.append(f.name, f.value);
        }

        // Submit
        var xhr = new XMLHttpRequest();
        xhr.open(
          "POST",
          config.submit_endpoint || (BASE + "/api/submit?token=" + opts.token),
          true
        );
        xhr.timeout = 30000;
        xhr.onreadystatechange = function () {
          if (xhr.readyState === 4) {
            submitBtn.classList.remove("loading");
            if (xhr.status >= 200 && xhr.status < 300) {
              disableForm();
              showMessage(opts.successMessage, "success");
              completeSession();
              var submittedData = collectData();
              if (typeof opts.onSubmit === "function") {
                opts.onSubmit(submittedData);
              }
            } else {
              showMessage(opts.errorMessage, "error");
              submitBtn.disabled = false;
              if (typeof opts.onError === "function") {
                opts.onError(new Error("HTTP " + xhr.status));
              }
            }
          }
        };
        xhr.onerror = function () {
          submitBtn.classList.remove("loading");
          submitBtn.disabled = false;
          showMessage(opts.errorMessage, "error");
          if (typeof opts.onError === "function") {
            opts.onError(new Error("Network error"));
          }
        };
        xhr.ontimeout = function () {
          submitBtn.classList.remove("loading");
          submitBtn.disabled = false;
          showMessage("Request timed out. Please try again.", "error");
          if (typeof opts.onError === "function") {
            opts.onError(new Error("Timeout"));
          }
        };
        xhr.send(formData);
      });

      // Initialize step visibility
      if (isMultiStep) {
        showStep(0);
      } else {
        // Clear progress label text for single step
        if (progressLabel) progressLabel.textContent = "";
      }

      container.innerHTML = "";
      container.appendChild(form);
      }); // fetchVariant callback
    }); // fetchConfig callback

    return {
      destroy: (function () {
        return function () {
          container.innerHTML = "";
          var style = document.getElementById("af-style-" + formId);
          if (style) style.remove();
        };
      })(),
    };
  }

  // Expose globally
  window.AF = {
    render: render,
    version: "2.0.0",
  };
})(window, document);