(() => {
  const mount = (editor, { signal } = {}) => {
  const form = editor?.querySelector("[data-theme-form]");
  if (!editor || !form) return;
  const listenerOptions = signal ? { signal } : undefined;

  const previewRoots = () => Array.from(editor.querySelectorAll("[data-theme-preview-root]"));
  const tokenVariables = {
    bg1: "--bg-1",
    bg2: "--bg-2",
    bg3: "--bg-3",
    text: "--ink",
    muted: "--ink-soft",
    accent: "--sea",
    accentAlt: "--sun",
    success: "--lumi-success",
    warning: "--lumi-warning",
    danger: "--rose",
    info: "--lumi-info",
    surface: "--card",
    surface2: "--surface-2",
    surface3: "--surface-3",
    border: "--border",
    link: "--lumi-link",
    buttonBg: "--lumi-button-bg",
    buttonText: "--lumi-button-text",
    buttonHover: "--lumi-button-hover",
    inputBg: "--lumi-input-bg",
    inputBorder: "--lumi-input-border",
    inputText: "--lumi-input-text",
    focusRing: "--lumi-focus"
  };
  const metricVariables = {
    radius: ["--lumi-radius", "px"],
    shadowStrength: ["--lumi-shadow-strength", ""],
    spacingScale: ["--lumi-space-scale", ""]
  };
  const typographyVariables = {
    body: "--lumi-font-body",
    display: "--lumi-font-display",
    mono: "--lumi-font-mono",
    baseSize: ["--lumi-font-size-base", "px"],
    headingScale: ["--lumi-heading-scale", ""],
    controlScale: ["--lumi-control-scale", ""]
  };
  let popout = null;
  let previewMode = "light";

  const updateOutputs = () => {
    form.querySelectorAll('input[type="color"]').forEach((input) => {
      const output = input.closest("label")?.querySelector("output");
      if (output) output.value = input.value.toUpperCase();
    });
    form.querySelectorAll("[data-theme-metric]").forEach((input) => {
      const output = input.closest("label")?.querySelector("[data-range-output]");
      if (output) output.value = `${input.value}${input.dataset.unit || ""}`;
    });
    form.querySelectorAll("[data-theme-typography]").forEach((input) => {
      const output = input.closest("label")?.querySelector("[data-range-output]");
      if (output) output.value = `${input.value}${input.dataset.unit || ""}`;
    });
  };

  const buildPreviewVariables = () => {
    const variables = [];
    form.querySelectorAll(`[data-theme-mode="${previewMode}"]`).forEach((input) => {
      const variable = tokenVariables[input.dataset.themeToken];
      if (variable) variables.push([variable, input.value]);
    });
    form.querySelectorAll("[data-theme-role]").forEach((input) => {
      variables.push([`--role-${input.dataset.themeRole}`, input.value]);
    });
    form.querySelectorAll("[data-theme-metric]").forEach((input) => {
      const config = metricVariables[input.dataset.themeMetric];
      if (config) variables.push([config[0], `${input.value}${config[1]}`]);
    });
    form.querySelectorAll("[data-theme-font]").forEach((select) => {
      const variable = typographyVariables[select.dataset.themeFont];
      const stack = select.selectedOptions[0]?.dataset.fontStack;
      if (variable && stack) variables.push([variable, stack]);
    });
    form.querySelectorAll("[data-theme-typography]").forEach((input) => {
      const config = typographyVariables[input.dataset.themeTypography];
      if (config) variables.push([config[0], `${input.value}${config[1]}`]);
    });
    return variables;
  };

  const applyVariables = (target, variables) => {
    if (!target) return;
    target.dataset.colorScheme = previewMode;
    variables.forEach(([name, value]) => {
      target.style.setProperty(name, value);
    });
  };

  const applyPreview = () => {
    const variables = buildPreviewVariables();
    previewRoots().forEach((target) => applyVariables(target, variables));
    updateOutputs();
    updateWarnings();
    syncPopout(variables);
  };

  const parseHex = (value) => {
    const hex = String(value || "").replace("#", "");
    return [0, 2, 4].map((index) => Number.parseInt(hex.slice(index, index + 2), 16));
  };

  const luminance = (value) => {
    const channels = parseHex(value).map((channel) => {
      const normalized = channel / 255;
      return normalized <= 0.03928
        ? normalized / 12.92
        : Math.pow((normalized + 0.055) / 1.055, 2.4);
    });
    return 0.2126 * channels[0] + 0.7152 * channels[1] + 0.0722 * channels[2];
  };

  const contrastRatio = (left, right) => {
    const a = luminance(left);
    const b = luminance(right);
    return (Math.max(a, b) + 0.05) / (Math.min(a, b) + 0.05);
  };

  const getModeValue = (token) =>
    form.querySelector(`[data-theme-mode="${previewMode}"][data-theme-token="${token}"]`)?.value;

  const updateWarnings = () => {
    const panel = editor.querySelector("[data-theme-warnings]");
    if (!panel) return;
    const checks = [
      ["Text on surface", getModeValue("text"), getModeValue("surface")],
      ["Button text", getModeValue("buttonText"), getModeValue("buttonBg")],
      ["Input text", getModeValue("inputText"), getModeValue("inputBg")]
    ];
    const warnings = checks
      .map(([label, foreground, background]) => [label, contrastRatio(foreground, background)])
      .filter(([, ratio]) => Number.isFinite(ratio) && ratio < 4.5);
    panel.replaceChildren(
      ...warnings.map(([label, ratio]) => {
        const item = document.createElement("div");
        item.className = "theme-warning";
        item.textContent = `${label} contrast is ${ratio.toFixed(2)}:1. Save will reject values below 4.5:1.`;
        return item;
      })
    );
  };

  const syncPopout = (variables = buildPreviewVariables()) => {
    if (!popout || popout.closed) return;
    popout.document.documentElement.dataset.colorScheme = previewMode;
    variables.forEach(([name, value]) => {
      popout.document.documentElement.style.setProperty(name, value);
    });
  };

  const applyCanonicalTheme = (theme) => {
    if (!theme) return;
    const root = document.documentElement;
    const explicitScheme = root.dataset.colorScheme;
    const mode = explicitScheme === "dark" || (!explicitScheme && window.matchMedia("(prefers-color-scheme: dark)").matches)
      ? "dark"
      : "light";
    const values = theme[mode] || theme.light;
    Object.entries(tokenVariables).forEach(([field, variable]) => {
      if (values?.[field]) root.style.setProperty(variable, values[field]);
    });
    Object.entries(metricVariables).forEach(([field, [variable, unit]]) => {
      if (theme.metrics?.[field] !== undefined) root.style.setProperty(variable, `${theme.metrics[field]}${unit}`);
    });
    if (theme.typography) {
      root.style.setProperty("--lumi-font-body", theme.typography.bodyFontStack);
      root.style.setProperty("--lumi-font-display", theme.typography.displayFontStack);
      root.style.setProperty("--lumi-font-mono", theme.typography.monoFontStack);
      root.style.setProperty("--lumi-font-size-base", `${theme.typography.baseSize}px`);
      root.style.setProperty("--lumi-heading-scale", theme.typography.headingScale);
      root.style.setProperty("--lumi-control-scale", theme.typography.controlScale);
    }
    Object.entries(theme.role || {}).forEach(([role, value]) => root.style.setProperty(`--role-${role}`, value));
    document.body.dataset.themeId = theme.id || "";
    const activeStatus = document.querySelector("[data-active-theme-status]");
    if (activeStatus) activeStatus.textContent = `Active: ${theme.name}`;
  };

  const previewShell = () => `<!doctype html>
    <html lang="en">
      <head>
        <meta charset="utf-8">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <title>Lumi Theme Preview</title>
        <link rel="stylesheet" href="/lumi-tokens.css">
        <link rel="stylesheet" href="/styles.css">
        <link rel="stylesheet" href="/lumi-layout.css">
        <link rel="stylesheet" href="/lumi-components.css">
        <link rel="stylesheet" href="/theme-editor.css">
        <style>
          body{margin:0;background:radial-gradient(circle at 16% 8%,var(--bg-1),transparent 38%),var(--bg-2);font-family:var(--lumi-font-body);font-size:var(--lumi-font-size-base);color:var(--lumi-text)}
          .preview-app{display:grid;grid-template-columns:15rem minmax(0,1fr);min-height:100vh}
          .preview-sidebar{padding:var(--lumi-space-4);border-right:1px solid var(--lumi-border);background:var(--lumi-surface)}
          .preview-brand{display:flex;align-items:center;gap:var(--lumi-space-2);font:800 1rem var(--lumi-font-display)}
          .preview-logo{width:2.4rem;height:2.4rem;display:grid;place-items:center;border-radius:var(--lumi-radius-sm);background:var(--lumi-primary);color:var(--lumi-button-text)}
          .preview-nav{display:grid;gap:var(--lumi-space-2);margin-top:var(--lumi-space-5)}
          .preview-nav a{padding:var(--lumi-space-2);border-radius:var(--lumi-radius-sm);color:var(--lumi-text);text-decoration:none}
          .preview-nav a.active,.preview-nav a:hover{background:var(--lumi-surface-subtle);box-shadow:var(--lumi-shadow-sm)}
          .preview-page{display:grid;gap:var(--lumi-space-4);align-content:start;padding:var(--lumi-space-5)}
          .preview-grid{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:var(--lumi-space-4)}
          .preview-metric{display:grid;gap:var(--lumi-space-1)}
          .preview-modal-sample{position:relative;min-height:9rem;display:grid;place-items:center;border:1px dashed var(--lumi-border);border-radius:var(--lumi-radius-md);background:color-mix(in srgb,var(--lumi-surface-subtle) 80%,transparent)}
          .preview-modal-card{width:min(20rem,90%);padding:var(--lumi-space-4);border-radius:var(--lumi-radius-md);background:var(--lumi-surface);box-shadow:var(--lumi-shadow-lg)}
          @media (max-width:760px){.preview-app{grid-template-columns:1fr}.preview-sidebar{position:static;border-right:0;border-bottom:1px solid var(--lumi-border)}.preview-grid{grid-template-columns:1fr}}
        </style>
      </head>
      <body>
        <div class="preview-app">
          <aside class="preview-sidebar">
            <div class="preview-brand"><span class="preview-logo">L</span><span>Lumi Bot</span></div>
            <nav class="preview-nav" aria-label="Preview navigation">
              <a class="active" href="#dashboard">Dashboard</a>
              <a href="#settings">Settings</a>
              <a href="#logs">Logs</a>
              <a href="#ai">Lumi AI</a>
            </nav>
          </aside>
          <main class="preview-page">
            <section class="hero">
              <span class="eyebrow">Faithful preview</span>
              <h1>Community control center</h1>
              <p>Draft theme values are isolated to this preview until you save and apply the theme.</p>
              <div class="button-group"><button class="button">Primary action</button><button class="button subtle">Secondary</button></div>
            </section>
            <section class="preview-grid">
              <article class="card preview-metric"><span class="hint">Messages</span><strong>12,480</strong><span class="status-success">Healthy stream</span></article>
              <article class="card preview-metric"><span class="hint">Warnings</span><strong>3</strong><span class="status-warning">Needs review</span></article>
              <article class="card">
                <h2>Settings panel</h2>
                <label>Channel title<input value="Cozy Carnage" readonly></label>
                <label class="switch"><input class="switch-input" type="checkbox" checked><span class="switch-track"></span><span class="switch-text">Enabled toggle</span></label>
                <div class="is-unsaved" style="padding:var(--lumi-space-2);border-radius:var(--lumi-radius-sm)">Unsaved marker sample</div>
              </article>
              <article class="card">
                <h2>Logs table</h2>
                <div class="table-wrap"><table class="table"><thead><tr><th>Level</th><th>Message</th></tr></thead><tbody><tr><td><span class="status-danger">error</span></td><td>Webhook retry failed</td></tr><tr><td><span class="status-success">info</span></td><td>Command synced</td></tr></tbody></table></div>
              </article>
              <article class="card">
                <h2>State button</h2>
                <button class="button lumi-state-btn"><span class="lumi-state-btn-content"><span data-state-view="idle">Download</span><span data-state-view="loading" data-state-hidden="true"><span class="lumi-state-btn-spinner"></span>Downloading 64%</span><span data-state-view="success" data-state-hidden="true">Downloaded</span></span></button>
                <p><span class="badge">Badge</span> <span class="pill">Preview pill</span></p>
              </article>
              <article class="card preview-modal-sample">
                <div class="preview-modal-card"><h3>Modal sample</h3><p class="hint">Confirmation panels inherit theme surface, shadow, radius, and button tokens.</p><button class="button danger">Delete sample</button></div>
              </article>
            </section>
          </main>
        </div>
      </body>
    </html>`;

  form.addEventListener("input", applyPreview, listenerOptions);
  form.addEventListener("change", applyPreview, listenerOptions);
  form.addEventListener("lumi:form-saved", (event) => {
    const { theme, applied } = event.detail?.data || {};
    if (applied) applyCanonicalTheme(theme);
    applyPreview();
  }, listenerOptions);
  editor.querySelectorAll("[data-theme-preview-mode]").forEach((button) => {
    button.addEventListener("click", () => {
      previewMode = button.dataset.themePreviewMode;
      editor.querySelectorAll("[data-theme-preview-mode]").forEach((item) => {
        item.classList.toggle("is-selected", item === button);
      });
      applyPreview();
    }, listenerOptions);
  });

  editor.querySelector("[data-theme-reset]")?.addEventListener("click", () => {
    form.reset();
    applyPreview();
    window.LumiStateButton?.success(editor.querySelector("[data-theme-reset]"));
  }, listenerOptions);

  editor.querySelector("[data-theme-reset-to-base]")?.addEventListener("click", () => {
    form.querySelectorAll("[data-base-value]").forEach((input) => {
      input.value = input.dataset.baseValue;
    });
    applyPreview();
  }, listenerOptions);

  editor.querySelectorAll("[data-theme-popout]").forEach((button) => {
    button.addEventListener("click", () => {
      popout = window.open("", "lumi-theme-preview", "width=430,height=760,menubar=no,toolbar=no,location=no,status=no");
      const status = editor.querySelector("[data-theme-popout-status]");
      if (!popout) {
        if (status) status.textContent = "Pop-out preview was blocked by the browser.";
        return;
      }
      popout.document.open();
      popout.document.write(previewShell());
      popout.document.close();
      popout.focus?.();
      if (status) status.textContent = "Pop-out preview is open and updates with this editor.";
      syncPopout();
    }, listenerOptions);
  });

  applyPreview();
  return () => {
    if (popout && !popout.closed) popout.close();
  };
  };

  if (window.LumiPage) {
    window.LumiPage.register("theme-studio", {
      selector: "[data-theme-editor]",
      mount
    });
  } else {
    mount(document.querySelector("[data-theme-editor]"));
  }
})();
