Q_WORKSPACE_V5_1.jsx
Design Mockups/Archived Mockups/DOC20 Mockups and Design/DOC20 Archived Mockups/DOC20 Workspace Redo/Q_WORKSPACE_V5_1.jsx
ELNOR REPO READER TEXT MIRROR
Original path: Design Mockups/Archived Mockups/DOC20 Mockups and Design/DOC20 Archived Mockups/DOC20 Workspace Redo/Q_WORKSPACE_V5_1.jsx
Source repo: /Users/OpenClaw1/Elnor/Elnor Specs
Git branch: main
Git commit: dbaa25962edc11ab30e8d4ca1715f9ae5bf77331
Generated: 2026-06-09T01:23:58.539Z
---
import { useState, useRef, useCallback, useEffect } from "react";
const font={sans:"'Söhne','Helvetica Neue',-apple-system,BlinkMacSystemFont,sans-serif"};
const R={sm:"6px",md:"10px",full:"9999px"};
const c={bgApp:"#F8F8F6",bgPanel:"#FFFFFF",bgPanelAlt:"#F9FAFB",bgCard:"#FFFFFF",bgInput:"#EFF1F3",bgSidebar:"#131820",textPri:"#1A1D21",textSec:"#5E6570",textTer:"#8B919A",accentBtn:"#31588c",warn:"#D97706",error:"#B04040",border:"#E0E2E5",borderLight:"#ECEEF0",green:"#2E8B57",agentAv:"#a1a7aa",borderDark:"#263040"};
const Ic=({d,size=18,color,sw=1.75})=><svg width={size} height={size} viewBox="0 0 24 24" fill="none" stroke={color||"currentColor"} strokeWidth={sw} strokeLinecap="round" strokeLinejoin="round"><path d={d}/></svg>;
const I={Plus:p=><Ic {...p} d="M12 5v14 M5 12h14"/>,X:p=><Ic {...p} d="M18 6L6 18 M6 6l12 12"/>,Check:p=><Ic {...p} d="M20 6L9 17l-5-5"/>,Spark:p=><Ic {...p} d="M12 2l1.5 4.5L18 8l-4.5 1.5L12 14l-1.5-4.5L6 8l4.5-1.5L12 2z M12 14l1 3 3 1-3 1-1 3-1-3-3-1 3-1 1-3z"/>,MsgCircle:p=><Ic {...p} d="M21 11.5a8.38 8.38 0 01-.9 3.8 8.5 8.5 0 01-7.6 4.7 8.38 8.38 0 01-3.8-.9L3 21l1.9-5.7a8.38 8.38 0 01-.9-3.8 8.5 8.5 0 014.7-7.6 8.38 8.38 0 013.8-.9h.5a8.48 8.48 0 018 8v.5z"/>,ChevD:p=><Ic {...p} d="M6 9l6 6 6-6"/>,ChevR:p=><Ic {...p} d="M9 18l6-6-6-6"/>,Search:p=><Ic {...p} d="M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z"/>,Maximize:p=><Ic {...p} d="M8 3H5a2 2 0 00-2 2v3m18 0V5a2 2 0 00-2-2h-3m0 18h3a2 2 0 002-2v-3M3 16v3a2 2 0 002 2h3"/>,Save:p=><Ic {...p} d="M19 21H5a2 2 0 01-2-2V5a2 2 0 012-2h11l5 5v11a2 2 0 01-2 2z M17 21v-8H7v8 M7 3v5h8"/>,Copy:p=><Ic {...p} d="M20 9h-9a2 2 0 00-2 2v9a2 2 0 002 2h9a2 2 0 002-2v-9a2 2 0 00-2-2z M5 15H4a2 2 0 01-2-2V4a2 2 0 012-2h9a2 2 0 012 2v1"/>,Link:p=><Ic {...p} d="M10 13a5 5 0 007.54.54l3-3a5 5 0 00-7.07-7.07l-1.72 1.71 M14 11a5 5 0 00-7.54-.54l-3 3a5 5 0 007.07 7.07l1.71-1.71"/>,Eye:p=><Ic {...p} d="M1 12s4-8 11-8 11 8 11 8-4 8-11 8-11-8-11-8z M12 9a3 3 0 100 6 3 3 0 000-6z"/>,Edit:p=><Ic {...p} d="M11 4H4a2 2 0 00-2 2v14a2 2 0 002 2h14a2 2 0 002-2v-7 M18.5 2.5a2.12 2.12 0 013 3L12 15l-4 1 1-4 9.5-9.5z"/>,Undo:p=><Ic {...p} d="M3 7v6h6 M21 17a9 9 0 00-9-9 9 9 0 00-6.69 3L3 13"/>,Redo:p=><Ic {...p} d="M21 7v6h-6 M3 17a9 9 0 019-9 9 9 0 016.69 3L21 13"/>,Folder:p=><Ic {...p} d="M22 19a2 2 0 01-2 2H4a2 2 0 01-2-2V5a2 2 0 012-2h5l2 3h9a2 2 0 012 2v11z"/>,FileText:p=><Ic {...p} d="M14 2H6a2 2 0 00-2 2v16a2 2 0 002 2h12a2 2 0 002-2V8z M14 2v6h6 M16 13H8 M16 17H8"/>,Settings:p=><Ic {...p} d="M12 15a3 3 0 100-6 3 3 0 000 6z"/>,List:p=><Ic {...p} d="M8 6h13 M8 12h13 M8 18h13 M3 6h.01 M3 12h.01 M3 18h.01"/>,Bell:p=><Ic {...p} d="M18 8A6 6 0 006 8c0 7-3 9-3 9h18s-3-2-3-9 M13.73 21a2 2 0 01-3.46 0"/>,Calendar:p=><Ic {...p} d="M19 4H5a2 2 0 00-2 2v14a2 2 0 002 2h14a2 2 0 002-2V6a2 2 0 00-2-2z M16 2v4 M8 2v4 M3 10h18"/>,Mail:p=><Ic {...p} d="M4 4h16c1.1 0 2 .9 2 2v12c0 1.1-.9 2-2 2H4c-1.1 0-2-.9-2-2V6c0-1.1.9-2 2-2z M22 6l-10 7L2 6"/>,Zap:p=><Ic {...p} d="M13 2L3 14h9l-1 8 10-12h-9l1-8z"/>,Sun:p=><Ic {...p} d="M12 17a5 5 0 100-10 5 5 0 000 10z M12 1v2 M12 21v2 M4.22 4.22l1.42 1.42 M18.36 18.36l1.42 1.42 M1 12h2 M21 12h2"/>,Grip:p=><Ic {...p} d="M9 4h.01M9 9h.01M9 14h.01M9 19h.01M15 4h.01M15 9h.01M15 14h.01M15 19h.01" sw={3}/>,Grid:p=><Ic {...p} d="M3 3h7v7H3z M14 3h7v7h-7z M3 14h7v7H3z M14 14h7v7h-7z"/>,};
const Dot=({color,size=8})=><span style={{display:"inline-flex",width:size,height:size,flexShrink:0}}><span style={{display:"block",width:size,height:size,borderRadius:"50%",backgroundColor:color}}/></span>;
const Btn=({children,primary,ghost,small,onClick,disabled,style:s})=><button onClick={disabled?undefined:onClick} style={{padding:small?"2px 8px":"5px 14px",borderRadius:R.sm,border:primary?"none":ghost?`1.5px solid ${c.border}`:`1px solid ${c.border}`,backgroundColor:primary?(disabled?c.accentBtn+"60":c.accentBtn):"transparent",color:primary?"#fff":c.textSec,fontSize:small?11:12.5,fontWeight:primary?550:450,cursor:disabled?"not-allowed":"pointer",fontFamily:font.sans,display:"flex",alignItems:"center",gap:5,height:small?22:28,opacity:disabled?.5:1,...s}}>{children}</button>;
const Av=({letter,color,size=20})=><div style={{width:size,height:size,borderRadius:R.sm,backgroundColor:color||c.accentBtn,color:"#fff",display:"flex",alignItems:"center",justifyContent:"center",fontSize:size*.42,fontWeight:700,flexShrink:0}}>{letter}</div>;
const TBtn=({icon,title,active,onClick,label,dropdown})=><button onClick={onClick} title={title} style={{padding:label?"3px 8px":"3px 6px",borderRadius:R.sm,border:`1px solid ${active?c.accentBtn+"40":c.borderLight}`,backgroundColor:active?c.accentBtn+"08":"transparent",cursor:"pointer",display:"flex",alignItems:"center",gap:4,color:active?c.accentBtn:c.textSec,fontFamily:font.sans,fontSize:10.5,fontWeight:active?600:450,height:26}} onMouseEnter={e=>{if(!active)e.currentTarget.style.backgroundColor=c.bgInput}} onMouseLeave={e=>{e.currentTarget.style.backgroundColor=active?c.accentBtn+"08":"transparent"}}>{icon}{label&&<span>{label}</span>}{dropdown&&<I.ChevD size={8}/>}</button>;
const Sep=()=><div style={{width:1,height:18,backgroundColor:c.borderLight,margin:"0 3px",flexShrink:0}}/>;
const Toast=({msg,onDone})=>{useEffect(()=>{const t=setTimeout(onDone,2200);return()=>clearTimeout(t)},[onDone]);return <div style={{position:"fixed",bottom:24,left:"50%",transform:"translateX(-50%)",backgroundColor:c.textPri,color:"#fff",padding:"8px 18px",borderRadius:R.sm,fontSize:12,fontWeight:500,fontFamily:font.sans,zIndex:9999,boxShadow:"0 4px 16px rgba(0,0,0,0.2)"}}>{msg}</div>};
const DItem=({children,onClick,active})=><button onClick={onClick} style={{display:"flex",alignItems:"center",gap:6,width:"100%",padding:"6px 10px",border:"none",cursor:"pointer",backgroundColor:active?c.accentBtn+"08":"transparent",fontSize:11.5,color:c.textPri,textAlign:"left",borderRadius:R.sm,fontFamily:font.sans,fontWeight:active?600:400}} onMouseEnter={e=>{if(!active)e.currentTarget.style.backgroundColor=c.bgInput}} onMouseLeave={e=>{if(!active)e.currentTarget.style.backgroundColor=active?c.accentBtn+"08":"transparent"}}>{children}</button>;
const agents=[{name:"Elnor",color:c.agentAv,letter:"E"}];
// Feed presets library
const feedPresets=[
{id:"fp1",name:"System Activity",icon:"spark",desc:"Agent completions, chain results, memory updates",category:"system",cost:false},
{id:"fp2",name:"System Notices",icon:"bell",desc:"Errors, warnings, sync issues, re-auth needed",category:"system",cost:false},
{id:"fp3",name:"Gate Approvals",icon:"check",desc:"Pending chain gates and approval requests",category:"system",cost:false},
{id:"fp4",name:"Active Operations",icon:"zap",desc:"Running agents, chains, and tasks",category:"system",cost:false},
{id:"fp5",name:"Morning Summary",icon:"sun",desc:"Daily briefing from Elnor — overnight activity, priorities",category:"agent",cost:true},
{id:"fp6",name:"Email Watch",icon:"mail",desc:"Flag important emails per your criteria",category:"agent",cost:true},
{id:"fp7",name:"Deadline Tracker",icon:"calendar",desc:"Calendar deadlines from Outlook integration",category:"agent",cost:true},
];
// Block data
const initBlocks=[
{id:"b00",type:"text",content:""},
{id:"b0",type:"bar",title:"Email from Sparacino received — Narayanan agreement redline",time:"2:15 PM",accent:c.accentBtn},
{id:"b1",type:"text",content:"Quick note: need to confirm with Danny that he's available for the May trial week before filing the expert disclosure."},
{id:"b2",type:"tasks",title:"To Do",collapsed:false,tasks:[
{id:"t1",text:"Draft expert disclosure for Christensen",done:false,due:"Apr 4",link:"Expert Depo Prep",sub:[{id:"s1",text:"Pull Christensen CV",done:true},{id:"s2",text:"List opinions to be offered",done:false},{id:"s3",text:"Identify documents reviewed",done:false}]},
{id:"t2",text:"Review Henderson MSJ brief — Elnor tracked changes",done:false,due:"Mar 20",link:"Henderson Discovery Priorities"},
{id:"t3",text:"Respond to Sparacino re: Narayanan agreement",done:false,due:"Mar 19"},
{id:"t4",text:"Follow up: opposing counsel on discovery extension",done:false,due:"Mar 19"},
{id:"t5",text:"Review Quark patent analysis — new filings",done:false,link:"Quark Patent Analysis"},
{id:"t6",text:"File Folb trial exhibit list",done:true,due:"Mar 17"},
]},
{id:"b3",type:"thread",collapsed:false,contextQuote:"opposing counsel on discovery extension",messages:[
{id:"m1",author:"You",color:c.accentBtn,body:"@Elnor draft a response declining the extension, cite the scheduling order deadline and the prejudice from further delay",time:"45m"},
{id:"m2",author:"Elnor",color:c.agentAv,body:"Draft ready. Key points: scheduling order set discovery cutoff March 28, extension would prejudice plaintiff's expert disclosure timeline, defendant has had 4 months to complete discovery. Want me to open it in a new note or paste below?",time:"40m"},
]},
{id:"b4",type:"text",content:"Call with Sparacino re: Narayanan — need to confirm NY vs CA choice of law for the restrictive covenant."},
{id:"b5",type:"feed",title:"Activity Brief",collapsed:false,preset:"fp1",sections:[
{key:"elnor",icon:"spark",label:"Elnor",items:[
{text:"Reviewed 3 Henderson depo transcripts — flagged 2 citation issues",time:"5h"},{text:"Updated Quark patent landscape — 4 new filings",time:"4h"},{text:"Scanned SEC filings — no Henderson-relevant amendments",time:"3h"},
]},
{key:"system",icon:"bell",label:"System",items:[
{text:"OneDrive sync paused — re-auth needed",time:"6h",accent:c.warn},{text:"DOC15 red-team review completed — 3 findings",time:"2h",accent:c.green},
]},
]},
{id:"b6",type:"text",content:""},
];
const feedIcons={spark:<I.Spark size={11} color={c.agentAv}/>,bell:<I.Bell size={11} color={c.warn}/>,check:<I.Check size={11} color={c.green}/>,zap:<I.Zap size={11} color={c.accentBtn}/>,sun:<I.Sun size={11} color={c.warn}/>,mail:<I.Mail size={11} color={c.accentBtn}/>,calendar:<I.Calendar size={11} color={c.error}/>};
export default function WorkspaceV5(){
const idC=useRef(500);const nid=()=>"x"+(++idC.current);
const [browserOpen,setBrowserOpen]=useState(false);
const [commentsOpen,setCommentsOpen]=useState(false);
const [rightTab,setRightTab]=useState("comments");
const [showMarkup,setShowMarkup]=useState(true);
const [findBar,setFindBar]=useState(false);
const [fullScreen,setFullScreen]=useState(false);
const [openDrop,setOpenDrop]=useState(null);
const [toast,setToast]=useState(null);
const [blocks,setBlocks]=useState(initBlocks);
const [expandedTask,setExpandedTask]=useState(null);
const [threadReplyId,setThreadReplyId]=useState(null);
const [threadReplyText,setThreadReplyText]=useState("");
const [newTaskText,setNewTaskText]=useState("");
const [newSubText,setNewSubText]=useState({});
const [collapsedFeeds,setCollapsedFeeds]=useState(new Set());
const [editingTitle,setEditingTitle]=useState(null);
// Module picker state
const [pickerOpen,setPickerOpen]=useState(false);
const [pickerStep,setPickerStep]=useState("choose"); // "choose" | "feed_presets" | "feed_custom"
const [pickerTab,setPickerTab]=useState("system");
const [customName,setCustomName]=useState("");
const [customInstruction,setCustomInstruction]=useState("");
const editorRef=useRef(null);const agent=agents[0];const flash=msg=>setToast(msg);
const toggleBlock=(id)=>setBlocks(p=>p.map(b=>b.id===id?{...b,collapsed:!b.collapsed}:b));
const toggleTask=(bid,tid)=>setBlocks(p=>p.map(b=>b.id===bid?{...b,tasks:b.tasks.map(t=>t.id===tid?{...t,done:!t.done}:t)}:b));
const toggleSub=(bid,tid,sid)=>setBlocks(p=>p.map(b=>b.id===bid?{...b,tasks:b.tasks.map(t=>t.id===tid?{...t,sub:t.sub.map(s=>s.id===sid?{...s,done:!s.done}:s)}:t)}:b));
const deleteBlock=id=>setBlocks(p=>p.filter(b=>b.id!==id));
const toggleFeedSection=key=>{const s=new Set(collapsedFeeds);s.has(key)?s.delete(key):s.add(key);setCollapsedFeeds(s)};
const addTask=(bid,text)=>{if(!text.trim())return;setBlocks(p=>p.map(b=>b.id===bid?{...b,tasks:[...b.tasks,{id:nid(),text:text.trim(),done:false,sub:[]}]}:b));setNewTaskText("")};
const addSubtask=(bid,tid,text)=>{if(!text.trim())return;setBlocks(p=>p.map(b=>b.id===bid?{...b,tasks:b.tasks.map(t=>t.id===tid?{...t,sub:[...t.sub,{id:nid(),text:text.trim(),done:false}]}:t)}:b));setNewSubText(p=>({...p,[tid]:""}))};
const addThreadReply=(bid)=>{if(!threadReplyText.trim())return;setBlocks(p=>p.map(b=>b.id===bid?{...b,messages:[...b.messages,{id:nid(),author:"You",color:c.accentBtn,body:threadReplyText.trim(),time:"now"}]}:b));setThreadReplyId(null);setThreadReplyText("")};
// Insert block at end (toolbar button inserts at cursor position in real impl)
const insertBlock=(type,preset)=>{
const newId=nid();let block;
if(type==="tasks")block={id:newId,type:"tasks",title:"New Task List",collapsed:false,tasks:[]};
else if(type==="feed"){
const p=preset||{name:"Custom Feed",sections:[]};
block={id:newId,type:"feed",title:p.name,collapsed:false,preset:p.id,sections:
p.id==="fp1"?[{key:"activity",icon:"spark",label:"Activity",items:[{text:"Waiting for events…",time:"now"}]}]:
p.id==="fp2"?[{key:"notices",icon:"bell",label:"Notices",items:[{text:"No active notices",time:"now"}]}]:
p.id==="fp5"?[{key:"morning",icon:"sun",label:"Summary",items:[{text:"Generating morning brief…",time:"now"}]}]:
[{key:"custom",icon:"spark",label:p.name,items:[{text:"Configure this feed via the gear icon or @Elnor",time:"now"}]}]
};
}
else if(type==="thread")block={id:newId,type:"thread",collapsed:false,contextQuote:"",messages:[{id:nid(),author:"You",color:c.accentBtn,body:"@Elnor ",time:"now"}]};
else if(type==="bar")block={id:newId,type:"bar",title:"New notice — click Elnor to configure",accent:c.warn};
else return;
setBlocks(p=>{
// Simulate inserting at cursor — in real Tiptap, inserts at cursor position
// In mockup, insert before the last text block (simulates typing position)
const lastTextIdx=p.map((b,i)=>b.type==="text"?i:-1).filter(i=>i>=0).pop();
const pos=lastTextIdx!==undefined?lastTextIdx:p.length;
return [...p.slice(0,pos),block,...p.slice(pos)];
});
setPickerOpen(false);setPickerStep("choose");
flash(`${type==="feed"?(preset?.name||"Feed"):type} block added`);
};
const DragHandle=()=><div style={{width:14,display:"flex",alignItems:"center",justifyContent:"center",cursor:"grab",opacity:0.18,flexShrink:0,marginRight:2}} onMouseEnter={e=>e.currentTarget.style.opacity=0.55} onMouseLeave={e=>e.currentTarget.style.opacity=0.18}><I.Grip size={12} color={c.textTer}/></div>;
const renderBlock=(block)=>{
// BAR
if(block.type==="bar") return <div key={block.id} style={{display:"flex",alignItems:"center",gap:8,padding:"7px 12px",borderRadius:R.sm,border:`1px solid ${block.accent||c.accentBtn}30`,backgroundColor:(block.accent||c.accentBtn)+"06",margin:"14px 0"}}>
<DragHandle/>
<span style={{flex:1,fontSize:13,color:c.textPri,lineHeight:1.4}}>{block.title}</span>
{block.time&&<span style={{fontSize:10,color:c.textTer,flexShrink:0}}>{block.time}</span>}
<button onClick={()=>flash(`Opening chat with ref to block:${block.id}`)} title="Ask Elnor" style={{padding:"2px 7px",borderRadius:R.sm,border:`1px solid ${c.agentAv}40`,backgroundColor:c.agentAv+"10",cursor:"pointer",display:"flex",alignItems:"center",gap:3,fontSize:10,fontFamily:font.sans,color:c.agentAv,fontWeight:600}}><I.Spark size={10}/>Elnor</button>
<button onClick={()=>deleteBlock(block.id)} style={{border:"none",background:"none",cursor:"pointer",padding:1,display:"flex",color:c.textTer}} onMouseEnter={e=>e.currentTarget.style.color=c.error} onMouseLeave={e=>e.currentTarget.style.color=c.textTer}><I.X size={11}/></button>
</div>;
// TEXT
if(block.type==="text") return <div key={block.id} style={{display:"flex",alignItems:"flex-start",margin:"4px 0",position:"relative"}} onMouseEnter={e=>{const d=e.currentTarget.querySelector("[data-del]");if(d)d.style.opacity=0.4}} onMouseLeave={e=>{const d=e.currentTarget.querySelector("[data-del]");if(d)d.style.opacity=0}}>
<div style={{paddingTop:6}}><DragHandle/></div>
<p contentEditable suppressContentEditableWarning style={{flex:1,fontSize:14,lineHeight:1.75,color:block.content?c.textPri:c.textTer,outline:"none",minHeight:28,padding:"4px 0"}}>{block.content||"Type here… @Elnor to ask, /todo /feed /ask for modules"}</p>
<button data-del="1" onClick={()=>deleteBlock(block.id)} style={{opacity:0,border:"none",background:"none",cursor:"pointer",padding:2,display:"flex",color:c.textTer,flexShrink:0,marginTop:6,transition:"opacity 0.1s"}}><I.X size={11}/></button>
</div>;
// TASKS
if(block.type==="tasks"){
const active=block.tasks.filter(t=>!t.done);const done=block.tasks.filter(t=>t.done);
if(block.collapsed) return <div key={block.id} style={{margin:"14px 0"}}><div onClick={()=>toggleBlock(block.id)} style={{display:"flex",alignItems:"center",gap:6,padding:"6px 10px",borderRadius:R.sm,border:`1px solid ${c.borderLight}`,backgroundColor:c.bgPanelAlt,cursor:"pointer"}}><DragHandle/><I.ChevR size={10} color={c.textTer}/><I.List size={12} color={c.warn}/><span style={{fontSize:12,fontWeight:650}}>{block.title}</span><span style={{fontSize:9.5,color:c.textTer,backgroundColor:c.bgInput,padding:"1px 6px",borderRadius:3}}>{active.length} open</span><span style={{flex:1}}/><button onClick={e=>{e.stopPropagation();deleteBlock(block.id)}} style={{border:"none",background:"none",cursor:"pointer",padding:1,display:"flex",color:c.textTer}} onMouseEnter={e=>e.currentTarget.style.color=c.error} onMouseLeave={e=>e.currentTarget.style.color=c.textTer}><I.X size={11}/></button></div></div>;
return <div key={block.id} style={{margin:"14px 0",borderRadius:R.sm,border:`1px solid ${c.borderLight}`,overflow:"hidden"}}>
<div onClick={()=>toggleBlock(block.id)} style={{display:"flex",alignItems:"center",gap:6,padding:"7px 10px",backgroundColor:c.bgPanelAlt,cursor:"pointer",borderBottom:`1px solid ${c.borderLight}`}}>
<DragHandle/><I.ChevD size={10} color={c.textTer}/><I.List size={12} color={c.warn}/>
{editingTitle===block.id?<input autoFocus defaultValue={block.title} onBlur={e=>{setBlocks(p=>p.map(b=>b.id===block.id?{...b,title:e.target.value||block.title}:b));setEditingTitle(null)}} onKeyDown={e=>{if(e.key==="Enter"){setBlocks(p=>p.map(b=>b.id===block.id?{...b,title:e.target.value||block.title}:b));setEditingTitle(null)}if(e.key==="Escape")setEditingTitle(null)}} onClick={e=>e.stopPropagation()} style={{flex:1,fontSize:12.5,fontWeight:700,border:`1px solid ${c.accentBtn}40`,borderRadius:3,padding:"1px 6px",outline:"none",fontFamily:font.sans,backgroundColor:c.bgCard}}/>
:<span style={{fontSize:12.5,fontWeight:700,flex:1,cursor:"text"}} onClick={e=>{e.stopPropagation();setEditingTitle(block.id)}}>{block.title}</span>}
<span style={{fontSize:9.5,color:c.textTer,backgroundColor:c.bgInput,padding:"1px 6px",borderRadius:3}}>{active.length} open</span>
<button onClick={e=>{e.stopPropagation();flash("Configure…")}} style={{border:"none",background:"none",cursor:"pointer",padding:1,display:"flex",color:c.textTer}}><I.Settings size={11}/></button>
<button onClick={e=>{e.stopPropagation();deleteBlock(block.id)}} style={{border:"none",background:"none",cursor:"pointer",padding:1,display:"flex",color:c.textTer}} onMouseEnter={e=>e.currentTarget.style.color=c.error} onMouseLeave={e=>e.currentTarget.style.color=c.textTer}><I.X size={11}/></button>
</div>
<div style={{padding:"4px 8px"}}>
{active.map(task=><div key={task.id} style={{borderBottom:`1px solid ${c.borderLight}`,paddingBottom:expandedTask===task.id?6:0}}>
<div style={{display:"flex",alignItems:"center",gap:8,padding:"6px 4px",cursor:"pointer"}} onClick={()=>setExpandedTask(expandedTask===task.id?null:task.id)}>
<input type="checkbox" checked={false} onChange={()=>toggleTask(block.id,task.id)} onClick={e=>e.stopPropagation()} style={{width:15,height:15,accentColor:c.accentBtn,flexShrink:0}}/>
<span style={{flex:1,fontSize:13.5,lineHeight:1.45,color:c.textPri}}>{task.text}</span>
<div style={{display:"flex",gap:5,alignItems:"center",flexShrink:0}}>
{task.due&&<span style={{fontSize:10,color:c.textTer}}>{task.due}</span>}
{task.link&&<span style={{fontSize:10,color:c.accentBtn,cursor:"pointer",display:"flex",alignItems:"center",gap:2}} onClick={e=>{e.stopPropagation();flash(`Open "${task.link}"`)}}><I.Link size={9}/>Note</span>}
{task.sub?.length>0&&<span style={{fontSize:10,color:c.textTer}}>{task.sub.filter(s=>s.done).length}/{task.sub.length}</span>}
<div style={{transform:expandedTask===task.id?"rotate(90deg)":"none",transition:"transform 0.1s"}}><I.ChevR size={9} color={c.textTer}/></div>
</div>
</div>
{expandedTask===task.id&&<div style={{padding:"2px 0 4px 30px"}}>
{task.sub?.map(s=><div key={s.id} style={{display:"flex",alignItems:"center",gap:6,padding:"3px 0"}}>
<input type="checkbox" checked={s.done} onChange={()=>toggleSub(block.id,task.id,s.id)} style={{width:13,height:13,accentColor:c.accentBtn}}/>
<span style={{fontSize:12.5,color:s.done?c.textTer:c.textPri,textDecoration:s.done?"line-through":"none"}}>{s.text}</span>
</div>)}
<div style={{display:"flex",alignItems:"center",gap:6,padding:"3px 0"}}>
<input type="checkbox" disabled style={{width:13,height:13,opacity:0.2}}/>
<input value={newSubText[task.id]||""} onChange={e=>setNewSubText(p=>({...p,[task.id]:e.target.value}))} placeholder="Add subtask…" onKeyDown={e=>{if(e.key==="Enter")addSubtask(block.id,task.id,newSubText[task.id]||"")}} style={{flex:1,border:"none",borderBottom:`1px solid ${c.borderLight}`,outline:"none",fontSize:12,fontFamily:font.sans,color:c.textPri,backgroundColor:"transparent",padding:"2px 0"}}/>
</div>
<div style={{display:"flex",gap:4,marginTop:6}}>
<Btn small ghost onClick={()=>flash("@Elnor…")}><I.Spark size={9} color={c.agentAv}/>@Elnor</Btn>
<Btn small ghost onClick={()=>flash(task.link?`Open "${task.link}"`:"Link note…")}><I.Link size={9}/>{task.link?"Open Note":"Link Note"}</Btn>
</div>
</div>}
</div>)}
<div style={{display:"flex",alignItems:"center",gap:8,padding:"6px 4px"}}>
<input type="checkbox" disabled style={{width:15,height:15,opacity:0.2}}/>
<input value={newTaskText} onChange={e=>setNewTaskText(e.target.value)} placeholder="Add task…" onKeyDown={e=>{if(e.key==="Enter")addTask(block.id,newTaskText)}} style={{flex:1,border:"none",borderBottom:`1px solid ${c.borderLight}`,outline:"none",fontSize:13.5,fontFamily:font.sans,color:c.textPri,backgroundColor:"transparent",padding:"2px 0"}}/>
</div>
{done.length>0&&<details style={{padding:"2px 4px 4px"}}><summary style={{fontSize:10,fontWeight:600,color:c.textTer,cursor:"pointer",padding:"4px 0"}}>Done ({done.length})</summary>
{done.map(t=><div key={t.id} style={{display:"flex",alignItems:"center",gap:8,padding:"3px 4px",opacity:.4}}><input type="checkbox" checked onChange={()=>toggleTask(block.id,t.id)} style={{width:14,height:14,accentColor:c.accentBtn}}/><span style={{fontSize:12.5,textDecoration:"line-through",color:c.textTer}}>{t.text}</span></div>)}
</details>}
</div>
</div>;
}
// FEED
if(block.type==="feed"){
const totalItems=block.sections.reduce((a,s)=>a+s.items.length,0);
if(block.collapsed) return <div key={block.id} style={{margin:"14px 0"}}><div onClick={()=>toggleBlock(block.id)} style={{display:"flex",alignItems:"center",gap:6,padding:"6px 10px",borderRadius:R.sm,border:`1px solid ${c.borderLight}`,backgroundColor:c.bgPanelAlt,cursor:"pointer"}}><DragHandle/><I.ChevR size={10} color={c.textTer}/><I.Spark size={12} color={c.agentAv}/><span style={{fontSize:12,fontWeight:650}}>{block.title}</span><span style={{fontSize:9,color:c.green,fontWeight:600}}>● live</span><span style={{fontSize:9.5,color:c.textTer,backgroundColor:c.bgInput,padding:"1px 6px",borderRadius:3}}>{totalItems}</span><span style={{flex:1}}/><button onClick={e=>{e.stopPropagation();deleteBlock(block.id)}} style={{border:"none",background:"none",cursor:"pointer",padding:1,display:"flex",color:c.textTer}} onMouseEnter={e=>e.currentTarget.style.color=c.error} onMouseLeave={e=>e.currentTarget.style.color=c.textTer}><I.X size={11}/></button></div></div>;
return <div key={block.id} style={{margin:"14px 0",borderRadius:R.sm,border:`1px solid ${c.borderLight}`,overflow:"hidden"}}>
<div onClick={()=>toggleBlock(block.id)} style={{display:"flex",alignItems:"center",gap:6,padding:"7px 10px",backgroundColor:c.bgPanelAlt,cursor:"pointer",borderBottom:`1px solid ${c.borderLight}`}}>
<DragHandle/><I.ChevD size={10} color={c.textTer}/><I.Spark size={12} color={c.agentAv}/>
{editingTitle===block.id?<input autoFocus defaultValue={block.title} onBlur={e=>{setBlocks(p=>p.map(b=>b.id===block.id?{...b,title:e.target.value||block.title}:b));setEditingTitle(null)}} onKeyDown={e=>{if(e.key==="Enter"){setBlocks(p=>p.map(b=>b.id===block.id?{...b,title:e.target.value||block.title}:b));setEditingTitle(null)}if(e.key==="Escape")setEditingTitle(null)}} onClick={e=>e.stopPropagation()} style={{flex:1,fontSize:12.5,fontWeight:700,border:`1px solid ${c.accentBtn}40`,borderRadius:3,padding:"1px 6px",outline:"none",fontFamily:font.sans,backgroundColor:c.bgCard}}/>
:<span style={{fontSize:12.5,fontWeight:700,flex:1,cursor:"text"}} onClick={e=>{e.stopPropagation();setEditingTitle(block.id)}}>{block.title}</span>}
<span style={{fontSize:9,color:c.green,fontWeight:600}}>● auto-updating</span>
<span style={{fontSize:9.5,color:c.textTer,backgroundColor:c.bgInput,padding:"1px 6px",borderRadius:3}}>{totalItems}</span>
<button onClick={e=>{e.stopPropagation();flash("Configure…")}} style={{border:"none",background:"none",cursor:"pointer",padding:1,display:"flex",color:c.textTer}}><I.Settings size={11}/></button>
<button onClick={e=>{e.stopPropagation();deleteBlock(block.id)}} style={{border:"none",background:"none",cursor:"pointer",padding:1,display:"flex",color:c.textTer}} onMouseEnter={e=>e.currentTarget.style.color=c.error} onMouseLeave={e=>e.currentTarget.style.color=c.textTer}><I.X size={11}/></button>
</div>
<div style={{maxHeight:280,overflowY:"auto",padding:"6px 8px"}}>
{block.sections.map(sec=><div key={sec.key} style={{marginBottom:4}}>
<div onClick={()=>toggleFeedSection(sec.key)} style={{display:"flex",alignItems:"center",gap:5,padding:"3px 4px",cursor:"pointer"}}>
<div style={{transform:collapsedFeeds.has(sec.key)?"none":"rotate(90deg)",transition:"transform 0.1s"}}><I.ChevR size={8} color={c.textTer}/></div>
{feedIcons[sec.icon]||<I.Spark size={11}/>}<span style={{fontSize:11.5,fontWeight:700,color:c.textSec}}>{sec.label}</span><span style={{fontSize:9,color:c.textTer}}>({sec.items.length})</span>
</div>
{!collapsedFeeds.has(sec.key)&&sec.items.map((item,i)=><div key={i} style={{display:"flex",alignItems:"flex-start",gap:6,padding:"4px 4px 4px 22px"}}>
<span style={{color:c.textTer,fontSize:10,marginTop:2,flexShrink:0}}>▹</span>
{item.accent&&<Dot color={item.accent} size={5}/>}
<span style={{flex:1,fontSize:12.5,color:c.textPri,lineHeight:1.45}}>{item.text}</span>
<span style={{fontSize:9.5,color:c.textTer,flexShrink:0,whiteSpace:"nowrap"}}>{item.time}</span>
</div>)}
</div>)}
</div>
</div>;
}
// THREAD
if(block.type==="thread"){
if(block.collapsed) return <div key={block.id} style={{margin:"14px 0"}}><div onClick={()=>toggleBlock(block.id)} style={{display:"flex",alignItems:"center",gap:6,padding:"6px 10px",borderRadius:R.sm,border:`1px solid ${c.borderLight}`,backgroundColor:c.bgPanelAlt,cursor:"pointer"}}><DragHandle/><I.ChevR size={10} color={c.textTer}/><Av letter="E" color={c.agentAv} size={16}/><span style={{fontSize:11.5,color:c.textPri,flex:1}}><strong style={{color:c.agentAv}}>Elnor</strong> · {block.messages.length} messages</span><span style={{fontSize:9.5,color:c.textTer}}>{block.messages[block.messages.length-1]?.time}</span><button onClick={e=>{e.stopPropagation();deleteBlock(block.id)}} style={{border:"none",background:"none",cursor:"pointer",padding:1,display:"flex",color:c.textTer}} onMouseEnter={e=>e.currentTarget.style.color=c.error} onMouseLeave={e=>e.currentTarget.style.color=c.textTer}><I.X size={11}/></button></div></div>;
return <div key={block.id} style={{margin:"14px 0",borderRadius:R.sm,border:`1px solid ${c.accentBtn}20`,backgroundColor:c.accentBtn+"03",overflow:"hidden"}}>
<div onClick={()=>toggleBlock(block.id)} style={{padding:"5px 12px",display:"flex",alignItems:"center",gap:6,cursor:"pointer",backgroundColor:c.accentBtn+"06",borderBottom:`1px solid ${c.accentBtn}15`}}>
<DragHandle/><I.ChevD size={10} color={c.accentBtn}/><I.MsgCircle size={11} color={c.accentBtn}/>
<span style={{fontSize:10.5,fontWeight:600,color:c.accentBtn,flex:1}}>Thread · {block.messages.length}</span>
{block.contextQuote&&<span style={{fontSize:9,color:c.textTer,fontStyle:"italic"}}>re: "{block.contextQuote}"</span>}
<button onClick={e=>{e.stopPropagation();deleteBlock(block.id)}} style={{border:"none",background:"none",cursor:"pointer",padding:1,display:"flex",color:c.textTer}} onMouseEnter={e=>e.currentTarget.style.color=c.error} onMouseLeave={e=>e.currentTarget.style.color=c.textTer}><I.X size={11}/></button>
</div>
{block.messages.map((msg,i)=><div key={msg.id} style={{padding:"7px 14px",borderBottom:i<block.messages.length-1?`1px solid ${c.borderLight}`:"none",backgroundColor:msg.author==="You"?"transparent":c.agentAv+"06"}}>
<div style={{display:"flex",alignItems:"center",gap:6,marginBottom:3}}><Av letter={msg.author[0]} color={msg.color} size={16}/><span style={{fontSize:11,fontWeight:650,color:msg.color}}>{msg.author}</span><span style={{fontSize:9,color:c.textTer}}>{msg.time}</span>{msg.author==="You"&&<><span style={{fontSize:9,color:c.textTer,cursor:"pointer",marginLeft:"auto"}}>edit</span><span style={{fontSize:9,color:c.error+"80",cursor:"pointer"}}>delete</span></>}</div>
<div style={{fontSize:12.5,lineHeight:1.55,color:c.textPri,paddingLeft:22}}>{msg.body}</div>
</div>)}
{threadReplyId===block.id?<div style={{padding:"7px 14px",borderTop:`1px solid ${c.borderLight}`,backgroundColor:c.bgPanelAlt}}>
<textarea value={threadReplyText} onChange={e=>setThreadReplyText(e.target.value)} placeholder="Reply… @Elnor" autoFocus onKeyDown={e=>{if(e.key==="Enter"&&!e.shiftKey){e.preventDefault();addThreadReply(block.id)}}} style={{width:"100%",padding:"6px 8px",borderRadius:R.sm,border:`1px solid ${c.border}`,fontSize:12,fontFamily:font.sans,outline:"none",minHeight:36,resize:"vertical"}}/>
<div style={{display:"flex",gap:4,marginTop:4}}><Btn small primary onClick={()=>addThreadReply(block.id)} disabled={!threadReplyText.trim()}>Send</Btn><Btn small ghost onClick={()=>{setThreadReplyId(null);setThreadReplyText("")}}>Cancel</Btn></div>
</div>:<div style={{padding:"5px 14px",borderTop:`1px solid ${c.borderLight}`,backgroundColor:c.bgPanelAlt}}><div onClick={()=>{setThreadReplyId(block.id);setThreadReplyText("")}} style={{display:"flex",alignItems:"center",gap:5,padding:"4px 8px",borderRadius:R.sm,border:`1px solid ${c.border}`,backgroundColor:c.bgCard,cursor:"text"}}><I.Plus size={10} color={c.textTer}/><span style={{fontSize:11,color:c.textTer}}>Reply… @Elnor</span></div></div>}
</div>;
}
return null;
};
return (
<div style={{display:"flex",width:"100%",height:"100vh",fontFamily:font.sans,color:c.textPri,backgroundColor:c.bgApp}} onClick={()=>{setOpenDrop(null);if(pickerOpen&&pickerStep==="choose")setPickerOpen(false)}}>
<style>{`*{box-sizing:border-box;margin:0;padding:0}::-webkit-scrollbar{width:4px}::-webkit-scrollbar-track{background:transparent}::-webkit-scrollbar-thumb{background:transparent;border-radius:2px}*:hover::-webkit-scrollbar-thumb{background:#d1d5db}::selection{background:${c.accentBtn}22}details>summary{list-style:none}details>summary::-webkit-details-marker{display:none}`}</style>
{toast&&<Toast msg={toast} onDone={()=>setToast(null)}/>}
{/* SIDEBAR RAIL */}
<div style={{width:44,flexShrink:0,backgroundColor:c.bgSidebar,borderRight:`1px solid ${c.borderDark}`,display:"flex",flexDirection:"column",alignItems:"center",paddingTop:10,gap:6}}>
<div style={{width:26,height:26,borderRadius:R.sm,backgroundColor:c.accentBtn,color:"#fff",display:"flex",alignItems:"center",justifyContent:"center",fontSize:11,fontWeight:700,marginBottom:6}}>Q</div>
<button onClick={()=>setBrowserOpen(!browserOpen)} title="Browser (⌘B)" style={{width:28,height:28,borderRadius:R.sm,border:"none",cursor:"pointer",backgroundColor:browserOpen?"#ffffff18":"transparent",color:browserOpen?"#fff":"#777",display:"flex",alignItems:"center",justifyContent:"center"}}><I.Search size={15}/></button>
<button onClick={()=>setCommentsOpen(!commentsOpen)} title="Comments" style={{width:28,height:28,borderRadius:R.sm,border:"none",cursor:"pointer",backgroundColor:commentsOpen?"#ffffff18":"transparent",color:commentsOpen?"#fff":"#777",display:"flex",alignItems:"center",justifyContent:"center"}}><I.MsgCircle size={15}/></button>
</div>
{/* BROWSER placeholder */}
{browserOpen&&<div style={{width:270,flexShrink:0,backgroundColor:c.bgPanel,borderRight:`1px solid ${c.border}`,display:"flex",flexDirection:"column"}}><div style={{padding:"10px 12px",borderBottom:`1px solid ${c.borderLight}`,display:"flex",alignItems:"center",justifyContent:"space-between"}}><span style={{fontSize:12,fontWeight:650}}>Browser</span><button onClick={()=>setBrowserOpen(false)} style={{border:"none",background:"none",cursor:"pointer",display:"flex",color:c.textTer}}><I.X size={12}/></button></div><div style={{flex:1,display:"flex",alignItems:"center",justifyContent:"center",padding:20}}><div style={{textAlign:"center",fontSize:11,color:c.textTer,fontStyle:"italic",lineHeight:1.6}}>Browser with Notes scope<br/>from V4.5</div></div></div>}
{/* MAIN */}
<div style={{flex:1,display:"flex",flexDirection:"column",overflow:"hidden"}}>
{/* TOOLBAR */}
<div style={{display:"flex",alignItems:"center",gap:3,padding:"4px 10px",borderBottom:`1px solid ${c.border}`,backgroundColor:c.bgPanel,flexWrap:"wrap"}}>
<select style={{padding:"2px 4px",borderRadius:3,border:`1px solid ${c.borderLight}`,fontSize:10.5,fontFamily:font.sans,color:c.textSec,backgroundColor:"transparent",height:24}}><option>Paragraph</option><option>H1</option><option>H2</option></select>
<TBtn icon={<span style={{fontWeight:700,fontSize:12}}>B</span>}/><TBtn icon={<span style={{fontStyle:"italic",fontSize:12}}>I</span>}/><TBtn icon={<span style={{textDecoration:"underline",fontSize:12}}>U</span>}/>
<Sep/><TBtn icon={<I.Undo size={13}/>}/><TBtn icon={<I.Redo size={13}/>}/>
<Sep/><TBtn icon={<I.Copy size={13}/>} title="Copy" onClick={()=>flash("Copied")}/>
<div style={{position:"relative"}}><TBtn icon={<I.Save size={13}/>} label="Save As…" dropdown onClick={e=>{e.stopPropagation();setOpenDrop(openDrop==="save"?null:"save")}}/>
{openDrop==="save"&&<div onClick={e=>e.stopPropagation()} style={{position:"absolute",top:28,left:0,backgroundColor:c.bgCard,border:`1px solid ${c.border}`,borderRadius:R.sm,boxShadow:"0 8px 24px rgba(0,0,0,0.12)",zIndex:999,minWidth:180,padding:4}}>
<DItem onClick={()=>{flash("Export MD");setOpenDrop(null)}}>Export as Markdown</DItem>
<DItem onClick={()=>{flash("Export DOCX");setOpenDrop(null)}}>Export as DOCX</DItem>
<DItem onClick={()=>{flash("Export PDF");setOpenDrop(null)}}>Export as PDF</DItem>
<div style={{borderTop:`1px solid ${c.borderLight}`,margin:"2px 0"}}/>
<DItem onClick={()=>{flash("Save as Prompt");setOpenDrop(null)}}>Save as Prompt</DItem>
</div>}</div>
<TBtn icon={<I.Link size={13}/>} label="Ref" onClick={()=>flash("Ref copied")}/>
<Sep/>
{/* ═══ ADD MODULE BUTTON ═══ */}
<div style={{position:"relative"}}>
<TBtn icon={<I.Grid size={13}/>} label="+Module" dropdown active={pickerOpen} onClick={e=>{e.stopPropagation();setPickerOpen(!pickerOpen);setPickerStep("choose")}}/>
{pickerOpen&&<div onClick={e=>e.stopPropagation()} style={{position:"absolute",top:30,left:0,backgroundColor:c.bgCard,border:`1px solid ${c.border}`,borderRadius:R.sm,boxShadow:"0 8px 28px rgba(0,0,0,0.15)",zIndex:999,width:pickerStep==="choose"?220:380,padding:0,overflow:"hidden"}}>
{/* STEP 1: Choose block type */}
{pickerStep==="choose"&&<div style={{padding:6}}>
<div style={{padding:"6px 10px",fontSize:10,fontWeight:600,color:c.textTer,textTransform:"uppercase",letterSpacing:".05em"}}>Insert Module</div>
<DItem onClick={()=>{insertBlock("tasks");}}><I.List size={14} color={c.warn}/><div><div style={{fontWeight:600}}>Task List</div><div style={{fontSize:9.5,color:c.textTer}}>Checkboxes, subtasks, due dates</div></div></DItem>
<DItem onClick={()=>{setPickerStep("feed_presets");setPickerTab("system")}}><I.Spark size={14} color={c.agentAv}/><div><div style={{fontWeight:600}}>Activity Feed</div><div style={{fontSize:9.5,color:c.textTer}}>Live updates, agent summaries</div></div></DItem>
<DItem onClick={()=>insertBlock("thread")}><I.MsgCircle size={14} color={c.accentBtn}/><div><div style={{fontWeight:600}}>@Elnor Thread</div><div style={{fontSize:9.5,color:c.textTer}}>Inline conversation</div></div></DItem>
<DItem onClick={()=>insertBlock("bar")}><I.Bell size={14} color={c.warn}/><div><div style={{fontWeight:600}}>Notice Bar</div><div style={{fontSize:9.5,color:c.textTer}}>Alert, reminder, status</div></div></DItem>
</div>}
{/* STEP 2: Feed preset picker */}
{pickerStep==="feed_presets"&&<div>
<div style={{display:"flex",alignItems:"center",padding:"8px 10px",borderBottom:`1px solid ${c.borderLight}`,gap:6}}>
<button onClick={()=>setPickerStep("choose")} style={{border:"none",background:"none",cursor:"pointer",display:"flex",color:c.textTer,padding:0}}><I.ChevR size={12} style={{transform:"rotate(180deg)"}}/></button>
<span style={{fontSize:12,fontWeight:650,flex:1}}>Choose Feed Preset</span>
</div>
{/* Tabs */}
<div style={{display:"flex",borderBottom:`1px solid ${c.borderLight}`}}>
{[{id:"system",label:"System"},{id:"agent",label:"Agent"},{id:"custom",label:"My Presets"}].map(tab=>(
<button key={tab.id} onClick={()=>setPickerTab(tab.id)} style={{flex:1,padding:"8px 4px",border:"none",cursor:"pointer",fontFamily:font.sans,fontSize:10.5,fontWeight:pickerTab===tab.id?650:400,color:pickerTab===tab.id?c.accentBtn:c.textTer,backgroundColor:"transparent",borderBottom:pickerTab===tab.id?`2px solid ${c.accentBtn}`:"2px solid transparent",display:"flex",alignItems:"center",justifyContent:"center"}}>{tab.label}</button>
</button>
))}
</div>
{/* Preset cards */}
<div style={{padding:6,maxHeight:260,overflowY:"auto"}}>
{feedPresets.filter(p=>pickerTab==="custom"?p.category==="custom":p.category===pickerTab).map(preset=>(
<div key={preset.id} onClick={()=>insertBlock("feed",preset)} style={{display:"flex",alignItems:"center",gap:10,padding:"8px 10px",borderRadius:R.sm,cursor:"pointer",marginBottom:2}} onMouseEnter={e=>e.currentTarget.style.backgroundColor=c.bgInput} onMouseLeave={e=>e.currentTarget.style.backgroundColor="transparent"}>
<div style={{width:32,height:32,borderRadius:R.sm,backgroundColor:c.accentBtn+"10",display:"flex",alignItems:"center",justifyContent:"center",flexShrink:0}}>
{feedIcons[preset.icon]||<I.Spark size={14}/>}
</div>
<div style={{flex:1,minWidth:0}}>
<div style={{fontSize:12,fontWeight:600,color:c.textPri}}>{preset.name}</div>
<div style={{fontSize:10,color:c.textTer,overflow:"hidden",textOverflow:"ellipsis",whiteSpace:"nowrap"}}>{preset.desc}</div>
</div>
</div>
))}
{pickerTab==="custom"&&<div style={{padding:"12px 10px",textAlign:"center",color:c.textTer,fontSize:11,fontStyle:"italic"}}>No custom presets yet.<br/>Configure a feed and click "Save as Preset"</div>}
</div>
{/* Create custom */}
<div style={{borderTop:`1px solid ${c.borderLight}`,padding:6}}>
<DItem onClick={()=>setPickerStep("feed_custom")}><I.Plus size={12} color={c.accentBtn}/><span style={{color:c.accentBtn,fontWeight:600}}>Create Custom Feed…</span></DItem>
</div>
</div>}
{/* STEP 3: Custom feed configuration */}
{pickerStep==="feed_custom"&&<div>
<div style={{display:"flex",alignItems:"center",padding:"8px 10px",borderBottom:`1px solid ${c.borderLight}`,gap:6}}>
<button onClick={()=>setPickerStep("feed_presets")} style={{border:"none",background:"none",cursor:"pointer",display:"flex",color:c.textTer,padding:0}}><I.ChevR size={12} style={{transform:"rotate(180deg)"}}/></button>
<span style={{fontSize:12,fontWeight:650,flex:1}}>Create Custom Feed</span>
</div>
<div style={{padding:"10px 12px"}}>
<div style={{marginBottom:10}}>
<div style={{fontSize:11,fontWeight:600,color:c.textTer,marginBottom:4}}>Feed name</div>
<input value={customName} onChange={e=>setCustomName(e.target.value)} placeholder="e.g., Henderson Email Watch" style={{width:"100%",padding:"6px 8px",borderRadius:R.sm,border:`1px solid ${c.border}`,fontSize:12,fontFamily:font.sans,outline:"none"}}/>
</div>
<div style={{marginBottom:10}}>
<div style={{fontSize:11,fontWeight:600,color:c.textTer,marginBottom:4}}>Source</div>
<div style={{display:"flex",gap:4}}>
<button style={{flex:1,padding:"8px 6px",borderRadius:R.sm,border:`2px solid ${c.green}40`,backgroundColor:c.green+"08",cursor:"pointer",fontFamily:font.sans,textAlign:"left"}}>
<div style={{fontSize:11,fontWeight:600,color:c.green}}>System Events</div>
<div style={{fontSize:9,color:c.textTer}}>Real-time event subscriptions</div>
</button>
<button style={{flex:1,padding:"8px 6px",borderRadius:R.sm,border:`2px solid ${c.accentBtn}40`,backgroundColor:c.accentBtn+"08",cursor:"pointer",fontFamily:font.sans,textAlign:"left"}}>
<div style={{fontSize:11,fontWeight:600,color:c.accentBtn}}>Agent Task</div>
<div style={{fontSize:9,color:c.textTer}}>Runs on a schedule</div>
</button>
</div>
</div>
<div style={{marginBottom:10}}>
<div style={{fontSize:11,fontWeight:600,color:c.textTer,marginBottom:4}}>Agent</div>
<div style={{display:"flex",alignItems:"center",gap:6,padding:"6px 8px",borderRadius:R.sm,border:`1px solid ${c.border}`,backgroundColor:c.bgCard,cursor:"pointer"}}>
<Av letter="E" color={c.agentAv} size={18}/><span style={{flex:1,fontSize:12,fontWeight:500}}>Elnor</span><I.ChevD size={10} color={c.textTer}/>
</div>
<div style={{fontSize:9,color:c.textTer,marginTop:2}}>Choose which agent runs this feed</div>
</div>
<div style={{marginBottom:10}}>
<div style={{fontSize:11,fontWeight:600,color:c.textTer,marginBottom:4}}>Instruction</div>
<textarea value={customInstruction} onChange={e=>setCustomInstruction(e.target.value)} placeholder="e.g., Monitor Outlook for emails from opposing counsel. Summarize each in one line." style={{width:"100%",padding:"6px 8px",borderRadius:R.sm,border:`1px solid ${c.border}`,fontSize:12,fontFamily:font.sans,outline:"none",minHeight:55,resize:"vertical"}}/>
</div>
<div style={{marginBottom:10}}>
<div style={{fontSize:11,fontWeight:600,color:c.textTer,marginBottom:4}}>Update every</div>
<div style={{display:"flex",gap:4,alignItems:"center"}}>
<input type="number" defaultValue={1} min={1} style={{width:50,padding:"4px 6px",borderRadius:R.sm,border:`1px solid ${c.border}`,fontSize:11,fontFamily:font.sans,outline:"none",textAlign:"center"}}/>
<div style={{display:"flex",gap:2}}>
{["minutes","hours","days"].map((u,i)=><button key={u} style={{padding:"4px 8px",borderRadius:R.sm,border:`1px solid ${i===1?c.accentBtn+"50":c.borderLight}`,backgroundColor:i===1?c.accentBtn+"08":"transparent",fontSize:10,fontFamily:font.sans,color:i===1?c.accentBtn:c.textTer,cursor:"pointer",fontWeight:i===1?600:400}}>{u}</button>)}
</div>
<span style={{fontSize:10,color:c.textTer,margin:"0 4px"}}>or</span>
<button style={{padding:"4px 8px",borderRadius:R.sm,border:`1px solid ${c.borderLight}`,backgroundColor:"transparent",fontSize:10,fontFamily:font.sans,color:c.textTer,cursor:"pointer"}}>manual only</button>
</div>
</div>
<div style={{display:"flex",gap:6,marginTop:12}}>
<Btn primary onClick={()=>{insertBlock("feed",{id:nid(),name:customName||"Custom Feed"});setCustomName("");setCustomInstruction("")}} style={{flex:1,justifyContent:"center"}}>Create Feed</Btn>
<Btn ghost onClick={()=>{setPickerStep("feed_presets")}}>Cancel</Btn>
</div>
</div>
</div>}
</div>}
</div>
<Sep/>
<TBtn icon={<I.Search size={13}/>} active={findBar} onClick={()=>setFindBar(!findBar)}/>
<TBtn icon={<I.Maximize size={13}/>} active={fullScreen} onClick={()=>setFullScreen(!fullScreen)}/>
<Sep/><TBtn icon={<I.MsgCircle size={13}/>} label="2" active={commentsOpen&&rightTab==="comments"} onClick={()=>{if(commentsOpen&&rightTab==="comments")setCommentsOpen(false);else{setCommentsOpen(true);setRightTab("comments")}}}/>
<Sep/><TBtn icon={<I.Eye size={13}/>} label={showMarkup?"Markup":"Clean"} active={showMarkup} onClick={()=>setShowMarkup(!showMarkup)}/>
<TBtn icon={<I.Edit size={13}/>} label="0 ▾"/>
<div style={{flex:1}}/><span style={{fontSize:10,color:c.green,fontWeight:500}}>Saved just now</span>
<Sep/><button onClick={()=>{if(commentsOpen&&rightTab==="send")setCommentsOpen(false);else{setCommentsOpen(true);setRightTab("send")}}} style={{padding:"3px 10px",borderRadius:R.sm,border:`1px solid ${c.accentBtn}40`,backgroundColor:(commentsOpen&&rightTab==="send")?c.accentBtn:c.accentBtn+"08",cursor:"pointer",display:"flex",alignItems:"center",gap:4,color:(commentsOpen&&rightTab==="send")?"#fff":c.accentBtn,fontFamily:font.sans,fontSize:10.5,fontWeight:600,height:26}}><I.Spark size={12}/>Send to Agent</button>
</div>
{findBar&&<div style={{display:"flex",alignItems:"center",gap:6,padding:"5px 12px",borderBottom:`1px solid ${c.borderLight}`,backgroundColor:c.bgPanelAlt}}><I.Search size={12} color={c.textTer}/><input placeholder="Find…" autoFocus style={{flex:1,border:"none",backgroundColor:"transparent",fontSize:12,fontFamily:font.sans,outline:"none",maxWidth:250}}/><span style={{fontSize:10,color:c.textTer}}>0/0</span><button onClick={()=>setFindBar(false)} style={{padding:2,border:"none",cursor:"pointer",backgroundColor:"transparent",display:"flex",color:c.textTer}}><I.X size={12}/></button></div>}
{/* CONTENT */}
<div style={{flex:1,display:"flex",overflow:"hidden"}}>
<div style={{flex:1,display:"flex",flexDirection:"column",overflow:"hidden",minWidth:0}}>
<div ref={editorRef} style={{flex:1,overflowY:"auto",padding:"16px 32px 60px",userSelect:"text"}}>
{/* Title */}
<div style={{display:"flex",alignItems:"center",gap:8,marginBottom:3}}>
<I.Sun size={20} color={c.warn}/>
<div style={{fontSize:22,fontWeight:700}} contentEditable suppressContentEditableWarning>Today — Wednesday, March 19</div>
</div>
<div style={{fontSize:10.5,color:c.textTer,marginBottom:8,display:"flex",alignItems:"center",gap:4}}>
Pinned · Auto-updating · Configurable modules
<button onClick={()=>flash("Configure workspace template…")} style={{border:`1px solid ${c.borderLight}`,borderRadius:3,backgroundColor:"transparent",cursor:"pointer",padding:"1px 6px",fontSize:9,color:c.textTer,fontFamily:font.sans,display:"flex",alignItems:"center",gap:2,marginLeft:4}}><I.Settings size={9}/>Configure</button>
</div>
{/* Blocks with natural spacing */}
{blocks.map(block=>renderBlock(block))}
{/* Slash command hint */}
<div style={{marginTop:30,padding:"8px 12px",borderRadius:R.sm,border:`1px dashed ${c.borderLight}`,backgroundColor:c.bgPanelAlt,display:"flex",alignItems:"center",gap:8}}>
<I.Grid size={12} color={c.accentBtn}/>
<span style={{fontSize:11,color:c.textTer}}>Use <strong style={{color:c.accentBtn}}>+Module</strong> in toolbar · Type <strong style={{color:c.accentBtn}}>/todo</strong> <strong style={{color:c.accentBtn}}>/feed</strong> <strong style={{color:c.accentBtn}}>/ask</strong> anywhere · Type <strong style={{color:c.accentBtn}}>@Elnor</strong> on any line</span>
</div>
</div>
</div>
{/* COMMENTS placeholder */}
{commentsOpen&&!fullScreen&&<div style={{width:rightTab==="send"?290:260,flexShrink:0,borderLeft:`1px solid ${c.border}`,display:"flex",flexDirection:"column",backgroundColor:c.bgPanelAlt}}>
<div style={{display:"flex",borderBottom:`1px solid ${c.borderLight}`,flexShrink:0}}>
<button onClick={()=>setRightTab("comments")} style={{flex:1,padding:"7px 0",border:"none",cursor:"pointer",backgroundColor:rightTab==="comments"?c.bgPanelAlt:c.bgInput,color:rightTab==="comments"?c.accentBtn:c.textTer,fontSize:10.5,fontWeight:rightTab==="comments"?650:450,fontFamily:font.sans,borderBottom:rightTab==="comments"?`2px solid ${c.accentBtn}`:"2px solid transparent",display:"flex",alignItems:"center",justifyContent:"center",gap:3}}><I.MsgCircle size={10}/>Comments</button>
<button onClick={()=>setRightTab("send")} style={{flex:1,padding:"7px 0",border:"none",cursor:"pointer",backgroundColor:rightTab==="send"?c.bgPanel:c.bgInput,color:rightTab==="send"?c.accentBtn:c.textTer,fontSize:10.5,fontWeight:rightTab==="send"?650:450,fontFamily:font.sans,borderBottom:rightTab==="send"?`2px solid ${c.accentBtn}`:"2px solid transparent",display:"flex",alignItems:"center",justifyContent:"center",gap:3}}><I.Spark size={10}/>Send to Agent</button>
<button onClick={()=>setCommentsOpen(false)} style={{width:26,border:"none",cursor:"pointer",backgroundColor:"transparent",display:"flex",alignItems:"center",justifyContent:"center",color:c.textTer}}><I.X size={11}/></button>
</div>
<div style={{flex:1,display:"flex",alignItems:"center",justifyContent:"center",padding:16}}><div style={{textAlign:"center",fontSize:11,color:c.textTer,fontStyle:"italic",lineHeight:1.6}}>Comments + Send to Agent<br/>from Q_NOTES_FULL.jsx</div></div>
</div>}
</div>
</div>
{/* CHAT INDICATOR */}
<div style={{width:40,borderLeft:`1px solid ${c.border}`,backgroundColor:c.bgPanel,display:"flex",flexDirection:"column",alignItems:"center",paddingTop:12,gap:8,flexShrink:0}}>
<div style={{writingMode:"vertical-rl",fontSize:10,fontWeight:600,color:c.accentBtn,letterSpacing:".05em",cursor:"pointer",padding:"8px 4px"}}>CHAT →</div>
<Dot color={c.green} size={6}/><div style={{fontSize:8,color:c.textTer,writingMode:"vertical-rl"}}>Henderson</div>
</div>
</div>
);
}