function aiAppParseColorValue(value) {
  if (!value || typeof value !== "string") return value;
  var trimmed = value.trim();
  if (trimmed.charAt(0) !== "{" && trimmed.charAt(0) !== "[") return value;
  try {
    return JSON.parse(trimmed);
  } catch (err) {
    return value;
  }
}

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

function aiAppNormalizeAlphaValue(alpha) {
  if (typeof alpha !== "number" || isNaN(alpha)) return 1;
  if (alpha > 1) {
    return aiAppClamp(alpha / 100, 0, 1);
  }
  return aiAppClamp(alpha, 0, 1);
}

function aiAppHexToRgb(hex) {
  if (!hex) return null;
  var clean = hex.replace("#", "").trim();
  if (clean.length === 3) {
    clean = clean
      .split("")
      .map(function (c) {
        return c + c;
      })
      .join("");
  }
  if (clean.length === 8) {
    clean = clean.substr(0, 6);
  }
  if (!/^[0-9a-fA-F]{6}$/.test(clean)) return null;
  return {
    r: parseInt(clean.substr(0, 2), 16),
    g: parseInt(clean.substr(2, 2), 16),
    b: parseInt(clean.substr(4, 2), 16)
  };
}

function aiAppRgbToHex(r, g, b) {
  var toHex = function (value) {
    var hex = aiAppClamp(Math.round(value), 0, 255).toString(16);
    return hex.length === 1 ? "0" + hex : hex;
  };
  return "#" + toHex(r) + toHex(g) + toHex(b);
}

function aiAppRgbToHsv(r, g, b) {
  r /= 255;
  g /= 255;
  b /= 255;
  var max = Math.max(r, g, b);
  var min = Math.min(r, g, b);
  var delta = max - min;
  var h = 0;
  if (delta !== 0) {
    if (max === r) {
      h = ((g - b) / delta) % 6;
    } else if (max === g) {
      h = (b - r) / delta + 2;
    } else {
      h = (r - g) / delta + 4;
    }
    h = Math.round(h * 60);
    if (h < 0) h += 360;
  }
  var s = max === 0 ? 0 : delta / max;
  return { h: h, s: s, v: max };
}

function aiAppHsvToRgb(h, s, v) {
  var c = v * s;
  var x = c * (1 - Math.abs(((h / 60) % 2) - 1));
  var m = v - c;
  var r = 0;
  var g = 0;
  var b = 0;

  if (h >= 0 && h < 60) {
    r = c;
    g = x;
    b = 0;
  } else if (h >= 60 && h < 120) {
    r = x;
    g = c;
    b = 0;
  } else if (h >= 120 && h < 180) {
    r = 0;
    g = c;
    b = x;
  } else if (h >= 180 && h < 240) {
    r = 0;
    g = x;
    b = c;
  } else if (h >= 240 && h < 300) {
    r = x;
    g = 0;
    b = c;
  } else {
    r = c;
    g = 0;
    b = x;
  }

  return {
    r: Math.round((r + m) * 255),
    g: Math.round((g + m) * 255),
    b: Math.round((b + m) * 255)
  };
}

function aiAppColorToRgbaString(hex, alpha) {
  var rgb = aiAppHexToRgb(hex);
  if (!rgb) return hex || "";
  var safeAlpha = aiAppNormalizeAlphaValue(alpha);
  if (safeAlpha >= 0.999) {
    return aiAppRgbToHex(rgb.r, rgb.g, rgb.b);
  }
  return "rgba(" + rgb.r + ", " + rgb.g + ", " + rgb.b + ", " + safeAlpha.toFixed(3) + ")";
}

function aiAppNormalizeStopsArray(stops) {
  if (!Array.isArray(stops) || stops.length === 0) {
    return [];
  }
  var total = stops.length;
  return stops.map(function (stop, index) {
    var color = stop && typeof stop.color === "string" ? stop.color : "#5c5c5c";
    var rgb = aiAppHexToRgb(color);
    if (!rgb) {
      color = "#5c5c5c";
    }
    var alpha =
      stop && typeof stop.alpha !== "undefined"
        ? aiAppNormalizeAlphaValue(stop.alpha)
        : stop && typeof stop.opacity !== "undefined"
        ? aiAppNormalizeAlphaValue(stop.opacity)
        : 1;
    var pos =
      stop && typeof stop.pos === "number"
        ? stop.pos
        : stop && typeof stop.position === "number"
        ? stop.position
        : stop && typeof stop.offset === "number"
        ? stop.offset
        : total > 1
        ? index * (100 / (total - 1))
        : 100;
    return {
      color: color,
      alpha: alpha,
      pos: aiAppClamp(pos, 0, 100)
    };
  });
}

function aiAppNormalizeSolidData(data) {
  if (!data || typeof data !== "object") return null;
  var color = null;
  var alpha = 1;
  if (typeof data.color === "string") {
    color = aiAppNormalizeHexInput(data.color);
    if (color && color.length === 9) {
      alpha = parseInt(color.substr(7, 2), 16) / 255;
      color = "#" + color.substr(1, 6);
    }
  }
  if (!color && typeof data.color === "string") {
    color = data.color.trim();
  }
  if (!color) return null;

  alpha =
    typeof data.alpha !== "undefined"
      ? aiAppNormalizeAlphaValue(data.alpha)
      : typeof data.opacity !== "undefined"
      ? aiAppNormalizeAlphaValue(data.opacity)
      : alpha;

  return {
    type: "solid",
    color: color,
    alpha: alpha
  };
}

function aiAppNormalizeGradientData(data) {
  if (!data || typeof data !== "object") return null;
  if (data.type === "gradient" && Array.isArray(data.stops)) {
    var normalizedStops = aiAppNormalizeStopsArray(data.stops);
    return {
      type: "gradient",
      mode: data.mode === "radial" ? "radial" : "linear",
      angle: typeof data.angle === "number" ? data.angle : 90,
      shape: data.shape || "circle",
      position: data.position || "center",
      stops: normalizedStops
    };
  }
  if (data.type === "gradient" && Array.isArray(data.colors)) {
    var stops = data.colors.map(function (color, index) {
      var pos = Array.isArray(data.positions) ? data.positions[index] : null;
      return {
        color: color,
        alpha: 1,
        pos: typeof pos === "number" ? pos : index * (data.colors.length > 1 ? 100 / (data.colors.length - 1) : 100)
      };
    });
    stops = aiAppNormalizeStopsArray(stops);
    var directionMap = {
      "to bottom": 180,
      "to right": 90,
      "to top": 0,
      "to left": 270,
      "to bottom right": 135
    };
    return {
      type: "gradient",
      mode: "linear",
      angle: directionMap[data.direction] !== undefined ? directionMap[data.direction] : 180,
      shape: "circle",
      position: "center",
      stops: stops
    };
  }
  return null;
}

function aiAppBuildGradientCss(data) {
  if (!data || typeof data !== "object") return "";
  var normalized = aiAppNormalizeGradientData(data) || data;
  if (!normalized.stops || !normalized.stops.length) return "";
  var stops = normalized.stops
    .slice()
    .sort(function (a, b) {
      return (a.pos || 0) - (b.pos || 0);
    })
    .map(function (stop) {
      var color = aiAppColorToRgbaString(stop.color, stop.alpha);
      var pos = typeof stop.pos === "number" ? aiAppClamp(stop.pos, 0, 100) : null;
      return pos !== null ? color + " " + pos + "%" : color;
    });

  if ((normalized.mode || data.mode) === "radial") {
    return "radial-gradient(circle at center, " + stops.join(", ") + ")";
  }
  var angle = typeof normalized.angle === "number" ? aiAppClamp(normalized.angle, 0, 360) : 90;
  return "linear-gradient(" + angle + "deg, " + stops.join(", ") + ")";
}

function aiAppNormalizeColorValue(value) {
  var parsed = aiAppParseColorValue(value);
  if (parsed && typeof parsed === "object") {
    if (parsed.type === "solid") {
      var normalizedSolid = aiAppNormalizeSolidData(parsed) || parsed;
      return aiAppColorToHexWithAlpha(
        normalizedSolid.color || "",
        normalizedSolid.alpha
      );
    }
    if (parsed.type === "gradient") {
      return aiAppBuildGradientCss(parsed);
    }
    if (parsed.color) {
      return parsed.color || "";
    }
  }
  var rgbaValue = aiAppParseRgbaString(value);
  if (rgbaValue) {
    return aiAppColorToHexWithAlpha(rgbaValue.hex, rgbaValue.alpha);
  }
  return value || "";
}

function aiAppComparableColorValue(value) {
  var parsed = aiAppParseColorValue(value);
  if (!parsed || typeof parsed !== "object") {
    return parsed || "";
  }
  if (parsed.type === "solid") {
    var normalizedSolid = aiAppNormalizeSolidData(parsed) || parsed;
    var alpha = aiAppNormalizeAlphaValue(normalizedSolid.alpha);
    if (alpha >= 0.999) {
      return normalizedSolid.color || "";
    }
    return aiAppColorToHexWithAlpha(normalizedSolid.color || "", alpha);
  }
  if (parsed.type === "gradient") {
    var normalized = aiAppNormalizeGradientData(parsed) || parsed;
    var normalizedStops = aiAppNormalizeStopsArray(normalized.stops || []);
    normalizedStops.sort(function (a, b) {
      return (a.pos || 0) - (b.pos || 0);
    });
    var payload = {
      type: "gradient",
      mode: normalized.mode === "radial" ? "radial" : "linear",
      angle: typeof normalized.angle === "number" ? aiAppClamp(normalized.angle, 0, 360) : 90,
      shape: normalized.shape || "circle",
      position: normalized.position || "center",
      stops: normalizedStops
    };
    return JSON.stringify(payload);
  }
  if (parsed.color) {
    return parsed.color || "";
  }
  var rgbaValue = aiAppParseRgbaString(value);
  if (rgbaValue) {
    return aiAppColorToHexWithAlpha(rgbaValue.hex, rgbaValue.alpha);
  }
  return JSON.stringify(parsed);
}

function aiAppApplyBackgroundStyle(element, value) {
  if (!element) return;
  var cssValue = aiAppNormalizeColorValue(value);
  if (cssValue.indexOf("linear-gradient") === 0 || cssValue.indexOf("radial-gradient") === 0) {
    element.style.background = cssValue;
  } else {
    element.style.backgroundImage = "";
    element.style.backgroundColor = cssValue;
  }
}

function aiAppBuildColorArray(inputName, baseKey, allowGradient) {
  var radios = document.querySelectorAll('input[type="radio"][name="' + inputName + '"]');
  var result = [];

  radios.forEach(function (radio) {
    var rawValue = radio.value;
    var isChecked = radio.checked;
    var parsedValue = aiAppParseColorValue(rawValue);
    var valueForStore =
      parsedValue && typeof parsedValue === "object" ? parsedValue : rawValue;

    var obj = {};
    obj[baseKey + (isChecked ? "_selected" : "")] = valueForStore;
    result.push(obj);
  });

  return result;
}

function aiAppCreateCustomColorLabel(inputName, value, isSelected) {
  var trigger = document.querySelector(
    '.select-color.ai-app-color-trigger[data-color-field="' + inputName + '"]'
  );
  if (!trigger) return null;

  var container = trigger.parentNode;
  var existing = container.querySelector(".ai-app-custom-color");
  if (existing) {
    var existingRadio = existing.querySelector('input[type="radio"]');
    var existingSpan = existing.querySelector("span.checkmark");
    if (existingRadio) {
      var existingComparable = aiAppComparableColorValue(value);
      existingRadio.value = existingComparable;
      existingRadio.checked = !!isSelected;
      existingRadio.name = inputName;
    }
    if (existingSpan) {
      var existingCssValue = aiAppNormalizeColorValue(value);
      if (existingCssValue.indexOf("linear-gradient") === 0 || existingCssValue.indexOf("radial-gradient") === 0) {
        existingSpan.style.background = existingCssValue;
        existingSpan.style.border = "1px solid #9ca3af";
      } else {
        existingSpan.style.backgroundColor = existingCssValue;
        existingSpan.style.border = "1px solid " + existingCssValue;
      }
    }
    return existingRadio;
  }

  var label = document.createElement("label");
  label.className = "color-container " + inputName + " ai-app-custom-color";

  var radio = document.createElement("input");
  radio.type = "radio";
  radio.name = inputName;
  radio.className = "color";

  var comparableValue = aiAppComparableColorValue(value);
  radio.value = comparableValue;

  var radioId =
    comparableValue && comparableValue.charAt(0) === "#"
      ? comparableValue.substring(1)
      : "aiapp-color-" + Date.now();
  radio.id = radioId;

  if (isSelected) {
    radio.checked = true;
    radio.setAttribute("checked", "checked");
  }

  var span = document.createElement("span");
  span.className = "checkmark";

  var cssValue = aiAppNormalizeColorValue(value);
  if (cssValue.indexOf("linear-gradient") === 0 || cssValue.indexOf("radial-gradient") === 0) {
    span.style.background = cssValue;
    span.style.border = "1px solid #9ca3af";
  } else {
    span.style.backgroundColor = cssValue;
    span.style.border = "1px solid " + cssValue;
  }

  label.appendChild(radio);
  label.appendChild(span);
  container.insertBefore(label, trigger);

  return radio;
}

function aiAppUpdateSwatchLabel(label, inputName, value, isSelected) {
  if (!label) return null;
  var radio = label.querySelector('input[type="radio"]');
  var span = label.querySelector("span.checkmark");
  if (!radio || !span) return null;

  var comparableValue = aiAppComparableColorValue(value);
  radio.value = comparableValue;
  radio.name = inputName;

  if (isSelected) {
    radio.checked = true;
    radio.setAttribute("checked", "checked");
  }

  var cssValue = aiAppNormalizeColorValue(value);
  if (cssValue.indexOf("linear-gradient") === 0 || cssValue.indexOf("radial-gradient") === 0) {
    span.style.background = cssValue;
    span.style.border = "1px solid #9ca3af";
  } else {
    span.style.backgroundColor = cssValue;
    span.style.border = "1px solid " + cssValue;
  }

  return radio;
}

function aiAppUpdateLastSwatch(inputName, value, isSelected) {
  var trigger = document.querySelector(
    '.select-color.ai-app-color-trigger[data-color-field="' + inputName + '"]'
  );
  if (!trigger || !trigger.parentNode) return null;

  var labels = Array.prototype.filter.call(
    trigger.parentNode.querySelectorAll("label.color-container"),
    function (label) {
      return !label.classList.contains("ai-app-color-trigger");
    }
  );

  if (!labels.length) return null;
  return aiAppUpdateSwatchLabel(labels[labels.length - 1], inputName, value, isSelected);
}

function applyColorSelection(config) {
  var dataArray   = config.data || [];
  var baseKey     = config.baseKey;
  var inputName   = config.inputName;

  dataArray.forEach(function (item) {
    if (!Object.prototype.hasOwnProperty.call(item, baseKey + "_selected")) {
      return;
    }

    var selected = item[baseKey + "_selected"];
    var radios   = document.querySelectorAll('input[name="' + inputName + '"]');
    var comparable = aiAppComparableColorValue(selected);
    var radio = Array.prototype.find.call(radios, function (r) { 
      return r.value === comparable; 
    });

    if (radio) {
      radio.checked = true;
      radio.setAttribute("checked", "checked");
    } else {
      aiAppUpdateLastSwatch(inputName, selected, true);
    }
  });
}

var aiAppColorPopupState = {
  isOpen: false,
  fieldName: "",
  allowGradient: false,
  mode: "solid",
  angle: 90,
  stops: [],
  activeStop: 0,
  hsv: { h: 210, s: 0.5, v: 0.5 },
  alpha: 1,
  suppressSync: false,
  triggerEl: null,
  syncSwatchLabel: null,
  draftSnapshot: null
};
var aiAppColorPopupElements = null;

function aiAppGetColorPopupElements() {
  if (
    aiAppColorPopupElements &&
    aiAppColorPopupElements.popup &&
    !document.contains(aiAppColorPopupElements.popup)
  ) {
    aiAppColorPopupElements = null;
  }
  if (aiAppColorPopupElements) return aiAppColorPopupElements;
  var popup = document.getElementById("ai-app-color-popup");
  if (!popup) return null;
  aiAppColorPopupElements = {
    popup: popup,
    modeButton: popup.querySelector("#ai-app-color-mode-button"),
    modeLabel: popup.querySelector("#ai-app-color-mode-label"),
    modeMenu: popup.querySelector("#ai-app-color-mode-menu"),
    modeOptions: popup.querySelectorAll(".ai-app-color-popup__mode-option"),
    gradientHint: popup.querySelector("#ai-app-color-gradient-hint"),
    gradientBar: popup.querySelector("#ai-app-color-gradient-bar"),
    gradientTrack: popup.querySelector("#ai-app-color-gradient-track"),
    gradientStops: popup.querySelector("#ai-app-color-gradient-stops"),
    panel: popup.querySelector("#ai-app-color-panel"),
    panelThumb: popup.querySelector("#ai-app-color-panel-thumb"),
    hue: popup.querySelector("#ai-app-color-hue"),
    hueThumb: popup.querySelector("#ai-app-color-hue-thumb"),
    alpha: popup.querySelector("#ai-app-color-alpha"),
    alphaTrack: popup.querySelector("#ai-app-color-alpha-track"),
    alphaThumb: popup.querySelector("#ai-app-color-alpha-thumb"),
    angleWrap: popup.querySelector("#ai-app-color-angle"),
    angleDial: popup.querySelector("#ai-app-color-angle-dial"),
    angleIndicator: popup.querySelector("#ai-app-color-angle .ai-app-color-popup__angle-indicator"),
    angleInput: popup.querySelector("#ai-app-color-angle-input"),
    angleRotate: popup.querySelector("#ai-app-color-angle-rotate"),
    hexInput: popup.querySelector("#ai-app-color-hex-input"),
    opacityInput: popup.querySelector("#ai-app-color-opacity-input"),
    formatButton: popup.querySelector("#ai-app-color-format-button"),
    applyButton: popup.querySelector("#ai-app-color-apply-button"),
    resetButton: popup.querySelector("#ai-app-color-reset-button"),
    angleTrashButton: popup.querySelector("#ai-app-color-angle-trash-button"),
    footerTrashButton: popup.querySelector("#ai-app-color-footer-trash-button"),
    closeButton: popup.querySelector(".ai-app-color-popup__close")
  };
  return aiAppColorPopupElements;
}

function aiAppNormalizeHexInput(value) {
  if (!value) return null;
  var clean = value.trim().replace(/^#/, "");
  if (
    !/^[0-9a-fA-F]{3}$/.test(clean) &&
    !/^[0-9a-fA-F]{6}$/.test(clean) &&
    !/^[0-9a-fA-F]{8}$/.test(clean)
  ) {
    return null;
  }
  if (clean.length === 3) {
    clean = clean
      .split("")
      .map(function (c) {
        return c + c;
      })
      .join("");
  }
  return "#" + clean.toLowerCase();
}

function aiAppColorToHexWithAlpha(hex, alpha) {
  var normalized = aiAppNormalizeHexInput(hex);
  if (!normalized) return hex || "";

  if (normalized.length === 9) {
    normalized = "#" + normalized.substr(1, 6);
  }

  var safeAlpha = aiAppNormalizeAlphaValue(alpha);
  if (safeAlpha >= 0.999) {
    return normalized;
  }

  var alphaHex = Math.round(safeAlpha * 255).toString(16);
  if (alphaHex.length === 1) {
    alphaHex = "0" + alphaHex;
  }

  return normalized + alphaHex;
}

function aiAppParseRgbaString(value) {
  if (typeof value !== "string") return null;
  var match = value
    .trim()
    .match(/^rgba?\(\s*([0-9.]+)\s*,\s*([0-9.]+)\s*,\s*([0-9.]+)(?:\s*,\s*([0-9.]+)\s*)?\)$/i);
  if (!match) return null;
  var alpha = typeof match[4] !== "undefined" ? parseFloat(match[4]) : 1;
  return {
    hex: aiAppRgbToHex(parseFloat(match[1]), parseFloat(match[2]), parseFloat(match[3])),
    alpha: aiAppNormalizeAlphaValue(alpha)
  };
}

function aiAppGetLastSwatchValue(fieldName) {
  var trigger = document.querySelector(
    '.select-color.ai-app-color-trigger[data-color-field="' + fieldName + '"]'
  );
  if (!trigger || !trigger.parentNode) return null;
  var labels = Array.prototype.filter.call(
    trigger.parentNode.querySelectorAll("label.color-container"),
    function (label) {
      return !label.classList.contains("ai-app-color-trigger");
    }
  );
  if (!labels.length) return null;
  var lastLabel = labels[labels.length - 1];
  var radio = lastLabel.querySelector('input[type="radio"]');
  return radio ? radio.value : null;
}

function aiAppResolvePickerHex(value) {
  var colorInfo = aiAppResolvePickerColorInfo(value);
  return colorInfo.hex || "#5c5c5c";
}

function aiAppResolvePickerColorInfo(value) {
  var parsed = aiAppParseColorValue(value);
  var color = "";
  var alpha = 1;
  if (parsed && typeof parsed === "object") {
    if (parsed.type === "gradient") {
      var normalized = aiAppNormalizeGradientData(parsed) || parsed;
      if (normalized.stops && normalized.stops[0] && normalized.stops[0].color) {
        color = normalized.stops[0].color;
        alpha = aiAppNormalizeAlphaValue(normalized.stops[0].alpha);
      }
    } else if (parsed.type === "solid" && parsed.color) {
      var normalizedSolid = aiAppNormalizeSolidData(parsed) || parsed;
      color = normalizedSolid.color || "";
      alpha = aiAppNormalizeAlphaValue(normalizedSolid.alpha);
    } else if (parsed.color) {
      color = parsed.color;
      if (typeof parsed.alpha !== "undefined") {
        alpha = aiAppNormalizeAlphaValue(parsed.alpha);
      } else if (typeof parsed.opacity !== "undefined") {
        alpha = aiAppNormalizeAlphaValue(parsed.opacity);
      }
    }
  } else if (typeof parsed === "string") {
    color = parsed;
    var normalizedString = aiAppNormalizeHexInput(parsed);
    if (normalizedString && normalizedString.length === 9) {
      color = "#" + normalizedString.substr(1, 6);
      alpha = parseInt(normalizedString.substr(7, 2), 16) / 255;
    } else {
      var rgbaColor = aiAppParseRgbaString(parsed);
      if (rgbaColor) {
        color = rgbaColor.hex;
        alpha = rgbaColor.alpha;
      }
    }
  }

  var normalizedColorValue = aiAppNormalizeHexInput(color);
  if (normalizedColorValue && normalizedColorValue.length === 9) {
    color = "#" + normalizedColorValue.substr(1, 6);
    if (alpha >= 0.999) {
      alpha = parseInt(normalizedColorValue.substr(7, 2), 16) / 255;
    }
  }

  return {
    hex: aiAppNormalizeHexInput(color) || "#5c5c5c",
    alpha: alpha
  };
}

function aiAppGetCurrentHexFromState() {
  var rgb = aiAppHsvToRgb(
    aiAppColorPopupState.hsv.h,
    aiAppColorPopupState.hsv.s,
    aiAppColorPopupState.hsv.v
  );
  return aiAppRgbToHex(rgb.r, rgb.g, rgb.b);
}

function aiAppSetHsvFromHex(hex) {
  var normalized = aiAppNormalizeHexInput(hex);
  if (!normalized) return;
  var rgb = aiAppHexToRgb(normalized);
  if (!rgb) return;
  aiAppColorPopupState.hsv = aiAppRgbToHsv(rgb.r, rgb.g, rgb.b);
}

function aiAppGetStopsFromSolid(hex) {
  var safeHex = aiAppResolvePickerHex(hex) || "#5c5c5c";
  return [
    { color: safeHex, alpha: 1, pos: 0 },
    { color: safeHex, alpha: 1, pos: 100 }
  ];
}

function aiAppBuildGradientValueFromState() {
  var stops = aiAppColorPopupState.stops.map(function (stop) {
    return {
      color: stop.color,
      alpha: aiAppNormalizeAlphaValue(stop.alpha),
      pos: Math.round(aiAppClamp(stop.pos, 0, 100))
    };
  });
  return {
    type: "gradient",
    mode: aiAppColorPopupState.mode === "radial" ? "radial" : "linear",
    angle: Math.round(aiAppClamp(aiAppColorPopupState.angle || 0, 0, 360)),
    shape: "circle",
    position: "center",
    stops: stops
  };
}

function aiAppSyncCustomColor(value) {
  if (aiAppColorPopupState.suppressSync) return;
  if (!aiAppColorPopupState.fieldName) return;
  var radio = null;
  if (aiAppColorPopupState.syncSwatchLabel) {
    radio = aiAppUpdateSwatchLabel(
      aiAppColorPopupState.syncSwatchLabel,
      aiAppColorPopupState.fieldName,
      value,
      true
    );
  }
  if (!radio) {
    radio = aiAppUpdateLastSwatch(
      aiAppColorPopupState.fieldName,
      value,
      true
    );
  }
  if (!radio) {
    radio = aiAppCreateCustomColorLabel(
      aiAppColorPopupState.fieldName,
      value,
      true
    );
  }
  if (radio) {
    radio.checked = true;
    radio.setAttribute("checked", "checked");
  }
}

function aiAppCloneColorPopupSnapshot(source) {
  return {
    mode: source.mode,
    angle: source.angle,
    stops: Array.isArray(source.stops)
      ? source.stops.map(function (stop) {
          return {
            color: stop.color,
            alpha: stop.alpha,
            pos: stop.pos
          };
        })
      : [],
    activeStop: source.activeStop,
    hsv: {
      h: source.hsv && typeof source.hsv.h === "number" ? source.hsv.h : 0,
      s: source.hsv && typeof source.hsv.s === "number" ? source.hsv.s : 0,
      v: source.hsv && typeof source.hsv.v === "number" ? source.hsv.v : 0
    },
    alpha: source.alpha
  };
}

function aiAppRestoreColorPopupSnapshot(snapshot) {
  if (!snapshot) return;
  aiAppColorPopupState.mode = snapshot.mode;
  aiAppColorPopupState.angle = snapshot.angle;
  aiAppColorPopupState.stops = Array.isArray(snapshot.stops)
    ? snapshot.stops.map(function (stop) {
        return {
          color: stop.color,
          alpha: stop.alpha,
          pos: stop.pos
        };
      })
    : [];
  aiAppColorPopupState.activeStop = snapshot.activeStop;
  aiAppColorPopupState.hsv = {
    h: snapshot.hsv.h,
    s: snapshot.hsv.s,
    v: snapshot.hsv.v
  };
  aiAppColorPopupState.alpha = snapshot.alpha;
  aiAppUpdatePopupUI(false);
}

function aiAppGetPopupCommittedValue() {
  if (aiAppColorPopupState.mode === "solid" || !aiAppColorPopupState.allowGradient) {
    var alpha = aiAppNormalizeAlphaValue(aiAppColorPopupState.alpha);
    if (alpha >= 0.999) {
      return aiAppGetCurrentHexFromState();
    }
    return aiAppColorToHexWithAlpha(aiAppGetCurrentHexFromState(), alpha);
  }
  return aiAppBuildGradientValueFromState();
}

function aiAppCommitColorPopupChanges() {
  var value = aiAppGetPopupCommittedValue();
  aiAppSyncCustomColor(value);
  aiAppCloseColorPopup();
}

function aiAppResetColorPopupChanges() {
  if (!aiAppColorPopupState.draftSnapshot) return;
  aiAppRestoreColorPopupSnapshot(aiAppColorPopupState.draftSnapshot);
}

function aiAppRemoveSelectedGradientStop() {
  if (!aiAppColorPopupState.allowGradient || aiAppColorPopupState.mode === "solid") {
    return;
  }
  if (!Array.isArray(aiAppColorPopupState.stops) || aiAppColorPopupState.stops.length <= 2) {
    return;
  }

  var index = aiAppClamp(
    aiAppColorPopupState.activeStop || 0,
    0,
    aiAppColorPopupState.stops.length - 1
  );
  aiAppColorPopupState.stops.splice(index, 1);
  aiAppColorPopupState.activeStop = Math.max(
    0,
    Math.min(index, aiAppColorPopupState.stops.length - 1)
  );

  var active = aiAppColorPopupState.stops[aiAppColorPopupState.activeStop];
  if (active) {
    aiAppSetHsvFromHex(active.color);
    aiAppColorPopupState.alpha = aiAppNormalizeAlphaValue(active.alpha);
  }

  aiAppUpdatePopupUI(false);
}

function aiAppUpdateAngleUI() {
  var elements = aiAppGetColorPopupElements();
  if (!elements) return;
  var angle = aiAppClamp(aiAppColorPopupState.angle || 0, 0, 360);
  if (elements.angleInput) {
    elements.angleInput.value = angle;
  }
  if (elements.angleDial) {
    elements.angleDial.style.transform = "rotate(" + angle + "deg)";
  }
}

function aiAppRefreshGradientUI(syncSwatch) {
  var elements = aiAppGetColorPopupElements();
  if (!elements || !elements.gradientTrack || !elements.gradientStops) return;
  var gradientValue = aiAppBuildGradientValueFromState();
  elements.gradientTrack.style.background = aiAppBuildGradientCss(gradientValue);
  elements.gradientStops.innerHTML = "";

  aiAppColorPopupState.stops.forEach(function (stop, index) {
    var stopEl = document.createElement("div");
    stopEl.className =
      "ai-app-color-stop" +
      (index === aiAppColorPopupState.activeStop ? " is-active" : "");
    stopEl.style.left = aiAppClamp(stop.pos, 0, 100) + "%";
    stopEl.style.background = aiAppColorToRgbaString(stop.color, stop.alpha);
    stopEl.dataset.index = index;

    stopEl.addEventListener("click", function (event) {
      event.stopPropagation();
      aiAppColorPopupState.activeStop = index;
      aiAppSetHsvFromHex(stop.color);
      aiAppColorPopupState.alpha = aiAppNormalizeAlphaValue(stop.alpha);
      aiAppUpdatePopupUI(false);
    });

    stopEl.addEventListener("dblclick", function (event) {
      event.preventDefault();
      event.stopPropagation();
      if (aiAppColorPopupState.stops.length <= 2) return;
      aiAppColorPopupState.stops.splice(index, 1);
      aiAppColorPopupState.activeStop = Math.max(
        0,
        Math.min(aiAppColorPopupState.activeStop, aiAppColorPopupState.stops.length - 1)
      );
      var active = aiAppColorPopupState.stops[aiAppColorPopupState.activeStop];
      if (active) {
        aiAppSetHsvFromHex(active.color);
        aiAppColorPopupState.alpha = aiAppNormalizeAlphaValue(active.alpha);
      }
      aiAppUpdatePopupUI(false);
    });

    stopEl.addEventListener("pointerdown", function (event) {
      event.preventDefault();
      event.stopPropagation();
      aiAppStartStopDrag(index, event);
    });

    elements.gradientStops.appendChild(stopEl);
  });

  if (syncSwatch) {
    aiAppSyncCustomColor(gradientValue);
  }
}

function aiAppUpdatePopupUI(syncSwatch) {
  var elements = aiAppGetColorPopupElements();
  if (!elements) return;

  if (!aiAppColorPopupState.allowGradient) {
    aiAppColorPopupState.mode = "solid";
  }

  var hex = aiAppGetCurrentHexFromState();
  var alphaValue = aiAppNormalizeAlphaValue(aiAppColorPopupState.alpha);

  if (elements.modeLabel) {
    var label = "Solid";
    if (aiAppColorPopupState.mode === "linear") {
      label = "Linear";
    } else if (aiAppColorPopupState.mode === "radial") {
      label = "Radial";
    }
    elements.modeLabel.textContent = label;
  }

  if (elements.modeButton) {
    elements.modeButton.classList.toggle(
      "is-static",
      !aiAppColorPopupState.allowGradient
    );
    elements.modeButton.setAttribute("aria-expanded", "false");
  }

  if (elements.modeMenu) {
    elements.modeMenu.classList.add("ai-app-hidden");
  }

  elements.modeOptions.forEach(function (option) {
    var isActive = option.dataset.mode === aiAppColorPopupState.mode;
    option.classList.toggle("is-active", isActive);
  });

  if (elements.panel) {
    elements.panel.style.background =
      "hsl(" + aiAppClamp(aiAppColorPopupState.hsv.h, 0, 360) + ", 100%, 50%)";
  }
  if (elements.panelThumb) {
    elements.panelThumb.style.left =
      aiAppClamp(aiAppColorPopupState.hsv.s, 0, 1) * 100 + "%";
    elements.panelThumb.style.top =
      (1 - aiAppClamp(aiAppColorPopupState.hsv.v, 0, 1)) * 100 + "%";
  }
  if (elements.hueThumb) {
    elements.hueThumb.style.left =
      (aiAppClamp(aiAppColorPopupState.hsv.h, 0, 360) / 360) * 100 + "%";
  }
  if (elements.alphaTrack) {
    var rgb = aiAppHexToRgb(hex);
    if (rgb) {
      elements.alphaTrack.style.background =
        "linear-gradient(to right, rgba(" +
        rgb.r +
        ", " +
        rgb.g +
        ", " +
        rgb.b +
        ", 0), rgba(" +
        rgb.r +
        ", " +
        rgb.g +
        ", " +
        rgb.b +
        ", 1))";
    }
  }
  if (elements.alphaThumb) {
    elements.alphaThumb.style.left = alphaValue * 100 + "%";
  }

  if (elements.hexInput) {
    elements.hexInput.value = hex;
  }
  if (elements.opacityInput) {
    elements.opacityInput.value = Math.round(alphaValue * 100) + "%";
    elements.opacityInput.disabled = false;
    elements.opacityInput.classList.remove("is-disabled");
  }

  if (elements.alpha) {
    elements.alpha.classList.remove("is-disabled");
  }

  var showTrash = aiAppColorPopupState.allowGradient && aiAppColorPopupState.mode !== "solid";
  var showAngleTrash = showTrash && aiAppColorPopupState.mode === "linear";
  var showFooterTrash = showTrash && aiAppColorPopupState.mode === "radial";
  var canRemoveStop =
    showTrash &&
    Array.isArray(aiAppColorPopupState.stops) &&
    aiAppColorPopupState.stops.length > 2;

  if (elements.angleTrashButton) {
    elements.angleTrashButton.classList.toggle("ai-app-hidden", !showAngleTrash);
    elements.angleTrashButton.classList.toggle("is-disabled", !canRemoveStop);
    elements.angleTrashButton.setAttribute(
      "aria-disabled",
      canRemoveStop ? "false" : "true"
    );
  }
  if (elements.footerTrashButton) {
    elements.footerTrashButton.classList.toggle("ai-app-hidden", !showFooterTrash);
    elements.footerTrashButton.classList.toggle("is-disabled", !canRemoveStop);
    elements.footerTrashButton.setAttribute(
      "aria-disabled",
      canRemoveStop ? "false" : "true"
    );
  }

  var showGradient =
    aiAppColorPopupState.allowGradient &&
    (aiAppColorPopupState.mode === "linear" || aiAppColorPopupState.mode === "radial");
  if (elements.gradientBar) {
    elements.gradientBar.classList.toggle("ai-app-hidden", !showGradient);
  }
  if (elements.gradientHint) {
    elements.gradientHint.classList.toggle("ai-app-hidden", !showGradient);
  }
  if (elements.angleWrap) {
    elements.angleWrap.classList.toggle(
      "ai-app-hidden",
      !(
        aiAppColorPopupState.allowGradient &&
        aiAppColorPopupState.mode === "linear"
      )
    );
  }

  aiAppUpdateAngleUI();

  if (showGradient) {
    aiAppRefreshGradientUI(false);
  } else if (syncSwatch) {
    aiAppSyncCustomColor(hex);
  }
}

function aiAppApplyColorChange(hex, alpha) {
  if (hex) {
    aiAppSetHsvFromHex(hex);
  }
  if (typeof alpha === "number") {
    aiAppColorPopupState.alpha = aiAppNormalizeAlphaValue(alpha);
  }

  if (aiAppColorPopupState.mode === "solid" || !aiAppColorPopupState.allowGradient) {
    aiAppUpdatePopupUI(false);
    return;
  }

  if (!aiAppColorPopupState.stops.length) {
    aiAppColorPopupState.stops = aiAppGetStopsFromSolid(aiAppGetCurrentHexFromState());
    aiAppColorPopupState.activeStop = 0;
  }

  var activeStop = aiAppColorPopupState.stops[aiAppColorPopupState.activeStop];
  if (activeStop) {
    activeStop.color = aiAppGetCurrentHexFromState();
    activeStop.alpha = aiAppColorPopupState.alpha;
  }

  aiAppUpdatePopupUI(false);
}

function aiAppSetMode(mode) {
  if (!aiAppColorPopupState.allowGradient) {
    mode = "solid";
  }
  if (mode !== "linear" && mode !== "radial") {
    mode = "solid";
  }
  aiAppColorPopupState.mode = mode;
  if (mode !== "solid") {
    if (!aiAppColorPopupState.stops.length) {
      aiAppColorPopupState.stops = aiAppGetStopsFromSolid(aiAppGetCurrentHexFromState());
    }
    aiAppColorPopupState.activeStop = Math.max(
      0,
      Math.min(aiAppColorPopupState.activeStop, aiAppColorPopupState.stops.length - 1)
    );
    var activeStop = aiAppColorPopupState.stops[aiAppColorPopupState.activeStop];
    if (activeStop) {
      aiAppSetHsvFromHex(activeStop.color);
      aiAppColorPopupState.alpha = aiAppNormalizeAlphaValue(activeStop.alpha);
    }
  }
  aiAppUpdatePopupUI(false);
}

function aiAppPositionPopup(popup, trigger) {
  if (!popup || !trigger) return;
  var rect = trigger.getBoundingClientRect();
  popup.style.visibility = "hidden";
  popup.classList.remove("ai-app-hidden");
  popup.setAttribute("aria-hidden", "false");
  popup.style.left = "0px";
  popup.style.top = "0px";
  var popupRect = popup.getBoundingClientRect();
  var top = rect.bottom + 8;
  var left = rect.left;
  var maxLeft = window.innerWidth - popupRect.width - 12;
  left = Math.max(12, Math.min(left, maxLeft));
  var maxTop = window.innerHeight - popupRect.height - 12;
  if (top > maxTop && rect.top - popupRect.height - 8 > 12) {
    top = rect.top - popupRect.height - 8;
  }
  top = Math.max(12, Math.min(top, maxTop));
  popup.style.top = top + "px";
  popup.style.left = left + "px";
  popup.style.visibility = "visible";
}

function aiAppCloseColorPopup() {
  var elements = aiAppGetColorPopupElements();
  if (!elements) return;
  elements.popup.classList.add("ai-app-hidden");
  elements.popup.setAttribute("aria-hidden", "true");
  if (elements.modeMenu) {
    elements.modeMenu.classList.add("ai-app-hidden");
  }
  aiAppColorPopupState.isOpen = false;
  aiAppColorPopupState.triggerEl = null;
  aiAppColorPopupState.syncSwatchLabel = null;
  aiAppColorPopupState.draftSnapshot = null;
}

function aiAppOpenColorPopup(trigger, sourceSwatchLabel) {
  if (!trigger) return;
  var elements = aiAppGetColorPopupElements();
  if (!elements) return;

  var fieldName = trigger.getAttribute("data-color-field");
  if (!fieldName) return;

  aiAppColorPopupState.fieldName = fieldName;
  aiAppColorPopupState.allowGradient =
    trigger.getAttribute("data-allow-gradient") === "1";
  aiAppColorPopupState.triggerEl = trigger;
  aiAppColorPopupState.syncSwatchLabel = sourceSwatchLabel || null;

  var lastSwatchValue = aiAppGetLastSwatchValue(fieldName);
  var selectedRadio = document.querySelector(
    'input[name="' + fieldName + '"]:checked'
  );
  var selectedValue = selectedRadio
    ? aiAppParseColorValue(selectedRadio.value)
    : null;

  var baseHex = aiAppResolvePickerHex(
    sourceSwatchLabel && sourceSwatchLabel.querySelector('input[type="radio"]')
      ? sourceSwatchLabel.querySelector('input[type="radio"]').value
      : lastSwatchValue
  );

  if (
    aiAppColorPopupState.allowGradient &&
    selectedValue &&
    typeof selectedValue === "object" &&
    selectedValue.type === "gradient"
  ) {
    var normalized = aiAppNormalizeGradientData(selectedValue) || selectedValue;
    aiAppColorPopupState.mode = normalized.mode === "radial" ? "radial" : "linear";
    aiAppColorPopupState.angle =
      typeof normalized.angle === "number" ? aiAppClamp(normalized.angle, 0, 360) : 90;
    aiAppColorPopupState.stops = aiAppNormalizeStopsArray(normalized.stops || []);
    if (aiAppColorPopupState.stops.length < 2) {
      aiAppColorPopupState.stops = aiAppGetStopsFromSolid(baseHex);
    }
    aiAppColorPopupState.activeStop = 0;
    var activeStop = aiAppColorPopupState.stops[0];
    if (activeStop) {
      aiAppSetHsvFromHex(activeStop.color);
      aiAppColorPopupState.alpha = aiAppNormalizeAlphaValue(activeStop.alpha);
    }
  } else if (
    selectedValue &&
    typeof selectedValue === "object" &&
    selectedValue.type === "solid"
  ) {
    aiAppColorPopupState.mode = "solid";
    aiAppColorPopupState.angle = 90;
    var selectedSolid = aiAppNormalizeSolidData(selectedValue) || selectedValue;
    aiAppSetHsvFromHex(selectedSolid.color);
    aiAppColorPopupState.alpha = aiAppNormalizeAlphaValue(selectedSolid.alpha);
    if (aiAppColorPopupState.allowGradient) {
      aiAppColorPopupState.stops = aiAppGetStopsFromSolid(selectedSolid.color);
      aiAppColorPopupState.activeStop = 0;
    } else {
      aiAppColorPopupState.stops = [];
      aiAppColorPopupState.activeStop = 0;
    }
  } else {
    aiAppColorPopupState.mode = "solid";
    aiAppColorPopupState.angle = 90;
    var solidColorInfo = aiAppResolvePickerColorInfo(
      selectedRadio ? selectedRadio.value : lastSwatchValue
    );
    var solidHex = solidColorInfo.hex || baseHex;
    aiAppSetHsvFromHex(solidHex);
    aiAppColorPopupState.alpha = solidColorInfo.alpha;
    if (aiAppColorPopupState.allowGradient) {
      aiAppColorPopupState.stops = aiAppGetStopsFromSolid(solidHex);
      aiAppColorPopupState.activeStop = 0;
    } else {
      aiAppColorPopupState.stops = [];
      aiAppColorPopupState.activeStop = 0;
    }
  }

  aiAppColorPopupState.draftSnapshot = aiAppCloneColorPopupSnapshot(
    aiAppColorPopupState
  );

  aiAppColorPopupState.suppressSync = true;
  aiAppUpdatePopupUI(false);
  aiAppColorPopupState.suppressSync = false;

  aiAppPositionPopup(elements.popup, trigger);
  aiAppColorPopupState.isOpen = true;
}

function aiAppFindColorTrigger(target) {
  var node = target;
  while (node && node !== document) {
    if (node.classList && node.classList.contains("ai-app-color-trigger")) {
      return node;
    }
    node = node.parentNode;
  }
  return null;
}

function aiAppFindColorSwatchLabel(target) {
  var node = target;
  while (node && node !== document) {
    if (
      node.tagName === "LABEL" &&
      node.classList &&
      node.classList.contains("color-container") &&
      !node.classList.contains("ai-app-color-trigger") &&
      node.querySelector('input[type="radio"]')
    ) {
      return node;
    }
    node = node.parentNode;
  }
  return null;
}

function aiAppGetColorTriggerByFieldName(fieldName) {
  if (!fieldName) return null;
  return document.querySelector(
    '.select-color.ai-app-color-trigger[data-color-field="' + fieldName + '"]'
  );
}

function aiAppStartStopDrag(index, event) {
  var elements = aiAppGetColorPopupElements();
  if (!elements || !elements.gradientStops) return;
  aiAppColorPopupState.activeStop = index;

  function onMove(e) {
    var rect = elements.gradientStops.getBoundingClientRect();
    var percent = ((e.clientX - rect.left) / rect.width) * 100;
    percent = aiAppClamp(percent, 0, 100);
    aiAppColorPopupState.stops[index].pos = percent;
    aiAppRefreshGradientUI(false);
  }

  function onUp() {
    document.removeEventListener("pointermove", onMove);
    document.removeEventListener("pointerup", onUp);
  }

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

function aiAppBindDrag(element, onMove) {
  if (!element) return;
  element.addEventListener("pointerdown", function (event) {
    event.preventDefault();
    onMove(event);

    function handleMove(e) {
      onMove(e);
    }

    function handleUp() {
      document.removeEventListener("pointermove", handleMove);
      document.removeEventListener("pointerup", handleUp);
    }

    document.addEventListener("pointermove", handleMove);
    document.addEventListener("pointerup", handleUp);
  });
}

function aiAppInitColorPopup() {
  var elements = aiAppGetColorPopupElements();
  if (!elements || !elements.popup) return;
  if (elements.popup.dataset.aiAppInitialized === "1") return;
  elements.popup.dataset.aiAppInitialized = "1";

  if (elements.closeButton) {
    elements.closeButton.addEventListener("click", function (event) {
      event.preventDefault();
      aiAppCloseColorPopup();
    });
  }

  if (elements.modeButton) {
    elements.modeButton.addEventListener("click", function (event) {
      event.preventDefault();
      if (!aiAppColorPopupState.allowGradient) return;
      elements.modeMenu.classList.toggle("ai-app-hidden");
      elements.modeButton.setAttribute(
        "aria-expanded",
        elements.modeMenu.classList.contains("ai-app-hidden") ? "false" : "true"
      );
    });
  }

  elements.modeOptions.forEach(function (option) {
    option.addEventListener("click", function (event) {
      event.preventDefault();
      if (!aiAppColorPopupState.allowGradient) return;
      var mode = option.dataset.mode || "solid";
      elements.modeMenu.classList.add("ai-app-hidden");
      aiAppSetMode(mode);
    });
  });

  if (elements.gradientBar) {
    elements.gradientBar.addEventListener("click", function (event) {
      if (!aiAppColorPopupState.allowGradient) return;
      if (aiAppColorPopupState.mode === "solid") return;
      if (event.target.closest(".ai-app-color-stop")) return;
      var rect = elements.gradientBar.getBoundingClientRect();
      var percent = ((event.clientX - rect.left) / rect.width) * 100;
      percent = aiAppClamp(percent, 0, 100);
      var newStop = {
        color: aiAppGetCurrentHexFromState(),
        alpha: aiAppNormalizeAlphaValue(aiAppColorPopupState.alpha),
        pos: percent
      };
      aiAppColorPopupState.stops.push(newStop);
      aiAppColorPopupState.activeStop = aiAppColorPopupState.stops.length - 1;
      aiAppUpdatePopupUI(false);
    });
  }

  aiAppBindDrag(elements.panel, function (event) {
    var rect = elements.panel.getBoundingClientRect();
    var x = aiAppClamp((event.clientX - rect.left) / rect.width, 0, 1);
    var y = aiAppClamp((event.clientY - rect.top) / rect.height, 0, 1);
    aiAppColorPopupState.hsv.s = x;
    aiAppColorPopupState.hsv.v = 1 - y;
    aiAppApplyColorChange(aiAppGetCurrentHexFromState());
  });

  aiAppBindDrag(elements.hue, function (event) {
    var rect = elements.hue.getBoundingClientRect();
    var percent = aiAppClamp((event.clientX - rect.left) / rect.width, 0, 1);
    aiAppColorPopupState.hsv.h = percent * 360;
    aiAppApplyColorChange(aiAppGetCurrentHexFromState());
  });

  aiAppBindDrag(elements.alpha, function (event) {
    var rect = elements.alpha.getBoundingClientRect();
    var percent = aiAppClamp((event.clientX - rect.left) / rect.width, 0, 1);
    aiAppApplyColorChange(null, percent);
  });

  if (elements.angleDial) {
    aiAppBindDrag(elements.angleDial, function (event) {
      if (aiAppColorPopupState.mode !== "linear") return;
      var rect = elements.angleDial.getBoundingClientRect();
      var cx = rect.left + rect.width / 2;
      var cy = rect.top + rect.height / 2;
      var dx = event.clientX - cx;
      var dy = event.clientY - cy;
      var radians = Math.atan2(dy, dx);
      var deg = (radians * 180) / Math.PI + 90;
      if (deg < 0) deg += 360;
      aiAppColorPopupState.angle = Math.round(aiAppClamp(deg, 0, 360));
      aiAppUpdatePopupUI(false);
    });
  }

  if (elements.angleInput) {
    elements.angleInput.addEventListener("input", function () {
      if (aiAppColorPopupState.mode !== "linear") return;
      var value = parseFloat(elements.angleInput.value);
      if (isNaN(value)) return;
      aiAppColorPopupState.angle = aiAppClamp(value, 0, 360);
      aiAppUpdatePopupUI(false);
    });
  }

  if (elements.angleRotate) {
    elements.angleRotate.addEventListener("click", function (event) {
      event.preventDefault();
      if (aiAppColorPopupState.mode !== "linear") return;
      var nextAngle = (aiAppColorPopupState.angle || 0) + 45;
      aiAppColorPopupState.angle = nextAngle % 360;
      aiAppUpdatePopupUI(false);
    });
  }

  if (elements.hexInput) {
    elements.hexInput.addEventListener("input", function () {
      var normalized = aiAppNormalizeHexInput(elements.hexInput.value);
      if (!normalized) return;
      aiAppApplyColorChange(normalized);
    });
  }

  if (elements.opacityInput) {
    elements.opacityInput.addEventListener("input", function () {
      var value = elements.opacityInput.value.toString().replace("%", "");
      var percent = parseFloat(value);
      if (isNaN(percent)) return;
      aiAppApplyColorChange(null, aiAppClamp(percent, 0, 100) / 100);
    });
  }

  if (elements.applyButton) {
    elements.applyButton.addEventListener("click", function (event) {
      event.preventDefault();
      aiAppCommitColorPopupChanges();
    });
  }

  if (elements.resetButton) {
    elements.resetButton.addEventListener("click", function (event) {
      event.preventDefault();
      aiAppResetColorPopupChanges();
    });
  }

  if (elements.angleTrashButton) {
    elements.angleTrashButton.addEventListener("click", function (event) {
      event.preventDefault();
      aiAppRemoveSelectedGradientStop();
    });
  }

  if (elements.footerTrashButton) {
    elements.footerTrashButton.addEventListener("click", function (event) {
      event.preventDefault();
      aiAppRemoveSelectedGradientStop();
    });
  }

  if (!window.aiAppColorPopupDelegated) {
    window.aiAppColorPopupDelegated = true;
    document.addEventListener("click", function (event) {
      var trigger = aiAppFindColorTrigger(event.target);
      if (trigger) {
        event.preventDefault();
        event.stopPropagation();
        aiAppOpenColorPopup(trigger);
        return;
      }
    });
  }

  if (!window.aiAppColorPopupMouseBound) {
    window.aiAppColorPopupMouseBound = true;
    document.addEventListener("mousedown", function (event) {
      if (!aiAppColorPopupState.isOpen) return;
      var currentElements = aiAppGetColorPopupElements();
      if (
        (currentElements && currentElements.popup.contains(event.target)) ||
        aiAppFindColorTrigger(event.target)
      ) {
        return;
      }
      aiAppCloseColorPopup();
    });
  }

  if (!window.aiAppColorPopupEscapeBound) {
    window.aiAppColorPopupEscapeBound = true;
    document.addEventListener("keydown", function (event) {
      if (event.key === "Escape") {
        aiAppCloseColorPopup();
      }
    });
  }

  if (!window.aiAppColorPopupPositionBound) {
    window.aiAppColorPopupPositionBound = true;
    var scheduled = false;
    var scheduleReposition = function () {
      if (!aiAppColorPopupState.isOpen || !aiAppColorPopupState.triggerEl) return;
      if (scheduled) return;
      scheduled = true;
      window.requestAnimationFrame(function () {
        scheduled = false;
        var els = aiAppGetColorPopupElements();
        if (!els) return;
        aiAppPositionPopup(els.popup, aiAppColorPopupState.triggerEl);
      });
    };
    window.addEventListener("resize", scheduleReposition);
    window.addEventListener("scroll", scheduleReposition, true);
  }
}

if (document.readyState === "loading") {
  document.addEventListener("DOMContentLoaded", aiAppInitColorPopup);
} else {
  aiAppInitColorPopup();
}
