// toolkit-soc2-data.jsx — SOC 2 (AICPA Trust Services Criteria) toolkit contents + PDF engine + lead capture // Exposes window.TK_SOC2 (data, generatePDF, lead helpers) /* ── POLICY LIBRARY (20) ─────────────────────────────────── */ const SOC_POLICIES = [ ['Information Security Policy', 'Top-level security mandate, objectives, and management commitment.'], ['Access Control Policy', 'Rules for granting, reviewing, and revoking logical and physical access.'], ['Acceptable Use Policy', 'Expected behaviour for users of systems, data, and assets.'], ['Risk Assessment & Management Policy', 'How security and availability risk is identified, scored, and treated.'], ['Vendor & Third-Party Management Policy', 'Security requirements for subservice organizations and vendors.'], ['Change Management Policy', 'Controlled, authorized, and tested changes to systems and software.'], ['Data Classification & Handling Policy', 'Labelling and handling rules by sensitivity and confidentiality level.'], ['Encryption & Key Management Policy', 'Use of cryptography in transit and at rest, plus key lifecycle.'], ['Incident Response Policy', 'Detecting, escalating, and responding to security incidents.'], ['Business Continuity & Disaster Recovery Policy', 'Maintaining and recovering operations during disruption.'], ['Backup Policy', 'Backup scope, frequency, encryption, and restoration testing.'], ['Logging & Monitoring Policy', 'Event logging, alerting, retention, and review obligations.'], ['Vulnerability Management Policy', 'Identifying, prioritising, and remediating technical weaknesses.'], ['Secure Software Development Policy', 'Security requirements across the development lifecycle.'], ['Human Resources Security Policy', 'Security across the employment lifecycle, from screening to exit.'], ['Security Awareness & Training Policy', 'Role-based awareness and training expectations for all staff.'], ['Physical & Environmental Security Policy', 'Protection of facilities, equipment, and secure areas.'], ['Network Security Policy', 'Segmentation, boundary protection, and monitoring of networks.'], ['Data Retention & Disposal Policy', 'Retaining and securely disposing of information and media.'], ['Privacy Policy', 'Lawful collection, use, retention, and disclosure of personal data.'], ]; /* ── PROCEDURE SET (16) ──────────────────────────────────── */ const SOC_PROCEDURES = [ ['Risk Assessment Procedure', 'Step-by-step risk identification, analysis, and treatment.'], ['Access Provisioning & Deprovisioning Procedure', 'Granting and removing access on the joiner-mover-leaver path.'], ['User Access Review Procedure', 'Periodic recertification of logical access rights.'], ['Change Management Procedure', 'Requesting, approving, testing, and deploying changes.'], ['Incident Response Procedure', 'Triage, containment, eradication, and recovery steps.'], ['Vendor Risk Assessment Procedure', 'Evaluating and monitoring subservice organizations and vendors.'], ['Vulnerability & Patch Management Procedure', 'Scanning, prioritising, and remediating findings.'], ['Backup & Restore Procedure', 'Performing and verifying backups and restores.'], ['Business Continuity & DR Testing Procedure', 'Exercising continuity and recovery plans.'], ['Logging & Monitoring Procedure', 'Collecting, alerting on, and reviewing security events.'], ['Security Awareness Training Procedure', 'Delivering and tracking awareness training.'], ['Secure Development & Code Review Procedure', 'Embedding security across the SDLC.'], ['Data Retention & Secure Disposal Procedure', 'Retaining and destroying information securely.'], ['Evidence Collection Procedure', 'Generating and storing audit evidence as part of daily work.'], ['Onboarding & Offboarding Procedure', 'Securely bringing personnel in and out of the organization.'], ['Control Owner Review Procedure', 'Periodic owner attestation that each control operates as designed.'], ]; /* ── TRUST SERVICES CRITERIA (61) ────────────────────────── */ const TSC = [ { cat: 'Security · Common Criteria', icon: 'lock', items: [ ['CC1.1', 'Commitment to integrity and ethical values'], ['CC1.2', 'Board oversight and independence'], ['CC1.3', 'Management establishes structures, reporting lines and authorities'], ['CC1.4', 'Commitment to attract, develop and retain competent individuals'], ['CC1.5', 'Individuals held accountable for control responsibilities'], ['CC2.1', 'Use of relevant, quality information'], ['CC2.2', 'Internal communication of security objectives'], ['CC2.3', 'External communication of relevant matters'], ['CC3.1', 'Objectives specified with sufficient clarity'], ['CC3.2', 'Identification and analysis of risk'], ['CC3.3', 'Consideration of the potential for fraud'], ['CC3.4', 'Identification and assessment of changes'], ['CC4.1', 'Ongoing and separate evaluations of controls'], ['CC4.2', 'Evaluation and communication of deficiencies'], ['CC5.1', 'Selection and development of control activities'], ['CC5.2', 'Selection and development of general technology controls'], ['CC5.3', 'Deployment through policies and procedures'], ['CC6.1', 'Logical access security software and infrastructure'], ['CC6.2', 'Registration and authorization of new users'], ['CC6.3', 'Role-based access and least privilege'], ['CC6.4', 'Physical access to facilities is restricted'], ['CC6.5', 'Protection over assets removed from the environment'], ['CC6.6', 'Boundary protection from external threats'], ['CC6.7', 'Restriction of information in transit and on removable media'], ['CC6.8', 'Prevention and detection of unauthorized software'], ['CC7.1', 'Detection and monitoring of configuration and vulnerabilities'], ['CC7.2', 'Monitoring of system components for anomalies'], ['CC7.3', 'Evaluation of security events as incidents'], ['CC7.4', 'Response to identified security incidents'], ['CC7.5', 'Recovery from identified security incidents'], ['CC8.1', 'Changes are authorized, designed, tested and approved'], ['CC9.1', 'Risk-mitigation activities for business disruptions'], ['CC9.2', 'Assessment and management of vendor and partner risk'], ] }, { cat: 'Availability', icon: 'gauge', items: [ ['A1.1', 'Capacity is managed to meet processing demand'], ['A1.2', 'Environmental protections, backup and recovery infrastructure'], ['A1.3', 'Recovery plans are tested'], ] }, { cat: 'Confidentiality', icon: 'shield', items: [ ['C1.1', 'Confidential information is identified and maintained'], ['C1.2', 'Confidential information is disposed of securely'], ] }, { cat: 'Processing Integrity', icon: 'check', items: [ ['PI1.1', 'Quality information about processing objectives'], ['PI1.2', 'Inputs are complete and accurate'], ['PI1.3', 'Processing is complete, valid, accurate and timely'], ['PI1.4', 'Outputs are complete and accurate'], ['PI1.5', 'Inputs and outputs are stored completely and accurately'], ] }, { cat: 'Privacy', icon: 'users', items: [ ['P1.1', 'Notice of privacy practices is provided'], ['P2.1', 'Choice and consent are communicated and obtained'], ['P3.1', 'Personal information is collected consistent with objectives'], ['P3.2', 'Explicit consent for sensitive personal information'], ['P4.1', 'Use is limited to the purposes in the notice'], ['P4.2', 'Personal information is retained no longer than necessary'], ['P4.3', 'Personal information is disposed of securely'], ['P5.1', 'Individuals can access their personal information'], ['P5.2', 'Personal information can be corrected or amended'], ['P6.1', 'Disclosure to third parties occurs with consent'], ['P6.2', 'Record of authorized disclosures is maintained'], ['P6.3', 'Record of unauthorized disclosures is maintained'], ['P6.4', 'Third parties handle information per privacy commitments'], ['P6.5', 'Notification of third-party breaches is obtained'], ['P6.6', 'Notification of unauthorized disclosures is provided'], ['P6.7', 'Accounting of disclosures is available'], ['P7.1', 'Personal information is accurate and complete'], ['P8.1', 'Complaints and disputes are handled'], ] }, ]; /* ── COMMON CRITERIA SERIES (for coverage row) ───────────── */ const CC_SERIES = [['CC1', 'Control Environment'], ['CC2', 'Communication'], ['CC3', 'Risk Assessment'], ['CC4', 'Monitoring'], ['CC5', 'Control Activities'], ['CC6', 'Access Controls'], ['CC7', 'System Operations'], ['CC8', 'Change Mgmt'], ['CC9', 'Risk Mitigation']]; /* ── ASSET METADATA ──────────────────────────────────────── */ const SOC_ASSETS = { policies: { icon: 'doc', label: 'Policy Library', count: 20, unit: 'policies', file: 'Verigo-SOC2-Policy-Library.pdf', pdfTitle: 'SOC 2 Policy Library', blurb: 'The complete, criteria-aligned security policy set — 20 approval-ready policies covering the Common Criteria and every optional Trust Services category.', intro: 'This index lists the 20 policies included in the Verigo Global SOC 2 Policy Library. Each policy ships as an editable, organization-tailored document with purpose, scope, policy statements, roles and responsibilities, and a review cadence — ready to adopt as the documentation backbone of a SOC 2 control environment.' }, procedures: { icon: 'file', label: 'Procedure Set', count: 16, unit: 'procedures', file: 'Verigo-SOC2-Procedure-Set.pdf', pdfTitle: 'SOC 2 Procedure Set', blurb: '16 operational procedures that turn policy into repeatable practice — so evidence is generated by the process, not assembled before the examination.', intro: 'This index lists the 16 procedures included in the Verigo Global SOC 2 Procedure Set. Each procedure documents the step-by-step workflow, roles, inputs, outputs, and records — the operating machinery that keeps your controls running and the Type II observation window evidenced continuously.' }, controls: { icon: 'layers', label: 'Trust Services Criteria Templates', count: 61, unit: 'criteria', file: 'Verigo-SOC2-Trust-Services-Criteria.pdf', pdfTitle: 'SOC 2 Trust Services Criteria Control Templates', blurb: 'All 61 points of focus across the five Trust Services categories, each as an implementation template with control objective, guidance, evidence, and owner fields.', intro: 'This index lists the 61 criteria across the five Trust Services categories — Security / Common Criteria (33), Availability (3), Confidentiality (2), Processing Integrity (5), and Privacy (18). Each criterion ships as an implementation template capturing the control objective, applicability, implementation guidance, evidence expectations, owner, and status.' }, standard: { icon: 'layers', label: 'Standard Toolkit Package', count: 97, unit: 'documents', file: 'Verigo-SOC2-Standard-Package.pdf', pdfTitle: 'SOC 2 Standard Toolkit Package', blurb: 'The complete Standard package index — every policy, procedure, and Trust Services Criteria template in one branded document.', intro: 'This index summarizes the complete Verigo Global SOC 2 Standard Toolkit Package — 20 policies, 16 procedures, and all 61 Trust Services Criteria control templates. Each artefact ships as an editable, organization-tailored document, ready to adopt as the documentation backbone of a SOC 2 examination.' }, }; /* ── PURCHASE: TIERS + ADD-ONS ───────────────────────────── */ const fmtPrice = (n) => '$' + Number(n).toLocaleString('en-US'); const SOC_TIERS = [ { id: 'starter', name: 'Starter', price: 1495, tagline: 'The complete document toolkit, ready to deploy.', forWho: 'Teams driving their own SOC 2 readiness.', features: ['All 20 policies, 16 procedures & 61 Trust Services Criteria templates', 'Editable source files (Word & Excel)', 'Control matrix & evidence request (PBC) tracker', 'Audit-readiness checklists', '12 months of content updates', 'Email support'] }, { id: 'professional', name: 'Professional', price: 4950, tagline: 'The toolkit tailored to you, with practitioner guidance.', popular: true, forWho: 'Organizations that want the toolkit shaped to their scope.', features: ['Everything in Starter', 'Documents tailored to your scope & selected criteria', 'Half-day kickoff & gap-review workshop', 'Online readiness self-assessment', 'Cross-framework control mapping', 'Named practitioner with scheduled check-ins', 'Priority support'] }, { id: 'enterprise', name: 'Enterprise', price: 11900, priceNote: 'from', tagline: 'End-to-end support, all the way to a clean opinion.', forWho: 'Teams targeting a Type II report across multiple criteria.', features: ['Everything in Professional', 'Hands-on implementation support', 'Type II observation-window readiness', 'Pre-examination mock audit & findings log', 'Independent CPA examination coordination', 'Unlimited tailoring & review cycles', 'Dedicated delivery team'] }, ]; const SOC_ADDONS = [ { id: 'impl', name: 'Hands-on implementation support', desc: 'A practitioner embeds with your team to operationalize every control.', price: 6500 }, { id: 'preaudit', name: 'Pre-examination preparation', desc: 'Mock examination and evidence test with a findings log before the CPA arrives.', price: 3800 }, { id: 'cpa', name: 'CPA examination coordination', desc: 'We coordinate the independent CPA firm and manage evidence through to a clean opinion.', price: 3400 }, { id: 'evidence', name: 'Evidence engine setup', desc: 'Stand up the continuous evidence-collection routine for the Type II window.', price: 2600 }, { id: 'mapping', name: 'Cross-framework mapping', desc: 'Map controls to ISO 27001, HIPAA & NIST so evidence is reused, not rebuilt.', price: 2400 }, { id: 'criteria', name: 'Additional Trust Services category', desc: 'Extend scope to add Availability, Confidentiality, Processing Integrity, or Privacy.', price: 1800 }, ]; /* ── LEAD CAPTURE (localStorage) ─────────────────────────── */ const LEAD_KEY = 'verigo_toolkit_leads'; const USER_KEY = 'verigo_toolkit_user'; function getUser() { try { return JSON.parse(localStorage.getItem(USER_KEY) || 'null'); } catch (e) { return null; } } function storeLead(lead) { try { const rec = { ...lead, toolkit: 'SOC 2', ts: new Date().toISOString() }; const all = JSON.parse(localStorage.getItem(LEAD_KEY) || '[]'); all.push(rec); localStorage.setItem(LEAD_KEY, JSON.stringify(all)); const prev = getUser() || {}; const merged = { ...prev }; Object.keys(lead).forEach((k) => { if (k !== 'source' && lead[k] !== undefined && lead[k] !== '') merged[k] = lead[k]; }); localStorage.setItem(USER_KEY, JSON.stringify(merged)); } catch (e) { /* storage unavailable */ } window.submitInquiry && window.submitInquiry({ form_type: lead.source || 'toolkit', name: lead.name, email: lead.email, company: lead.company, phone: lead.phone, framework: 'SOC 2', metadata: lead, }); } /* ── CUSTOM PACKAGE: BASE + OPTION MODULES ───────────────── */ const QUOTE_BASE = { id: 'base', name: 'SOC 2 Document Toolkit', price: 1495, desc: 'All 20 policies, 16 procedures and 61 Trust Services Criteria control templates as editable source files (Word & Excel), plus the control matrix, evidence (PBC) tracker, and audit-readiness checklists. 12 months of content updates included.' }; const QUOTE_MODULES = [ { id: 'tailor', name: 'Document tailoring to your scope', price: 1950, desc: 'Every policy, procedure and control adapted to your scope, selected criteria and existing tooling.' }, { id: 'guidance', name: 'Practitioner guidance & check-ins', price: 1500, desc: 'A named practitioner, a kickoff workshop, and scheduled check-ins through your project.' }, { id: 'impl', name: 'Hands-on implementation support', price: 6500, desc: 'A practitioner embeds with your team to operationalize every control.' }, { id: 'preaudit', name: 'Pre-examination preparation', price: 3800, desc: 'Mock examination and evidence test with a findings log before the CPA arrives.' }, { id: 'cpa', name: 'CPA examination coordination', price: 3400, desc: 'We coordinate the independent CPA firm and manage evidence through to a clean opinion.' }, { id: 'evidence', name: 'Evidence engine setup', price: 2600, desc: 'Stand up the continuous evidence-collection routine for the Type II window.' }, { id: 'mapping', name: 'Cross-framework mapping', price: 2400, desc: 'Map controls to ISO 27001, HIPAA & NIST so evidence is reused, not rebuilt.' }, { id: 'criteria', name: 'Additional Trust Services category', price: 1800, desc: 'Extend scope to add Availability, Confidentiality, Processing Integrity, or Privacy.' }, ]; const QUOTE_TERMS = [ 'This quote is indicative and valid for 30 days from the date of issue.', 'No payment is due at this stage. A senior practitioner will confirm final scope and pricing within one business day.', 'The independent SOC 2 examination and opinion are issued by a licensed CPA firm; Verigo coordinates but does not perform the examination.', 'Pricing assumes the Security (Common Criteria) category unless additional Trust Services categories are included.', 'Document tailoring and delivery typically begin within 5 business days of a signed engagement.', 'All deliverables are provided under mutual confidentiality; documents are licensed for the named organization’s internal use.', 'Taxes, where applicable, are not included in the figures shown.', ]; /* ── CUSTOM QUOTE PDF (jsPDF) ────────────────────────────── */ function generateQuotePDF(order, user) { const lib = window.jspdf; if (!lib || !lib.jsPDF) { alert('PDF engine is still loading — please try again in a moment.'); return null; } const u = user || {}; const ref = order.ref || ('VG-' + Date.now().toString(36).toUpperCase().slice(-6)); const lineItems = [{ name: QUOTE_BASE.name, price: QUOTE_BASE.price, desc: QUOTE_BASE.desc }] .concat(order.modules.map((m) => ({ name: m.name, price: m.price, desc: m.desc }))); const total = lineItems.reduce((s, i) => s + i.price, 0); const doc = new lib.jsPDF({ unit: 'pt', format: 'a4' }); const W = doc.internal.pageSize.getWidth(); const H = doc.internal.pageSize.getHeight(); const M = 50; const PURPLE = [91, 46, 145], ORANGE = [232, 98, 42], INK = [30, 30, 46], GREY = [120, 120, 134]; const fmt = (n) => '$' + Number(n).toLocaleString('en-US'); let y = 0; const header = () => { doc.setFillColor(...PURPLE); doc.rect(0, 0, W, 70, 'F'); doc.setFillColor(...ORANGE); doc.rect(W - M - 11, 28, 11, 11, 'F'); doc.setTextColor(255, 255, 255); doc.setFont('helvetica', 'bold'); doc.setFontSize(15); doc.text('VERIGO GLOBAL', M, 33); doc.setFont('helvetica', 'normal'); doc.setFontSize(8.5); doc.setTextColor(214, 204, 232); doc.text('Compliance by Design', M, 49); doc.setTextColor(255, 255, 255); doc.setFontSize(8.5); doc.text('AICPA · SOC 2', W - M - 20, 35, { align: 'right' }); y = 100; }; const newPage = () => { doc.addPage(); header(); }; header(); doc.setTextColor(...INK); doc.setFont('helvetica', 'bold'); doc.setFontSize(21); doc.text('Custom Package Quote', M, y); y += 12; doc.setDrawColor(...ORANGE); doc.setLineWidth(2.5); doc.line(M, y, M + 54, y); y += 20; doc.setFont('helvetica', 'normal'); doc.setFontSize(9.5); doc.setTextColor(...GREY); const issued = new Date(); const valid = new Date(issued.getTime() + 30 * 864e5); const dstr = (d) => d.toLocaleDateString('en-US', { year: 'numeric', month: 'long', day: 'numeric' }); doc.text('Quote ' + ref, M, y); doc.text('Issued ' + dstr(issued) + ' · Valid until ' + dstr(valid), W - M, y, { align: 'right' }); y += 22; doc.setDrawColor(224, 224, 232); doc.setLineWidth(0.5); const rows = []; if (u.company) rows.push(['Organization', u.company]); if (u.name) rows.push(['Contact', u.name + (u.role ? ' · ' + u.role : '')]); if (u.email) rows.push(['Email', u.email]); if (u.phone) rows.push(['Phone', u.phone]); if (u.industry) rows.push(['Industry', u.industry]); if (u.employees) rows.push(['Company size', u.employees]); if (u.region) rows.push(['Primary region', u.region]); if (u.locations) rows.push(['Sites / locations', u.locations]); if (u.systems) rows.push(['In scope', u.systems]); if (u.certs) rows.push(['Existing certifications', u.certs]); if (u.target) rows.push(['Target report', u.target]); doc.setFontSize(11); doc.setFont('helvetica', 'bold'); doc.setTextColor(...PURPLE); doc.text('Prepared for', M, y); y += 16; doc.setFontSize(9.5); rows.forEach(([k, v]) => { if (y > H - 80) newPage(); doc.setFont('helvetica', 'bold'); doc.setTextColor(...INK); doc.text(k, M, y); doc.setFont('helvetica', 'normal'); doc.setTextColor(...GREY); doc.splitTextToSize(String(v), W - M - (M + 150)).forEach((ln, i) => doc.text(ln, M + 150, y + i * 12)); y += Math.max(14, doc.splitTextToSize(String(v), W - M - (M + 150)).length * 12); }); y += 8; if (y > H - 140) newPage(); doc.setFont('helvetica', 'bold'); doc.setFontSize(12.5); doc.setTextColor(...PURPLE); doc.text('Your custom package', M, y); y += 6; doc.setDrawColor(...PURPLE); doc.setLineWidth(0.8); doc.line(M, y, W - M, y); y += 18; lineItems.forEach((it, idx) => { const descLines = doc.splitTextToSize(it.desc, W - M - (M + 90)); const h = 14 + descLines.length * 11 + 10; if (y + h > H - 70) newPage(); doc.setFont('helvetica', 'bold'); doc.setFontSize(10.5); doc.setTextColor(...INK); doc.text((idx === 0 ? 'Base · ' : '') + it.name, M, y); doc.setTextColor(...PURPLE); doc.text(fmt(it.price), W - M, y, { align: 'right' }); y += 14; doc.setFont('helvetica', 'normal'); doc.setFontSize(9); doc.setTextColor(...GREY); descLines.forEach((ln) => { doc.text(ln, M, y); y += 11; }); y += 10; doc.setDrawColor(237, 237, 245); doc.setLineWidth(0.5); doc.line(M, y - 4, W - M, y - 4); }); y += 4; if (y > H - 70) newPage(); doc.setFillColor(245, 245, 247); doc.rect(M, y - 4, W - 2 * M, 30, 'F'); doc.setFont('helvetica', 'bold'); doc.setFontSize(11); doc.setTextColor(...INK); doc.text('Indicative total', M + 12, y + 15); doc.setFontSize(15); doc.setTextColor(...PURPLE); doc.text(fmt(total), W - M - 12, y + 16, { align: 'right' }); y += 44; if (y > H - 120) newPage(); doc.setFont('helvetica', 'bold'); doc.setFontSize(12.5); doc.setTextColor(...PURPLE); doc.text('Terms & conditions', M, y); y += 6; doc.setDrawColor(...PURPLE); doc.setLineWidth(0.8); doc.line(M, y, W - M, y); y += 16; doc.setFont('helvetica', 'normal'); doc.setFontSize(9); doc.setTextColor(...GREY); QUOTE_TERMS.forEach((t) => { const lines = doc.splitTextToSize(t, W - 2 * M - 14); if (y + lines.length * 12 > H - 56) newPage(); doc.setTextColor(...ORANGE); doc.setFont('helvetica', 'bold'); doc.text('•', M, y); doc.setTextColor(...GREY); doc.setFont('helvetica', 'normal'); lines.forEach((ln, i) => doc.text(ln, M + 14, y + i * 12)); y += lines.length * 12 + 6; }); const totalPages = doc.internal.getNumberOfPages(); for (let i = 1; i <= totalPages; i++) { doc.setPage(i); doc.setDrawColor(224, 224, 232); doc.setLineWidth(0.5); doc.line(M, H - 38, W - M, H - 38); doc.setFont('helvetica', 'normal'); doc.setFontSize(8); doc.setTextColor(150, 150, 160); doc.text('© 2026 Verigo Global · Custom quote ' + ref + ' · Indicative — not a binding offer', M, H - 24); doc.text(i + ' / ' + totalPages, W - M, H - 24, { align: 'right' }); } doc.save('Verigo-SOC2-Custom-Quote-' + ref + '.pdf'); return ref; } /* ── PDF ENGINE (jsPDF) ──────────────────────────────────── */ function sectionsFor(assetKey) { const polSec = { heading: 'Security policy set (20)', items: SOC_POLICIES.map(([t, d], i) => ({ code: String(i + 1).padStart(2, '0'), title: t, desc: d })) }; const prcSec = { heading: 'SOC 2 procedure set (16)', items: SOC_PROCEDURES.map(([t, d], i) => ({ code: String(i + 1).padStart(2, '0'), title: t, desc: d })) }; const ctrlSecs = TSC.map(g => ({ heading: g.cat + ' (' + g.items.length + ')', items: g.items.map(([c, t]) => ({ code: c, title: t, desc: '' })) })); if (assetKey === 'policies') return [polSec]; if (assetKey === 'procedures') return [prcSec]; if (assetKey === 'standard') return [polSec, prcSec, ...ctrlSecs]; return ctrlSecs; } function generatePDF(assetKey, user) { const lib = window.jspdf; if (!lib || !lib.jsPDF) { alert('PDF engine is still loading — please try again in a moment.'); return; } const meta = SOC_ASSETS[assetKey]; const doc = new lib.jsPDF({ unit: 'pt', format: 'a4' }); const W = doc.internal.pageSize.getWidth(); const H = doc.internal.pageSize.getHeight(); const M = 50, CX = M + 56, RW = W - M - CX; const PURPLE = [91, 46, 145], ORANGE = [232, 98, 42], INK = [30, 30, 46], GREY = [120, 120, 134]; let y = 0; const header = () => { doc.setFillColor(...PURPLE); doc.rect(0, 0, W, 70, 'F'); doc.setFillColor(...ORANGE); doc.rect(W - M - 11, 28, 11, 11, 'F'); doc.setTextColor(255, 255, 255); doc.setFont('helvetica', 'bold'); doc.setFontSize(15); doc.text('VERIGO GLOBAL', M, 33); doc.setFont('helvetica', 'normal'); doc.setFontSize(8.5); doc.setTextColor(214, 204, 232); doc.text('Compliance by Design', M, 49); doc.setTextColor(255, 255, 255); doc.setFontSize(8.5); doc.text('AICPA · SOC 2', W - M - 20, 35, { align: 'right' }); y = 100; }; const newPage = () => { doc.addPage(); header(); }; header(); doc.setTextColor(...INK); doc.setFont('helvetica', 'bold'); doc.setFontSize(21); doc.text(meta.pdfTitle, M, y); y += 12; doc.setDrawColor(...ORANGE); doc.setLineWidth(2.5); doc.line(M, y, M + 54, y); y += 22; doc.setFont('helvetica', 'normal'); doc.setFontSize(10); doc.setTextColor(...GREY); doc.splitTextToSize(meta.intro, W - 2 * M).forEach(ln => { doc.text(ln, M, y); y += 14; }); y += 6; if (user && (user.company || user.name)) { doc.setDrawColor(224, 224, 232); doc.setLineWidth(0.5); doc.line(M, y, W - M, y); y += 16; doc.setFontSize(9); doc.setTextColor(...PURPLE); doc.setFont('helvetica', 'bold'); doc.text('Prepared for ' + (user.company || user.name), M, y); doc.setFont('helvetica', 'normal'); doc.setTextColor(...GREY); doc.text(new Date().toLocaleDateString('en-US', { year: 'numeric', month: 'long', day: 'numeric' }), W - M, y, { align: 'right' }); y += 20; } sectionsFor(assetKey).forEach(sec => { if (y > H - 120) newPage(); y += 8; doc.setFont('helvetica', 'bold'); doc.setFontSize(12.5); doc.setTextColor(...PURPLE); doc.text(sec.heading, M, y); y += 6; doc.setDrawColor(...PURPLE); doc.setLineWidth(0.8); doc.line(M, y, W - M, y); y += 16; sec.items.forEach(it => { const titleLines = doc.splitTextToSize(it.title, RW); const descLines = it.desc ? doc.splitTextToSize(it.desc, RW) : []; const h = titleLines.length * 12 + descLines.length * 11 + 9; if (y + h > H - 56) newPage(); doc.setFont('helvetica', 'bold'); doc.setFontSize(9); doc.setTextColor(...ORANGE); doc.text(it.code, M, y + 1); doc.setFontSize(10.5); doc.setTextColor(...INK); titleLines.forEach((ln, i) => doc.text(ln, CX, y + i * 12)); let yy = y + titleLines.length * 12; if (descLines.length) { doc.setFont('helvetica', 'normal'); doc.setFontSize(9); doc.setTextColor(...GREY); descLines.forEach((ln, i) => doc.text(ln, CX, yy + 2 + i * 11)); yy += descLines.length * 11; } y = yy + 9; }); }); const total = doc.internal.getNumberOfPages(); for (let i = 1; i <= total; i++) { doc.setPage(i); doc.setDrawColor(224, 224, 232); doc.setLineWidth(0.5); doc.line(M, H - 38, W - M, H - 38); doc.setFont('helvetica', 'normal'); doc.setFontSize(8); doc.setTextColor(150, 150, 160); doc.text('© 2026 Verigo Global · Confidential — for the named recipient', M, H - 24); doc.text(i + ' / ' + total, W - M, H - 24, { align: 'right' }); } doc.save(meta.file); } window.TK_SOC2 = { POLICIES: SOC_POLICIES, PROCEDURES: SOC_PROCEDURES, TSC, CC_SERIES, ASSETS: SOC_ASSETS, TIERS: SOC_TIERS, ADDONS: SOC_ADDONS, QUOTE_BASE, QUOTE_MODULES, QUOTE_TERMS, fmtPrice, getUser, storeLead, generatePDF, generateQuotePDF };