const {
  useState: useStateCat,
  useEffect: useEffectCat,
  useRef: useRefCat,
} = React;

// ── helpers ────────────────────────────────────────────────────────────────────

function genSlug(name) {
  return name.toLowerCase().replace(/\s+/g, "_").replace(/[^a-z0-9_]/g, "");
}

// ── Background removal ─────────────────────────────────────────────────────────

const REMOVE_BG_KEY = "x1VdpRc71wqTwKDU22EHJj4W";

async function removeBg(blob) {
  const form = new FormData();
  form.append("image_file", blob, "image.png");
  form.append("size", "auto");
  const res = await fetch("https://api.remove.bg/v1.0/removebg", {
    method: "POST",
    headers: { "X-Api-Key": REMOVE_BG_KEY },
    body: form,
  });
  if (!res.ok) {
    const msg = await res.text();
    throw new Error(`remove.bg: ${res.status} ${msg}`);
  }
  return await res.blob();
}

// ── Image upload ───────────────────────────────────────────────────────────────

async function uploadImage(sb, file, bucket, path) {
  const { data, error } = await sb.storage.from(bucket).upload(path, file, {
    upsert: true,
    contentType: file.type,
  });
  if (error) {
    console.error("Storage upload error:", error);
    throw new Error(error.message || error.error || JSON.stringify(error));
  }
  const { data: urlData } = sb.storage.from(bucket).getPublicUrl(data.path);
  return urlData.publicUrl;
}

// ── Modal shell ────────────────────────────────────────────────────────────────

const Modal = ({ title, onClose, children }) => (
  <div
    style={{
      position: "fixed", inset: 0, zIndex: 100,
      background: "rgba(0,0,0,0.35)", display: "flex",
      alignItems: "center", justifyContent: "center",
    }}
    onClick={e => { if (e.target === e.currentTarget) onClose(); }}
  >
    <div
      className="panel cat-modal-inner"
      style={{ width: 420, maxHeight: "90vh", overflow: "auto", padding: 24 }}
    >
      <div style={{ display: "flex", alignItems: "center", justifyContent: "space-between", marginBottom: 18 }}>
        <span style={{ fontWeight: 600, fontSize: 14 }}>{title}</span>
        <button className="btn ghost" onClick={onClose} style={{ height: 24, padding: "0 8px" }}>✕</button>
      </div>
      {children}
    </div>
  </div>
);

// ── ImageField ─────────────────────────────────────────────────────────────────

// ── CropModal ──────────────────────────────────────────────────────────────────

const CropModal = ({ file, outputSize = 128, shape = 'square', onConfirm, onClose }) => {
  const CROP_PX = 220;
  const [imgSrc, setImgSrc] = useStateCat(null);
  const [naturalSize, setNaturalSize] = useStateCat({ w: 0, h: 0 });
  const [scale, setScale] = useStateCat(1);
  const [offset, setOffset] = useStateCat({ x: 0, y: 0 });
  const [dragging, setDragging] = useStateCat(false);
  const [dragOrigin, setDragOrigin] = useStateCat(null);
  const imgRef = useRefCat(null);

  useEffectCat(() => {
    const url = URL.createObjectURL(file);
    setImgSrc(url);
    return () => URL.revokeObjectURL(url);
  }, [file]);

  const handleImgLoad = (e) => {
    const { naturalWidth: w, naturalHeight: h } = e.target;
    setNaturalSize({ w, h });
    const fit = Math.max(CROP_PX / w, CROP_PX / h);
    setScale(fit);
    setOffset({ x: 0, y: 0 });
  };

  const getClientXY = (e) => {
    if (e.touches) return { x: e.touches[0].clientX, y: e.touches[0].clientY };
    return { x: e.clientX, y: e.clientY };
  };

  const onDragStart = (e) => {
    e.preventDefault();
    const { x, y } = getClientXY(e);
    setDragging(true);
    setDragOrigin({ x: x - offset.x, y: y - offset.y });
  };
  const onDragMove = (e) => {
    if (!dragging) return;
    const { x, y } = getClientXY(e);
    setOffset({ x: x - dragOrigin.x, y: y - dragOrigin.y });
  };
  const onDragEnd = () => setDragging(false);

  const onWheel = (e) => {
    e.preventDefault();
    setScale(s => Math.min(8, Math.max(0.1, s + (e.deltaY < 0 ? 0.08 : -0.08))));
  };

  const handleConfirm = () => {
    const img = imgRef.current;
    if (!img || !naturalSize.w) return;
    const canvas = document.createElement('canvas');
    canvas.width = outputSize;
    canvas.height = outputSize;
    const ctx = canvas.getContext('2d');
    ctx.imageSmoothingEnabled = true;
    ctx.imageSmoothingQuality = 'high';
    const rw = naturalSize.w * scale, rh = naturalSize.h * scale;
    const imgLeft = CROP_PX / 2 - rw / 2 + offset.x;
    const imgTop  = CROP_PX / 2 - rh / 2 + offset.y;
    const srcX = -imgLeft / scale;
    const srcY = -imgTop  / scale;
    const srcW = CROP_PX / scale;
    const srcH = CROP_PX / scale;
    if (shape === 'circle') {
      ctx.beginPath();
      ctx.arc(outputSize / 2, outputSize / 2, outputSize / 2, 0, Math.PI * 2);
      ctx.clip();
    }
    ctx.drawImage(img, srcX, srcY, srcW, srcH, 0, 0, outputSize, outputSize);
    canvas.toBlob(blob => { if (blob) onConfirm(blob); }, 'image/png');
  };

  const imgStyle = {
    position: 'absolute',
    width:  naturalSize.w * scale,
    height: naturalSize.h * scale,
    left: CROP_PX / 2 - (naturalSize.w * scale) / 2 + offset.x,
    top:  CROP_PX / 2 - (naturalSize.h * scale) / 2 + offset.y,
    pointerEvents: 'none',
    userSelect: 'none',
    draggable: false,
  };

  return (
    <Modal title="Crop & resize" onClose={onClose}>
      <div style={{ display: 'flex', flexDirection: 'column', gap: 14, alignItems: 'center' }}>
        {/* crop window */}
        <div
          style={{
            width: CROP_PX, height: CROP_PX,
            borderRadius: shape === 'circle' ? '50%' : 6,
            overflow: 'hidden', position: 'relative',
            background: 'var(--surface-3)',
            border: '2px solid var(--accent)',
            cursor: dragging ? 'grabbing' : 'grab',
            touchAction: 'none',
          }}
          onMouseDown={onDragStart} onMouseMove={onDragMove} onMouseUp={onDragEnd} onMouseLeave={onDragEnd}
          onTouchStart={onDragStart} onTouchMove={onDragMove} onTouchEnd={onDragEnd}
          onWheel={onWheel}
        >
          {imgSrc && <img ref={imgRef} src={imgSrc} alt="" style={imgStyle} onLoad={handleImgLoad} />}
        </div>

        {/* zoom slider */}
        <div style={{ width: '100%', display: 'flex', flexDirection: 'column', gap: 4 }}>
          <div style={{ display: 'flex', justifyContent: 'space-between', fontSize: 11, color: 'var(--ink-3)', fontFamily: 'var(--font-mono)' }}>
            <span>Zoom</span><span>{(scale * 100).toFixed(0)}%</span>
          </div>
          <input
            type="range" min="0.1" max="8" step="0.01" value={scale}
            onChange={e => setScale(parseFloat(e.target.value))}
            style={{ width: '100%' }}
          />
        </div>

        <div style={{ fontSize: 11, color: 'var(--ink-3)' }}>
          Drag to reposition · scroll or slider to zoom · output {outputSize}×{outputSize}px
        </div>

        <div style={{ display: 'flex', gap: 8, width: '100%', justifyContent: 'flex-end' }}>
          <button className="btn ghost" onClick={onClose}>Cancel</button>
          <button className="btn primary" onClick={handleConfirm}>Crop &amp; use</button>
        </div>
      </div>
    </Modal>
  );
};

// ── ImageField ─────────────────────────────────────────────────────────────────

const ImageField = ({ value, onChange, label, outputSize = 128, shape = 'square' }) => {
  const inputRef = useRefCat(null);
  const [preview, setPreview] = useStateCat(value || "");
  const [cropFile, setCropFile] = useStateCat(null);
  const [status, setStatus] = useStateCat(null); // null | string

  useEffectCat(() => { setPreview(value || ""); }, [value]);

  const handleFile = (e) => {
    const file = e.target.files?.[0];
    if (!file) return;
    setCropFile(file);
    e.target.value = '';
  };

  const handleCropConfirm = async (blob) => {
    setCropFile(null);
    const sb = window.supabaseClient;
    try {
      setStatus("Removing background…");
      const noBgBlob = await removeBg(blob);

      setStatus("Uploading…");
      const file = new File([noBgBlob], `icon_${Date.now()}.png`, { type: 'image/png' });
      const path = `categories/${file.name}`;
      const url = await uploadImage(sb, file, "media", path);
      setPreview(url);
      onChange(url);
      setStatus(null);
    } catch (err) {
      setStatus(null);
      alert("Upload failed: " + err.message);
    }
  };

  const handleUrlCommit = (url) => {
    if (!url.trim()) return;
    const img = new Image();
    img.crossOrigin = 'anonymous';
    img.onload = () => {
      const canvas = document.createElement('canvas');
      canvas.width = img.naturalWidth;
      canvas.height = img.naturalHeight;
      canvas.getContext('2d').drawImage(img, 0, 0);
      canvas.toBlob(blob => {
        if (!blob) { alert("Could not load image from URL."); return; }
        const file = new File([blob], `pasted_${Date.now()}.png`, { type: 'image/png' });
        setCropFile(file);
      }, 'image/png');
    };
    img.onerror = () => alert("Could not load image from URL — the server may not allow cross-origin access.");
    img.src = url;
  };

  const previewRadius = shape === 'circle' ? '50%' : 6;

  return (
    <div style={{ display: "flex", flexDirection: "column", gap: 6 }}>
      {cropFile && (
        <CropModal
          file={cropFile}
          outputSize={outputSize}
          shape={shape}
          onConfirm={handleCropConfirm}
          onClose={() => setCropFile(null)}
        />
      )}
      <label style={{ fontSize: 11, fontWeight: 500, color: "var(--ink-2)", textTransform: "uppercase", letterSpacing: "0.06em", fontFamily: "var(--font-mono)" }}>
        {label}
      </label>
      <div style={{ display: "flex", alignItems: "center", gap: 10 }}>
        <div
          style={{
            width: 52, height: 52, borderRadius: previewRadius,
            background: "var(--surface-3)", border: "1px solid var(--hairline)",
            overflow: "hidden", display: "flex", alignItems: "center", justifyContent: "center",
            flexShrink: 0,
          }}
        >
          {preview
            ? <img src={preview} alt="" style={{ width: "100%", height: "100%", objectFit: "cover" }} />
            : <span style={{ fontSize: 20 }}>🖼</span>}
        </div>
        <div style={{ flex: 1 }}>
          <input
            type="url"
            value={preview}
            onChange={e => setPreview(e.target.value)}
            onBlur={e => { if (e.target.value) handleUrlCommit(e.target.value); }}
            onKeyDown={e => { if (e.key === 'Enter' && preview) handleUrlCommit(preview); }}
            placeholder="Paste URL or upload →"
            style={{
              width: "100%", padding: "6px 10px", fontSize: 12,
              border: "1px solid var(--hairline)", borderRadius: 5,
              background: "var(--surface-2)", color: "var(--ink)",
              outline: "none", fontFamily: "var(--font-mono)",
            }}
          />
          <input ref={inputRef} type="file" accept="image/*" style={{ display: "none" }} onChange={handleFile} />
          <button
            className="btn ghost"
            style={{ marginTop: 4, height: 24, fontSize: 11 }}
            onClick={() => inputRef.current?.click()}
            disabled={!!status}
          >
            {status ?? "Upload image"}
          </button>
        </div>
      </div>
    </div>
  );
};

// ── FormField ──────────────────────────────────────────────────────────────────

const FormField = ({ label, children }) => (
  <div style={{ display: "flex", flexDirection: "column", gap: 6 }}>
    <label style={{ fontSize: 11, fontWeight: 500, color: "var(--ink-2)", textTransform: "uppercase", letterSpacing: "0.06em", fontFamily: "var(--font-mono)" }}>
      {label}
    </label>
    {children}
  </div>
);

const textInputStyle = {
  padding: "7px 10px", fontSize: 13, borderRadius: 5,
  border: "1px solid var(--hairline)", background: "var(--surface-2)",
  color: "var(--ink)", outline: "none", fontFamily: "var(--font-sans)", width: "100%",
};

// ── MainCategoryModal ──────────────────────────────────────────────────────────

const MainCategoryModal = ({ initial, onSave, onClose }) => {
  const [name, setName] = useStateCat(initial?.name || "");
  const [slug, setSlug] = useStateCat(initial?.slug || "");
  const [iconUrl, setIconUrl] = useStateCat(initial?.icon_url || "");
  const [displayOrder, setDisplayOrder] = useStateCat(initial?.display_order ?? 0);
  const [isActive, setIsActive] = useStateCat(initial?.is_active ?? true);
  const [saving, setSaving] = useStateCat(false);
  const [err, setErr] = useStateCat(null);

  const handleNameChange = (v) => {
    setName(v);
    if (!initial) setSlug(genSlug(v));
  };

  const handleSubmit = async () => {
    if (!name.trim() || !slug.trim()) { setErr("Name and slug are required."); return; }
    setSaving(true);
    setErr(null);
    try {
      await onSave({ name: name.trim(), slug: slug.trim(), icon_url: iconUrl || null, display_order: Number(displayOrder), is_active: isActive });
      onClose();
    } catch (e) {
      setErr(e.message);
    } finally {
      setSaving(false);
    }
  };

  return (
    <Modal title={initial ? "Edit main category" : "New main category"} onClose={onClose}>
      <div style={{ display: "flex", flexDirection: "column", gap: 14 }}>
        <FormField label="Name">
          <input style={textInputStyle} value={name} onChange={e => handleNameChange(e.target.value)} placeholder="e.g. Food" />
        </FormField>
        <FormField label="Slug">
          <input style={{ ...textInputStyle, fontFamily: "var(--font-mono)", fontSize: 12 }} value={slug} onChange={e => setSlug(e.target.value)} placeholder="e.g. food" />
          <span style={{ fontSize: 11, color: "var(--ink-3)" }}>Must match products.category values</span>
        </FormField>
        <ImageField label="Icon" value={iconUrl} onChange={setIconUrl} outputSize={512} shape="square" />
        <FormField label="Display order">
          <input style={{ ...textInputStyle, width: 80 }} type="number" value={displayOrder} onChange={e => setDisplayOrder(e.target.value)} />
        </FormField>
        <div style={{ display: "flex", alignItems: "center", gap: 8 }}>
          <input type="checkbox" id="mc-active" checked={isActive} onChange={e => setIsActive(e.target.checked)} />
          <label htmlFor="mc-active" style={{ fontSize: 13, cursor: "pointer" }}>Active</label>
        </div>
        {err && <div style={{ fontSize: 12, color: "var(--neg)", background: "var(--neg-soft)", padding: "8px 10px", borderRadius: 5 }}>{err}</div>}
        <div style={{ display: "flex", gap: 8, justifyContent: "flex-end" }}>
          <button className="btn ghost" onClick={onClose}>Cancel</button>
          <button className="btn primary" onClick={handleSubmit} disabled={saving}>{saving ? "Saving…" : "Save"}</button>
        </div>
      </div>
    </Modal>
  );
};

// ── SubcategoryModal ───────────────────────────────────────────────────────────

const SubcategoryModal = ({ initial, mainCategoryId, onSave, onClose }) => {
  const [name, setName] = useStateCat(initial?.name || "");
  const [slug, setSlug] = useStateCat(initial?.slug || "");
  const [iconUrl, setIconUrl] = useStateCat(initial?.icon_url || "");
  const [displayOrder, setDisplayOrder] = useStateCat(initial?.display_order ?? 0);
  const [isActive, setIsActive] = useStateCat(initial?.is_active ?? true);
  const [saving, setSaving] = useStateCat(false);
  const [err, setErr] = useStateCat(null);

  const handleNameChange = (v) => {
    setName(v);
    if (!initial) setSlug(genSlug(v));
  };

  const handleSubmit = async () => {
    if (!name.trim() || !slug.trim()) { setErr("Name and slug are required."); return; }
    setSaving(true);
    setErr(null);
    try {
      await onSave({ main_category_id: mainCategoryId, name: name.trim(), slug: slug.trim(), icon_url: iconUrl || null, display_order: Number(displayOrder), is_active: isActive });
      onClose();
    } catch (e) {
      setErr(e.message);
    } finally {
      setSaving(false);
    }
  };

  return (
    <Modal title={initial ? "Edit subcategory" : "New subcategory"} onClose={onClose}>
      <div style={{ display: "flex", flexDirection: "column", gap: 14 }}>
        <FormField label="Name">
          <input style={textInputStyle} value={name} onChange={e => handleNameChange(e.target.value)} placeholder="e.g. Pizza" />
        </FormField>
        <FormField label="Slug">
          <input style={{ ...textInputStyle, fontFamily: "var(--font-mono)", fontSize: 12 }} value={slug} onChange={e => setSlug(e.target.value)} placeholder="e.g. pizza" />
        </FormField>
        <ImageField label="Icon" value={iconUrl} onChange={setIconUrl} outputSize={256} shape="square" />
        <FormField label="Display order">
          <input style={{ ...textInputStyle, width: 80 }} type="number" value={displayOrder} onChange={e => setDisplayOrder(e.target.value)} />
        </FormField>
        <div style={{ display: "flex", alignItems: "center", gap: 8 }}>
          <input type="checkbox" id="sc-active" checked={isActive} onChange={e => setIsActive(e.target.checked)} />
          <label htmlFor="sc-active" style={{ fontSize: 13, cursor: "pointer" }}>Active</label>
        </div>
        {err && <div style={{ fontSize: 12, color: "var(--neg)", background: "var(--neg-soft)", padding: "8px 10px", borderRadius: 5 }}>{err}</div>}
        <div style={{ display: "flex", gap: 8, justifyContent: "flex-end" }}>
          <button className="btn ghost" onClick={onClose}>Cancel</button>
          <button className="btn primary" onClick={handleSubmit} disabled={saving}>{saving ? "Saving…" : "Save"}</button>
        </div>
      </div>
    </Modal>
  );
};

// ── ToggleRow ──────────────────────────────────────────────────────────────────

const ToggleRow = ({ label, description, value, onChange, saving }) => (
  <div style={{
    display: "flex", alignItems: "center", justifyContent: "space-between",
    padding: "14px 0", borderBottom: "1px solid var(--hairline)",
  }}>
    <div>
      <div style={{ fontWeight: 500, fontSize: 13, color: "var(--ink)" }}>{label}</div>
      <div style={{ fontSize: 11, color: "var(--ink-3)", marginTop: 2 }}>{description}</div>
    </div>
    <button
      onClick={() => !saving && onChange(!value)}
      disabled={saving}
      style={{
        width: 40, height: 22, borderRadius: 11, border: "none", cursor: saving ? "not-allowed" : "pointer",
        background: value ? "var(--accent)" : "var(--surface-3)",
        position: "relative", transition: "background 0.15s", flexShrink: 0,
      }}
    >
      <span style={{
        position: "absolute", top: 3, left: value ? 21 : 3,
        width: 16, height: 16, borderRadius: "50%",
        background: value ? "#fff" : "var(--ink-4)",
        transition: "left 0.15s",
      }} />
    </button>
  </div>
);

// ── CategoriesPage ─────────────────────────────────────────────────────────────

const CategoriesPage = () => {
  const I = window.Icons;
  const sb = window.supabaseClient;

  const [mainCats, setMainCats] = useStateCat([]);
  const [subCats, setSubCats] = useStateCat([]);
  const [selectedId, setSelectedId] = useStateCat(null);
  const [loading, setLoading] = useStateCat(true);
  const [subLoading, setSubLoading] = useStateCat(false);

  // modals
  const [mainModal, setMainModal] = useStateCat(null);   // null | "new" | {row}
  const [subModal, setSubModal] = useStateCat(null);     // null | "new" | {row}
  const [deleteTarget, setDeleteTarget] = useStateCat(null); // {type, row}

  // feature toggles
  const [toggles, setToggles] = useStateCat({ show_subcategory_row: true, show_filter_pills: true });
  const [savingToggle, setSavingToggle] = useStateCat(null);

  const selected = mainCats.find(c => c.id === selectedId) || null;

  // ── fetch main categories ──────────────────────────────────────────────────

  const fetchMain = async () => {
    const { data, error } = await sb.from("store_main_categories").select("*").order("display_order");
    if (!error && data) {
      setMainCats(data);
      if (!selectedId && data.length > 0) setSelectedId(data[0].id);
    }
    setLoading(false);
  };

  useEffectCat(() => {
    if (!sb) return;
    fetchMain();
  }, []);

  // ── fetch app_settings toggles ─────────────────────────────────────────────

  useEffectCat(() => {
    if (!sb) return;
    sb.from("app_settings")
      .select("key, value")
      .in("key", ["show_subcategory_row", "show_filter_pills"])
      .then(({ data }) => {
        if (!data) return;
        const t = { ...toggles };
        data.forEach(row => { t[row.key] = row.value === "true"; });
        setToggles(t);
      });
  }, []);

  // ── fetch subcategories ────────────────────────────────────────────────────

  useEffectCat(() => {
    if (!sb || !selectedId) return;
    setSubLoading(true);
    sb.from("store_subcategories")
      .select("*")
      .eq("main_category_id", selectedId)
      .order("display_order")
      .then(({ data, error }) => {
        if (!error && data) setSubCats(data);
        setSubLoading(false);
      });
  }, [selectedId]);

  // ── save main category ─────────────────────────────────────────────────────

  const saveMain = async (payload) => {
    if (mainModal?.id) {
      const { error } = await sb.from("store_main_categories").update(payload).eq("id", mainModal.id);
      if (error) { console.error("saveMain update error:", error); throw new Error(error.message || error.error || JSON.stringify(error)); }
    } else {
      const { error } = await sb.from("store_main_categories").insert(payload);
      if (error) { console.error("saveMain insert error:", error); throw new Error(error.message || error.error || JSON.stringify(error)); }
    }
    await fetchMain();
  };

  // ── save subcategory ───────────────────────────────────────────────────────

  const saveSub = async (payload) => {
    if (subModal?.id) {
      const { main_category_id, ...updatePayload } = payload;
      const { error } = await sb.from("store_subcategories").update(updatePayload).eq("id", subModal.id);
      if (error) { console.error("saveSub update error:", error); throw new Error(error.message || error.error || JSON.stringify(error)); }
    } else {
      const { error } = await sb.from("store_subcategories").insert(payload);
      if (error) { console.error("saveSub insert error:", error); throw new Error(error.message || error.error || JSON.stringify(error)); }
    }
    const { data } = await sb.from("store_subcategories").select("*").eq("main_category_id", selectedId).order("display_order");
    if (data) setSubCats(data);
  };

  // ── delete ─────────────────────────────────────────────────────────────────

  const handleDelete = async () => {
    if (!deleteTarget) return;
    const { type, row } = deleteTarget;
    if (type === "main") {
      await sb.from("store_main_categories").delete().eq("id", row.id);
      await fetchMain();
      if (selectedId === row.id) setSelectedId(null);
    } else {
      await sb.from("store_subcategories").delete().eq("id", row.id);
      setSubCats(s => s.filter(x => x.id !== row.id));
    }
    setDeleteTarget(null);
  };

  // ── toggle active ──────────────────────────────────────────────────────────

  const toggleMainActive = async (cat) => {
    const { error } = await sb.from("store_main_categories").update({ is_active: !cat.is_active }).eq("id", cat.id);
    if (!error) setMainCats(cs => cs.map(c => c.id === cat.id ? { ...c, is_active: !c.is_active } : c));
  };

  const toggleSubActive = async (sub) => {
    const { error } = await sb.from("store_subcategories").update({ is_active: !sub.is_active }).eq("id", sub.id);
    if (!error) setSubCats(ss => ss.map(s => s.id === sub.id ? { ...s, is_active: !s.is_active } : s));
  };

  // ── app_settings toggle ────────────────────────────────────────────────────

  const handleToggle = async (key, val) => {
    setSavingToggle(key);
    await sb.from("app_settings").upsert({ key, value: String(val) }, { onConflict: "key" });
    setToggles(t => ({ ...t, [key]: val }));
    setSavingToggle(null);
  };

  // ── render ─────────────────────────────────────────────────────────────────

  return (
    <div className="page" data-screen-label="Categories">
      <div className="page-h">
        <div>
          <div className="ts">{loading ? "Loading…" : `${mainCats.length} main categories · ${mainCats.filter(c => c.is_active).length} active`}</div>
          <h1>Deal Categories</h1>
        </div>
      </div>

      <div className="cat-layout" style={{ display: "grid", gridTemplateColumns: "280px 1fr 260px", gap: 14, alignItems: "start" }}>

        {/* ── LEFT: main categories ─────────────────────────────────────────── */}
        <div className="panel" style={{ overflow: "hidden" }}>
          <div className="panel-h">
            <span>Main categories</span>
            <button className="btn" style={{ height: 26 }} onClick={() => setMainModal("new")}>
              <I.plus size={11} /> New
            </button>
          </div>
          {loading ? (
            <div style={{ padding: 24, textAlign: "center", color: "var(--ink-3)", fontSize: 12 }}>Loading…</div>
          ) : mainCats.length === 0 ? (
            <div style={{ padding: 24, textAlign: "center", color: "var(--ink-3)", fontSize: 12 }}>No categories</div>
          ) : (
            <div className="cat-main-list">
              {mainCats.map(cat => {
                const sel = cat.id === selectedId;
                return (
                  <div
                    key={cat.id}
                    onClick={() => setSelectedId(cat.id)}
                    style={{
                      display: "grid", gridTemplateColumns: "36px 1fr auto auto",
                      gap: 8, alignItems: "center", padding: "9px 12px",
                      borderBottom: "1px solid var(--hairline)",
                      background: sel ? "var(--surface-2)" : "transparent",
                      cursor: "pointer", position: "relative",
                    }}
                  >
                    {sel && <div style={{ position: "absolute", left: 0, top: 6, bottom: 6, width: 2, background: "var(--accent)" }} />}
                    <div style={{
                      width: 32, height: 32, borderRadius: "50%",
                      background: "var(--surface-3)", overflow: "hidden",
                      display: "flex", alignItems: "center", justifyContent: "center",
                      fontSize: 14, flexShrink: 0,
                    }}>
                      {cat.icon_url
                        ? <img src={cat.icon_url} alt={cat.name} style={{ width: "100%", height: "100%", objectFit: "cover" }} />
                        : cat.name[0]}
                    </div>
                    <div style={{ minWidth: 0 }}>
                      <div style={{ fontWeight: 500, fontSize: 12.5, whiteSpace: "nowrap", overflow: "hidden", textOverflow: "ellipsis" }}>{cat.name}</div>
                      <div style={{ fontSize: 10.5, color: "var(--ink-3)", fontFamily: "var(--font-mono)" }}>{cat.slug}</div>
                    </div>
                    <span
                      className={`chip dot ${cat.is_active ? "pos" : "warn"}`}
                      style={{ flexShrink: 0, cursor: "pointer", fontSize: 10 }}
                      onClick={e => { e.stopPropagation(); toggleMainActive(cat); }}
                    >
                      {cat.is_active ? "on" : "off"}
                    </span>
                    <div style={{ display: "flex", gap: 3 }}>
                      <button
                        className="btn ghost"
                        style={{ height: 22, width: 22, padding: 0, display: "grid", placeItems: "center" }}
                        onClick={e => { e.stopPropagation(); setMainModal(cat); }}
                      ><I.edit size={10} /></button>
                      <button
                        className="btn ghost"
                        style={{ height: 22, width: 22, padding: 0, display: "grid", placeItems: "center", color: "var(--neg)" }}
                        onClick={e => { e.stopPropagation(); setDeleteTarget({ type: "main", row: cat }); }}
                      ><I.trash size={10} /></button>
                    </div>
                  </div>
                );
              })}
            </div>
          )}
        </div>

        {/* ── MIDDLE: subcategories ─────────────────────────────────────────── */}
        <div className="panel" style={{ overflow: "hidden" }}>
          <div className="panel-h">
            <span>{selected ? `${selected.name} — Subcategories` : "Subcategories"}</span>
            {selected && (
              <button className="btn" style={{ height: 26 }} onClick={() => setSubModal("new")}>
                <I.plus size={11} /> New
              </button>
            )}
          </div>
          {!selected ? (
            <div style={{ padding: 32, textAlign: "center", color: "var(--ink-3)", fontSize: 12 }}>
              Select a main category
            </div>
          ) : subLoading ? (
            <div style={{ padding: 24, textAlign: "center", color: "var(--ink-3)", fontSize: 12 }}>Loading…</div>
          ) : subCats.length === 0 ? (
            <div style={{ padding: 24, textAlign: "center", color: "var(--ink-3)", fontSize: 12 }}>No subcategories yet</div>
          ) : (
            <div className="t-wrap">
              <table className="t">
                <thead>
                  <tr>
                    <th style={{ width: 40 }}></th>
                    <th>Name</th>
                    <th>Slug</th>
                    <th style={{ textAlign: "center" }}>Order</th>
                    <th style={{ textAlign: "center" }}>Active</th>
                    <th></th>
                  </tr>
                </thead>
                <tbody>
                  {subCats.map(sub => (
                    <tr key={sub.id}>
                      <td>
                        <div style={{
                          width: 30, height: 30, borderRadius: "50%",
                          background: "var(--surface-3)", overflow: "hidden",
                          display: "flex", alignItems: "center", justifyContent: "center", fontSize: 12,
                        }}>
                          {sub.icon_url
                            ? <img src={sub.icon_url} alt={sub.name} style={{ width: "100%", height: "100%", objectFit: "cover" }} />
                            : sub.name[0]}
                        </div>
                      </td>
                      <td style={{ fontWeight: 500 }}>{sub.name}</td>
                      <td><span className="id" style={{ fontFamily: "var(--font-mono)", fontSize: 11 }}>{sub.slug}</span></td>
                      <td style={{ textAlign: "center" }}><span className="num">{sub.display_order}</span></td>
                      <td style={{ textAlign: "center" }}>
                        <span
                          className={`chip dot ${sub.is_active ? "pos" : "warn"}`}
                          style={{ cursor: "pointer", fontSize: 10 }}
                          onClick={() => toggleSubActive(sub)}
                        >
                          {sub.is_active ? "on" : "off"}
                        </span>
                      </td>
                      <td>
                        <div style={{ display: "flex", gap: 4, justifyContent: "flex-end" }}>
                          <button
                            className="btn ghost"
                            style={{ height: 22, width: 22, padding: 0, display: "grid", placeItems: "center" }}
                            onClick={() => setSubModal(sub)}
                          ><I.edit size={10} /></button>
                          <button
                            className="btn ghost"
                            style={{ height: 22, width: 22, padding: 0, display: "grid", placeItems: "center", color: "var(--neg)" }}
                            onClick={() => setDeleteTarget({ type: "sub", row: sub })}
                          ><I.trash size={10} /></button>
                        </div>
                      </td>
                    </tr>
                  ))}
                </tbody>
              </table>
            </div>
          )}
        </div>

        {/* ── RIGHT: feature toggles ────────────────────────────────────────── */}
        <div className="panel" style={{ padding: "0 16px 4px" }}>
          <div className="panel-h" style={{ paddingLeft: 0, paddingRight: 0 }}>
            <span>App toggles</span>
          </div>
          <ToggleRow
            label="Subcategory icon row"
            description="Show circular subcategory icons in the app"
            value={toggles.show_subcategory_row}
            onChange={v => handleToggle("show_subcategory_row", v)}
            saving={savingToggle === "show_subcategory_row"}
          />
          <ToggleRow
            label="Filter pills row"
            description="Show filter pills below the category icons"
            value={toggles.show_filter_pills}
            onChange={v => handleToggle("show_filter_pills", v)}
            saving={savingToggle === "show_filter_pills"}
          />
          <div style={{ padding: "12px 0 8px", fontSize: 11, color: "var(--ink-3)" }}>
            Changes take up to 5 min to reflect in the app (mobile cache).
          </div>
        </div>
      </div>

      {/* ── Modals ───────────────────────────────────────────────────────────── */}

      {mainModal && (
        <MainCategoryModal
          initial={mainModal === "new" ? null : mainModal}
          onSave={saveMain}
          onClose={() => setMainModal(null)}
        />
      )}

      {subModal && selected && (
        <SubcategoryModal
          initial={subModal === "new" ? null : subModal}
          mainCategoryId={selected.id}
          onSave={saveSub}
          onClose={() => setSubModal(null)}
        />
      )}

      {deleteTarget && (
        <Modal title="Confirm delete" onClose={() => setDeleteTarget(null)}>
          <div style={{ display: "flex", flexDirection: "column", gap: 16 }}>
            <div style={{ fontSize: 13, color: "var(--ink-2)" }}>
              Delete <strong>{deleteTarget.row.name}</strong>? This cannot be undone.
              {deleteTarget.type === "main" && (
                <span style={{ color: "var(--neg)" }}> All subcategories will also be deleted.</span>
              )}
            </div>
            <div style={{ display: "flex", gap: 8, justifyContent: "flex-end" }}>
              <button className="btn ghost" onClick={() => setDeleteTarget(null)}>Cancel</button>
              <button
                className="btn"
                style={{ background: "var(--neg)", color: "#fff", borderColor: "var(--neg)" }}
                onClick={handleDelete}
              >Delete</button>
            </div>
          </div>
        </Modal>
      )}
    </div>
  );
};

window.CategoriesPage = CategoriesPage;
