/* The Pulse — editor panel (left side; not exported). */
(function () {
  const I = window.PulseIcons;
  const { useState, useRef } = React;

  // Resize an uploaded image to a sane max width and re-encode small,
  // so it embeds in the email + fits in browser storage. White-fills
  // transparency so uploaded QR codes (often transparent PNG) stay scannable.
  function fileToDataURL(file, maxW, cb) {
    const reader = new FileReader();
    reader.onload = (e) => {
      const img = new Image();
      img.onload = () => {
        const scale = Math.min(1, maxW / img.width);
        const w = Math.max(1, Math.round(img.width * scale));
        const h = Math.max(1, Math.round(img.height * scale));
        const cv = document.createElement("canvas");
        cv.width = w; cv.height = h;
        const ctx = cv.getContext("2d");
        ctx.fillStyle = "#ffffff"; ctx.fillRect(0, 0, w, h);
        ctx.drawImage(img, 0, 0, w, h);
        cb(cv.toDataURL("image/jpeg", 0.82));
      };
      img.onerror = () => cb(null);
      img.src = e.target.result;
    };
    reader.readAsDataURL(file);
  }

  function ImageField({ label, hint, value, set, maxW }) {
    const ref = useRef(null);
    const [busy, setBusy] = useState(false);
    const pick = (e) => {
      const f = e.target.files && e.target.files[0];
      if (!f) return;
      setBusy(true);
      window.pulseProcessImage(f, maxW || 1000).then((url) => { setBusy(false); if (url) set(url); });
      e.target.value = "";
    };
    return (
      <div className="fld">
        {label && <label>{label}</label>}
        <input ref={ref} type="file" accept="image/*" onChange={pick} style={{ display: "none" }} />
        {value ? (
          <div className="img-has">
            <img src={value} alt="" className="img-thumb" />
            <div className="img-acts">
              <button className="img-btn" onClick={() => ref.current && ref.current.click()}>
                <I.Upload size={13} /> Replace
              </button>
              <button className="img-btn danger" onClick={() => set("")}>
                <I.Trash size={13} /> Remove
              </button>
            </div>
          </div>
        ) : (
          <button className="img-drop" onClick={() => ref.current && ref.current.click()} disabled={busy}>
            <I.Image size={18} />
            <span>{busy ? "Adding…" : "Upload image"}</span>
            {hint && <em>{hint}</em>}
          </button>
        )}
      </div>
    );
  }

  function ToggleRow({ label, hint, on, set }) {
    return (
      <div className="tgl-row">
        <div className="tgl-txt">
          <b>{label}</b>
          {hint && <span>{hint}</span>}
        </div>
        <Toggle on={on} onClick={() => set(!on)} />
      </div>
    );
  }

  function Segmented({ label, value, set, opts }) {
    return (
      <div className="fld">
        {label && <label>{label}</label>}
        <div className="seg">
          {opts.map((o) => (
            <button key={o.id} className={"seg-btn" + (value === o.id ? " on" : "")}
                    onClick={() => set(o.id)}>{o.name}</button>
          ))}
        </div>
      </div>
    );
  }

  function Toggle({ on, onClick }) {
    return <div className={"tg" + (on ? " on" : "")} onClick={(e) => { e.stopPropagation(); onClick(); }} />;
  }

  function Field({ label, val, set, area, rows, ph, half }) {
    const props = {
      value: val || "",
      placeholder: ph || "",
      onChange: (e) => set(e.target.value)
    };
    return (
      <div className="fld" style={half ? null : null}>
        {label && <label>{label}</label>}
        {area
          ? <textarea {...props} style={{ minHeight: (rows || 3) * 22 }} />
          : <input type="text" {...props} />}
      </div>
    );
  }

  function Acc({ ic, color, title, summary, enabled, onToggle, defaultOpen, children, noToggle, onMoveUp, onMoveDown, canUp, canDown, style }) {
    const [open, setOpen] = useState(!!defaultOpen);
    const Ic = ic;
    const movable = onMoveUp || onMoveDown;
    return (
      <div className={"acc" + (open ? " open" : "")} style={style}>
        <div className="acc-head" onClick={() => setOpen(!open)}>
          {movable && (
            <div className="acc-move" onClick={(e) => e.stopPropagation()}>
              <button className="acc-mv" disabled={!canUp} title="Move section up"
                      onClick={(e) => { e.stopPropagation(); onMoveUp(); }}>
                <span className="mv-up"><I.ChevDown size={13} /></span>
              </button>
              <button className="acc-mv" disabled={!canDown} title="Move section down"
                      onClick={(e) => { e.stopPropagation(); onMoveDown(); }}>
                <I.ChevDown size={13} />
              </button>
            </div>
          )}
          <div className="acc-ico" style={{ background: color }}><Ic size={17} /></div>
          <div className="acc-titles">
            <h3>{title}</h3>
            <p>{summary}</p>
          </div>
          {!noToggle && <Toggle on={enabled} onClick={onToggle} />}
          <span className="acc-chev"><I.Arrow size={16} /></span>
        </div>
        {open && <div className="acc-body">{children}</div>}
      </div>
    );
  }

  function PillList({ items, setItems }) {
    const [v, setV] = useState("");
    const add = () => { if (v.trim()) { setItems([...(items || []), v.trim()]); setV(""); } };
    return (
      <div className="fld">
        <label>Takeaways</label>
        <div className="pills">
          {(items || []).map((t, i) => (
            <span className="pill-i" key={i}>
              {t}
              <button onClick={() => setItems(items.filter((_, j) => j !== i))}>×</button>
            </span>
          ))}
        </div>
        <div className="pill-add">
          <input value={v} placeholder="Add takeaway…" onChange={(e) => setV(e.target.value)}
                 onKeyDown={(e) => e.key === "Enter" && add()} />
          <button onClick={add}>Add</button>
        </div>
      </div>
    );
  }

  function ListBlock({ items, setItems, blank, label, render }) {
    return (
      <div>
        {(items || []).map((it, i) => (
          <div className="litem" key={i}>
            <button className="litem-x" onClick={() => setItems(items.filter((_, j) => j !== i))}>×</button>
            <div className="litem-n">{label} {i + 1}</div>
            {render(it, (patch) => setItems(items.map((x, j) => j === i ? { ...x, ...patch } : x)))}
          </div>
        ))}
        <button className="add-btn" onClick={() => setItems([...(items || []), { ...blank }])}>
          <I.Sparkle size={14} /> Add {label.toLowerCase()}
        </button>
      </div>
    );
  }

  function pfFirstName(name) { return String(name || "").trim().split(/\s+/)[0] || String(name || ""); }
  function pfInitials(name) {
    const parts = String(name || "").trim().split(/\s+/).filter(Boolean);
    if (!parts.length) return "";
    if (parts.length === 1) return parts[0].slice(0, 2).toUpperCase();
    return (parts[0][0] + parts[parts.length - 1][0]).toUpperCase();
  }

  function Avatar({ photo, initials, size }) {
    const s = size || 30;
    if (photo) return <img src={photo} alt="" style={{ width: s, height: s, borderRadius: "50%", objectFit: "cover", display: "block", flexShrink: 0 }} />;
    return (
      <div style={{ width: s, height: s, borderRadius: "50%", flexShrink: 0,
                    background: "linear-gradient(135deg,#004860,#00778B)", color: "#fff",
                    display: "flex", alignItems: "center", justifyContent: "center",
                    fontSize: Math.round(s * 0.36), fontWeight: 800, letterSpacing: ".3px" }}>
        {initials || "?"}
      </div>
    );
  }

  // "Written by" chips in the Welcome section — pick who's writing this issue's note.
  function AuthorPicker({ profiles, currentUser, authorId, onPick, onManage }) {
    const meId = currentUser ? String(currentUser).replace(/khyp$/i, "").toLowerCase() : null;
    const chip = (on) => ({
      display: "inline-flex", alignItems: "center", gap: 7, cursor: "pointer",
      fontFamily: "inherit", fontSize: 11.5, fontWeight: 600,
      padding: "4px 11px 4px 4px", borderRadius: 20, transition: ".12s",
      border: "1.5px solid " + (on ? "#00778B" : "#dce8ea"),
      background: on ? "#00778B" : "#fff", color: on ? "#fff" : "#33525e",
      boxShadow: on ? "0 0 0 2px rgba(0,119,139,.12)" : "none"
    });
    return (
      <div className="fld">
        <label>Written by</label>
        <div style={{ display: "flex", flexWrap: "wrap", gap: 6 }}>
          {(profiles || []).map((p) => {
            const on = authorId === p.id;
            return (
              <button key={p.id} onClick={() => onPick(p)} title={p.name + " · " + p.role} style={chip(on)}>
                <Avatar photo={p.photo} initials={p.initials} size={22} />
                <span>{pfFirstName(p.name)}{meId && p.id === meId ? " (you)" : ""}</span>
              </button>
            );
          })}
          <button onClick={() => onPick(null)} title="Someone not on the committee"
                  style={{ ...chip(!authorId), paddingLeft: 12 }}>Other…</button>
        </div>
        {onManage && (
          <button onClick={onManage}
                  style={{ border: "none", background: "none", color: "#00778B", fontFamily: "inherit",
                           fontSize: 11.5, fontWeight: 700, cursor: "pointer", padding: "9px 0 2px",
                           display: "inline-flex", alignItems: "center", gap: 6 }}>
            <I.Image size={13} /> Manage committee profiles &amp; photos
          </button>
        )}
      </div>
    );
  }

  // Shared profile manager (photo + role per committee member).
  function ProfilesModal({ profiles, updateProfile, onClose }) {
    return (
      <div onClick={onClose}
           style={{ position: "fixed", inset: 0, zIndex: 100, background: "rgba(0,40,54,.44)",
                    display: "flex", alignItems: "center", justifyContent: "center", padding: 18 }}>
        <div onClick={(e) => e.stopPropagation()}
             style={{ width: 420, maxWidth: "100%", maxHeight: "88vh", display: "flex", flexDirection: "column",
                      background: "#fff", borderRadius: 16, boxShadow: "0 24px 70px rgba(0,40,54,.34)", overflow: "hidden" }}>
          <div style={{ padding: "18px 20px 14px", borderBottom: "1px solid #eef4f5", display: "flex", alignItems: "flex-start", gap: 12 }}>
            <div style={{ flex: 1, minWidth: 0 }}>
              <div style={{ fontSize: 15, fontWeight: 800, color: "#004860" }}>Committee profiles</div>
              <div style={{ fontSize: 11.5, color: "#6D6E71", marginTop: 3, lineHeight: 1.5 }}>
                Photos &amp; roles are shared and reused every time someone is picked in a Welcome note.
              </div>
            </div>
            <button onClick={onClose} title="Close"
                    style={{ border: "none", background: "#F4F8F9", color: "#004860", width: 30, height: 30,
                             borderRadius: 8, cursor: "pointer", fontSize: 18, lineHeight: 1, flexShrink: 0 }}>×</button>
          </div>
          <div style={{ overflowY: "auto", padding: "14px 20px 18px" }}>
            {(profiles || []).map((p) => (
              <div key={p.id} style={{ border: "1px solid #e7f0f0", borderRadius: 12, padding: 13, marginBottom: 12, background: "#fbfdfd" }}>
                <div style={{ display: "flex", alignItems: "center", gap: 12, marginBottom: 11 }}>
                  <Avatar photo={p.photo} initials={p.initials} size={46} />
                  <div style={{ flex: 1, minWidth: 0 }}>
                    <div style={{ fontWeight: 700, color: "#004860", fontSize: 13.5 }}>{p.name || "Unnamed"}</div>
                    <div style={{ fontSize: 11, color: "#6D6E71" }}>{p.role}</div>
                  </div>
                </div>
                <div className="frow">
                  <Field label="Name" val={p.name} set={(v) => updateProfile(p.id, { name: v, initials: pfInitials(v) })} />
                  <Field label="Initials" val={p.initials} set={(v) => updateProfile(p.id, { initials: v })} />
                </div>
                <Field label="Role" val={p.role} set={(v) => updateProfile(p.id, { role: v })} />
                <ImageField label="Photo" hint="A square headshot works best" value={p.photo}
                            set={(v) => updateProfile(p.id, { photo: v })} maxW={600} />
              </div>
            ))}
          </div>
          <div style={{ padding: 14, borderTop: "1px solid #eef4f5" }}>
            <button className="btn btn-prime" onClick={onClose} style={{ width: "100%" }}>Done</button>
          </div>
        </div>
      </div>
    );
  }

  function Editor({ content, setContent, profiles, updateProfile, currentUser }) {
    const c = content;
    const CustomEditor = window.PulseCustomEditor;
    const [showProfiles, setShowProfiles] = useState(false);

    // pick who's writing the welcome note -> copy their profile into this issue
    const pickAuthor = (p) => setContent((prev) => ({
      ...prev,
      welcome: p
        ? { ...prev.welcome, authorId: p.id, name: p.name, role: p.role, initials: p.initials, photo: p.photo || "" }
        : { ...prev.welcome, authorId: null }
    }));
    // when the profile manager closes, pull a newly-added photo into the current note
    const closeProfiles = () => {
      setShowProfiles(false);
      const aid = c.welcome.authorId;
      if (!aid) return;
      const p = (profiles || []).find((x) => x.id === aid);
      if (p && p.photo) setContent((prev) => ({ ...prev, welcome: { ...prev.welcome, photo: p.photo } }));
    };
    const sset = (sec, key) => (val) => setContent((p) => ({ ...p, [sec]: { ...p[sec], [key]: val } }));
    const toggle = (sec) => () => setContent((p) => ({ ...p, [sec]: { ...p[sec], enabled: !p[sec].enabled } }));
    const setList = (sec, key) => (arr) => setContent((p) => ({ ...p, [sec]: { ...p[sec], [key]: arr } }));

    // section reorder — includes dynamic custom_* sections
    const DEFAULT_ORDER = ["welcome", "featured", "recap", "spotlight", "upcoming", "community"];
    const isCustom = (k) => c[k] && c[k].type === "custom";
    const customKeys = Object.keys(c).filter(isCustom);
    const allKeys = DEFAULT_ORDER.concat(customKeys);
    const norm = (p) => {
      const ck = Object.keys(p).filter((k) => p[k] && p[k].type === "custom");
      const valid = DEFAULT_ORDER.concat(ck);
      let ord = (p.sectionOrder || DEFAULT_ORDER).filter((k) => valid.indexOf(k) !== -1);
      valid.forEach((k) => { if (ord.indexOf(k) === -1) ord.push(k); });
      return ord;
    };
    const order = norm(c);
    const moveSection = (key, dir) => setContent((p) => {
      const ord = norm(p);
      const i = ord.indexOf(key); const j = i + dir;
      if (i < 0 || j < 0 || j >= ord.length) return p;
      ord.splice(j, 0, ord.splice(i, 1)[0]);
      return { ...p, sectionOrder: ord };
    });
    const mv = (key) => {
      const i = order.indexOf(key);
      return {
        style: { order: i },
        onMoveUp: () => moveSection(key, -1),
        onMoveDown: () => moveSection(key, 1),
        canUp: i > 0,
        canDown: i < order.length - 1
      };
    };

    const addCustom = () => setContent((p) => {
      const key = "custom_" + Math.random().toString(36).slice(2, 8);
      const ord = norm(p);
      ord.push(key);
      return { ...p, [key]: window.pulseMakeCustom(), sectionOrder: ord };
    });
    const deleteCustom = (key) => {
      if (!confirm("Delete this custom section? This cannot be undone.")) return;
      setContent((p) => {
        const next = { ...p };
        delete next[key];
        next.sectionOrder = norm(p).filter((k) => k !== key);
        return next;
      });
    };

    const mastheads = [
      { id: "editorial", cls: "thumb-ed", name: "Editorial" },
      { id: "banner", cls: "thumb-bn", name: "Banner" },
      { id: "gradient", cls: "thumb-gr", name: "Gradient" }
    ];

    return (
      <React.Fragment>
        {/* Masthead direction */}
        <div className="mast-pick">
          <div className="lbl">Masthead Style</div>
          <div className="mast-opts">
            {mastheads.map((m) => (
              <div key={m.id}
                   className={"mast-opt" + (c.meta.masthead === m.id ? " on" : "")}
                   onClick={() => sset("meta", "masthead")(m.id)}>
                <div className={"mast-thumb " + m.cls} />
                <span>{m.name}</span>
              </div>
            ))}
          </div>
        </div>

        {/* Issue details */}
        <Acc ic={I.Calendar} color="#004860" title="Issue Details" noToggle defaultOpen
             summary={`${c.meta.month} ${c.meta.year} · Issue ${c.meta.issueNo}`}>
          <div className="frow">
            <Field label="Month" val={c.meta.month} set={sset("meta", "month")} />
            <Field label="Year" val={c.meta.year} set={sset("meta", "year")} />
          </div>
          <Field label="Issue #" val={c.meta.issueNo} set={sset("meta", "issueNo")} />
          <Field label="Brand line" val={c.meta.brand} set={sset("meta", "brand")} />
          <Field label="Tagline" val={c.meta.tagline} set={sset("meta", "tagline")} area rows={2} />
        </Acc>

        <div className="reorder">
        {/* Welcome */}
        <Acc {...mv("welcome")} ic={I.Heart} color="#00778B" title="Welcome Note" enabled={c.welcome.enabled}
             onToggle={toggle("welcome")} summary={c.welcome.name + " · " + c.welcome.role}>
          <AuthorPicker profiles={profiles} currentUser={currentUser} authorId={c.welcome.authorId}
                        onPick={pickAuthor} onManage={() => setShowProfiles(true)} />
          <div className="frow">
            <Field label="Name" val={c.welcome.name} set={sset("welcome", "name")} />
            <Field label="Initials" val={c.welcome.initials} set={sset("welcome", "initials")} />
          </div>
          <Field label="Role" val={c.welcome.role} set={sset("welcome", "role")} />
          <ImageField label="Author photo (optional)" hint="Replaces the initials circle"
                      value={c.welcome.photo} set={sset("welcome", "photo")} maxW={600} />
          <Field label="Message" val={c.welcome.body} set={sset("welcome", "body")} area rows={5} />
        </Acc>

        {/* Featured event */}
        <Acc {...mv("featured")} ic={I.Sparkle} color="#00B7BD" title="Featured Event" enabled={c.featured.enabled}
             onToggle={toggle("featured")} summary={c.featured.title}>
          <Field label="Eyebrow chip" val={c.featured.kicker} set={sset("featured", "kicker")} />
          <Field label="Event title" val={c.featured.title} set={sset("featured", "title")} />
          <Field label="Date & time" val={c.featured.date} set={sset("featured", "date")} />
          <Field label="Location" val={c.featured.location} set={sset("featured", "location")} />
          <Field label="Third detail line" val={c.featured.paces} set={sset("featured", "paces")} />
          <Field label="Description" val={c.featured.description} set={sset("featured", "description")} area rows={4} />
          <Field label="Bring-a-friend line" val={c.featured.friend} set={sset("featured", "friend")} area rows={2} />
          <ImageField label="Event photo (optional)" hint="Shown at the top of the card"
                      value={c.featured.image} set={sset("featured", "image")} maxW={1100} />
          <ToggleRow label="Show QR code" hint="Auto-built from the sign-up link below"
                     on={c.featured.showQr !== false} set={(v) => sset("featured", "showQr")(v)} />
          {c.featured.showQr !== false && (
            <div className="frow">
              <Field label="QR caption" val={c.featured.qrCaption} set={sset("featured", "qrCaption")} />
              <Field label="QR / sign-up URL" val={c.featured.qrUrl} set={sset("featured", "qrUrl")} />
            </div>
          )}
        </Acc>

        {/* Recap */}
        <Acc {...mv("recap")} ic={I.Mic} color="#0a9aa3" title="Event Recap" enabled={c.recap.enabled}
             onToggle={toggle("recap")} summary={c.recap.name}>
          <Field label="Event tag" val={c.recap.eventTag} set={sset("recap", "eventTag")} />
          <div className="frow">
            <Field label="Speaker name" val={c.recap.name} set={sset("recap", "name")} />
            <Field label="Initials" val={c.recap.initials} set={sset("recap", "initials")} />
          </div>
          <Field label="Speaker role" val={c.recap.role} set={sset("recap", "role")} />
          <ImageField label="Speaker photo (optional)" hint="Replaces the initials circle"
                      value={c.recap.speakerPhoto} set={sset("recap", "speakerPhoto")} maxW={600} />
          <ImageField label="Event photo (optional)" hint="A shot from the event"
                      value={c.recap.photo} set={sset("recap", "photo")} maxW={1100} />
          {c.recap.photo && (
            <Segmented label="Photo size" value={c.recap.photoSize || "full"} set={sset("recap", "photoSize")}
                       opts={[{ id: "small", name: "Small" }, { id: "medium", name: "Medium" }, { id: "full", name: "Full width" }]} />
          )}
          <ParaEditor label="Body paragraph" paras={c.recap.paras} set={setList("recap", "paras")} />
          <Field label="Pull quote" val={c.recap.quote} set={sset("recap", "quote")} area rows={3} />
          <Field label="Quote attribution" val={c.recap.quoteBy} set={sset("recap", "quoteBy")} />
          <PillList items={c.recap.takeaways} setItems={setList("recap", "takeaways")} />
        </Acc>

        {/* Spotlight */}
        <Acc {...mv("spotlight")} ic={I.Star} color="#8C30F5" title="YP Spotlight" enabled={c.spotlight.enabled}
             onToggle={toggle("spotlight")} summary={c.spotlight.name}>
          <div className="frow">
            <Field label="Name" val={c.spotlight.name} set={sset("spotlight", "name")} />
            <Field label="Initials" val={c.spotlight.initials} set={sset("spotlight", "initials")} />
          </div>
          <Field label="Role / tenure" val={c.spotlight.role} set={sset("spotlight", "role")} />
          <ImageField label="Headshot (optional)" hint="Bigger when placed left or right"
                      value={c.spotlight.photo} set={sset("spotlight", "photo")} maxW={800} />
          {c.spotlight.photo && (
            <Segmented label="Photo layout" value={c.spotlight.photoLayout || "inline"} set={sset("spotlight", "photoLayout")}
                       opts={[{ id: "inline", name: "Small inline" }, { id: "left", name: "Big · left" }, { id: "right", name: "Big · right" }]} />
          )}
          <Field label="KH value" val={c.spotlight.value} set={sset("spotlight", "value")} />
          <ParaEditor label="Story paragraph" paras={c.spotlight.paras} set={setList("spotlight", "paras")} />
          <Field label="Pull quote" val={c.spotlight.quote} set={sset("spotlight", "quote")} area rows={3} />
          <Field label="Quote attribution" val={c.spotlight.quoteBy} set={sset("spotlight", "quoteBy")} />
          <Field label="Nominate callout" val={c.spotlight.nominate} set={sset("spotlight", "nominate")} area rows={3} />
        </Acc>

        {/* Upcoming */}
        <Acc {...mv("upcoming")} ic={I.List} color="#004860" title="Upcoming Events" enabled={c.upcoming.enabled}
             onToggle={toggle("upcoming")} summary={(c.upcoming.items || []).length + " events listed"}>
          <Field label="Intro line" val={c.upcoming.intro} set={sset("upcoming", "intro")} area rows={2} />
          <ListBlock items={c.upcoming.items} setItems={setList("upcoming", "items")} label="Event"
                     blank={{ day: "01", mon: "MAY", title: "", meta: "", tag: "Wellness" }}
                     render={(it, patch) => (
                       <React.Fragment>
                         <div className="frow">
                           <Field label="Day" val={it.day} set={(v) => patch({ day: v })} />
                           <Field label="Month (3 ltr)" val={it.mon} set={(v) => patch({ mon: v.toUpperCase() })} />
                         </div>
                         <Field label="Title" val={it.title} set={(v) => patch({ title: v })} />
                         <Field label="Time · place" val={it.meta} set={(v) => patch({ meta: v })} />
                         <TagSelect val={it.tag} set={(v) => patch({ tag: v })} opts={["Wellness", "Social", "Develop", "Serve"]} />
                       </React.Fragment>
                     )} />
        </Acc>

        {/* Community */}
        <Acc {...mv("community")} ic={I.People} color="#FF6A14" title="Community Corner" enabled={c.community.enabled}
             onToggle={toggle("community")} summary={(c.community.items || []).length + " opportunities"}>
          <Field label="Intro line" val={c.community.intro} set={sset("community", "intro")} area rows={2} />
          <ListBlock items={c.community.items} setItems={setList("community", "items")} label="Item"
                     blank={{ category: "", icon: "heart", title: "", desc: "", where: "" }}
                     render={(it, patch) => (
                       <React.Fragment>
                         <div className="frow">
                           <Field label="Category" val={it.category} set={(v) => patch({ category: v })} />
                           <IconSelect val={it.icon} set={(v) => patch({ icon: v })} />
                         </div>
                         <Field label="Title" val={it.title} set={(v) => patch({ title: v })} />
                         <Field label="Description" val={it.desc} set={(v) => patch({ desc: v })} area rows={3} />
                         <Field label="Where / when" val={it.where} set={(v) => patch({ where: v })} />
                       </React.Fragment>
                     )} />
        </Acc>

        {/* Custom sections */}
        {customKeys.map((key) => (
          <Acc key={key} {...mv(key)} ic={I.Sparkle} color={c[key].accent || "#00778B"}
               title={c[key].label || "Custom Section"} enabled={c[key].enabled}
               onToggle={toggle(key)} summary={(c[key].blocks || []).length + " block" + ((c[key].blocks || []).length === 1 ? "" : "s")}>
            <CustomEditor sectionKey={key} content={c} setContent={setContent} onDelete={() => deleteCustom(key)} />
          </Acc>
        ))}
        </div>

        {/* Add custom section */}
        <div className="add-custom-wrap">
          <button className="add-custom" onClick={addCustom}>
            <I.Plus size={16} /> Add custom section
          </button>
          <p className="add-custom-hint">A blank, fully flexible section — headings, text, images, galleries, stats, quotes, lists &amp; buttons.</p>
        </div>

        {/* Footer */}
        <Acc ic={I.Mail} color="#6D6E71" title="Footer & Contact" noToggle summary={c.footer.contactEmail}>
          <Field label="Contact email" val={c.footer.contactEmail} set={sset("footer", "contactEmail")} />
          <Field label="Audience line" val={c.footer.audience} set={sset("footer", "audience")} />
          <Field label="Get-involved line" val={c.footer.involve} set={sset("footer", "involve")} />
        </Acc>

        {showProfiles && (
          <ProfilesModal profiles={profiles} updateProfile={updateProfile} onClose={closeProfiles} />
        )}
      </React.Fragment>
    );
  }

  function ParaEditor({ label, paras, set }) {
    return (
      <div className="fld">
        <label>{label}s</label>
        {(paras || []).map((p, i) => (
          <div key={i} style={{ position: "relative", marginBottom: 8 }}>
            <textarea value={p} onChange={(e) => set(paras.map((x, j) => j === i ? e.target.value : x))}
                      style={{ minHeight: 70, width: "100%", fontFamily: "inherit", fontSize: "12.5px",
                               color: "#1d3c49", background: "#F4F8F9", border: "1.5px solid transparent",
                               borderRadius: 8, padding: "9px 30px 9px 11px", lineHeight: 1.5, resize: "vertical" }} />
            <button onClick={() => set(paras.filter((_, j) => j !== i))}
                    style={{ position: "absolute", top: 8, right: 8, width: 20, height: 20, borderRadius: 6,
                             border: "none", background: "#fff", color: "#CB2C30", cursor: "pointer", fontSize: 13,
                             boxShadow: "0 1px 3px rgba(0,0,0,.08)" }}>×</button>
          </div>
        ))}
        <button className="add-btn" onClick={() => set([...(paras || []), ""])}>
          <I.Sparkle size={14} /> Add paragraph
        </button>
      </div>
    );
  }

  function TagSelect({ val, set, opts }) {
    return (
      <div className="fld">
        <label>Tag</label>
        <div style={{ display: "flex", gap: 6, flexWrap: "wrap" }}>
          {opts.map((o) => (
            <button key={o} onClick={() => set(o)}
              style={{ fontFamily: "inherit", fontSize: 11, fontWeight: 700, padding: "6px 11px",
                       borderRadius: 7, cursor: "pointer", border: "1.5px solid",
                       borderColor: val === o ? "#00778B" : "#dce8ea",
                       background: val === o ? "#00778B" : "#fff",
                       color: val === o ? "#fff" : "#6D6E71" }}>{o}</button>
          ))}
        </div>
      </div>
    );
  }

  function IconSelect({ val, set }) {
    const opts = [
      { id: "run", Ic: I.Run }, { id: "book", Ic: I.Book }, { id: "hands", Ic: I.Hands },
      { id: "tree", Ic: I.Tree }, { id: "people", Ic: I.People }, { id: "heart", Ic: I.Heart }
    ];
    return (
      <div className="fld">
        <label>Icon</label>
        <div style={{ display: "flex", gap: 6, flexWrap: "wrap" }}>
          {opts.map(({ id, Ic }) => (
            <button key={id} onClick={() => set(id)} title={id}
              style={{ width: 34, height: 34, borderRadius: 8, cursor: "pointer", border: "1.5px solid",
                       display: "flex", alignItems: "center", justifyContent: "center",
                       borderColor: val === id ? "#00778B" : "#dce8ea",
                       background: val === id ? "#00778B" : "#fff",
                       color: val === id ? "#fff" : "#6D6E71" }}>
              <Ic size={17} />
            </button>
          ))}
        </div>
      </div>
    );
  }

  window.PulseEditor = Editor;
})();
