// Recursive MLS — Field Studio (MLS-staff schema console). Surface B, all screens.
// Edits the SAME window.RC_FIELDS registry the agent Add/Edit form renders from.
const { useState } = React;

function FieldStudio({ go }) {
  const F = window.RC_FIELDS;
  const _p = new URLSearchParams(location.search);
  const [tab, setTab] = useState(_p.get("fs") || "catalog");
  const [draft, setDraft] = useState(F.draft.changes);
  const [editKey, setEditKey] = useState(null);
  const [addOpen, setAddOpen] = useState(false);
  const addToDraft = (chg) => setDraft((d) => [...d, { id: "c" + (d.length + 1) + "_" + Date.now(), ...chg }]);
  const blocking = draft.filter((c) => c.blocking).length;

  const tabs = [
    { id: "catalog", icon: "table-2", label: "Field catalog" },
    { id: "enums", icon: "list", label: "Enumerations" },
    { id: "layout", icon: "layout-panel-left", label: "Layout designer" },
    { id: "rules", icon: "git-branch", label: "Rules builder" },
    { id: "statuses", icon: "activity", label: "Status map" },
    { id: "review", icon: "git-pull-request", label: "Review & publish", badge: draft.length },
  ];

  return (
    <div style={{ display: "flex", flexDirection: "column", height: "100%", minHeight: 0 }}>
      {/* ===== studio header ===== */}
      <div style={{ padding: "18px 28px 0", background: "#fff", borderBottom: "1px solid #ececec" }}>
        <div style={{ display: "flex", alignItems: "flex-start", justifyContent: "space-between", flexWrap: "wrap", gap: 16 }}>
          <div>
            <div style={{ display: "flex", alignItems: "center", gap: 11 }}>
              <span style={{ width: 34, height: 34, borderRadius: 8, background: "#006747", display: "flex", alignItems: "center", justifyContent: "center" }}><Icon name="sliders-horizontal" size={18} color="#fff" /></span>
              <div>
                <h1 style={{ margin: 0, fontSize: 21, fontWeight: 600, letterSpacing: "-0.5px", color: "#1d241f" }}>Field Studio</h1>
                <div style={{ fontSize: 12.5, color: "#8a8e88", marginTop: 1 }}>Customize your market's fields, lookups, layouts, rules & statuses — no vendor ticket.</div>
              </div>
            </div>
          </div>
          <div style={{ display: "flex", alignItems: "center", gap: 14 }}>
            <TenantPicker />
            <ConformanceMeter />
          </div>
        </div>
        {/* tabs */}
        <div style={{ display: "flex", gap: 3, marginTop: 16 }}>
          {tabs.map((t) => (
            <button key={t.id} onClick={() => setTab(t.id)} style={{ position: "relative", display: "inline-flex", alignItems: "center", gap: 8, border: 0, background: "transparent", fontFamily: "inherit", fontSize: 13.5, fontWeight: tab === t.id ? 600 : 500, color: tab === t.id ? "#006747" : "#6b706a", padding: "11px 14px", cursor: "pointer", borderBottom: tab === t.id ? "2px solid #006747" : "2px solid transparent" }}>
              <Icon name={t.icon} size={16} color={tab === t.id ? "#006747" : "#a8aca6"} /> {t.label}
              {t.badge > 0 && <span style={{ fontFamily: "'Space Mono', monospace", fontSize: 10.5, fontWeight: 700, color: "#fff", background: "#006747", borderRadius: 999, padding: "1px 7px" }}>{t.badge}</span>}
            </button>
          ))}
        </div>
      </div>

      {/* open-draft banner */}
      {draft.length > 0 && tab !== "review" && (
        <div style={{ display: "flex", alignItems: "center", gap: 11, background: blocking ? "#fdf4f3" : "#eef3fb", borderBottom: "1px solid " + (blocking ? "#f2d6d2" : "#d9e3f5"), padding: "10px 28px" }}>
          <Icon name={blocking ? "alert-triangle" : "git-pull-request-draft"} size={16} color={blocking ? "#b3261e" : "#2f6bd0"} />
          <span style={{ fontSize: 13, color: blocking ? "#7a2420" : "#2a4d86", flex: 1 }}><strong>{F.draft.name}</strong> · {draft.length} pending change{draft.length !== 1 ? "s" : ""}{blocking ? ` · ${blocking} blocking` : ""}</span>
          <button onClick={() => setTab("review")} style={{ ...fsBtnTiny, background: blocking ? "#b3261e" : "#2f6bd0", color: "#fff", border: 0 }}>Review & publish <Icon name="arrow-right" size={13} color="#fff" /></button>
        </div>
      )}

      {/* ===== content ===== */}
      <div style={{ flex: 1, overflowY: "auto", minHeight: 0, background: "#f4f3ef" }}>
        {tab === "catalog" && <Catalog onEdit={setEditKey} onAdd={() => setAddOpen(true)} />}
        {tab === "enums" && <EnumManager addToDraft={addToDraft} />}
        {tab === "layout" && <LayoutDesigner />}
        {tab === "rules" && <RulesBuilder />}
        {tab === "statuses" && <StatusMapEditor />}
        {tab === "review" && <ReviewPublish draft={draft} setDraft={setDraft} />}
      </div>

      {editKey && <FieldEditorDrawer fieldKey={editKey} onClose={() => setEditKey(null)} addToDraft={addToDraft} />}
      {addOpen && <AddFieldModal onClose={() => setAddOpen(false)} addToDraft={addToDraft} />}
    </div>
  );
}

/* ============================ header widgets ============================ */
function TenantPicker() {
  const F = window.RC_FIELDS;
  return (
    <button onClick={() => {}} style={{ display: "flex", alignItems: "center", gap: 9, background: "#f6f5f1", border: "1px solid #e7e5df", borderRadius: 8, padding: "8px 12px", cursor: "pointer", fontFamily: "inherit" }}>
      <span style={{ width: 8, height: 8, borderRadius: "50%", background: "#1f8a5b" }} />
      <div style={{ textAlign: "left" }}><div style={{ fontSize: 13, fontWeight: 600, color: "#1d241f" }}>{F.tenant.short}</div><div style={{ fontSize: 10.5, color: "#8a8e88" }}>{F.tenant.name}</div></div>
      <Icon name="chevron-down" size={15} color="#8a8e88" />
    </button>
  );
}
function ConformanceMeter() {
  const F = window.RC_FIELDS, c = F.conformance;
  const total = c.standard + c.local + c.idx;
  const col = c.score >= 80 ? "#1f8a5b" : c.score >= 60 ? "#9a6a12" : "#c0612f";
  return (
    <div style={{ display: "flex", alignItems: "center", gap: 16, background: "#f6f5f1", border: "1px solid #e7e5df", borderRadius: 10, padding: "9px 15px" }}>
      <div style={{ display: "flex", alignItems: "center", gap: 11 }}>
        <Ring pct={c.score} color={col} />
        <div>
          <div style={{ fontSize: 11, fontWeight: 600, letterSpacing: ".3px", textTransform: "uppercase", color: "#a8aca6" }}>DD conformance</div>
          <div style={{ display: "flex", alignItems: "baseline", gap: 6 }}><span style={{ fontFamily: "'Space Mono', monospace", fontSize: 18, fontWeight: 700, color: col }}>{c.score}%</span><span style={{ fontSize: 11.5, color: "#1f8a5b" }}>▲ {c.trend}</span></div>
        </div>
      </div>
      <div style={{ display: "flex", gap: 10, borderLeft: "1px solid #e2e0d8", paddingLeft: 15 }}>
        {[["standard", c.standard], ["local", c.local], ["idx", c.idx]].map(([p, n]) => { const ch = F.chip(p); return (
          <div key={p} style={{ textAlign: "center" }}><div style={{ fontFamily: "'Space Mono', monospace", fontSize: 15, fontWeight: 700, color: ch.fg }}>{n}</div><div style={{ fontSize: 9.5, fontWeight: 600, letterSpacing: ".3px", color: "#a8aca6", textTransform: "uppercase" }}>{ch.short}</div></div>
        ); })}
      </div>
    </div>
  );
}
function Ring({ pct, color, size = 40 }) {
  const r = size / 2 - 4, circ = 2 * Math.PI * r;
  return (
    <svg width={size} height={size} style={{ transform: "rotate(-90deg)", flex: "none" }}>
      <circle cx={size / 2} cy={size / 2} r={r} fill="none" stroke="#e6e4dc" strokeWidth="4" />
      <circle cx={size / 2} cy={size / 2} r={r} fill="none" stroke={color} strokeWidth="4" strokeLinecap="round" strokeDasharray={circ} strokeDashoffset={circ * (1 - pct / 100)} />
    </svg>
  );
}

/* ============================ B1 · Field catalog ============================ */
function Catalog({ onEdit, onAdd }) {
  const F = window.RC_FIELDS;
  const [prov, setProv] = useState("all");
  const [q, setQ] = useState("");
  const c = F.conformance;
  const rows = F.fields.filter((f) => (prov === "all" || f.provenance === prov) && (!q || f.key.toLowerCase().includes(q.toLowerCase()) || f.label.toLowerCase().includes(q.toLowerCase())));
  return (
    <div style={{ padding: "20px 28px 90px" }}>
      {/* quota nudge */}
      <div style={{ display: "flex", alignItems: "center", gap: 11, background: "#fbf7ea", border: "1px solid #efe6c8", borderRadius: 10, padding: "11px 15px", marginBottom: 16 }}>
        <Icon name="lightbulb" size={16} color="#9a6a12" />
        <span style={{ fontSize: 13, color: "#7a5a15", flex: 1 }}><strong>{c.local} local fields</strong> · consider mapping {c.quotaNudge} to DD {c.ddVersion} equivalents to raise conformance. Local fields still reach data consumers via your data API.</span>
      </div>

      <div style={{ display: "flex", alignItems: "center", gap: 12, marginBottom: 14, flexWrap: "wrap" }}>
        <div style={{ display: "flex", alignItems: "center", gap: 8, background: "#fff", borderRadius: 8, padding: "8px 12px", boxShadow: "inset 0 0 0 1px rgba(0,0,0,.08)", flex: 1, minWidth: 220, maxWidth: 340 }}>
          <Icon name="search" size={15} color="#a8aca6" />
          <input value={q} onChange={(e) => setQ(e.target.value)} placeholder="Search fields — name or key…" style={{ flex: 1, border: 0, outline: 0, background: "transparent", fontFamily: "inherit", fontSize: 13 }} />
        </div>
        <div style={{ display: "flex", background: "#fff", borderRadius: 8, padding: 3, boxShadow: "inset 0 0 0 1px rgba(0,0,0,.08)" }}>
          {[["all", "All"], ["standard", "Standard"], ["local", "Local"], ["idx", "IDX"]].map(([k, l]) => (
            <button key={k} onClick={() => setProv(k)} style={{ border: 0, background: prov === k ? "#eef4f1" : "transparent", color: prov === k ? "#006747" : "#6b706a", fontFamily: "inherit", fontSize: 12.5, fontWeight: 600, padding: "6px 13px", borderRadius: 6, cursor: "pointer" }}>{l}</button>
          ))}
        </div>
        <div style={{ flex: 1 }} />
        <button onClick={onAdd} style={fsBtnPrimary}><Icon name="plus" size={15} color="#fff" /> Add field</button>
      </div>

      <div style={{ background: "#fff", borderRadius: 10, boxShadow: "inset 0 0 0 1px rgba(0,0,0,.07)", overflow: "hidden" }}>
        <div style={{ display: "grid", gridTemplateColumns: "minmax(0,2.4fr) 90px 90px 96px 150px 70px", gap: 12, padding: "11px 18px", background: "#faf9f5", borderBottom: "1px solid #f1f0ea", fontSize: 10.5, fontWeight: 600, letterSpacing: ".4px", textTransform: "uppercase", color: "#a8aca6" }}>
          <span>Field</span><span>Type</span><span>Source</span><span>Lifecycle</span><span>Population</span><span>Refs</span>
        </div>
        {rows.map((f, i) => (
          <div key={f.key} onClick={() => onEdit(f.key)} className="rc-row" style={{ display: "grid", gridTemplateColumns: "minmax(0,2.4fr) 90px 90px 96px 150px 70px", gap: 12, padding: "12px 18px", alignItems: "center", cursor: "pointer", borderTop: i ? "1px solid #f4f3ee" : "none" }}>
            <div style={{ minWidth: 0 }}>
              <div style={{ fontSize: 13.5, fontWeight: 600, color: "#1d241f", display: "flex", alignItems: "center", gap: 7 }}>{f.label}{f.locked && <Icon name="lock" size={12} color="#9a6a12" />}{f.agentOnly && <Icon name="eye-off" size={12} color="#a8aca6" />}</div>
              <div style={{ fontFamily: "'Space Mono', monospace", fontSize: 11, color: "#8a8e88", marginTop: 2, overflow: "hidden", textOverflow: "ellipsis" }}>{f.key}</div>
            </div>
            <span style={{ fontSize: 12, color: "#6b706a" }}>{f.type}</span>
            <ProvChip prov={f.provenance} />
            <LifeChip life={f.life} />
            <PopBar pct={f.population} />
            <span style={{ fontSize: 12, color: "#8a8e88", fontFamily: "'Space Mono', monospace" }}>{f.lookup ? "1↗" : "—"}</span>
          </div>
        ))}
      </div>
    </div>
  );
}

/* ============================ B2 · Add-field DD-first flow ============================ */
function AddFieldModal({ onClose, addToDraft }) {
  const F = window.RC_FIELDS;
  const [step, setStep] = useState(1);
  const [q, setQ] = useState("Waterfront");
  const [label, setLabel] = useState("");
  const [type, setType] = useState("boolean");
  const results = F.ddCatalog.filter((d) => !q || d.name.toLowerCase().includes(q.toLowerCase()) || d.def.toLowerCase().includes(q.toLowerCase()));
  const key = "X_SABOR_" + (label.replace(/[^a-zA-Z0-9]/g, "") || "…");
  return (
    <div onClick={onClose} style={fsOverlay}>
      <div onClick={(e) => e.stopPropagation()} style={{ ...fsModal, width: 620 }}>
        <div style={fsModalHead}>
          <div><div style={{ fontSize: 16, fontWeight: 600, color: "#1d241f" }}>Add a field</div><div style={{ fontSize: 12.5, color: "#8a8e88", marginTop: 2 }}>{step === 1 ? "Search the RESO Data Dictionary first — adopting a standard field keeps you interoperable." : "No standard field fits — register a governed local field."}</div></div>
          <button onClick={onClose} style={fsIconBtn}><Icon name="x" size={16} color="#8a8e88" /></button>
        </div>

        {step === 1 ? (
          <div style={{ padding: 18 }}>
            <div style={{ display: "flex", alignItems: "center", gap: 9, background: "#f6f5f1", border: "1px solid #e7e5df", borderRadius: 9, padding: "11px 13px" }}>
              <Icon name="search" size={17} color="#8a8e88" />
              <input autoFocus value={q} onChange={(e) => setQ(e.target.value)} placeholder="Search DD fields — e.g. Waterfront, View, Fireplace…" style={{ flex: 1, border: 0, outline: 0, background: "transparent", fontFamily: "inherit", fontSize: 14 }} />
              <span style={{ fontSize: 11, color: "#a8aca6" }}>DD {F.conformance.ddVersion}</span>
            </div>
            <div style={{ marginTop: 12, display: "flex", flexDirection: "column", gap: 8, maxHeight: 300, overflowY: "auto" }}>
              {results.map((d) => (
                <div key={d.name} style={{ display: "flex", alignItems: "flex-start", gap: 12, borderRadius: 10, boxShadow: "inset 0 0 0 1px rgba(0,0,0,.08)", padding: "12px 14px" }}>
                  <span style={{ width: 30, height: 30, borderRadius: 7, background: "#e8f4ee", display: "flex", alignItems: "center", justifyContent: "center", flex: "none" }}><Icon name="check-check" size={15} color="#1f8a5b" /></span>
                  <div style={{ flex: 1, minWidth: 0 }}>
                    <div style={{ display: "flex", alignItems: "center", gap: 8 }}>
                      <span style={{ fontFamily: "'Space Mono', monospace", fontSize: 13, fontWeight: 700, color: "#1d241f" }}>{d.name}</span>
                      <ProvChip prov="standard" size="xs" />
                      {d.active && <span style={{ fontSize: 10, fontWeight: 700, color: "#8a8e88", background: "#f0efe9", borderRadius: 999, padding: "2px 7px" }}>ALREADY ACTIVE</span>}
                    </div>
                    <div style={{ fontSize: 12, color: "#8a8e88", marginTop: 3, lineHeight: 1.45 }}>{d.type} · {d.def}</div>
                  </div>
                  {d.active ? <span style={{ fontSize: 12, color: "#a8aca6", alignSelf: "center" }}>In registry</span> :
                    <button onClick={() => { addToDraft({ kind: "field", verb: "Adopt standard field", target: d.name, provenance: "standard", detail: `Adopt DD field ${d.name} — key frozen, config editable.`, refs: { layouts: 0, rules: 0, statuses: 0 }, records: 0, blocking: false }); onClose(); }} style={{ ...fsBtnTiny, background: "#006747", color: "#fff", border: 0, alignSelf: "center" }}>Adopt</button>}
                </div>
              ))}
            </div>
            <div style={{ marginTop: 16, borderTop: "1px solid #f1f0ea", paddingTop: 14, display: "flex", justifyContent: "flex-end" }}>
              <button onClick={() => setStep(2)} style={{ display: "inline-flex", alignItems: "center", gap: 6, background: "transparent", border: 0, cursor: "pointer", fontFamily: "inherit", fontSize: 13, color: "#8a8e88" }}>None of these match <Icon name="arrow-right" size={14} color="#8a8e88" /></button>
            </div>
          </div>
        ) : (
          <div style={{ padding: 18, display: "flex", flexDirection: "column", gap: 14 }}>
            <div style={{ display: "flex", alignItems: "center", gap: 8, fontSize: 12.5, color: "#9a6a12", background: "#fbf2dc", borderRadius: 8, padding: "9px 12px" }}>
              <Icon name="info" size={14} color="#9a6a12" /> Local fields cost interoperability — data partners must map them. Register only when no standard field fits.
            </div>
            <div style={{ display: "grid", gridTemplateColumns: "1fr 1fr", gap: 12 }}>
              <label style={fsLabel}><span style={fsLabelTx}>Display label</span><input autoFocus value={label} onChange={(e) => setLabel(e.target.value)} placeholder="Waterfront name" style={fsInp} /></label>
              <label style={fsLabel}><span style={fsLabelTx}>Frozen key (auto)</span><div style={{ ...fsInp, fontFamily: "'Space Mono', monospace", color: "#006747", background: "#f6f5f1", display: "flex", alignItems: "center" }}>{key}</div></label>
            </div>
            <label style={fsLabel}><span style={fsLabelTx}>Type</span>
              <div style={{ display: "flex", gap: 6, flexWrap: "wrap" }}>{["text", "number", "money", "boolean", "enum", "multi", "date"].map((t) => (
                <button key={t} onClick={() => setType(t)} style={{ border: type === t ? "1.5px solid #006747" : "1px solid #e2e0d8", background: type === t ? "#eef4f1" : "#fff", color: type === t ? "#006747" : "#6b706a", fontFamily: "inherit", fontSize: 12.5, fontWeight: 600, padding: "7px 13px", borderRadius: 7, cursor: "pointer" }}>{t}</button>
              ))}</div>
            </label>
            <label style={fsLabel}><span style={fsLabelTx}>Nearest DD field <span style={{ color: "#c0612f" }}>* required</span></span><input placeholder="WaterBodyName" style={fsInp} /></label>
            <label style={fsLabel}><span style={fsLabelTx}>Why no standard field fits <span style={{ color: "#c0612f" }}>*</span></span><textarea placeholder="SABOR tracks the specific named lake/river; DD has only a boolean WaterfrontYN." style={{ ...fsInp, height: 60, resize: "vertical", fontFamily: "inherit" }} /></label>
            <div style={{ background: "#faf9f5", borderRadius: 9, padding: "12px 14px" }}>
              <div style={{ fontSize: 11, fontWeight: 600, letterSpacing: ".3px", textTransform: "uppercase", color: "#a8aca6", marginBottom: 8 }}>Backend support preview</div>
              <div style={{ display: "flex", gap: 18 }}>
                <span style={{ display: "inline-flex", alignItems: "center", gap: 6, fontSize: 12.5, color: "#1f8a5b" }}><Icon name="check-circle-2" size={14} color="#1f8a5b" /> Lattice · sidecar field</span>
                <span style={{ display: "inline-flex", alignItems: "center", gap: 6, fontSize: 12.5, color: "#1f8a5b" }}><Icon name="check-circle-2" size={14} color="#1f8a5b" /> Displet · custom field</span>
              </div>
            </div>
            <div style={{ display: "flex", justifyContent: "space-between", borderTop: "1px solid #f1f0ea", paddingTop: 14 }}>
              <button onClick={() => setStep(1)} style={fsBtnOutline}><Icon name="arrow-left" size={14} color="#006747" /> Back to DD search</button>
              <button onClick={() => { addToDraft({ kind: "field", verb: "Add local field", target: key, provenance: "local", detail: `New ${type} local field — delivered to data consumers via the SABOR data API.`, refs: { layouts: 0, rules: 0, statuses: 0 }, records: 0, blocking: false }); onClose(); }} disabled={!label} style={{ ...fsBtnPrimary, opacity: label ? 1 : 0.5 }}>Add to draft</button>
            </div>
          </div>
        )}
      </div>
    </div>
  );
}

/* ============================ B3 · Field editor drawer ============================ */
function FieldEditorDrawer({ fieldKey, onClose, addToDraft }) {
  const F = window.RC_FIELDS, f = F.byKey(fieldKey);
  const [label, setLabel] = useState(f.label);
  const [help, setHelp] = useState(f.help || "");
  const [span, setSpan] = useState(f.span);
  const [searchable, setSearchable] = useState(!!f.searchable);
  const [updatable, setUpdatable] = useState(!!f.updatable);
  const [agentOnly, setAgentOnly] = useState(!!f.agentOnly);
  const facts = [["Key", f.key], ["Type", f.type], ["Provenance", F.chip(f.provenance).label], ["DD mapping", f.ddMapping || "—"]];
  return (
    <div onClick={onClose} style={fsOverlay}>
      <div onClick={(e) => e.stopPropagation()} style={{ position: "absolute", top: 0, right: 0, bottom: 0, width: 460, background: "#fff", boxShadow: "-12px 0 40px rgba(0,0,0,.2)", display: "flex", flexDirection: "column" }}>
        <div style={{ padding: "16px 20px", borderBottom: "1px solid #f1f0ea", display: "flex", alignItems: "flex-start", justifyContent: "space-between", gap: 10 }}>
          <div>
            <div style={{ display: "flex", alignItems: "center", gap: 8 }}><div style={{ fontSize: 16, fontWeight: 600, color: "#1d241f" }}>{f.label}</div><ProvChip prov={f.provenance} /><LifeChip life={f.life} /></div>
            <div style={{ fontFamily: "'Space Mono', monospace", fontSize: 12, color: "#8a8e88", marginTop: 3 }}>{f.key}</div>
          </div>
          <button onClick={onClose} style={fsIconBtn}><Icon name="x" size={17} color="#8a8e88" /></button>
        </div>
        <div style={{ flex: 1, overflowY: "auto", padding: 20, display: "flex", flexDirection: "column", gap: 16 }}>
          {/* immutable facts */}
          <div style={{ background: "#faf9f5", borderRadius: 9, padding: "13px 15px" }}>
            <div style={{ fontSize: 11, fontWeight: 600, letterSpacing: ".3px", textTransform: "uppercase", color: "#a8aca6", marginBottom: 10, display: "flex", alignItems: "center", gap: 6 }}><Icon name="lock" size={12} color="#a8aca6" /> Immutable facts</div>
            <div style={{ display: "grid", gridTemplateColumns: "1fr 1fr", gap: "10px 14px" }}>
              {facts.map(([k, v]) => <div key={k}><div style={{ fontSize: 10.5, color: "#a8aca6" }}>{k}</div><div style={{ fontSize: 13, fontWeight: 500, color: "#4a504a", fontFamily: k === "Key" ? "'Space Mono', monospace" : "inherit" }}>{v}</div></div>)}
            </div>
          </div>
          {/* mutable surface */}
          <div style={{ fontSize: 11, fontWeight: 600, letterSpacing: ".3px", textTransform: "uppercase", color: "#a8aca6" }}>Configuration</div>
          <label style={fsLabel}><span style={fsLabelTx}>Label</span><input value={label} onChange={(e) => setLabel(e.target.value)} style={fsInp} /></label>
          <label style={fsLabel}><span style={fsLabelTx}>Help text</span><input value={help} onChange={(e) => setHelp(e.target.value)} placeholder="Shown under the field" style={fsInp} /></label>
          <label style={fsLabel}><span style={fsLabelTx}>Column span (of 12)</span>
            <div style={{ display: "flex", gap: 5 }}>{[3, 4, 6, 8, 12].map((s) => <button key={s} onClick={() => setSpan(s)} style={{ flex: 1, border: span === s ? "1.5px solid #006747" : "1px solid #e2e0d8", background: span === s ? "#eef4f1" : "#fff", color: span === s ? "#006747" : "#6b706a", fontFamily: "inherit", fontSize: 12.5, fontWeight: 600, padding: "7px 0", borderRadius: 7, cursor: "pointer" }}>{s}</button>)}</div>
          </label>
          <Toggle label="Searchable" sub="Appears as a filter & search column" on={searchable} onChange={setSearchable} />
          <Toggle label="Updatable by agents" sub="Agents can edit after publish" on={updatable} onChange={setUpdatable} />
          <Toggle label="Agent-only" sub="Hidden from the public listing" on={agentOnly} onChange={setAgentOnly} />
          {f.lookup && <div style={{ display: "flex", alignItems: "center", gap: 9, background: "#faf9f5", borderRadius: 9, padding: "11px 14px" }}><Icon name="list" size={15} color="#8a8e88" /><span style={{ fontSize: 13, color: "#4a504a", flex: 1 }}>Bound lookup: <strong>{f.lookup}</strong></span><span style={{ fontSize: 12, color: "#006747", fontWeight: 600 }}>Manage →</span></div>}
          {/* lifecycle actions */}
          <div style={{ borderTop: "1px solid #f1f0ea", paddingTop: 16 }}>
            <div style={{ fontSize: 11, fontWeight: 600, letterSpacing: ".3px", textTransform: "uppercase", color: "#a8aca6", marginBottom: 10 }}>Lifecycle</div>
            <div style={{ display: "flex", gap: 8 }}>
              <button onClick={() => { addToDraft({ kind: "field", verb: "Deprecate field", target: f.key, detail: "Deprecate — stays on historical records as a tombstone.", refs: { layouts: 1, rules: 0, statuses: 0 }, records: Math.round(f.population * 31), blocking: false }); onClose(); }} style={{ ...fsBtnOutline, color: "#9a6a12", borderColor: "#e6d6a8" }}>Deprecate</button>
              <button style={{ ...fsBtnOutline, color: "#b3261e", borderColor: "#f0d6d3" }}>Retire</button>
            </div>
            <div style={{ fontSize: 11.5, color: "#a8aca6", marginTop: 9, lineHeight: 1.5 }}>Referenced by <strong>1 layout</strong> · populated on <strong>{f.population}%</strong> of listings. These are previewed before the change lands in the draft.</div>
          </div>
        </div>
        <div style={{ padding: "14px 20px", borderTop: "1px solid #f1f0ea", display: "flex", justifyContent: "flex-end", gap: 10 }}>
          <button onClick={onClose} style={fsBtnOutline}>Cancel</button>
          <button onClick={() => { addToDraft({ kind: "field", verb: "Edit field config", target: f.key, detail: `Label, span & flags updated on ${f.label}.`, refs: { layouts: 1, rules: 0, statuses: 0 }, records: 0, blocking: false }); onClose(); }} style={fsBtnPrimary}>Add to draft</button>
        </div>
      </div>
    </div>
  );
}

/* ============================ B4 · Enum manager ============================ */
function EnumManager({ addToDraft }) {
  const F = window.RC_FIELDS;
  const keys = Object.keys(F.lookups);
  const [sel, setSel] = useState(keys[1]); // PropertySubType (has parent + alias)
  const [merge, setMerge] = useState(null);
  const lk = F.lookups[sel];
  const active = lk.values.filter((v) => v.life !== "retired");
  const retired = lk.values.filter((v) => v.life === "retired");
  return (
    <div style={{ padding: "20px 28px 90px", display: "grid", gridTemplateColumns: "230px 1fr", gap: 20, alignItems: "start" }}>
      <div style={{ background: "#fff", borderRadius: 10, boxShadow: "inset 0 0 0 1px rgba(0,0,0,.07)", overflow: "hidden" }}>
        <div style={{ padding: "11px 14px", fontSize: 11, fontWeight: 600, letterSpacing: ".4px", textTransform: "uppercase", color: "#a8aca6", borderBottom: "1px solid #f1f0ea" }}>Lookups</div>
        {keys.map((k) => (
          <div key={k} onClick={() => setSel(k)} className="rc-row" style={{ padding: "10px 14px", cursor: "pointer", background: sel === k ? "#eef4f1" : "transparent", borderLeft: sel === k ? "3px solid #006747" : "3px solid transparent" }}>
            <div style={{ fontSize: 13, fontWeight: sel === k ? 600 : 500, color: sel === k ? "#006747" : "#4a504a" }}>{F.lookups[k].label}</div>
            <div style={{ fontSize: 11, color: "#a8aca6" }}>{F.lookups[k].values.filter((v) => v.life !== "retired").length} values{F.lookups[k].parentOf ? " · dependent" : ""}</div>
          </div>
        ))}
      </div>

      <div style={{ background: "#fff", borderRadius: 10, boxShadow: "inset 0 0 0 1px rgba(0,0,0,.07)", overflow: "hidden" }}>
        <div style={{ padding: "14px 18px", borderBottom: "1px solid #f1f0ea", display: "flex", alignItems: "center", gap: 10 }}>
          <div style={{ flex: 1 }}><div style={{ fontSize: 15, fontWeight: 600, color: "#1d241f", display: "flex", alignItems: "center", gap: 8 }}>{lk.label} <ProvChip prov={lk.provenance} /></div><div style={{ fontFamily: "'Space Mono', monospace", fontSize: 11.5, color: "#8a8e88", marginTop: 2 }}>{lk.key}{lk.parentOf ? ` · depends on ${lk.parentOf}` : ""}</div></div>
          <button style={fsBtnOutline}><Icon name="plus" size={14} color="#006747" /> Add value</button>
        </div>
        {/* table head */}
        <div style={{ display: "grid", gridTemplateColumns: lk.parentOf ? "1fr 1fr 130px 100px 90px" : "1fr 1fr 130px 90px", gap: 12, padding: "9px 18px", background: "#faf9f5", borderBottom: "1px solid #f1f0ea", fontSize: 10.5, fontWeight: 600, letterSpacing: ".4px", textTransform: "uppercase", color: "#a8aca6" }}>
          <span>Display label</span><span>Key (frozen)</span>{lk.parentOf && <span>Parent</span>}<span>Lifecycle</span><span>Sort</span>
        </div>
        {active.map((v, i) => (
          <div key={v.key} style={{ display: "grid", gridTemplateColumns: lk.parentOf ? "1fr 1fr 130px 100px 90px" : "1fr 1fr 130px 90px", gap: 12, padding: "10px 18px", alignItems: "center", borderTop: i ? "1px solid #f4f3ee" : "none" }} className="rc-row">
            <input defaultValue={v.label} style={{ ...fsInp, padding: "6px 9px", fontSize: 13 }} />
            <span style={{ fontFamily: "'Space Mono', monospace", fontSize: 11.5, color: "#a8aca6" }}>{v.key}</span>
            {lk.parentOf && <span style={{ fontSize: 12, color: "#6b706a" }}>{v.parent || "—"}</span>}
            <LifeChip life={v.life} />
            <div style={{ display: "flex", gap: 4, alignItems: "center" }}>
              <button style={fsSortBtn}><Icon name="chevron-up" size={14} color="#8a8e88" /></button>
              <button style={fsSortBtn}><Icon name="chevron-down" size={14} color="#8a8e88" /></button>
              <button onClick={() => setMerge(v)} title="Merge into…" style={fsSortBtn}><Icon name="git-merge" size={13} color="#8a8e88" /></button>
            </div>
          </div>
        ))}
        {retired.length > 0 && (
          <details style={{ borderTop: "1px solid #f1f0ea" }}>
            <summary style={{ padding: "11px 18px", fontSize: 12.5, fontWeight: 600, color: "#8a8e88", cursor: "pointer" }}>Retired values ({retired.length}) — still render on historical listings</summary>
            {retired.map((v) => (
              <div key={v.key} style={{ display: "flex", alignItems: "center", gap: 12, padding: "9px 18px", borderTop: "1px solid #f4f3ee", opacity: 0.7 }}>
                <span style={{ flex: 1, fontSize: 13, color: "#8a8e88", textDecoration: "line-through" }}>{v.label}</span>
                <span style={{ fontFamily: "'Space Mono', monospace", fontSize: 11.5, color: "#c4c7c1" }}>{v.key}</span><LifeChip life="retired" />
              </div>
            ))}
          </details>
        )}
      </div>

      {merge && <MergeModal value={merge} lookup={lk} onClose={() => setMerge(null)} addToDraft={addToDraft} />}
    </div>
  );
}
function MergeModal({ value, lookup, onClose, addToDraft }) {
  const F = window.RC_FIELDS;
  const [target, setTarget] = useState(null);
  const opts = lookup.values.filter((v) => v.key !== value.key && v.life !== "retired");
  return (
    <div onClick={onClose} style={fsOverlay}>
      <div onClick={(e) => e.stopPropagation()} style={{ ...fsModal, width: 480 }}>
        <div style={fsModalHead}><div><div style={{ fontSize: 16, fontWeight: 600, color: "#1d241f" }}>Merge “{value.label}”</div><div style={{ fontSize: 12.5, color: "#8a8e88", marginTop: 2 }}>Merged values leave an alias — no data is lost.</div></div><button onClick={onClose} style={fsIconBtn}><Icon name="x" size={16} color="#8a8e88" /></button></div>
        <div style={{ padding: 18 }}>
          <div style={fsLabelTx}>Merge into…</div>
          <div style={{ display: "flex", flexDirection: "column", gap: 7, marginTop: 8 }}>
            {opts.map((o) => (
              <button key={o.key} onClick={() => setTarget(o.key)} style={{ display: "flex", alignItems: "center", gap: 10, padding: "11px 13px", borderRadius: 9, border: target === o.key ? "1.5px solid #006747" : "1px solid #e6e4dc", background: target === o.key ? "#f5f9f7" : "#fff", cursor: "pointer", fontFamily: "inherit", textAlign: "left" }}>
                <Icon name={target === o.key ? "check-circle-2" : "circle"} size={16} color={target === o.key ? "#006747" : "#c4c7c1"} />
                <span style={{ fontSize: 13.5, fontWeight: 600, color: "#1d241f", flex: 1 }}>{o.label}</span>
                <span style={{ fontFamily: "'Space Mono', monospace", fontSize: 11, color: "#a8aca6" }}>{o.key}</span>
              </button>
            ))}
          </div>
          {target && (
            <div style={{ marginTop: 14, background: "#fbf7ea", border: "1px solid #efe6c8", borderRadius: 9, padding: "12px 14px", fontSize: 12.5, color: "#7a5a15", lineHeight: 1.5, display: "flex", gap: 10 }}>
              <Icon name="alert-triangle" size={15} color="#9a6a12" style={{ flex: "none", marginTop: 1 }} />
              <span><strong>214 historical listings</strong> show “{value.label}” → will display “{opts.find((o) => o.key === target).label}”. “{value.label}” remains as an <strong>alias</strong>.</span>
            </div>
          )}
        </div>
        <div style={{ padding: "14px 18px", borderTop: "1px solid #f1f0ea", display: "flex", justifyContent: "flex-end", gap: 10 }}>
          <button onClick={onClose} style={fsBtnOutline}>Cancel</button>
          <button onClick={() => { addToDraft({ kind: "enum", verb: "Merge enum value", target: `${lookup.key} · ${value.label} → ${opts.find((o) => o.key === target).label}`, detail: `214 historical listings remapped; “${value.label}” kept as alias.`, refs: { layouts: 1, rules: 0, statuses: 0 }, records: 214, blocking: false }); onClose(); }} disabled={!target} style={{ ...fsBtnPrimary, opacity: target ? 1 : 0.5 }}>Add merge to draft</button>
        </div>
      </div>
    </div>
  );
}

/* ============================ B5 · Layout designer ============================ */
function LayoutDesigner() {
  const F = window.RC_FIELDS;
  const [previewType, setPreviewType] = useState("Residential");
  const [previewStatus, setPreviewStatus] = useState("Active");
  const [activeSec, setActiveSec] = useState("details");
  return (
    <div style={{ padding: "20px 28px 90px" }}>
      <div style={{ display: "flex", alignItems: "center", gap: 12, marginBottom: 14, flexWrap: "wrap" }}>
        <div style={{ display: "flex", alignItems: "center", gap: 8 }}>
          <span style={{ fontSize: 12.5, color: "#8a8e88" }}>Layout</span>
          <select defaultValue="Default" style={{ ...fsInp, width: "auto", padding: "7px 30px 7px 11px", appearance: "none", cursor: "pointer" }}><option>Default</option><option>Residential</option><option>Land</option><option>Commercial</option></select>
        </div>
        <div style={{ flex: 1 }} />
        <span style={{ fontSize: 12, color: "#a8aca6" }}>Live preview renders the real form markup →</span>
      </div>
      <div style={{ display: "grid", gridTemplateColumns: "1fr 420px", gap: 20, alignItems: "start" }}>
        {/* builder */}
        <div style={{ display: "flex", flexDirection: "column", gap: 12 }}>
          {F.sections.map((s) => {
            const secFields = F.bySection(s.id);
            const open = activeSec === s.id;
            return (
              <div key={s.id} style={{ background: "#fff", borderRadius: 10, boxShadow: "inset 0 0 0 1px rgba(0,0,0,.07)", overflow: "hidden" }}>
                <div onClick={() => setActiveSec(open ? null : s.id)} style={{ display: "flex", alignItems: "center", gap: 11, padding: "12px 15px", cursor: "pointer" }}>
                  <Icon name="grip-vertical" size={16} color="#c4c7c1" />
                  <Icon name={s.icon} size={16} color="#006747" />
                  <span style={{ fontSize: 14, fontWeight: 600, color: "#1d241f", flex: 1 }}>{s.label}</span>
                  <span style={{ fontSize: 12, color: "#a8aca6" }}>{secFields.length} fields</span>
                  <button style={fsSortBtn}><Icon name="chevron-up" size={14} color="#8a8e88" /></button>
                  <button style={fsSortBtn}><Icon name="chevron-down" size={14} color="#8a8e88" /></button>
                  <Icon name={open ? "chevron-up" : "chevron-down"} size={16} color="#8a8e88" />
                </div>
                {open && (
                  <div style={{ borderTop: "1px solid #f1f0ea", padding: 12 }}>
                    {secFields.map((f) => (
                      <div key={f.key} className="rc-row" style={{ display: "flex", alignItems: "center", gap: 10, padding: "8px 10px", borderRadius: 7 }}>
                        <Icon name="grip-vertical" size={14} color="#d4d2c8" />
                        <span style={{ fontSize: 13, color: "#1d241f", flex: 1 }}>{f.label}</span>
                        {f.required && <span style={{ fontSize: 10.5, fontWeight: 600, color: "#c0612f", background: "#faf0e8", borderRadius: 999, padding: "2px 7px" }}>requiredIf</span>}
                        {f.dependsOn && <span style={{ fontSize: 10.5, fontWeight: 600, color: "#2f6bd0", background: "#eef3fb", borderRadius: 999, padding: "2px 7px" }}>visibleIf</span>}
                        <ProvChip prov={f.provenance} size="xs" withLabel={false} />
                        <span style={{ fontSize: 11, color: "#a8aca6", fontFamily: "'Space Mono', monospace" }}>col {f.span}</span>
                        <button style={fsSortBtn}><Icon name="chevron-up" size={13} color="#a8aca6" /></button>
                        <button style={fsSortBtn}><Icon name="chevron-down" size={13} color="#a8aca6" /></button>
                      </div>
                    ))}
                    <button style={{ ...fsBtnOutline, marginTop: 8, fontSize: 12.5, padding: "7px 12px" }}><Icon name="plus" size={13} color="#006747" /> Add field from registry</button>
                  </div>
                )}
              </div>
            );
          })}
          <button style={{ ...fsBtnOutline, alignSelf: "flex-start" }}><Icon name="plus" size={14} color="#006747" /> Add section</button>
        </div>
        {/* live preview */}
        <div style={{ position: "sticky", top: 12 }}>
          <div style={{ background: "#fff", borderRadius: 10, boxShadow: "inset 0 0 0 1px rgba(0,0,0,.07)", overflow: "hidden" }}>
            <div style={{ padding: "11px 14px", borderBottom: "1px solid #f1f0ea", display: "flex", alignItems: "center", gap: 8 }}>
              <Icon name="eye" size={14} color="#006747" /><span style={{ fontSize: 12.5, fontWeight: 600, color: "#1d241f", flex: 1 }}>Live form preview</span>
            </div>
            <div style={{ padding: "10px 14px", borderBottom: "1px solid #f1f0ea", display: "flex", gap: 8, background: "#faf9f5" }}>
              <MiniSelect label="Type" value={previewType} set={setPreviewType} opts={["Residential", "Land", "Commercial"]} />
              <MiniSelect label="Status" value={previewStatus} set={setPreviewStatus} opts={["ComingSoon", "Active", "Pending", "Sold"]} />
            </div>
            <div style={{ padding: 14, maxHeight: 440, overflowY: "auto", display: "flex", flexDirection: "column", gap: 14 }}>
              {F.sections.filter((s) => s.id !== "photos").map((s) => (
                <div key={s.id}>
                  <div style={{ fontSize: 11.5, fontWeight: 600, color: "#6b706a", marginBottom: 8, display: "flex", alignItems: "center", gap: 6 }}><Icon name={s.icon} size={13} color="#a8aca6" /> {s.label}</div>
                  <div style={{ display: "grid", gridTemplateColumns: "repeat(12, 1fr)", gap: 7 }}>
                    {F.bySection(s.id).filter((f) => !(f.dependsOn && previewStatus === "Sold" && f.key === "AssociationFeeFrequency")).map((f) => (
                      <div key={f.key} style={{ gridColumn: `span ${Math.min(12, f.span)}` }}>
                        <div style={{ fontSize: 9.5, color: "#a8aca6", marginBottom: 3, display: "flex", alignItems: "center", gap: 4 }}>{f.label}{f.required && <span style={{ color: "#c0612f" }}>*</span>}</div>
                        <div style={{ height: 26, borderRadius: 5, background: "#f4f3ef", boxShadow: "inset 0 0 0 1px #eceae2" }} />
                      </div>
                    ))}
                  </div>
                </div>
              ))}
            </div>
          </div>
        </div>
      </div>
    </div>
  );
}
function MiniSelect({ label, value, set, opts }) {
  return (
    <label style={{ flex: 1, display: "flex", flexDirection: "column", gap: 3 }}>
      <span style={{ fontSize: 9.5, fontWeight: 600, letterSpacing: ".3px", textTransform: "uppercase", color: "#a8aca6" }}>{label}</span>
      <select value={value} onChange={(e) => set(e.target.value)} style={{ ...fsInp, padding: "5px 8px", fontSize: 12 }}>{opts.map((o) => <option key={o}>{o}</option>)}</select>
    </label>
  );
}

/* ============================ B6 · Rules builder ============================ */
function RulesBuilder() {
  const F = window.RC_FIELDS;
  const [kind, setKind] = useState("required");
  const kinds = [["required", "Required-by-status"], ["conditional", "Conditional"], ["validation", "Validation"]];
  const list = F.rules.filter((r) => r.kind === kind);
  return (
    <div style={{ padding: "20px 28px 90px", display: "grid", gridTemplateColumns: "1fr 380px", gap: 20, alignItems: "start" }}>
      <div>
        <div style={{ display: "flex", gap: 6, marginBottom: 14 }}>
          {kinds.map(([k, l]) => <button key={k} onClick={() => setKind(k)} style={{ border: 0, background: kind === k ? "#006747" : "#fff", color: kind === k ? "#fff" : "#6b706a", boxShadow: kind === k ? "none" : "inset 0 0 0 1px rgba(0,0,0,.08)", fontFamily: "inherit", fontSize: 13, fontWeight: 600, padding: "8px 14px", borderRadius: 8, cursor: "pointer" }}>{l}</button>)}
        </div>

        {kind === "required" ? (
          <div style={{ background: "#fff", borderRadius: 10, boxShadow: "inset 0 0 0 1px rgba(0,0,0,.07)", overflow: "hidden" }}>
            <div style={{ padding: "13px 16px", borderBottom: "1px solid #f1f0ea", fontSize: 14, fontWeight: 600, color: "#1d241f" }}>Required fields × status</div>
            <div style={{ overflowX: "auto" }}>
              <table style={{ borderCollapse: "collapse", width: "100%", minWidth: 480 }}>
                <thead><tr>
                  <th style={{ ...matTh, textAlign: "left", paddingLeft: 16 }}>Field</th>
                  {Object.keys(F.reqMatrix).map((s) => <th key={s} style={matTh}>{F.statusByKey(s) ? F.statusByKey(s).name : s}</th>)}
                </tr></thead>
                <tbody>
                  {F.reqMatrixFields.map((fk, i) => (
                    <tr key={fk} style={{ borderTop: "1px solid #f4f3ee" }}>
                      <td style={{ padding: "9px 16px", fontSize: 12.5, color: "#1d241f", display: "flex", alignItems: "center", gap: 7 }}>{(F.byKey(fk) || { label: fk }).label}<ProvChip prov={(F.byKey(fk) || { provenance: "standard" }).provenance} size="xs" withLabel={false} /></td>
                      {Object.keys(F.reqMatrix).map((s) => { const on = F.reqMatrix[s][fk]; return (
                        <td key={s} style={{ textAlign: "center", padding: "9px 0" }}>
                          <span style={{ display: "inline-flex", width: 20, height: 20, borderRadius: 5, background: on ? "#006747" : "#fff", boxShadow: on ? "none" : "inset 0 0 0 1px #d4d2c8", alignItems: "center", justifyContent: "center", cursor: "pointer" }}>{on && <Icon name="check" size={13} color="#fff" />}</span>
                        </td>
                      ); })}
                    </tr>
                  ))}
                </tbody>
              </table>
            </div>
          </div>
        ) : (
          <div style={{ display: "flex", flexDirection: "column", gap: 10 }}>
            {list.map((r) => (
              <div key={r.id} style={{ background: "#fff", borderRadius: 10, boxShadow: "inset 0 0 0 1px rgba(0,0,0,.07)", padding: "14px 16px" }}>
                <div style={{ display: "flex", alignItems: "center", gap: 9, marginBottom: 10 }}>
                  <span style={{ fontSize: 14, fontWeight: 600, color: "#1d241f", flex: 1 }}>{r.label}</span>
                  <span style={{ fontSize: 10.5, fontWeight: 700, letterSpacing: ".3px", textTransform: "uppercase", color: r.severity === "error" ? "#b3261e" : "#9a6a12", background: r.severity === "error" ? "#fbe9e7" : "#fbf2dc", borderRadius: 999, padding: "3px 9px" }}>{r.severity}</span>
                </div>
                <div style={{ display: "flex", alignItems: "center", gap: 7, flexWrap: "wrap", fontSize: 12.5 }}>
                  <span style={condChip}>{r.when || r.value}</span>
                  <Icon name="arrow-right" size={13} color="#a8aca6" />
                  <span style={{ ...condChip, background: "#eef4f1", color: "#006747" }}>{r.effect || r.op} {(F.byKey(r.field) || { label: r.field }).label}</span>
                </div>
              </div>
            ))}
            <button style={{ ...fsBtnOutline, alignSelf: "flex-start" }}><Icon name="plus" size={14} color="#006747" /> New {kind} rule</button>
          </div>
        )}
      </div>

      {/* live sample form evaluating rules */}
      <div style={{ position: "sticky", top: 12, background: "#fff", borderRadius: 10, boxShadow: "inset 0 0 0 1px rgba(0,0,0,.07)", overflow: "hidden" }}>
        <div style={{ padding: "12px 15px", borderBottom: "1px solid #f1f0ea", display: "flex", alignItems: "center", gap: 8 }}>
          <Icon name="flask-conical" size={15} color="#006747" /><span style={{ fontSize: 13, fontWeight: 600, color: "#1d241f", flex: 1 }}>Sample listing — rules as built</span>
        </div>
        <div style={{ padding: 15, display: "flex", flexDirection: "column", gap: 11 }}>
          <div style={{ fontSize: 11.5, color: "#8a8e88", lineHeight: 1.5 }}>The preview evaluates with the production engine — it can't lie.</div>
          <SampleRow ok label="Public remarks present" note="required → Active" />
          <SampleRow ok label="List price present" note="required → Active" />
          <SampleRow ok={false} label="≥1 photo" note="blocks Active · 0 photos" />
          <SampleRow ok label="HOA frequency shown" note="HOA fee > 0 → show" cond />
          <SampleRow ok={false} label="Waterfront name" note="Waterfront = Yes → require" cond warn />
          <div style={{ borderTop: "1px solid #f1f0ea", paddingTop: 11, display: "flex", alignItems: "center", gap: 8, fontSize: 12.5, color: "#c0612f" }}>
            <Icon name="shield-alert" size={14} color="#c0612f" /> 1 blocker, 1 warning at status <strong>Active</strong>
          </div>
        </div>
      </div>
    </div>
  );
}
function SampleRow({ ok, label, note, cond, warn }) {
  const col = ok ? "#1f8a5b" : warn ? "#9a6a12" : "#b3261e";
  return (
    <div style={{ display: "flex", alignItems: "flex-start", gap: 9 }}>
      <Icon name={ok ? "check-circle-2" : warn ? "alert-triangle" : "x-circle"} size={15} color={col} style={{ marginTop: 1 }} />
      <div style={{ flex: 1 }}><div style={{ fontSize: 13, color: "#1d241f" }}>{label}</div><div style={{ fontSize: 11, color: "#a8aca6" }}>{note}{cond ? " · conditional" : ""}</div></div>
    </div>
  );
}

/* ============================ B7 · Status-map editor ============================ */
function StatusMapEditor() {
  const F = window.RC_FIELDS;
  const [expanded, setExpanded] = useState("Active");
  return (
    <div style={{ padding: "20px 28px 90px" }}>
      <div style={{ display: "flex", alignItems: "center", gap: 11, background: "#eef3fb", border: "1px solid #d9e3f5", borderRadius: 10, padding: "11px 15px", marginBottom: 16 }}>
        <Icon name="info" size={16} color="#2f6bd0" /><span style={{ fontSize: 13, color: "#2a4d86" }}>Your local statuses map many-to-one onto the <strong>11 fixed RESO DD 2.0 StandardStatus</strong> values. Keys are frozen; names, mappings, visibility & transitions are yours.</span>
      </div>
      <div style={{ background: "#fff", borderRadius: 10, boxShadow: "inset 0 0 0 1px rgba(0,0,0,.07)", overflow: "hidden" }}>
        <div style={{ display: "grid", gridTemplateColumns: "40px 1fr 1fr 200px 90px 60px", gap: 12, padding: "10px 16px", background: "#faf9f5", borderBottom: "1px solid #f1f0ea", fontSize: 10.5, fontWeight: 600, letterSpacing: ".4px", textTransform: "uppercase", color: "#a8aca6" }}>
          <span></span><span>Local status</span><span>Key (frozen)</span><span>StandardStatus</span><span>Public</span><span>Sort</span>
        </div>
        {F.statuses.map((s, i) => (
          <div key={s.key}>
            <div onClick={() => setExpanded(expanded === s.key ? null : s.key)} className="rc-row" style={{ display: "grid", gridTemplateColumns: "40px 1fr 1fr 200px 90px 60px", gap: 12, padding: "11px 16px", alignItems: "center", cursor: "pointer", borderTop: i ? "1px solid #f4f3ee" : "none" }}>
              <Icon name={expanded === s.key ? "chevron-down" : "chevron-right"} size={16} color="#a8aca6" />
              <div style={{ display: "flex", alignItems: "center", gap: 8 }}><input defaultValue={s.name} onClick={(e) => e.stopPropagation()} style={{ ...fsInp, padding: "5px 9px", fontSize: 13, maxWidth: 150 }} />{s.initial && <span style={{ fontSize: 9.5, fontWeight: 700, color: "#006747", background: "#eef4f1", borderRadius: 999, padding: "2px 7px" }}>INITIAL</span>}</div>
              <span style={{ fontFamily: "'Space Mono', monospace", fontSize: 12, color: "#8a8e88" }}>{s.key}</span>
              <div style={{ position: "relative" }} onClick={(e) => e.stopPropagation()}>
                <select defaultValue={s.std} style={{ ...fsInp, padding: "6px 28px 6px 10px", fontSize: 12.5, appearance: "none", cursor: "pointer" }}>{F.STANDARD_STATUS.map((v) => <option key={v}>{v}</option>)}</select>
                <span style={{ position: "absolute", right: 9, top: "50%", transform: "translateY(-50%)", pointerEvents: "none" }}><Icon name="chevron-down" size={13} color="#8a8e88" /></span>
              </div>
              <div onClick={(e) => e.stopPropagation()}><Toggle on={s.visible} onChange={() => {}} compact /></div>
              <div style={{ display: "flex", gap: 3 }}><button style={fsSortBtn}><Icon name="chevron-up" size={13} color="#a8aca6" /></button><button style={fsSortBtn}><Icon name="chevron-down" size={13} color="#a8aca6" /></button></div>
            </div>
            {expanded === s.key && (
              <div style={{ padding: "4px 16px 16px 56px", background: "#faf9f5", borderTop: "1px solid #f4f3ee" }}>
                <div style={{ display: "grid", gridTemplateColumns: "1fr 1fr", gap: 18, paddingTop: 12 }}>
                  <div>
                    <div style={{ fontSize: 11, fontWeight: 600, letterSpacing: ".3px", textTransform: "uppercase", color: "#a8aca6", marginBottom: 9 }}>Allowed transitions → (× role)</div>
                    <table style={{ borderCollapse: "collapse", width: "100%" }}>
                      <thead><tr><th style={{ ...matTh, textAlign: "left" }}>Next</th><th style={matTh}>Agent</th><th style={matTh}>Staff</th></tr></thead>
                      <tbody>
                        {(s.next.length ? s.next : ["—"]).map((nk) => { const ns = F.statusByKey(nk); return (
                          <tr key={nk} style={{ borderTop: "1px solid #eeede7" }}>
                            <td style={{ padding: "7px 0", fontSize: 12.5, color: "#1d241f" }}>{ns ? ns.name : "No transitions"}</td>
                            <td style={{ textAlign: "center" }}>{ns && <CheckCell on={ns.roles.agent} />}</td>
                            <td style={{ textAlign: "center" }}>{ns && <CheckCell on={ns.roles.staff} />}</td>
                          </tr>
                        ); })}
                      </tbody>
                    </table>
                  </div>
                  <div>
                    <div style={{ fontSize: 11, fontWeight: 600, letterSpacing: ".3px", textTransform: "uppercase", color: "#a8aca6", marginBottom: 9 }}>Automation & companion fields</div>
                    {s.auto ? <div style={{ display: "flex", alignItems: "flex-start", gap: 8, fontSize: 12.5, color: "#2a4d86", background: "#eef3fb", borderRadius: 8, padding: "9px 11px", marginBottom: 8 }}><Icon name="calendar-clock" size={14} color="#2f6bd0" style={{ marginTop: 1 }} />{s.auto}</div> : <div style={{ fontSize: 12.5, color: "#a8aca6", marginBottom: 8 }}>No auto-transition.</div>}
                    {s.companion && <div style={{ fontSize: 12.5, color: "#4a504a" }}>Companion fields required: {s.companion.map((c) => <span key={c} style={{ ...condChip, marginRight: 6 }}>{c}</span>)}</div>}
                    {s.initial && <div style={{ fontSize: 12.5, color: "#006747", display: "flex", alignItems: "center", gap: 6, marginTop: 8 }}><Icon name="flag" size={13} color="#006747" /> Available as an initial status for new listings</div>}
                  </div>
                </div>
              </div>
            )}
          </div>
        ))}
      </div>
    </div>
  );
}
function CheckCell({ on }) { return <span style={{ display: "inline-flex", width: 18, height: 18, borderRadius: 5, background: on ? "#006747" : "#fff", boxShadow: on ? "none" : "inset 0 0 0 1px #d4d2c8", alignItems: "center", justifyContent: "center" }}>{on && <Icon name="check" size={12} color="#fff" />}</span>; }

/* ============================ B8 · Review / impact / publish + history ============================ */
function ReviewPublish({ draft, setDraft }) {
  const F = window.RC_FIELDS;
  const [view, setView] = useState("review");
  const [ack, setAck] = useState(false);
  const blocking = draft.filter((c) => c.blocking);
  const warnings = draft.filter((c) => !c.blocking && (c.records > 500 || c.refs.rules > 0));
  const canPublish = blocking.length === 0 && ack;
  return (
    <div style={{ padding: "20px 28px 90px", maxWidth: 940, margin: "0 auto" }}>
      <div style={{ display: "flex", gap: 6, marginBottom: 16 }}>
        {[["review", "Review & impact"], ["history", "Version history"]].map(([k, l]) => <button key={k} onClick={() => setView(k)} style={{ border: 0, background: view === k ? "#006747" : "#fff", color: view === k ? "#fff" : "#6b706a", boxShadow: view === k ? "none" : "inset 0 0 0 1px rgba(0,0,0,.08)", fontFamily: "inherit", fontSize: 13, fontWeight: 600, padding: "8px 15px", borderRadius: 8, cursor: "pointer" }}>{l}</button>)}
      </div>

      {view === "review" ? (
        <>
          <div style={{ display: "flex", alignItems: "center", gap: 10, marginBottom: 14 }}>
            <div><h2 style={{ margin: 0, fontSize: 18, fontWeight: 600, color: "#1d241f" }}>{F.draft.name}</h2><div style={{ fontSize: 12.5, color: "#8a8e88", marginTop: 2 }}>{draft.length} changes · {F.draft.author}</div></div>
          </div>

          {/* change diff cards */}
          <div style={{ display: "flex", flexDirection: "column", gap: 10, marginBottom: 22 }}>
            {draft.map((c) => (
              <div key={c.id} style={{ background: "#fff", borderRadius: 10, boxShadow: "inset 0 0 0 1px " + (c.blocking ? "#f2d6d2" : "rgba(0,0,0,.08)"), padding: "13px 16px", display: "flex", alignItems: "flex-start", gap: 12 }}>
                <span style={{ width: 30, height: 30, borderRadius: 7, background: c.blocking ? "#fbe9e7" : "#eef4f1", display: "flex", alignItems: "center", justifyContent: "center", flex: "none" }}><Icon name={c.kind === "field" ? "square-pen" : c.kind === "enum" ? "list" : c.kind === "rule" ? "git-branch" : "activity"} size={15} color={c.blocking ? "#b3261e" : "#006747"} /></span>
                <div style={{ flex: 1, minWidth: 0 }}>
                  <div style={{ fontSize: 13.5, fontWeight: 600, color: "#1d241f" }}>{c.verb}: <span style={{ fontFamily: "'Space Mono', monospace", fontWeight: 400 }}>{c.target}</span></div>
                  <div style={{ fontSize: 12.5, color: "#8a8e88", marginTop: 3, lineHeight: 1.45 }}>{c.detail}</div>
                  <div style={{ display: "flex", gap: 12, marginTop: 7, fontSize: 11, color: "#a8aca6" }}>
                    <span>{c.refs.layouts} layouts</span><span>{c.refs.rules} rules</span><span>{c.refs.statuses} statuses</span><span style={{ color: c.records > 500 ? "#9a6a12" : "#a8aca6" }}>{c.records.toLocaleString()} records</span>
                  </div>
                </div>
                <button onClick={() => setDraft(draft.filter((x) => x.id !== c.id))} style={fsIconBtn}><Icon name="x" size={14} color="#a8aca6" /></button>
              </div>
            ))}
            {draft.length === 0 && <div style={{ textAlign: "center", padding: 40, color: "#a8aca6", fontSize: 14 }}>No pending changes. The draft is empty.</div>}
          </div>

          {/* impact report */}
          {draft.length > 0 && (
            <div style={{ background: "#fff", borderRadius: 12, boxShadow: "inset 0 0 0 1px rgba(0,0,0,.08)", overflow: "hidden", marginBottom: 18 }}>
              <div style={{ padding: "14px 18px", borderBottom: "1px solid #f1f0ea", display: "flex", alignItems: "center", gap: 9 }}><Icon name="scan-search" size={17} color="#006747" /><h3 style={{ margin: 0, fontSize: 15, fontWeight: 600, color: "#1d241f" }}>Impact report</h3></div>
              <div style={{ padding: 18, display: "flex", flexDirection: "column", gap: 14 }}>
                {blocking.length > 0 && (
                  <ImpactBlock tone="block" title={`${blocking.length} blocking finding${blocking.length !== 1 ? "s" : ""} — publish disabled`}>
                    {blocking.map((c) => <li key={c.id} style={impactLi}><strong>{c.target}</strong> — {c.detail} <span style={{ color: "#b3261e" }}>({c.records.toLocaleString()} records affected)</span></li>)}
                  </ImpactBlock>
                )}
                {warnings.length > 0 && (
                  <ImpactBlock tone="warn" title={`${warnings.length} warning${warnings.length !== 1 ? "s" : ""}`}>
                    {warnings.map((c) => <li key={c.id} style={impactLi}><strong>{c.target}</strong> — affects {c.records.toLocaleString()} historical records{c.refs.rules ? `, referenced by ${c.refs.rules} rule(s)` : ""}.</li>)}
                  </ImpactBlock>
                )}
                <ImpactBlock tone="ok" title="References touched">
                  <li style={impactLi}>{draft.reduce((n, c) => n + c.refs.layouts, 0)} layout references · {draft.reduce((n, c) => n + c.refs.rules, 0)} rules · {draft.reduce((n, c) => n + c.refs.statuses, 0)} statuses</li>
                  <li style={impactLi}>{draft.reduce((n, c) => n + c.records, 0).toLocaleString()} historical records total across all changes</li>
                </ImpactBlock>
              </div>
            </div>
          )}

          {/* publish */}
          {draft.length > 0 && (
            <div style={{ background: "#fff", borderRadius: 12, boxShadow: "inset 0 0 0 1px rgba(0,0,0,.08)", padding: 18 }}>
              {blocking.length > 0 && <div style={{ display: "flex", alignItems: "center", gap: 9, fontSize: 13, color: "#b3261e", background: "#fbe9e7", borderRadius: 8, padding: "10px 13px", marginBottom: 14 }}><Icon name="ban" size={15} color="#b3261e" /> Resolve the blocking finding (add a merge or widen the type) before publishing.</div>}
              <label style={{ display: "flex", alignItems: "flex-start", gap: 10, cursor: blocking.length ? "not-allowed" : "pointer", opacity: blocking.length ? 0.5 : 1 }}>
                <input type="checkbox" disabled={blocking.length > 0} checked={ack} onChange={(e) => setAck(e.target.checked)} style={{ marginTop: 2, accentColor: "#006747" }} />
                <span style={{ fontSize: 13, color: "#4a504a", lineHeight: 1.5 }}>I've reviewed the impact report and understand these changes affect input forms and search for every {F.tenant.short} agent.</span>
              </label>
              <div style={{ display: "flex", alignItems: "center", gap: 12, marginTop: 16 }}>
                <label style={{ display: "flex", alignItems: "center", gap: 8, fontSize: 12.5, color: "#8a8e88" }}><Icon name="calendar" size={14} color="#a8aca6" /> Effective <select style={{ ...fsInp, padding: "6px 10px", fontSize: 12.5, width: "auto" }}><option>Immediately</option><option>Scheduled…</option></select></label>
                <div style={{ flex: 1 }} />
                <button disabled={!canPublish} style={{ ...fsBtnPrimary, padding: "11px 20px", opacity: canPublish ? 1 : 0.5, cursor: canPublish ? "pointer" : "not-allowed" }}><Icon name={canPublish ? "check-check" : "lock"} size={15} color="#fff" /> Publish as v19</button>
              </div>
            </div>
          )}
        </>
      ) : (
        <div style={{ display: "flex", flexDirection: "column", gap: 10 }}>
          {F.versions.map((v) => (
            <details key={v.v} style={{ background: "#fff", borderRadius: 10, boxShadow: "inset 0 0 0 1px rgba(0,0,0,.08)", overflow: "hidden" }}>
              <summary style={{ padding: "14px 16px", cursor: "pointer", display: "flex", alignItems: "center", gap: 12 }}>
                <span style={{ fontFamily: "'Space Mono', monospace", fontSize: 14, fontWeight: 700, color: "#006747" }}>{v.v}</span>
                <div style={{ flex: 1 }}><div style={{ fontSize: 13.5, color: "#1d241f" }}>{v.note}</div><div style={{ fontSize: 11.5, color: "#a8aca6", marginTop: 2 }}>{v.date} · {v.author} · {v.changes} changes</div></div>
                <button onClick={(e) => e.preventDefault()} style={{ ...fsBtnOutline, fontSize: 12, padding: "6px 12px" }}><Icon name="rotate-ccw" size={13} color="#006747" /> Roll back</button>
              </summary>
              <div style={{ padding: "0 16px 14px 44px", fontSize: 12.5, color: "#8a8e88", lineHeight: 1.6 }}>
                Rolling back creates a new draft that passes the <strong>same impact review</strong> before publishing — restoring an old schema can affect records added since. Audited like any publish.
              </div>
            </details>
          ))}
        </div>
      )}
    </div>
  );
}
function ImpactBlock({ tone, title, children }) {
  const map = { block: { fg: "#b3261e", bg: "#fdf4f3", icon: "octagon-x" }, warn: { fg: "#9a6a12", bg: "#fbf7ea", icon: "alert-triangle" }, ok: { fg: "#4a504a", bg: "#faf9f5", icon: "link" } };
  const m = map[tone];
  return (
    <div style={{ background: m.bg, borderRadius: 9, padding: "12px 15px" }}>
      <div style={{ display: "flex", alignItems: "center", gap: 8, fontSize: 13, fontWeight: 600, color: m.fg, marginBottom: 8 }}><Icon name={m.icon} size={15} color={m.fg} /> {title}</div>
      <ul style={{ margin: 0, paddingLeft: 18, display: "flex", flexDirection: "column", gap: 5 }}>{children}</ul>
    </div>
  );
}

/* ---- shared toggle + styles ---- */
function Toggle({ label, sub, on, onChange, compact }) {
  const sw = (
    <button onClick={() => onChange(!on)} style={{ width: 38, height: 22, borderRadius: 999, border: 0, background: on ? "#006747" : "#d4d2c8", position: "relative", cursor: "pointer", flex: "none", transition: "background .15s" }}>
      <span style={{ position: "absolute", top: 2, left: on ? 18 : 2, width: 18, height: 18, borderRadius: "50%", background: "#fff", transition: "left .15s" }} />
    </button>
  );
  if (compact) return sw;
  return (
    <div style={{ display: "flex", alignItems: "center", gap: 12 }}>
      <div style={{ flex: 1 }}><div style={{ fontSize: 13, fontWeight: 500, color: "#1d241f" }}>{label}</div>{sub && <div style={{ fontSize: 11.5, color: "#a8aca6", marginTop: 1 }}>{sub}</div>}</div>
      {sw}
    </div>
  );
}

const fsBtnPrimary = { display: "inline-flex", alignItems: "center", gap: 7, background: "#006747", color: "#fff", border: 0, borderRadius: 8, padding: "9px 15px", fontFamily: "inherit", fontSize: 13, fontWeight: 600, cursor: "pointer" };
const fsBtnOutline = { display: "inline-flex", alignItems: "center", gap: 7, background: "#fff", color: "#006747", border: "1px solid #d9d7cd", borderRadius: 8, padding: "9px 14px", fontFamily: "inherit", fontSize: 13, fontWeight: 600, cursor: "pointer" };
const fsBtnTiny = { display: "inline-flex", alignItems: "center", gap: 5, fontFamily: "inherit", fontSize: 12, fontWeight: 600, padding: "6px 12px", borderRadius: 7, cursor: "pointer" };
const fsIconBtn = { border: 0, background: "transparent", cursor: "pointer", display: "flex", padding: 4 };
const fsSortBtn = { border: 0, background: "transparent", cursor: "pointer", display: "flex", padding: 2, borderRadius: 4 };
const fsInp = { width: "100%", boxSizing: "border-box", border: "1px solid #e2e0d8", borderRadius: 7, padding: "9px 11px", fontFamily: "inherit", fontSize: 13.5, color: "#1d241f", background: "#fff", outline: "none" };
const fsLabel = { display: "flex", flexDirection: "column", gap: 6 };
const fsLabelTx = { fontSize: 11.5, fontWeight: 600, color: "#6b706a", letterSpacing: ".2px" };
const fsOverlay = { position: "fixed", inset: 0, background: "rgba(20,28,22,.42)", display: "flex", alignItems: "center", justifyContent: "center", zIndex: 40, padding: 20 };
const fsModal = { background: "#fff", borderRadius: 12, boxShadow: "0 24px 60px rgba(0,0,0,.28)", maxHeight: "88vh", overflowY: "auto" };
const fsModalHead = { padding: "16px 18px", borderBottom: "1px solid #f1f0ea", display: "flex", alignItems: "flex-start", justifyContent: "space-between", gap: 10 };
const matTh = { fontSize: 10, fontWeight: 600, letterSpacing: ".3px", textTransform: "uppercase", color: "#a8aca6", padding: "8px 6px", textAlign: "center" };
const condChip = { display: "inline-flex", alignItems: "center", fontSize: 12, fontWeight: 500, color: "#4a504a", background: "#f4f3ef", borderRadius: 6, padding: "4px 9px", fontFamily: "'Space Mono', monospace" };
const impactLi = { fontSize: 12.5, color: "#4a504a", lineHeight: 1.5 };

window.FieldStudio = FieldStudio;
