Q_NOTES_FULL.jsx
Design Mockups/DOC20 Mockups/Q_NOTES_FULL.jsx
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",textPri:"#1A1D21",textSec:"#5E6570",textTer:"#8B919A",accentBtn:"#31588c",warn:"#D97706",error:"#B04040",border:"#E0E2E5",borderLight:"#ECEEF0",green:"#2E8B57",agentAv:"#a1a7aa"};
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"/>,Pin:p=><Ic {...p} d="M12 17v5 M9 2l.5 5L7 10l1.5 3h7L17 10l-2.5-3L15 2"/>,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"/>,Trash:p=><Ic {...p} d="M3 6h18 M19 6v14a2 2 0 01-2 2H7a2 2 0 01-2-2V6m3 0V4a2 2 0 012-2h4a2 2 0 012 2v2"/>,Archive:p=><Ic {...p} d="M21 8v13H3V8 M1 3h22v5H1z M10 12h4"/>,};
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 Radio=({selected,label,desc,onClick})=><button onClick={onClick} style={{display:"flex",alignItems:"center",gap:6,width:"100%",padding:"6px 10px",borderRadius:R.sm,border:`1px solid ${selected?c.accentBtn+"50":c.border}`,backgroundColor:selected?c.accentBtn+"06":"transparent",marginBottom:4,cursor:"pointer",textAlign:"left",fontFamily:font.sans}}><span style={{width:12,height:12,borderRadius:"50%",border:`2px solid ${selected?c.accentBtn:c.border}`,backgroundColor:selected?c.accentBtn:"transparent",display:"flex",alignItems:"center",justifyContent:"center",flexShrink:0}}>{selected&&<span style={{width:4,height:4,borderRadius:"50%",backgroundColor:"#fff"}}/>}</span><div style={{flex:1}}><div style={{fontSize:11,fontWeight:selected?600:450,color:selected?c.accentBtn:c.textPri}}>{label}</div>{desc&&<div style={{fontSize:9,color:c.textTer,marginTop:1}}>{desc}</div>}</div></button>;
const tcColors={You:{del:c.accentBtn,ins:c.accentBtn},Elnor:{del:"#B04040",ins:"#2E8B57"},Scout:{del:"#8B5E00",ins:"#2563EB"}};
const agents=[{name:"Elnor",color:c.agentAv,letter:"E"},{name:"Scout",color:"#5B5F97",letter:"S"}];
const chats=[{name:"Henderson discovery",color:c.accentBtn,origin:true},{name:"Quark patent search",color:c.green},{name:"New chat",color:c.textTer}];
const initFolders=[{id:"nf1",title:"Henderson Case",parent:null},{id:"nf2",title:"Privilege Issues",parent:"nf1"},{id:"nf3",title:"Motion Practice",parent:"nf1"},{id:"nf4",title:"Quark Patents",parent:null},{id:"nf5",title:"Expert Depositions",parent:"nf3"},{id:"nf6",title:"Summary Judgment",parent:"nf3"}];
const initNotes=[
{id:"n1",title:"Henderson Discovery Priorities",folder:"nf2",mod:"2h",comments:3,pinned:true,pending:true,proj:"Henderson",projColor:"#31588c",status:"active"},
{id:"n2",title:"Weekly Task List",folder:null,mod:"4h",comments:0,pinned:true,proj:"Henderson",projColor:"#31588c",status:"active"},
{id:"n3",title:"Judge Chen Conference Notes",folder:"nf3",mod:"3d",comments:2,proj:"Henderson",projColor:"#31588c",status:"active"},
{id:"n4",title:"Privilege Review Checklist",folder:"nf2",mod:"1d",comments:0,proj:"Henderson",projColor:"#31588c",status:"active"},
{id:"n5",title:"Quark Patent Analysis",folder:"nf4",mod:"1d",comments:1,proj:"Quark",projColor:"#2E8B57",status:"active"},
{id:"n6",title:"AI in Legal Discovery",folder:null,mod:"5d",comments:0,status:"active"},
{id:"n7",title:"Old Case Research",folder:null,mod:"2w",comments:0,status:"archived"},
{id:"n8",title:"Expert Depo Prep — Dr. Smith",folder:"nf5",mod:"1w",comments:0,proj:"Henderson",projColor:"#31588c",status:"active"},
];
const segs=[{id:"s1",t:"p",v:"Key documents to review from discovery batch #4."},{id:"s2",t:"h2",v:"Priority Items"},{id:"s3",t:"li",v:"Email chain: Henderson → Outside Counsel (March 12-15) — 23 messages, 8 flagged"},{id:"s4",t:"li",v:"Privileged strategy memo (March 18) discussing litigation posture and settlement authority"},{id:"s5",t:"li",v:"Board minutes from Q1 2024 executive session"},{id:"s6",t:"h2",v:"Timeline Conflicts"},{id:"s7",t:"p",v:"Deposition transcript (Feb 12): initial contact January 5, but metadata suggests January 8."},{id:"s8",t:"p",v:"Cross-reference calendar, email timestamps, phone records Jan 5-8."},{id:"s9",t:"h2",v:"Next Steps"},{id:"s10",t:"p",v:"Prepare updated privilege log with all newly identified documents."}];
const initChanges=[{id:"tc1",segId:"s4",author:"Elnor",oldText:"discussing litigation posture and settlement authority",newText:"discussing litigation posture, settlement authority, and insurance coverage implications",status:"pending"},{id:"tc2",segId:"s7",author:"Elnor",oldText:"initial contact January 5, but metadata suggests January 8",newText:"initial contact January 5, but metadata and email headers suggest January 8",status:"pending"},{id:"tc3",segId:"s10",author:"You",oldText:"Prepare updated privilege log with all newly identified documents.",newText:"Prepare updated privilege log with all newly identified documents. Include Bates-stamp cross-references.",status:"pending"}];
const initComments=[{id:"c1",author:"You",color:c.accentBtn,body:"Follow up on March 2024 emails — may be privileged.",time:"2h ago",status:"open",segId:"s3",anchor:"Email chain: Henderson",replies:[{id:"r1",author:"Elnor",color:c.agentAv,body:"Flagged 8. Add to privilege log?",time:"1h ago"}]},{id:"c2",author:"Elnor",color:c.agentAv,body:"Timeline conflict vs deposition. Cross-check.",time:"4h ago",status:"open",segId:"s7",anchor:"Deposition transcript (Feb 12)",replies:[]},{id:"c3",author:"Scout",color:"#5B5F97",body:"Judge Chen 5-day rule applies retroactively.",time:"1d ago",status:"resolved",segId:"s9",anchor:"Next Steps",replies:[]}];
const noteSortOpts=["Modified","Alphabetical","Created"];
const timeVal=t=>{if(!t)return 99999;if(t.includes("m"))return parseInt(t);if(t.includes("h"))return parseInt(t)*60;if(t.includes("d"))return parseInt(t)*1440;if(t.includes("w"))return parseInt(t)*10080;return 99999};
export default function NotesV5(){
const idC=useRef(300);const nid=()=>"x"+(++idC.current);
const [notes,setNotes]=useState(initNotes);
const [comments,setComments]=useState(initComments);const [changes,setChanges]=useState(initChanges);
const [activeComment,setActiveComment]=useState(null);const [bubbleMenu,setBubbleMenu]=useState(null);
const [noteListOpen,setNoteListOpen]=useState(true);const [folderView,setFolderView]=useState(true);
const [selectedNote,setSelectedNote]=useState("n1");const [noteFolders,setNoteFolders]=useState(initFolders);
const [expandedFolders,setExpandedFolders]=useState(new Set(["nf1","nf3"]));
const [rightOpen,setRightOpen]=useState(true);const [rightTab,setRightTab]=useState("comments");
const [showMarkup,setShowMarkup]=useState(true);const [findBar,setFindBar]=useState(false);
const [fullScreen,setFullScreen]=useState(false);const [toast,setToast]=useState(null);const [openDrop,setOpenDrop]=useState(null);
const [newFolderMode,setNewFolderMode]=useState(null);const [newFolderName,setNewFolderName]=useState("");const [hoverFolder,setHoverFolder]=useState(null);
// Note list controls
const [noteSearch,setNoteSearch]=useState("");const [noteSort,setNoteSort]=useState("Modified");const [noteSortDrop,setNoteSortDrop]=useState(false);
const [showArchived,setShowArchived]=useState(false);
const [contextMenu,setContextMenu]=useState(null); // {x,y,noteId}
const [deletingNote,setDeletingNote]=useState(null);
// Comment editing
const [replyingTo,setReplyingTo]=useState(null);const [replyText,setReplyText]=useState("");
const [editingId,setEditingId]=useState(null);const [editText,setEditText]=useState("");const [deletingId,setDeletingId]=useState(null);
const [newCm,setNewCm]=useState(null);const [newCmText,setNewCmText]=useState("");
// Send drawer
const [agentIdx,setAgentIdx]=useState(0);const [agentDrop,setAgentDrop]=useState(false);
const [chatIdx,setChatIdx]=useState(0);const [chatDrop,setChatDrop]=useState(false);
const [sendScope,setSendScope]=useState("full");const [selectedCmIds,setSelectedCmIds]=useState(new Set());
const [outputMode,setOutputMode]=useState("respond_in_chat");const [subMode,setSubMode]=useState("tracked_changes");
const [instruction,setInstruction]=useState("");
const editorRef=useRef(null);const cmRef=useRef(null);const nfRef=useRef(null);
const agent=agents[agentIdx];const openC=comments.filter(x=>x.status==="open");const resolvedC=comments.filter(x=>x.status==="resolved");
const pendingChanges=changes.filter(x=>x.status==="pending");const flash=msg=>setToast(msg);
// Filtered & sorted notes
const activeNotes=notes.filter(n=>n.status==="active");
const archivedNotes=notes.filter(n=>n.status==="archived");
const filteredNotes=(noteSearch?activeNotes.filter(n=>n.title.toLowerCase().includes(noteSearch.toLowerCase())):activeNotes).sort((a,b)=>{
if(a.pinned&&!b.pinned)return -1;if(!a.pinned&&b.pinned)return 1;
if(noteSort==="Alphabetical")return a.title.localeCompare(b.title);
return timeVal(a.mod)-timeVal(b.mod);
});
const archiveNote=id=>{setNotes(p=>p.map(n=>n.id===id?{...n,status:"archived"}:n));setContextMenu(null);flash("Archived")};
const unarchiveNote=id=>{setNotes(p=>p.map(n=>n.id===id?{...n,status:"active"}:n));flash("Restored")};
const deleteNote=id=>{setNotes(p=>p.filter(n=>n.id!==id));setDeletingNote(null);setContextMenu(null);flash("Permanently deleted")};
const handleMouseUp=useCallback(e=>{if(e.target.closest("[data-bubble]"))return;const sel=window.getSelection();if(!sel||sel.isCollapsed||!sel.toString().trim()){setBubbleMenu(null);return}const text=sel.toString().trim();if(text.length<3)return;const rect=sel.getRangeAt(0).getBoundingClientRect();const er=editorRef.current?.getBoundingClientRect();if(!er)return;setBubbleMenu({x:rect.left-er.left+rect.width/2,y:rect.top-er.top-8,text})},[]);
const dismissBubble=()=>{setBubbleMenu(null);window.getSelection()?.removeAllRanges()};
const startComment=()=>{if(!bubbleMenu)return;setNewCm({text:bubbleMenu.text});setBubbleMenu(null);setRightOpen(true);setRightTab("comments");setTimeout(()=>cmRef.current?.focus(),100)};
const addComment=()=>{if(!newCmText.trim())return;const cm={id:nid(),author:"You",color:c.accentBtn,body:newCmText.trim(),time:"just now",status:"open",segId:null,anchor:newCm?.text||null,replies:[]};setComments(p=>[...p,cm]);setNewCm(null);setNewCmText("");setActiveComment(cm.id)};
const addReply=cmId=>{if(!replyText.trim())return;setComments(p=>p.map(cm=>cm.id===cmId?{...cm,replies:[...cm.replies,{id:nid(),author:"You",color:c.accentBtn,body:replyText.trim(),time:"just now"}]}:cm));setReplyingTo(null);setReplyText("")};
const saveEdit=id=>{if(!editText.trim())return;setComments(p=>p.map(cm=>cm.id===id?{...cm,body:editText.trim()}:cm));setEditingId(null)};
const doDelete=id=>{setComments(p=>p.filter(cm=>cm.id!==id));setDeletingId(null)};
const resolveComment=id=>{setComments(p=>p.map(cm=>cm.id===id?{...cm,status:"resolved"}:cm));if(activeComment===id)setActiveComment(null)};
const reopenComment=id=>setComments(p=>p.map(cm=>cm.id===id?{...cm,status:"open"}:cm));
const acceptChange=id=>setChanges(p=>p.map(x=>x.id===id?{...x,status:"accepted"}:x));
const rejectChange=id=>setChanges(p=>p.map(x=>x.id===id?{...x,status:"rejected"}:x));
const acceptAll=()=>{setChanges(p=>p.map(x=>x.status==="pending"?{...x,status:"accepted"}:x));flash("All accepted")};
const rejectAll=()=>{setChanges(p=>p.map(x=>x.status==="pending"?{...x,status:"rejected"}:x));flash("All rejected")};
const toggleCmSelect=id=>{const s=new Set(selectedCmIds);s.has(id)?s.delete(id):s.add(id);setSelectedCmIds(s)};
const createFolder=parent=>{if(!newFolderName.trim())return;setNoteFolders(p=>[...p,{id:"nf"+(p.length+10),title:newFolderName.trim(),parent}]);if(parent){const s=new Set(expandedFolders);s.add(parent);setExpandedFolders(s)}setNewFolderMode(null);setNewFolderName("");flash("Folder created")};
const handleSend=()=>{if(outputMode==="respond_in_chat"){flash(`Opening "${chats[chatIdx].name}" (ref:note:n1)…`)}else{if(!instruction.trim())return;flash(`${agent.name}: ${subMode} (ref:note:n1)…`)}};
const renderText=seg=>{const tc=changes.find(x=>x.segId===seg.id&&x.status==="pending");const tca=changes.find(x=>x.segId===seg.id&&x.status==="accepted");if(tca)return <span>{seg.v.replace(tca.oldText,tca.newText)}</span>;if(!tc||!showMarkup){if(tc&&!showMarkup)return <span>{seg.v.replace(tc.oldText,tc.newText)}</span>;return <span>{seg.v}</span>}const idx=seg.v.indexOf(tc.oldText);if(idx===-1)return <span>{seg.v}</span>;const ac=tcColors[tc.author]||tcColors.Elnor;return <span>{seg.v.slice(0,idx)}<span style={{color:ac.del,textDecoration:"line-through",opacity:.7}}>{tc.oldText}</span><span style={{color:ac.ins,textDecoration:"underline",fontWeight:500}}>{tc.newText}</span>{" "}<span style={{display:"inline-flex",gap:2,verticalAlign:"middle"}}><button onClick={()=>acceptChange(tc.id)} style={{width:15,height:15,borderRadius:3,border:`1px solid ${ac.ins}40`,backgroundColor:ac.ins+"10",cursor:"pointer",display:"inline-flex",alignItems:"center",justifyContent:"center",padding:0}}><I.Check size={9} color={ac.ins}/></button><button onClick={()=>rejectChange(tc.id)} style={{width:15,height:15,borderRadius:3,border:`1px solid ${ac.del}30`,backgroundColor:ac.del+"08",cursor:"pointer",display:"inline-flex",alignItems:"center",justifyContent:"center",padding:0}}><I.X size={9} color={ac.del}/></button><span style={{fontSize:8.5,color:ac.ins,fontStyle:"italic",fontWeight:600}}>{tc.author}</span></span>{seg.v.slice(idx+tc.oldText.length)}</span>};
const renderSeg=seg=>{const hasCm=openC.some(cm=>cm.segId===seg.id);const isAct=activeComment&&comments.find(cm=>cm.id===activeComment)?.segId===seg.id;const hl=isAct?{backgroundColor:c.accentBtn+"18",borderRadius:3,padding:"2px 4px",margin:"-2px -4px",boxShadow:`inset 0 0 0 1.5px ${c.accentBtn}40`}:hasCm?{backgroundColor:c.accentBtn+"08",borderRadius:3,padding:"1px 3px",margin:"-1px -3px"}:{};const cnt=openC.filter(cm=>cm.segId===seg.id).length;if(seg.t==="h2")return <h2 key={seg.id} style={{fontSize:16,fontWeight:700,color:c.textPri,margin:"18px 0 8px",paddingBottom:5,borderBottom:`1px solid ${c.borderLight}`}}><span style={hl}>{seg.v}</span></h2>;if(seg.t==="li")return <li key={seg.id} style={{marginBottom:5}}><span style={hl}>{renderText(seg)}</span>{cnt>0&&<span style={{fontSize:9,color:c.accentBtn,marginLeft:4,cursor:"pointer"}} onClick={()=>{const cm=openC.find(x=>x.segId===seg.id);if(cm)setActiveComment(cm.id)}}>💬{cnt}</span>}</li>;return <p key={seg.id} style={{marginBottom:12}}><span style={hl}>{renderText(seg)}</span>{cnt>0&&<span style={{fontSize:9,color:c.accentBtn,marginLeft:4,cursor:"pointer"}} onClick={()=>{const cm=openC.find(x=>x.segId===seg.id);if(cm)setActiveComment(cm.id)}}>💬{cnt}</span>}</p>};
const CmCard=({cm,resolved})=>{const isAct=activeComment===cm.id;return <div style={{margin:"0 8px 8px",borderRadius:R.sm,border:`1px solid ${isAct?cm.color+"60":c.borderLight}`,backgroundColor:isAct?cm.color+"06":c.bgCard,overflow:"hidden",cursor:"pointer",opacity:resolved?.6:1}} onClick={()=>setActiveComment(isAct?null:cm.id)}>
<div style={{borderLeft:`3px solid ${cm.color}${resolved?"30":"40"}`,padding:"9px 11px"}}>
{cm.anchor&&<div style={{fontSize:10.5,color:c.accentBtn,backgroundColor:c.accentBtn+"08",padding:"3px 6px",borderRadius:3,marginBottom:6,fontStyle:"italic",overflow:"hidden",textOverflow:"ellipsis",whiteSpace:"nowrap"}}>"{cm.anchor.slice(0,55)}"</div>}
<div style={{display:"flex",alignItems:"center",gap:5,marginBottom:5}}><Av letter={cm.author[0]} color={cm.color} size={16}/><span style={{fontSize:11.5,fontWeight:650,color:cm.color}}>{cm.author}</span><span style={{fontSize:9.5,color:c.textTer}}>{cm.time}</span></div>
{editingId===cm.id?<div onClick={e=>e.stopPropagation()}><textarea value={editText} onChange={e=>setEditText(e.target.value)} autoFocus style={{width:"100%",padding:"5px 7px",borderRadius:R.sm,border:`1px solid ${c.accentBtn}40`,fontSize:12,fontFamily:font.sans,outline:"none",minHeight:40,resize:"vertical"}}/><div style={{display:"flex",gap:4,marginTop:4}}><Btn small primary onClick={()=>saveEdit(cm.id)}>Save</Btn><Btn small ghost onClick={()=>setEditingId(null)}>Cancel</Btn></div></div>
:<div style={{fontSize:12,lineHeight:1.5,color:c.textSec,marginBottom:5}}>{cm.body}</div>}
{editingId!==cm.id&&<div style={{display:"flex",alignItems:"center",gap:6,fontSize:10.5}} onClick={e=>e.stopPropagation()}>
{!resolved&&<span style={{color:c.textTer,cursor:"pointer",fontWeight:500}} onClick={()=>{setReplyingTo(replyingTo===cm.id?null:cm.id);setReplyText("")}}>Reply</span>}
{!resolved&&<span style={{color:c.textTer,cursor:"pointer",fontWeight:500}} onClick={()=>resolveComment(cm.id)}>Resolve</span>}
{resolved&&<span style={{color:c.accentBtn,cursor:"pointer",fontWeight:500}} onClick={()=>reopenComment(cm.id)}>Reopen</span>}
{cm.author==="You"&&<span style={{color:c.textTer,cursor:"pointer",fontWeight:500}} onClick={()=>{setEditingId(cm.id);setEditText(cm.body)}}>Edit</span>}
{cm.author==="You"&&deletingId!==cm.id&&<span style={{color:c.error,cursor:"pointer",fontWeight:500,opacity:.7}} onClick={()=>setDeletingId(cm.id)}>Delete</span>}
{deletingId===cm.id&&<><span style={{color:c.error,fontWeight:600,fontSize:10}}>Delete?</span><span style={{color:c.error,cursor:"pointer",fontWeight:700,textDecoration:"underline"}} onClick={()=>doDelete(cm.id)}>Yes</span><span style={{color:c.textTer,cursor:"pointer"}} onClick={()=>setDeletingId(null)}>No</span></>}
<span style={{flex:1}}/><span onClick={()=>flash(`Sent to ${agent.name}`)} style={{cursor:"pointer",display:"flex",alignItems:"center",gap:2,color:c.textSec,fontWeight:600,fontSize:10}} onMouseEnter={e=>e.currentTarget.style.color=c.accentBtn} onMouseLeave={e=>e.currentTarget.style.color=c.textSec}><I.Spark size={11}/>Send</span>
</div>}
</div>
{cm.replies.map(r=><div key={r.id} style={{borderLeft:`3px solid ${r.color}40`,borderTop:`1px solid ${c.borderLight}`,padding:"7px 11px",backgroundColor:c.bgPanelAlt}}><div style={{display:"flex",alignItems:"center",gap:5,marginBottom:4}}><Av letter={r.author[0]} color={r.color} size={14}/><span style={{fontSize:10.5,fontWeight:650,color:r.color}}>{r.author}</span><span style={{fontSize:9,color:c.textTer}}>{r.time}</span></div><div style={{fontSize:11.5,lineHeight:1.5,color:c.textSec}}>{r.body}</div></div>)}
{replyingTo===cm.id&&<div style={{borderTop:`1px solid ${c.borderLight}`,padding:"8px 11px",backgroundColor:c.bgPanelAlt}} onClick={e=>e.stopPropagation()}><textarea value={replyText} onChange={e=>setReplyText(e.target.value)} placeholder="Reply… (Enter)" autoFocus onKeyDown={e=>{if(e.key==="Enter"&&!e.shiftKey){e.preventDefault();addReply(cm.id)}}} style={{width:"100%",padding:"5px 7px",borderRadius:R.sm,border:`1px solid ${c.border}`,fontSize:11.5,fontFamily:font.sans,outline:"none",minHeight:36,resize:"vertical"}}/><div style={{display:"flex",gap:4,marginTop:4}}><Btn small primary onClick={()=>addReply(cm.id)} disabled={!replyText.trim()}>Reply</Btn><Btn small ghost onClick={()=>setReplyingTo(null)}>Cancel</Btn></div></div>}
</div>};
// Note row — with right-click context menu
const NoteRow=({n,depth=0})=><div onContextMenu={e=>{e.preventDefault();setContextMenu({x:e.clientX,y:e.clientY,noteId:n.id})}} onClick={()=>setSelectedNote(n.id)} style={{padding:`7px 10px 7px ${14+depth*14}px`,borderBottom:`1px solid ${c.borderLight}`,cursor:"pointer",backgroundColor:selectedNote===n.id?c.accentBtn+"06":"transparent",borderLeft:selectedNote===n.id?`2px solid ${c.accentBtn}`:"2px solid transparent"}}>
<div style={{display:"flex",alignItems:"center",gap:3,marginBottom:2}}>{n.pinned&&<I.Pin size={8} color={c.warn}/>}<span style={{fontSize:12,fontWeight:550,flex:1,overflow:"hidden",textOverflow:"ellipsis",whiteSpace:"nowrap"}}>{n.title}</span>{n.pending&&<Dot color={c.green} size={5}/>}</div>
<div style={{fontSize:9.5,color:c.textTer}}>{n.mod}{n.comments>0&&` · 💬${n.comments}`}{n.proj&&<> · <Dot color={n.projColor} size={4}/></>}</div>
</div>;
// Folder tree — supports any depth, with + icon on all folders
const renderFolders=(parentId,depth)=>noteFolders.filter(f=>f.parent===parentId).map(folder=>{
const isExp=expandedFolders.has(folder.id);const children=noteFolders.filter(ch=>ch.parent===folder.id);
const folderNotes=filteredNotes.filter(n=>n.folder===folder.id);const isHover=hoverFolder===folder.id;
return <div key={folder.id}>
<div onMouseEnter={()=>setHoverFolder(folder.id)} onMouseLeave={()=>setHoverFolder(null)} onClick={()=>{const s=new Set(expandedFolders);s.has(folder.id)?s.delete(folder.id):s.add(folder.id);setExpandedFolders(s)}} style={{display:"flex",alignItems:"center",gap:4,padding:`4px 8px 4px ${8+depth*14}px`,cursor:"pointer",backgroundColor:c.bgPanelAlt,borderBottom:`1px solid ${c.borderLight}`}}>
{isExp?<I.ChevD size={10} color={c.textTer}/>:<I.ChevR size={10} color={c.textTer}/>}
<I.Folder size={11} color={depth===0?c.warn:c.textTer}/><span style={{fontSize:11.5,fontWeight:600,flex:1,overflow:"hidden",textOverflow:"ellipsis",whiteSpace:"nowrap"}}>{folder.title}</span>
{isHover&&<span onClick={e=>{e.stopPropagation();setNewFolderMode({parent:folder.id});setNewFolderName("");setTimeout(()=>nfRef.current?.focus(),50)}} style={{cursor:"pointer",display:"flex",color:c.textTer}} title="Add subfolder"><I.Plus size={10}/></span>}
</div>
{isExp&&<>
{newFolderMode&&newFolderMode.parent===folder.id&&<div style={{display:"flex",alignItems:"center",gap:4,padding:`3px 8px 3px ${22+depth*14}px`,borderBottom:`1px solid ${c.borderLight}`}}><I.Folder size={10} color={c.textTer}/><input ref={nfRef} value={newFolderName} onChange={e=>setNewFolderName(e.target.value)} placeholder="Subfolder…" onKeyDown={e=>{if(e.key==="Enter")createFolder(folder.id);if(e.key==="Escape"){setNewFolderMode(null);setNewFolderName("")}}} style={{flex:1,border:`1px solid ${c.accentBtn}40`,borderRadius:3,padding:"2px 6px",fontSize:11,fontFamily:font.sans,outline:"none",backgroundColor:c.bgCard}}/></div>}
{folderNotes.map(n=><NoteRow key={n.id} n={n} depth={depth+1}/>)}
{renderFolders(folder.id,depth+1)}
</>}
</div>;
});
const showNL=noteListOpen&&!fullScreen;const showRP=rightOpen&&!fullScreen;
return (
<div style={{display:"flex",width:"100%",height:"100vh",fontFamily:font.sans,color:c.textPri,backgroundColor:c.bgApp}} onClick={()=>{setOpenDrop(null);setAgentDrop(false);setChatDrop(false);setContextMenu(null);setNoteSortDrop(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}`}</style>
{toast&&<Toast msg={toast} onDone={()=>setToast(null)}/>}
{/* Context menu */}
{contextMenu&&<div onClick={e=>e.stopPropagation()} style={{position:"fixed",left:contextMenu.x,top:contextMenu.y,backgroundColor:c.bgCard,border:`1px solid ${c.border}`,borderRadius:R.sm,boxShadow:"0 4px 16px rgba(0,0,0,0.15)",zIndex:9999,minWidth:140,padding:4}}>
<DItem onClick={()=>{archiveNote(contextMenu.noteId)}}><I.Archive size={12} color={c.textTer}/>Archive</DItem>
{deletingNote===contextMenu.noteId?<div style={{display:"flex",alignItems:"center",gap:4,padding:"6px 10px"}}>
<span style={{fontSize:11,color:c.error,fontWeight:600}}>Delete permanently?</span>
<span style={{color:c.error,cursor:"pointer",fontWeight:700,fontSize:11,textDecoration:"underline"}} onClick={()=>deleteNote(contextMenu.noteId)}>Yes</span>
<span style={{color:c.textTer,cursor:"pointer",fontSize:11}} onClick={()=>setDeletingNote(null)}>No</span>
</div>
:<DItem onClick={()=>setDeletingNote(contextMenu.noteId)}><I.Trash size={12} color={c.error}/>Delete</DItem>}
</div>}
{/* Note list */}
{showNL&&<div style={{width:240,flexShrink:0,borderRight:`1px solid ${c.border}`,display:"flex",flexDirection:"column",backgroundColor:c.bgPanel}}>
<div style={{display:"flex",alignItems:"center",justifyContent:"space-between",padding:"8px 10px",borderBottom:`1px solid ${c.borderLight}`}}>
<span style={{fontSize:12.5,fontWeight:650}}>Notes</span>
<div style={{display:"flex",gap:3}}>
<button onClick={()=>setFolderView(!folderView)} style={{padding:2,border:"none",cursor:"pointer",backgroundColor:folderView?c.accentBtn+"12":"transparent",borderRadius:3,display:"flex",color:folderView?c.accentBtn:c.textTer}}><I.Folder size={12}/></button>
{folderView&&<button onClick={()=>{setNewFolderMode({parent:null});setNewFolderName("");setTimeout(()=>nfRef.current?.focus(),50)}} style={{padding:"2px 6px",borderRadius:R.sm,border:`1px solid ${c.border}`,backgroundColor:"transparent",cursor:"pointer",fontSize:9.5,color:c.textTer,fontFamily:font.sans,display:"flex",alignItems:"center",gap:2}} title="New folder"><I.Folder size={8}/>+</button>}
<button onClick={()=>flash("New note…")} style={{padding:"2px 6px",borderRadius:R.sm,border:`1px solid ${c.border}`,backgroundColor:"transparent",cursor:"pointer",fontSize:9.5,color:c.accentBtn,fontFamily:font.sans,display:"flex",alignItems:"center",gap:2}} title="New note"><I.FileText size={8}/>+</button>
</div>
</div>
{/* Search + sort */}
<div style={{display:"flex",alignItems:"center",gap:4,padding:"4px 8px",borderBottom:`1px solid ${c.borderLight}`}}>
<div style={{display:"flex",alignItems:"center",gap:3,flex:1,padding:"3px 6px",borderRadius:R.sm,backgroundColor:c.bgInput,border:`1px solid ${c.borderLight}`}}>
<I.Search size={10} color={c.textTer}/><input value={noteSearch} onChange={e=>setNoteSearch(e.target.value)} placeholder="Search notes…" style={{flex:1,border:"none",backgroundColor:"transparent",fontSize:10.5,fontFamily:font.sans,color:c.textPri,outline:"none"}}/>
{noteSearch&&<button onClick={()=>setNoteSearch("")} style={{padding:0,border:"none",cursor:"pointer",backgroundColor:"transparent",display:"flex",color:c.textTer}}><I.X size={9}/></button>}
</div>
<div style={{position:"relative"}}>
<button onClick={e=>{e.stopPropagation();setNoteSortDrop(!noteSortDrop)}} style={{padding:"2px 5px",borderRadius:3,border:`1px solid ${c.borderLight}`,backgroundColor:"transparent",cursor:"pointer",fontSize:9,color:c.textTer,fontFamily:font.sans}}>{noteSort} ▾</button>
{noteSortDrop&&<div onClick={e=>e.stopPropagation()} style={{position:"absolute",top:22,right:0,backgroundColor:c.bgCard,border:`1px solid ${c.border}`,borderRadius:R.sm,boxShadow:"0 4px 12px rgba(0,0,0,0.1)",zIndex:50,minWidth:100,padding:3}}>
{noteSortOpts.map(s=><button key={s} onClick={()=>{setNoteSort(s);setNoteSortDrop(false)}} style={{display:"block",width:"100%",padding:"4px 8px",border:"none",cursor:"pointer",backgroundColor:s===noteSort?c.accentBtn+"08":"transparent",fontSize:10.5,color:s===noteSort?c.accentBtn:c.textPri,textAlign:"left",borderRadius:R.sm,fontFamily:font.sans,fontWeight:s===noteSort?600:400}}>{s}</button>)}
</div>}
</div>
</div>
<div style={{flex:1,overflowY:"auto"}}>
{folderView?<>
{newFolderMode&&newFolderMode.parent===null&&<div style={{display:"flex",alignItems:"center",gap:4,padding:"4px 8px",borderBottom:`1px solid ${c.borderLight}`}}><I.Folder size={11} color={c.warn}/><input ref={nfRef} value={newFolderName} onChange={e=>setNewFolderName(e.target.value)} placeholder="Folder name…" onKeyDown={e=>{if(e.key==="Enter")createFolder(null);if(e.key==="Escape"){setNewFolderMode(null);setNewFolderName("")}}} style={{flex:1,border:`1px solid ${c.accentBtn}40`,borderRadius:3,padding:"2px 6px",fontSize:11,fontFamily:font.sans,outline:"none",backgroundColor:c.bgCard}}/></div>}
{renderFolders(null,0)}
<div style={{padding:"5px 8px",borderBottom:`1px solid ${c.borderLight}`,backgroundColor:c.bgPanelAlt}}><span style={{fontSize:11,fontWeight:600,color:c.textTer,fontStyle:"italic"}}>Unfiled</span></div>
{filteredNotes.filter(n=>!n.folder).map(n=><NoteRow key={n.id} n={n}/>)}
</>:<>{filteredNotes.map(n=><NoteRow key={n.id} n={n}/>)}</>}
{/* Archived */}
{archivedNotes.length>0&&<div style={{padding:"6px 8px",borderTop:`1px solid ${c.borderLight}`,borderBottom:`1px solid ${c.borderLight}`,backgroundColor:c.bgPanelAlt,display:"flex",alignItems:"center",justifyContent:"space-between",cursor:"pointer"}} onClick={()=>setShowArchived(!showArchived)}>
<span style={{fontSize:10,fontWeight:600,color:c.textTer}}>Archived ({archivedNotes.length})</span>
{showArchived?<I.ChevD size={10} color={c.textTer}/>:<I.ChevR size={10} color={c.textTer}/>}
</div>}
{showArchived&&archivedNotes.map(n=><div key={n.id} style={{padding:"7px 10px 7px 14px",borderBottom:`1px solid ${c.borderLight}`,cursor:"pointer",opacity:.5,display:"flex",alignItems:"center",gap:6}} onClick={()=>setSelectedNote(n.id)}>
<I.Archive size={10} color={c.textTer}/>
<span style={{flex:1,fontSize:11.5,overflow:"hidden",textOverflow:"ellipsis",whiteSpace:"nowrap"}}>{n.title}</span>
<button onClick={e=>{e.stopPropagation();unarchiveNote(n.id)}} style={{padding:"1px 6px",borderRadius:3,border:`1px solid ${c.border}`,backgroundColor:"transparent",cursor:"pointer",fontSize:9,color:c.accentBtn,fontFamily:font.sans}}>Restore</button>
</div>)}
{filteredNotes.length===0&&!noteSearch&&<div style={{padding:16,fontSize:11,color:c.textTer,textAlign:"center",fontStyle:"italic"}}>No notes</div>}
{noteSearch&&filteredNotes.length===0&&<div style={{padding:16,fontSize:11,color:c.textTer,textAlign:"center",fontStyle:"italic"}}>No notes match "{noteSearch}"</div>}
</div>
<div style={{padding:"3px 8px",borderTop:`1px solid ${c.borderLight}`,fontSize:9,color:c.textTer}}>{activeNotes.length} notes · {noteSort}{archivedNotes.length>0&&` · ${archivedNotes.length} archived`}</div>
</div>}
{/* Editor */}
<div style={{flex:1,display:"flex",flexDirection:"column",overflow:"hidden"}}>
{/* Toolbar — same as previous version, abbreviated for space */}
<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 all" 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/><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={`${openC.length}`} active={rightOpen&&rightTab==="comments"} onClick={()=>{if(rightOpen&&rightTab==="comments")setRightOpen(false);else{setRightOpen(true);setRightTab("comments")}}}/>
{pendingChanges.length>0&&<><Sep/><TBtn icon={<I.Eye size={13}/>} label={showMarkup?"Markup":"Clean"} active={showMarkup} onClick={()=>setShowMarkup(!showMarkup)}/>
<div style={{position:"relative"}}><TBtn icon={<I.Edit size={13}/>} label={`${pendingChanges.length}`} dropdown active onClick={e=>{e.stopPropagation();setOpenDrop(openDrop==="review"?null:"review")}}/>
{openDrop==="review"&&<div onClick={e=>e.stopPropagation()} style={{position:"absolute",top:28,right: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:160,padding:4}}>
<DItem onClick={()=>{acceptAll();setOpenDrop(null)}}>✓ Accept All ({pendingChanges.length})</DItem>
<DItem onClick={()=>{rejectAll();setOpenDrop(null)}}>✗ Reject All ({pendingChanges.length})</DItem>
</div>}</div></>}
<div style={{flex:1}}/><span style={{fontSize:10,color:c.green,fontWeight:500}}>Saved 2m ago</span>
<Sep/><button onClick={()=>{if(rightOpen&&rightTab==="send")setRightOpen(false);else{setRightOpen(true);setRightTab("send")}}} style={{padding:"3px 10px",borderRadius:R.sm,border:`1px solid ${c.accentBtn}40`,backgroundColor:(rightOpen&&rightTab==="send")?c.accentBtn:c.accentBtn+"08",cursor:"pointer",display:"flex",alignItems:"center",gap:4,color:(rightOpen&&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 in note…" 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>}
<div style={{flex:1,display:"flex",overflow:"hidden"}}>
<div ref={editorRef} style={{flex:1,overflowY:"auto",padding:"20px 28px 40px",position:"relative",userSelect:"text"}} onMouseUp={handleMouseUp} onMouseDown={e=>{if(bubbleMenu&&!e.target.closest("[data-bubble]"))setBubbleMenu(null)}}>
<div style={{fontSize:21,fontWeight:700,color:c.textPri,marginBottom:4}} contentEditable suppressContentEditableWarning>Henderson Discovery Priorities</div>
<div style={{display:"flex",alignItems:"center",gap:6,fontSize:10.5,color:c.textTer,marginBottom:16}}><Dot color="#31588c" size={5}/>Henderson · 2h ago · <span style={{cursor:"pointer",color:c.textTer}} title="Right-click notes in sidebar to archive or delete">ℹ Right-click notes to archive/delete</span></div>
<div style={{fontSize:14,lineHeight:1.75,color:c.textSec}}>{segs.map(renderSeg)}</div>
{bubbleMenu&&<div data-bubble="1" style={{position:"absolute",left:Math.max(10,Math.min(bubbleMenu.x-140,(editorRef.current?.clientWidth||500)-300)),top:bubbleMenu.y-44,backgroundColor:c.bgCard,border:`1px solid ${c.border}`,borderRadius:R.sm,boxShadow:"0 4px 16px rgba(0,0,0,0.12)",padding:"4px 6px",display:"flex",gap:2,zIndex:100,alignItems:"center"}}>
<button onClick={startComment} style={{padding:"5px 10px",borderRadius:R.sm,border:"none",cursor:"pointer",backgroundColor:c.accentBtn,color:"#fff",fontSize:11,fontWeight:600,fontFamily:font.sans,display:"flex",alignItems:"center",gap:4}}><I.MsgCircle size={11}/>Comment</button><Sep/>
<div style={{display:"flex",alignItems:"center",gap:2,padding:"2px 6px",borderRadius:R.sm,border:`1px solid ${c.borderLight}`,cursor:"pointer"}}><Dot color={agent.color} size={6}/><span style={{fontSize:10,fontWeight:500}}>{agent.name}</span></div>
<button onClick={()=>{flash(`Sent to ${agent.name}`);dismissBubble()}} style={{padding:"5px 8px",borderRadius:R.sm,border:"none",cursor:"pointer",backgroundColor:"transparent",color:c.textSec,fontSize:11,fontFamily:font.sans,display:"flex",alignItems:"center",gap:3}} onMouseEnter={e=>e.currentTarget.style.backgroundColor=c.bgInput} onMouseLeave={e=>e.currentTarget.style.backgroundColor="transparent"}><I.Spark size={11}/>Ask {agent.name}</button>
{["Rewrite","Expand","Shorten"].map(a=><button key={a} onClick={()=>{flash(`${agent.name}: ${a}…`);dismissBubble()}} style={{padding:"5px 8px",borderRadius:R.sm,border:"none",cursor:"pointer",backgroundColor:"transparent",color:c.textSec,fontSize:11,fontFamily:font.sans}} onMouseEnter={e=>e.currentTarget.style.backgroundColor=c.bgInput} onMouseLeave={e=>e.currentTarget.style.backgroundColor="transparent"}>{a}</button>)}
<button onClick={dismissBubble} style={{padding:3,border:"none",cursor:"pointer",backgroundColor:"transparent",color:c.textTer,display:"flex"}}><I.X size={11}/></button>
</div>}
</div>
{/* Right panel — abbreviated, same as artifact viewer pattern */}
{showRP&&<div style={{width:rightTab==="send"?290:260,flexShrink:0,borderLeft:`1px solid ${c.border}`,display:"flex",flexDirection:"column",backgroundColor:c.bgPanelAlt,overflow:"hidden"}}>
<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 ({openC.length})</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={()=>setRightOpen(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>
{rightTab==="comments"&&<div style={{flex:1,overflowY:"auto",padding:"8px 0"}}>
{newCm&&<div style={{margin:"0 8px 10px",borderRadius:R.sm,border:`2px solid ${c.accentBtn}40`,backgroundColor:c.bgCard,overflow:"hidden"}}><div style={{padding:"8px 11px"}}>{newCm.text&&<div style={{fontSize:10.5,color:c.accentBtn,backgroundColor:c.accentBtn+"08",padding:"3px 6px",borderRadius:3,marginBottom:8,fontStyle:"italic"}}>"{newCm.text.slice(0,80)}"</div>}<textarea ref={cmRef} value={newCmText} onChange={e=>setNewCmText(e.target.value)} placeholder="Comment… (Enter)" onKeyDown={e=>{if(e.key==="Enter"&&!e.shiftKey){e.preventDefault();addComment()}}} style={{width:"100%",padding:"6px 8px",borderRadius:R.sm,border:`1px solid ${c.border}`,fontSize:12,fontFamily:font.sans,outline:"none",minHeight:42,resize:"vertical"}}/><div style={{display:"flex",gap:6,marginTop:6}}><Btn small primary onClick={addComment} disabled={!newCmText.trim()}>Add</Btn><Btn small ghost onClick={()=>{setNewCm(null);setNewCmText("")}}>Cancel</Btn></div></div></div>}
{openC.length>0&&<div style={{padding:"3px 10px 6px"}}><span style={{fontSize:9.5,fontWeight:650,color:c.textTer,textTransform:"uppercase",letterSpacing:".06em"}}>Open ({openC.length})</span></div>}
{openC.map(cm=><CmCard key={cm.id} cm={cm} resolved={false}/>)}
{resolvedC.length>0&&<div style={{padding:"8px 10px 4px"}}><span style={{fontSize:9.5,fontWeight:650,color:c.textTer,textTransform:"uppercase",letterSpacing:".06em"}}>Resolved ({resolvedC.length})</span></div>}
{resolvedC.map(cm=><CmCard key={cm.id} cm={cm} resolved={true}/>)}
<div style={{padding:"8px 10px"}}><div style={{display:"flex",alignItems:"center",gap:5,padding:"7px 9px",borderRadius:R.sm,border:`1px solid ${c.border}`,backgroundColor:c.bgCard,cursor:"text"}} onClick={()=>setNewCm({text:""})}><I.Plus size={11} color={c.textTer}/><span style={{fontSize:11.5,color:c.textTer}}>Add general comment…</span></div></div>
</div>}
{rightTab==="send"&&<><div style={{flex:1,overflowY:"auto",padding:12,backgroundColor:c.bgPanel}}>
<div style={{marginBottom:12}}><div style={{fontSize:11,fontWeight:600,color:c.textTer,marginBottom:5}}>Agent</div><div style={{position:"relative"}}><div onClick={e=>{e.stopPropagation();setAgentDrop(!agentDrop)}} style={{display:"flex",alignItems:"center",gap:6,padding:"7px 10px",borderRadius:R.sm,border:`1px solid ${c.border}`,backgroundColor:c.bgCard,cursor:"pointer"}}><Av letter={agent.letter} color={agent.color} size={20}/><span style={{flex:1,fontSize:12,fontWeight:600}}>{agent.name}</span><I.ChevD size={11} color={c.textTer}/></div>{agentDrop&&<div style={{position:"absolute",top:"100%",left:0,right:0,marginTop:2,backgroundColor:c.bgCard,border:`1px solid ${c.border}`,borderRadius:R.sm,boxShadow:"0 4px 12px rgba(0,0,0,0.1)",zIndex:50,padding:3}}>{agents.map((a,i)=><DItem key={a.name} active={i===agentIdx} onClick={()=>{setAgentIdx(i);setAgentDrop(false)}}><Av letter={a.letter} color={a.color} size={18}/>{a.name}{i===agentIdx&&<I.Check size={12} color={c.accentBtn}/>}</DItem>)}</div>}</div></div>
<div style={{marginBottom:12}}><div style={{fontSize:11,fontWeight:600,color:c.textTer,marginBottom:5}}>Send in</div><div style={{position:"relative"}}><div onClick={e=>{e.stopPropagation();setChatDrop(!chatDrop)}} style={{display:"flex",alignItems:"center",gap:6,padding:"6px 10px",borderRadius:R.sm,border:`1px solid ${c.border}`,backgroundColor:c.bgCard,fontSize:11.5,cursor:"pointer"}}><Dot color={chats[chatIdx].color} size={5}/><span style={{flex:1,color:c.textSec}}>{chats[chatIdx].name}</span>{chats[chatIdx].origin&&<span style={{fontSize:9,color:c.textTer}}>origin</span>}<I.ChevD size={10} color={c.textTer}/></div>{chatDrop&&<div style={{position:"absolute",top:"100%",left:0,right:0,marginTop:2,backgroundColor:c.bgCard,border:`1px solid ${c.border}`,borderRadius:R.sm,boxShadow:"0 4px 12px rgba(0,0,0,0.1)",zIndex:50,padding:3}}>{chats.map((ch,i)=><DItem key={ch.name} active={i===chatIdx} onClick={()=>{setChatIdx(i);setChatDrop(false)}}><Dot color={ch.color} size={5}/>{ch.name}{ch.origin&&<span style={{fontSize:9,color:c.textTer}}>origin</span>}{i===chatIdx&&<I.Check size={12} color={c.accentBtn}/>}</DItem>)}</div>}</div></div>
<div style={{marginBottom:12}}><div style={{fontSize:11,fontWeight:600,color:c.textTer,marginBottom:5}}>Context scope</div><Radio selected={sendScope==="full"} label="Full note + all comments" onClick={()=>setSendScope("full")}/><Radio selected={sendScope==="comments_only"} label="Comments & referenced portions" onClick={()=>setSendScope("comments_only")}/><Radio selected={sendScope==="select"} label="Select comments & references" onClick={()=>setSendScope("select")}/></div>
{openC.length>0&&<div style={{marginBottom:12}}><div style={{fontSize:11,fontWeight:600,color:c.textTer,marginBottom:5}}>Comments ({sendScope==="select"?`${selectedCmIds.size} selected`:openC.length})</div>{openC.map(cm=><div key={cm.id} style={{display:"flex",alignItems:"center",gap:6,padding:"4px 8px",borderRadius:R.sm,border:`1px solid ${sendScope==="select"&&selectedCmIds.has(cm.id)?c.accentBtn+"50":c.borderLight}`,marginBottom:3,backgroundColor:sendScope==="select"&&selectedCmIds.has(cm.id)?c.accentBtn+"06":c.bgPanelAlt,cursor:sendScope==="select"?"pointer":"default"}} onClick={()=>{if(sendScope==="select")toggleCmSelect(cm.id)}}>{sendScope==="select"&&<input type="checkbox" checked={selectedCmIds.has(cm.id)} readOnly style={{width:12,height:12,accentColor:c.accentBtn,flexShrink:0}}/>}<div style={{flex:1,minWidth:0,fontSize:10,color:c.textSec,overflow:"hidden",textOverflow:"ellipsis",whiteSpace:"nowrap"}}>{cm.body}</div></div>)}</div>}
<div style={{marginBottom:12}}><div style={{fontSize:11,fontWeight:600,color:c.textTer,marginBottom:5}}>Output mode</div><Radio selected={outputMode==="respond_in_chat"} label="Respond in chat" desc="Opens chat with context." onClick={()=>setOutputMode("respond_in_chat")}/><Radio selected={outputMode==="send_with_instructions"} label="Send with instructions" desc="Agent processes and produces result." onClick={()=>setOutputMode("send_with_instructions")}/></div>
{outputMode==="send_with_instructions"&&<><div style={{marginBottom:12}}><div style={{fontSize:11,fontWeight:600,color:c.textTer,marginBottom:5}}>Result format</div><Radio selected={subMode==="tracked_changes"} label="Apply as tracked changes" onClick={()=>setSubMode("tracked_changes")}/><Radio selected={subMode==="revised_copy"} label="Create revised copy" onClick={()=>setSubMode("revised_copy")}/><Radio selected={subMode==="respond_in_comments"} label="Respond in comments" desc="Agent replies to each comment." onClick={()=>setSubMode("respond_in_comments")}/></div><div style={{marginBottom:12}}><div style={{fontSize:11,fontWeight:600,color:c.textPri,marginBottom:5}}>Instruction <span style={{color:c.error}}>*</span></div><textarea value={instruction} onChange={e=>setInstruction(e.target.value)} placeholder="Tell the agent…" style={{width:"100%",padding:"8px 10px",borderRadius:R.sm,border:`1px solid ${instruction.trim()?c.border:c.warn+"60"}`,fontSize:12,fontFamily:font.sans,outline:"none",minHeight:50,resize:"vertical"}}/>{!instruction.trim()&&<div style={{fontSize:9,color:c.warn,marginTop:3}}>Required</div>}</div></>}
{outputMode==="respond_in_chat"&&<div style={{marginBottom:12}}><div style={{fontSize:11,fontWeight:600,color:c.textTer,marginBottom:5}}>Message (optional)</div><textarea value={instruction} onChange={e=>setInstruction(e.target.value)} placeholder="Optional…" style={{width:"100%",padding:"8px 10px",borderRadius:R.sm,border:`1px solid ${c.border}`,fontSize:12,fontFamily:font.sans,outline:"none",minHeight:44,resize:"vertical"}}/></div>}
<div style={{fontSize:9,color:c.textTer}}>Reference: note:n1 included automatically.</div>
</div><div style={{padding:"10px 12px",borderTop:`1px solid ${c.borderLight}`,backgroundColor:c.bgPanel,display:"flex",gap:6}}><Btn primary disabled={outputMode==="send_with_instructions"&&!instruction.trim()} onClick={handleSend} style={{flex:1,justifyContent:"center"}}><I.Spark size={12} color="#fff"/>{outputMode==="respond_in_chat"?"Open in Chat":`Send to ${agent.name}`}</Btn><Btn ghost onClick={()=>setRightOpen(false)}>Cancel</Btn></div></>}
</div>}
</div>
</div>
</div>
);
}