/* Main app — state, tabs, edit modal, refresh-from-Meta */

const { useState, useMemo, useCallback } = React;

const TWEAK_DEFAULTS = /*EDITMODE-BEGIN*/{
  "accent": "#318555",
  "headings": "serif",
  "density": "regular",
  "showCardMetrics": true
}/*EDITMODE-END*/;

// Launch plans: "standard" = one ad per creative via /api/push; the rest = 6-ad Master packs via /api/push-master.
const LAUNCH_PLANS = {
  standard: { label: "Standard — 1 ad per creative", master: false },
  m1: { label: "Master #1 — CBO ($90/day · 1 ad set · 6 ads)", master: true, template: "1", split: false, daily_budget_cents: 9000 },
  m2: { label: "Master #2 — ABO ($90/day · 1 ad set · 6 ads)", master: true, template: "2", split: false, daily_budget_cents: 9000 },
  m3: { label: "Master #3 — CBO split ($90/day campaign · 6 ad sets)", master: true, template: "1", split: true, daily_budget_cents: 9000 },
  m4: { label: "Master #4 — ABO split (6 ad sets × $15/day)", master: true, template: "2", split: true, adset_budget_cents: 1500 },
};

// Removed-creative history — persisted in localStorage so deletions survive refresh + reload.
const REMOVED_KEY = "adore_removed_creatives";
function loadRemoved() { try { return JSON.parse(localStorage.getItem(REMOVED_KEY) || "{}"); } catch (e) { return {}; } }
function saveRemoved(id, meta) { const m = loadRemoved(); m[id] = meta; try { localStorage.setItem(REMOVED_KEY, JSON.stringify(m)); } catch (e) {} }
function clearRemoved(id) { const m = loadRemoved(); delete m[id]; try { localStorage.setItem(REMOVED_KEY, JSON.stringify(m)); } catch (e) {} }

// Per-creative override defaults (applied server-side too if a field is blank).
const DEFAULT_PIXEL = "303246340715974";   // Adore Homes's Main Pixel
const DEFAULT_RADIUS_MI = 40;              // miles from San Jose (0 = nationwide US)
const DEFAULT_URL_TAGS = "utm_id={{campaign.id}}&ad_id={{ad.id}}&adset_id={{adset.id}}&placement={{placement}}&site_source_name={{site_source_name}}&fbc_id={{adset.id}}&h_ad_id={{ad.id}}&utm_source=Meta&utm_medium=cpc&utm_content={{adset.name}}&utm_campaign={{campaign.name}}&utm_term={{ad.name}}&hsa_acc=435787260938097&hsa_cam={{campaign.id}}&hsa_grp={{adset.id}}&hsa_ad={{ad.id}}&hsa_src=[SITE_SOURCE_NAME]&hsa_net=facebook&hsa_ver=3";

function App() {
  const [t, setTweak] = useTweaks(TWEAK_DEFAULTS);
  const P = window.ADORE.platforms;
  const modelList = window.ADORE.modelList;

  const [creatives, setCreatives] = useState(() => {
    const removed = loadRemoved();   // re-apply prior deletions so they don't reappear on reload/refresh
    return window.ADORE.creatives.map(c => ({ ...c, removed: !!removed[c.id], removedAt: (removed[c.id] && removed[c.id].at) || null }));
  });
  const [mode, setMode] = useState("pipeline");
  const [refreshing, setRefreshing] = useState(false);
  const [tab, setTab] = useState("gallery");
  const [sel, setSel] = useState(new Set());

  // gallery filters
  const [modelFilter, setModelFilter] = useState("all");
  const [mediaFilter, setMediaFilter] = useState("all");
  const [showRemoved, setShowRemoved] = useState(false);
  // table filter
  const [statusFilter, setStatusFilter] = useState("all");

  // edit modal
  const [editingId, setEditingId] = useState(null);
  // generate
  const [queue, setQueue] = useState([]);
  const [copied, setCopied] = useState(null);
  // launch
  const [launchState, setLaunchState] = useState({ loading: false, result: null, kind: "ok" });
  const [plan, setPlan] = useState("standard");
  const [genPrefill, setGenPrefill] = useState(null);   // Studio → Generate handoff

  const useInGenerate = (g) => {
    setGenPrefill({
      assetUrl: (g && g.assetUrl) || "", model: (g && g.model) || modelList[0],
      format: (g && g.format) || "Video", aspect: (g && g.aspect) || "9:16", scene: (g && g.brief) || "",
    });
    setTab("generate");
  };
  const [refreshRange, setRefreshRange] = useState("max");   // Meta insights window: 7 | 30 | 90 | max

  const refresh = useCallback(async (rng) => {
    const range = rng || refreshRange;
    setRefreshing(true);
    try {
      const r = await fetch("/api/refresh?range=" + encodeURIComponent(range));
      const d = await r.json();
      if (d && d.ok && d.performance) {
        setCreatives(cs => cs.map(c => {
          const p = d.performance[c.id]; if (!p) return c;
          const live = { ...c.live,
            spend: p.spend != null ? p.spend : c.live.spend,
            leads: p.leads != null ? p.leads : c.live.leads,
            impressions: p.impressions != null ? p.impressions : c.live.impressions,
            clicks: p.clicks != null ? p.clicks : c.live.clicks,
            ctr: p.ctr != null ? p.ctr : c.live.ctr,
            cpa: p.cpa != null ? p.cpa : c.live.cpa,
            frequency: p.frequency != null ? p.frequency : c.live.frequency };
          return { ...c, live, liveStatus: (window.recomputeLive ? window.recomputeLive(live, c.status) : c.liveStatus) };
        }));
      }
    } catch (e) { /* still flip to live so the UI shows whatever data exists */ }
    setMode("live");
    setRefreshing(false);
  }, [refreshRange]);

  const nextId = useCallback((extra) => {
    const nums = creatives.map(c => parseInt(c.id.split("-")[1], 10));
    const base = Math.max(...nums) + 1 + (extra || 0);
    return "CR-" + String(base).padStart(4, "0");
  }, [creatives]);

  // Save a Generate-tab brief straight into Gallery & Launch as a new creative.
  const saveBriefToGallery = (f) => {
    const id = nextId(0);
    const isVideo = (f.format || "") === "Video";
    const mk = (window.ADORE.modelKey ? window.ADORE.modelKey(f.model) : "sigB");
    const creative = {
      id, model: f.model, modelKey: mk, angle: f.angle || "",
      format: `${f.format} ${f.aspect}`.trim(), isVideo, aspect: f.aspect,
      tone: f.tone || "—", headline: f.headline || "", primary: f.primary || "",
      cta: f.cta || "Learn More", scene: f.scene || f.hook || "", assetUrl: (f.assetUrl || "").trim(),
      status: (f.assetUrl || "").trim() ? "ready" : "queued",
      liveStatus: (f.assetUrl || "").trim() ? "ready" : "queued", removed: false,
      live: { spend: 0, leads: 0, impressions: 0, clicks: 0, ctr: 0, cpa: null, frequency: 0, roas: 0 },
    };
    setCreatives(cs => [creative, ...cs]);
    setTab("gallery");
    return id;
  };

  const removeCreative = (id) => {
    const c = creatives.find(x => x.id === id);
    const ok = window.confirm(`Remove ${id}${c && c.headline ? ' — "' + c.headline + '"' : ""}?\n\nIt'll be hidden from the gallery and stay hidden after refresh/reload. You can bring it back anytime via "Show removed".`);
    if (!ok) return;
    const at = new Date().toISOString();
    saveRemoved(id, { at, headline: (c && c.headline) || "", model: (c && c.model) || "", format: (c && c.format) || "" });
    setCreatives(cs => cs.map(x => x.id === id ? { ...x, removed: true, removedAt: at } : x));
  };
  const restoreCreative = (id) => {
    clearRemoved(id);
    setCreatives(cs => cs.map(c => c.id === id ? { ...c, removed: false, removedAt: null } : c));
  };
  const saveEdit = (id, patch) => setCreatives(cs => cs.map(c => c.id === id ? { ...c, ...patch } : c));

  const launch = async () => {
    const picks = creatives.filter(c => sel.has(c.id) && !c.removed);
    if (!picks.length) return;
    const cfg = LAUNCH_PLANS[plan] || LAUNCH_PLANS.standard;
    setLaunchState({ loading: true, result: null, kind: "ok" });
    try {
      if (!cfg.master) {
        // Standard: one ad per creative
        const r = await fetch("/api/push", {
          method: "POST", headers: { "Content-Type": "application/json" },
          body: JSON.stringify({ objective: "OUTCOME_TRAFFIC", items: picks.map(c => ({
            id: c.id, model: c.model, angle: c.angle, headline: c.headline,
            primary: c.primary, cta: c.cta, assetUrl: c.assetUrl, format: c.format,
            campaign_name: c.campaign_name, adset_name: c.adset_name, ad_name: c.ad_name, link_url: c.link_url || "",
            pixel_id: (c.pixel_id !== undefined ? c.pixel_id : DEFAULT_PIXEL), url_tags: (c.url_tags !== undefined ? c.url_tags : DEFAULT_URL_TAGS), radius_mi: (c.radius_mi !== undefined ? c.radius_mi : DEFAULT_RADIUS_MI) })) }),
        });
        const d = await r.json();
        if (d && d.ok) {
          const extra = (d.failed && d.failed.length ? ` · ${d.failed.length} failed` : "") + (d.skipped_videos && d.skipped_videos.length ? ` · ${d.skipped_videos.length} video(s) skipped` : "");
          setLaunchState({ loading: false, result: `✓ ${d.created} PAUSED campaign${d.created > 1 ? "s" : ""} created in Meta${extra}`, kind: "ok" });
          setTimeout(() => { setSel(new Set()); setLaunchState({ loading: false, result: null, kind: "ok" }); }, 4000);
        } else {
          setLaunchState({ loading: false, result: "Push failed: " + ((d && d.error) || "unknown"), kind: "bad" });
        }
      } else {
        // Master plan: one 6-ad pack per selected creative (sequential — video upload is slow)
        let ok = 0; const fails = [];
        for (const c of picks) {
          const body = { label: c.id, template: cfg.template, split: cfg.split, launch: false };
          if (c.isVideo) body.video_url = c.assetUrl; else body.image_url = c.assetUrl;
          if (cfg.daily_budget_cents) body.daily_budget_cents = cfg.daily_budget_cents;
          if (cfg.adset_budget_cents) body.adset_budget_cents = cfg.adset_budget_cents;
          try {
            const r = await fetch("/api/push-master", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify(body) });
            const d = await r.json();
            if (d && d.ok) ok++; else fails.push(c.id + ": " + ((d && d.error) || "unknown"));
          } catch (e) { fails.push(c.id + ": " + e); }
        }
        const planName = cfg.label.split(" —")[0];
        setLaunchState({ loading: false, result: (ok ? `✓ ${ok} ${planName} pack${ok > 1 ? "s" : ""} created PAUSED (6 ads each)` : "") + (fails.length ? ` · ⚠️ ${fails.length} failed: ${fails[0]}` : ""), kind: fails.length && !ok ? "bad" : "ok" });
        if (ok) setTimeout(() => { setSel(new Set()); setLaunchState({ loading: false, result: null, kind: "ok" }); }, 6000);
      }
    } catch (e) { setLaunchState({ loading: false, result: "Error: " + e, kind: "bad" }); }
  };

  const copyGen = () => { setCopied("cmd"); setTimeout(() => setCopied(null), 1600); };

  // ---- KPI computation ----
  const k = useMemo(() => {
    const live = creatives.filter(c => !c.removed);
    const images = live.filter(c => !c.isVideo).length;
    const videos = live.length - images;
    if (mode === "live") {
      const m = live.filter(c => c.liveStatus !== "paused");
      const spend = m.reduce((s, c) => s + c.live.spend, 0);
      const leads = m.reduce((s, c) => s + c.live.leads, 0);
      const clicks = m.reduce((s, c) => s + c.live.clicks, 0);
      const impr = m.reduce((s, c) => s + c.live.impressions, 0);
      const cpl = leads ? spend / leads : null;
      const blended = cpl || 130;
      return {
        creatives: live.length, images, videos, selected: sel.size, spend, leads,
        ctr: impr ? clicks / impr * 100 : 0, cpl, target: P.target_cpl,
        active: live.filter(c => c.liveStatus === "active").length,
        fatigued: live.filter(c => c.liveStatus === "fatigued").length,
        under: live.filter(c => c.liveStatus === "underperformer").length,
        cplTrend: [blended * 1.3, blended * 1.1, blended * 1.18, blended * 0.96, blended * 1.04, blended * 0.9, blended],
      };
    }
    return { creatives: live.length, images, videos, selected: sel.size, spend: 0, leads: 0, ctr: 0, cpl: null, target: P.target_cpl, active: 0, fatigued: 0, under: 0 };
  }, [creatives, mode, sel, P.target_cpl]);

  const metaSummary = useMemo(() => {
    const live = creatives.filter(c => !c.removed);
    return { spend: k.spend, leads: k.leads, creatives: live.length, active: k.active, cpl: k.cpl };
  }, [creatives, k]);

  const editing = editingId ? creatives.find(c => c.id === editingId) : null;
  const galleryCount = creatives.filter(c => !c.removed).length;

  const shellStyle = {
    "--acc": t.accent,
    "--serif": t.headings === "sans" ? "var(--sans)" : '"Spectral", Georgia, serif',
  };

  return (
    <div className="shell" style={shellStyle} data-density={t.density} data-hide-metrics={t.showCardMetrics ? "0" : "1"}>
      <Header mode={mode} refreshing={refreshing} onRefresh={refresh} P={P}
        refreshRange={refreshRange} setRefreshRange={setRefreshRange} />
      <PlatformStrip mode={mode} meta={metaSummary} P={P} />
      <KpiStrip mode={mode} k={k} />

      <div className="tabs">
        <Tab id="generate" cur={tab} set={setTab}><Ico d={I.spark} s={14} fill="currentColor" /> Generate</Tab>
        <Tab id="studio" cur={tab} set={setTab}><Ico d={I.spark} s={14} /> Creative Studio</Tab>
        <Tab id="gallery" cur={tab} set={setTab} count={galleryCount}><Ico d={I.grid} s={14} /> Gallery &amp; Launch</Tab>
        <Tab id="all" cur={tab} set={setTab}><Ico d={I.filter} s={14} /> All Ads</Tab>
        <Tab id="leads" cur={tab} set={setTab} count={window.__ADORE_LEADS ? window.__ADORE_LEADS.rows.length : null}><Ico d={I.arrowUp} s={14} /> Leads</Tab>
        <Tab id="insights" cur={tab} set={setTab}><Ico d={I.arrowUp} s={14} /> Insights &amp; Performance</Tab>
        <Tab id="google" cur={tab} set={setTab}><Ico d={I.filter} s={14} /> Google Ads</Tab>
      </div>

      {tab === "studio" && (
        <StudioTab modelList={modelList} onUseInGenerate={useInGenerate} />
      )}
      {tab === "generate" && (
        <GenerateTab nextId={nextId} queue={queue} setQueue={setQueue} modelList={modelList} onCopy={copyGen} copied={copied} onSave={saveBriefToGallery} prefill={genPrefill} clearPrefill={() => setGenPrefill(null)} />
      )}
      {tab === "gallery" && (
        <GalleryTab creatives={creatives} mode={mode} sel={sel} setSel={setSel}
          modelFilter={modelFilter} setModelFilter={setModelFilter}
          mediaFilter={mediaFilter} setMediaFilter={setMediaFilter}
          showRemoved={showRemoved} setShowRemoved={setShowRemoved}
          onEdit={setEditingId} onRemove={removeCreative} onRestore={restoreCreative}
          modelList={modelList} onLaunch={launch} launchState={launchState}
          plan={plan} setPlan={setPlan} plans={LAUNCH_PLANS} />
      )}
      {tab === "all" && (
        <AllAdsTab creatives={creatives} mode={mode} sel={sel} setSel={setSel}
          statusFilter={statusFilter} setStatusFilter={setStatusFilter}
          onEdit={setEditingId} onRemove={removeCreative} />
      )}
      {tab === "leads" && <LeadsTab />}
      {tab === "insights" && <InsightsTab creatives={creatives} mode={mode} />}
      {tab === "google" && <GoogleTab />}

      {editing && <EditModal c={editing} modelList={modelList} onClose={() => setEditingId(null)} onSave={saveEdit} />}

      <TweaksPanel>
        <TweakSection label="Brand accent" />
        <TweakColor label="Accent color" value={t.accent}
          options={["#318555", "#2E6FB0", "#B07A1E", "#A14E8C", "#C0533A"]}
          onChange={(v) => setTweak("accent", v)} />
        <TweakSection label="Type & layout" />
        <TweakRadio label="Headings" value={t.headings} options={["serif", "sans"]}
          onChange={(v) => setTweak("headings", v)} />
        <TweakRadio label="Density" value={t.density} options={["compact", "regular", "comfy"]}
          onChange={(v) => setTweak("density", v)} />
        <TweakToggle label="Metric overlay on cards" value={t.showCardMetrics}
          onChange={(v) => setTweak("showCardMetrics", v)} />
      </TweaksPanel>
    </div>
  );
}

function Tab({ id, cur, set, count, children }) {
  return (
    <button className={"tab" + (cur === id ? " on" : "")} onClick={() => set(id)}>
      {children}{count != null && <span className="tcount">{count}</span>}
    </button>
  );
}

function EditModal({ c, modelList, onClose, onSave }) {
  const [headline, setHeadline] = useState(c.headline || "");
  const [primary, setPrimary] = useState(c.primary || "");
  const [cta, setCta] = useState(c.cta || "Learn More");
  const [model, setModel] = useState(c.model);
  const [angle, setAngle] = useState(c.angle || "");
  const [tone, setTone] = useState(c.tone || "Warm");
  const [formatType, setFormatType] = useState(c.isVideo ? "Video" : "Image");
  const [aspect, setAspect] = useState(c.aspect || (c.format ? (c.format.split(" ")[1] || "") : "") || (c.isVideo ? "9:16" : "1:1"));
  const [assetUrl, setAssetUrl] = useState(c.assetUrl || "");
  const [campaignName, setCampaignName] = useState(c.campaign_name || "");
  const [adsetName, setAdsetName] = useState(c.adset_name || "");
  const [adName, setAdName] = useState(c.ad_name || "");
  const [linkUrl, setLinkUrl] = useState(c.link_url || "");
  const [pixelId, setPixelId] = useState(c.pixel_id !== undefined ? c.pixel_id : DEFAULT_PIXEL);
  const [urlTags, setUrlTags] = useState(c.url_tags !== undefined ? c.url_tags : DEFAULT_URL_TAGS);
  const [radiusMi, setRadiusMi] = useState(c.radius_mi !== undefined ? c.radius_mi : DEFAULT_RADIUS_MI);

  const url = assetUrl.trim();
  const isVideoUrl = /\.(mp4|mov|webm)(\?|$)/i.test(url);
  const models = (modelList && modelList.length) ? modelList : [c.model];

  function save() {
    const isVideo = formatType === "Video";
    const status = url ? "ready" : "queued";
    const patch = {
      headline, primary, cta, model, angle, tone,
      isVideo, aspect, format: `${formatType} ${aspect}`.trim(),
      modelKey: (window.ADORE && window.ADORE.modelKey) ? window.ADORE.modelKey(model) : c.modelKey,
      assetUrl: url, status,
      liveStatus: (window.recomputeLive ? window.recomputeLive(c.live || {}, status) : status),
      campaign_name: campaignName.trim(), adset_name: adsetName.trim(), ad_name: adName.trim(),
      link_url: linkUrl.trim(), pixel_id: pixelId, url_tags: urlTags, radius_mi: radiusMi,
    };
    onSave(c.id, patch); onClose();
  }
  return (
    <div className="overlay" onClick={onClose}>
      <div className="modal" onClick={e => e.stopPropagation()}>
        <div className="modal-head">
          <div>
            <h3 className="serif">Edit creative</h3>
            <div className="mid">{c.id} · {shortModel(model)}{angle ? " · " + angle : ""}</div>
          </div>
          <button className="ico-btn" onClick={onClose}><Ico d={I.x} s={14} /></button>
        </div>
        <div className="modal-body" style={{ maxHeight: "68vh", overflowY: "auto" }}>
          <div className="row">
            <div className="field"><label>Model / product</label>
              <select className="select" value={model} onChange={e => setModel(e.target.value)}>
                {models.map(m => <option key={m}>{m}</option>)}
              </select></div>
            <div className="field"><label>Marketing angle</label>
              <input className="input" value={angle} onChange={e => setAngle(e.target.value)} placeholder="e.g. Multi-gen / Rental-income" /></div>
          </div>
          <div className="row">
            <div className="field"><label>Format</label>
              <select className="select" value={formatType} onChange={e => setFormatType(e.target.value)}><option>Video</option><option>Image</option></select></div>
            <div className="field"><label>Aspect</label>
              <select className="select" value={aspect} onChange={e => setAspect(e.target.value)}><option>9:16</option><option>1:1</option><option>16:9</option><option>4:5</option></select></div>
            <div className="field"><label>Tone</label>
              <select className="select" value={tone} onChange={e => setTone(e.target.value)}><option>Warm</option><option>Upbeat</option><option>Cinematic</option></select></div>
          </div>
          <div className="field"><label>Headline</label>
            <input className="input" value={headline} onChange={e => setHeadline(e.target.value)} /></div>
          <div className="field"><label>Primary text</label>
            <textarea className="textarea" style={{ minHeight: 100 }} value={primary} onChange={e => setPrimary(e.target.value)} /></div>
          <div className="field"><label>Call to action</label>
            <select className="select" value={cta} onChange={e => setCta(e.target.value)}>
              <option>Book Now</option><option>Learn More</option><option>Get Quote</option><option>Sign Up</option><option>Contact Us</option>
            </select></div>
          <div className="field"><label>Website URL (where the ad clicks to)</label>
            <input className="input" value={linkUrl} onChange={e => setLinkUrl(e.target.value)} placeholder="https://hello.adore-homes.com/ (default if blank)" /></div>
          <div className="field"><label>Asset URL (image or video — fills the thumbnail & makes it launch-ready)</label>
            <input className="input" value={assetUrl} onChange={e => setAssetUrl(e.target.value)} placeholder="https://… .mp4 / .jpg — blank = Queued" /></div>
          {url && (
            <div style={{ borderRadius: 10, overflow: "hidden", border: "1px solid var(--line)", maxWidth: 220 }}>
              {isVideoUrl
                ? <video src={url} muted loop playsInline style={{ width: "100%", display: "block" }} />
                : <img src={url} alt="" style={{ width: "100%", display: "block" }} />}
            </div>
          )}

          <div style={{ margin: "18px 0 -4px", font: "10.5px var(--mono)", letterSpacing: ".12em", textTransform: "uppercase", color: "var(--t3)", borderTop: "1px solid var(--line)", paddingTop: 16 }}>
            Meta launch structure <span style={{ textTransform: "none", letterSpacing: 0, color: "var(--t4)" }}>· optional — blank = auto-named on push</span>
          </div>
          <div className="field"><label>Campaign name</label>
            <input className="input" value={campaignName} onChange={e => setCampaignName(e.target.value)} placeholder={`Auto: ADORE_${(model || "").replace(/[^A-Za-z0-9]+/g, "").slice(0, 16) || "ADU"}_${(angle || "").replace(/[^A-Za-z0-9]+/g, "").slice(0, 16) || "ADU"}_${formatType}`} /></div>
          <div className="row">
            <div className="field"><label>Ad set name</label>
              <input className="input" value={adsetName} onChange={e => setAdsetName(e.target.value)} placeholder="Auto: …_AdSet" /></div>
            <div className="field"><label>Ad name</label>
              <input className="input" value={adName} onChange={e => setAdName(e.target.value)} placeholder="Auto: …_Ad" /></div>
          </div>

          <div style={{ margin: "18px 0 -4px", font: "10.5px var(--mono)", letterSpacing: ".12em", textTransform: "uppercase", color: "var(--t3)", borderTop: "1px solid var(--line)", paddingTop: 16 }}>
            Tracking &amp; targeting <span style={{ textTransform: "none", letterSpacing: 0, color: "var(--t4)" }}>· defaults applied if left as-is</span>
          </div>
          <div className="row">
            <div className="field"><label>Website-events pixel</label>
              <select className="select" value={pixelId} onChange={e => setPixelId(e.target.value)}>
                <option value="303246340715974">Adore Homes's Main Pixel</option>
                <option value="">No pixel</option>
              </select></div>
            <div className="field"><label>Targeting (miles from San Jose · 0 = nationwide)</label>
              <input className="input" type="number" min="0" value={radiusMi} onChange={e => setRadiusMi(e.target.value)} /></div>
          </div>
          <div className="field"><label>URL parameters (appended to the link)</label>
            <textarea className="textarea" style={{ minHeight: 70, fontFamily: "var(--mono)", fontSize: 11 }} value={urlTags} onChange={e => setUrlTags(e.target.value)} spellCheck={false} /></div>
        </div>
        <div className="modal-foot">
          <button className="link-btn"><Ico d={I.ext} s={14} /> Edit in Google Sheet</button>
          <div style={{ display: "flex", gap: 10 }}>
            <button className="btn btn-ghost" onClick={onClose}>Cancel</button>
            <button className="btn btn-accent" onClick={save}><Ico d={I.check} s={14} /> Save changes</button>
          </div>
        </div>
      </div>
    </div>
  );
}

ReactDOM.createRoot(document.getElementById("root")).render(<App />);
