;(function (window, document) {
  "use strict";

  const COUNTER_SELECTOR = ".admin-field-counter";
  const GUIDANCE_SELECTOR = ".admin-upload-guidance";
  const COUNTER_BOUND_KEY = "adminCounterBound";
  const AUTO_GUIDANCE_ATTR = "data-admin-upload-guidance";
  const OBSERVER_BOUND_KEY = "__adminFormHelpersObserver";
  let generatedFieldToken = 0;

  const FIELD_RULES = {
    "/admin/about-us": [
      { selector: "#heroTitle", maxLength: 72 },
      { selector: "#heroBreadcrumb", maxLength: 120 },
      { selector: "#heroBackgroundImage", maxLength: 255 },
      { selector: "#introSubheading", maxLength: 40 },
      { selector: "#introHeading", maxLength: 72 },
      { selector: "#introDescription", maxLength: 260 },
      { selector: "#introImage", maxLength: 255 },
      { selector: "#missionSubheading", maxLength: 40 },
      { selector: "#missionHeading", maxLength: 72 },
      { selector: "#missionDescription", maxLength: 260 },
      { selector: "#missionCtaLabel", maxLength: 32 },
      { selector: "#missionCtaHref", maxLength: 255 },
      { selector: "[id^='missionImg_']", maxLength: 255 },
      { selector: "#featuresSubheading", maxLength: 40 },
      { selector: "#featuresHeading", maxLength: 72 },
      { selector: "#featuresDescription", maxLength: 260 },
      { selector: "#featuresBgImage", maxLength: 255 },
      { selector: "#featuresImage", maxLength: 255 },
      { selector: "#featuresCtaLabel", maxLength: 32 },
      { selector: "#featuresCtaHref", maxLength: 255 },
      { selector: "[id^='missionItemLabel_']", maxLength: 48 },
      { selector: "[id^='missionItemDescription_']", maxLength: 160 },
      { selector: "[id^='missionItemIcon_']", maxLength: 255 },
      { selector: "[id^='missionFeature_']", maxLength: 96 },
      { selector: "[id^='featureItemTitle_']", maxLength: 48 },
      { selector: "[id^='featureItemDescription_']", maxLength: 160 },
      { selector: "[id^='featureItemIcon_']", maxLength: 255 },
      { selector: "#newsSubheading", maxLength: 40 },
      { selector: "#newsHeading", maxLength: 72 },
      { selector: "#newsCtaLabel", maxLength: 32 },
      { selector: "#newsCtaHref", maxLength: 255 },
    ],
    "/admin/booking": [
      { selector: "#heroBackgroundImage", maxLength: 255 },
      { selector: "#heroTitle", maxLength: 72 },
      { selector: "#searchBarLocationLabel", maxLength: 32 },
      { selector: "#searchBarHolidaySeasonLabel", maxLength: 32 },
      { selector: "#searchBarSearchButtonText", maxLength: 24 },
      { selector: "input[name^='locationValue_']", maxLength: 32 },
      { selector: "input[name^='locationLabel_']", maxLength: 48 },
      { selector: "input[name^='holidayValue_']", maxLength: 32 },
      { selector: "input[name^='holidayLabel_']", maxLength: 48 },
      { selector: "#filterPanelTitle", maxLength: 48 },
      { selector: "#filterPanelPriceTitle", maxLength: 40 },
      { selector: "#filterPanelPriceLabel", maxLength: 32 },
      { selector: "#filterPanelPricePlaceholder", maxLength: 32 },
      { selector: "#filterPanelActivitiesTitle", maxLength: 40 },
      { selector: "#filterPanelAgeTitle", maxLength: 40 },
      { selector: "#filterPanelAgeSelectPlaceholder", maxLength: 32 },
      { selector: "#filterPanelRatingTitle", maxLength: 40 },
      { selector: "#filterPanelResetButtonText", maxLength: 24 },
      { selector: "input[name^='ratingValue_']", maxLength: 8 },
      { selector: "input[name^='ratingLabel_']", maxLength: 32 },
      { selector: "input[name^='programValue_']", maxLength: 32 },
      { selector: "input[name^='programLabel_']", maxLength: 48 },
      { selector: "input[name^='campName_']", maxLength: 72 },
      { selector: "input[name^='campPriceText_']", maxLength: 32 },
      { selector: "input[name^='campProgram_']", maxLength: 32 },
      { selector: "input[name^='campImage_']", maxLength: 255 },
      { selector: "input[name^='campLink_']", maxLength: 255 },
      { selector: "input[name^='discountName_']", maxLength: 48 },
      { selector: "textarea[name^='discountDescription_']", maxLength: 180 },
      { selector: "input[name^='voucherCode_']", maxLength: 24 },
      { selector: "input[name^='voucherDescription_']", maxLength: 120 },
      { selector: "[name='formTitle']", maxLength: 64 },
      { selector: "[name='formSubtitle']", maxLength: 48 },
      { selector: "[name^='stepTitle_']", maxLength: 64 },
      { selector: "[name^='sectionTitle_']", maxLength: 64 },
      { selector: "[name^='fieldLabel_']", maxLength: 48 },
      { selector: "[name^='fieldName_']", maxLength: 32 },
      { selector: "[name^='fieldPlaceholder_']", maxLength: 72 },
      { selector: "[name^='validationMessage_']", maxLength: 120 },
    ],
    "/admin/pricing": [
      { selector: "#heroBackgroundImage", maxLength: 255 },
      { selector: "#heroTitle", maxLength: 72 },
      { selector: "#pricingSectionSubtitle", maxLength: 40 },
      { selector: "#pricingSectionHeading", maxLength: 72 },
      { selector: "#pricingSectionDescription", maxLength: 220 },
      { selector: ".plan-name", maxLength: 40 },
      { selector: ".plan-price", maxLength: 16 },
      { selector: ".plan-currency", maxLength: 8 },
      { selector: ".plan-period", maxLength: 12 },
      { selector: ".plan-button-text", maxLength: 32 },
      { selector: ".plan-button-link", maxLength: 255 },
      { selector: ".plan-button-icon", maxLength: 64 },
      { selector: ".plan-features", maxLength: 320 },
      { selector: "#testimonialsSubtitle", maxLength: 40 },
      { selector: "#testimonialsHeading", maxLength: 72 },
      { selector: "#testimonialsButtonText", maxLength: 32 },
      { selector: "#testimonialsButtonLink", maxLength: 255 },
      { selector: "#testimonialsButtonIcon", maxLength: 64 },
      { selector: "#testimonialsImage", maxLength: 255 },
      { selector: ".testimonial-name", maxLength: 48 },
      { selector: ".testimonial-role", maxLength: 48 },
      { selector: ".testimonial-content", maxLength: 220 },
    ],
    "/admin/visa": [
      { selector: "input[name='name']", maxLength: 40 },
      { selector: "input[name='icon']", maxLength: 255 },
      { selector: "input[name='services[]']", maxLength: 56 },
      { selector: "input[name='detail_title']", maxLength: 72 },
      { selector: "input[name='mainImage']", maxLength: 255 },
      { selector: "textarea[name='description']", maxLength: 360 },
      { selector: "textarea[name='additionalInfo']", maxLength: 360 },
      { selector: "input[name='tagline']", maxLength: 72 },
      { selector: "input[name^='visa_title_']", maxLength: 56 },
      { selector: "textarea[name^='visa_desc_']", maxLength: 220 },
      { selector: "input[name='process_title']", maxLength: 72 },
      { selector: "input[name='step_title[]']", maxLength: 56 },
      { selector: "textarea[name='step_desc[]']", maxLength: 180 },
      { selector: "input[name='bannerImageGallery']", maxLength: 255 },
      { selector: "input[name='category_title[]']", maxLength: 56 },
      { selector: "textarea[name='category_desc[]']", maxLength: 180 },
      { selector: "input[name='related_title[]']", maxLength: 56 },
      { selector: "textarea[name='related_desc[]']", maxLength: 180 },
      { selector: "input[name='related_file[]']", maxLength: 255 },
      { selector: "input[name='contact_title']", maxLength: 72 },
      { selector: "input[name='contact_phone']", maxLength: 32 },
      { selector: "input[name='contact_email']", maxLength: 120 },
      { selector: "input[name='contact_address']", maxLength: 160 },
      { selector: "input[name='contact_image']", maxLength: 255 },
    ],
    "/admin/activity/*": [
      { selector: "input[name='heroTitle']", maxLength: 72 },
      { selector: "input[name='heroBannerImage']", maxLength: 255 },
      { selector: "input[name='name']", maxLength: 72 },
      { selector: "input[name='priceText']", maxLength: 32 },
      { selector: "input[name='link']", maxLength: 255 },
      { selector: "input[name='program']", maxLength: 32 },
      { selector: "#customLocations", maxLength: 120 },
      { selector: "input[name='image']", maxLength: 255 },
      { selector: "input[name='campDetailHeroTitle']", maxLength: 72 },
      { selector: "input[name='campDetailHeroBgImage']", maxLength: 255 },
      { selector: "input[name='campDetailBasicInfoLocation']", maxLength: 48 },
      { selector: "textarea[name='campDetailBasicInfoAgeRange']", maxLength: 120 },
      { selector: "input[name='campDetailBasicInfoAccommodationType']", maxLength: 72 },
      { selector: "input[name='campDetailBasicInfoCareLevel']", maxLength: 72 },
      { selector: "input[name='campDetailBasicInfoLanguages']", maxLength: 72 },
    ],
    "/admin/activity": [],
  };

  const GUIDANCE_RULES = {
    "/admin/about-us": [
      {
        selector: "#heroBackgroundImage",
        title: "Upload guidance",
        lines: [
          "Displayed as a wide page hero.",
          "Recommended upload: at least 1920x700px.",
        ],
      },
      {
        selector: "#introImage",
        title: "Upload guidance",
        lines: [
          "Displayed around 596x787px on desktop.",
          "Recommended upload: at least 1200x1600px.",
        ],
      },
      {
        selector: "#featuresImage",
        title: "Upload guidance",
        lines: [
          "Displayed around 375x419px on desktop.",
          "Recommended upload: at least 750x840px.",
        ],
      },
    ],
    "/admin/booking": [
      {
        selector: "#heroBackgroundImage",
        title: "Upload guidance",
        lines: [
          "Booking page hero background.",
          "Recommended upload: at least 1920x700px.",
        ],
      },
      {
        selector: "input[name^='campImage_']",
        title: "Upload guidance",
        lines: [
          "Used in booking camp cards.",
          "Recommended upload: a landscape image at 704x432px or larger.",
        ],
      },
    ],
    "/admin/pricing": [
      {
        selector: "#heroBackgroundImage",
        title: "Upload guidance",
        lines: [
          "Pricing page hero background.",
          "Recommended upload: at least 1920x700px.",
        ],
      },
    ],
    "/admin/visa": [
      {
        selector: "input[name='icon']",
        title: "Upload guidance",
        lines: [
          "Displayed as a small country flag or icon.",
          "Prefer SVG; otherwise use a square image at 96x96px or larger.",
        ],
      },
      {
        selector: "input[name='mainImage'], input[name='bannerImageGallery'], input[name='contact_image'], input[name='related_file[]']",
        title: "Upload guidance",
        lines: [
          "Used in visa detail content blocks.",
          "Recommended upload: at least 1000x750px for primary imagery and 800x600px for supporting images.",
        ],
      },
    ],
    "/admin/activity/*": [
      {
        selector: "input[name='heroBannerImage'], input[name='campDetailHeroBgImage']",
        title: "Upload guidance",
        lines: [
          "Activity page hero-style image.",
          "Recommended upload: at least 1920x700px.",
        ],
      },
      {
        selector: "input[name='image']",
        title: "Upload guidance",
        lines: [
          "Used in activity listing cards.",
          "Recommended upload: a landscape image at 704x432px or larger.",
        ],
      },
    ],
    "/admin/home": [
      {
        selector: "#whyChooseUsMainImage",
        title: "Upload guidance",
        lines: [
          "Displayed around 318x347px on desktop.",
          "Recommended upload: at least 750x820px.",
        ],
      },
      {
        selector: "#whyChooseUsSecondaryImage",
        title: "Upload guidance",
        lines: [
          "Displayed around 363x380px on desktop.",
          "Recommended upload: at least 760x800px.",
        ],
      },
      {
        selector: "#testimonialsVideoThumbnail",
        title: "Upload guidance",
        lines: [
          "Displayed around 416x370px on desktop.",
          "Recommended upload: at least 832x740px.",
        ],
      },
      {
        selector: "[id^='testimonialsAvatar_']",
        title: "Upload guidance",
        lines: [
          "Displayed around 48x48px.",
          "Recommended upload: 96x96px or 128x128px square.",
        ],
      },
      {
        selector: "#visaCountriesFlag_0",
        title: "Upload guidance",
        lines: [
          "Displayed around 840x830px on desktop.",
          "Recommended upload: at least 1000x1000px.",
        ],
      },
    ],
    "*": [
      {
        selector: ".btn-upload-image",
        title: "Upload guidance",
        lines: [
          "Use a clear, high-resolution image that matches the visible frame.",
          "Prefer SVG for logos or icons and at least 2x the displayed size for raster uploads.",
        ],
      },
    ],
  };

  function toScope(scope) {
    return scope && scope.querySelectorAll ? scope : document;
  }

  function normalizeText(value) {
    return String(value ?? "").replace(/\s+/g, " ").trim();
  }

  function buildDescriptor(input) {
    return [
      input?.id,
      input?.name,
      input?.placeholder,
      input?.closest(".col-md-12, .col-md-9, .col-md-6, .col-md-5, .col-md-4, .col-md-3, .col-md-2, .col-lg-12, .col-lg-8, .col-lg-6, .col-lg-4, .col-12")?.querySelector("label")?.textContent,
    ]
      .filter(Boolean)
      .join(" ")
      .replace(/([a-z])([A-Z])/g, "$1 $2")
      .replace(/[_[\].-]+/g, " ")
      .toLowerCase();
  }

  function isUploadDescriptor(descriptor) {
    return /(?:^|[^a-z])(image|icon|logo|background|banner|thumbnail|avatar|flag|path|src|file)(?:[^a-z]|$)/.test(descriptor);
  }

  function resolveUploadTarget(targetId, anchor) {
    if (targetId) {
      const byId = document.getElementById(targetId);
      if (byId) {
        return byId;
      }

      if (window.CSS && typeof window.CSS.escape === "function") {
        const byName = document.querySelector(`[name="${window.CSS.escape(targetId)}"]`);
        if (byName) {
          return byName;
        }
      }
    }

    return anchor || null;
  }

  function hasManualUploadHint(target) {
    const anchor = resolveGuidanceAnchor(target);
    if (!anchor) {
      return false;
    }

    const host =
      anchor.closest(".form-group, .mb-3, .col-md-12, .col-md-9, .col-md-6, .col-md-5, .col-md-4, .col-md-3, .col-md-2, .col-lg-12, .col-lg-8, .col-lg-6, .col-lg-4, .col-12") ||
      anchor.parentElement;
    if (!host) {
      return false;
    }

    const candidates = [
      ...host.querySelectorAll("small.text-muted, small.form-text, .form-text, .text-muted"),
      ...Array.from(host.nextElementSibling ? host.nextElementSibling.querySelectorAll?.("small.text-muted, small.form-text, .form-text, .text-muted") || [] : []),
    ];

    return candidates.some((node) => {
      if (node.classList?.contains("admin-field-counter") || node.classList?.contains("admin-upload-guidance")) {
        return false;
      }

      const text = normalizeText(node.textContent || "");
      return /recommended|min(imum)? upload|upload|svg|png|webp|render|displayed|size|preview|icon/i.test(text);
    });
  }

  function getFieldLimit(input) {
    const dataMax = Number(input?.dataset?.maxlength);
    if (Number.isFinite(dataMax) && dataMax > 0) {
      return dataMax;
    }

    const attrMax = Number(input?.getAttribute("maxlength"));
    if (Number.isFinite(attrMax) && attrMax > 0) {
      return attrMax;
    }

    return null;
  }

  function getWordLimit(input) {
    const dataMax = Number(input?.dataset?.maxwords);
    if (Number.isFinite(dataMax) && dataMax > 0) {
      return dataMax;
    }

    return null;
  }

  function getFieldToken(input) {
    if (!input) {
      return "";
    }

    if (input.id) {
      return `id:${input.id}`;
    }

    if (input.name) {
      const indexWithinNameGroup = Array.from(document.querySelectorAll(`[name="${CSS.escape(input.name)}"]`)).indexOf(input);
      return `name:${input.name}:${Math.max(indexWithinNameGroup, 0)}`;
    }

    if (!input.dataset.adminFieldToken) {
      generatedFieldToken += 1;
      input.dataset.adminFieldToken = `generated:${generatedFieldToken}`;
    }

    return input.dataset.adminFieldToken;
  }

  function isDragDropField(element) {
    if (!element || !element.closest) {
      return false;
    }

    return Boolean(
      element.closest(
        ".social-link-item, .floating-contact-action-item, .menu-links-sortable, .social-links-sortable, .sortable-container, .sortable-list, .sortable-item, [data-top-menu-index], [data-top-social-index], [data-bottom-menu-index], [data-bottom-social-index], [draggable='true']",
      ),
    );
  }

  function refreshCountersWithin(scope) {
    if (!scope || !scope.querySelectorAll) {
      return;
    }

    scope
      .querySelectorAll("input[data-maxlength], textarea[data-maxlength], input[data-maxwords], textarea[data-maxwords], input[maxlength], textarea[maxlength]")
      .forEach((field) => {
        if (field.dataset[COUNTER_BOUND_KEY] === "true") {
          updateCounter(field);
        }
      });
  }

  function getCounterRefreshScope(input) {
    if (!isDragDropField(input)) {
      return null;
    }

    return (
      input.closest(".floating-contact-action-item, .social-link-item, [data-top-menu-index], [data-top-social-index], [data-bottom-menu-index], [data-bottom-social-index]") ||
      input.closest(".menu-links-sortable, .social-links-sortable, .sortable-container, .sortable-list")
    );
  }

  function getCounterHost(input) {
    return (
      input.closest(".input-group") ||
      input.closest(".col, [class^='col-'], [class*=' col-']") ||
      input.parentElement ||
      input
    );
  }

  function ensureCounterElement(input) {
    const counterToken = getFieldToken(input);
    const existingAnywhere = counterToken ? document.querySelector(`[data-counter-for="${counterToken}"]`) : null;
    if (existingAnywhere) {
      return existingAnywhere;
    }

    const host = getCounterHost(input);
    const nextSibling = host.nextElementSibling;
    const matchingNextSibling =
      nextSibling &&
      nextSibling.matches(COUNTER_SELECTOR) &&
      nextSibling.dataset.counterFor === counterToken
        ? nextSibling
        : null;
    const existing = matchingNextSibling || host.querySelector(`${COUNTER_SELECTOR}[data-counter-for="${counterToken}"]`);

    if (existing) {
      return existing;
    }

    const counter = document.createElement("small");
    counter.className = "form-text admin-field-counter";
    counter.dataset.counterFor = counterToken;
    counter.setAttribute("aria-live", "polite");

    if (host.classList?.contains("input-group")) {
      host.insertAdjacentElement("afterend", counter);
    } else {
      host.appendChild(counter);
    }

    return counter;
  }

  function matchesPathKey(key, pathname) {
    if (key === "*") {
      return true;
    }

    if (key.endsWith("*")) {
      return pathname.startsWith(key.slice(0, -1));
    }

    return key === pathname;
  }

  function getPathRules(registry) {
    const pathname = window.location.pathname;
    return Object.keys(registry).reduce((rules, key) => {
      if (!matchesPathKey(key, pathname)) {
        return rules;
      }

      return rules.concat(registry[key] || []);
    }, []);
  }

  function findTargets(root, selector) {
    const targets = [];
    if (root.matches && root.matches(selector)) {
      targets.push(root);
    }
    if (root.querySelectorAll) {
      targets.push(...root.querySelectorAll(selector));
    }
    return targets;
  }

  function applyFieldRules(scope) {
    const root = toScope(scope);
    getPathRules(FIELD_RULES).forEach((rule) => {
      findTargets(root, rule.selector).forEach((input) => {
        if (rule.maxLength && !input.dataset.maxlength) {
          input.dataset.maxlength = String(rule.maxLength);
          input.setAttribute("maxlength", String(rule.maxLength));
        }
        if (rule.maxWords && !input.dataset.maxwords) {
          input.dataset.maxwords = String(rule.maxWords);
        }
      });
    });

    root.querySelectorAll("input, textarea").forEach((input) => {
      if (
        input.disabled ||
        input.type === "hidden" ||
        input.type === "file" ||
        input.dataset.maxlength ||
        input.dataset.maxwords ||
        input.getAttribute("maxlength")
      ) {
        return;
      }

      const type = (input.getAttribute("type") || "").toLowerCase();
      if (type && !["text", "email", "tel", "search", "url"].includes(type) && input.tagName !== "TEXTAREA") {
        return;
      }

      const descriptor = buildDescriptor(input);

      if (/json|editor|html|content-block|blocks/.test(descriptor)) {
        return;
      }

      let inferredMaxLength = 72;
      if (input.tagName === "TEXTAREA") {
        inferredMaxLength = /description|content|overview|additional info|quote|note|message|summary/.test(descriptor) ? 500 : 220;
      } else if (type === "email" || /email/.test(descriptor)) {
        inferredMaxLength = 120;
      } else if (type === "tel" || /phone|tel|mobile|whatsapp|zalo/.test(descriptor)) {
        inferredMaxLength = 32;
      } else if (/url|href|link/.test(descriptor) || isUploadDescriptor(descriptor)) {
        inferredMaxLength = 255;
      } else if (/slug|code|id/.test(descriptor)) {
        inferredMaxLength = 32;
      } else if (/title|heading|name|label|subtitle|platform/.test(descriptor)) {
        inferredMaxLength = 72;
      }

      input.dataset.maxlength = String(inferredMaxLength);
      input.setAttribute("maxlength", String(inferredMaxLength));
    });
  }

  function updateCounter(input) {
    const counter = ensureCounterElement(input);
    const maxLength = getFieldLimit(input);
    const maxWords = getWordLimit(input);
    const currentValue = normalizeText(input.value || "");
    const currentLength = currentValue.length;

    if (maxWords) {
      const words = currentValue ? currentValue.split(" ") : [];
      const currentWords = words.filter(Boolean).length;

      if (maxLength && currentLength > maxLength) {
        input.value = currentValue.slice(0, maxLength);
      }

      if (maxLength) {
        counter.textContent = `${currentWords}/${maxWords} words, ${Math.min(currentLength, maxLength)}/${maxLength} characters`;
        counter.classList.toggle("is-danger", currentWords >= maxWords || currentLength >= maxLength);
      } else {
        counter.textContent = `${currentWords}/${maxWords} words`;
        counter.classList.toggle("is-danger", currentWords >= maxWords);
      }
      return;
    }

    if (!maxLength) {
      counter.textContent = "";
      return;
    }

    if (currentLength > maxLength) {
      input.value = currentValue.slice(0, maxLength);
    }

    counter.textContent = `${Math.min(currentLength, maxLength)}/${maxLength} characters`;
    counter.classList.toggle("is-danger", currentLength >= maxLength);
  }

  function bindCounter(input) {
    if (!input || input.dataset[COUNTER_BOUND_KEY] === "true") {
      return;
    }

    input.dataset[COUNTER_BOUND_KEY] = "true";
    const syncCounter = () => {
      updateCounter(input);
      const refreshScope = getCounterRefreshScope(input);
      if (refreshScope) {
        refreshCountersWithin(refreshScope);
      }
    };

    syncCounter();
    input.addEventListener("input", syncCounter);
    input.addEventListener("change", syncCounter);
    input.addEventListener("blur", syncCounter);
    input.addEventListener("focus", syncCounter);
  }

  function buildGuidanceLines(options = {}) {
    const title = normalizeText(options.title) || "Upload guidance";
    const lines = Array.isArray(options.lines) ? options.lines.map(normalizeText).filter(Boolean) : [];

    if (!lines.length) {
      lines.push("Use a clear, high-resolution image that matches the visible frame.");
      lines.push("Prefer a file that is at least 2x the displayed size for crisp rendering.");
      lines.push("Keep the original aspect ratio unless the page explicitly asks for a crop.");
    }

    return { title, lines };
  }

  function resolveGuidanceAnchor(target) {
    if (!target) {
      return null;
    }

    if (typeof target === "string") {
      return document.querySelector(target);
    }

    if (target instanceof Element) {
      return target;
    }

    return null;
  }

  function renderUploadGuidance(target, options = {}) {
    const anchor = resolveGuidanceAnchor(target);
    if (!anchor) {
      return null;
    }

    const host = anchor.closest(".form-group, .mb-3, .col-md-12, .col-md-9, .col-md-6, .col-md-4, .col-md-3, .col-lg-12, .col-lg-8, .col-lg-6, .col-lg-4, .col-12") || anchor.parentElement;
    if (!host) {
      return null;
    }

    const matchingAnchorSibling =
      anchor.nextElementSibling &&
      anchor.nextElementSibling.matches(GUIDANCE_SELECTOR) &&
      anchor.nextElementSibling.dataset.guidanceFor === (options.for || "")
        ? anchor.nextElementSibling
        : null;
    const matchingHostSibling =
      host.nextElementSibling &&
      host.nextElementSibling.matches(GUIDANCE_SELECTOR) &&
      host.nextElementSibling.dataset.guidanceFor === (options.for || "")
        ? host.nextElementSibling
        : null;
    const existing =
      matchingAnchorSibling ||
      matchingHostSibling ||
      host.querySelector(`${GUIDANCE_SELECTOR}[data-guidance-for="${options.for || ""}"]`);
    if (existing) {
      return existing;
    }

    const payload = buildGuidanceLines(options);
    const note = document.createElement("div");
    note.className = "admin-upload-guidance";
    note.dataset.guidanceFor = options.for || "";
    note.setAttribute("role", "note");
    note.innerHTML = `
      <div class="admin-upload-guidance__title">${payload.title}</div>
      <ul class="admin-upload-guidance__list">
        ${payload.lines.map((line) => `<li>${line}</li>`).join("")}
      </ul>
    `;

    const insertionTarget = host !== anchor ? host : anchor;
    insertionTarget.insertAdjacentElement("afterend", note);
    return note;
  }

  function autoWireGuidance(scope) {
    const root = toScope(scope);
    root.querySelectorAll(`[${AUTO_GUIDANCE_ATTR}]`).forEach((anchor) => {
      const guidanceValue = anchor.getAttribute(AUTO_GUIDANCE_ATTR);
      if (guidanceValue === "false") {
        return;
      }

      if (isDragDropField(anchor)) {
        return;
      }

      if (hasManualUploadHint(anchor)) {
        return;
      }

      renderUploadGuidance(anchor, {
        for: anchor.id || anchor.dataset.targetInput || "",
        title: anchor.dataset.adminUploadGuidanceTitle || "Upload guidance",
        lines: anchor.dataset.adminUploadGuidance
          ? anchor.dataset.adminUploadGuidance.split("|").map((part) => part.trim())
          : undefined,
      });
    });
  }

  function applyGuidanceRules(scope) {
    const root = toScope(scope);
    getPathRules(GUIDANCE_RULES).forEach((rule) => {
      findTargets(root, rule.selector).forEach((anchor) => {
        if (isDragDropField(anchor)) {
          return;
        }

        if (hasManualUploadHint(anchor)) {
          return;
        }

        if (anchor.matches(".btn-upload-image")) {
          const targetId = anchor.dataset.targetInput;
          const target = resolveUploadTarget(targetId, anchor);
          renderUploadGuidance(target || anchor, {
            for: targetId || anchor.id || "",
            title: rule.title,
            lines: rule.lines,
          });
          return;
        }

        renderUploadGuidance(anchor, {
          for: anchor.id || anchor.name || "",
          title: rule.title,
          lines: rule.lines,
        });
      });
    });

    root.querySelectorAll("input[type='text'], textarea").forEach((input) => {
      if (isDragDropField(input)) {
        return;
      }

      const descriptor = buildDescriptor(input);

      if (!isUploadDescriptor(descriptor)) {
        return;
      }

      if (hasManualUploadHint(input)) {
        return;
      }

      const host =
        input.parentElement?.querySelector(".admin-upload-guidance") ||
        input.closest(".col-md-12, .col-md-6, .col-md-4, .col-lg-12, .col-lg-6, .col-lg-4, .col-12")?.querySelector(".admin-upload-guidance");
      if (host) {
        return;
      }

      renderUploadGuidance(input, {
        for: input.id || input.name || "",
        title: "Upload guidance",
        lines: [
          "Use a clear, high-resolution image sized for the frontend frame.",
          "Prefer SVG for logos or icons and at least 2x the displayed size for raster uploads.",
        ],
      });
    });
  }

  function observeMutations() {
    if (document.body[OBSERVER_BOUND_KEY]) {
      return;
    }

    const observer = new MutationObserver((mutations) => {
      mutations.forEach((mutation) => {
        mutation.addedNodes.forEach((node) => {
          if (!node || node.nodeType !== 1) {
            return;
          }
          init(node);
        });
      });
    });

    observer.observe(document.body, { childList: true, subtree: true });
    document.body[OBSERVER_BOUND_KEY] = true;
  }

  function init(scope = document) {
    const root = toScope(scope);

    applyFieldRules(root);
    root.querySelectorAll("input[data-maxlength], textarea[data-maxlength], input[data-maxwords], textarea[data-maxwords], input[maxlength], textarea[maxlength]").forEach(bindCounter);
    autoWireGuidance(root);
    applyGuidanceRules(root);
  }

  function refresh(scope = document) {
    init(scope);
  }

  function shouldAutoInit() {
    return document.body && document.body.dataset.adminHelpers === "true";
  }

  const api = {
    init,
    refresh,
    renderUploadGuidance,
    updateCounter,
  };

  window.AdminFormHelpers = api;

  if (shouldAutoInit()) {
    if (document.readyState === "loading") {
      window.addEventListener("load", () => {
        init(document);
        observeMutations();
      }, { once: true });
    } else {
      init(document);
      observeMutations();
    }
  }
})(window, document);
