`); w.document.close(); } // ─── REPORTS ───────────────────────────────────────────────────────────────── function Reports(){ const{C,state,dispatch,entity}=useContext(Ctx); const rptPos=entity==='ALL'?state.active:state.active.filter(p=>p.entity===entity); const rptFMV=rptPos.reduce((a,p)=>a+p.fmv,0); const rptCost=rptPos.reduce((a,p)=>a+p.costBase,0); const [rptType,setRptType]=useState('Monthly Snapshot'); const [audience,setAudience]=useState('LP (External)'); const [quals,setQuals]=useState({execNote:'',gateNote:'',advisoryNote:''}); const [copied,setCopied]=useState(false); const report=useMemo(()=>generateReport(state,entity,rptType,audience,quals),[state,entity,rptType,audience,quals]); const copy=()=>{navigator.clipboard.writeText(report).catch(()=>{});setCopied(true);setTimeout(()=>setCopied(false),2500);}; const [rptTab,setRptTab]=useState('portfolio'); const deals=entity==='ALL'?state.active:state.active.filter(p=>p.entity===entity); const blankUpd={id:null,dealId:deals[0]?.id||'',company:deals[0]?.company||'',entity:deals[0]?.entity||entity,period:'',updateType:'Monthly',revenue:'',arr:'',headcount:'',runway:'',narrative:'',milestones:'',risks:'',nextPriorities:'',companyAsks:'',cioNote:''}; const [updForm,setUpdForm]=useState({...blankUpd}); const [updAud,setUpdAud]=useState('LP (External)'); const [updDoc,setUpdDoc]=useState(''); const [updSaved,setUpdSaved]=useState(false); const [updCopied,setUpdCopied]=useState(false); const savedUpdates=(state.companyUpdates||[]).filter(u=>entity==='ALL'||u.entity===entity); const selDeal=state.active.find(p=>p.id===updForm.dealId)||deals[0]; const genUpd=()=>{if(!updForm.company||!updForm.period)return;setUpdDoc(generateCompanyUpdateDoc(selDeal,updForm,updAud,updForm.entity||entity));}; const saveUpd=()=>{const u={...updForm,id:updForm.id||Date.now(),entity:updForm.entity||entity};dispatch({type:'CUPD_SAVE',u});setUpdSaved(true);setTimeout(()=>setUpdSaved(false),2000);}; const tab=(id,label)=>; return(
📊 Reports
Portfolio reports and company update intake for LP and IC distribution
{tab('portfolio','📊 Portfolio Reports')} {tab('company-update','📥 Company Updates')}
{rptTab==='portfolio'?( <>
{RPT_TYPES.map(t=>())}
{RPT_AUD.map(a=>())}
setQuals({...quals,execNote:e.target.value})} rows={2} placeholder="Add qualitative CIO commentary for this period..."/>
setQuals({...quals,gateNote:e.target.value})} rows={2} placeholder="Specific gate or milestone commentary..."/>
setQuals({...quals,advisoryNote:e.target.value})} placeholder="Additional forward-looking advisory note..."/>
{rptType.toUpperCase()} — {audience.toUpperCase()} — {entity}
{copied?'✓ Copied':'📋 Copy'}printReport(report,entity,rptType,audience,{totalFMV:rptFMV,totalCost:rptCost,mandate:entity!=='ALL'?MANDATES[entity]:null})}>🖨 Print / Export
{report}
):( <> {savedUpdates.length>0&&(
SAVED UPDATES
{[...savedUpdates].sort((a,b)=>b.id-a.id).map(u=>(
{u.company} — {u.period} {u.updateType}
))}
)}
UPDATE DETAILS
setUpdForm({...updForm,period:e.target.value})} placeholder="e.g. Q2 2026 or April 2026" style={{width:'100%',fontSize:12,padding:'7px 10px',borderRadius:6,border:`1px solid ${C.bord}`,background:C.surf2,color:C.text,outline:'none'}}/>
{[['Revenue / GMV','revenue','e.g. $2.1M'],['ARR','arr','e.g. $800K'],['Headcount','headcount','e.g. 24'],['Cash Runway','runway','e.g. 9 months']].map(([label,key,ph])=>(
setUpdForm({...updForm,[key]:e.target.value})} placeholder={ph} style={{width:'100%',fontSize:12,padding:'7px 10px',borderRadius:6,border:`1px solid ${C.bord}`,background:C.surf2,color:C.text,outline:'none'}}/>
))}
OUTPUT & AUDIENCE
{RPT_AUD.map(a=>())}
setUpdForm({...updForm,cioNote:e.target.value})} rows={5} placeholder="Brief CIO commentary to append — context, perspective, anything you want recipients to take away alongside the company's own update..."/>
Generate One-Pager {updSaved?'✓ Saved':'Save Draft'}
setUpdForm({...updForm,narrative:e.target.value})} rows={7} placeholder="Paste the company's update here — founder email, monthly update, board report excerpt, or any written communication from the portfolio company. This forms the core of the generated document..."/>
setUpdForm({...updForm,milestones:e.target.value})} rows={4} placeholder="• Launched v2 product • Signed first enterprise contract • Closed seed extension at $4M..."/> setUpdForm({...updForm,risks:e.target.value})} rows={4} placeholder="• Burn rate elevated — 6 months runway • Key hire still outstanding • Churn uptick in Q2..."/> setUpdForm({...updForm,nextPriorities:e.target.value})} rows={4} placeholder="• Close Series A • Expand to SEA market • Hire VP Sales..."/> setUpdForm({...updForm,companyAsks:e.target.value})} rows={4} placeholder="• Introductions to enterprise procurement contacts • Guidance on cap table structure • Bridge capital consideration..."/>
{updDoc&&(
{updForm.updateType.toUpperCase()} UPDATE — {(updForm.company||'').toUpperCase()} — {updAud.toUpperCase()}
{navigator.clipboard.writeText(updDoc).catch(()=>{});setUpdCopied(true);setTimeout(()=>setUpdCopied(false),2500);}}>{updCopied?'✓ Copied':'📋 Copy'} printCompanyUpdate(selDeal,updForm,updAud,updForm.entity||entity)}>🖨 Print / Export
{updDoc}
)} )}
); } // ─── NEW DEAL ───────────────────────────────────────────────────────────────── function NewDeal(){ const{C,dispatch,entity}=useContext(Ctx); const blank={company:'',entity,sector:'AI/ML',dealType:'VC Seed',geography:'Australia/NZ',stage:'Sourced',costBase:'',fmv:'',holdMonths:'',smsfFlag:false,spv:false,cgtNote:'',notes:''}; const [form,setForm]=useState({...blank}); const [saved,setSaved]=useState(false); const sub=()=>{ if(!form.company)return; dispatch({type:'ADD',deal:{...form,id:Date.now(),costBase:+form.costBase||0,fmv:+form.fmv||+form.costBase||0,holdMonths:+form.holdMonths||0,alerts:[],stress:{exitMult:form.entity==='FLLIP'?20:3,dilution:20,holdYears:5,feeDrag:0,carry:20}}}); setSaved(true);setForm({...blank});setTimeout(()=>setSaved(false),2500); }; const F=(label,key,type='text',opts=null)=>(
{opts?setForm({...form,[key]:type==='checkbox'?e.target.checked:e.target.value})}/>}
); return(
⚡ New Deal
Add a new investment opportunity to the pipeline or portfolio
{F('Company / Fund Name','company')} {F('Entity','entity',null,['FLLIP','TPIF'])} {F('Sector','sector',null,SECTORS)} {F('Deal Type','dealType',null,DEAL_TYPES)} {F('Geography','geography',null,GEOS)} {F('Stage','stage',null,ALL_STAGES)} {F('Cost Base (AUD)','costBase','number')} {F('Initial FMV (AUD)','fmv','number')} {F('Hold Months','holdMonths','number')}
setForm({...form,cgtNote:e.target.value})} placeholder="e.g. CGT discount active — >12mo hold"/>
{[{l:'SMSF Position',k:'smsfFlag'},{l:'SPV Structure',k:'spv'}].map(({l,k})=>( ))}
setForm({...form,notes:e.target.value})} rows={3} placeholder="Investment rationale, key terms, co-investors..."/>
{saved?'✓ Deal Added':'+ Add Deal'}
); } // ─── IPS ───────────────────────────────────────────────────────────────────── function IPS(){ const{C,state,dispatch,entity}=useContext(Ctx); const [text,setText]=useState(state.ips?.[entity]||''); const [saved,setSaved]=useState(false); useEffect(()=>setText(state.ips?.[entity]||''),[entity,state.ips]); const save=()=>{dispatch({type:'IPS_SAVE',key:entity,v:text});setSaved(true);setTimeout(()=>setSaved(false),2000);}; const lastSaved=state.ips?.[entity]?'Document stored — last edit saved':'No document stored yet.'; return(
⚖️ Investment Policy Statement
Proprietary investment mandate and policy document · {entity}
POLICY DOCUMENT — {entity}
{lastSaved}
setText(e.target.value)} rows={28} placeholder={`Enter the Investment Policy Statement for ${entity}...\n\nSuggested sections:\n\n1. INVESTMENT MANDATE & OBJECTIVES\n • Primary return targets (MOIC / IRR)\n • Investment horizon\n • Liquidity requirements\n\n2. ASSET ALLOCATION TARGETS\n • Asset class limits\n • Geographic allocation\n • Sector concentration limits\n\n3. RISK PARAMETERS\n • Maximum position size\n • Portfolio concentration limits\n • Risk rating methodology\n\n4. GOVERNANCE FRAMEWORK\n • IC composition and quorum\n • Decision authority levels\n • Reporting cadence\n\n5. ESG / IMPACT CRITERIA\n • Exclusions\n • Positive screening criteria\n • Impact measurement framework\n\n6. MONITORING & REPORTING\n • Valuation methodology\n • Reporting obligations\n • Review triggers`}/>
{saved?'✓ IPS Saved':'Save IPS'}
); } // ─── APP ────────────────────────────────────────────────────────────────────── function App(){ const [state,dispatch]=useReducer(reducer,null,load); useEffect(()=>{try{localStorage.setItem(SK,JSON.stringify(state));}catch{}},[state]); const [dark,setDark]=useState(true); const [entity,setEntity]=useState('FLLIP'); const [page,setPage]=useState('overview'); const C=useMemo(()=>palette(dark,entity),[dark,entity]); const ctx={state,dispatch,C,dark,setDark,entity,setEntity}; const views={overview:,pipeline:,portfolio:,cgt:,meetings:,memos:,dd:,reports:,'new-deal':,ips:}; return(
{views[page]||}
); } ReactDOM.createRoot(document.getElementById('root')).render();