// 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, useLayoutEffect: _ce_ule } = React;

function CardBtn({ onClick, count }) {
  return (
    <button
      className="btn ghost icon tiny"
      onClick={onClick}
      title="Cards — media & notes"
      style={{ color: "var(--fg-3)", padding: "3px 5px", display: "flex", alignItems: "center", gap: 3 }}
    >
      {window.Icons.Cards(12)}
      {!!count && <span style={{ fontSize: 9.5, fontFamily: "var(--font-mono)", letterSpacing: ".04em", lineHeight: 1 }}>{count}</span>}
    </button>
  );
}

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

  _ce_ue(() => {
    if (!scrollTo) return;
    const tagMap = { consist: 'constant', function: 'function', perspective: 'perspective', pattern: 'pattern', essence: 'essence' };
    const tagId = tagMap[scrollTo] || scrollTo;
    const el = document.getElementById('ce-section-' + tagId);
    if (el) el.scrollIntoView({ behavior: 'smooth', block: 'start' });
  }, [scrollTo]);

  const [cardCounts, setCardCounts] = _ce_us({});
  _ce_ue(() => {
    if (!window.cardsService) return;
    window.cardsService.getCardsByConceptId(c.id).then(rows => {
      const m = {};
      rows.forEach(q => { m[q.parent_id] = (m[q.parent_id] || 0) + 1; });
      setCardCounts(m);
    });
  }, [c.id]);

  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: "none", margin: 0, padding: panelMode ? "20px 22px" : "68px 24px 80px 108px" }}>
      {/* 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={{ position: "fixed", top: 14, left: 98, right: 14, zIndex: 30, display: "flex", alignItems: "center", gap: 12, padding: "6px 10px", background: "var(--bg)", backdropFilter: "blur(12px)", WebkitBackdropFilter: "blur(12px)", borderRadius: 12 }}>
          <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: 1, background: "var(--bg-sunk)", borderRadius: 7, padding: 2 }}>
              <button className="btn tiny" style={{ border: 0, padding: "2px 8px", fontSize: 11, background: "var(--bg-elev)", color: "var(--fg)", boxShadow: "0 1px 2px rgba(0,0,0,.08)" }}>Edit</button>
              <button className="btn tiny" style={{ border: 0, padding: "2px 8px", fontSize: 11, background: "transparent", color: "var(--fg-3)" }} onClick={() => onSwitchMode("read")}>Read</button>
            </div>
            <div className="mode-pill">
              <button className="btn tiny" data-active="true" style={modeBtnStyle(true)}>{window.Icons.Word(13)} Word</button>
              {onOpenCardsHub && <button className="btn tiny" style={modeBtnStyle(false)} onClick={onOpenCardsHub}>{window.Icons.Cards(13)} Card</button>}
              <button className="btn tiny" style={modeBtnStyle(false)} onClick={onOpenSolar}>{window.Icons.Planet(13)} Solar</button>
              <button className="btn tiny" style={modeBtnStyle(false)} onClick={() => onOpenGraph && onOpenGraph(c.id)}>{window.Icons.Graph(13)} Graph</button>
              <button className="btn tiny" style={modeBtnStyle(false)} onClick={() => onOpenGroup && onOpenGroup(c.id)}>{window.Icons.Atom(13)} Group</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."
            action={
              <CardBtn onClick={() => onOpenCards && onOpenCards("consist", "cons_" + c.id, c.consist || c.title)} count={cardCounts["cons_" + c.id] || 0} />
            }
          >
            <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={
              <div style={{ display: "flex", gap: 6 }}>
                <CardBtn onClick={() => onOpenCards && onOpenCards("function", "func_" + c.id, getFunctions()[0]?.body || c.title)} count={cardCounts["func_" + c.id] || 0} />
                <button className="add-btn" onClick={addFunction}>{window.Icons.Plus(10)} new</button>
              </div>
            }
          >
            <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="add-btn" onClick={addPerspective}>{window.Icons.Plus(10)} new</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)}
                  onOpenCards={() => onOpenCards && onOpenCards("perspective", p.id, p.title || p.body || "(untitled)")}
                  cardCount={cardCounts[p.id] || 0}
                  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="add-btn" onClick={addPattern}>{window.Icons.Plus(10)} new</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)}
                  onOpenCards={() => onOpenCards && onOpenCards("pattern", p.id, p.title || p.body || "(untitled)")}
                  cardCount={cardCounts[p.id] || 0}
                  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="add-btn" onClick={addEssence}>{window.Icons.Plus(10)} new</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)}
                  onOpenCards={() => onOpenCards && onOpenCards("essence", e.id, e.body || "(untitled)")}
                  cardCount={cardCounts[e.id] || 0}
                />
              ))}
              {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 }}>
            <CardRailPreview concept={c} onOpenCardsHub={onOpenCardsHub} />
            <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(--c-nucleus)" : "transparent",
    boxShadow: active ? "0 1px 3px rgba(0,0,0,.15)" : "none",
    color: active ? "rgba(0,0,0,0.8)" : "var(--fg-3)",
  };
}

function Section({ tag, label, heading, help, children, action }) {
  return (
    <section id={'ce-section-' + tag} 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, onOpenCards, cardCount }) {
  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)" }}
        />
        {onOpenCards && <CardBtn onClick={onOpenCards} count={cardCount || 0} />}
        <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, onOpenCards, cardCount }) {
  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)" }}
        />
        {onOpenCards && <CardBtn onClick={onOpenCards} count={cardCount || 0} />}
        <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, onOpenCards, cardCount }) {
  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"; }}
        />
        <div style={{ display: "flex", gap: 4, flexShrink: 0, marginTop: 6 }}>
          {onOpenCards && <CardBtn onClick={onOpenCards} count={cardCount || 0} />}
          <button className="btn ghost icon tiny" onClick={onRemove}>{window.Icons.Trash(12)}</button>
        </div>
      </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>
  );
}


function CardRailPreview({ concept, onOpenCardsHub }) {
  var cardsState = _ce_us([]);
  var cards = cardsState[0], setCards = cardsState[1];

  _ce_ue(function() {
    if (!window.cardsService) return;
    window.cardsService.getAllCards().then(function(rows) {
      var arr = rows.filter(function(q) { return q.concept_id === concept.id; });
      for (var i = arr.length - 1; i > 0; i--) {
        var j = Math.floor(Math.random() * (i + 1));
        var tmp = arr[i]; arr[i] = arr[j]; arr[j] = tmp;
      }
      setCards(arr);
    });
  }, [concept.id]);

  var cols = cards.length === 1 ? 1 : cards.length <= 4 ? 2 : 3;

  var TYPE_COLOR = {
    note:  'var(--fg-3)',
    image: 'var(--c-pattern)',
    quote: 'var(--c-perspective)',
    link:  'var(--c-function)',
    video: 'var(--c-essence)',
  };

  function mkCard(q, key) {
    var text = q.type === 'link' ? (q.caption || q.content) : q.content;
    var snippet = (text || '').slice(0, 60) + ((text || '').length > 60 ? '...' : '');
    if (q.type === 'image' && q.content) {
      return (
        <div key={key} style={{ borderRadius: 6, overflow: 'hidden', marginBottom: 6, breakInside: 'avoid' }}>
          <img src={q.content} alt='' style={{ width: '100%', display: 'block' }} />
        </div>
      );
    }
    if (q.type === 'video' && q.content) {
      var m = q.content.match(/\/embed\/([A-Za-z0-9_-]{11})/);
      if (m) {
        return (
          <div key={key} style={{ borderRadius: 6, overflow: 'hidden', marginBottom: 6, breakInside: 'avoid' }}>
            <img src={'https://img.youtube.com/vi/' + m[1] + '/mqdefault.jpg'} alt='' style={{ width: '100%', display: 'block' }} />
          </div>
        );
      }
    }
    return (
      <div key={key} style={{ padding: '8px 10px', background: 'var(--bg-sunk)', borderRadius: 6, marginBottom: 6, breakInside: 'avoid' }}>
        <div style={{ display: 'flex', alignItems: 'center', gap: 4, marginBottom: 4 }}>
          <span style={{ width: 4, height: 4, borderRadius: 999, background: TYPE_COLOR[q.type] || 'var(--fg-3)', flexShrink: 0 }} />
          <span style={{ fontFamily: 'var(--font-mono)', fontSize: 8.5, letterSpacing: '.1em', textTransform: 'uppercase', color: 'var(--fg-3)' }}>{q.type}</span>
        </div>
        <div style={{
          fontSize: q.type === 'quote' ? 11.5 : 11,
          fontFamily: q.type === 'quote' ? 'var(--font-serif)' : 'var(--font-ui)',
          fontStyle: q.type === 'quote' ? 'italic' : 'normal',
          color: 'var(--fg-2)', lineHeight: 1.5,
        }}>
          {q.type === 'quote' ? ('"' + snippet + '"') : snippet}
        </div>
      </div>
    );
  }

  return (
    <div className='surface' style={{ padding: 12, display: 'flex', flexDirection: 'column', gap: 8 }}>
      <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center' }}>
        <div style={{ display: 'flex', alignItems: 'center', gap: 7 }}>
          <span style={{ color: 'var(--fg-3)', display: 'flex' }}>{window.Icons.Cards(11)}</span>
          <div className='tag-flat'>Cards</div>
          {cards.length > 0 && (
            <span style={{ fontFamily: 'var(--font-mono)', fontSize: 10, color: 'var(--fg-3)', opacity: 0.5 }}>{cards.length}</span>
          )}
        </div>
        {cards.length > 0 && onOpenCardsHub && (
          <button className='btn ghost tiny' onClick={onOpenCardsHub} style={{ fontSize: 10, color: 'var(--fg-3)' }}>open &rarr;</button>
        )}
      </div>

      {cards.length === 0 ? (
        <div style={{ height: 220, display: 'flex', alignItems: 'center', justifyContent: 'center', padding: '0 8px' }}>
          <p style={{ margin: 0, fontSize: 12, color: 'var(--fg-3)', fontStyle: 'italic', lineHeight: 1.55, textAlign: 'center' }}>
            Use the card button next to any level to attach notes, quotes, or images.
          </p>
        </div>
      ) : (
        <div style={{ height: 220, overflow: 'hidden' }}>
          <div style={{
            columnCount: cols,
            columnGap: 6,
          }}>
            {cards.map(function(q, i) { return mkCard(q, i); })}
          </div>
        </div>
      )}
    </div>
  );
}


Object.assign(window, { ConceptEdit });
