CIM Generator OpenAI v4 | 360 Biz Brokers
CIM Generator — New CIM
💾 Save
👁 Preview
⬇ Export PDF
📝 Export Word
Quick Start
📄
Cover Info
Name, price, key metrics
✍️
Executive Summary
AI can write this for you
💰
Financials
Revenue, SDE, EBITDA
📸
Upload Photos
Logos & business photos
🤖 AI Connection
The upload and AI writing tools require a working WordPress REST proxy endpoint. If your site returns 404, paste the current proxy URL below and click Save.
📥 Step 1 — Download & Send Intake Form to Seller
Download the 360 Biz Brokers Listing Intake Form. Send it to your seller to complete. Once returned, upload it in Step 2 below and AI will auto-populate all CIM fields.
English Version
Full listing intake • 4 pages • All CIM sections
⬇ Download (English)
Spanish Version / Versión en Español
Formulario completo • 4 páginas • Todas las secciones
⬇ Descargar (Español)
💡 Tip: Save as PDF from your browser's Print dialog (File → Print → Save as PDF) before emailing to the seller.
⚡ Step 2 — Upload Completed Intake & Auto-Fill CIM
Upload a listing intake form, seller questionnaire, or any business document. AI will read it and automatically populate all CIM fields.
📋
Drop one or more listing intake files here
Supports multiple PDFs, Word, Excel/CSV, TXT, and common images. For best browser stability, use optimized files when possible.
Browse Files
📄
✨ Extract & Auto-Fill
✕
Choose CIM Template
CONFIDENTIAL
Business Name
Presented by 360 Biz Brokers
Gold & Black ★
CONFIDENTIAL
Business Name
Investment Overview
Navy Professional
CONFIDENTIAL
Business Name
Presented by Broker
Forest Green
CONFIDENTIAL
Business Name
Luxury Brief
Burgundy Luxury
Know the Listing Broker
Broker Biography
✨ AI:
Improve Wording
Make More Professional
Expand
Executive Summary
Executive Summary
✨ AI:
🪄 Generate from All Data
Improve
Rewrite for Buyers
Make Professional
Summarize
Expand
Business Overview
Business Description
History & Background
Legal Structure
Select... LLC S-Corp C-Corp Sole Proprietorship Partnership
Ownership Type
Select... Single Owner Partnership Family-Owned Absentee-Owned
Hours of Operation
Customer Demographics
Competitive Advantages
Improve Description
Rewrite for Buyers
Expand Advantages
Investment Highlights
Investment Highlights (one per line)
🪄 Generate from Data
Improve
Add More
Location & Market Overview
Location Description & Demographics
🌐 Research Location & Demographics
Improve
Expand
Nearby Demand Drivers / Attractions
Products & Services
Products & Services
Improve
Rewrite for Buyers
Expand
Revenue Mix / Top Revenue Sources
Operations & Staff
Operations Overview
Improve
Make Professional
Staff & Org Notes
Facilities & Lease
Facility & Lease Description
Improve
Make Professional
Financial Summary & Recasted Earnings
Recasted Earnings Notes & Add-Backs
Improve
Make Professional
📊 Financial Documents — AI Auto-Extract
Upload tax returns, P&Ls, or spreadsheets. AI will read the numbers and auto-populate the financial table above. You can upload up to 3 documents (one per year).
✨ Extract Financials from Documents
✕ Clear All
Supports PDF, Word, Excel/CSV, JPG/PNG · Tax returns, P&Ls, QuickBooks exports
Uploaded Documents Preview
These document thumbnails will appear in the printed CIM appendix as source document references.
Competition & Industry Analysis
Competitive Landscape
🌐 Research Competitors
Improve
Industry Analysis & Trends
🌐 Research Industry
Improve
Public Reviews Summary
🌐 Research Public Reviews
Growth Opportunities
Growth Opportunities (one per line)
🪄 Generate from Data
Improve
Add More
Reason for Sale & Transition Support
Reason for Sale
Transition Support Offered
Improve Reason
Improve Transition
Asset List (Included in Sale)
ITEM DESCRIPTION
QTY
FAIR MKT VALUE
+ Add Asset
Asset List Notes
Confidentiality Disclaimer
Disclaimer Text
Additional Appendix Notes
CIM Preview — use Print to save as PDF
🖨 Print / Save PDF
📝 Word
✕ Close
✨ AI Writing Assistant
Processing...
`);
printWin.document.close();
printWin.onload = () => {
setTimeout(() => {
printWin.focus();
printWin.print();
}, 700);
};
}
function buildCIM() {
const t=ST.tpl;
const tc={
1:{bg:'#111111',ac:'#C9A84C',tx:'white',sb:'rgba(255,255,255,0.5)',tf:"'Anton',sans-serif"},
2:{bg:'#1a2744',ac:'#4a90d9',tx:'white',sb:'rgba(255,255,255,0.5)',tf:"'Playfair Display',serif"},
3:{bg:'#1b3a2d',ac:'#5cb87a',tx:'white',sb:'rgba(255,255,255,0.5)',tf:"'Montserrat',sans-serif"},
4:{bg:'#2d0a1e',ac:'#b8436e',tx:'white',sb:'rgba(255,255,255,0.5)',tf:"'Playfair Display',serif"},
}[t];
const bn=g('f-biz-name')||'Business Name';
const bt=g('f-biz-type');
const ap=g('f-asking-price');
const rv=g('f-revenue');
const sd=g('f-sde');
const lc=g('f-location');
const yr=g('f-years');
const bk=g('f-brokerage')||'360 Biz Brokers';
const brn=g('f-broker-name');
const brokerLogoHtml=im('broker-logo')?`
`:`
${bk}
`;
const headerLogo = brokerLogoHtml;
const bizLogoHtml=im('biz-logo')?`
`:'';
const coverPhotoSrc=im('cover-photo')||'';
const badgeKeys=['broker-badge','broker-badge-2','broker-badge-3','broker-badge-4','broker-badge-5'];
const badgeImgs=badgeKeys.map(k=>im(k)).filter(Boolean);
const badgeHtml=badgeImgs.length?``:``;
const brokerPhotoHtml=im('broker-photo')?`
`:`
👤
`;
function tp(text) {
if(!text) return '';
return text.split('\n').filter(l=>l.trim()).map(l=>`
${l.trim()}
`).join('');
}
function tb(text) {
if(!text) return '';
return `
${text.split('\n').filter(l=>l.trim()).map(l=>`▸ ${l.trim().replace(/^[-•*▸]\s*/,'')} `).join('')} `;
}
let pageNo = 1;
function pageChrome(content, opts={}) {
const dark = opts.dark || false;
const noHeader = opts.noHeader || false;
const noFooter = opts.noFooter || false;
const pageClass = opts.className || '';
const pageStyle = opts.style || '';
const num = pageNo++;
return `
${noHeader?'':``}
${content}
${noFooter?'':``}
`;
}
function sec(label, title, body) {
if(!body||!body.trim()) return '';
const content = `${label?`
${label}
`:''}
${title}
${body}
`;
return pageChrome(content);
}
// Cover meta
const metaItems=[['Industry',bt],['Asking Price',ap],['Annual Revenue',rv],['SDE / Owner Benefit',sd],['Location',lc],['Years Established',yr?(yr+' Years'):'']].filter(([,v])=>v);
const coverMeta=metaItems.length?`
${metaItems.map(([k,v])=>`
`).join('')}
`:'';
// KPI grid
const kpis=[[ap,'Asking Price'],[rv,'Annual Revenue'],[sd,'SDE / Owner Benefit'],[yr?yr+' Yrs':'','Years Established']].filter(([v])=>v);
const kpiHtml=kpis.length?`
${kpis.map(([v,l])=>`
`).join('')}
`:'';
// Financial table
const finRows=[['Gross Revenue','f-rev'],['Cost of Goods Sold','f-cogs'],['Gross Profit','f-gp'],['Total Operating Expenses','f-opex'],['Net SDE / Owner Benefit','f-sde']];
const hasFinData=['f-rev1','f-rev2','f-rev3','f-sde1','f-sde2','f-sde3'].some(id=>g(id));
const finTable=hasFinData?`
Financial Metric Year 1 Year 2 Year 3 (Latest) ${finRows.map(([lbl,px],i)=>{const last=i===finRows.length-1;const r1=g(px+'1'),r2=g(px+'2'),r3=g(px+'3');return`${lbl} ${r1||'—'} ${r2||'—'} ${r3||'—'} `}).join('')}
`:'';
// Assets
const assetRows=Array.from(document.querySelectorAll('#asset-rows > div')).map(r=>{const inp=r.querySelectorAll('input');return inp.length>=3?[inp[0].value,inp[1].value,inp[2].value]:null;}).filter(r=>r&&r[0]);
const assetTable=assetRows.length?`
Asset Description Qty FMV ${assetRows.map(([d,q,f])=>`${d} ${q||'1'} ${f||'—'} `).join('')}
`:'';
// Gallery
const gphotos=['p2','p3','p4','p5','p6'].map(k=>im(k)).filter(Boolean);
const gallery=gphotos.length?pageChrome(`
Gallery
Business Photos
${gphotos.slice(0,6).map(s=>`
`).join('')}
`):'';
// Financial body
const finBody=[
kpiHtml,finTable,
g('f-recast')?`
${tp(g('f-recast'))}
`:'',
[g('f-valuation')&&`
Valuation: ${g('f-valuation')}`,g('f-deal')&&`
Deal Structure: ${g('f-deal')}`].filter(Boolean).join('
'),
].filter(Boolean).join('');
// Broker bio
const brokerBio=(g('f-broker-bio')||g('f-broker-fullname'))?pageChrome(`
Your Listing Broker
Know Your Broker
${brokerPhotoHtml}
${g('f-broker-fullname')||brn}
${g('f-broker-title')||'Principal Broker'}
${g('f-broker-phone')?`
${g('f-broker-phone')}
`:''}
${g('f-broker-email')?`
${g('f-broker-email')}
`:''}
${g('f-broker-website')?`
${g('f-broker-website')}
`:''}
${g('f-broker-bio')?`
${tp(g('f-broker-bio'))}
`:''}
`):'';
// Info rows helper
function infoRow(items) {
const filled=items.filter(([,v])=>v);
if(!filled.length) return '';
return `
${filled.map(([k,v])=>`${k}: ${v}`).join(' · ')}
`;
}
const disclosureBody = tp(g('f-disclaimer'));
const coverImageBlock = coverPhotoSrc ? `
` : '';
const coverNum = pageNo++;
return `
${coverImageBlock}
${brokerLogoHtml}
Confidential Information Memorandum
${bn}
${bizLogoHtml?`
${bizLogoHtml}
`:''}
${bt?`
${bt}
`:''}
${coverMeta}
Presented exclusively by ${bk}${brn?' | '+brn:''}
Strictly Confidential
Page ${coverNum}
${disclosureBody?pageChrome(`
Confidentiality
Confidentiality Disclosure
${disclosureBody}
`):''}
${brokerBio}
${sec('','Executive Summary',tp(g('f-exec')))}
${(g('f-biz-desc')||g('f-biz-history'))?sec('The Opportunity','Business Overview',[tp(g('f-biz-desc')),g('f-biz-history')?`
${tp(g('f-biz-history'))}
`:'',infoRow([['Legal',g('f-legal')],['Ownership',g('f-ownership')],['Hours',g('f-hours')]]),g('f-customers')?`
Customer Demographics: ${g('f-customers')}
`:'' ].filter(Boolean).join('')):''}
${g('f-highlights')?sec('Why Buy','Investment Highlights',tb(g('f-highlights'))):''}
${gallery}
${(g('f-loc-desc')||g('f-demand'))?sec('Market','Location & Market Overview',[lc?`
Area: ${lc}
`:'',tp(g('f-loc-desc')),g('f-demand')?`
Nearby Demand Drivers: ${tp(g('f-demand'))}
`:'' ].filter(Boolean).join('')):''}
${(g('f-products')||g('f-rev-mix'))?sec('Offerings','Products & Services',[tp(g('f-products')),g('f-rev-mix')?`
Revenue Mix: ${g('f-rev-mix')}
`:'' ].filter(Boolean).join('')):''}
${(g('f-ops')||g('f-employees'))?sec('How It Runs','Operations & Staff',[infoRow([['Team',g('f-employees')],['Owner Role',g('f-owner-role')],['Key Staff',g('f-mgmt')]]),tp(g('f-ops')),g('f-staff')?`
${tp(g('f-staff'))}
`:'' ].filter(Boolean).join('')):''}
${(g('f-facilities')||g('f-sqft')||g('f-rent'))?sec('The Space','Facilities & Lease',[infoRow([['Size',g('f-sqft')],['Monthly Rent',g('f-rent')],['Lease Exp.',g('f-lease-exp')]]),tp(g('f-facilities'))].filter(Boolean).join('')):''}
${finBody?sec('Performance','Financial Summary & Recasted Earnings',finBody):''}
${(g('f-competition')||g('f-industry')||g('f-reviews'))?sec('The Market','Competition & Industry Analysis',[g('f-competition')?`
Competitive Landscape ${tp(g('f-competition'))}`:'',g('f-industry')?`
Industry Analysis ${tp(g('f-industry'))}`:'',g('f-reviews')?`
Public Reputation ${tp(g('f-reviews'))}`:''].filter(Boolean).join('')):''}
${g('f-growth')?sec('The Upside','Growth Opportunities',tb(g('f-growth'))):''}
${(g('f-reason')||g('f-transition'))?sec('Next Steps','Reason for Sale & Transition',[g('f-reason')?`
Reason for Sale: ${tp(g('f-reason'))}
`:'',g('f-transition')?`
Transition Support: ${tp(g('f-transition'))}
`:'' ].filter(Boolean).join('')):''}
${(assetTable||g('f-asset-notes'))?sec('Included Assets','Asset List',[assetTable,g('f-asset-notes')?tp(g('f-asset-notes')):'' ].filter(Boolean).join('')):''}
${g('f-appendix')?sec('Appendix','Additional Appendix Notes',tp(g('f-appendix'))):''}
`;
}
// ── INTAKE FORM DOWNLOAD ──
function downloadIntakeForm(lang) {
const isES = lang === 'es';
const L = {
title: isES ? 'Formulario de Listado — Cuestionario del Vendedor' : 'Business Listing Intake Form — Seller Questionnaire',
confidential: isES ? 'CONFIDENCIAL' : 'CONFIDENTIAL',
tagline: isES ? 'Complete este formulario y devuélvalo a su corredor. Toda información será mantenida estrictamente confidencial.' : 'Please complete this form and return it to your broker. All information will be kept strictly confidential.',
broker_label: isES ? 'Corredor Asignado' : 'Assigned Broker',
date_label: isES ? 'Fecha' : 'Date',
s1: isES ? 'SECCIÓN 1 — INFORMACIÓN GENERAL DEL NEGOCIO' : 'SECTION 1 — GENERAL BUSINESS INFORMATION',
s2: isES ? 'SECCIÓN 2 — FINANZAS' : 'SECTION 2 — FINANCIALS',
s3: isES ? 'SECCIÓN 3 — OPERACIONES Y PERSONAL' : 'SECTION 3 — OPERATIONS & STAFF',
s4: isES ? 'SECCIÓN 4 — INSTALACIONES Y ARRENDAMIENTO' : 'SECTION 4 — FACILITIES & LEASE',
s5: isES ? 'SECCIÓN 5 — PRODUCTOS Y SERVICIOS' : 'SECTION 5 — PRODUCTS & SERVICES',
s6: isES ? 'SECCIÓN 6 — ACTIVOS INCLUIDOS EN LA VENTA' : 'SECTION 6 — ASSETS INCLUDED IN SALE',
s7: isES ? 'SECCIÓN 7 — RAZÓN DE VENTA Y TRANSICIÓN' : 'SECTION 7 — REASON FOR SALE & TRANSITION',
s8: isES ? 'SECCIÓN 8 — INFORMACIÓN ADICIONAL' : 'SECTION 8 — ADDITIONAL INFORMATION',
disclaimer: isES
? 'Este formulario es estrictamente confidencial y está destinado únicamente para uso interno de 360 Biz Brokers. La información proporcionada se utilizará exclusivamente para la preparación del Memorando de Información Confidencial (CIM).'
: 'This form is strictly confidential and intended solely for internal use by 360 Biz Brokers. Information provided will be used exclusively for preparation of the Confidential Information Memorandum (CIM).',
fields: isES ? {
biz_name: 'Nombre Legal del Negocio', dba: 'Nombre Comercial (DBA)', biz_type: 'Tipo de Negocio / Industria',
founded: 'Año de Fundación', years: 'Años en Operación', address: 'Dirección Completa',
city_state: 'Ciudad, Estado, Código Postal', phone: 'Teléfono del Negocio', website: 'Sitio Web',
legal_structure: 'Estructura Legal (LLC, Corp, etc.)', ein: 'EIN / Número de Identificación Fiscal',
owner_name: 'Nombre del Propietario', owner_phone: 'Teléfono del Propietario', owner_email: 'Correo del Propietario',
asking_price: 'Precio Pedido', price_rationale: 'Justificación del Precio',
rev_yr1: 'Ingresos Brutos — Año 1 ($)', rev_yr2: 'Ingresos Brutos — Año 2 ($)', rev_yr3: 'Ingresos Brutos — Año 3 / Más Reciente ($)',
cogs_yr3: 'Costo de Ventas — Año 3 ($)', opex_yr3: 'Gastos Operativos Totales — Año 3 ($)',
owner_salary: 'Salario del Propietario Incluido en Gastos ($)', sde: 'SDE / Beneficio Neto del Propietario ($)',
addbacks: 'Gastos Adicionales (add-backs) y Gastos Personales', taxes_current: '¿Impuestos al Día?',
employees_ft: 'Empleados de Tiempo Completo', employees_pt: 'Empleados de Tiempo Parcial',
owner_hours: 'Horas del Propietario por Semana', owner_role: 'Rol del Propietario en el Negocio',
key_staff: 'Personal Clave y Sus Roles', staff_staying: '¿El Personal Clave Continuará?',
systems: 'Sistemas / Software / POS Utilizados', suppliers: 'Proveedores Principales',
sqft: 'Metros Cuadrados del Local', rent: 'Renta Mensual ($)', lease_exp: 'Vencimiento del Arrendamiento',
lease_options: 'Opciones de Renovación del Arrendamiento', parking: 'Estacionamiento Disponible',
landlord: 'Relación con el Arrendador', real_estate: '¿Se Incluye Bienes Raíces?',
products_desc: 'Descripción de Productos y/o Servicios', revenue_mix: 'Mezcla de Ingresos (% por línea de producto/servicio)',
customers: 'Perfil del Cliente Principal', contracts: 'Contratos o Clientes Recurrentes',
ffe_desc: 'Describa el FF&E Incluido (muebles, equipos, accesorios)',
inventory: 'Valor Estimado del Inventario ($)', vehicles: 'Vehículos Incluidos',
ip: 'Propiedad Intelectual (marcas, patentes, dominio web)',
reason: 'Razón para Vender', timeline: 'Línea de Tiempo Deseada para Cerrar',
training: 'Capacitación / Soporte de Transición Ofrecido', seller_financing: '¿Considera Financiamiento del Vendedor?',
competition: 'Principales Competidores', advantages: 'Ventajas Competitivas',
growth: 'Oportunidades de Crecimiento', risks: 'Riesgos o Desafíos a Revelar',
pending_legal: 'Litigios Pendientes o Problemas Legales', licenses: 'Licencias y Permisos Requeridos',
other: 'Información Adicional que el Comprador Debe Conocer'
} : {
biz_name: 'Legal Business Name', dba: 'Trade Name / DBA', biz_type: 'Business Type / Industry',
founded: 'Year Founded', years: 'Years in Operation', address: 'Full Business Address',
city_state: 'City, State, Zip Code', phone: 'Business Phone', website: 'Website',
legal_structure: 'Legal Structure (LLC, Corp, etc.)', ein: 'EIN / Federal Tax ID',
owner_name: 'Owner Full Name', owner_phone: 'Owner Phone', owner_email: 'Owner Email',
asking_price: 'Asking Price', price_rationale: 'Basis for Asking Price',
rev_yr1: 'Gross Revenue — Year 1 ($)', rev_yr2: 'Gross Revenue — Year 2 ($)', rev_yr3: 'Gross Revenue — Year 3 / Most Recent ($)',
cogs_yr3: 'Cost of Goods Sold — Year 3 ($)', opex_yr3: 'Total Operating Expenses — Year 3 ($)',
owner_salary: 'Owner Salary Included in Expenses ($)', sde: 'SDE / Net Owner Benefit ($)',
addbacks: 'Add-Back Items & Personal Expenses Run Through Business', taxes_current: 'Are Business Taxes Current?',
employees_ft: 'Full-Time Employees', employees_pt: 'Part-Time Employees',
owner_hours: 'Owner Hours Per Week', owner_role: 'Owner\'s Role in the Business',
key_staff: 'Key Staff Members & Their Roles', staff_staying: 'Will Key Staff Stay Post-Sale?',
systems: 'Systems / Software / POS Used', suppliers: 'Major Suppliers / Vendors',
sqft: 'Total Square Footage', rent: 'Monthly Rent ($)', lease_exp: 'Lease Expiration Date',
lease_options: 'Lease Renewal Options', parking: 'Parking Available',
landlord: 'Landlord Relationship', real_estate: 'Is Real Estate Included in Sale?',
products_desc: 'Description of Products and/or Services Offered', revenue_mix: 'Revenue Mix (% breakdown by product/service line)',
customers: 'Primary Customer Profile / Demographics', contracts: 'Recurring Contracts or Key Accounts',
ffe_desc: 'Describe FF&E Included (furniture, fixtures, equipment)',
inventory: 'Estimated Inventory Value at Time of Sale ($)', vehicles: 'Vehicles Included',
ip: 'Intellectual Property (trademarks, patents, website domain)',
reason: 'Reason for Selling', timeline: 'Desired Closing Timeline',
training: 'Training / Transition Support Offered', seller_financing: 'Open to Seller Financing?',
competition: 'Primary Competitors', advantages: 'Key Competitive Advantages',
growth: 'Untapped Growth Opportunities', risks: 'Known Risks or Challenges to Disclose',
pending_legal: 'Pending Litigation or Legal Issues', licenses: 'Licenses & Permits Required to Operate',
other: 'Any Other Information a Buyer Should Know'
}
};
const F = L.fields;
function row(label, lines=1, hint='') {
const h = lines === 1
? `
`
: `
`;
return `
${label}${hint?` — ${hint} `:''}
${h}
`;
}
function section(num, title, body) {
return `
`;
}
function twoCol(f1, f2, lines=1) {
return `
${row(f1,lines)}${row(f2,lines)}
`;
}
function threeCol(f1, f2, f3) {
return `
${row(f1)}${row(f2)}${row(f3)}
`;
}
const html = `
${L.title} — 360 Biz Brokers
360 Biz Brokers — Listing Intake Form Preview
🖨 Print / Save as PDF
360 BIZ BROKERS
360bizbrokers.com · (954) 325-2625 · val@360bizbrokers.com
${section(1, L.s1, `
${twoCol(F.biz_name, F.dba)}
${twoCol(F.biz_type, F.legal_structure)}
${threeCol(F.founded, F.years, F.ein)}
${row(F.address)}
${twoCol(F.city_state, F.phone)}
${twoCol(F.website, '')}
${threeCol(F.owner_name, F.owner_phone, F.owner_email)}
${twoCol(F.asking_price, F.price_rationale)}
`)}
${section(2, L.s2, `
${threeCol(F.rev_yr1, F.rev_yr2, F.rev_yr3)}
${threeCol(F.cogs_yr3, F.opex_yr3, F.owner_salary)}
${twoCol(F.sde, F.taxes_current)}
${row(F.addbacks, 3, isES?'Describa cada partida y monto':'Describe each item and amount')}
`)}
${section(3, L.s3, `
${threeCol(F.employees_ft, F.employees_pt, F.owner_hours)}
${row(F.owner_role, 2)}
${row(F.key_staff, 3, isES?'Nombre, cargo, salario, años en la empresa':'Name, title, salary, years with company')}
${twoCol(F.staff_staying, F.systems)}
${row(F.suppliers, 2)}
`)}
${section(4, L.s4, `
${threeCol(F.sqft, F.rent, F.lease_exp)}
${twoCol(F.lease_options, F.parking)}
${twoCol(F.landlord, F.real_estate)}
`)}
${section(5, L.s5, `
${row(F.products_desc, 4)}
${row(F.revenue_mix, 2, isES?'ej. 60% comidas, 25% catering':'e.g. 60% dine-in, 25% catering')}
${row(F.customers, 2)}
${row(F.contracts, 2)}
`)}
${section(6, L.s6, `
${row(F.ffe_desc, 4, isES?'Liste los equipos más importantes y su estado':'List major equipment items and condition')}
${threeCol(F.inventory, F.vehicles, F.ip)}
`)}
${section(7, L.s7, `
${row(F.reason, 3)}
${twoCol(F.timeline, F.seller_financing)}
${row(F.training, 3)}
`)}
${section(8, L.s8, `
${row(F.competition, 2)}
${row(F.advantages, 2)}
${row(F.growth, 3)}
${row(F.risks, 2)}
${twoCol(F.pending_legal, F.licenses)}
${row(F.other, 3)}
`)}
${isES?'Firma del Propietario':'Owner Signature'}
${isES?'Nombre impreso y fecha':'Printed name and date'}
${isES?'Firma del Corredor':'Broker Signature'}
${isES?'Nombre impreso y fecha':'Printed name and date'}
360 Biz Brokers — A DBA of Florida 360 Realty, LLC · ${isES?'Todos los derechos reservados':'All rights reserved'} © ${new Date().getFullYear()}
${L.confidential}
${L.disclaimer}
`;
// Open in new window and trigger print
const win = window.open('', '_blank');
win.document.write(html);
win.document.close();
// Small delay so fonts load before print dialog
win.onload = () => setTimeout(() => win.focus(), 400);
}
// ── INTAKE EXTRACTION ──
let intakeFileData = null;
let intakeFileType = null;
let intakeFileName = null;
function handleIntakeUpload(input) {
const file = input.files[0];
if (!file) return;
intakeFileName = file.name;
const sizeMB = (file.size / 1024 / 1024).toFixed(1);
// Show preview bar
document.getElementById('intake-preview-bar').style.display = 'flex';
document.getElementById('intake-filename').textContent = file.name;
document.getElementById('intake-filesize').textContent = sizeMB + ' MB · ' + (file.type || 'document');
// Detect file type
const ext = file.name.split('.').pop().toLowerCase();
const isImage = file.type.startsWith('image/');
const mimeMap = {
pdf: 'application/pdf',
docx: 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
doc: 'application/msword',
txt: 'text/plain',
csv: 'text/csv'
};
intakeFileType = isImage ? file.type : (file.type || mimeMap[ext] || 'application/octet-stream');
const reader = new FileReader();
reader.onload = (e) => {
intakeFileData = e.target.result.split(',')[1];
};
reader.readAsDataURL(file);
// Style the drop zone
const dz = document.getElementById('intake-drop-zone');
dz.style.borderColor = 'var(--gold)';
dz.style.background = 'rgba(201,168,76,0.06)';
}
function clearIntake() {
intakeFileData = null; intakeFileType = null; intakeFileName = null;
document.getElementById('intake-file-input').value = '';
document.getElementById('intake-preview-bar').style.display = 'none';
document.getElementById('intake-status').style.display = 'none';
const dz = document.getElementById('intake-drop-zone');
dz.style.borderColor = 'var(--gold-light)';
dz.style.background = 'rgba(201,168,76,0.04)';
}
async function runIntakeExtraction() {
if (!intakeFileData) { toast('No file loaded','err'); return; }
const statusEl = document.getElementById('intake-status');
statusEl.style.display = 'block';
statusEl.innerHTML = '
AI is reading your intake document and extracting data… this may take 15–30 seconds. ';
const systemPrompt = `You are an expert business broker assistant. You will be given a listing intake form, seller questionnaire, or business document. Extract all available information and return it as a single valid JSON object with these exact keys (use empty string "" if not found):
{
"f-biz-name": "",
"f-biz-type": "",
"f-asking-price": "",
"f-revenue": "",
"f-sde": "",
"f-location": "",
"f-years": "",
"f-brokerage": "",
"f-broker-name": "",
"f-broker-fullname": "",
"f-broker-title": "",
"f-broker-phone": "",
"f-broker-email": "",
"f-broker-website": "",
"f-broker-bio": "",
"f-exec": "",
"f-biz-desc": "",
"f-biz-history": "",
"f-legal": "",
"f-ownership": "",
"f-hours": "",
"f-customers": "",
"f-advantages": "",
"f-address": "",
"f-neighborhood": "",
"f-loc-desc": "",
"f-demand": "",
"f-products": "",
"f-rev-mix": "",
"f-employees": "",
"f-owner-role": "",
"f-ops": "",
"f-staff": "",
"f-sqft": "",
"f-rent": "",
"f-lease-exp": "",
"f-facilities": "",
"f-rev1": "",
"f-rev2": "",
"f-rev3": "",
"f-cogs1": "",
"f-cogs2": "",
"f-cogs3": "",
"f-gp1": "",
"f-gp2": "",
"f-gp3": "",
"f-opex1": "",
"f-opex2": "",
"f-opex3": "",
"f-sde1": "",
"f-sde2": "",
"f-sde3": "",
"f-recast": "",
"f-valuation": "",
"f-deal": "",
"f-competition": "",
"f-industry": "",
"f-growth": "",
"f-reason": "",
"f-transition": "",
"f-asset-notes": "",
"f-highlights": "",
"f-appendix": ""
}
Rules:
- Return ONLY the raw JSON object. No markdown, no backticks, no explanation.
- For financial fields (f-rev1/2/3, f-sde1/2/3, etc.) use the most recently labeled years available.
- For f-highlights and f-growth, format as one item per line.
- For f-legal, use one of: LLC, S-Corp, C-Corp, Sole Proprietorship, Partnership — or leave blank.
- For f-ownership, use one of: Single Owner, Partnership, Family-Owned, Absentee-Owned — or leave blank.
- For f-mgmt, use one of: Yes all key staff staying, Most key staff staying, Varies, Unknown — or leave blank.
- Be comprehensive — extract every piece of information available in the document.`;
try {
// Determine media type and build message content
let msgContent;
if (intakeFileType && intakeFileType.startsWith('image/')) {
msgContent = [
{ type: 'image', source: { type: 'base64', media_type: intakeFileType, data: intakeFileData } },
{ type: 'text', text: 'Extract all business listing information from this intake form image and return as JSON.' }
];
} else {
msgContent = [
{ type: 'document', source: { type: 'base64', media_type: intakeFileType || 'application/octet-stream', filename: intakeFileName || 'uploaded-document', data: intakeFileData } },
{ type: 'text', text: 'Extract all business listing information from this uploaded document and return as JSON.' }
];
}
const payload = {
model: AI_MODEL,
max_tokens: 2000,
system: systemPrompt,
messages: [{ role: 'user', content: msgContent }]
};
const data = await callProxyAI(payload);
const rawText = parseProxyResponse(data);
const extracted = extractJsonObject(rawText);
// Count fields populated
let filled = 0;
Object.entries(extracted).forEach(([k, v]) => {
if (v && v.toString().trim()) {
const el = document.getElementById(k);
if (el) { el.value = v; filled++; }
}
});
updateTopbar();
updateProgress();
saveData();
statusEl.innerHTML = `
✅ Extraction complete — ${filled} fields populated from "${intakeFileName}". Review each section and use AI Assist to refine any content.
`;
toast(`✅ ${filled} fields auto-filled from intake!`);
// Highlight the drop zone
const dz = document.getElementById('intake-drop-zone');
dz.style.borderColor = '#16a34a';
dz.style.background = 'rgba(34,197,94,0.04)';
} catch(err) {
console.error('Intake extraction error:', err);
statusEl.innerHTML = `
❌ Extraction failed: ${err.message}
`;
}
}
// ── FINANCIAL DOCUMENT EXTRACTION ──
const finDocs = { 1: null, 2: null, 3: null };
const finDocTypes = { 1: null, 2: null, 3: null };
const finDocNames = { 1: null, 2: null, 3: null };
const FIN_ICONS = {
pdf: '📄', docx: '📝', doc: '📝',
xlsx: '📊', xls: '📊', csv: '📊',
jpg: '🖼️', jpeg: '🖼️', png: '🖼️', tiff: '🖼️', tif: '🖼️'
};
function handleFinDoc(input, yearNum) {
const file = input.files[0];
if (!file) return;
const ext = file.name.split('.').pop().toLowerCase();
finDocNames[yearNum] = file.name;
const zone = document.getElementById('fin-zone-' + yearNum);
const iconEl = document.getElementById('fin-icon-' + yearNum);
const labelEl = document.getElementById('fin-label-' + yearNum);
const nameEl = document.getElementById('fin-doc-name-' + yearNum);
zone.style.borderColor = 'var(--gold)';
zone.style.background = 'rgba(201,168,76,0.06)';
iconEl.textContent = FIN_ICONS[ext] || '📄';
labelEl.innerHTML = '
' + file.name.substring(0,22) + (file.name.length>22?'…':'') + ' ';
nameEl.textContent = (file.size/1024).toFixed(0) + ' KB';
nameEl.style.display = 'block';
const isWord = ext === 'docx' || ext === 'doc';
const isImg = file.type.startsWith('image/');
finDocTypes[yearNum] = isWord ? 'docx' : (ext === 'pdf' ? 'application/pdf' : (isImg ? file.type : (ext === 'csv' || ext === 'xlsx' || ext === 'xls' ? 'spreadsheet' : 'application/pdf')));
const reader = new FileReader();
if (isWord || ext === 'xlsx' || ext === 'xls' || ext === 'csv') {
reader.onload = (e) => {
const bytes = new Uint8Array(e.target.result);
let bin = '';
bytes.forEach(b => bin += String.fromCharCode(b));
finDocs[yearNum] = btoa(bin);
updateFinImgPreviews();
};
reader.readAsArrayBuffer(file);
} else {
reader.onload = (e) => {
finDocs[yearNum] = e.target.result.split(',')[1];
finDocTypes[yearNum] = isImg ? file.type : 'application/pdf';
updateFinImgPreviews();
};
reader.readAsDataURL(file);
}
}
function updateFinImgPreviews() {
const previewSection = document.getElementById('fin-img-previews');
const grid = document.getElementById('fin-img-grid');
const hasAny = Object.values(finDocNames).some(n => n);
if (!hasAny) { previewSection.style.display = 'none'; return; }
previewSection.style.display = 'block';
grid.innerHTML = '';
[1, 2, 3].forEach(yr => {
if (!finDocNames[yr]) return;
const ext = finDocNames[yr].split('.').pop().toLowerCase();
const isImg = ['jpg','jpeg','png','tiff','tif','gif','webp'].includes(ext);
const cell = document.createElement('div');
cell.style.cssText = 'border:1px solid var(--g200);border-radius:var(--r);overflow:hidden;background:var(--g50)';
if (isImg && finDocs[yr]) {
// Show actual image preview
cell.innerHTML = '
'
+ '
Year ' + yr + ' — ' + finDocNames[yr].substring(0,20) + '
';
} else {
// Show a styled doc tile
const icon = FIN_ICONS[ext] || '📄';
cell.innerHTML = '
'
+ '
' + icon + '
'
+ '
' + finDocNames[yr].substring(0,22) + (finDocNames[yr].length>22?'…':'') + '
'
+ '
'
+ '
Year ' + yr + (yr===3?' (Latest)':'') + '
';
}
grid.appendChild(cell);
});
}
function clearFinDocs() {
[1,2,3].forEach(yr => {
finDocs[yr]=null; finDocTypes[yr]=null; finDocNames[yr]=null;
const inp = document.getElementById('fin-file-'+yr);
if (inp) inp.value='';
const zone = document.getElementById('fin-zone-'+yr);
if (zone) { zone.style.borderColor='var(--g200)'; zone.style.background='var(--g50)'; }
const icon = document.getElementById('fin-icon-'+yr);
if (icon) icon.textContent='📂';
const lbl = document.getElementById('fin-label-'+yr);
if (lbl) lbl.innerHTML = 'Tax Return / P&L
Year ' + yr + (yr===3?' / Latest':'');
const nm = document.getElementById('fin-doc-name-'+yr);
if (nm) nm.style.display='none';
});
document.getElementById('fin-img-previews').style.display='none';
document.getElementById('fin-extract-status').style.display='none';
}
async function runFinExtraction() {
const hasAny = Object.values(finDocs).some(d => d);
if (!hasAny) { toast('Upload at least one financial document first','err'); return; }
const statusEl = document.getElementById('fin-extract-status');
statusEl.style.display='block';
statusEl.innerHTML='
AI is reading your financial documents and extracting numbers… this may take 20–40 seconds. ';
const finSysPrompt = `You are an expert business broker and CPA assistant. You will be given one or more financial documents (tax returns, P&Ls, income statements, spreadsheets). Extract the key financial figures for each year and return ONLY a valid JSON object with these exact keys. Use empty string "" if not found. Format all dollar amounts with $ and commas (e.g. "$485,000").
{
"f-rev1": "",
"f-rev2": "",
"f-rev3": "",
"f-cogs1": "",
"f-cogs2": "",
"f-cogs3": "",
"f-gp1": "",
"f-gp2": "",
"f-gp3": "",
"f-opex1": "",
"f-opex2": "",
"f-opex3": "",
"f-sde1": "",
"f-sde2": "",
"f-sde3": "",
"f-recast": "",
"f-valuation": "",
"year1_label": "",
"year2_label": "",
"year3_label": ""
}
Rules:
- year1_label/year2_label/year3_label should be the actual year (e.g. "2022", "2023", "2024").
- f-rev = Gross Revenue / Total Sales / Total Income
- f-cogs = Cost of Goods Sold / Cost of Sales / Direct Costs
- f-gp = Gross Profit (Revenue minus COGS)
- f-opex = Total Operating Expenses (excluding COGS)
- f-sde = Seller's Discretionary Earnings / Net Income + owner compensation + depreciation + amortization + other add-backs
- f-recast = Summarize any add-back items found (owner salary, personal expenses, depreciation, one-time items)
- For multiple documents assign year numbers based on the document's tax year or date
- Return ONLY raw JSON, no markdown, no explanation`;
try {
// Build message content with all uploaded docs
const msgContent = [];
const yearLabels = ['first','second','third'];
[1,2,3].forEach((yr, i) => {
if (!finDocs[yr]) return;
const ft = finDocTypes[yr] || 'application/pdf';
const isImg = ft.startsWith('image/');
if (isImg) {
msgContent.push({ type:'image', source:{ type:'base64', media_type:ft, data:finDocs[yr] } });
} else {
msgContent.push({ type:'document', source:{ type:'base64', media_type:ft || 'application/octet-stream', filename:finDocNames[yr] || ('financial-year-' + yr), data:finDocs[yr] } });
}
msgContent.push({ type:'text', text:'The ' + yearLabels[i] + ' document above corresponds to Year ' + yr + '.' });
});
msgContent.push({ type:'text', text:'Extract all financial figures from these documents and return as JSON.' });
const payload = {
model:AI_MODEL, max_tokens:1500,
system:finSysPrompt,
messages:[{ role:'user', content:msgContent }]
};
const data = await callProxyAI(payload);
const rawText = parseProxyResponse(data);
const extracted = extractJsonObject(rawText);
const finFields = ['f-rev1','f-rev2','f-rev3','f-cogs1','f-cogs2','f-cogs3','f-gp1','f-gp2','f-gp3','f-opex1','f-opex2','f-opex3','f-sde1','f-sde2','f-sde3','f-recast','f-valuation'];
let filled = 0;
finFields.forEach(k => {
if (extracted[k] && extracted[k].trim()) {
const el = document.getElementById(k);
if (el) { el.value = extracted[k]; filled++; }
}
});
// Update year column headers if we got labels
const headers = document.querySelectorAll('#panel-s-financials table thead th');
if (headers.length >= 4) {
if (extracted.year1_label) headers[1].textContent = extracted.year1_label;
if (extracted.year2_label) headers[2].textContent = extracted.year2_label;
if (extracted.year3_label) headers[3].textContent = extracted.year3_label + ' (Latest)';
}
updateProgress();
saveData();
statusEl.innerHTML='
✅ Extracted ' + filled + ' financial values from ' + Object.values(finDocNames).filter(Boolean).length + ' document(s). Review the table above and adjust any figures as needed.
';
toast('✅ ' + filled + ' financial fields populated!');
} catch(err) {
console.error(err);
statusEl.innerHTML='
❌ Extraction failed: ' + err.message + '
';
}
}
// Drag-and-drop support for intake zone
document.addEventListener('DOMContentLoaded', () => {
const dz = document.getElementById('intake-drop-zone');
if (!dz) return;
dz.addEventListener('dragover', e => { e.preventDefault(); dz.style.borderColor='var(--gold)'; dz.style.background='rgba(201,168,76,0.1)'; });
dz.addEventListener('dragleave', () => { dz.style.borderColor='var(--gold-light)'; dz.style.background='rgba(201,168,76,0.04)'; });
dz.addEventListener('drop', e => {
e.preventDefault();
const file = e.dataTransfer.files[0];
if (file) {
const inp = document.getElementById('intake-file-input');
// Create a DataTransfer to assign file
const dt = new DataTransfer(); dt.items.add(file); inp.files = dt.files;
handleIntakeUpload(inp);
}
});
});
// Spin animation for intake loader
const spinStyle = document.createElement('style');
spinStyle.textContent = '@keyframes spin{to{transform:rotate(360deg)}}';
document.head.appendChild(spinStyle);
/* =========================
v12 CIM PRINT LAYOUT OVERRIDE
- clean 8.5x11 pages
- integrated cover image
- section-by-section page breaks
- working page numbers
- stable preview/PDF
========================= */
function cimEsc(v){return (v||'').toString().replace(/[&<>"']/g,m=>({'&':'&','<':'<','>':'>','"':'"',"'":'''}[m]));}
function cimParas(v){return (v||'').split('\n').map(x=>x.trim()).filter(Boolean).map(x=>`
${cimEsc(x)}
`).join('');}
function cimBullets(v){return (v||'').split('\n').map(x=>x.trim()).filter(Boolean).map(x=>x.replace(/^[-•*▸]\s*/,'')).map(x=>`
${cimEsc(x)} `).join('');}
function cimMoney(v){return cimEsc(v||'—');}
function buildCIM(){
const tc={bg:'#111111',ac:'#C9A84C',tx:'#fff',muted:'#6b7280'};
const bn=g('f-biz-name')||'Business Name';
const bt=g('f-biz-type');
const ap=g('f-asking-price');
const rv=g('f-revenue');
const sd=g('f-sde');
const lc=g('f-location');
const yr=g('f-years');
const bk=g('f-brokerage')||'360 Biz Brokers';
const brokerLogo=im('broker-logo');
const bizLogo=im('biz-logo');
const coverPhoto=im('cover-photo');
const brokerPhoto=im('broker-photo');
const badges=['broker-badge','broker-badge-2','broker-badge-3','broker-badge-4','broker-badge-5'].map(k=>im(k)).filter(Boolean);
let pageNo=0;
const totalPlaceholder='{{TOTAL_PAGES}}';
const brokerLogoTag=brokerLogo?`
`:`
${cimEsc(bk)}
`;
const footerBadges=badges.length?badges.map(s=>`
`).join(''):'';
function page(label,title,body,cls=''){
pageNo++;
return `
${cimEsc(label||'')}
${cimEsc(title||'')}
${body}
`;
}
function infoGrid(items){
const rows=items.filter(x=>x[1]);
if(!rows.length) return '';
return `
${rows.map(([k,v])=>`
${cimEsc(k)} ${cimEsc(v)}
`).join('')}
`;
}
function noteBox(html){return html?`
${html}
`:'';}
const defaultDisclosure=`This is a confidential memorandum intended solely for your own use in considering whether to pursue negotiations to acquire this business.\n\nThis confidential document contains selected pertaining to the Business and has been prepared by the Listing Broker from information supplied by the Owner. It does not purport to be all-inclusive or to contain all the information which a prospective purchaser may desire or deem relevant in determining whether to acquire the Business. Neither the Owner, nor the Listing Broker, nor any of their respective owners, directors, employees, representatives, or agents make any representation or warranty expressed or implied as to the accuracy or completeness of this confidential document or any of its contents and no legal liability is assumed or to be implied with respect thereto. The Owner reserves the right to withdraw the Business from the market or change the terms of offering at any time and will have no legal obligation unless and until written agreements have been approved and executed by all parties involved in the purchase of the Business. This document is provided subject to errors, omission, prior sale, change of price or terms, and other changes in the information and is subject to modification or withdrawal without notice.\n\nThe contents herein are confidential and are not to be reproduced or distributed to another party without prior written consent of The Listing Broker. Recipient(s) of this document recognize(s) that this proposed sale is a highly confidential undertaking, and that the Owner’s intent to sell, or execution of an agreement to sell, if disclosed or discussed publicly prior to closing, could cause irreparable damage to the Owner’s Business. Accordingly, all facts, information, discussions (written or verbal), reports by paper, facsimile, or digital media (computer disks, email, etc.) given to Recipient relating to this proposed sale shall be kept absolutely private and confidential. No reproduction, distribution, or public discussion is authorized without written permission of The Listing Broker.\n\nRecipients of this document who do not honor this confidentiality requirement could face punitive damages associated with a breach of confidentiality. This information is provided strictly on a need-to-know basis and should not be discussed with anyone beyond the Recipient’s immediate Business Associates who have a need to know to properly evaluate this opportunity, including CPA and other advisor. Confidentiality requirements apply to anyone in Recipient’s immediate business organization who has access to any information relating to this proposed sale. If, after reviewing the following information you decide not to pursue the purchase further, please return all information received to Listing Broker.`;
const disclosure=g('f-disclaimer')||defaultDisclosure;
const meta=infoGrid([['Industry',bt],['Asking Price',ap],['Annual Revenue',rv],['SDE / Owner Benefit',sd],['Location',lc],['Years Established',yr]]);
let pages=[];
pageNo++;
pages.push(`
Confidential Information Memorandum
${cimEsc(bn)}
${bizLogo?`
`:''}
${bt?`
${cimEsc(bt)}
`:''}
Presented exclusively by ${cimEsc(bk)}
${coverPhoto?`
`:''}
${brokerLogoTag}
`);
pages.push(page('Confidentiality','Confidentiality Disclosure',`
${cimParas(disclosure)}
`));
const brokerBody=`
${brokerPhoto?`
`:''}
${cimEsc(g('f-broker-fullname')||g('f-broker-name')||'Listing Broker')} ${cimEsc(g('f-broker-title')||'Principal Broker')} ${g('f-broker-phone')?`
📞 ${cimEsc(g('f-broker-phone'))}
`:''}${g('f-broker-email')?`
✉️ ${cimEsc(g('f-broker-email'))}
`:''}${g('f-broker-website')?`
🌐 ${cimEsc(g('f-broker-website'))}
`:''}
${cimParas(g('f-broker-bio'))}
`;
if(g('f-broker-bio')||g('f-broker-fullname')||g('f-broker-name')) pages.push(page('Your Listing Broker','Know Your Broker',brokerBody));
if(g('f-exec')) pages.push(page('Executive Summary','Executive Summary',`
${cimParas(g('f-exec'))}
`));
const overview=[cimParas(g('f-biz-desc')),cimParas(g('f-biz-history')),infoGrid([['Legal Structure',g('f-legal')],['Ownership',g('f-ownership')],['Hours',g('f-hours')],['Customers',g('f-customers')]]),g('f-advantages')?`
Competitive Advantages ${cimParas(g('f-advantages'))}`:''].filter(Boolean).join('');
if(overview) pages.push(page('The Opportunity','Business Overview',`
${overview}
`));
if(g('f-highlights')) pages.push(page('Why Buy','Investment Highlights',`
${cimBullets(g('f-highlights'))} `));
const market=[infoGrid([['Area',lc],['Address',g('f-address')],['Neighborhood',g('f-neighborhood')]]),cimParas(g('f-loc-desc')),g('f-demand')?`
Nearby Demand Drivers ${cimParas(g('f-demand'))}`:''].filter(Boolean).join('');
if(market) pages.push(page('Market','Location & Market Overview',`
${market}
`));
const products=[cimParas(g('f-products')),g('f-rev-mix')?noteBox(`
Revenue Mix: ${cimEsc(g('f-rev-mix'))}`):''].filter(Boolean).join('');
if(products) pages.push(page('Offerings','Products & Services',`
${products}
`));
const ops=[infoGrid([['Team',g('f-employees')],['Owner Role',g('f-owner-role')],['Key Staff',g('f-mgmt')]]),cimParas(g('f-ops')),cimParas(g('f-staff'))].filter(Boolean).join('');
if(ops) pages.push(page('How It Runs','Operations & Staff',`
${ops}
`));
const facilities=[infoGrid([['Square Feet',g('f-sqft')],['Monthly Rent',g('f-rent')],['Lease Expiration',g('f-lease-exp')]]),cimParas(g('f-facilities'))].filter(Boolean).join('');
if(facilities) pages.push(page('The Space','Facilities & Lease',`
${facilities}
`));
const hasFin=['f-rev1','f-rev2','f-rev3','f-cogs1','f-cogs2','f-cogs3','f-gp1','f-gp2','f-gp3','f-opex1','f-opex2','f-opex3','f-sde1','f-sde2','f-sde3'].some(id=>g(id));
const finTable=hasFin?`
Financial Metric Year 1 Year 2 Year 3 / Latest ${[['Gross Revenue','f-rev'],['Cost of Goods Sold','f-cogs'],['Gross Profit','f-gp'],['Operating Expenses','f-opex'],['Net SDE / Owner Benefit','f-sde']].map(([lbl,p],i)=>`${lbl} ${cimMoney(g(p+'1'))} ${cimMoney(g(p+'2'))} ${cimMoney(g(p+'3'))} `).join('')}
`:'';
const kpis=`
${[['Asking Price',ap],['Annual Revenue',rv],['SDE / Owner Benefit',sd],['Years Established',yr]].filter(x=>x[1]).map(([k,v])=>`
${cimEsc(k)} ${cimEsc(v)}
`).join('')}
`;
const finBody=`${kpis}${finTable}${g('f-recast')?noteBox(cimParas(g('f-recast'))):''}
${g('f-valuation')?`
Valuation: ${cimEsc(g('f-valuation'))}
`:''}${g('f-deal')?`
Deal Structure: ${cimEsc(g('f-deal'))}
`:''}
`;
if(ap||hasFin||g('f-valuation')||g('f-deal')) pages.push(page('Performance','Financial Summary & Recasted Earnings',finBody));
const comp=[g('f-competition')?`
Competitive Landscape ${cimParas(g('f-competition'))}`:'',g('f-industry')?`
Industry Analysis ${cimParas(g('f-industry'))}`:'',g('f-reviews')?`
Public Reputation ${cimParas(g('f-reviews'))}`:''].filter(Boolean).join('');
if(comp) pages.push(page('The Market','Competition & Industry Analysis',`
${comp}
`));
if(g('f-growth')) pages.push(page('The Upside','Growth Opportunities',`
${cimBullets(g('f-growth'))} `));
const transition=[g('f-reason')?`
Reason for Sale ${cimParas(g('f-reason'))}`:'',g('f-transition')?`
Transition Support ${cimParas(g('f-transition'))}`:''].filter(Boolean).join('');
if(transition) pages.push(page('Next Steps','Reason for Sale & Transition',`
${transition}
`));
const assetRows=Array.from(document.querySelectorAll('#asset-rows > div')).map(r=>{const ins=r.querySelectorAll('input');return ins.length>=3?[ins[0].value,ins[1].value,ins[2].value]:null}).filter(r=>r&&r[0]);
const assetTable=assetRows.length?`
Asset Qty Value ${assetRows.map(r=>`${cimEsc(r[0])} ${cimEsc(r[1]||'1')} ${cimEsc(r[2]||'—')} `).join('')}
`:'';
if(assetTable||g('f-asset-notes')) pages.push(page('Included Assets','Asset List',`${assetTable}
${cimParas(g('f-asset-notes'))}
`));
let html=`
${pages.join('')}
`;
html=html.replaceAll(totalPlaceholder,String(pageNo));
return html;
}
function showPreview(){
try{
updateProgress();
const doc=document.getElementById('cim-doc');
doc.innerHTML=buildCIM();
document.getElementById('preview-overlay').classList.add('open');
}catch(err){console.error(err); alert('Preview failure: '+err.message);}
}
function printCIM(){
try{
const w=window.open('','_blank');
const css=document.getElementById('cim-v12-styles')?.textContent || '';
w.document.open();
w.document.write(`
CIM Export ${buildCIM()}`);
w.document.close();
w.onload=()=>setTimeout(()=>{w.focus();w.print();},700);
}catch(err){console.error(err); alert('PDF export failure: '+err.message);}
}
(function(){
const st=document.createElement('style');
st.id='cim-v12-styles';
st.textContent=`
.cim-v12{font-family:'Lato',Arial,sans-serif;background:#e5e5e5;color:#111;}
.cim-page{width:8.5in;min-height:11in;margin:0 auto 24px;background:#fff;position:relative;box-shadow:0 10px 35px rgba(0,0,0,.18);display:flex;flex-direction:column;break-after:page;page-break-after:always;overflow:hidden;}
.cim-page:last-child{break-after:auto;page-break-after:auto;}
.cim-header{height:.62in;display:flex;align-items:center;justify-content:space-between;padding:0 .62in;border-bottom:1px solid #eee;flex:0 0 .62in;}
.page-logo{max-height:.38in;max-width:1.75in;object-fit:contain}.page-logo-text{font-weight:900;color:#C9A84C;letter-spacing:1px}.cim-small-label,.section-kicker{text-transform:uppercase;letter-spacing:.16em;font-size:10px;font-weight:900;color:#C9A84C;}
.cim-content{padding:.44in .62in .34in;flex:1 1 auto;overflow:hidden}.cim-content h1{font-size:28px;line-height:1.1;margin:6px 0 8px;font-weight:900}.cim-content h2{font-size:15px;margin:18px 0 8px;font-weight:900}.rule{height:2px;background:#111;margin:0 0 22px}.body-copy{font-size:13.5px;line-height:1.62}.body-copy p{margin:0 0 12px}.executive-copy{font-size:12.8px;line-height:1.53}.disclosure-box{background:#f8f7f2;border-left:4px solid #C9A84C;padding:24px 28px;border-radius:8px;font-size:12.2px;line-height:1.48}.disclosure-box p{margin:0 0 12px}
.cim-footer{height:.52in;display:flex;align-items:center;gap:12px;padding:0 .62in;border-top:1px solid #eee;flex:0 0 .52in}.badge-row{display:flex;gap:8px;align-items:center;flex:1}.badge-row img{max-height:.28in;max-width:.82in;object-fit:contain}.conf-foot{font-size:8px;letter-spacing:.18em;text-transform:uppercase;color:#777}.page-num{font-size:9px;letter-spacing:.08em;text-transform:uppercase;color:#555;white-space:nowrap}
.cover-page{background:#111;color:#fff;display:grid;grid-template-columns:56% 44%;height:11in;min-height:11in}.cover-left{padding:1.75in .62in .85in;position:relative}.cover-right{position:relative;overflow:hidden;background:#222}.cover-right>img{width:100%;height:100%;object-fit:cover;display:block}.cover-logo-wrap{position:absolute;top:.55in;right:.46in;background:rgba(0,0,0,.55);padding:14px}.cover-logo-wrap .page-logo{max-height:.82in;max-width:1.45in}.cover-tag{display:inline-block;border:1px solid rgba(201,168,76,.5);color:#C9A84C;font-size:10px;letter-spacing:.22em;text-transform:uppercase;padding:8px 14px;border-radius:4px;margin-bottom:28px}.cover-left h1{font-size:43px;line-height:1.08;margin:0 0 16px;font-weight:900}.biz-logo-cover{max-height:.78in;max-width:2.95in;background:#fff;padding:5px;margin:0 0 18px;display:block}.cover-subtitle{font-size:14px;line-height:1.45;color:#ddd;margin-bottom:22px}.gold-line{width:.62in;height:3px;background:#C9A84C;margin:0 0 22px}.cover-meta{display:grid;grid-template-columns:1fr 1fr;gap:16px 22px}.cover-meta span,.info-grid span,.kpi-row span{display:block;text-transform:uppercase;letter-spacing:.16em;font-size:9px;color:#C9A84C;font-weight:900}.cover-meta strong{display:block;color:#fff;font-size:14px;line-height:1.35;margin-top:4px}.cover-presented{position:absolute;left:.62in;bottom:.85in;color:#aaa;font-size:10px;letter-spacing:.06em}.cover-footer{position:absolute;left:.62in;right:.62in;bottom:.28in;border-top:1px solid rgba(255,255,255,.25);padding-top:12px;display:flex;justify-content:space-between;font-size:8px;text-transform:uppercase;letter-spacing:.18em;color:#999;grid-column:1/3}
.broker-card{display:grid;grid-template-columns:120px 1fr;gap:22px;align-items:center;border-left:4px solid #C9A84C;background:#fff;border-radius:10px;box-shadow:0 0 0 1px #eee;padding:20px;margin-bottom:22px}.broker-photo{width:92px;height:92px;border-radius:50%;object-fit:cover;border:3px solid #C9A84C}.broker-card h2{font-size:22px;margin:0 0 3px}.broker-card h3{font-size:12px;color:#C9A84C;letter-spacing:.12em;text-transform:uppercase;margin:0 0 8px}.broker-card p{margin:2px 0;font-size:13px}.info-grid{display:grid;grid-template-columns:repeat(2,1fr);gap:10px;margin:14px 0}.info-grid div{background:#f8f7f2;border-radius:6px;padding:10px 12px}.info-grid strong{display:block;font-size:12.5px;margin-top:4px}.highlight-list{list-style:none;margin:0;padding:0;font-size:14px;line-height:1.52}.highlight-list li{position:relative;padding:9px 0 9px 22px;border-bottom:1px solid #eee}.highlight-list li:before{content:'▸';position:absolute;left:0;color:#C9A84C;font-weight:900}.note-box{background:#f8f7f2;border-left:4px solid #C9A84C;border-radius:6px;padding:14px 18px;margin:16px 0;font-size:13px;line-height:1.55}.kpi-row{display:grid;grid-template-columns:repeat(4,1fr);gap:12px;margin-bottom:20px}.kpi-row div{background:#111;color:#fff;border-radius:8px;padding:16px;text-align:center}.kpi-row strong{display:block;font-size:17px;margin-top:8px;color:#fff}.fin-table{width:100%;border-collapse:collapse;font-size:12px;margin:14px 0 18px}.fin-table th{background:#111;color:#C9A84C;text-transform:uppercase;letter-spacing:.08em;font-size:10px;text-align:left;padding:10px}.fin-table td{border-bottom:1px solid #eee;padding:10px}.fin-table td:not(:first-child),.fin-table th:not(:first-child){text-align:right}.fin-table .total td{font-weight:900;background:#f8f7f2;border-top:2px solid #C9A84C}
@media print{ @page{size:letter;margin:0} html,body{margin:0!important;padding:0!important;background:#fff!important;-webkit-print-color-adjust:exact!important;print-color-adjust:exact!important}.cim-v12{background:#fff!important}.cim-page{margin:0!important;box-shadow:none!important;width:8.5in!important;height:11in!important;min-height:11in!important;max-height:11in!important;overflow:hidden!important}.no-print,.preview-controls,#sidebar,.topbar{display:none!important} }
`;
document.head.appendChild(st);
})();
/* =========================
v16 SAFETY + FEATURE OVERRIDE
Implements multi-file intake, section attachments, additional notes,
generic AI assist, IndexedDB saving, Word export, richer bullets,
editable financial labels/extra rows, photos/media, appendix and disclaimer.
========================= */
const CIM_SECTIONS_V16 = [
['s-broker','Broker Bio'],['s-exec','Executive Summary'],['s-overview','Business Overview'],['s-highlights','Investment Highlights'],
['s-location','Location & Market'],['s-products','Products / Services'],['s-operations','Operations & Staff'],['s-facilities','Facilities & Lease'],
['s-financials','Financials & Recast'],['s-competition','Competition & Industry'],['s-growth','Growth & Transition'],['s-assets','Asset List'],['s-appendix','Appendix & Disclaimer']
];
ST.sectionFiles = ST.sectionFiles || {};
ST.mediaFiles = ST.mediaFiles || [];
let intakeFilesV16 = [];
function v16FileIcon(name,type){const e=(name||'').split('.').pop().toLowerCase(); if((type||'').startsWith('image/')) return '🖼️'; if(e==='pdf') return '📄'; if(['doc','docx'].includes(e)) return '📝'; if(['xls','xlsx','csv'].includes(e)) return '📊'; if((type||'').startsWith('video/')) return '🎬'; return '📎';}
function v16Bytes(n){if(!n) return '0 KB'; const u=['B','KB','MB','GB']; let i=0,x=n; while(x>1024&&i
{const r=new FileReader(); r.onload=()=>res(r.result); r.onerror=rej; r.readAsDataURL(file);});}
function fileToBase64(file){return new Promise((res,rej)=>{const r=new FileReader(); r.onload=()=>res(String(r.result).split(',')[1]||''); r.onerror=rej; r.readAsDataURL(file);});}
function addSectionExtras(){
CIM_SECTIONS_V16.forEach(([pid,label])=>{
const panel=document.getElementById('panel-'+pid); if(!panel || panel.querySelector('.v16-extra-card')) return;
const card=document.createElement('div'); card.className='card v16-extra-card';
card.innerHTML=`Additional Content / Notes + Supporting Files
Additional Content / Notes
✨ Generic AI Assist for These Notes • Add Bullet
Section Image / Supporting File Placeholder
Accepted: common image formats and PDFs. Image files can appear in the report; PDFs are listed as supporting files.
`;
panel.appendChild(card);
});
const photosPanel=document.getElementById('panel-s-photos');
if(photosPanel && !photosPanel.querySelector('.v16-media-card')){
const card=document.createElement('div'); card.className='card v16-media-card';
card.innerHTML=`Business Photos, Videos & Related Media
Dedicated media section for photos, videos, and related media files. Photos can be shown in the report. Videos and large media are listed as supporting files so PDF generation remains stable.
`;
photosPanel.appendChild(card);
}
const finPanel=document.getElementById('panel-s-financials');
if(finPanel && !document.getElementById('v16-add-fin-row')){
const btn=document.createElement('button'); btn.id='v16-add-fin-row'; btn.className='btn btn-outline btn-sm'; btn.style.marginBottom='14px'; btn.textContent='+ Add Custom Financial Row'; btn.onclick=addCustomFinRow;
const table=finPanel.querySelector('table'); if(table) table.parentElement.appendChild(btn);
makeFinancialLabelsEditable();
}
}
function makeFinancialLabelsEditable(){
const labels=['Gross Revenue','Cost of Goods Sold','Gross Profit','Total Operating Expenses','Net SDE / Owner Benefit'];
document.querySelectorAll('#panel-s-financials tbody tr').forEach((tr,i)=>{const td=tr.querySelector('td'); if(!td || td.querySelector('input')) return; td.innerHTML=` `;});
}
function addCustomFinRow(){
const tbody=document.querySelector('#panel-s-financials tbody'); if(!tbody) return; const i=tbody.querySelectorAll('tr').length;
const tr=document.createElement('tr'); tr.className='v16-custom-fin-row';
tr.innerHTML=`
`;
tbody.appendChild(tr);
}
async function handleSectionFiles(input,pid){
ST.sectionFiles[pid]=ST.sectionFiles[pid]||[];
for(const file of Array.from(input.files||[])){
const rec={name:file.name,type:v16ExtMime(file),size:file.size,icon:v16FileIcon(file.name,file.type)};
if(file.type.startsWith('image/')) rec.dataUrl=await fileToDataURL(file); else rec.dataUrl='';
ST.sectionFiles[pid].push(rec);
}
renderSectionFileList(pid); saveData();
}
function renderSectionFileList(pid){const el=document.getElementById('x-file-list-'+pid); if(!el) return; const arr=ST.sectionFiles[pid]||[]; el.innerHTML=arr.map((f,i)=>`${f.icon} ${escapeHtml(f.name)} (${v16Bytes(f.size)}) remove `).join(' '); const lab=document.getElementById('x-file-label-'+pid); if(lab&&arr.length) lab.innerHTML='✅'+arr.length+' file(s) attached ';}
function removeSectionFile(pid,i){(ST.sectionFiles[pid]||[]).splice(i,1); renderSectionFileList(pid); saveData();}
async function handleMediaFiles(input){
for(const file of Array.from(input.files||[])){const rec={name:file.name,type:v16ExtMime(file),size:file.size,icon:v16FileIcon(file.name,file.type)}; if(file.type.startsWith('image/')) rec.dataUrl=await fileToDataURL(file); ST.mediaFiles.push(rec);} renderMediaList(); saveData();
}
function renderMediaList(){const el=document.getElementById('x-media-list'); if(!el) return; el.innerHTML=(ST.mediaFiles||[]).map((f,i)=>`${f.icon} ${escapeHtml(f.name)} (${v16Bytes(f.size)}) remove `).join(' ');}
function removeMediaFile(i){ST.mediaFiles.splice(i,1); renderMediaList(); saveData();}
function insertBullet(id){const el=document.getElementById(id); if(!el) return; const start=el.selectionStart||el.value.length; const prefix=(start===0||el.value[start-1]=='\n')?'• ':'\n• '; el.setRangeText(prefix,start,start,'end'); el.focus();}
function genericAIForField(fieldId){
ST.aiField=fieldId; document.getElementById('ai-modal').classList.add('open');
document.getElementById('ai-status').className='smsg info'; document.getElementById('ai-status').innerHTML='Describe what you want AI to do:';
document.getElementById('ai-result').style.display='block'; document.getElementById('ai-result').innerHTML=``;
document.getElementById('ai-apply-btn').style.display='inline-flex'; document.getElementById('ai-apply-btn').textContent='Run Generic AI'; document.getElementById('ai-apply-btn').onclick=runGenericAI;
}
async function runGenericAI(){
const task=(document.getElementById('generic-ai-task')||{}).value||''; const fld=ST.aiField; const cur=g(fld);
if(!task.trim()){toast('Please enter an AI instruction','err'); return;}
document.getElementById('ai-status').className='smsg info'; document.getElementById('ai-status').textContent='⏳ AI is processing...';
try{ST.aiResult=dedupeText(await callAI('You are a helpful CIM assistant. Complete the user task. Preserve bullets where useful. Return only the finished content.',`Task: ${task}\n\nCurrent section text:\n${cur}\n\nRelevant CIM context:\n${ctx()}`));
document.getElementById('ai-result').textContent=ST.aiResult; document.getElementById('ai-apply-btn').textContent='Apply to Field'; document.getElementById('ai-apply-btn').onclick=applyAi;
document.getElementById('ai-status').textContent='✅ Review the result:';
}catch(e){document.getElementById('ai-status').className='smsg error'; document.getElementById('ai-status').textContent='❌ '+e.message;}
}
const _aiAssistV15 = aiAssist;
aiAssist = async function(fieldId, action){ await _aiAssistV15(fieldId, action); if(ST.aiResult) ST.aiResult=dedupeText(ST.aiResult); };
function dedupeText(t){const lines=String(t||'').split('\n'); const out=[]; let prev=''; for(const l of lines){const k=l.trim(); if(k && k===prev) continue; out.push(l); if(k) prev=k;} return out.join('\n').trim();}
function applyAi(){ if(ST.aiField&&ST.aiResult){const el=document.getElementById(ST.aiField); if(el) el.value=dedupeText(ST.aiResult); closeAiModal(); document.getElementById('ai-apply-btn').textContent='Apply to Field'; document.getElementById('ai-apply-btn').onclick=applyAi; toast('AI content applied ✓'); updateProgress(); saveData();}}
handleIntakeUpload = async function(input){
const files=Array.from(input.files||[]); if(!files.length) return; intakeFilesV16=[]; document.getElementById('intake-preview-bar').style.display='flex';
for(const file of files){intakeFilesV16.push({name:file.name,type:v16ExtMime(file),size:file.size,data:await fileToBase64(file)});}
document.getElementById('intake-filename').textContent=files.length===1?files[0].name:(files.length+' files selected');
document.getElementById('intake-filesize').textContent=files.map(f=>f.name+' ('+v16Bytes(f.size)+')').join(' · ');
const dz=document.getElementById('intake-drop-zone'); dz.style.borderColor='var(--gold)'; dz.style.background='rgba(201,168,76,0.06)';
};
clearIntake = function(){intakeFilesV16=[]; intakeFileData=null; intakeFileType=null; intakeFileName=null; const i=document.getElementById('intake-file-input'); if(i) i.value=''; document.getElementById('intake-preview-bar').style.display='none'; document.getElementById('intake-status').style.display='none';};
runIntakeExtraction = async function(){
if(!intakeFilesV16.length && intakeFileData){intakeFilesV16=[{name:intakeFileName,type:intakeFileType,size:0,data:intakeFileData}];}
if(!intakeFilesV16.length){toast('No file loaded','err'); return;}
const statusEl=document.getElementById('intake-status'); statusEl.style.display='block'; statusEl.innerHTML='AI is reading '+intakeFilesV16.length+' intake file(s). This can take 20–60 seconds depending on size.
';
const keys=['f-biz-name','f-biz-type','f-asking-price','f-revenue','f-sde','f-location','f-years','f-brokerage','f-broker-name','f-broker-fullname','f-broker-title','f-broker-phone','f-broker-email','f-broker-website','f-broker-bio','f-exec','f-biz-desc','f-biz-history','f-legal-entity','f-legal','f-ownership','f-hours','f-customers','f-advantages','f-address','f-neighborhood','f-loc-desc','f-demand','f-products','f-rev-mix','f-employees','f-owner-role','f-ops','f-staff','f-sqft','f-rent','f-lease-exp','f-facilities','f-rev1','f-rev2','f-rev3','f-cogs1','f-cogs2','f-cogs3','f-gp1','f-gp2','f-gp3','f-opex1','f-opex2','f-opex3','f-sde1','f-sde2','f-sde3','f-recast','f-valuation','f-deal','f-competition','f-industry','f-growth','f-reason','f-transition','f-asset-notes','f-highlights','f-appendix'];
const schema='{\n'+keys.map(k=>' "'+k+'": ""').join(',\n')+'\n}';
const systemPrompt='You are an expert business broker assistant. Extract all CIM/listing information from all uploaded files. Return ONLY one valid JSON object using exactly these keys. Preserve bullet points as one item per line where applicable. Use empty string if not found. JSON schema: '+schema;
const content=[];
intakeFilesV16.forEach((f,i)=>{ if((f.type||'').startsWith('image/')) content.push({type:'image',source:{type:'base64',media_type:f.type,data:f.data}}); else content.push({type:'document',source:{type:'base64',media_type:f.type,filename:f.name,data:f.data}}); content.push({type:'text',text:'File '+(i+1)+': '+f.name}); });
content.push({type:'text',text:'Extract the complete CIM data from all files into the requested JSON.'});
try{const data=await callProxyAI({model:AI_MODEL,max_tokens:3000,system:systemPrompt,messages:[{role:'user',content}]}); const extracted=extractJsonObject(parseProxyResponse(data)); let filled=0; Object.entries(extracted).forEach(([k,v])=>{if(v&&String(v).trim()){const el=document.getElementById(k); if(el){el.value=String(v); filled++;}}}); updateTopbar(); updateProgress(); saveData(); statusEl.innerHTML='✅ Extraction complete — '+filled+' fields populated from '+intakeFilesV16.length+' file(s).
'; toast('✅ '+filled+' fields auto-filled!');}
catch(err){statusEl.innerHTML='❌ Extraction failed: '+escapeHtml(err.message)+'
';}
};
function openDB(){return new Promise((res,rej)=>{const r=indexedDB.open('cim360_v16_db',1); r.onupgradeneeded=()=>r.result.createObjectStore('projects'); r.onsuccess=()=>res(r.result); r.onerror=()=>rej(r.error);});}
async function dbPut(k,v){const db=await openDB(); return new Promise((res,rej)=>{const tx=db.transaction('projects','readwrite'); tx.objectStore('projects').put(v,k); tx.oncomplete=()=>res(); tx.onerror=()=>rej(tx.error);});}
async function dbGet(k){const db=await openDB(); return new Promise((res,rej)=>{const tx=db.transaction('projects','readonly'); const rq=tx.objectStore('projects').get(k); rq.onsuccess=()=>res(rq.result); rq.onerror=()=>rej(rq.error);});}
saveData = async function(){
const data={}; document.querySelectorAll('input[type=text],input[type=email],input[type=number],textarea,select').forEach(el=>{ if(el.id) data[el.id]=el.value; });
data._tpl=ST.tpl; data._imgs=ST.imgs; data._sectionFiles=ST.sectionFiles; data._mediaFiles=ST.mediaFiles;
try{await dbPut('autosave',data); localStorage.setItem('cim360_small_marker',JSON.stringify({savedAt:new Date().toISOString(),biz:g('f-biz-name')})); toast('Progress saved ✓');}
catch(e){try{localStorage.setItem('cim360_fields_only',JSON.stringify({...data,_imgs:{},_sectionFiles:{},_mediaFiles:[]})); downloadProjectBackup(data); toast('Browser storage is full. Downloaded a project backup instead.','err');}catch(_){toast('Save failed. Use Export Word/PDF before closing.','err');}}
};
loadData = async function(){
try{let data=await dbGet('autosave'); if(!data){const raw=localStorage.getItem('cim360')||localStorage.getItem('cim360_fields_only'); if(raw) data=JSON.parse(raw);} if(!data) return;
Object.keys(data).forEach(k=>{ if(k==='_tpl'){selectTemplate(data[k]); return;} if(k==='_imgs'){ST.imgs=data[k]||{}; Object.keys(ST.imgs).forEach(ik=>{const img=document.getElementById('img-'+ik),ph=document.getElementById('ph-'+ik); if(img){img.src=ST.imgs[ik]; img.style.display='block';} if(ph) ph.style.display='none';}); return;} if(k==='_sectionFiles'){ST.sectionFiles=data[k]||{}; return;} if(k==='_mediaFiles'){ST.mediaFiles=data[k]||[]; return;} const el=document.getElementById(k); if(el) el.value=data[k]; });
CIM_SECTIONS_V16.forEach(([pid])=>renderSectionFileList(pid)); renderMediaList(); updateTopbar(); updateProgress();}
catch(e){console.warn('Load failed',e);}
};
function downloadProjectBackup(data){const blob=new Blob([JSON.stringify(data,null,2)],{type:'application/json'}); const a=document.createElement('a'); a.href=URL.createObjectURL(blob); a.download=(g('f-biz-name')||'CIM_Project')+'_backup.json'; a.click(); setTimeout(()=>URL.revokeObjectURL(a.href),1000);}
function v16Esc(v){return String(v||'').replace(/[&<>"']/g,m=>({'&':'&','<':'<','>':'>','"':'"',"'":'''}[m]));}
function renderRich(v){
const lines=String(v||'').split('\n'); let html='', inUl=false;
for(let raw of lines){let l=raw.trim(); if(!l){if(inUl){html+=''; inUl=false;} continue;} const isBullet=/^([•\-*▸]|\d+[.)])\s+/.test(l); if(isBullet){if(!inUl){html+=''; inUl=true;} html+=''+v16Esc(l.replace(/^([•\-*▸]|\d+[.)])\s+/,''))+' ';} else {if(inUl){html+=' '; inUl=false;} html+=''+v16Esc(l)+'
';}}
if(inUl) html+=''; return html;
}
function sectionExtrasHtml(pid){const note=renderRich(g('x-note-'+pid)); const files=ST.sectionFiles[pid]||[]; const imgs=files.filter(f=>f.dataUrl); const pdfs=files.filter(f=>!f.dataUrl); let h=''; if(note) h+=''; if(imgs.length) h+=''+imgs.map(f=>'
'+v16Esc(f.name)+' ').join('')+'
'; if(pdfs.length) h+='Supporting Files: '+pdfs.map(f=>f.icon+' '+v16Esc(f.name)+' ('+v16Bytes(f.size)+')').join(' ')+'
'; return h;}
function infoGrid(items){items=items.filter(x=>x[1]); return items.length?''+items.map(([k,v])=>'
'+v16Esc(k)+' '+v16Esc(v)+'
').join('')+'
':'';}
function reportSection(pid,kicker,title,body){body=(body||'')+sectionExtrasHtml(pid); if(!body.trim()) return ''; return `${v16Esc(kicker)}
${pageLogoHTML()}${v16Esc(kicker)}
${v16Esc(title)}
${body}
`;}
function pageLogoHTML(){const logo=im('broker-logo'); return logo?` `:`${v16Esc(g('f-brokerage')||'360 Biz Brokers')} `;}
function footerHTML(){const imgs=['broker-badge','broker-badge-2','broker-badge-3','broker-badge-4','broker-badge-5'].map(k=>im(k)).filter(Boolean); return `${imgs.map(s=>'
').join('')}
STRICTLY CONFIDENTIAL
`;}
buildCIM = function(){
const bn=g('f-biz-name')||'Business Name', bt=g('f-biz-type'), bk=g('f-brokerage')||'360 Biz Brokers';
const cover=im('cover-photo'), blogo=im('biz-logo');
let pages=[];
pages.push(`Confidential Information Memorandum
${v16Esc(bn)} ${blogo?`
`:''}${bt?`
${v16Esc(bt)}
`:''}
${infoGrid([['Industry',bt],['Asking Price',g('f-asking-price')],['Annual Revenue',g('f-revenue')],['SDE / Owner Benefit',g('f-sde')],['Location',g('f-location')],['Years Established',g('f-years')]])}
Presented exclusively by ${v16Esc(bk)}
${cover?`
`:''}
${pageLogoHTML()}
`);
if(g('f-disclaimer')) pages.push(reportSection('s-appendix','Confidentiality','Confidentiality Disclosure',`${renderRich(g('f-disclaimer'))}
`));
const broker=[im('broker-photo')?` `:'👤
',`${v16Esc(g('f-broker-fullname')||g('f-broker-name'))} ${v16Esc(g('f-broker-title')||'Listing Broker')} ${v16Esc(g('f-broker-phone'))}
${v16Esc(g('f-broker-email'))}
${v16Esc(g('f-broker-website'))}
`].join('');
if(g('f-broker-bio')||g('f-broker-fullname')||g('f-broker-name')) pages.push(reportSection('s-broker','Your Listing Broker','Know Your Broker',`${broker}
${renderRich(g('f-broker-bio'))}`));
pages.push(reportSection('s-exec','Executive Summary','Executive Summary',renderRich(g('f-exec'))));
pages.push(reportSection('s-overview','The Opportunity','Business Overview',`${renderRich(g('f-biz-desc'))}${renderRich(g('f-biz-history'))}${infoGrid([['Legal Entity Name',g('f-legal-entity')],['Legal Structure',g('f-legal')],['Ownership',g('f-ownership')],['Hours',g('f-hours')],['Customers',g('f-customers')]])}${g('f-advantages')?'Competitive Advantages '+renderRich(g('f-advantages')):''}`));
pages.push(reportSection('s-highlights','Why Buy','Investment Highlights',g('f-highlights')?''+String(g('f-highlights')).split('\n').filter(Boolean).map(x=>''+v16Esc(x.replace(/^[-•*▸]\s*/,''))+' ').join('')+' ':''));
pages.push(reportSection('s-location','Market','Location & Market Overview',`${infoGrid([['Area',g('f-location')],['Address',g('f-address')],['Neighborhood',g('f-neighborhood')]])}${renderRich(g('f-loc-desc'))}${g('f-demand')?'Demand Drivers '+renderRich(g('f-demand')):''}`));
pages.push(reportSection('s-products','Offerings','Products & Services',`${renderRich(g('f-products'))}${g('f-rev-mix')?'Revenue Mix / Top Revenue Sources '+renderRich(g('f-rev-mix')):''}`));
pages.push(reportSection('s-operations','How It Runs','Operations & Staff',`${infoGrid([['Team',g('f-employees')],['Owner Role',g('f-owner-role')],['Key Management',g('f-mgmt')]])}${renderRich(g('f-ops'))}${renderRich(g('f-staff'))}`));
pages.push(reportSection('s-facilities','The Space','Facilities & Lease',`${infoGrid([['Square Feet',g('f-sqft')],['Monthly Rent',g('f-rent')],['Lease Expiration',g('f-lease-exp')]])}${renderRich(g('f-facilities'))}`));
const baseLabels=['Gross Revenue','Cost of Goods Sold','Gross Profit','Operating Expenses','Net SDE / Owner Benefit']; const prefixes=['f-rev','f-cogs','f-gp','f-opex','f-sde'];
let rows=prefixes.map((p,i)=>[g('fin-label-'+i)||baseLabels[i],g(p+'1'),g(p+'2'),g(p+'3')]); document.querySelectorAll('.v16-custom-fin-row').forEach((tr,i)=>{const ins=tr.querySelectorAll('input'); if(ins[0]?.value) rows.push([ins[0].value,ins[1]?.value,ins[2]?.value,ins[3]?.value]);});
const finTable=''+[['Asking Price',g('f-asking-price')],['Annual Revenue',g('f-revenue')],['SDE / Owner Benefit',g('f-sde')],['Years Established',g('f-years')]].filter(x=>x[1]).map(([k,v])=>`
${v16Esc(k)} ${v16Esc(v)}
`).join('')+'
Financial Metric Year 1 Year 2 Year 3 / Latest '+rows.map((r,i)=>`${v16Esc(r[0])} ${v16Esc(r[1]||'—')} ${v16Esc(r[2]||'—')} ${v16Esc(r[3]||'—')} `).join('')+'
';
pages.push(reportSection('s-financials','Performance','Financial Summary & Recasted Earnings',`${finTable}${renderRich(g('f-recast'))}${g('f-valuation')?'Valuation: '+v16Esc(g('f-valuation'))+'
':''}${g('f-deal')?'Deal Structure: '+v16Esc(g('f-deal'))+'
':''}`));
pages.push(reportSection('s-competition','The Market','Competition & Industry Analysis',`${g('f-competition')?'Competitive Landscape '+renderRich(g('f-competition')):''}${g('f-industry')?'Industry Analysis '+renderRich(g('f-industry')):''}${g('f-reviews')?'Public Reputation '+renderRich(g('f-reviews')):''}`));
pages.push(reportSection('s-growth','The Upside','Growth Opportunities',`${g('f-growth')?''+String(g('f-growth')).split('\n').filter(Boolean).map(x=>''+v16Esc(x.replace(/^[-•*▸]\s*/,''))+' ').join('')+' ':''}${g('f-reason')?'Reason for Sale '+renderRich(g('f-reason')):''}${g('f-transition')?'Transition Support '+renderRich(g('f-transition')):''}`));
const assetRows=Array.from(document.querySelectorAll('#asset-rows > div')).map(r=>{const ins=r.querySelectorAll('input');return ins.length>=3?[ins[0].value,ins[1].value,ins[2].value]:null}).filter(r=>r&&r[0]);
const assets=assetRows.length?'Asset Qty Value '+assetRows.map(r=>`${v16Esc(r[0])} ${v16Esc(r[1]||'1')} ${v16Esc(r[2]||'—')} `).join('')+'
':'';
pages.push(reportSection('s-assets','Included Assets','Asset List',assets+renderRich(g('f-asset-notes'))));
const photoKeys=['cover-photo','p2','p3','p4','p5','p6']; const photoImgs=photoKeys.map(k=>im(k)).filter(Boolean).map((s,i)=>({dataUrl:s,name:i?'Business Photo '+(i+1):'Cover / Hero Photo'})); const mediaImgs=(ST.mediaFiles||[]).filter(f=>f.dataUrl); const mediaOther=(ST.mediaFiles||[]).filter(f=>!f.dataUrl);
const pics=[...photoImgs,...mediaImgs]; let picBody=''; if(pics.length) picBody+=''+pics.map(f=>`
${v16Esc(f.name)} `).join('')+'
'; if(mediaOther.length) picBody+='Videos / Related Media Files: '+mediaOther.map(f=>f.icon+' '+v16Esc(f.name)+' ('+v16Bytes(f.size)+')').join(' ')+'
';
pages.push(reportSection('s-photos','Media','Pictures of the Business',picBody));
pages.push(reportSection('s-appendix','Appendix','Appendix',renderRich(g('f-appendix'))));
pages.push(reportSection('s-appendix','Broker Disclaimer','Broker’s Disclaimer',`${renderRich(g('f-disclaimer'))}
`));
return ''+pages.filter(Boolean).join('')+'
';
};
showPreview = function(){updateProgress(); document.getElementById('cim-doc').innerHTML=buildCIM(); document.getElementById('preview-overlay').classList.add('open');};
printCIM = function(){const w=window.open('','_blank'); const css=document.getElementById('cim-v16-styles').textContent; w.document.write(`CIM Export ${buildCIM()}`); w.document.close(); w.onload=()=>setTimeout(()=>{w.focus();w.print();},600);};
function exportWordCIM(){const css=document.getElementById('cim-v16-styles').textContent; const html=`${buildCIM()}`; const blob=new Blob(['\ufeff',html],{type:'application/msword'}); const a=document.createElement('a'); a.href=URL.createObjectURL(blob); a.download=(g('f-biz-name')||'CIM_Report').replace(/[^a-z0-9]+/gi,'_')+'.doc'; a.click(); setTimeout(()=>URL.revokeObjectURL(a.href),1000);}
(function(){
const st=document.createElement('style'); st.id='cim-v16-styles'; st.textContent=`
*{box-sizing:border-box;-webkit-print-color-adjust:exact!important;print-color-adjust:exact!important}.cim-v16{font-family:'Lato',Arial,sans-serif;color:#111;background:#e5e5e5}.cim-page{width:8.5in;min-height:11in;margin:0 auto 24px;background:#fff;position:relative;display:flex;flex-direction:column;page-break-after:always;break-after:page;box-shadow:0 10px 35px rgba(0,0,0,.18);overflow:visible}.cim-page:last-child{page-break-after:auto;break-after:auto}.cim-page>header{height:.62in;display:flex;align-items:center;justify-content:space-between;padding:0 .62in;border-bottom:1px solid #eee;flex:0 0 .62in}.cim-page>header>div:first-child,.kicker{font-size:10px;text-transform:uppercase;letter-spacing:.18em;color:#C9A84C;font-weight:900}.page-logo{max-height:.38in;max-width:1.75in;object-fit:contain}.page-logo-text{color:#C9A84C;font-weight:900;letter-spacing:.08em}.cim-page>main{padding:.44in .62in .5in;flex:1}.cim-page h1{font-size:29px;line-height:1.1;margin:6px 0 8px;font-weight:900}.rule{height:2px;background:#111;margin-bottom:22px}.body-copy{font-size:13.4px;line-height:1.58}.body-copy p{margin:0 0 12px}.body-copy h2,.extra-note h3{font-size:15px;margin:18px 0 8px;font-weight:900}.cim-page>footer{min-height:.52in;padding:0 .62in;border-top:1px solid #eee;display:flex;align-items:center;justify-content:space-between;color:#777;text-transform:uppercase;letter-spacing:.16em;font-size:8px}.badges{display:flex;gap:8px;align-items:center;flex:1}.badges img{max-height:.28in;max-width:.82in;object-fit:contain}.cover{background:#111;color:#fff;display:grid;grid-template-columns:56% 44%;height:11in;min-height:11in}.cover-left{padding:1.5in .62in .8in;position:relative}.cover-right{position:relative;background:#222;min-height:11in}.cover-right>img{width:100%;height:100%;object-fit:cover}.cover-logo{position:absolute;top:.55in;right:.42in;background:rgba(17,17,17,.65);padding:12px}.tag{display:inline-block;border:1px solid rgba(201,168,76,.55);color:#C9A84C;font-size:10px;text-transform:uppercase;letter-spacing:.22em;padding:8px 14px;border-radius:4px;margin-bottom:30px}.cover h1{font-size:42px;line-height:1.08;margin:0 0 18px;font-weight:900}.cover-type{font-size:16px;color:#ddd}.gold-line{width:.62in;height:3px;background:#C9A84C;margin:20px 0}.presented{position:absolute;bottom:.82in;color:#bbb;font-size:11px}.cover-footer{position:absolute;left:.62in;right:.62in;bottom:.28in;border-top:1px solid rgba(255,255,255,.22);padding-top:12px;color:#aaa;font-size:8px;letter-spacing:.18em}.biz-logo-cover{max-height:.8in;max-width:2.8in;background:#fff;padding:6px;margin-bottom:14px}.info-grid{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:10px;margin:14px 0}.cover .info-grid div{background:transparent;padding:0}.info-grid div{background:#f8f7f2;border-radius:6px;padding:10px 12px}.info-grid span,.kpi-row span{display:block;text-transform:uppercase;letter-spacing:.15em;font-size:9px;color:#C9A84C;font-weight:900}.info-grid strong{display:block;font-size:12.5px;margin-top:4px}.cover .info-grid strong{color:#fff}.broker-card{display:grid;grid-template-columns:120px 1fr;gap:22px;align-items:center;border-left:5px solid #C9A84C;border-radius:10px;box-shadow:0 0 0 1px #eee;padding:20px;margin-bottom:22px}.broker-photo{width:92px;height:92px;border-radius:50%;object-fit:cover;border:3px solid #C9A84C;display:flex;align-items:center;justify-content:center;background:#f8f7f2}.broker-card h2{font-size:22px;margin:0}.broker-card h3{font-size:12px;color:#C9A84C;letter-spacing:.12em;text-transform:uppercase;margin:4px 0 8px}.highlight-list,.cim-bullets{list-style:none;padding:0;margin:0 0 12px}.highlight-list li,.cim-bullets li{position:relative;padding:8px 0 8px 22px;border-bottom:1px solid #eee}.highlight-list li:before,.cim-bullets li:before{content:'▸';position:absolute;left:0;color:#C9A84C;font-weight:900}.kpi-row{display:grid;grid-template-columns:repeat(4,1fr);gap:12px;margin-bottom:18px}.kpi-row div{background:#111;color:#fff;border-radius:8px;padding:15px;text-align:center}.kpi-row strong{display:block;font-size:16px;color:#fff;margin-top:6px}.fin-table{width:100%;border-collapse:collapse;font-size:12.2px;margin:14px 0 18px}.fin-table th{background:#111;color:#C9A84C;text-transform:uppercase;letter-spacing:.08em;font-size:10px;text-align:left;padding:10px}.fin-table td{border-bottom:1px solid #eee;padding:9px}.fin-table td:not(:first-child),.fin-table th:not(:first-child){text-align:right}.fin-table .total td{font-weight:900;background:#f8f7f2;border-top:2px solid #C9A84C}.disclaimer-box,.extra-note,.support-list{background:#f8f7f2;border-left:4px solid #C9A84C;border-radius:6px;padding:14px 18px;margin:16px 0}.support-grid{display:grid;grid-template-columns:repeat(2,1fr);gap:14px;margin:16px 0}.support-grid figure{margin:0;border:1px solid #eee;border-radius:8px;overflow:hidden;background:#fff}.support-grid img{width:100%;height:210px;object-fit:cover;display:block}.support-grid figcaption{font-size:10px;color:#777;padding:7px}.photos img{height:235px}@media print{@page{size:letter;margin:0}html,body{margin:0!important;padding:0!important;background:#fff!important}.cim-v16{background:#fff!important}.cim-page{margin:0!important;box-shadow:none!important;width:8.5in!important;min-height:11in!important;break-after:page;page-break-after:always}.no-print,.preview-controls,#sidebar,.topbar{display:none!important}}
`; document.head.appendChild(st);
})();
document.addEventListener('DOMContentLoaded',()=>{
const overview=document.querySelector('#panel-s-overview .fr.fr3');
if(overview && !document.getElementById('f-legal-entity')){const div=document.createElement('div'); div.className='fg'; div.innerHTML='Legal Entity Name '; overview.prepend(div); overview.style.gridTemplateColumns='1fr 1fr 1fr 1fr';}
document.getElementById('intake-file-input')?.setAttribute('multiple','multiple');
addSectionExtras(); makeFinancialLabelsEditable(); CIM_SECTIONS_V16.forEach(([pid])=>renderSectionFileList(pid)); renderMediaList();
});
// INIT
initAiProxySettings();
loadData();
updateProgress();
setInterval(saveData,120000);