ELNOR REPO READER TEXT MIRROR Original path: Design Mockups/Archived Mockups/DOC20 Mockups and Design/DOC20 Current Mockups/Q_UNIFIED_WORKSPACE_V7_11 (2).jsx Source repo: /Users/OpenClaw1/Elnor/Elnor Specs Git branch: main Git commit: dbaa25962edc11ab30e8d4ca1715f9ae5bf77331 Generated: 2026-06-09T01:23:58.539Z --- import { useState, useRef, useEffect, useMemo, useCallback } from "react"; const font={sans:"'IBM Plex Sans','Helvetica Neue',-apple-system,BlinkMacSystemFont,sans-serif",mono:"'SF Mono','Fira Code','Cascadia Code',monospace"}; 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",neutral:"#6B7280",agentAv:"#a1a7aa",borderDark:"#263040",purple:"#7C3AED",incBg:"#2A1F3D",incBorder:"#3d2e5c",incText:"#a78bfa", // Floating palette colors fpBg:"#1a1d23",fpBorder:"#2e3340",fpText:"#c8cdd5",fpTextDim:"#6b7280",fpAccent:"#5b8dd9",fpInput:"#252830"}; const Ic=({d,size=18,color,sw=1.75})=>; const I={Search:p=>,Plus:p=>,ChevR:p=>,ChevD:p=>,Pin:p=>,Folder:p=>,File:p=>,X:p=>,Check:p=>,Save:p=>,Trash:p=>,Copy:p=>,Link:p=>,Maximize:p=>,Spark:p=>,MsgCircle:p=>,Undo:p=>,Redo:p=>,Eye:p=>,Edit:p=>,FileText:p=>,ExtLink:p=>,Printer:p=>,Clock:p=>,ArrowL:p=>,ArrowR:p=>,Refresh:p=>,Star:p=>,Lock:p=>,Book:p=>,Scissors:p=>,Globe:p=>,Home:p=>,Settings:p=>,Inbox:p=>,Grid:p=>,Download:p=>,List:p=>,Bell:p=>,Zap:p=>,Sun:p=>,Mail:p=>,Calendar:p=>,Mask:p=>,Grip:p=>,Archive:p=>,Sidebar:p=>,Paperclip:p=>,Compass:p=>,Users:p=>,User:p=>,Database:p=>,Layers:p=>,CheckSq:p=>,Columns:p=>,Keyboard:p=>,Camera:p=>,Terminal:p=>,Hash:p=>,Minus:p=>,Send:p=>,Plug:p=>,Bucket:p=>,ListTodo:p=>,Subtask:p=>,ListChecks:p=>}; const navPageIcons={activity:"Bell",tasks:"Subtask",projects:"Folder",knowledge:"Database",forums:"MsgCircle",agents:"User",skills:"Plug",overlays:"Layers",buckets:"Bucket",settings:"Settings"}; const tabIconMap={note:'FileText',doc:'File',web:'Globe',clips:'Scissors',chat:'MsgCircle',todo:'ListTodo',room:'Users',task:'List',panel:'Grid',forum:'MsgCircle',utility:'Settings'}; const TabIcon=({type,icon,size=12})=>{if(type==="utility"&&icon){const nm=navPageIcons[icon];if(nm){const C=I[nm];return C?:null}}const C=I[tabIconMap[type]||'File'];return C?:null}; const NavIcon=({id,size=13})=>{const nm=navPageIcons[id];const C=nm?I[nm]:null;return C?:null}; const Dot=({color,size=8})=>; const Toast=({msg,onDone})=>{useEffect(()=>{const t=setTimeout(onDone,2200);return()=>clearTimeout(t)},[onDone]);return
{msg}
}; const TBtn=({icon,title,active,onClick,label,dropdown})=>; const Sep=()=>
; const Btn=({children,primary,ghost,small,onClick,disabled,style:s})=>; const Av=({letter,color,size=20})=>
{letter}
; const DItem=({children,onClick,active,disabled})=>; const Radio=({selected,label,desc,onClick,disabled})=>; const DragHandle=()=>
e.currentTarget.style.opacity=0.55} onMouseLeave={e=>e.currentTarget.style.opacity=0.18}>
; // ═══ DATA ═══ const agentName="Elnor"; const agents=[{name:"Elnor",color:c.agentAv,letter:"E"},{name:"Scout",color:"#5B5F97",letter:"S"}]; const chats=[{name:"Paramount damages",color:c.accentBtn,origin:true},{name:"Brooge causation",color:c.green},{name:"New chat",color:c.textTer}]; const typeColors={Note:c.accentBtn,Chat:c.green,Doc:c.textTer,Task:c.warn,Artifact:"#8B5CF6",Prompt:"#D97706",Preset:c.neutral,Skill:c.neutral,Agent:"#5B5F97",Overlay:"#9333EA",Template:"#0891B2",Chain:"#DC2626",Memory:c.green,Room:"#6366F1",Bookmark:c.warn}; const projects=[{id:1,name:"Paramount v. City of LA",color:"#31588c"},{id:2,name:"White v. Brooge Energy",color:"#2E8B57"},{id:3,name:"Internal Ops",color:"#8B7355"}]; const collections=[{name:"Priority",color:"#B04040"},{name:"Research",color:"#2E8B57"},{name:"Draft",color:"#D97706"},{name:"Archive",color:"#6B7280"},{name:"Urgent",color:"#9E5E5E"},{name:"Reference",color:"#5B5F97"}]; const scopeFams=["Collection","Project","Bucket","Places","Saved Views"]; const typeChips=["Document","Chat","Preset","Skill","Task","Agent","Overlay","Note","Artifact","Prompt","Template","Chain","Memory","Room","Bookmark","Panel","Forum","To Do"]; const sortOptions=["Modified","Alphabetical","Type","Created","Running"]; const savedViews=[{id:"sv1",name:"Recent",sys:true},{id:"sv2",name:"Deadlines this week",sys:false},{id:"sv3",name:"Active matters",sys:false}]; const tabColors={note:"#31588c",doc:"#2E8B57",web:"#64748B",clips:"#7C3AED",chat:"#1a5276",room:"#6366F1",task:"#D97706",todo:"#0891B2",utility:c.neutral}; const groupColors=["#EF4444","#F97316","#22C55E","#3B82F6","#8B5CF6","#6B7280"]; const recentConvos=[{id:"cv1",name:"Paramount damages strategy",color:c.accentBtn,time:"1h",starred:true},{id:"cv2",name:"Brooge loss causation",color:c.green,time:"3h",starred:true},{id:"cv3",name:"Expert depo prep",color:c.warn,time:"1d"},{id:"cv4",name:"Trial brief §III draft",color:c.accentBtn,time:"1d"},{id:"cv5",name:"Signage rights research",color:"#5B5F97",time:"2d"},{id:"cv6",name:"Patent landscape scan",color:c.green,time:"3d"}]; // V7.4: "Knowledge Manager" → "Knowledge" const navPages=[{id:"activity",label:"Activity & Notifications"},{id:"tasks",label:"Tasks"},{id:"projects",label:"Projects"},{id:"knowledge",label:"Knowledge"},{id:"forums",label:"Forums & Panels"},{id:"agents",label:"Agents"},{id:"skills",label:"Skills & Connectors"},{id:"overlays",label:"Overlays & Prompts"},{id:"buckets",label:"Context Buckets"},{id:"settings",label:"Settings"}]; const feedPresets=[{id:"fp1",name:"System Activity",icon:"spark",desc:"Agent completions, memory updates",category:"system"},{id:"fp2",name:"System Notices",icon:"bell",desc:"Errors, warnings, sync issues",category:"system"},{id:"fp3",name:"Gate Approvals",icon:"check",desc:"Pending chain gates",category:"system"},{id:"fp4",name:"Active Operations",icon:"zap",desc:"Running agents and tasks",category:"system"},{id:"fp5",name:"Morning Summary",icon:"sun",desc:"Daily briefing — priorities",category:"agent"},{id:"fp6",name:"Email Watch",icon:"mail",desc:"Flag important emails",category:"agent"},{id:"fp7",name:"Deadline Tracker",icon:"calendar",desc:"Calendar deadlines",category:"agent"}]; const feedIcons={spark:,bell:,check:,zap:,sun:,mail:,calendar:}; const initPlaces=[{id:"p1",title:"Paramount Case Files",path:"~/OneDrive-schallfirm/Paramount",status:"ok"},{id:"p2",title:"Firm Templates",path:"~/OneDrive-schallfirm/Templates",status:"ok"},{id:"p3",title:"Local Research",path:"~/Documents/Research",status:"ok"},{id:"p4",title:"Archived Cases",path:"/Volumes/External/Cases",status:"missing"}]; const placeContents={root:[{name:"Expert_Reports",isFolder:true},{name:"Exhibits",isFolder:true},{name:"Paramount_Complaint.pdf",type:"PDF",size:"2.4 MB",mod:"1d"},{name:"Privilege_Log_v4.docx",type:"DOCX",size:"340 KB",mod:"3h"}],Expert_Reports:[{name:"Sanli_Report.pdf",type:"PDF",size:"1.2 MB",mod:"1w"},{name:"Christensen_CV.pdf",type:"PDF",size:"890 KB",mod:"2w"}],Exhibits:[{name:"Exhibit_A.pdf",type:"PDF",size:"3.1 MB",mod:"3d"}]}; const allItems=[{type:"Note",title:"Today — April 4, 2026",time:"2h",pin:true,proj:1,cols:["Priority"]},{type:"Note",title:"Trial Prep Checklist",time:"4h",pin:true,proj:1,cols:[]},{type:"Doc",title:"Sanli Expert Report.pdf",time:"10m",proj:1,cols:["Priority"]},{type:"Artifact",title:"Motion in Limine No. 3",time:"1d",proj:1,cols:[]},{type:"Doc",title:"Christensen_CV.pdf",time:"1d",proj:1,cols:["Reference"]},{type:"Note",title:"Brooge Loss Causation",time:"1d",proj:2,cols:["Research"]},{type:"Task",title:"Review Sanli depo",time:"2h",proj:1,st:"running",cols:[]},{type:"Chat",title:"Paramount damages",time:"1h",proj:1,cols:["Priority"]},{type:"Artifact",title:"Fair Fund — Brooge",time:"2h",proj:2,cols:[]},{type:"Doc",title:"BC587659_MIL_3.pdf",time:"2d",proj:1,cols:[]},{type:"Task",title:"Draft trial brief §III",time:"4h",proj:1,st:"waiting",cols:["Priority"]},{type:"Prompt",title:"Expert Analysis Template",time:"1w",proj:null,cols:[]},{type:"Preset",title:"Legal Brief Review",time:"1w",proj:null,cols:[]},{type:"Doc",title:"Standing_Orders.md",time:"3d",proj:null,cols:["Reference"]}]; const timeVal=t=>{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}; const initTabs=[{id:"t1",type:"note",icon:"note",title:"Today — April 4, 2026",color:tabColors.note,group:"g1"},{id:"t2",type:"doc",icon:"doc",title:"Sanli Expert Report.pdf",color:tabColors.doc},{id:"t3",type:"web",icon:"web",title:"Paramount MIL — PACER",color:tabColors.web,group:"g1"},{id:"t4",type:"clips",icon:"clips",title:"Clips: 4.4-1",color:tabColors.clips},{id:"t5",type:"chat",icon:"chat",title:"Paramount damages",color:tabColors.chat}]; const initGroups=[{id:"g1",label:"Paramount Research",color:"#22C55E",collapsed:false}]; const initComments=[{id:"c1",author:"You",color:c.accentBtn,body:"Verify Sanli's discount rate — 18% seems unsupported.",time:"10m ago",status:"open",anchor:"discount rate of 18%",replies:[{id:"r1",author:agentName,color:c.agentAv,body:"Found 3 comparables: avg 8-12%. Sanli's 18% is an outlier.",time:"5m ago"}]},{id:"c2",author:"You",color:c.accentBtn,body:"Cross-ref with Christensen methodology.",time:"8m ago",status:"open",anchor:"willing buyer-willing seller",replies:[]},{id:"c3",author:agentName,color:c.agentAv,body:"Sargon gatekeeper standard briefed in §II.",time:"6m ago",status:"resolved",anchor:"Legal Standard",replies:[]}]; const tcColors={You:{del:c.accentBtn,ins:c.accentBtn},Agent:{del:"#B04040",ins:"#2E8B57"}}; const initChanges=[{id:"tc1",segId:"s4",author:"Agent",oldText:"discussing litigation posture",newText:"discussing litigation posture and insurance coverage",status:"pending"},{id:"tc2",segId:"s7",author:"You",oldText:"Prepare updated privilege log",newText:"Prepare updated privilege log with Bates-stamp cross-refs",status:"pending"}]; const noteSegs=[{id:"s1",t:"p",v:"Trial May 4 — 30 days out. Focus items for today."},{id:"s2",t:"h2",v:"Expert Motions"},{id:"s3",t:"p",v:"Finalize MIL No. 3 — Sanli discount rate argument."},{id:"s4",t:"p",v:"Cross-reference discussing litigation posture with Christensen opinions."},{id:"s7",t:"h2",v:"Next Steps"},{id:"s8",t:"p",v:"Prepare updated privilege log with all newly identified documents."}]; const initBlocks=[{id:"b2",type:"todo",title:"To Do",collapsed:false,tasks:[{id:"t1",text:"Finalize MIL No. 3 re: Sanli",done:false,due:"Apr 7",sub:[{id:"s1",text:"Pull Sanli discount rate comparables",done:true},{id:"s2",text:"Draft Sargon gatekeeper argument",done:false}]},{id:"t2",text:"Review Christensen engagement",done:true,due:"Apr 3",sub:[]},{id:"t3",text:"Prep Sanli depo cross-exam",done:false,due:"Apr 10",sub:[]},{id:"t4",text:"File trial exhibit list",done:true,due:"Apr 1",sub:[]}]},{id:"b3",type:"thread",collapsed:false,contextQuote:"Sanli discount rate",messages:[{id:"m1",author:"You",color:c.accentBtn,body:"@Agent find comparable signage transactions with discount rates",time:"45m"},{id:"m2",author:"Agent",color:c.agentAv,body:"Found 3 comparables: avg 8-12%. Sanli's 18% is unsupported. See attached analysis.",time:"40m"}]},{id:"b5",type:"feed",title:"Activity Brief",collapsed:false,sections:[{key:"elnor",icon:"spark",label:"Agent",items:[{text:"Reviewed 3 depo transcripts — flagged 2 issues",time:"5h"},{text:"Updated patent landscape — 4 new filings",time:"4h"}]},{key:"system",icon:"bell",label:"System",items:[{text:"OneDrive sync paused — re-auth needed",time:"6h",accent:c.warn}]}]}]; const initNoteFolders=[{id:"nf1",title:"Case Notes",parent:null},{id:"nf2",title:"Paramount",parent:"nf1"},{id:"nf3",title:"Brooge",parent:"nf1"},{id:"nf4",title:"Session Notes",parent:null}]; const initNotes=[{id:"n1",title:"Today — April 4, 2026",mod:"2h",pinned:true,folder:"nf2",comments:2},{id:"n2",title:"Trial Prep Checklist",mod:"4h",pinned:true,folder:"nf2",comments:0},{id:"n3",title:"Danny Christensen",mod:"3d",folder:"nf2",comments:1},{id:"n4",title:"Brooge Loss Causation",mod:"1d",folder:"nf3",comments:0},{id:"n5",title:"Clips: 4.4-1",mod:"2h",folder:"nf4",comments:0}]; const initBrowserFolders=[{id:"f1",title:"Paramount Case",parent:null},{id:"f2",title:"Expert Reports",parent:"f1"},{id:"f3",title:"Motion Practice",parent:"f1"},{id:"f4",title:"Brooge Research",parent:null}]; const initBookmarks=[ {id:"bm0",title:"Bookmarks Bar",parent:null,isBar:true,items:[{id:"bar1",title:"PACER",url:"pacer.uscourts.gov",color:"#1a5276"},{id:"bar2",title:"Westlaw",url:"westlaw.com",color:"#8B0000"},{id:"bar3",title:"EDGAR",url:"sec.gov",color:"#1B4F72"},{id:"bar4",title:"Bloomberg",url:"bloomberglaw.com",color:"#000"}]}, {id:"bm1",title:"Legal Research",parent:null,items:[{id:"bi1",title:"PACER — CACD",url:"pacer.uscourts.gov",color:"#1a5276"},{id:"bi2",title:"Westlaw",url:"westlaw.com",color:"#8B0000"},{id:"bi3",title:"CM/ECF Login",url:"ecf.cacd.uscourts.gov",color:"#2c3e50"},{id:"bi4",title:"EDGAR Full-Text",url:"sec.gov",color:"#1B4F72"}]}, {id:"bm2",title:"Clients",parent:null,items:[{id:"bi5",title:"Paramount SharePoint",url:"schallfirm.sharepoint.com",color:"#0078d4"},{id:"bi6",title:"Brooge Portal",url:"brooge.com",color:"#2E8B57"}]}, {id:"bm3",title:"Reference",parent:null,items:[{id:"bi7",title:"Cal. Rules of Court",url:"courts.ca.gov",color:"#8B7355"},{id:"bi8",title:"LAMC Full Text",url:"codelibrary.amlegal.com",color:"#6B7280"}]}, {id:"bm4",title:"Daily",parent:"bm1",items:[{id:"bi9",title:"Bloomberg Law",url:"bloomberglaw.com",color:"#000"}]} ]; // Floating palette chat history const initFpMessages=[ {id:"fp1",from:"You",text:"What's the strongest Sargon argument against Sanli?",time:"2:14 PM"}, {id:"fp2",from:"Elnor",text:"Three comparable signage transactions show discount rates of 8-12%. Sanli's 18% is an unsupported outlier — this is a textbook Sargon gatekeeper exclusion.",time:"2:14 PM"}, {id:"fp3",from:"You",text:"Pull the exact cite from Sargon for the brief.",time:"2:16 PM"}, {id:"fp4",from:"Elnor",text:"Sargon Enterprises, Inc. v. University of Southern California (2012) 55 Cal.4th 747, 770: \"the trial court acts as a gatekeeper to exclude expert opinion testimony that is (1) based on matter of a type on which an expert may not reasonably rely, (2) based on reasons unsupported by the material on which the expert relies, or (3) speculative.\"",time:"2:16 PM"}, ]; // V7.9: Unified To Do lists — first-class entities, viewable from palette / notes / standalone tabs const initFpTodoLists=[ {id:"tl1",name:"Daily",noteId:"n2",tasks:[{id:"td1",text:"File exhibit list amendment",done:false,sub:[]},{id:"td2",text:"Review Sanli depo transcript pp. 40-80",done:false,sub:[{id:"tds1",text:"Flag discount rate testimony",done:true},{id:"tds2",text:"Note methodology admissions",done:false}]},{id:"td3",text:"Send Christensen CV to co-counsel",done:true,sub:[]},{id:"td4",text:"Pull Sargon gatekeeper cases",done:true,sub:[]}]}, {id:"tl2",name:"Trial Prep",noteId:"n2",tasks:[{id:"td5",text:"Witness list finalization",done:false,sub:[]},{id:"td6",text:"Jury instructions draft",done:false,sub:[]},{id:"td7",text:"Trial binder assembly",done:true,sub:[]}]} ]; // Calendar module data const calViews=["All","Paramount","Brooge","Personal"]; const calModes=["Month","Week","Day","List"]; const outlookCals=[{id:"ol1",name:"Will Schall — Main",linked:true,sync:"bidirectional"},{id:"ol2",name:"Paramount v. City of LA",linked:true,sync:"push_to_outlook"},{id:"ol3",name:"White v. Brooge Energy",linked:true,sync:"pull_only"},{id:"ol4",name:"Firm Shared",linked:false,sync:"none"},{id:"ol5",name:"Personal",linked:false,sync:"none"}]; const reminderTimings=["At time of event","5 minutes before","15 minutes before","30 minutes before","1 hour before","2 hours before","1 day before","2 days before","1 week before"]; const reminderMethods=["Q Notification","Email","Discord","SMS"]; const initCalEvents=[ {id:"ce1",title:"Trial — Paramount v. City of LA",date:"2026-05-04",time:"09:00",endTime:"17:00",cal:"Paramount",color:"#31588c",location:"LASC Dept. 47",notes:"Trial Day 1. Bring binders.",reminders:[{timing:"1 day before",method:"Email"},{timing:"1 hour before",method:"Q Notification"}],allDay:false,recurring:null}, {id:"ce2",title:"Sanli Depo — Cross Exam",date:"2026-04-10",time:"10:00",endTime:"12:00",cal:"Paramount",color:"#31588c",location:"Schall Firm Conference Room",notes:"Focus on discount rate methodology",reminders:[{timing:"1 day before",method:"Email"},{timing:"15 minutes before",method:"Q Notification"}],allDay:false}, {id:"ce3",title:"Expert Disclosure Deadline",date:"2026-04-07",time:null,endTime:null,cal:"Paramount",color:"#B04040",location:"",notes:"CCP §2034 deadline — Christensen",reminders:[{timing:"2 days before",method:"Email"},{timing:"1 day before",method:"Discord"}],allDay:true}, {id:"ce4",title:"Brooge Hearing — Loss Causation",date:"2026-04-14",time:"14:00",endTime:"15:30",cal:"Brooge",color:"#2E8B57",location:"S.D.N.Y. Courtroom 15B",notes:"",reminders:[{timing:"1 day before",method:"Email"}],allDay:false}, {id:"ce5",title:"File Trial Exhibit List",date:"2026-04-08",time:null,endTime:null,cal:"Paramount",color:"#D97706",location:"",notes:"Via CM/ECF",reminders:[{timing:"1 day before",method:"Q Notification"}],allDay:true}, {id:"ce6",title:"Team Sync",date:"2026-04-05",time:"11:00",endTime:"11:30",cal:"Personal",color:"#6B7280",location:"Zoom",notes:"Weekly standup",reminders:[{timing:"15 minutes before",method:"Q Notification"}],allDay:false,recurring:"weekly"}, {id:"ce7",title:"MIL No. 3 Filing Deadline",date:"2026-04-11",time:null,endTime:null,cal:"Paramount",color:"#B04040",location:"",notes:"Motion in Limine re: Sanli",reminders:[{timing:"2 days before",method:"Email"},{timing:"1 day before",method:"Discord"},{timing:"1 hour before",method:"Q Notification"}],allDay:true}, {id:"ce8",title:"Privilege Log Review",date:"2026-04-09",time:"14:00",endTime:"16:00",cal:"Paramount",color:"#31588c",location:"",notes:"v4 with Bates stamps",reminders:[],allDay:false}, ]; export default function UnifiedWorkspaceV74(){ const idC=useRef(500);const nid=()=>"x"+(++idC.current); // Tabs const [tabs,setTabs]=useState(initTabs);const [tabGroups,setTabGroups]=useState(initGroups); const [activeTabId,setActiveTabId]=useState("t1");const [selectedTabs,setSelectedTabs]=useState(new Set()); const [tabContextMenu,setTabContextMenu]=useState(null);const [newTabDrop,setNewTabDrop]=useState(false); const [dragTabId,setDragTabId]=useState(null);const [groupCtx,setGroupCtx]=useState(null); // V7.4: split screen const [splitMode,setSplitMode]=useState(false);const [splitActiveTabId,setSplitActiveTabId]=useState(null); const [splitFocus,setSplitFocus]=useState("left"); // which pane has focus const [splitWidth,setSplitWidth]=useState(50); // right pane percentage const [splitTabs,setSplitTabs]=useState([]); // tabs in right pane const [splitNewTabDrop,setSplitNewTabDrop]=useState(false); const [splitRightOpen,setSplitRightOpen]=useState(false);const [splitRightTab,setSplitRightTab]=useState("send"); // Browser const [browserOpen,setBrowserOpen]=useState(true);const [browserWidth,setBrowserWidth]=useState(280); const [browserMode,setBrowserMode]=useState("browser"); const [activeScope,setActiveScope]=useState(null);const [activeProjIdx,setActiveProjIdx]=useState(0);const [noProject,setNoProject]=useState(false); const [activeTypes,setActiveTypes]=useState(new Set());const [selectedCollections,setSelectedCollections]=useState(new Set()); const [splitterPos,setSplitterPos]=useState(150);const [selectedIdx,setSelectedIdx]=useState(null); const [browserFolders,setBrowserFolders]=useState(initBrowserFolders);const [expandedFolders,setExpandedFolders]=useState(new Set(["f1"])); const [activeFolder,setActiveFolder]=useState(null);const [hoverFolder,setHoverFolder]=useState(null); const [newFolderMode,setNewFolderMode]=useState(null);const [newFolderName,setNewFolderName]=useState(""); const [deletingFolder,setDeletingFolder]=useState(null); const [searchMode,setSearchMode]=useState("this_view");const [sortKey,setSortKey]=useState("Modified");const [sortDrop,setSortDrop]=useState(false); const [folderOverlay,setFolderOverlay]=useState(false);const [dropTarget,setDropTarget]=useState(null);const [dragItem,setDragItem]=useState(null); const [places,setPlaces]=useState(initPlaces);const [activePlace,setActivePlace]=useState(null);const [placePath,setPlacePath]=useState([]); const [hoverPlace,setHoverPlace]=useState(null);const [placeCollections]=useState([{name:"All",color:null},{name:"Active Cases",color:"#31588c"},{name:"Research",color:"#2E8B57"},{name:"Templates",color:"#D97706"}]);const [placeCollectionFilter,setPlaceCollectionFilter]=useState("All");const [placeCollDrop,setPlaceCollDrop]=useState(false);const [removingPlace,setRemovingPlace]=useState(null); const [activeSavedView,setActiveSavedView]=useState(null);const [userSavedViews,setUserSavedViews]=useState([]); const [saveFromBar,setSaveFromBar]=useState(false);const [saveViewName,setSaveViewName]=useState(""); // Notes browser const [noteFolders,setNoteFolders]=useState(initNoteFolders);const [noteExpandedFolders,setNoteExpandedFolders]=useState(new Set(["nf1"])); const [notes]=useState(initNotes);const [selectedNote,setSelectedNote]=useState("n1"); const [noteSearch,setNoteSearch]=useState("");const [noteSort,setNoteSort]=useState("Modified");const [noteSortDrop,setNoteSortDrop]=useState(false); const [allNotesSort,setAllNotesSort]=useState("Modified");const [allNotesSortDrop,setAllNotesSortDrop]=useState(false); const [noteNewFolderMode,setNoteNewFolderMode]=useState(null);const [noteNewFolderName,setNoteNewFolderName]=useState(""); const [noteHoverFolder,setNoteHoverFolder]=useState(null); const [renamingNoteFolder,setRenamingNoteFolder]=useState(null);const [renamingNoteFolderText,setRenamingNoteFolderText]=useState(""); const [deletingNoteFolder,setDeletingNoteFolder]=useState(null); const [noteSplitterPos,setNoteSplitterPos]=useState(140);const [showArchived,setShowArchived]=useState(false);const [noteContextMenu,setNoteContextMenu]=useState(null); // V7.9.2: Notes browser scope (Notes / To Do / Calendars) const [noteBrowserScope,setNoteBrowserScope]=useState(new Set(["notes","todo","calendars"])); // Bookmarks const [bmExpanded,setBmExpanded]=useState(new Set(["bm1"])); const [bmFolders,setBmFolders]=useState(initBookmarks); const [bmHoverFolder,setBmHoverFolder]=useState(null);const [bmHoverItem,setBmHoverItem]=useState(null); const [bmRenamingFolder,setBmRenamingFolder]=useState(null);const [bmRenamingText,setBmRenamingText]=useState(""); const [bmDeletingFolder,setBmDeletingFolder]=useState(null); const [bmNewFolderMode,setBmNewFolderMode]=useState(null);const [bmNewFolderName,setBmNewFolderName]=useState(""); const [bmRenamingItem,setBmRenamingItem]=useState(null);const [bmRenamingItemText,setBmRenamingItemText]=useState(""); const [bmSearch,setBmSearch]=useState("");const [bmSplitterPos,setBmSplitterPos]=useState(180); // V7.4: bookmarks bar visibility const [bmBarVisible,setBmBarVisible]=useState(true); // Right panel — V7.4: per-tab state const [rightOpen,setRightOpen]=useState(false);const [rightTab,setRightTab]=useState("comments");const [rightWidth,setRightWidth]=useState(290); const [comments,setComments]=useState(initComments);const [activeComment,setActiveComment]=useState(null); 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(""); // V7.4: Simplified Ask panel state const [agentIdx,setAgentIdx]=useState(0);const [agentDrop,setAgentDrop]=useState(false); const [askSendIn,setAskSendIn]=useState("inline"); // inline | existing | new const [askChatIdx,setAskChatIdx]=useState(0);const [askChatDrop,setAskChatDrop]=useState(false); const [askScope,setAskScope]=useState("doc_only"); // doc_only | all_comments | select const [selectedCmIds,setSelectedCmIds]=useState(new Set()); const [askInstruction,setAskInstruction]=useState(""); const [askIncludeClips,setAskIncludeClips]=useState(false); const [askConfigCollapsed,setAskConfigCollapsed]=useState(false); const [agentResponse,setAgentResponse]=useState(null); // Content const [showMarkup,setShowMarkup]=useState(true);const [findBar,setFindBar]=useState(false); const [pinned,setPinned]=useState(false);const [bookmarked,setBookmarked]=useState(false);const [readerMode,setReaderMode]=useState(false); const [openDrop,setOpenDrop]=useState(null);const [bubbleMenu,setBubbleMenu]=useState(null); const [changes,setChanges]=useState(initChanges); // V7.4: doc title right-click menu const [docTitleMenu,setDocTitleMenu]=useState(null); // Blocks 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); const [pickerOpen,setPickerOpen]=useState(false);const [pickerStep,setPickerStep]=useState("choose");const [pickerTab,setPickerTab]=useState("system"); const [customName,setCustomName]=useState("");const [customInstruction,setCustomInstruction]=useState("");const [insertionPoint,setInsertionPoint]=useState(null); const [showDownloads,setShowDownloads]=useState(false); const [chatColumnOpen,setChatColumnOpen]=useState(false); const [sessionMinutes,setSessionMinutes]=useState(47);const [clipsCount,setClipsCount]=useState(2); // V7.4: zoom slider const [zoomLevel,setZoomLevel]=useState(100); // V7.4: floating palette const [fpOpen,setFpOpen]=useState(false);const [fpMode,setFpMode]=useState("chat");const [fpSidebarOpen,setFpSidebarOpen]=useState(false);const [fpSidebarMode,setFpSidebarMode]=useState(null);const [fpPinned,setFpPinned]=useState(false);const [fpSilent,setFpSilent]=useState(false);const [fpNoticeFilter,setFpNoticeFilter]=useState("all");const [fpNotices]=useState([{id:"fn1",source:"Calendar",color:"#D97706",title:"Trial prep deadline tomorrow",desc:"File exhibit list amendment by Apr 7",time:"12m",unread:true,snoozed:false},{id:"fn2",source:"Elnor",color:"#7C3AED",title:"Depo transcript review complete",desc:"Flagged 2 issues in Sanli transcript pp. 40-80",time:"1h",unread:true,snoozed:false},{id:"fn3",source:"Email",color:"#3B82F6",title:"New email from co-counsel",desc:"RE: Christensen expert engagement — action needed",time:"2h",unread:false,snoozed:false},{id:"fn4",source:"System",color:"#6B7280",title:"OneDrive sync restored",desc:"Paramount case files re-synced at 2:45 PM",time:"3h",unread:false,snoozed:false}]); const [fpMessages,setFpMessages]=useState(initFpMessages);const [fpInput,setFpInput]=useState(""); const [fpNoteText,setFpNoteText]=useState("");const [fpCmdSearch,setFpCmdSearch]=useState(""); // V7.9.3: Note selector for palette const [fpSelectedNoteId,setFpSelectedNoteId]=useState("n1");const [fpNoteListDrop,setFpNoteListDrop]=useState(false);const [fpNoteNewMode,setFpNoteNewMode]=useState(false);const [fpNoteNewName,setFpNoteNewName]=useState(""); const [fpScreenCapture,setFpScreenCapture]=useState(false); // V7.9.4: Chat selector for palette const [fpSelectedChatId,setFpSelectedChatId]=useState("quick");const [fpChatListDrop,setFpChatListDrop]=useState(false); const fpChatList=[{id:"quick",name:"Quick Chat",pinned:true,time:"now"},...recentConvos.slice(0,9).map(cv=>({id:cv.id,name:cv.name,pinned:false,time:cv.time,color:cv.color}))]; const [fpChatRenaming,setFpChatRenaming]=useState(false);const [fpChatRenameText,setFpChatRenameText]=useState(""); // V7.6.9: Todo tab state const [fpTodoLists,setFpTodoLists]=useState(initFpTodoLists);const [fpActiveTodoList,setFpActiveTodoList]=useState("tl1"); const [fpTodoNewItem,setFpTodoNewItem]=useState("");const [fpTodoDoneOpen,setFpTodoDoneOpen]=useState(false); const [fpTodoListDrop,setFpTodoListDrop]=useState(false);const [fpTodoNewListMode,setFpTodoNewListMode]=useState(false);const [fpTodoNewListName,setFpTodoNewListName]=useState(""); const [fpTodoRenaming,setFpTodoRenaming]=useState(false);const [fpTodoRenameText,setFpTodoRenameText]=useState(""); const [fpTodoExpanded,setFpTodoExpanded]=useState(new Set());const [fpTodoNewSub,setFpTodoNewSub]=useState({}); const [fpTodoEditingId,setFpTodoEditingId]=useState(null);const [fpTodoEditText,setFpTodoEditText]=useState(""); // V7.6.9: Key capture for shortcut command const [fpKeyCapture,setFpKeyCapture]=useState(false);const [fpCapturedKey,setFpCapturedKey]=useState("⌥Space"); // V7.8: Calendar module state const [calEvents,setCalEvents]=useState(initCalEvents);const [calViewFilter,setCalViewFilter]=useState("All");const [calMode,setCalMode]=useState("Month"); const [calSelectedEvent,setCalSelectedEvent]=useState(null);const [calNewEvent,setCalNewEvent]=useState(null); const [calSettingsOpen,setCalSettingsOpen]=useState(false);const [calSettingsTab,setCalSettingsTab]=useState("instructions"); const [calViewDrop,setCalViewDrop]=useState(false);const [calMonth,setCalMonth]=useState(3);const [calYear,setCalYear]=useState(2026); const [calAgentActive,setCalAgentActive]=useState(true);const [calAgentInstructions,setCalAgentInstructions]=useState("Check my Outlook calendars every 24 hours. Pull any new case deadlines. Add to-do items with due dates. Send me a Discord ping for anything within 48 hours. Include today's events in morning summary."); const [calExcludeFromMaster,setCalExcludeFromMaster]=useState(new Set());const [calOutlookCals,setCalOutlookCals]=useState(outlookCals); const [calSearch,setCalSearch]=useState("");const [calSearchOpen,setCalSearchOpen]=useState(false); const [calCustomViews,setCalCustomViews]=useState([]);const [calNewCalName,setCalNewCalName]=useState("");const [calNewCalMode,setCalNewCalMode]=useState(false); const [calAgentIdx,setCalAgentIdx]=useState(0);const [calModelIdx,setCalModelIdx]=useState(0);const [calThinkLevel,setCalThinkLevel]=useState("standard"); const [calListDays,setCalListDays]=useState(10);const [calListMax,setCalListMax]=useState(20); const [calExcludeMap,setCalExcludeMap]=useState({}); // V7.9: Task date/reminder popover const [taskDatePopover,setTaskDatePopover]=useState(null);// {blockId, taskId} or {listId, taskId} for palette const [taskDateData,setTaskDateData]=useState({date:"",time:"",cal:"",reminders:[]}); const [todoListDefaults,setTodoListDefaults]=useState({cal:"",reminders:[]});const [todoDefaultsOpen,setTodoDefaultsOpen]=useState(false); // V7.9: Palette list-level defaults const [fpTodoDefaultsOpen,setFpTodoDefaultsOpen]=useState(false); // V7.9.1: Standalone tab list selection (shared pool) const [tabTodoListId,setTabTodoListId]=useState("tl1");const [tabTodoListDrop,setTabTodoListDrop]=useState(false); // V7.4: Nav tab groups expanded const [navTabGroupsOpen,setNavTabGroupsOpen]=useState(false); const [toast,setToast]=useState(null); const editorRef=useRef(null);const cmRef=useRef(null);const nfRef=useRef(null); const flash=msg=>setToast(msg);const agent=agents[agentIdx]; const activeTab=tabs.find(t=>t.id===activeTabId)||tabs[0]; const openC=comments.filter(x=>x.status==="open");const resolvedC=comments.filter(x=>x.status==="resolved"); const isNoteType=activeTab.type==="note"||activeTab.type==="clips"; const pendingChanges=changes.filter(x=>x.status==="pending"); const bmBar=bmFolders.find(f=>f.isBar); useEffect(()=>{const iv=setInterval(()=>setSessionMinutes(m=>m+1),60000);return()=>clearInterval(iv)},[]); useEffect(()=>{if(activeTab.type==="note"||activeTab.type==="clips")setBrowserMode("notes");else if(activeTab.type==="web")setBrowserMode("bookmarks");else if(activeTab.type==="chat"||activeTab.type==="utility"||activeTab.type==="todo")setBrowserMode("nav");else setBrowserMode("browser")},[activeTabId]); // V7.4: Reset right panel per-tab (close for utility, reset state for content) useEffect(()=>{setActiveComment(null);setReplyingTo(null);setEditingId(null);setNewCm(null);setNewCmText("");setAgentResponse(null);setAskConfigCollapsed(false);if(activeTab.type==="utility"){setRightOpen(false)}},[activeTabId]); // Open tab with duplicate prevention + transient handling const openTab=(type,title,icon,extra={})=>{ const existing=tabs.find(t=>t.title===title&&t.type===type); if(existing){setActiveTabId(existing.id);flash("Already open — switched to tab");return} if(type==="utility"){const old=tabs.find(t=>t.type==="utility"&&!t.pinned);if(old)setTabs(p=>p.filter(t=>t.id!==old.id))} const id="t"+Date.now();const newTab={id,type,icon,title,color:tabColors[type]||c.neutral,...extra}; if(type==="utility"){setTabs(p=>[newTab,...p])}else{setTabs(p=>[...p,newTab])} setActiveTabId(id);setNewTabDrop(false)}; // Helpers const toggleType=t=>{const s=new Set(activeTypes);s.has(t)?s.delete(t):s.add(t);setActiveTypes(s)}; const toggleCollection=n=>{const s=new Set(selectedCollections);s.has(n)?s.delete(n):s.add(n);setSelectedCollections(s)}; const toggleFolder=id=>{const s=new Set(expandedFolders);s.has(id)?s.delete(id):s.add(id);setExpandedFolders(s)}; const selectScope=s=>{if(activeScope===s){setActiveScope(null);setActiveFolder(null);setActivePlace(null);setPlacePath([])}else{setActiveScope(s);setActiveFolder(null);setActivePlace(null);setPlacePath([])}}; const toggleCmSelect=id=>{const s=new Set(selectedCmIds);s.has(id)?s.delete(id):s.add(id);setSelectedCmIds(s)}; const createBrowserFolder=parent=>{if(!newFolderName.trim())return;setBrowserFolders(p=>[...p,{id:"f"+(p.length+10),title:newFolderName.trim(),parent}]);setNewFolderMode(null);setNewFolderName("");flash("Folder created")}; const deleteBrowserFolder=id=>{setBrowserFolders(p=>p.filter(f=>f.id!==id&&f.parent!==id));setDeletingFolder(null);flash("Folder deleted")}; const removePlace=id=>{setPlaces(p=>p.filter(x=>x.id!==id));setRemovingPlace(null);flash("Place removed")}; const currentPlaceFiles=()=>{const key=placePath.length?placePath[placePath.length-1]:"root";return placeContents[key]||[{name:"(empty)",dimmed:true,type:"—",size:"—",mod:"—"}]}; const createNoteFolder=parent=>{if(!noteNewFolderName.trim())return;setNoteFolders(p=>[...p,{id:"nf"+(p.length+10),title:noteNewFolderName.trim(),parent}]);setNoteNewFolderMode(null);setNoteNewFolderName("");flash("Folder created")}; const renameNoteFolder=(id,name)=>{if(!name.trim())return;setNoteFolders(p=>p.map(f=>f.id===id?{...f,title:name.trim()}:f));setRenamingNoteFolder(null);flash("Renamed")}; const deleteNoteFolder=id=>{setNoteFolders(p=>p.filter(f=>f.id!==id&&f.parent!==id));setDeletingNoteFolder(null);flash("Folder removed (notes kept)")}; const createBmFolder=parent=>{if(!bmNewFolderName.trim())return;setBmFolders(p=>[...p,{id:"bm"+Date.now(),title:bmNewFolderName.trim(),parent,items:[]}]);setBmNewFolderMode(null);setBmNewFolderName("");flash("Bookmark folder created")}; const renameBmFolder=(id,name)=>{if(!name.trim())return;setBmFolders(p=>p.map(f=>f.id===id?{...f,title:name.trim()}:f));setBmRenamingFolder(null);flash("Renamed")}; const deleteBmFolder=id=>{setBmFolders(p=>p.filter(f=>f.id!==id&&f.parent!==id));setBmDeletingFolder(null);flash("Folder deleted")}; const renameBmItem=(folderId,itemId,name)=>{if(!name.trim())return;setBmFolders(p=>p.map(f=>f.id===folderId?{...f,items:f.items.map(i=>i.id===itemId?{...i,title:name.trim()}:i)}:f));setBmRenamingItem(null);flash("Renamed")}; const deleteBmItem=(folderId,itemId)=>{setBmFolders(p=>p.map(f=>f.id===folderId?{...f,items:f.items.filter(i=>i.id!==itemId)}:f));flash("Bookmark deleted")}; 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("")}; // V7.4: Note Block added to module picker const insertBlock=(type,preset)=>{const newId=nid();let block;if(type==="note")block={id:newId,type:"note",title:"Note",collapsed:false,text:""};else if(type==="todo")block={id:newId,type:"todo",title:"To Do",collapsed:false,tasks:[],linkedListId:null};else if(type==="feed"){const p=preset||{name:"Custom Feed"};block={id:newId,type:"feed",title:p.name,collapsed:false,sections:[{key:"custom",icon:"spark",label:p.name,items:[{text:"Waiting for events…",time:"now"}]}]}}else if(type==="thread")block={id:newId,type:"thread",collapsed:false,contextQuote:"",messages:[{id:nid(),author:"You",color:c.accentBtn,body:`@${agent.name} `,time:"now"}]};else if(type==="bar")block={id:newId,type:"bar",title:"New notice",accent:c.warn};else if(type==="calendar")block={id:newId,type:"calendar",title:"Calendar",collapsed:false};else return;setBlocks(p=>[...p,block]);setPickerOpen(false);setPickerStep("choose");flash(`${type} added`)}; 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 addReply=cmId=>{if(!replyText.trim())return;setComments(p=>p.map(cm=>cm.id===cmId?{...cm,replies:[...cm.replies,{id:"r"+Date.now(),author:"You",color:c.accentBtn,body:replyText.trim(),time:"just now"}]}:cm));setReplyingTo(null);setReplyText("")}; const resolveComment=id=>setComments(p=>p.map(cm=>cm.id===id?{...cm,status:"resolved"}:cm)); const reopenComment=id=>setComments(p=>p.map(cm=>cm.id===id?{...cm,status:"open"}:cm)); 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 addComment=()=>{if(!newCmText.trim())return;setComments(p=>[...p,{id:"c"+Date.now(),author:"You",color:c.accentBtn,body:newCmText.trim(),time:"just now",status:"open",anchor:newCm?.text||null,replies:[]}]);setNewCm(null);setNewCmText("")}; const closeTab=id=>{if(tabs.length<=1)return;const idx=tabs.findIndex(t=>t.id===id);setTabs(p=>p.filter(t=>t.id!==id));if(activeTabId===id){const next=tabs[idx===0?1:idx-1];if(next)setActiveTabId(next.id)}}; const addTab=(type,inc=false)=>{const id="t"+Date.now();const t=type==="note"?{id,type:"note",icon:"note",title:"Untitled Note",color:tabColors.note}:type==="doc"?{id,type:"doc",icon:"doc",title:"Open Document…",color:tabColors.doc}:type==="todo"?{id,type:"todo",icon:"todo",title:"New To Do",color:tabColors.todo}:{id,type:"web",icon:"web",title:"New Tab",color:tabColors.web,incognito:inc};setTabs(p=>[...p,t]);setActiveTabId(id);setNewTabDrop(false);flash(inc?"Incognito tab":type==="doc"?"Opening file picker…":type==="todo"?"New To Do":"New "+type)}; const handleTabDrop=targetId=>{if(!dragTabId||dragTabId===targetId)return;setTabs(prev=>{const d=prev.find(t=>t.id===dragTabId);const r=prev.filter(t=>t.id!==dragTabId);const ti=r.findIndex(t=>t.id===targetId);return [...r.slice(0,ti),d,...r.slice(ti)]});setDragTabId(null)}; // V7.4: Ask panel send const handleAskSend=()=>{if(askSendIn==="inline"){setAgentResponse({text:`Based on "${activeTab.title}": The discount rate of 18% lacks comparable transaction support. Three signage transactions show 8-12% average. This is a strong Sargon gatekeeper argument.`,time:"just now"});setAskConfigCollapsed(true);setAskInstruction("")}else if(askSendIn==="new"){openTab("chat",`${activeTab.title} follow-up`,"chat");setAgentResponse(null)}else{flash(`Opening "${chats[askChatIdx].name}"…`)}}; // V7.4: Floating palette send const fpSend=()=>{if(!fpInput.trim())return;const msg={id:"fp"+Date.now(),from:"You",text:fpInput.trim(),time:new Date().toLocaleTimeString([],{hour:"numeric",minute:"2-digit"})};setFpMessages(p=>[...p,msg]);setFpInput("");setTimeout(()=>{setFpMessages(p=>[...p,{id:"fpa"+Date.now(),from:"Elnor",text:"I'll look into that. Let me check the relevant documents and get back to you.",time:new Date().toLocaleTimeString([],{hour:"numeric",minute:"2-digit"})}])},800)}; const fpNewThread=()=>{setFpMessages([]);flash("New thread started")}; // V7.6.9: Todo helpers const fpTodoList=fpTodoLists.find(l=>l.id===fpActiveTodoList)||fpTodoLists[0]; const fpTodoActive=(fpTodoList?.tasks||[]).filter(t=>!t.done);const fpTodoDone=(fpTodoList?.tasks||[]).filter(t=>t.done); const fpToggleTodo=(tid)=>setFpTodoLists(p=>p.map(l=>l.id===fpActiveTodoList?{...l,tasks:l.tasks.map(t=>t.id===tid?{...t,done:!t.done}:t)}:l)); const fpToggleTodoSub=(tid,sid)=>setFpTodoLists(p=>p.map(l=>l.id===fpActiveTodoList?{...l,tasks:l.tasks.map(t=>t.id===tid?{...t,sub:t.sub.map(s=>s.id===sid?{...s,done:!s.done}:s)}:t)}:l)); const fpAddTodo=()=>{if(!fpTodoNewItem.trim())return;setFpTodoLists(p=>p.map(l=>l.id===fpActiveTodoList?{...l,tasks:[...l.tasks,{id:"td"+Date.now(),text:fpTodoNewItem.trim(),done:false,sub:[]}]}:l));setFpTodoNewItem("")}; const fpCreateTodoList=()=>{if(!fpTodoNewListName.trim())return;const id="tl"+Date.now();setFpTodoLists(p=>[...p,{id,name:fpTodoNewListName.trim(),noteId:null,tasks:[]}]);setFpActiveTodoList(id);setFpTodoNewListMode(false);setFpTodoNewListName("");flash("List created (note auto-created)")}; const fpRenameTodoList=()=>{if(!fpTodoRenameText.trim())return;setFpTodoLists(p=>p.map(l=>l.id===fpActiveTodoList?{...l,name:fpTodoRenameText.trim()}:l));setFpTodoRenaming(false);flash("List renamed")}; const fpToggleTodoExp=tid=>{const s=new Set(fpTodoExpanded);s.has(tid)?s.delete(tid):s.add(tid);setFpTodoExpanded(s)}; const fpAddTodoSub=(tid)=>{const text=(fpTodoNewSub[tid]||"").trim();if(!text)return;setFpTodoLists(p=>p.map(l=>l.id===fpActiveTodoList?{...l,tasks:l.tasks.map(t=>t.id===tid?{...t,sub:[...t.sub,{id:"tds"+Date.now(),text,done:false}]}:t)}:l));setFpTodoNewSub(p=>({...p,[tid]:""}))}; const fpAskAboutTask=(text)=>{setFpMode("chat");setFpInput(`Re: "${text}" — `)}; const fpAskAboutList=()=>{const items=fpTodoList.tasks.filter(t=>!t.done).map(t=>t.text).join(", ");setFpMode("chat");setFpInput(`About my "${fpTodoList.name}" list: ${items} — `)}; const fpSaveTodoEdit=(tid)=>{if(!fpTodoEditText.trim()){setFpTodoEditingId(null);return}setFpTodoLists(p=>p.map(l=>l.id===fpActiveTodoList?{...l,tasks:l.tasks.map(t=>t.id===tid?{...t,text:fpTodoEditText.trim()}:t)}:l));setFpTodoEditingId(null)}; const fpDeleteTodo=(tid)=>setFpTodoLists(p=>p.map(l=>l.id===fpActiveTodoList?{...l,tasks:l.tasks.filter(t=>t.id!==tid)}:l)); const fpDeleteTodoSub=(tid,sid)=>setFpTodoLists(p=>p.map(l=>l.id===fpActiveTodoList?{...l,tasks:l.tasks.map(t=>t.id===tid?{...t,sub:t.sub.filter(s=>s.id!==sid)}:t)}:l)); const fpHandleKeyCapture=(e)=>{e.preventDefault();const parts=[];if(e.metaKey)parts.push("⌘");if(e.ctrlKey)parts.push("⌃");if(e.altKey)parts.push("⌥");if(e.shiftKey)parts.push("⇧");if(!["Meta","Control","Alt","Shift"].includes(e.key))parts.push(e.key==="Space"||e.key===" "?"Space":e.key.length===1?e.key.toUpperCase():e.key);if(parts.length>1||(parts.length===1&&!["⌘","⌃","⌥","⇧"].includes(parts[0]))){setFpCapturedKey(parts.join(""));setFpKeyCapture(false);flash("Shortcut set: "+parts.join(""))}}; 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 filtered=useMemo(()=>{let items=[...allItems];if(activeScope==="Project"&&!noProject)items=items.filter(it=>it.proj===projects[activeProjIdx].id);if(activeScope==="Project"&&noProject)items=items.filter(it=>it.proj===null);if(selectedCollections.size>0)items=items.filter(it=>[...selectedCollections].every(col=>it.cols?.includes(col)));if(activeTypes.size>0)items=items.filter(it=>activeTypes.has(it.type));if(sortKey==="Alphabetical")items.sort((a,b)=>a.title.localeCompare(b.title));else if(sortKey==="Type")items.sort((a,b)=>a.type.localeCompare(b.type));else items.sort((a,b)=>timeVal(a.time)-timeVal(b.time));return [...items.filter(x=>x.pin),...items.filter(x=>!x.pin)]},[activeScope,activeProjIdx,noProject,selectedCollections,activeTypes,sortKey]); const filteredNotes=(noteSearch?notes.filter(n=>n.title.toLowerCase().includes(noteSearch.toLowerCase())):notes).sort((a,b)=>{if(a.pinned&&!b.pinned)return -1;if(!a.pinned&&b.pinned)return 1;return timeVal(a.mod)-timeVal(b.mod)}); const renderText=seg=>{const tc=changes.find(x=>x.segId===seg.id&&x.status==="pending");if(!tc||!showMarkup)return {tc&&!showMarkup?seg.v.replace(tc.oldText,tc.newText):seg.v};const idx=seg.v.indexOf(tc.oldText);if(idx===-1)return {seg.v};const ac=tcColors[tc.author]||tcColors.Agent;return {seg.v.slice(0,idx)}{tc.oldText}{tc.newText}{" "}{tc.author}{seg.v.slice(idx+tc.oldText.length)}}; // Comment card — restored from V7.3 const CmCard=({cm,resolved})=>{const isAct=activeComment===cm.id;return
setActiveComment(isAct?null:cm.id)}>
{cm.anchor&&
"{cm.anchor.slice(0,55)}"
}
{cm.author}{cm.time}
{editingId===cm.id?
e.stopPropagation()}>