Q_WORKSPACE_V4.jsx
Design Mockups/Archived Mockups/DOC20 Mockups and Design/DOC20 Archived Mockups/DOC20 Workspace Redo/Q_WORKSPACE_V4.jsx
import { useState, useRef, useCallback, useEffect } from "react";
// ═══ TOKENS + ICONS + COMPONENTS — verbatim from Q_NOTES_FULL ═══
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"/>,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"/>,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"/>,};
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>;
// ═══ DATA — from Q_NOTES_FULL (verbatim) ═══
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 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",segId:"s3"},{id:"c2",segId:"s7"}]; // minimal for highlight tracking
// ═══ NEW DATA — To-Do + Elnor Feed ═══
const initTodos=[
{id:"t1",text:"Draft expert disclosure for Christensen",done:false,pri:1,due:"Apr 4",linkedNote:"Expert Depo Prep — Dr. Smith",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's tracked changes",done:false,pri:1,due:"Mar 20",linkedNote:"Henderson Discovery Priorities",sub:[]},
{id:"t3",text:"Respond to Sparacino re: Narayanan agreement",done:false,pri:2,due:"Mar 19",sub:[]},
{id:"t4",text:"Follow up: opposing counsel on discovery extension",done:false,pri:2,due:"Mar 19",sub:[]},
{id:"t5",text:"Review Quark patent analysis — new filings flagged overnight",done:false,pri:3,linkedNote:"Quark Patent Analysis",sub:[]},
{id:"t6",text:"File Folb trial exhibit list",done:true,pri:2,due:"Mar 17",sub:[]},
];
const elnorFeedData={
"Elnor":[{id:"e1",text:"Reviewed 3 Henderson deposition transcripts — flagged 2 citation issues in Chen depo",time:"5h ago"},{id:"e2",text:"Updated Quark patent landscape — 4 new filings",time:"4h ago"},{id:"e3",text:"Scanned SEC filings — no new Henderson-relevant 10-K amendments",time:"3h ago"},{id:"e4",text:"DOC15 red-team review completed — 3 findings flagged",time:"2h ago",accent:c.green}],
"Calendar":[{id:"e5",text:"Expert disclosure deadline — Folb v. City of LA",time:"47 days",accent:c.error},{id:"e6",text:"Henderson MSJ response due",time:"12 days",accent:c.warn},{id:"e7",text:"Danny Christensen engagement call",time:"Tomorrow 2pm"}],
"Email":[{id:"e8",text:"Sparacino — Narayanan agreement redline",time:"Yesterday"},{id:"e9",text:"Opposing counsel — discovery extension request",time:"2d ago",accent:c.warn}],
"System":[{id:"e10",text:"OneDrive sync paused — re-auth needed",time:"6h ago",accent:c.warn}],
"News":[{id:"e11",text:"SEC announces new cybersecurity disclosure rules effective Q2",time:"Today"},{id:"e12",text:"9th Circuit: new opinion on securities fraud scienter standard",time:"Yesterday",accent:c.accentBtn}],
};
const elnorIcons={Elnor:<I.Spark size={12} color={c.agentAv}/>,Calendar:<I.Calendar size={12} color={c.error}/>,Email:<I.Mail size={12} color={c.accentBtn}/>,System:<I.Bell size={12} color={c.warn}/>,News:<I.Zap size={12} color={c.green}/>};
// ═══════════════════════════════════════════
export default function WorkspaceV4(){
const idC=useRef(300);const nid=()=>"x"+(++idC.current);
// Collapse toggles
const [browserOpen,setBrowserOpen]=useState(true);
const [noteListOpen,setNoteListOpen]=useState(true);
const [commentsOpen,setCommentsOpen]=useState(false);
// Editor state (from Q_NOTES_FULL)
const [changes,setChanges]=useState(initChanges);
const [activeComment,setActiveComment]=useState(null);
const [bubbleMenu,setBubbleMenu]=useState(null);
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 [agentIdx]=useState(0);
const editorRef=useRef(null);
const agent=agents[agentIdx];
const pendingChanges=changes.filter(x=>x.status==="pending");
const flash=msg=>setToast(msg);
// To-do state
const [todos,setTodos]=useState(initTodos);
const [expandedTodo,setExpandedTodo]=useState("t1");
const [todoCollapsed,setTodoCollapsed]=useState(false);
const [elnorCollapsed,setElnorCollapsed]=useState(false);
const [newTodoText,setNewTodoText]=useState("");
// Editor logic (from Q_NOTES_FULL verbatim)
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 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()};
// To-do logic
const toggleTodo=id=>setTodos(p=>p.map(t=>t.id===id?{...t,done:!t.done}:t));
const toggleSub=(pid,sid)=>setTodos(p=>p.map(t=>t.id===pid?{...t,sub:t.sub.map(s=>s.id===sid?{...s,done:!s.done}:s)}:t));
const priColor=p=>p===1?c.error:p===2?c.warn:c.accentBtn;
const priLabel=p=>p===1?"P1":p===2?"P2":"P3";
const activeTodos=todos.filter(t=>!t.done);
const doneTodos=todos.filter(t=>t.done);
// Tracked changes rendering (from Q_NOTES_FULL verbatim)
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=initComments.some(cm=>cm.segId===seg.id);const isAct=activeComment&&initComments.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=initComments.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=initComments.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=initComments.find(x=>x.segId===seg.id);if(cm)setActiveComment(cm.id)}}>💬{cnt}</span>}</p>};
return (
<div style={{display:"flex",width:"100%",height:"100vh",fontFamily:font.sans,color:c.textPri,backgroundColor:c.bgApp}} onClick={()=>{setOpenDrop(null)}}>
<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)}/>}
{/* ═══ SIDEBAR ICON 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={()=>setNoteListOpen(!noteListOpen)} title="Notes sidebar" style={{width:28,height:28,borderRadius:R.sm,border:"none",cursor:"pointer",backgroundColor:noteListOpen?"#ffffff18":"transparent",color:noteListOpen?"#fff":"#777",display:"flex",alignItems:"center",justifyContent:"center"}}><I.FileText 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, collapsible ═══ */}
{browserOpen&&<div style={{width:260,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"}}>
<div style={{fontSize:11,color:c.textTer,fontStyle:"italic",lineHeight:1.6}}>
Q_BROWSER_R13.jsx<br/>plugs in here verbatim<br/><br/>
<span style={{fontSize:10}}>260px · collapsible<br/>Full scope/type/filter/sort/folder overlay/places/saved views</span>
</div>
</div>
</div>
</div>}
{/* ═══ NOTES SIDEBAR — placeholder, collapsible ═══ */}
{noteListOpen&&!fullScreen&&<div style={{width:220,flexShrink:0,backgroundColor:c.bgPanel,borderRight:`1px solid ${c.border}`,display:"flex",flexDirection:"column"}}>
<div style={{display:"flex",borderBottom:`1px solid ${c.borderLight}`}}>
<button style={{flex:1,padding:"8px 0",border:"none",cursor:"pointer",fontFamily:font.sans,fontSize:10,fontWeight:650,color:c.accentBtn,backgroundColor:c.accentBtn+"06",borderBottom:`2px solid ${c.accentBtn}`,display:"flex",alignItems:"center",justifyContent:"center",gap:3}}><I.FileText size={10}/>Notes</button>
<button style={{flex:1,padding:"8px 0",border:"none",cursor:"pointer",fontFamily:font.sans,fontSize:10,fontWeight:450,color:c.textTer,backgroundColor:"transparent",borderBottom:"2px solid transparent",display:"flex",alignItems:"center",justifyContent:"center",gap:3}}><I.List size={10}/>To-Do Lists</button>
</div>
<div style={{flex:1,display:"flex",alignItems:"center",justifyContent:"center",padding:16}}>
<div style={{textAlign:"center"}}>
<div style={{fontSize:11,color:c.textTer,fontStyle:"italic",lineHeight:1.6}}>
Notes sidebar from<br/>Q_NOTES_FULL.jsx<br/>plugs in here<br/><br/>
<span style={{fontSize:10}}>220px · collapsible<br/>Folder tree · search · sort<br/>+Folder · +Note · archive<br/>Right-click context menu<br/><br/><strong>New: To-Do Lists tab</strong><br/>Saved lists with icons + counts</span>
</div>
</div>
</div>
</div>}
{/* ═══ MAIN WORKSPACE ═══ */}
<div style={{flex:1,display:"flex",flexDirection:"column",overflow:"hidden"}}>
{/* ─── Full toolbar (from Q_NOTES_FULL verbatim) ─── */}
<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="2" active={commentsOpen} onClick={()=>setCommentsOpen(!commentsOpen)}/>
{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={()=>flash("Send to Agent…")} style={{padding:"3px 10px",borderRadius:R.sm,border:`1px solid ${c.accentBtn}40`,backgroundColor:c.accentBtn+"08",cursor:"pointer",display:"flex",alignItems:"center",gap:4,color: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>}
{/* ─── CONTENT: To-Do | Editor | Comments ─── */}
<div style={{flex:1,display:"flex",overflow:"hidden"}}>
{/* ═══ TO-DO + ELNOR COLUMN (real, left of editor) ═══ */}
{!fullScreen&&<div style={{width:310,borderRight:`1px solid ${c.border}`,display:"flex",flexDirection:"column",backgroundColor:c.bgPanelAlt,flexShrink:0}}>
{/* My Tasks header */}
<div onClick={()=>setTodoCollapsed(!todoCollapsed)} style={{padding:"8px 10px",display:"flex",alignItems:"center",gap:6,cursor:"pointer",backgroundColor:c.bgPanel,borderBottom:`1px solid ${c.borderLight}`}}>
<div style={{transform:todoCollapsed?"none":"rotate(90deg)",transition:"transform 0.1s"}}><I.ChevR size={10} color={c.textTer}/></div>
<span style={{fontSize:13,fontWeight:700,flex:1}}>Today</span>
<span style={{fontSize:10,color:c.textTer,backgroundColor:c.bgInput,padding:"1px 7px",borderRadius:3}}>{activeTodos.length}</span>
<button onClick={e=>{e.stopPropagation();flash("Configure list…")}} style={{border:"none",background:"none",cursor:"pointer",padding:2,display:"flex"}}><I.Settings size={13} color={c.textTer}/></button>
</div>
<div style={{flex:1,overflowY:"auto"}}>
{/* Tasks */}
{!todoCollapsed&&<div style={{padding:"6px 8px"}}>
{activeTodos.map(todo=><div key={todo.id} style={{marginBottom:3,borderRadius:R.sm,backgroundColor:c.bgCard,border:`1px solid ${expandedTodo===todo.id?c.accentBtn+"25":c.borderLight}`}}>
<div style={{display:"flex",alignItems:"flex-start",gap:6,padding:"7px 10px",cursor:"pointer"}} onClick={()=>setExpandedTodo(expandedTodo===todo.id?null:todo.id)}>
<input type="checkbox" checked={false} onChange={()=>toggleTodo(todo.id)} onClick={e=>e.stopPropagation()} style={{width:15,height:15,accentColor:c.accentBtn,marginTop:1,flexShrink:0}}/>
<div style={{flex:1,minWidth:0}}>
<div style={{fontSize:12.5,fontWeight:500,lineHeight:1.4,color:c.textPri}}>{todo.text}</div>
<div style={{display:"flex",gap:6,marginTop:3,alignItems:"center",flexWrap:"wrap"}}>
<span style={{fontSize:9,fontWeight:700,color:priColor(todo.pri),border:`1px solid ${priColor(todo.pri)}35`,borderRadius:3,padding:"0 4px",lineHeight:"16px"}}>{priLabel(todo.pri)}</span>
{todo.due&&<span style={{fontSize:10,color:c.textTer}}>{todo.due}</span>}
{todo.linkedNote&&<span style={{fontSize:10,color:c.accentBtn,cursor:"pointer",display:"flex",alignItems:"center",gap:2}} onClick={e=>{e.stopPropagation();flash(`Opening "${todo.linkedNote}"`)}}><I.Link size={9}/>Note</span>}
{todo.sub.length>0&&<span style={{fontSize:10,color:c.textTer}}>{todo.sub.filter(s=>s.done).length}/{todo.sub.length}</span>}
</div>
</div>
<div style={{transform:expandedTodo===todo.id?"rotate(90deg)":"none",transition:"transform 0.1s",marginTop:4}}><I.ChevR size={10} color={c.textTer}/></div>
</div>
{expandedTodo===todo.id&&<div style={{padding:"0 10px 8px 32px",borderTop:`1px solid ${c.borderLight}`}}>
{todo.sub.map(s=><div key={s.id} style={{display:"flex",alignItems:"center",gap:6,padding:"4px 0"}}>
<input type="checkbox" checked={s.done} onChange={()=>toggleSub(todo.id,s.id)} style={{width:13,height:13,accentColor:c.accentBtn}}/>
<span style={{fontSize:11.5,color:s.done?c.textTer:c.textSec,textDecoration:s.done?"line-through":"none"}}>{s.text}</span>
</div>)}
<div style={{display:"flex",gap:4,marginTop:8}}>
<Btn small ghost onClick={()=>flash("@Elnor…")}><I.Spark size={10} color={c.agentAv}/>@Elnor</Btn>
<Btn small ghost><I.Plus size={10}/>Sub</Btn>
<Btn small ghost onClick={()=>flash(todo.linkedNote?`Open "${todo.linkedNote}"`:"Link a note…")}><I.Link size={10}/>{todo.linkedNote?"Open Note":"Link Note"}</Btn>
</div>
</div>}
</div>)}
{/* Add task */}
<div style={{display:"flex",alignItems:"center",gap:6,padding:"7px 10px",borderRadius:R.sm,border:`1px dashed ${c.borderLight}`,marginTop:4}}>
<I.Plus size={12} color={c.textTer}/>
<input value={newTodoText} onChange={e=>setNewTodoText(e.target.value)} placeholder="Add task… (type @Elnor to assign)" onKeyDown={e=>{if(e.key==="Enter"&&newTodoText.trim()){setTodos(p=>[...p,{id:"t"+Date.now(),text:newTodoText,done:false,pri:3,sub:[]}]);setNewTodoText("")}}} style={{flex:1,border:"none",outline:"none",fontSize:12,fontFamily:font.sans,backgroundColor:"transparent",color:c.textPri}}/>
</div>
{/* Done */}
{doneTodos.length>0&&<div style={{marginTop:10}}>
<div style={{fontSize:10,fontWeight:650,color:c.textTer,textTransform:"uppercase",letterSpacing:".05em",padding:"4px 0"}}>Done ({doneTodos.length})</div>
{doneTodos.map(t=><div key={t.id} style={{display:"flex",alignItems:"center",gap:6,padding:"5px 10px",opacity:.45}}>
<input type="checkbox" checked onChange={()=>toggleTodo(t.id)} style={{width:14,height:14,accentColor:c.accentBtn}}/>
<span style={{fontSize:11.5,textDecoration:"line-through",color:c.textTer}}>{t.text}</span>
</div>)}
</div>}
</div>}
{/* ═══ ELNOR FEED (with category headers) ═══ */}
<div style={{borderTop:`1px solid ${c.borderLight}`}}>
<div onClick={()=>setElnorCollapsed(!elnorCollapsed)} style={{padding:"8px 10px",display:"flex",alignItems:"center",gap:6,cursor:"pointer",backgroundColor:c.bgPanel}}>
<div style={{transform:elnorCollapsed?"none":"rotate(90deg)",transition:"transform 0.1s"}}><I.ChevR size={10} color={c.textTer}/></div>
<I.Spark size={13} color={c.agentAv}/>
<span style={{fontSize:13,fontWeight:700,flex:1}}>Elnor</span>
<span style={{fontSize:10,color:c.textTer,backgroundColor:c.bgInput,padding:"1px 7px",borderRadius:3}}>{Object.values(elnorFeedData).flat().length}</span>
</div>
{!elnorCollapsed&&<div style={{padding:"4px 8px 10px"}}>
{Object.entries(elnorFeedData).map(([cat,items])=><div key={cat} style={{marginBottom:8}}>
<div style={{display:"flex",alignItems:"center",gap:5,padding:"4px 6px",marginBottom:3}}>
{elnorIcons[cat]}
<span style={{fontSize:11,fontWeight:700,color:c.textSec,textTransform:"uppercase",letterSpacing:".04em"}}>{cat}</span>
<span style={{fontSize:9.5,color:c.textTer}}>({items.length})</span>
</div>
{items.map(item=><div key={item.id} style={{display:"flex",alignItems:"flex-start",gap:6,padding:"5px 8px 5px 26px",borderRadius:R.sm,cursor:"pointer"}} onMouseEnter={e=>e.currentTarget.style.backgroundColor=c.bgInput} onMouseLeave={e=>e.currentTarget.style.backgroundColor="transparent"}>
{item.accent&&<Dot color={item.accent} size={5}/>}
<span style={{flex:1,fontSize:12,color:c.textSec,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>
</div>
</div>}
{/* ═══ EDITOR (from Q_NOTES_FULL — real, working) ═══ */}
<div style={{flex:1,display:"flex",flexDirection:"column",overflow:"hidden",minWidth:0}}>
<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}}>2h ago · 2 comments · 3 pending changes</div>
<div style={{fontSize:14,lineHeight:1.75,color:c.textSec}}>{segs.map(renderSeg)}</div>
{/* Bubble menu (from Q_NOTES_FULL verbatim) */}
{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={()=>{flash("Comment…");dismissBubble()}} 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>
</div>
{/* ═══ COMMENTS PANEL — placeholder, collapsible ═══ */}
{commentsOpen&&!fullScreen&&<div style={{width: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 style={{flex:1,padding:"7px 0",border:"none",cursor:"pointer",backgroundColor:c.bgPanelAlt,color:c.accentBtn,fontSize:10.5,fontWeight:650,fontFamily:font.sans,borderBottom:`2px solid ${c.accentBtn}`,display:"flex",alignItems:"center",justifyContent:"center",gap:3}}><I.MsgCircle size={10}/>Comments (2)</button>
<button style={{flex:1,padding:"7px 0",border:"none",cursor:"pointer",backgroundColor:c.bgInput,color:c.textTer,fontSize:10.5,fontWeight:450,fontFamily:font.sans,borderBottom:"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"}}>
<div style={{fontSize:11,color:c.textTer,fontStyle:"italic",lineHeight:1.6}}>
Comments + Send to Agent<br/>from Q_NOTES_FULL.jsx<br/>plugs in here verbatim<br/><br/>
<span style={{fontSize:10}}>260–290px · right of editor<br/>Full comment cards<br/>Reply/Resolve/Edit/Delete<br/>Per-comment ✨ Send<br/>Agent/Chat selector<br/>Context scope radios<br/>Output mode + result format<br/><br/><strong>New: @mention support</strong><br/>Type @Elnor in any text field<br/>(in specs, not visual here)</span>
</div>
</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>
);
}