`;
container.innerHTML = html;
}
function wipdSwitchTab(tabId) {
document.querySelectorAll('.wipd-tab-btn').forEach(b => b.classList.remove('active'));
document.querySelectorAll('.wipd-content').forEach(c => c.classList.remove('active'));
const idx = tabId === 'builder' ? 0 : 1;
document.querySelectorAll('.wipd-tab-btn')[idx].classList.add('active');
document.getElementById('wipd-' + tabId).classList.add('active');
if (tabId === 'preview') {
wipdRenderOutline();
}
}
function wipdLoadExample() {
if(!confirm("Overwrite current inputs with example data?")) return;
document.getElementById('inp-org').value = "MegaCorp Financial Services";
document.getElementById('inp-date').valueAsDate = new Date();
document.getElementById('inp-intake').value = "Chief Ethics and Compliance Officer (CECO)";
document.getElementById('inp-lead').value = "Audit Committee Chair & Outside Counsel";
document.getElementById('inp-confidentiality').value = "Identity is strictly protected and revealed only to the minimum extent necessary to complete the investigation, or as required by court order. All documents are marked 'CONFIDENTIAL: ATTORNEY-CLIENT PRIVILEGE.'";
document.getElementById('inp-evidence').value = "Legal hold issued immediately upon receipt of credible report. All electronic communications (email/chat) related to the alleged violation are preserved by IT Forensics. Physical evidence secured in a locked, single-access facility.";
document.getElementById('inp-remediation').value = "Findings are documented in a final report and presented to the Board Audit Committee. Remedial action (disciplinary measures, process change) is determined by the Board, executed by HR, and tracked for effectiveness by the CECO.";
wipdRenderOutline();
wipdSwitchTab('preview');
}
/* --- PDF Generation --- */
async function wipdGeneratePDF() {
wipdRenderOutline(); // Final render
const data = {
org: document.getElementById('inp-org').value || "Organization Name",
date: document.getElementById('inp-date').value,
intake: document.getElementById('inp-intake').value || "Intake Officer",
lead: document.getElementById('inp-lead').value || "Investigation Lead",
confidentiality: document.getElementById('inp-confidentiality').value || "Standard confidentiality rules apply.",
evidence: document.getElementById('inp-evidence').value || "Evidence preservation details pending.",
remediation: document.getElementById('inp-remediation').value || "Final reporting and corrective actions pending."
};
const { jsPDF } = window.jspdf;
const doc = new jsPDF('p', 'mm', 'a4');
const slate = [93, 109, 126];
let y = 20;
// Header
doc.setFillColor(...slate);
doc.rect(0, 0, 210, 20, 'F');
doc.setTextColor(255, 255, 255);
doc.setFontSize(16);
doc.text("Internal Whistleblower Investigation Protocol", 14, 13);
// Title/Metadata Block
doc.setTextColor(0, 0, 0);
doc.setFontSize(10);
doc.text(`Document Owner: ${data.org} | Effective Date: ${data.date}`, 14, 25);
y = 35;
// Helper function to add structured text sections
const addSection = (title, level, startY, content = null) => {
if (startY > 270) { doc.addPage(); startY = 20; }
let color = [0, 0, 0];
let size = 12;
let margin = 14;
if (level === 1) { color = [52, 73, 94]; size = 14; margin = 14; }
else if (level === 2) { color = slate; size = 11; margin = 20; }
else if (level === 3) { color = [120, 120, 120]; size = 9; margin = 25; }
doc.setFontSize(size);
doc.setFont("times", "bold");
doc.setTextColor(...color);
doc.text(title, margin, startY);
startY += size / 2 + 3;
if (content) {
doc.setFont("times", "normal");
doc.setTextColor(50, 50, 50);
doc.setFontSize(9);
const splitContent = doc.splitTextToSize(content, 180 - margin);
doc.text(splitContent, margin, startY);
startY += (splitContent.length * 4) + 5;
}
return startY;
};
// --- SECTION 1: GOVERNANCE AND SCOPE ---
y = addSection("SECTION 1: GOVERNANCE AND SCOPE", 1, y);
y = addSection("1.1. Purpose and Authority", 2, y);
y = addSection("1.2. Key Roles and Responsibilities", 2, y);
y = addSection(`1.2.1. Primary Intake Officer: ${data.intake}`, 3, y, "Role responsible for initial triage and safeguarding whistleblower identity.");
y = addSection(`1.2.2. Investigation Lead: ${data.lead}`, 3, y, "Executive or external counsel authorized to command resources for the investigation.");
// --- SECTION 2: CONFIDENTIALITY AND TRIAGE ---
y = addSection("SECTION 2: REPORTING, CONFIDENTIALITY, AND TRIAGE", 1, y);
y = addSection("2.1. Confidentiality and Protection of Identity", 2, y);
y = addSection("2.1.1. Confidentiality Scope:", 3, y, data.confidentiality);
y = addSection("2.1.2. Non-Retaliation Policy:", 3, y, "All whistleblowers are protected from retaliation under organizational policy and relevant law.");
// --- SECTION 3: INVESTIGATION PROCEDURE ---
y = addSection("SECTION 3: FORMAL INVESTIGATION PROCEDURE", 1, y);
y = addSection("3.1. Evidence Collection and Preservation", 2, y, data.evidence);
y = addSection("3.2. Final Reporting, Review, and Remediation", 2, y, data.remediation);
// --- SIGNATURE BLOCK ---
y += 15;
if (y > 270) { doc.addPage(); y = 20; }
doc.setFontSize(10);
doc.text("Document Approved and Adopted By:", 14, y);
y += 20;
doc.setDrawColor(150);
doc.line(14, y, 100, y);
doc.text("Chief Compliance Officer Signature", 14, y + 5);
doc.line(120, y, 190, y);
doc.text("Date", 120, y + 5);
doc.save(`Whistleblower_Protocol_${data.org.replace(/\s/g, '_')}.pdf`);
}
