// concept-edit.jsx — The hero screen. The thinking surface.
// Left column: 5 stacked sections (Consist, Function, Perspectives, Patterns, Essence).
// Right column: live mini solar preview + a small "structure" map showing groupings.

const { useState: _ce_us, useMemo: _ce_um, useEffect: _ce_ue, useRef: _ce_ur } = React;

function ConceptEdit({ concept, allConcepts = [], onChange, onSwitchMode, onBack, onOpenSolar, onOpenConcept, onOpenGraph, onDelete, density, panelMode = false }) {
  const c = concept;
  const update = (patch) => onChange({ ...c, ...patch });
  const [confirmDelete, setConfirmDelete] = _ce_us(false);
  const confirmTimer = _ce_ur(null);

  function handleDelete() {
    if (!confirmDelete) {
      setConfirmDelete(true);
      clearTimeout(confirmTimer.current);
      confirmTimer.current = setTimeout(() => setConfirmDelete(false), 2500);
    } else {
      clearTimeout(confirmTimer.current);
      onDelete && onDelete();
    }
  }

  function setPerspective(id, patch) {
    update({ perspectives: c.perspectives.map(p => p.id === id ? { ...p, ...patch } : p) });
  }
  function addPerspective() {
    const id = "p" + Date.now();
    update({ perspectives: [...c.perspectives, { id, title: "", body: "", patternId: null }] });
  }
  function removePerspective(id) {
    update({ perspectives: c.perspectives.filter(p => p.id !== id) });
  }

  function setPattern(id, patch) {
    update({ patterns: c.patterns.map(p => p.id === id ? { ...p, ...patch } : p) });
  }
  function addPattern() {
    const id = "pat" + Date.now();
    update({ patterns: [...c.patterns, { id, title: "", body: "", essenceId: null }] });
  }
  function removePattern(id) {
    update({
      patterns: c.patterns.filter(p => p.id !== id),
      perspectives: c.perspectives.map(p => p.patternId === id ? { ...p, patternId: null } : p)
    });
  }

  function getFunctions() {
    if (c.functions && c.functions.length > 0) return c.functions;
    return [{ id: "fn0", body: c.function || "" }];
  }
  function syncFunctions(fns) {
    update({ functions: fns, function: fns[0]?.body || "" });
  }
  function addFunction() {
    syncFunctions([...getFunctions(), { id: "fn" + Date.now(), body: "" }]);
  }
  function setFunction(id, body) {
    syncFunctions(getFunctions().map(f => f.id === id ? { ...f, body } : f));
  }
  function removeFunction(id) {
    const next = getFunctions().filter(f => f.id !== id);
    syncFunctions(next.length > 0 ? next : [{ id: "fn0", body: "" }]);
  }

  function setEssence(id, patch) {
    update({ essences: c.essences.map(e => e.id === id ? { ...e, ...patch } : e) });
  }
  function addEssence() {
    const id = "es" + Date.now();
    update({ essences: [...c.essences, { id, body: "" }] });
  }
  function removeEssence(id) {
    update({
      essences: c.essences.filter(e => e.id !== id),
      patterns: c.patterns.map(p => p.essenceId === id ? { ...p, essenceId: null } : p)
    });
  }

  return (
    <div className="page" data-screen-label="Concept · Edit" style={{ maxWidth: panelMode ? "none" : 1340, padding: panelMode ? "20px 22px" : undefined }}>
      {/* Top toolbar */}
      {panelMode ? (
        <div style={{ display: "flex", alignItems: "center", justifyContent: "space-between", marginBottom: 18 }}>
          <span style={{ fontSize: 10.5, color: "var(--fg-3)", fontFamily: "var(--font-mono)", textTransform: "uppercase", letterSpacing: ".08em" }}>Edit</span>
          <div style={{ display: "flex", gap: 6 }}>
            <button className="btn ghost tiny" onClick={onBack}>close ✕</button>
          </div>
        </div>
      ) : (
        <div className="view-toolbar" style={{ display: "flex", alignItems: "center", gap: 12, marginBottom: 28 }}>
          <button className="btn ghost tiny" onClick={onBack}>{window.Icons.ArrowL(13)} Library</button>
          <div style={{ flex: 1 }} />
          <div className="view-mode-sw" style={{ display: "flex", alignItems: "center", gap: 8 }}>
            {onDelete && (
              <button
                className="btn ghost tiny"
                onClick={handleDelete}
                style={{ color: confirmDelete ? "var(--c-essence)" : "var(--fg-3)" }}
              >
                {confirmDelete ? "confirm delete?" : window.Icons.Trash(13)}
              </button>
            )}
            <div style={{ display: "flex", gap: 4, background: "var(--bg-sunk)", padding: 3, borderRadius: 9, border: "1px solid var(--border-soft)" }}>
              <button className="btn tiny" style={modeBtnStyle(true)}>{window.Icons.Edit(13)} Edit</button>
              <button className="btn tiny" style={modeBtnStyle(false)} onClick={() => onSwitchMode("read")}>{window.Icons.Eye(13)} Read</button>
              <button className="btn tiny" style={modeBtnStyle(false)} onClick={onOpenSolar}>{window.Icons.Planet(13)} System</button>
              <button className="btn tiny" style={modeBtnStyle(false)} onClick={onOpenGraph}>{window.Icons.Graph(13)} Graph</button>
            </div>
          </div>
        </div>
      )}

      {/* Hero — concept title */}
      <div className={panelMode ? "" : "ce-grid"} style={{ display: "grid", gridTemplateColumns: panelMode ? "1fr" : "1.6fr 1fr", gap: panelMode ? 0 : 56, alignItems: "start" }}>
        <div>
          <input
            className={panelMode ? "concept-title" : "concept-title ce-title"}
            value={c.title}
            onChange={e => update({ title: e.target.value })}
            placeholder="Untitled concept"
            style={{ fontSize: panelMode ? 34 : 78, lineHeight: 1, marginBottom: 14, width: "100%", padding: 0, background: "transparent" }}
          />
          <div style={{ display: "flex", alignItems: "center", gap: 10, marginBottom: 24 }}>
            <window.Dots concept={c} size={7} />
            <span className="tag-flat" style={{ color: "var(--fg-3)" }}>updated {c.updated}</span>
          </div>
          <div className="field" style={{ marginBottom: 36, padding: "8px 12px" }}>
            <div style={{ fontSize: 10, fontFamily: "var(--font-mono)", letterSpacing: ".1em", textTransform: "uppercase", color: "var(--fg-3)", marginBottom: 4 }}>Category</div>
            <input
              value={c.category}
              onChange={e => update({ category: e.target.value })}
              placeholder="object, feeling, system…"
              style={{ fontSize: 13, color: "var(--fg)", width: "100%" }}
            />
          </div>

          {/* Section 1 — Consist */}
          <Section
            tag="constant"
            label="01 · Consist"
            heading="What is it made of?"
            help="Objective. The components or elements it is made of. Same for everyone."
          >
            <FieldArea
              value={c.consist}
              onChange={(v) => update({ consist: v })}
              placeholder="From what is this made or composed?"
              minHeight={90}
            />
          </Section>

          {/* Section 2 — Function */}
          <Section
            tag="function"
            label={`02 · Function${getFunctions().filter(f => f.body).length > 1 ? ` · ${getFunctions().filter(f => f.body).length}` : ""}`}
            heading="How does it work?"
            help="Objective. The mechanism of its action. Same for everyone."
            action={<button className="btn tiny" onClick={addFunction}>{window.Icons.Plus(12)} add function</button>}
          >
            <div style={{ display: "grid", gap: 10 }}>
              {getFunctions().map((fn, i) => {
                const fns = getFunctions();
                return (
                  <div key={fn.id} style={{ position: "relative" }}>
                    <FieldArea
                      value={fn.body}
                      onChange={(v) => setFunction(fn.id, v)}
                      placeholder="How does this work, by its nature?"
                      minHeight={90}
                    />
                    {fns.length > 1 && (
                      <button
                        className="btn ghost icon tiny"
                        onClick={() => removeFunction(fn.id)}
                        title="Remove"
                        style={{ position: "absolute", top: 8, right: 8 }}
                      >
                        {window.Icons.Trash(12)}
                      </button>
                    )}
                  </div>
                );
              })}
            </div>
          </Section>

          {/* Section 3 — Perspective */}
          <Section
            tag="perspective"
            label={`03 · Perspective${c.perspectives.length ? ` · ${c.perspectives.length}` : ""}`}
            heading="How have you used or experienced it?"
            help="Subjective. Your own experience with it — no one else's."
            action={<button className="btn tiny" onClick={addPerspective}>{window.Icons.Plus(12)} add perspective</button>}
          >
            <div style={{ display: "grid", gap: 12 }}>
              {c.perspectives.map((p) => (
                <PerspectiveCard
                  key={p.id}
                  p={p}
                  patterns={c.patterns}
                  onChange={(patch) => setPerspective(p.id, patch)}
                  onRemove={() => removePerspective(p.id)}
                  onCreatePattern={() => {
                    const id = "pat" + Date.now();
                    update({
                      patterns: [...c.patterns, { id, title: "", body: "", essenceId: null }],
                      perspectives: c.perspectives.map(pp => pp.id === p.id ? { ...pp, patternId: id } : pp)
                    });
                  }}
                />
              ))}
              {c.perspectives.length === 0 && (
                <EmptyInvite onClick={addPerspective} placeholder="How did you use it, or what did it mean to you?" />
              )}
            </div>
          </Section>

          {/* Section 4 — Pattern */}
          <Section
            tag="pattern"
            label={`04 · Pattern${c.patterns.length ? ` · ${c.patterns.length}` : ""}`}
            heading="What do your perspectives have in common?"
            help="What two or more perspectives quietly agree on."
            action={<button className="btn tiny" onClick={addPattern}>{window.Icons.Plus(12)} add pattern</button>}
          >
            <div style={{ display: "grid", gap: 12 }}>
              {c.patterns.map((p) => (
                <PatternCard
                  key={p.id}
                  pattern={p}
                  perspectives={c.perspectives.filter(x => x.patternId === p.id)}
                  essences={c.essences}
                  onChange={(patch) => setPattern(p.id, patch)}
                  onRemove={() => removePattern(p.id)}
                  onCreateEssence={() => {
                    const id = "es" + Date.now();
                    update({
                      essences: [...c.essences, { id, body: "" }],
                      patterns: c.patterns.map(pp => pp.id === p.id ? { ...pp, essenceId: id } : pp)
                    });
                  }}
                />
              ))}
              {c.patterns.length === 0 && (
                <EmptyInvite onClick={addPattern} placeholder="What two or more perspectives quietly agree on?" />
              )}
            </div>
          </Section>

          {/* Section 5 — Essence */}
          <Section
            tag="essence"
            label={`05 · Essence${c.essences.length ? ` · ${c.essences.length}` : ""}`}
            heading="What remains after all of it?"
            help="Your personal understanding. Not a fact — a residue."
            action={<button className="btn tiny" onClick={addEssence}>{window.Icons.Plus(12)} add essence</button>}
          >
            <div style={{ display: "grid", gap: 12 }}>
              {c.essences.map((e) => (
                <EssenceCard
                  key={e.id}
                  essence={e}
                  patterns={c.patterns.filter(p => p.essenceId === e.id)}
                  onChange={(patch) => setEssence(e.id, patch)}
                  onRemove={() => removeEssence(e.id)}
                />
              ))}
              {c.essences.length === 0 && (
                <EmptyInvite onClick={addEssence} placeholder="What remains after everything else falls away?" big />
              )}
            </div>
          </Section>

          {/* Section 6 — Links */}
          <LinksSection
            concept={c}
            allConcepts={allConcepts}
            onUpdate={update}
          />

          <div style={{ height: 100 }} />
        </div>

        {/* Sticky right rail — hidden in panelMode */}
        {!panelMode && (
          <div style={{ position: "sticky", top: 92, alignSelf: "start", display: "flex", flexDirection: "column", gap: 18 }}>
            <window.MiniSolar concept={c} />
            {allConcepts.length > 1 && (
              <window.MiniGraph concept={c} allConcepts={allConcepts} onOpen={onOpenConcept} />
            )}
            <StructureMap concept={c} />
            <Helpers concept={c} />
          </div>
        )}
      </div>
    </div>
  );
}

function modeBtnStyle(active) {
  return {
    border: 0,
    background: active ? "var(--bg-elev)" : "transparent",
    boxShadow: active ? "0 1px 2px rgba(0,0,0,.05)" : "none",
    color: active ? "var(--fg)" : "var(--fg-3)",
  };
}

function Section({ tag, label, heading, help, children, action }) {
  return (
    <section style={{ marginBottom: "var(--gap-section)" }}>
      <div className="section-head">
        <div style={{ display: "flex", alignItems: "center", gap: 10, flexWrap: "wrap" }}>
          <window.Tag kind={tag}>{label}</window.Tag>
          <h2 className="concept-title" style={{ fontSize: 24, margin: 0, color: "var(--fg)", fontStyle: "italic" }}>{heading}</h2>
        </div>
        {action}
      </div>
      <p style={{ color: "var(--fg-3)", margin: "0 0 14px", fontSize: 12.5, maxWidth: 580 }}>{help}</p>
      {children}
    </section>
  );
}

function FieldArea({ value, onChange, placeholder, minHeight = 80 }) {
  return (
    <div className="field">
      <textarea
        value={value || ""}
        onChange={(e) => onChange(e.target.value)}
        placeholder={placeholder}
        rows={3}
        style={{ minHeight }}
        onInput={(e) => { e.target.style.height = "auto"; e.target.style.height = e.target.scrollHeight + "px"; }}
      />
    </div>
  );
}

function EmptyInvite({ onClick, placeholder, big }) {
  return (
    <button
      onClick={onClick}
      className="field"
      style={{
        cursor: "pointer", textAlign: "left",
        padding: big ? "26px 18px" : "18px 16px",
        background: "transparent",
        borderStyle: "dashed",
        color: "var(--fg-3)",
        fontStyle: "italic",
        fontFamily: big ? "var(--font-serif)" : "var(--font-ui)",
        fontSize: big ? 19 : 14
      }}
    >
      {placeholder}
    </button>
  );
}

function PerspectiveCard({ p, patterns, onChange, onRemove, onCreatePattern }) {
  const solo = !p.patternId;
  return (
    <div className={`surface ${solo && (p.title || p.body) ? "solo" : ""}`} style={{ padding: 14, display: "flex", flexDirection: "column", gap: 6, borderLeft: "2px solid var(--c-perspective)" }}>
      <div style={{ display: "flex", alignItems: "center", gap: 8 }}>
        <span style={{ width: 8, height: 8, borderRadius: 999, background: "var(--c-perspective)", flexShrink: 0 }} />
        <input
          value={p.title}
          onChange={(e) => onChange({ title: e.target.value })}
          placeholder="Give this perspective a short name"
          style={{ fontWeight: 500, fontSize: 14.5, flex: 1, color: "var(--fg)" }}
        />
        <button className="btn ghost icon tiny" onClick={onRemove} title="Remove">{window.Icons.Trash(12)}</button>
      </div>
      <textarea
        value={p.body}
        onChange={(e) => onChange({ body: e.target.value })}
        placeholder="How did you use it, or what did it mean to you?"
        rows={3}
        style={{ fontSize: 14, lineHeight: 1.55, color: "var(--fg-2)" }}
        onInput={(e) => { e.target.style.height = "auto"; e.target.style.height = e.target.scrollHeight + "px"; }}
      />
      <div style={{ display: "flex", alignItems: "center", gap: 8, marginTop: 4, color: "var(--fg-3)", fontSize: 11.5 }}>
        <span style={{ display: "inline-flex", alignItems: "center", gap: 4, fontFamily: "var(--font-mono)", textTransform: "uppercase", letterSpacing: ".08em" }}>
          {window.Icons.Link(11)} groups with
        </span>
        <select
          value={p.patternId || ""}
          onChange={(e) => {
            const v = e.target.value;
            if (v === "__new__") onCreatePattern();
            else onChange({ patternId: v || null });
          }}
          style={{
            font: "inherit",
            background: "var(--bg-sunk)",
            color: "var(--fg)",
            border: "1px solid var(--border-soft)",
            borderRadius: 6,
            padding: "3px 6px",
            cursor: "pointer",
            outline: "none"
          }}
        >
          <option value="">— solo, on its own —</option>
          {patterns.map(pat => (
            <option key={pat.id} value={pat.id}>{pat.title || "(unnamed pattern)"}</option>
          ))}
          <option value="__new__">+ new pattern</option>
        </select>
        {solo && (p.title || p.body) && (
          <span className="solo-mark" style={{ marginLeft: "auto" }}>· solo orbit</span>
        )}
      </div>
    </div>
  );
}

function PatternCard({ pattern, perspectives, essences, onChange, onRemove, onCreateEssence }) {
  const solo = !pattern.essenceId;
  return (
    <div className={`surface ${solo && (pattern.title || pattern.body) ? "solo" : ""}`} style={{ padding: 14, display: "flex", flexDirection: "column", gap: 8, borderLeft: "2px solid var(--c-pattern)" }}>
      <div style={{ display: "flex", alignItems: "center", gap: 8 }}>
        <span style={{ width: 8, height: 8, borderRadius: 999, background: "var(--c-pattern)", flexShrink: 0 }} />
        <input
          value={pattern.title}
          onChange={(e) => onChange({ title: e.target.value })}
          placeholder="Name the pattern in a few words"
          style={{ fontWeight: 500, fontSize: 14.5, flex: 1, color: "var(--fg)" }}
        />
        <button className="btn ghost icon tiny" onClick={onRemove} title="Remove">{window.Icons.Trash(12)}</button>
      </div>
      <textarea
        value={pattern.body}
        onChange={(e) => onChange({ body: e.target.value })}
        placeholder="What is the silent thread between them?"
        rows={2}
        style={{ fontSize: 14, lineHeight: 1.55, color: "var(--fg-2)" }}
        onInput={(e) => { e.target.style.height = "auto"; e.target.style.height = e.target.scrollHeight + "px"; }}
      />
      <div style={{ display: "flex", flexWrap: "wrap", alignItems: "center", gap: 6, fontSize: 11.5, color: "var(--fg-3)" }}>
        <span className="tag-flat">from</span>
        {perspectives.length === 0
          ? <span style={{ fontStyle: "italic" }}>no perspectives grouped yet</span>
          : perspectives.map(p => (
              <span key={p.id} style={{
                display: "inline-flex", alignItems: "center", gap: 5,
                padding: "2px 7px 2px 6px", borderRadius: 999,
                background: "var(--bg-sunk)", border: "1px solid var(--border-soft)",
                color: "var(--fg-2)", fontSize: 11.5
              }}>
                <span style={{ width: 5, height: 5, borderRadius: 999, background: "var(--c-perspective)" }} />
                {p.title || "untitled"}
              </span>
            ))
        }
      </div>
      <div style={{ display: "flex", alignItems: "center", gap: 8, color: "var(--fg-3)", fontSize: 11.5 }}>
        <span style={{ display: "inline-flex", alignItems: "center", gap: 4, fontFamily: "var(--font-mono)", textTransform: "uppercase", letterSpacing: ".08em" }}>
          {window.Icons.Link(11)} leads to
        </span>
        <select
          value={pattern.essenceId || ""}
          onChange={(e) => {
            const v = e.target.value;
            if (v === "__new__") onCreateEssence();
            else onChange({ essenceId: v || null });
          }}
          style={{ font: "inherit", background: "var(--bg-sunk)", color: "var(--fg)", border: "1px solid var(--border-soft)", borderRadius: 6, padding: "3px 6px", cursor: "pointer" }}
        >
          <option value="">— solo, on its own —</option>
          {essences.map(e => (
            <option key={e.id} value={e.id}>{(e.body || "untitled essence").slice(0, 40)}</option>
          ))}
          <option value="__new__">+ new essence</option>
        </select>
        {solo && (pattern.title || pattern.body) && (
          <span className="solo-mark" style={{ marginLeft: "auto" }}>· solo orbit</span>
        )}
      </div>
    </div>
  );
}

function EssenceCard({ essence, patterns, onChange, onRemove }) {
  return (
    <div className="surface" style={{
      padding: "20px 22px", display: "flex", flexDirection: "column", gap: 12,
      borderLeft: "2px solid var(--c-essence)",
    }}>
      <div style={{ display: "flex", alignItems: "flex-start", gap: 10 }}>
        <span style={{ width: 10, height: 10, borderRadius: 999, background: "var(--c-essence)", marginTop: 12, flexShrink: 0 }} />
        <textarea
          value={essence.body}
          onChange={(e) => onChange({ body: e.target.value })}
          placeholder="What remains after everything else falls away?"
          rows={2}
          style={{ fontFamily: "var(--font-serif)", fontSize: 28, lineHeight: 1.2, color: "var(--fg)" }}
          onInput={(e) => { e.target.style.height = "auto"; e.target.style.height = e.target.scrollHeight + "px"; }}
        />
        <button className="btn ghost icon tiny" onClick={onRemove}>{window.Icons.Trash(12)}</button>
      </div>
      <div style={{ display: "flex", flexWrap: "wrap", gap: 6, alignItems: "center", color: "var(--fg-3)", fontSize: 11.5 }}>
        <span className="tag-flat">distilled from</span>
        {patterns.length === 0
          ? <span style={{ fontStyle: "italic" }}>no patterns lead here yet</span>
          : patterns.map(p => (
              <span key={p.id} style={{
                display: "inline-flex", alignItems: "center", gap: 5, padding: "2px 7px",
                borderRadius: 999, background: "var(--bg)", border: "1px solid var(--border-soft)",
                color: "var(--fg-2)"
              }}>
                <span style={{ width: 5, height: 5, borderRadius: 999, background: "var(--c-pattern)" }} />
                {p.title || "untitled pattern"}
              </span>
            ))
        }
      </div>
    </div>
  );
}

// Right rail — structure map (text-only sankey of perspectives patterns essences)
function StructureMap({ concept }) {
  const grouped = _ce_um(() => {
    const byEssence = {};
    concept.essences.forEach(e => byEssence[e.id] = { essence: e, patterns: [] });
    byEssence["__solo"] = { essence: null, patterns: [] };
    concept.patterns.forEach(p => {
      const key = p.essenceId && byEssence[p.essenceId] ? p.essenceId : "__solo";
      byEssence[key].patterns.push({
        pattern: p,
        perspectives: concept.perspectives.filter(x => x.patternId === p.id)
      });
    });
    const soloPerspectives = concept.perspectives.filter(p => !p.patternId);
    return { byEssence, soloPerspectives };
  }, [concept]);

  return (
    <div className="surface" style={{ padding: 16, display: "flex", flexDirection: "column", gap: 12 }}>
      <div className="tag-flat">Structure</div>
      <div style={{ fontSize: 12.5, lineHeight: 1.55, color: "var(--fg-2)" }}>
        {Object.values(grouped.byEssence).map(({ essence, patterns: pats }) => (
          (essence || pats.length > 0) && (
            <div key={essence?.id || "solo"} style={{ marginBottom: 14 }}>
              {essence ? (
                <div style={{ fontFamily: "var(--font-serif)", fontStyle: "italic", color: "var(--fg)", fontSize: 14, marginBottom: 6, display: "flex", gap: 6 }}>
                  <span style={{ width: 6, height: 6, borderRadius: 999, background: "var(--c-essence)", marginTop: 7, flexShrink: 0 }} />
                  &ldquo;{(essence.body || "(unnamed)").slice(0, 80)}{(essence.body || "").length > 80 ? "…" : ""}&rdquo;
                </div>
              ) : (
                pats.length > 0 && <div className="solo-mark" style={{ marginBottom: 6 }}>· solo patterns</div>
              )}
              <div style={{ paddingLeft: 12, borderLeft: "1px dashed var(--border)" }}>
                {pats.map(({ pattern, perspectives: ps }) => (
                  <div key={pattern.id} style={{ marginBottom: 6 }}>
                    <div style={{ display: "flex", gap: 6, alignItems: "center", color: "var(--fg)", fontSize: 12.5 }}>
                      <span style={{ width: 5, height: 5, borderRadius: 999, background: "var(--c-pattern)" }} />
                      {pattern.title || "(unnamed pattern)"}
                    </div>
                    <div style={{ paddingLeft: 11, display: "flex", flexDirection: "column", gap: 2, marginTop: 2 }}>
                      {ps.length
                        ? ps.map(p => (
                            <div key={p.id} style={{ display: "flex", gap: 5, alignItems: "center", color: "var(--fg-3)", fontSize: 11.5 }}>
                              <span style={{ width: 4, height: 4, borderRadius: 999, background: "var(--c-perspective)", flexShrink: 0 }} />
                              {p.title || "untitled"}
                            </div>
                          ))
                        : <span style={{ fontStyle: "italic", color: "var(--fg-3)", fontSize: 11.5 }}>no perspectives yet</span>}
                    </div>
                  </div>
                ))}
              </div>
            </div>
          )
        ))}
        {grouped.soloPerspectives.length > 0 && (
          <div>
            <div className="solo-mark" style={{ marginBottom: 4 }}>· solo perspectives</div>
            <div style={{ paddingLeft: 12, display: "flex", flexDirection: "column", gap: 2 }}>
              {grouped.soloPerspectives.map(p => (
                <div key={p.id} style={{ display: "flex", gap: 5, alignItems: "center", color: "var(--fg-3)", fontSize: 11.5 }}>
                  <span style={{ width: 4, height: 4, borderRadius: 999, background: "var(--c-perspective)", flexShrink: 0 }} />
                  {p.title || "untitled"}
                </div>
              ))}
            </div>
          </div>
        )}
        {concept.perspectives.length === 0 && concept.patterns.length === 0 && concept.essences.length === 0 && (
          <span style={{ color: "var(--fg-3)", fontStyle: "italic" }}>structure builds as you fill in</span>
        )}
      </div>
    </div>
  );
}

function Helpers({ concept }) {
  const f = window.levelsFilled(concept);
  const tips = [];
  if (!f.consist) tips.push("Name what it's physically made of.");
  if (!f.function) tips.push("Describe its mechanism, not its purpose.");
  if (concept.perspectives.length < 2) tips.push("Add at least 2 perspectives — patterns need company.");
  const ungrouped = concept.perspectives.filter(p => !p.patternId && (p.title || p.body)).length;
  if (concept.perspectives.length >= 2 && concept.patterns.length === 0) tips.push("Try grouping perspectives into a pattern.");
  if (ungrouped > 0 && concept.patterns.length > 0) tips.push(`${ungrouped} perspective${ungrouped > 1 ? "s" : ""} still solo — keep them solo if they belong there.`);
  if (concept.patterns.length >= 2 && concept.essences.length === 0) tips.push("Look for what your patterns share.");
  if (tips.length === 0) tips.push("This concept is alive. Read it back when it's been a few days.");

  return (
    <div className="surface" style={{ padding: 16, display: "flex", flexDirection: "column", gap: 8 }}>
      <div className="tag-flat">Where you are</div>
      <div style={{ fontSize: 12.5, color: "var(--fg-2)", lineHeight: 1.55 }}>{tips[0]}</div>
    </div>
  );
}

function LinksSection({ concept, allConcepts, onUpdate }) {
  const [pending, setPending] = _ce_us(null);

  const links = (concept.links || []).map(l =>
    typeof l === 'string' ? { id: l, targetId: l, type: 'unknown' } : l
  );
  const others = allConcepts.filter(c => c.id !== concept.id && !links.some(l => l.targetId === c.id));

  function addLink(targetId, type) {
    onUpdate({ links: [...links, { id: 'l' + Date.now(), targetId, type }] });
    setPending(null);
  }
  function removeLink(targetId) {
    onUpdate({ links: links.filter(l => l.targetId !== targetId) });
  }

  const LINK_TYPES = [
    { type: 'essence',     label: 'Essence',     color: 'var(--c-essence)',     help: 'same nature' },
    { type: 'pattern',     label: 'Pattern',     color: 'var(--c-pattern)',     help: 'same mechanism' },
    { type: 'perspective', label: 'Perspective', color: 'var(--c-perspective)', help: 'shared context' },
  ];

  const pendingConcept = pending ? allConcepts.find(c => c.id === pending) : null;

  return (
    <Section
      tag="nucleus"
      label={`06 · Links${links.length ? ` · ${links.length}` : ""}`}
      heading="Connected concepts"
      help="Other concepts this one relates to — shown in the graph view."
    >
      <div style={{ display: "flex", flexWrap: "wrap", gap: 8, alignItems: "center", marginBottom: (pending || others.length > 0) ? 12 : 0 }}>
        {links.map(link => {
          const linked = allConcepts.find(x => x.id === link.targetId);
          if (!linked) return null;
          const typeInfo = LINK_TYPES.find(t => t.type === link.type);
          return (
            <span key={link.targetId} style={{
              display: "inline-flex", alignItems: "center", gap: 6,
              padding: "4px 6px 4px 10px", borderRadius: 999,
              background: "var(--bg-sunk)", border: "1px solid var(--border-soft)",
              fontSize: 13, fontFamily: "var(--font-serif)", fontStyle: "italic"
            }}>
              {typeInfo && (
                <span style={{ width: 7, height: 7, borderRadius: 999, background: typeInfo.color, flexShrink: 0 }} />
              )}
              {linked.title}
              {typeInfo && (
                <span style={{ fontFamily: "var(--font-mono)", fontSize: 9, letterSpacing: ".07em", textTransform: "uppercase", color: "var(--fg-3)", fontStyle: "normal" }}>
                  {typeInfo.label}
                </span>
              )}
              <button className="btn ghost icon tiny" onClick={() => removeLink(link.targetId)}
                title="Remove link" style={{ padding: 2, borderRadius: 999 }}>
                {window.Icons.Trash(10)}
              </button>
            </span>
          );
        })}

        {links.length === 0 && !pending && others.length === 0 && (
          <span style={{ color: "var(--fg-3)", fontStyle: "italic", fontSize: 13 }}>
            No other concepts yet — add more to the library first.
          </span>
        )}
      </div>

      {/* Type picker shown after concept is selected */}
      {pending && pendingConcept && (
        <div style={{
          display: "flex", alignItems: "center", flexWrap: "wrap", gap: 8,
          padding: "10px 14px", background: "var(--bg-sunk)", borderRadius: 8, marginBottom: 10,
        }}>
          <span style={{ fontFamily: "var(--font-serif)", fontStyle: "italic", fontSize: 13, color: "var(--fg)" }}>
            {pendingConcept.title}
          </span>
          <span style={{ fontSize: 11, color: "var(--fg-3)", fontFamily: "var(--font-mono)" }}>via →</span>
          {LINK_TYPES.map(t => (
            <button key={t.type} className="btn ghost tiny"
              style={{ borderColor: t.color, color: t.color, fontFamily: "var(--font-mono)", fontSize: 10.5, letterSpacing: ".05em" }}
              onClick={() => addLink(pending, t.type)}
              title={t.help}
            >
              {t.label}
            </button>
          ))}
          <button className="btn ghost tiny" style={{ marginLeft: "auto", color: "var(--fg-3)" }}
            onClick={() => setPending(null)}>cancel</button>
        </div>
      )}

      {!pending && others.length > 0 && (
        <span style={{ position: "relative", display: "inline-flex", alignItems: "center" }}>
          <select
            value=""
            onChange={e => { if (e.target.value) setPending(e.target.value); e.target.value = ""; }}
            style={{
              font: "inherit", fontSize: 12.5,
              background: "var(--bg-sunk)", color: "var(--fg-3)",
              border: "1px dashed var(--border)", borderRadius: 999,
              padding: "4px 28px 4px 10px", cursor: "pointer", outline: "none",
              fontStyle: "italic", appearance: "none", WebkitAppearance: "none"
            }}
          >
            <option value="">+ link a concept</option>
            {others.map(oc => <option key={oc.id} value={oc.id}>{oc.title}</option>)}
          </select>
          <svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"
            style={{ position: "absolute", right: 9, pointerEvents: "none", color: "var(--fg-3)" }}>
            <path d="M6 9l6 6 6-6"/>
          </svg>
        </span>
      )}
    </Section>
  );
}

Object.assign(window, { ConceptEdit });
