// Source: index.html script block (extracted). Loaded via <script type="text/babel"> in index.html.
function Editor({ task, setRoute, onPatch, user }) {
  const { t: tr } = useLang();
  const [tab, setTab] = React.useState("scenario");
  const [saving, setSaving] = React.useState(tr("ed_saved_2s"));
  const [toast, setToast] = React.useState(null);
  const toastTimerRef = React.useRef(0);
  const readOnlyLockRef = React.useRef(0);

  const assigneeEmail = task?.assigneeEmail || task?.assignee_email || null;
  const canEdit = user?.role === "manager"
    || (assigneeEmail && assigneeEmail === user?.email)
    || (!assigneeEmail && user?.role === "manager");

  const showToast = (msg, ms = 2500) => {
    setToast(msg);
    if (toastTimerRef.current) clearTimeout(toastTimerRef.current);
    toastTimerRef.current = setTimeout(() => setToast(null), ms);
  };
  const notifyReadOnly = () => {
    const now = Date.now();
    if (now - readOnlyLockRef.current < 1000) return;
    readOnlyLockRef.current = now;
    showToast("Read-only: ask a manager to assign this task to you.");
  };

  const mark = () => { setSaving(tr("ed_saving_dot")); setTimeout(()=>setSaving(tr("ed_saved_just")), 600); };
  const patch = (p) => {
    if (!canEdit) { notifyReadOnly(); return; }
    onPatch(p);
    mark();
  };

  const tabs = [
    { k:"scenario", n:"01", label: tr("ed_tab_scenario") },
    { k:"persona", n:"02", label: tr("ed_tab_persona"), dirty:true },
    { k:"eval", n:"03", label: tr("ed_tab_criteria"), dirty:true },
    { k:"tools", n:"04", label: tr("ed_tab_tools") },
    { k:"dialogue", n:"05", label: tr("ed_tab_dialogue") },
    { k:"raw", n:"06", label: tr("ed_tab_raw") },
  ];

  const requiredTools = task.requiredTools || [];
  const optionalTools = task.optionalTools || [];
  const forbiddenTools = task.forbiddenTools || [];
  const history = task.history || [];
  const meds = task.meds || [];
  const allergies = task.allergies || [];
  const reasoning = task.reasoning || [];
  const refDialogue = task.refDialogue || [];
  const mustAskAbout = task.mustAskAbout || [];
  const mustNotLeak = task.mustNotLeak || [];
  const customTools = task.customTools || [];
  const qualityDims = task.qualityDims || {};
  const setDim = (key, v) => {
    patch({ qualityDims: { ...qualityDims, [key]: v } });
  };
  // Legacy `read`/`write` kinds are treated as `required`; unknown falls to `off`.
  const normalizeToolState = (state) => {
    if (state === 'required' || state === 'optional' || state === 'forbidden' || state === 'off') return state;
    if (state === 'read' || state === 'write') return 'required';
    return 'off';
  };
  const toolStateOf = (name) => {
    if (forbiddenTools.includes(name)) return 'forbidden';
    if (optionalTools.includes(name)) return 'optional';
    if (requiredTools.includes(name)) return 'required';
    return 'off';
  };
  // Shared transition — mutual exclusion across the three arrays.
  const setToolState = (toolName, nextState) => {
    const drop = (arr) => (arr || []).filter(n => n !== toolName);
    const req = drop(requiredTools);
    const opt = drop(optionalTools);
    const fbd = drop(forbiddenTools);
    if (nextState === 'required') req.push(toolName);
    else if (nextState === 'optional') opt.push(toolName);
    else if (nextState === 'forbidden') fbd.push(toolName);
    patch({ requiredTools: req, optionalTools: opt, forbiddenTools: fbd });
  };
  // Reconcile the three arrays whenever customTools changes. Built-in bindings
  // are preserved; custom-tool names are re-added per their current kind.
  const setCustomTools = (next) => {
    const prevNames = new Set(customTools.map(t => t.name).filter(Boolean));
    const strip = (arr) => (arr || []).filter(n => !prevNames.has(n));
    const req = strip(requiredTools);
    const opt = strip(optionalTools);
    const fbd = strip(forbiddenTools);
    next.forEach(t => {
      if (!t.name) return;
      const s = normalizeToolState(t.kind);
      if (s === 'required') req.push(t.name);
      else if (s === 'optional') opt.push(t.name);
      else if (s === 'forbidden') fbd.push(t.name);
    });
    patch({
      customTools: next,
      requiredTools: Array.from(new Set(req)),
      optionalTools: Array.from(new Set(opt)),
      forbiddenTools: Array.from(new Set(fbd)),
    });
  };
  const updateCustomAt = (i, updater) => {
    setCustomTools(customTools.map((t, idx) => idx === i ? updater(t) : t));
  };
  const removeForbiddenAt = (name) => {
    patch({ forbiddenTools: forbiddenTools.filter(n => n !== name) });
  };
  const trOr = (key, fallback) => {
    const v = tr(key);
    return v === key ? fallback : v;
  };

  const [showAssign, setShowAssign] = React.useState(false);
  const doAssign = async (email) => {
    try {
      await window.tasksApi.assign(task.id, email);
      onPatch({ assignee_email: email, assigneeEmail: email });
      mark();
      setShowAssign(false);
      showToast(email ? `Assigned to ${email}` : "Unassigned");
    } catch (e) {
      showToast(`Error: ${e?.message || e}`);
    }
  };

  const BUILT_IN_TOOL_NAMES = ["get_patient_by_mrn","search_disease_info","get_drug_info","order_lab_test","prescribe_medication","refer_to_specialist"];
  const isManager = user?.role === "manager";
  const catalogApiAvailable = !!(window.tasksApi && window.tasksApi.listTools);
  const [catalog, setCatalog] = React.useState(() => Array.isArray(window.__CAA_TOOL_CATALOG) ? window.__CAA_TOOL_CATALOG : []);
  const [catalogOffline, setCatalogOffline] = React.useState(!catalogApiAvailable);
  const [editingCatalog, setEditingCatalog] = React.useState(null); // { name, description, parameters }
  const [showBrowse, setShowBrowse] = React.useState(false);
  const reloadCatalog = React.useCallback(async () => {
    const fromWindow = Array.isArray(window.__CAA_TOOL_CATALOG) ? window.__CAA_TOOL_CATALOG : [];
    setCatalog(fromWindow);
    if (!window.tasksApi?.listTools) { setCatalogOffline(true); return; }
    try {
      const list = await window.tasksApi.listTools();
      if (list === "OFFLINE" || list?.offline || list?.error) { setCatalogOffline(true); return; }
      if (Array.isArray(list)) {
        setCatalog(list);
        window.__CAA_TOOL_CATALOG = list;
        setCatalogOffline(false);
      }
    } catch (e) { setCatalogOffline(true); }
  }, []);
  React.useEffect(() => {
    reloadCatalog();
    const handler = () => reloadCatalog();
    window.addEventListener("caa-tool-catalog-invalidated", handler);
    return () => window.removeEventListener("caa-tool-catalog-invalidated", handler);
  }, [reloadCatalog]);

  const catalogSig = (params) => {
    const list = Array.isArray(params) ? params : [];
    if (!list.length) return "()";
    return `(${list.map(p => `${p.name || "?"}: ${p.type || "string"}`).join(", ")})`;
  };
  const startEditCatalog = (entry) => {
    setEditingCatalog({
      name: entry.name,
      description: entry.description || '',
      parameters: (entry.parameters || []).map(p => ({ ...p })),
    });
  };
  const updateEditField = (updater) => setEditingCatalog(prev => prev ? updater(prev) : prev);
  const saveEditedCatalog = async () => {
    if (!editingCatalog) return;
    try {
      const res = await window.tasksApi.updateTool(editingCatalog.name, {
        description: editingCatalog.description,
        parameters: editingCatalog.parameters,
      });
      if (res?.error) { showToast(`Error: ${res.error}`); return; }
      setEditingCatalog(null);
      window.tasksApi.invalidateTools?.();
      reloadCatalog();
      showToast("Catalog updated.");
    } catch (e) {
      showToast(`Error: ${e?.message || e}`);
    }
  };
  const deleteCatalogEntry = async (name) => {
    if (!window.confirm(`Delete "${name}" from the global catalog? Tasks that reference this name will keep the binding but the definition will be gone.`)) return;
    try {
      const res = await window.tasksApi.deleteTool(name);
      if (res?.error) { showToast(`Error: ${res.error}`); return; }
      window.tasksApi.invalidateTools?.();
      reloadCatalog();
      showToast(`Deleted "${name}".`);
    } catch (e) {
      showToast(`Error: ${e?.message || e}`);
    }
  };
  const saveCustomToCatalog = async (i) => {
    const tool = customTools[i];
    if (!tool?.name) return;
    if (!window.confirm(`Promote "${tool.name}" to the global catalog? All future tasks can bind this tool.`)) return;
    try {
      const res = await window.tasksApi.saveTool({
        name: tool.name,
        description: tool.description || '',
        parameters: tool.parameters || [],
        kind: "write",
      });
      if (res?.error) { showToast(`Error: ${res.error}`); return; }
      // Remove from task.customTools but keep the binding name in the state arrays.
      onPatch({ customTools: customTools.filter((_, idx) => idx !== i) });
      mark();
      window.tasksApi.invalidateTools?.();
      reloadCatalog();
      showToast("Added to catalog.");
    } catch (e) {
      showToast(`Error: ${e?.message || e}`);
    }
  };
  const addCatalogBinding = (name) => {
    setToolState(name, 'required');
    setShowBrowse(false);
  };
  const boundNames = new Set([...requiredTools, ...optionalTools, ...forbiddenTools, ...customTools.map(t => t.name).filter(Boolean)]);
  const browseCandidates = catalog.filter(t => !boundNames.has(t.name));
  const dimKeys = ["clinical_accuracy", "scenario_realism", "evaluation_completeness", "difficulty"];
  const dimVals = dimKeys.map(k => qualityDims[k]).filter(v => typeof v === "number");
  const overallDisplay = dimVals.length
    ? (dimVals.reduce((a,b)=>a+b, 0) / dimVals.length).toFixed(1)
    : "—";

  return (
    <div className="workspace">
      <div className="ws-head">
        <div className="ws-crumbs">
          <span>editor</span> / <b>{task.id}</b> / <span>{tab}</span>
        </div>
        <div className="ws-status">
          <span className="ws-saving">{saving}</span>
          <button className="btn ghost" onClick={()=>setRoute("queue")}>{tr("ed_back_queue")}</button>
          <button
            className="btn"
            title={tr("export_task_hint")}
            disabled={!canEdit}
            onClick={()=>exportTasksJson([task], `${task.id}.json`)}
          >{Ico.download()} {tr("export_task")}</button>
          <button
            className="btn"
            disabled={!canEdit}
            onClick={()=>setRoute("simulate")}
          >{Ico.play()} {tr("ed_run_sim")} <span className="kbd">R</span></button>
          <button
            className="btn primary"
            disabled={!canEdit}
            onClick={()=>patch({
              status: 'approved',
              lastEditor: user?.email ?? user?.name ?? 'unknown',
              lastEdited: new Date().toISOString(),
            })}
          >{Ico.check()} {tr("ed_approve")} <span className="kbd">⏎</span></button>
        </div>
      </div>
      {!canEdit && (
        <div className="editor-readonly-banner" style={{padding:"8px 14px", background:"var(--bg-sunken)", borderBottom:"1px solid var(--line)", fontSize:12.5, color:"var(--ink-dim)", display:"flex", gap:10, alignItems:"center"}}>
          <span className="tag amber">read-only</span>
          <span>This task is not assigned to you. Contact a manager to request assignment.</span>
        </div>
      )}
      <div className="tabs">
        {tabs.map(t => (
          <button key={t.k} className="tab" data-active={tab===t.k} onClick={()=>setTab(t.k)}>
            <span className="tab-num">{t.n}</span>{t.label}
            {t.dirty && <span className="dot"/>}
          </button>
        ))}
      </div>
      <div className="ws-body">
        <div className="editor">
          <div className="editor-main">
            {tab === "scenario" && (
              <Section title="Scenario" hint="Clinical framing, surfaced to the patient simulator.">
                <Field label="chief_complaint">
                  <input className="inp" value={task.chief ?? ''} onChange={e=>patch({ chief: e.target.value })} />
                </Field>
                <Field label="suspected_dx">
                  <input className="inp diff-edited" value={task.diagnosis ?? ''} onChange={e=>patch({ diagnosis: e.target.value })} />
                </Field>
                <Field label="duration">
                  <input className="inp" value={task.duration ?? ''} onChange={e=>patch({ duration: e.target.value })}/>
                </Field>
                <Field label="severity">
                  <div style={{display:"flex", gap:6}}>
                    {["mild","moderate","severe"].map(s=>(
                      <button key={s} className="filter-pill" data-active={task.severity===s} onClick={()=>patch({ severity: s })}>{s}</button>
                    ))}
                  </div>
                </Field>
                <Field label="notes">
                  <textarea className="ta" value={task.notes ?? ''} onChange={e=>patch({ notes: e.target.value })}/>
                </Field>
                <Field label="purpose">
                  <input className="inp" value={task.purpose ?? ''} onChange={e=>patch({ purpose: e.target.value })} />
                </Field>
              </Section>
            )}

            {tab === "persona" && (
              <Section title="Patient persona" hint="Injected into user_scenario.instructions at simulation time.">
                <Field label="name">
                  <input className="inp" value={task.patientName ?? ''} onChange={e=>patch({ patientName: e.target.value })}/>
                </Field>
                <Field label="mrn">
                  <input
                    className="inp"
                    style={{fontFamily:"var(--font-mono)"}}
                    value={task.mrn ?? `MRN${String(task.id).slice(-6)}`}
                    onChange={e=>patch({ mrn: e.target.value })}
                  />
                </Field>
                <Field label="age">
                  <input
                    className="inp"
                    type="number"
                    value={task.age ?? ''}
                    onChange={e=>patch({ age: e.target.value === '' ? '' : Number(e.target.value) })}
                    style={{width:90}}
                  />
                </Field>
                <Field label="gender">
                  <div style={{display:"flex", gap:6}}>
                    {["male","female","other"].map(s=>(
                      <button key={s} className="filter-pill" data-active={task.gender===s} onClick={()=>patch({ gender: s })}>{s}</button>
                    ))}
                  </div>
                </Field>
                <Field label="past_medical_history">
                  <textarea
                    className="ta"
                    placeholder="one per line — e.g. Hypertension (10y)"
                    value={history.join('\n')}
                    onChange={e=>patch({ history: e.target.value.split('\n').map(s=>s.trim()).filter(Boolean) })}
                  />
                </Field>
                <Field label="medications">
                  <textarea
                    className="ta"
                    placeholder="drug · dose · frequency"
                    value={meds.join('\n')}
                    onChange={e=>patch({ meds: e.target.value.split('\n').map(s=>s.trim()).filter(Boolean) })}
                  />
                </Field>
                <Field label="allergies">
                  <input
                    className="inp"
                    value={allergies.join(', ')}
                    onChange={e=>patch({ allergies: e.target.value.split(',').map(s=>s.trim()).filter(Boolean) })}
                  />
                </Field>
                <Field label="social_history">
                  <textarea
                    className="ta"
                    placeholder="smoking, alcohol, occupation…"
                    value={task.socialHistory ?? ''}
                    onChange={e=>patch({ socialHistory: e.target.value })}
                  />
                </Field>
                <Field label="task_instructions">
                  <textarea
                    className="ta"
                    rows={6}
                    value={task.taskInstructions ?? ''}
                    onChange={e=>patch({ taskInstructions: e.target.value })}
                  />
                </Field>
              </Section>
            )}

            {tab === "eval" && (
              <Section title="Evaluation criteria" hint="Used by the RL reward model and clinical evaluator.">
                <EditableList
                  title="Required actions"
                  items={requiredTools}
                  tag={{ text: "req", cls: "green" }}
                  mono={true}
                  placeholder="tool_name"
                  addLabel="Add required action"
                  onChange={(next)=>patch({ requiredTools: next })}
                />
                <EditableList
                  title="Reasoning steps (ordered)"
                  items={reasoning}
                  numbered={true}
                  multiline={true}
                  placeholder="e.g. Assess severity and duration"
                  addLabel="Add step"
                  onChange={(next)=>patch({ reasoning: next })}
                />
                <EditableList
                  title="Must ask about"
                  items={mustAskAbout}
                  tag={{ text: "ask", cls: "accent" }}
                  placeholder="e.g. recent travel history"
                  addLabel="Add item"
                  onChange={(next)=>patch({ mustAskAbout: next })}
                />
                <EditableList
                  title="Must not leak"
                  items={mustNotLeak}
                  tag={{ text: "leak", cls: "red" }}
                  placeholder="e.g. true diagnosis label"
                  addLabel="Add item"
                  onChange={(next)=>patch({ mustNotLeak: next })}
                />
                <div style={{marginBottom:16}}>
                  <div style={{fontSize:11.5, color:"var(--ink-mute)", fontFamily:"var(--font-mono)", marginBottom:6, textTransform:"uppercase", letterSpacing:"0.05em"}}>{trOr("ed_forbidden_tools", "Forbidden tools")}</div>
                  {forbiddenTools.length === 0 ? (
                    <div style={{fontSize:12, color:"var(--ink-mute)", padding:"6px 0", fontStyle:"italic"}}>No forbidden tools configured.</div>
                  ) : (
                    forbiddenTools.map((name) => (
                      <div key={name} className="list-row">
                        <span className="tag red">{Ico.x()}</span>
                        <span style={{flex:1, fontFamily:"var(--font-mono)", fontSize:12.5}}>{name}</span>
                        <button
                          className="btn ghost danger"
                          title="remove from forbidden list"
                          onClick={()=>removeForbiddenAt(name)}
                        >{Ico.x()}</button>
                      </div>
                    ))
                  )}
                  <div style={{fontSize:11.5, color:"var(--ink-mute)", marginTop:8, lineHeight:1.5}}>
                    Tools forbidden for this task — configured on the Tools tab. Invoking any of these fails the evaluator.
                  </div>
                </div>
              </Section>
            )}

            {tab === "tools" && (
              <Section title="Tool bindings" hint="Tools exposed to the clinician agent during simulation.">
                {[
                  { n:"get_patient_by_mrn", k:"read", sig:"(mrn: str) → PatientRecord" },
                  { n:"search_disease_info", k:"read", sig:"(query: str) → DiseaseInfo" },
                  { n:"get_drug_info", k:"read", sig:"(drug: str) → DrugInfo" },
                  { n:"order_lab_test", k:"write", sig:"(test: str, priority: Priority) → Order" },
                  { n:"prescribe_medication", k:"write", sig:"(drug: str, dose: str, freq: str, dur: str) → Rx" },
                  { n:"refer_to_specialist", k:"write", sig:"(specialty: str, summary: str) → Referral" },
                ].map(tool=>{
                  const state = toolStateOf(tool.n);
                  return (
                    <div key={tool.n} className="tool-card">
                      <div className="tool-card-head">
                        {Ico.tool()}
                        <span className="tool-name">{tool.n}</span>
                        <span className="tool-kind" data-kind={tool.k}>{tool.k}</span>
                        <div style={{marginLeft:"auto", display:"flex", gap:4}}>
                          {["required","optional","forbidden","off"].map(s => (
                            <button
                              key={s}
                              className="filter-pill"
                              data-active={state === s}
                              onClick={()=>setToolState(tool.n, s)}
                            >{s}</button>
                          ))}
                        </div>
                      </div>
                      <div className="tool-card-body">
                        <span className="key">sig</span> <code>{tool.sig}</code>
                      </div>
                    </div>
                  );
                })}
                <div style={{marginTop:22, marginBottom:10, fontSize:11.5, color:"var(--ink-mute)", fontFamily:"var(--font-mono)", textTransform:"uppercase", letterSpacing:"0.05em"}}>Catalog tools</div>
                {catalogOffline ? (
                  <div style={{fontSize:12, color:"var(--ink-mute)", padding:"6px 0", fontStyle:"italic"}}>Catalog unavailable (server offline)</div>
                ) : catalog.length === 0 ? (
                  <div style={{fontSize:12, color:"var(--ink-mute)", padding:"6px 0", fontStyle:"italic"}}>No catalog tools yet — create one below and click Save to catalog.</div>
                ) : (
                  catalog.map(entry => {
                    const state = toolStateOf(entry.name);
                    const isEditing = editingCatalog && editingCatalog.name === entry.name;
                    return (
                      <div key={entry.name} className="tool-card">
                        <div className="tool-card-head">
                          {Ico.tool()}
                          <span className="tool-name">{entry.name}</span>
                          <span className="tool-kind" data-kind={entry.kind || 'write'}>{entry.kind || 'write'}</span>
                          <div style={{marginLeft:"auto", display:"flex", gap:4, alignItems:"center"}}>
                            {["required","optional","forbidden","off"].map(s => (
                              <button
                                key={s}
                                className="filter-pill"
                                data-active={state === s}
                                onClick={()=>setToolState(entry.name, s)}
                              >{s}</button>
                            ))}
                            {isManager && !isEditing && (
                              <React.Fragment>
                                <button className="btn ghost" style={{marginLeft:6}} onClick={()=>startEditCatalog(entry)}>Edit</button>
                                <button className="btn ghost danger" onClick={()=>deleteCatalogEntry(entry.name)}>Delete</button>
                              </React.Fragment>
                            )}
                          </div>
                        </div>
                        <div className="tool-card-body" style={{display:"grid", gap:8}}>
                          {isEditing ? (
                            <React.Fragment>
                              <textarea
                                className="ta"
                                rows={2}
                                placeholder="description"
                                value={editingCatalog.description}
                                onChange={e=>updateEditField(prev => ({ ...prev, description: e.target.value }))}
                              />
                              <div>
                                <div style={{fontSize:11, color:"var(--ink-mute)", marginBottom:6, fontFamily:"var(--font-mono)", textTransform:"uppercase", letterSpacing:"0.05em"}}>Parameters</div>
                                {(editingCatalog.parameters || []).map((p, pi) => (
                                  <div key={pi} className="list-row">
                                    <input
                                      className="inp"
                                      style={{flex:1, fontFamily:"var(--font-mono)"}}
                                      placeholder="name"
                                      value={p.name || ''}
                                      onChange={e=>updateEditField(prev => ({ ...prev, parameters: prev.parameters.map((q, qi) => qi === pi ? { ...q, name: e.target.value } : q) }))}
                                    />
                                    <select
                                      className="inp"
                                      style={{width:110}}
                                      value={p.type || 'string'}
                                      onChange={e=>updateEditField(prev => ({ ...prev, parameters: prev.parameters.map((q, qi) => qi === pi ? { ...q, type: e.target.value } : q) }))}
                                    >
                                      {["string","number","boolean","array","object"].map(x => (
                                        <option key={x} value={x}>{x}</option>
                                      ))}
                                    </select>
                                    <input
                                      className="inp"
                                      style={{flex:2}}
                                      placeholder="description"
                                      value={p.description || ''}
                                      onChange={e=>updateEditField(prev => ({ ...prev, parameters: prev.parameters.map((q, qi) => qi === pi ? { ...q, description: e.target.value } : q) }))}
                                    />
                                    <label style={{display:"flex", gap:5, alignItems:"center", fontSize:11.5, color:"var(--ink-mute)", whiteSpace:"nowrap"}}>
                                      <input
                                        type="checkbox"
                                        checked={!!p.required}
                                        onChange={e=>updateEditField(prev => ({ ...prev, parameters: prev.parameters.map((q, qi) => qi === pi ? { ...q, required: e.target.checked } : q) }))}
                                      /> required
                                    </label>
                                    <button
                                      className="btn ghost danger"
                                      onClick={()=>updateEditField(prev => ({ ...prev, parameters: prev.parameters.filter((_, qi) => qi !== pi) }))}
                                    >{Ico.x()}</button>
                                  </div>
                                ))}
                                <button
                                  className="btn"
                                  style={{marginTop:4}}
                                  onClick={()=>updateEditField(prev => ({ ...prev, parameters: [...(prev.parameters || []), { name:"", type:"string", description:"", required:false }] }))}
                                >{Ico.plus()} Add parameter</button>
                              </div>
                              <div style={{display:"flex", gap:8, justifyContent:"flex-end"}}>
                                <button className="btn ghost" onClick={()=>setEditingCatalog(null)}>Cancel</button>
                                <button className="btn primary" onClick={saveEditedCatalog}>Save</button>
                              </div>
                            </React.Fragment>
                          ) : (
                            <React.Fragment>
                              {entry.description && (
                                <div style={{fontSize:12, color:"var(--ink-dim)", lineHeight:1.5}}>{entry.description}</div>
                              )}
                              <div><span className="key">sig</span> <code>{catalogSig(entry.parameters)}</code></div>
                            </React.Fragment>
                          )}
                        </div>
                      </div>
                    );
                  })
                )}
                <div style={{marginTop:22, marginBottom:10, fontSize:11.5, color:"var(--ink-mute)", fontFamily:"var(--font-mono)", textTransform:"uppercase", letterSpacing:"0.05em"}}>Custom tools</div>
                {customTools.length === 0 && (
                  <div style={{fontSize:12, color:"var(--ink-mute)", padding:"6px 0", fontStyle:"italic"}}>no custom tools defined</div>
                )}
                {customTools.map((tool, i) => {
                  const isDup = !!tool.name && customTools.findIndex(t => t.name === tool.name) !== i;
                  const params = tool.parameters || [];
                  return (
                    <div key={i} className="tool-card tool-card-custom">
                      <div className="tool-card-head">
                        {Ico.tool()}
                        <input
                          className="inp"
                          style={{flex:1, fontFamily:"var(--font-mono)", fontSize:12.5}}
                          placeholder="tool_name"
                          value={tool.name || ''}
                          onChange={e=>updateCustomAt(i, t => ({ ...t, name: e.target.value }))}
                        />
                        <div style={{display:"flex", gap:4}}>
                          {["required","optional","forbidden","off"].map(s => (
                            <button
                              key={s}
                              className="filter-pill"
                              data-active={normalizeToolState(tool.kind) === s}
                              onClick={()=>updateCustomAt(i, t => ({ ...t, kind: s }))}
                            >{s}</button>
                          ))}
                        </div>
                        {isDup && (
                          <span style={{color:"var(--red)", fontSize:11, fontFamily:"var(--font-mono)"}}>duplicate name</span>
                        )}
                        {isManager && (
                          <button
                            className="btn ghost"
                            style={{marginLeft:"auto"}}
                            title="promote to global catalog"
                            disabled={!tool.name || isDup || BUILT_IN_TOOL_NAMES.includes(tool.name) || catalogOffline}
                            onClick={()=>saveCustomToCatalog(i)}
                          >Save to catalog</button>
                        )}
                        <button
                          className="btn ghost danger"
                          style={isManager ? undefined : {marginLeft:"auto"}}
                          title="remove tool"
                          onClick={()=>setCustomTools(customTools.filter((_, idx) => idx !== i))}
                        >{Ico.x()}</button>
                      </div>
                      <div className="tool-card-body" style={{display:"grid", gap:10}}>
                        <textarea
                          className="ta"
                          rows={2}
                          placeholder="description — what the tool does, when to use it"
                          value={tool.description || ''}
                          onChange={e=>updateCustomAt(i, t => ({ ...t, description: e.target.value }))}
                        />
                        <div>
                          <div style={{fontSize:11, color:"var(--ink-mute)", marginBottom:6, fontFamily:"var(--font-mono)", textTransform:"uppercase", letterSpacing:"0.05em"}}>Parameters</div>
                          {params.length === 0 && (
                            <div style={{fontSize:12, color:"var(--ink-mute)", padding:"4px 0", fontStyle:"italic"}}>no parameters</div>
                          )}
                          {params.map((p, pi) => (
                            <div key={pi} className="list-row">
                              <input
                                className="inp"
                                style={{flex:1, fontFamily:"var(--font-mono)"}}
                                placeholder="name"
                                value={p.name || ''}
                                onChange={e=>updateCustomAt(i, t => ({ ...t, parameters: (t.parameters || []).map((q, qi) => qi === pi ? { ...q, name: e.target.value } : q) }))}
                              />
                              <select
                                className="inp"
                                style={{width:110}}
                                value={p.type || 'string'}
                                onChange={e=>updateCustomAt(i, t => ({ ...t, parameters: (t.parameters || []).map((q, qi) => qi === pi ? { ...q, type: e.target.value } : q) }))}
                              >
                                {["string","number","boolean","array","object"].map(x => (
                                  <option key={x} value={x}>{x}</option>
                                ))}
                              </select>
                              <input
                                className="inp"
                                style={{flex:2}}
                                placeholder="description"
                                value={p.description || ''}
                                onChange={e=>updateCustomAt(i, t => ({ ...t, parameters: (t.parameters || []).map((q, qi) => qi === pi ? { ...q, description: e.target.value } : q) }))}
                              />
                              <label style={{display:"flex", gap:5, alignItems:"center", fontSize:11.5, color:"var(--ink-mute)", whiteSpace:"nowrap"}}>
                                <input
                                  type="checkbox"
                                  checked={!!p.required}
                                  onChange={e=>updateCustomAt(i, t => ({ ...t, parameters: (t.parameters || []).map((q, qi) => qi === pi ? { ...q, required: e.target.checked } : q) }))}
                                /> required
                              </label>
                              <button
                                className="btn ghost danger"
                                onClick={()=>updateCustomAt(i, t => ({ ...t, parameters: (t.parameters || []).filter((_, qi) => qi !== pi) }))}
                              >{Ico.x()}</button>
                            </div>
                          ))}
                          <button
                            className="btn"
                            style={{marginTop:4}}
                            onClick={()=>updateCustomAt(i, t => ({ ...t, parameters: [...(t.parameters || []), { name:"", type:"string", description:"", required:false }] }))}
                          >{Ico.plus()} Add parameter</button>
                        </div>
                      </div>
                    </div>
                  );
                })}
                <div style={{display:"flex", gap:8, marginTop:10}}>
                  <button
                    className="btn"
                    onClick={()=>setCustomTools([...customTools, { name:"", kind:"required", description:"", parameters:[] }])}
                  >{Ico.plus()} Add custom tool</button>
                  <button
                    className="btn ghost"
                    disabled={catalogOffline}
                    onClick={()=>setShowBrowse(true)}
                  >Browse catalog</button>
                </div>
              </Section>
            )}

            {tab === "dialogue" && (
              <Section title="Reference dialogue" hint="Optional — provides a canonical trajectory.">
                {refDialogue.map((m,i)=>(
                  <div key={i} style={{display:"grid", gridTemplateColumns:"90px 1fr auto", gap:10, padding:"8px 0", borderBottom:"1px dashed var(--line)", alignItems:"start"}}>
                    <button
                      className="btn ghost"
                      title="click to toggle role"
                      style={{fontFamily:"var(--font-mono)", fontSize:11.5, color: m.role==='assistant'?'var(--accent-ink)':'var(--ink-mute)', justifyContent:"flex-start", padding:"6px 6px"}}
                      onClick={()=>{
                        const nextRole = m.role === 'user' ? 'assistant' : 'user';
                        const next = refDialogue.map((turn, idx) => idx === i ? { ...turn, role: nextRole } : turn);
                        patch({ refDialogue: next });
                      }}
                    >{m.role}</button>
                    <textarea
                      className="ta"
                      value={m.text ?? ''}
                      rows={2}
                      onChange={e=>{
                        const next = refDialogue.map((turn, idx) => idx === i ? { ...turn, text: e.target.value } : turn);
                        patch({ refDialogue: next });
                      }}
                    />
                    <button
                      className="btn ghost danger"
                      onClick={()=>{
                        const next = refDialogue.filter((_, idx) => idx !== i);
                        patch({ refDialogue: next });
                      }}
                    >{Ico.x()}</button>
                  </div>
                ))}
                <button
                  className="btn"
                  style={{marginTop:10}}
                  onClick={()=>{
                    const last = refDialogue[refDialogue.length - 1];
                    const nextRole = last ? (last.role === 'user' ? 'assistant' : 'user') : 'user';
                    patch({ refDialogue: [...refDialogue, { role: nextRole, text: '' }] });
                  }}
                >{Ico.plus()} Add turn</button>
              </Section>
            )}

            {tab === "raw" && (
              <Section title="Raw task JSON" hint="source of truth · tau2 schema">
                <pre style={{margin:0, fontFamily:"var(--font-mono)", fontSize:11.5, lineHeight:1.55, color:"var(--ink-dim)", background:"var(--bg-sunken)", padding:14, borderRadius:6, overflow:"auto"}}>
{JSON.stringify(taskToTau2(task), null, 2)}
                </pre>
              </Section>
            )}
          </div>

          <div className="editor-side">
            <div style={{fontSize:11.5, color:"var(--ink-mute)", fontFamily:"var(--font-mono)", textTransform:"uppercase", letterSpacing:"0.05em", marginBottom:10}}>Annotation panel</div>
            <div className="overall">
              <span className="overall-score">{overallDisplay}</span>
              <span className="overall-max">/ 5.0</span>
              <span className="overall-label">Task quality<br/><span style={{color:"var(--ink-mute)"}}>auto + reviewer</span></span>
            </div>
            <AnnotGroup title="Task quality dimensions">
              <Pips label="Clinical accuracy" val={qualityDims.clinical_accuracy} onChange={v=>setDim('clinical_accuracy', v)}/>
              <Pips label="Scenario realism" val={qualityDims.scenario_realism} onChange={v=>setDim('scenario_realism', v)}/>
              <Pips label="Evaluation completeness" val={qualityDims.evaluation_completeness} onChange={v=>setDim('evaluation_completeness', v)}/>
              <Pips label="Difficulty" val={qualityDims.difficulty} onChange={v=>setDim('difficulty', v)}/>
            </AnnotGroup>
            <AnnotGroup title="Reviewer note">
              <textarea
                className="ta"
                rows={4}
                placeholder="Add context for the RL team — why did you accept/reject? Alternatives to consider?"
                value={task.reviewerNote ?? ''}
                onChange={e=>patch({ reviewerNote: e.target.value })}
              />
            </AnnotGroup>
            <div style={{display:"grid", gap:8}}>
              <button
                className="btn accent"
                style={{justifyContent:"center"}}
                disabled={!canEdit}
                onClick={()=>{
                  patch({
                    status: 'approved',
                    lastEditor: user?.email ?? user?.name ?? 'unknown',
                    lastEdited: new Date().toISOString(),
                  });
                  setRoute("queue");
                }}
              >{Ico.check()} Approve & move to next <span className="kbd">⇧⏎</span></button>
              <button
                className="btn"
                style={{justifyContent:"center"}}
                disabled={!canEdit}
                onClick={()=>patch({ status: 'needs-review' })}
              >Send back for regeneration</button>
              <button
                className="btn ghost danger"
                style={{justifyContent:"center"}}
                disabled={!canEdit}
                onClick={()=>{
                  if (window.confirm('Reject this task? This marks it as rejected and records you as the last editor.')) {
                    patch({
                      status: 'rejected',
                      lastEditor: user?.email ?? user?.name ?? 'unknown',
                      lastEdited: new Date().toISOString(),
                    });
                  }
                }}
              >Reject</button>
            </div>

            <div className="divider"/>
            <dl className="side-meta">
              <dt>Assigned to</dt>
              <dd>
                <span>{assigneeEmail || task.annotator || "— unassigned"}</span>
                {user?.role === "manager" && (
                  <span style={{position:"relative", marginLeft:8, display:"inline-block"}}>
                    <button
                      className="btn ghost"
                      style={{padding:"2px 6px", fontSize:11.5}}
                      onClick={()=>setShowAssign(v => !v)}
                    >Assign</button>
                    {showAssign && (
                      <AssignDropdown
                        onPick={doAssign}
                        onClose={()=>setShowAssign(false)}
                        allowClear={true}
                      />
                    )}
                  </span>
                )}
              </dd>
              <dt>Generated</dt><dd className="mono">{task.generatedAt ?? "—"}</dd>
              <dt>Quality score (auto)</dt><dd className="mono">6.73 / 10</dd>
              <dt>History</dt><dd className="mono">{task.edits} edits</dd>
            </dl>
          </div>
        </div>
      </div>
      {toast && (
        <div style={{position:"fixed", bottom:20, right:20, background:"var(--ink)", color:"var(--bg)", padding:"10px 14px", fontSize:12, borderRadius:4, zIndex:100, fontFamily:"var(--font-mono)"}}>
          {toast}
        </div>
      )}
      {showBrowse && (
        <div className="modal-backdrop" onClick={()=>setShowBrowse(false)}>
          <div className="modal" style={{maxWidth:640}} onClick={e=>e.stopPropagation()}>
            <div className="modal-head">
              <h3>Browse catalog</h3>
              <button className="btn ghost" style={{marginLeft:"auto"}} onClick={()=>setShowBrowse(false)}>{Ico.x()}</button>
            </div>
            <div className="modal-body" style={{padding:14}}>
              {catalogOffline ? (
                <div style={{fontSize:12, color:"var(--ink-mute)", fontStyle:"italic"}}>Catalog unavailable (server offline)</div>
              ) : browseCandidates.length === 0 ? (
                <div style={{fontSize:12, color:"var(--ink-mute)", fontStyle:"italic"}}>
                  {catalog.length === 0
                    ? "No catalog tools yet — create one below and click Save to catalog."
                    : "All catalog tools are already bound to this task."}
                </div>
              ) : (
                browseCandidates.map(entry => (
                  <div key={entry.name} className="tool-card" style={{marginBottom:10}}>
                    <div className="tool-card-head">
                      {Ico.tool()}
                      <span className="tool-name">{entry.name}</span>
                      <span className="tool-kind" data-kind={entry.kind || 'write'}>{entry.kind || 'write'}</span>
                      <button
                        className="btn primary"
                        style={{marginLeft:"auto"}}
                        onClick={()=>addCatalogBinding(entry.name)}
                      >Add</button>
                    </div>
                    <div className="tool-card-body" style={{display:"grid", gap:6}}>
                      {entry.description && <div style={{fontSize:12, color:"var(--ink-dim)"}}>{entry.description}</div>}
                      <div><span className="key">sig</span> <code>{catalogSig(entry.parameters)}</code></div>
                    </div>
                  </div>
                ))
              )}
            </div>
            <div className="modal-foot">
              <button className="btn ghost" style={{marginLeft:"auto"}} onClick={()=>setShowBrowse(false)}>Close</button>
            </div>
          </div>
        </div>
      )}
    </div>
  );
}

function Section({ title, hint, children }) {
  return (
    <div className="section">
      <div className="section-head"><h3>{title}</h3>{hint && <span className="section-hint">{hint}</span>}</div>
      <div className="section-body">{children}</div>
    </div>
  );
}
function Field({ label, children }) {
  return (
    <div className="field">
      <div className="field-label">{label}</div>
      <div className="field-value">{children}</div>
    </div>
  );
}
function AnnotGroup({ title, children }) {
  return (
    <div className="annot-group">
      <div className="annot-group-head">{title}</div>
      <div className="annot-group-body">{children}</div>
    </div>
  );
}
// Controlled when onChange is passed; falls back to local state for the
// Editor's preview usage which doesn't care about the value.
function Pips({ label, val, onChange }) {
  const [local, setLocal] = React.useState(val);
  const v = onChange ? val : local;
  const set = (i) => { if (onChange) onChange(i); else setLocal(i); };
  return (
    <div className="score-row">
      <div className="score-row-label">{label} <span>{v ? `${v}/5` : "—"}</span></div>
      <div className="score-pips">
        {[1,2,3,4,5].map(i=>(
          <div key={i} className="pip" data-filled={v != null && i<=v} onClick={()=>set(i)}/>
        ))}
      </div>
    </div>
  );
}

// Small editable list used on the Eval tab. Renders each entry as an input
// (or textarea) with a delete button, plus an "add" button at the bottom.
function EditableList({ title, items, tag, numbered, mono, multiline, placeholder, addLabel, onChange }) {
  const list = items || [];
  const updateAt = (i, v) => onChange(list.map((x, idx) => idx === i ? v : x));
  const removeAt = (i) => onChange(list.filter((_, idx) => idx !== i));
  const add = () => onChange([...list, ""]);
  return (
    <div style={{marginBottom:16}}>
      <div style={{fontSize:11.5, color:"var(--ink-mute)", fontFamily:"var(--font-mono)", marginBottom:6, textTransform:"uppercase", letterSpacing:"0.05em"}}>{title}</div>
      {list.length === 0 && (
        <div style={{fontSize:12, color:"var(--ink-mute)", padding:"6px 0", fontStyle:"italic"}}>no entries</div>
      )}
      {list.map((entry, i) => (
        <div key={i} className="list-row" style={multiline ? {alignItems:"flex-start"} : undefined}>
          {numbered
            ? <span className="tag">{i+1}</span>
            : tag
              ? <span className={`tag ${tag.cls || ''}`}>{tag.text}</span>
              : null}
          {multiline ? (
            <textarea
              className="ta"
              style={{flex:1, minHeight:34}}
              rows={2}
              placeholder={placeholder}
              value={entry}
              onChange={e=>updateAt(i, e.target.value)}
            />
          ) : (
            <input
              className="inp"
              style={{flex:1, ...(mono ? {fontFamily:"var(--font-mono)"} : {})}}
              placeholder={placeholder}
              value={entry}
              onChange={e=>updateAt(i, e.target.value)}
            />
          )}
          <button className="btn ghost danger" onClick={()=>removeAt(i)}>{Ico.x()}</button>
        </div>
      ))}
      <button className="btn" style={{marginTop:4}} onClick={add}>{Ico.plus()} {addLabel}</button>
    </div>
  );
}

Object.assign(window, { Editor, Section, Field, AnnotGroup, Pips, EditableList });
