Skip to content

Exec-adm#1

Open
E-privo wants to merge 1 commit intoCloudEngineHub:mainfrom
E-privo:patch-1
Open

Exec-adm#1
E-privo wants to merge 1 commit intoCloudEngineHub:mainfrom
E-privo:patch-1

Conversation

@E-privo
Copy link
Copy Markdown

@E-privo E-privo commented Mar 19, 2026

import { useState, useEffect, useRef } from “react”;

const FONTS = @import url('https://fonts.googleapis.com/css2?family=Plus+Jakarta+Sans:wght@300;400;500;600;700;800&family=JetBrains+Mono:wght@400;500;600&display=swap');;

const G = {
green:”#1B6B3A”, greenDk:”#0F4423”, greenLt:”#E8F5EE”, greenMid:”#2D8653”, greenPale:”#F0FAF4”, white:”#FFFFFF”, offWhite:”#F8F9FA”, border:”#E5E9EB”, borderMd:”#D0D7DC”, text:”#1A2028”, textMd:”#4A5568”, textLt:”#8A96A3”, red:”#E53E3E”, redLt:”#FEE2E2”, amber:”#D97706”, amberLt:”#FEF3C7”, blue:”#2563EB”, blueLt:”#EFF6FF”, purple:”#7C3AED”, purpleLt:”#EDE9FE”, teal:”#0D9488”, tealLt:”#CCFBF1”, gold:”#B45309”, goldLt:”#FEF3C7”, shadow:“0 2px 12px rgba(0,0,0,.08)”, shadowMd:“0 4px 24px rgba(0,0,0,.12)”, };

const CSS = ${FONTS} *{box-sizing:border-box;margin:0;padding:0;} body{background:${G.offWhite};color:${G.text};font-family:'Plus Jakarta Sans',sans-serif;min-height:100vh;-webkit-font-smoothing:antialiased;} ::-webkit-scrollbar{width:3px;} ::-webkit-scrollbar-thumb{background:${G.greenMid}55;border-radius:2px;} .mono{font-family:'JetBrains Mono',monospace;} @keyframes slideUp{from{opacity:0;transform:translateY(16px);}to{opacity:1;transform:translateY(0);}} @keyframes fadeIn{from{opacity:0;}to{opacity:1;}} @keyframes pop{0%{transform:scale(.95);opacity:0;}100%{transform:scale(1);opacity:1;}} @keyframes pulse{0%,100%{opacity:1;}50%{opacity:.4;}} .su{animation:slideUp .3s ease both;} .fi{animation:fadeIn .2s ease both;} .pp{animation:pop .3s cubic-bezier(.34,1.56,.64,1) both;} .pulse{animation:pulse 2s infinite;} .app{max-width:430px;margin:0 auto;min-height:100vh;background:${G.white};display:flex;flex-direction:column;position:relative;box-shadow:0 0 40px rgba(0,0,0,.1);} .top-header{background:${G.green};color:white;padding:16px 20px;position:sticky;top:0;z-index:50;} .top-header-flat{background:${G.white};border-bottom:1px solid ${G.border};padding:14px 20px;position:sticky;top:0;z-index:50;display:flex;align-items:center;gap:12px;} .btn-primary{background:${G.green};color:white;border:none;border-radius:12px;padding:14px 20px;font-family:'Plus Jakarta Sans',sans-serif;font-weight:700;font-size:15px;cursor:pointer;display:flex;align-items:center;justify-content:center;gap:8px;transition:all .2s;width:100%;} .btn-primary:hover{background:${G.greenDk};} .btn-primary:active{transform:scale(.98);} .btn-outline{background:white;color:${G.green};border:1.5px solid ${G.green};border-radius:12px;padding:13px 20px;font-family:'Plus Jakarta Sans',sans-serif;font-weight:700;font-size:15px;cursor:pointer;display:flex;align-items:center;justify-content:center;gap:8px;transition:all .2s;width:100%;} .btn-outline:hover{background:${G.greenLt};} .btn-sm{padding:8px 16px!important;font-size:13px!important;border-radius:8px!important;} .btn-ghost{background:transparent;border:1px solid ${G.border};color:${G.textMd};border-radius:8px;padding:8px 14px;font-size:13px;font-weight:600;cursor:pointer;font-family:'Plus Jakarta Sans',sans-serif;transition:all .2s;} .btn-ghost:hover{border-color:${G.green};color:${G.green};} .btn-red{background:${G.redLt};color:${G.red};border:1px solid ${G.red}33;border-radius:8px;padding:8px 14px;font-size:13px;font-weight:700;cursor:pointer;font-family:'Plus Jakarta Sans',sans-serif;transition:all .2s;} .btn-red:hover{background:${G.red};color:white;} .btn-amber{background:${G.amberLt};color:${G.amber};border:1px solid ${G.amber}33;border-radius:8px;padding:8px 14px;font-size:13px;font-weight:700;cursor:pointer;font-family:'Plus Jakarta Sans',sans-serif;} .card{background:${G.white};border:1px solid ${G.border};border-radius:16px;overflow:hidden;transition:all .2s;} .section-card{background:${G.white};border:1px solid ${G.border};border-radius:14px;overflow:hidden;margin-bottom:12px;} .list-row{display:flex;align-items:center;padding:14px 20px;border-bottom:1px solid ${G.border};gap:12px;transition:background .15s;cursor:pointer;} .list-row:last-child{border-bottom:none;} .list-row:hover{background:${G.greenPale};} .inp{background:${G.white};border:1.5px solid ${G.border};color:${G.text};border-radius:10px;padding:12px 14px;font-family:'Plus Jakarta Sans',sans-serif;font-size:14px;outline:none;width:100%;transition:border .2s;} .inp:focus{border-color:${G.green};} .inp::placeholder{color:${G.textLt};} .inp-label{font-size:11px;font-weight:700;color:${G.textLt};letter-spacing:.6px;margin-bottom:5px;display:block;} select.inp{appearance:auto;} textarea.inp{resize:none;} .av{border-radius:50%;display:flex;align-items:center;justify-content:center;font-weight:800;flex-shrink:0;letter-spacing:-.5px;} .badge{display:inline-flex;align-items:center;gap:4px;padding:3px 10px;border-radius:20px;font-size:11px;font-weight:700;letter-spacing:.3px;} .tag{display:inline-flex;padding:3px 9px;border-radius:5px;font-size:11px;font-weight:700;letter-spacing:.3px;} .tab-bar{position:sticky;bottom:0;background:${G.white};border-top:1px solid ${G.border};display:flex;z-index:50;} .tab-btn{flex:1;padding:9px 2px 11px;display:flex;flex-direction:column;align-items:center;gap:2px;cursor:pointer;border:none;background:transparent;transition:all .15s;font-family:'Plus Jakarta Sans',sans-serif;} .tab-btn.on{color:${G.green};} .tab-btn.off{color:${G.textLt};} .tab-icon{font-size:19px;line-height:1;} .tab-label{font-size:9px;font-weight:700;letter-spacing:.4px;} .toast{position:fixed;bottom:80px;left:50%;transform:translateX(-50%);background:${G.greenDk};color:white;padding:11px 22px;border-radius:30px;font-size:14px;font-weight:600;z-index:999;white-space:nowrap;box-shadow:${G.shadowMd};pointer-events:none;} .modal-bg{position:fixed;inset:0;background:rgba(0,0,0,.55);z-index:200;display:flex;align-items:flex-end;justify-content:center;} .modal-sheet{background:${G.white};border-radius:20px 20px 0 0;width:100%;max-width:430px;max-height:92vh;overflow-y:auto;padding:0 0 28px;} .modal-handle{width:36px;height:4px;background:${G.border};border-radius:2px;margin:12px auto 18px;} .toggle{width:46px;height:26px;border-radius:13px;cursor:pointer;position:relative;transition:background .25s;flex-shrink:0;} .toggle-dot{position:absolute;top:3px;width:20px;height:20px;border-radius:50%;background:white;transition:left .25s;box-shadow:0 2px 5px rgba(0,0,0,.25);} .divider{height:1px;background:${G.border};margin:12px 0;} .stat-bar{height:6px;background:${G.border};border-radius:3px;overflow:hidden;margin-top:6px;} .stat-fill{height:100%;border-radius:3px;transition:width 1s ease;};

/* ══════════════════ CONSTANTS ══════════════════ */ const uid = () => Math.random().toString(36).slice(2, 9); const now = () => new Date().toISOString().slice(0, 10); const fmt = (n, c = “USD”) => { try { return new Intl.NumberFormat(“en-US”, { style: “currency”, currency: c, minimumFractionDigits: 0 }).format(n || 0); } catch { return $${n}; } }; const fmtDate = d => d ? new Date(d).toLocaleDateString(“en-GB”, { day: “2-digit”, month: “short”, year: “numeric” }) : “—”;

const ADMIN_PIN = “2025”;
const KEY = “exec_hub_v2”;
const save = d => { try { localStorage.setItem(KEY, JSON.stringify(d)); } catch {} }; const load = () => { try { return JSON.parse(localStorage.getItem(KEY)); } catch { return null; } };

/* ══════════════════ SEED DATA ══════════════════ */ const SEED_EXECUTIVES = [
{ id: “satya”, firstName: “Satya”, lastName: “Nadella”, role: “Chairman & CEO”, company: “Microsoft”, email: “satyan@microsoft.com”, phone: “+1 425 882 8080”, whatsapp: “”, linkedin: “linkedin.com/in/satyanadella”, avatar: “SN”, color: “#0078D4”, metAt: “Microsoft Leadership Summit”, followUpStatus: “Warm”, priority: “High”, category: “Strategy”, salary: 55000, currency: “USD”, payFreq: “Monthly”, kycStatus: “Approved”, active: true, bio: “Chairman and CEO of Microsoft. Drives company-wide vision, AI strategy, and board-level decisions.”, decisionDomains: [“Company-wide strategy”, “Major acquisitions >$100M”, “Board reporting”, “AI and cloud roadmap”], whenToContact: “Spans multiple divisions, board-level decision, strategic partnership >$100M, or company-wide direction.”, whenDone: “Written email confirmation or board minutes. All decisions >$500M documented in board minutes.”, commStyle: “Data-driven, concise. Lead with metrics and customer impact. Growth mindset framing.”, tags: [“CEO”, “Strategy”, “AI”, “Cloud”] }, { id: “brad”, firstName: “Brad”, lastName: “Smith”, role: “Vice Chair & President”, company: “Microsoft”, email: “brsmith@microsoft.com”, phone: “+1 425 882 8080”, whatsapp: “”, linkedin: “linkedin.com/in/bradsmithpresident”, avatar: “BS”, color: “#5C2D91”, metAt: “GDPR Compliance Forum”, followUpStatus: “Hot Lead”, priority: “High”, category: “Legal”, salary: 45000, currency: “USD”, payFreq: “Monthly”, kycStatus: “Approved”, active: true, bio: “Vice Chair and President leading legal, corporate affairs, government relations, and privacy policy.”, decisionDomains: [“Legal decisions”, “GDPR/data privacy”, “Regulatory compliance”, “Antitrust matters”, “Contract review”], whenToContact: “Any legal risk, GDPR issue, contract >$1M, government engagement, or regulatory filing.”, whenDone: “Legal opinion issued in writing, contract countersigned, or DPA sign-off received.”, commStyle: “Formal, risk-aware. Lead with legal/regulatory dimension. Cite specific laws. Include risk rating.”, tags: [“Legal”, “GDPR”, “Compliance”, “Policy”] }, { id: “judson”, firstName: “Judson”, lastName: “Althoff”, role: “EVP — Commercial Business”, company: “Microsoft”, email: “jalthoff@microsoft.com”, phone: “+1 425 882 8080”, whatsapp: “+1 425 882 8080”, linkedin: “linkedin.com/in/judsonalthoff”, avatar: “JA”, color: “#107C10”, metAt: “Microsoft Partner Summit”, followUpStatus: “Hot Lead”, priority: “High”, category: “Sales”, salary: 48000, currency: “USD”, payFreq: “Monthly”, kycStatus: “Approved”, active: true, bio: “EVP overseeing enterprise sales, partner ecosystem, and commercial go-to-market strategy globally.”, decisionDomains: [“Enterprise sales strategy”, “Commercial deal structuring”, “Partner ecosystem”, “Revenue targets”], whenToContact: “Enterprise deal needs executive sponsor, partner agreement approval, or strategic account needs C-suite.”, whenDone: “Deal logged Closed-Won in CRM, partner agreement countersigned.”, commStyle: “Energetic, metrics-oriented. Frame in revenue impact. Lead with pipeline data and ARR numbers.”, tags: [“Sales”, “Revenue”, “Enterprise”, “Partnerships”] }, { id: “amyc”, firstName: “Amy”, lastName: “Coleman”, role: “EVP & Chief People Officer”, company: “Microsoft”, email: “acoleman@microsoft.com”, phone: “+1 425 882 8080”, whatsapp: “”, linkedin: “linkedin.com/in/amycolemanhr”, avatar: “AC”, color: “#D97706”, metAt: “Future of Work Conference”, followUpStatus: “Warm”, priority: “Medium”, category: “People”, salary: 42000, currency: “USD”, payFreq: “Monthly”, kycStatus: “Approved”, active: true, bio: “EVP and Chief People Officer leading global HR, talent, culture, DE&I, and employee experience.”, decisionDomains: [“Executive hiring”, “Compensation structure”, “Workforce planning”, “Culture programmes”, “DE&I strategy”], whenToContact: “Executive hire/termination, compensation benchmarking, org restructure >10 people, cultural issue.”, whenDone: “Offer letter in HR system, org change in HRIS, or written HR confirmation.”, commStyle: “Warm, people-centred. Lead with human impact. Frame business cases in terms of employee effect.”, tags: [“HR”, “People”, “Culture”, “Talent”] }, { id: “kathleen”, firstName: “Kathleen”, lastName: “Hogan”, role: “EVP — Strategy & Transformation”, company: “Microsoft”, email: “kahogan@microsoft.com”, phone: “+1 425 882 8080”, whatsapp: “”, linkedin: “linkedin.com/in/kathleenhogan”, avatar: “KH”, color: “#0369A1”, metAt: “Digital Transformation Summit”, followUpStatus: “Warm”, priority: “Medium”, category: “Strategy”, salary: 44000, currency: “USD”, payFreq: “Monthly”, kycStatus: “Approved”, active: true, bio: “EVP Office of Strategy and Transformation. Leads strategic planning, OKRs, and cross-functional alignment.”, decisionDomains: [“Corporate strategic planning”, “Transformation governance”, “OKR framework”, “Cross-functional alignment”], whenToContact: “Cross-functional initiative needs governance, strategic planning input needed, OKRs to set or review.”, whenDone: “Initiative in strategic planning system, OKRs published, or programme charter with milestones issued.”, commStyle: “Strategic, outcome-oriented. Think in OKRs. Show measurable outcomes and transformation arc.”, tags: [“Strategy”, “OKRs”, “Transformation”, “Planning”] }, { id: “takeshi”, firstName: “Takeshi”, lastName: “Numoto”, role: “EVP & Chief Marketing Officer”, company: “Microsoft”, email: “tnumoto@microsoft.com”, phone: “+1 425 882 8080”, whatsapp: “+1 425 882 8080”, linkedin: “linkedin.com/in/takeshinumoto”, avatar: “TN”, color: “#DC2626”, metAt: “Microsoft Inspire”, followUpStatus: “Warm”, priority: “Medium”, category: “Marketing”, salary: 43000, currency: “USD”, payFreq: “Monthly”, kycStatus: “Approved”, active: true, bio: “EVP and CMO leading global brand, product marketing, campaigns, and demand generation.”, decisionDomains: [“Global brand strategy”, “Campaign approval”, “Product launch marketing”, “PR & external comms”], whenToContact: “Major campaign CMO approval, product launch marketing, PR crisis, analyst/press briefing.”, whenDone: “Campaign brief signed off, press release approved, messaging framework locked.”, commStyle: “Creative, customer-story driven. Lead with customer story first. Use crisp messaging frameworks.”, tags: [“Marketing”, “Brand”, “PR”, “Campaigns”] }, ];

const SEED_FINANCE = {
budget: { total: 500000, used: 187400, currency: “USD”, fy: “FY2026” }, accounts: [
{ id: uid(), name: “SwiftFund Operating”, bank: “GTBank”, number: “****4421”, balance: 124500, currency: “USD”, type: “Operating”, lastSync: now() }, { id: uid(), name: “SwiftFund Payroll”, bank: “Access Bank”, number: “****8830”, balance: 68200, currency: “USD”, type: “Payroll”, lastSync: now() }, { id: uid(), name: “Wise Multi-Currency”, bank: “Wise”, number: “****2291”, balance: 31400, currency: “USD”, type: “FX”, lastSync: now() }, ],
transactions: [
{ id: uid(), date: “2026-03-01”, desc: “Satya Nadella — Monthly Retainer”, amount: -55000, type: “Payroll”, category: “Executive Pay”, status: “Cleared”, exec: “satya” }, { id: uid(), date: “2026-03-01”, desc: “Brad Smith — Monthly Retainer”, amount: -45000, type: “Payroll”, category: “Executive Pay”, status: “Cleared”, exec: “brad” }, { id: uid(), date: “2026-03-01”, desc: “Judson Althoff — Monthly Retainer”, amount: -48000, type: “Payroll”, category: “Executive Pay”, status: “Cleared”, exec: “judson” }, { id: uid(), date: “2026-03-05”, desc: “SwiftFund SaaS Revenue — March”, amount: 28400, type: “Income”, category: “Revenue”, status: “Cleared”, exec: null }, { id: uid(), date: “2026-03-08”, desc: “Enterprise Deal — TechCorp Ltd”, amount: 45000, type: “Income”, category: “Revenue”, status: “Cleared”, exec: null }, { id: uid(), date: “2026-03-10”, desc: “AWS Infrastructure — March”, amount: -8200, type: “Expense”, category: “Infrastructure”, status: “Cleared”, exec: null }, { id: uid(), date: “2026-03-12”, desc: “Legal Compliance Review — Q1”, amount: -12000, type: “Expense”, category: “Legal”, status: “Pending”, exec: “brad” }, { id: uid(), date: “2026-03-14”, desc: “Marketing Campaign — Africa Expansion”, amount: -15000, type: “Expense”, category: “Marketing”, status: “Pending”, exec: “takeshi” }, ],
budgetLines: [
{ id: uid(), name: “Executive Payroll”, allocated: 280000, spent: 131000, category: “People” }, { id: uid(), name: “Infrastructure & Cloud”, allocated: 60000, spent: 24600, category: “Tech” }, { id: uid(), name: “Sales & Marketing”, allocated: 80000, spent: 31800, category: “GTM” }, { id: uid(), name: “Legal & Compliance”, allocated: 40000, spent: 12000, category: “Legal” }, { id: uid(), name: “Operations”, allocated: 40000, spent: 18000, category: “Ops” }, ],
payrollSchedule: [
{ id: uid(), execId: “satya”, name: “Satya Nadella”, amount: 55000, currency: “USD”, nextPayDate: “2026-04-01”, status: “Scheduled”, processor: “Wire”, kycOk: true }, { id: uid(), execId: “brad”, name: “Brad Smith”, amount: 45000, currency: “USD”, nextPayDate: “2026-04-01”, status: “Scheduled”, processor: “Wire”, kycOk: true }, { id: uid(), execId: “judson”, name: “Judson Althoff”, amount: 48000, currency: “USD”, nextPayDate: “2026-04-01”, status: “Scheduled”, processor: “Wire”, kycOk: true }, { id: uid(), execId: “amyc”, name: “Amy Coleman”, amount: 42000, currency: “USD”, nextPayDate: “2026-04-01”, status: “On Hold”, processor: “Wire”, kycOk: true }, { id: uid(), execId: “kathleen”, name: “Kathleen Hogan”, amount: 44000, currency: “USD”, nextPayDate: “2026-04-01”, status: “Scheduled”, processor: “Wire”, kycOk: true }, { id: uid(), execId: “takeshi”, name: “Takeshi Numoto”, amount: 43000, currency: “USD”, nextPayDate: “2026-04-01”, status: “Scheduled”, processor: “Wire”, kycOk: true }, ],
};

const SEED_GOVERNANCE = {
policies: [
{ id: uid(), name: “Executive Payment Dual Approval”, category: “Finance”, severity: “Critical”, description: “All executive payments >$10,000 require CFO sign-off before processing.”, active: true, owner: “Amy Hood”, lastReview: now(), violations: 0, enforced: 12 }, { id: uid(), name: “GDPR Data Access Logging”, category: “Compliance”, severity: “Critical”, description: “All access to personal data must be logged with timestamp, user ID, and purpose.”, active: true, owner: “Brad Smith”, lastReview: now(), violations: 0, enforced: 847 }, { id: uid(), name: “Legal Review — Contracts >$1M”, category: “Legal”, severity: “High”, description: “All contracts exceeding $1M must be reviewed by Brad Smith’s legal team before execution.”, active: true, owner: “Brad Smith”, lastReview: now(), violations: 1, enforced: 8 }, { id: uid(), name: “Budget Variance Escalation”, category: “Finance”, severity: “High”, description: “Any budget line exceeding 80% utilisation triggers CFO review before further spend.”, active: true, owner: “Amy Hood”, lastReview: now(), violations: 0, enforced: 4 }, { id: uid(), name: “KYC Before First Payment”, category: “Compliance”, severity: “Critical”, description: “No executive or contractor may receive payment before KYC is verified and approved.”, active: true, owner: “Amy Hood”, lastReview: now(), violations: 0, enforced: 6 }, { id: uid(), name: “Quarterly OKR Review”, category: “Strategy”, severity: “Medium”, description: “All teams must submit OKR progress report to Kathleen Hogan’s office by last Friday of each quarter.”, active: true, owner: “Kathleen Hogan”, lastReview: now(), violations: 2, enforced: 4 }, { id: uid(), name: “PR Response — 24h SLA”, category: “Communications”, severity: “High”, description: “All media and press enquiries must receive a response within 24 hours via Takeshi Numoto’s office.”, active: true, owner: “Takeshi Numoto”, lastReview: now(), violations: 0, enforced: 7 }, { id: uid(), name: “Headcount Freeze — Unapproved Roles”, category: “People”, severity: “Medium”, description: “No new hiring may proceed without Amy Coleman’s written headcount approval.”, active: false, owner: “Amy Coleman”, lastReview: now(), violations: 0, enforced: 3 }, ],
auditLog: [
{ id: uid(), ts: “10:14”, date: now(), user: “Amy Hood”, action: “Approved payment”, detail: “Satya Nadella — $55,000 March retainer”, level: “info”, category: “Finance” }, { id: uid(), ts: “09:52”, date: now(), user: “Amy Hood”, action: “Policy enforced”, detail: “KYC Before First Payment — Amy Coleman cleared”, level: “success”, category: “Compliance” }, { id: uid(), ts: “09:31”, date: now(), user: “System”, action: “Budget alert”, detail: “Executive Payroll line at 81% — CFO review triggered”, level: “warn”, category: “Finance” }, { id: uid(), ts: “08:44”, date: now(), user: “Brad Smith”, action: “Legal review completed”, detail: “Q1 Compliance Review — approved”, level: “success”, category: “Legal” }, { id: uid(), ts: “08:12”, date: now(), user: “Amy Hood”, action: “Contact updated”, detail: “Takeshi Numoto — status changed to Warm”, level: “info”, category: “CRM” }, { id: uid(), ts: “Yesterday”, date: “2026-03-14”, user: “Judson Althoff”, action: “Deal logged”, detail: “TechCorp Ltd — $45,000 Closed-Won”, level: “success”, category: “Sales” }, { id: uid(), ts: “Yesterday”, date: “2026-03-14”, user: “System”, action: “Policy violation”, detail: “Legal Review policy — contract submitted without review”, level: “danger”, category: “Legal” }, ],
roles: [
{ id: uid(), name: “Super Admin”, description: “Full system access — Amy Hood only”, color: G.green, permissions: [“all”], assignedTo: [“Amy Hood”] }, { id: uid(), name: “Finance Admin”, description: “Full finance and payroll access”, color: G.blue, permissions: [“finance.view”, “finance.edit”, “payroll.view”, “payroll.approve”], assignedTo: [“Amy Hood”] }, { id: uid(), name: “Governance Admin”, description: “Policy management and audit access”, color: G.purple, permissions: [“policy.view”, “policy.edit”, “audit.view”], assignedTo: [“Brad Smith”, “Amy Hood”] }, { id: uid(), name: “Contact Manager”, description: “View and edit all executive contacts”, color: G.amber, permissions: [“contacts.view”, “contacts.edit”], assignedTo: [“Amy Hood”] }, { id: uid(), name: “Read Only”, description: “View contacts and reports only”, color: G.textLt, permissions: [“contacts.view”, “reports.view”], assignedTo: [] }, ],
complianceItems: [
{ id: uid(), entity: “Satya Nadella”, type: “KYC”, status: “Approved”, kycDate: “2026-01-10”, expiryDate: “2027-01-10”, documents: [“Passport”, “Tax ID”], fundHold: false, holdAmount: 0, amlClear: true }, { id: uid(), entity: “Brad Smith”, type: “KYC”, status: “Approved”, kycDate: “2026-01-08”, expiryDate: “2027-01-08”, documents: [“Passport”, “Government ID”], fundHold: false, holdAmount: 0, amlClear: true }, { id: uid(), entity: “Judson Althoff”, type: “KYC”, status: “Approved”, kycDate: “2026-01-12”, expiryDate: “2027-01-12”, documents: [“Passport”, “Tax ID”, “Bank Letter”], fundHold: false, holdAmount: 0, amlClear: true }, { id: uid(), entity: “Amy Coleman”, type: “KYC”, status: “Approved”, kycDate: “2026-01-15”, expiryDate: “2027-01-15”, documents: [“Passport”], fundHold: false, holdAmount: 0, amlClear: true }, { id: uid(), entity: “Kathleen Hogan”, type: “KYC”, status: “Approved”, kycDate: “2026-01-20”, expiryDate: “2027-01-20”, documents: [“Passport”, “Tax ID”], fundHold: false, holdAmount: 0, amlClear: true }, { id: uid(), entity: “Takeshi Numoto”, type: “KYC”, status: “Pending”, kycDate: “”, expiryDate: “”, documents: [“Passport”], fundHold: true, holdAmount: 43000, amlClear: false }, { id: uid(), entity: “SwiftFund Ltd”, type: “KYB”, status: “Approved”, kycDate: “2025-11-01”, expiryDate: “2026-11-01”, documents: [“Certificate of Inc.”, “Director IDs”, “Bank Letter”, “Tax Clearance”], fundHold: false, holdAmount: 0, amlClear: true }, ],
};

/* ══════════════════ ROOT ══════════════════ */
export default function App() {
const s = load();
const [authenticated, setAuthenticated] = useState(false);
const [tab, setTab] = useState(“dashboard”);
const [executives, setExecutives] = useState(s?.executives || SEED_EXECUTIVES);
const [finance, setFinance] = useState(s?.finance || SEED_FINANCE);
const [governance, setGovernance] = useState(s?.governance || SEED_GOVERNANCE);
const [tasks, setTasks] = useState(s?.tasks || []);
const [toastMsg, setToastMsg] = useState(””);
const [modal, setModal] = useState(null); // {type, data}

useEffect(() => { save({ executives, finance, governance, tasks }); }, [executives, finance, governance, tasks]);

const toast = (msg, dur = 2800) => { setToastMsg(msg); setTimeout(() => setToastMsg(””), dur); };

const addAuditLog = (action, detail, level = “info”, category = “System”) => { const entry = { id: uid(), ts: new Date().toLocaleTimeString([], { hour: “2-digit”, minute: “2-digit” }), date: now(), user: “Amy Hood”, action, detail, level, category }; setGovernance(p => ({ …p, auditLog: [entry, …p.auditLog.slice(0, 99)] })); };

const totalBalance = finance.accounts.reduce((a, b) => a + b.balance, 0); const totalPayroll = finance.payrollSchedule.reduce((a, b) => a + b.amount, 0); const revenue = finance.transactions.filter(t => t.amount > 0).reduce((a, b) => a + b.amount, 0); const expenses = finance.transactions.filter(t => t.amount < 0).reduce((a, b) => a + Math.abs(b.amount), 0); const violations = governance.policies.reduce((a, b) => a + b.violations, 0); const heldFunds = governance.complianceItems.filter(c => c.fundHold).reduce((a, b) => a + b.holdAmount, 0);

if (!authenticated) return <PinGate onUnlock={() => setAuthenticated(true)} />;

const NAV = [
{ k: “dashboard”, icon: “⬡”, label: “HOME” },
{ k: “contacts”, icon: “👥”, label: “TEAM” },
{ k: “finance”, icon: “💰”, label: “FINANCE” },
{ k: “govern”, icon: “⚖️”, label: “GOVERN” },
{ k: “settings”, icon: “⚙️”, label: “SYSTEM” },
];

return (

<style>{CSS}</style>
{toastMsg &&
✓ {toastMsg}
} {modal && }
    {tab === "dashboard" && <DashboardView executives={executives} finance={{ ...finance, totalBalance, totalPayroll, revenue, expenses }} governance={{ ...governance, violations, heldFunds }} tasks={tasks} setTab={setTab} setModal={setModal} />}
    {tab === "contacts"  && <ContactsAdmin executives={executives} setExecutives={setExecutives} toast={toast} addAuditLog={addAuditLog} setModal={setModal} />}
    {tab === "finance"   && <FinanceAdmin finance={finance} setFinance={setFinance} totalBalance={totalBalance} totalPayroll={totalPayroll} revenue={revenue} expenses={expenses} toast={toast} addAuditLog={addAuditLog} setModal={setModal} />}
    {tab === "govern"    && <GovernanceAdmin governance={governance} setGovernance={setGovernance} violations={violations} heldFunds={heldFunds} toast={toast} addAuditLog={addAuditLog} />}
    {tab === "settings"  && <SystemSettings executives={executives} setExecutives={setExecutives} finance={finance} governance={governance} tasks={tasks} toast={toast} addAuditLog={addAuditLog} onLock={() => setAuthenticated(false)} />}

    <div className="tab-bar">
      {NAV.map(n => (
        <button key={n.k} className={`tab-btn ${tab === n.k ? "on" : "off"}`} onClick={() => setTab(n.k)}>
          <div className="tab-icon">{n.icon}</div>
          <div className="tab-label">{n.label}</div>
        </button>
      ))}
    </div>
  </div>
</div>

);
}

/* ══════════════════ PIN GATE ══════════════════ */ function PinGate({ onUnlock }) {
const [pin, setPin] = useState(””);
const [error, setError] = useState(false);
const check = (p) => { if (p === ADMIN_PIN) { onUnlock(); } else if (p.length === 4) { setError(true); setPin(””); setTimeout(() => setError(false), 1000); } }; const press = (d) => { const np = pin + d; setPin(np); if (np.length === 4) check(np); }; return (

<style>{CSS}</style>
🔐
Admin Panel
Executive Hub — SwiftFund
{[0, 1, 2, 3].map(i => (
i ? (error ? G.red : G.green) : G.border, transition: “background .2s” }} /> ))}
{[1,2,3,4,5,6,7,8,9,””,0,“⌫”].map((d, i) => ( { if (d === “⌫”) setPin(p => p.slice(0, -1)); else if (d !== “”) press(String(d)); }} style={{ padding: “16px 8px”, borderRadius: 12, border: `1px solid ${G.border}`, background: d === “” ? “transparent” : G.offWhite, fontSize: 20, fontWeight: 700, cursor: d === “” ? “default” : “pointer”, color: G.text, fontFamily: “‘Plus Jakarta Sans’,sans-serif”, transition: “all .15s” }} onMouseDown={e => { if (d !== “”) e.currentTarget.style.background = G.greenLt; }} onMouseUp={e => { if (d !== “”) e.currentTarget.style.background = G.offWhite; }}> {d} ))}
{error &&
Incorrect PIN — try again
}
Default PIN: 2025 — change in System settings
); }

/* ══════════════════ DASHBOARD ══════════════════ */ function DashboardView({ executives, finance, governance, tasks, setTab, setModal }) { const pending = tasks.filter(t => !t.done);
const hotLeads = executives.filter(e => e.followUpStatus === “Hot Lead”); const recentAudit = governance.auditLog.slice(0, 4);

const KpiCard = ({ icon, label, value, sub, color, onClick }) => (

e.currentTarget.style.borderColor = color + “66”} onMouseLeave={e => e.currentTarget.style.borderColor = G.border}>
{icon}
{label.toUpperCase()}
{value}
{sub &&
{sub}
}
);

return (

Admin Dashboard
Amy Hood · CFO
SwiftFund Executive Control Centre
  <div style={{ padding: "16px 16px 100px" }}>
    <div style={{ display: "grid", gridTemplateColumns: "1fr 1fr", gap: 10, marginBottom: 16 }}>
      <KpiCard icon="💰" label="Total Balance" value={fmt(finance.totalBalance)} sub={`${finance.accounts.length} accounts`} color={G.green} onClick={() => setTab("finance")} />
      <KpiCard icon="📈" label="Revenue MTD" value={fmt(finance.revenue)} sub="This month" color={G.blue} onClick={() => setTab("finance")} />
      <KpiCard icon="👥" label="Executives" value={executives.filter(e => e.active).length} sub={`${executives.length} total`} color={G.amber} onClick={() => setTab("contacts")} />
      <KpiCard icon="⚠️" label="Violations" value={governance.violations} sub={`${governance.policies.filter(p => p.active).length} active policies`} color={governance.violations > 0 ? G.red : G.green} onClick={() => setTab("govern")} />
    </div>

    {governance.heldFunds > 0 && (
      <div style={{ background: G.redLt, border: `1px solid ${G.red}33`, borderRadius: 12, padding: "14px 16px", marginBottom: 14, display: "flex", gap: 10, alignItems: "center" }}>
        <span style={{ fontSize: 20 }}>⏸</span>
        <div>
          <div style={{ fontWeight: 700, fontSize: 14, color: G.red }}>Funds On Hold</div>
          <div style={{ fontSize: 12, color: G.red }}>{fmt(governance.heldFunds)} held pending KYC clearance</div>
        </div>
        <button className="btn-red btn-sm" style={{ marginLeft: "auto", flexShrink: 0 }} onClick={() => setTab("govern")}>Review</button>
      </div>
    )}

    {hotLeads.length > 0 && (
      <div style={{ background: G.amberLt, border: `1px solid ${G.amber}33`, borderRadius: 12, padding: "14px 16px", marginBottom: 14 }}>
        <div style={{ fontWeight: 700, fontSize: 13, color: G.amber, marginBottom: 8 }}>🔥 Hot Leads — Action Required</div>
        {hotLeads.map(e => (
          <div key={e.id} style={{ display: "flex", gap: 10, alignItems: "center", marginBottom: 6 }}>
            <div className="av" style={{ width: 28, height: 28, fontSize: 10, color: "white", background: e.color }}>{e.avatar}</div>
            <div style={{ flex: 1, fontSize: 13, fontWeight: 600 }}>{e.firstName} {e.lastName}</div>
            <span style={{ fontSize: 11, color: G.textLt }}>Follow up →</span>
          </div>
        ))}
      </div>
    )}

    {pending.length > 0 && (
      <div className="section-card" style={{ marginBottom: 14 }}>
        <div style={{ padding: "14px 16px 10px", fontWeight: 700, fontSize: 14 }}>📋 Pending Tasks ({pending.length})</div>
        {pending.slice(0, 3).map(t => {
          const exec = SEED_EXECUTIVES.find(e => e.id === t.contactId);
          return (
            <div key={t.id} style={{ padding: "10px 16px", borderTop: `1px solid ${G.border}`, display: "flex", gap: 10 }}>
              <span style={{ fontSize: 13 }}>○</span>
              <div style={{ flex: 1 }}>
                <div style={{ fontSize: 13, fontWeight: 600 }}>{t.notes || "Follow-up"}</div>
                {exec && <div style={{ fontSize: 11, color: G.green }}>{exec.firstName} {exec.lastName}</div>}
                <div style={{ fontSize: 11, color: G.textLt }}>Due: {fmtDate(t.date)}</div>
              </div>
            </div>
          );
        })}
      </div>
    )}

    <div className="section-card">
      <div style={{ padding: "14px 16px 8px", fontWeight: 700, fontSize: 14 }}>🕐 Recent Activity</div>
      {recentAudit.map(log => {
        const lc = { success: G.green, warn: G.amber, danger: G.red, info: G.blue }[log.level] || G.textLt;
        return (
          <div key={log.id} style={{ padding: "10px 16px", borderTop: `1px solid ${G.border}`, display: "flex", gap: 10, alignItems: "flex-start" }}>
            <div style={{ width: 8, height: 8, borderRadius: "50%", background: lc, marginTop: 5, flexShrink: 0 }} />
            <div style={{ flex: 1 }}>
              <div style={{ fontSize: 13, fontWeight: 600 }}>{log.action}</div>
              <div style={{ fontSize: 12, color: G.textMd }}>{log.detail}</div>
              <div style={{ fontSize: 11, color: G.textLt }}>{log.user} · {log.ts}</div>
            </div>
            <span className="tag" style={{ background: G.greenLt, color: G.green, flexShrink: 0 }}>{log.category}</span>
          </div>
        );
      })}
    </div>
  </div>
</div>

);
}

/* ══════════════════ CONTACTS ADMIN ══════════════════ */ function ContactsAdmin({ executives, setExecutives, toast, addAuditLog, setModal }) {
const [editId, setEditId] = useState(null);
const [showForm, setShowForm] = useState(false);
const BLANK = { firstName: “”, lastName: “”, role: “”, company: “Microsoft”, email: “”, phone: “”, whatsapp: “”, linkedin: “”, avatar: “”, color: G.green, metAt: “”, followUpStatus: “Warm”, priority: “Medium”, category: “Strategy”, salary: 0, currency: “USD”, payFreq: “Monthly”, kycStatus: “Pending”, active: true, bio: “”, tags: [] };
const [form, setForm] = useState(BLANK);

const openAdd = () => { setForm({ …BLANK, id: uid() }); setEditId(null); setShowForm(true); }; const openEdit = (e) => { setForm({ …e }); setEditId(e.id); setShowForm(true); }; const save = () => {
if (!form.firstName || !form.role) return;
const entry = { …form, avatar: form.avatar || (form.firstName.slice(0, 1) + form.lastName.slice(0, 1)).toUpperCase() }; if (editId) { setExecutives(p => p.map(e => e.id === editId ? entry : e)); addAuditLog(“Contact updated”, ${entry.firstName} ${entry.lastName}, “info”, “CRM”); } else { setExecutives(p => […p, entry]); addAuditLog(“Contact added”, ${entry.firstName} ${entry.lastName} — ${entry.role}, “info”, “CRM”); } setShowForm(false); toast(editId ? “Contact updated ✓” : “Contact added ✓”); };
const remove = (id, name) => { setExecutives(p => p.filter(e => e.id !== id)); addAuditLog(“Contact deleted”, name, “warn”, “CRM”); toast(“Contact removed”); }; const toggle = (id) => { setExecutives(p => p.map(e => e.id === id ? { …e, active: !e.active } : e)); };

const F = ({ label, k, type = “text”, ph = “”, opts = null }) => (

{label.toUpperCase()} {opts ? setForm(p => ({ …p, [k]: e.target.value }))}>{opts.map(o => {o})} : type === “textarea” ? <textarea className=“inp” rows={3} placeholder={ph} value={form[k] || “”} onChange={e => setForm(p => ({ …p, [k]: e.target.value }))} /> : setForm(p => ({ …p, [k]: e.target.value }))} />}
);

return (

{showForm && (
e.target === e.currentTarget && setShowForm(false)}>
{editId ? “Edit Contact” : “Add Contact”}
setShowForm(false)} style={{ background: G.offWhite, border: “none”, borderRadius: “50%”, width: 30, height: 30, fontSize: 18, cursor: “pointer” }}>×
{editId ? “Save Changes” : “Add Contact”} setShowForm(false)}>Cancel
)}
  <div className="top-header" style={{ paddingBottom: 18 }}>
    <div style={{ display: "flex", justifyContent: "space-between", alignItems: "center" }}>
      <div style={{ fontSize: 18, fontWeight: 800 }}>Team Management</div>
      <button onClick={openAdd} style={{ background: "white", color: G.green, border: "none", borderRadius: 8, padding: "8px 16px", fontWeight: 700, fontSize: 14, cursor: "pointer" }}>+ Add</button>
    </div>
    <div style={{ fontSize: 12, opacity: .75, marginTop: 4 }}>{executives.filter(e => e.active).length} active · {executives.length} total</div>
  </div>

  <div style={{ padding: "12px 16px 100px" }}>
    {executives.map((e, i) => (
      <div key={e.id} className="section-card su" style={{ animationDelay: `${i * .04}s`, opacity: e.active ? 1 : .55 }}>
        <div style={{ padding: "14px 16px" }}>
          <div style={{ display: "flex", gap: 12, alignItems: "flex-start" }}>
            <div className="av" style={{ width: 48, height: 48, fontSize: 15, color: "white", background: e.color }}>{e.avatar}</div>
            <div style={{ flex: 1, minWidth: 0 }}>
              <div style={{ display: "flex", gap: 8, alignItems: "center", marginBottom: 2 }}>
                <div style={{ fontWeight: 800, fontSize: 15 }}>{e.firstName} {e.lastName}</div>
                {!e.active && <span className="badge" style={{ background: G.redLt, color: G.red }}>Inactive</span>}
              </div>
              <div style={{ fontSize: 12, color: G.green, fontWeight: 600 }}>{e.role}</div>
              <div style={{ fontSize: 12, color: G.textLt }}>{e.company}</div>
              <div style={{ display: "flex", gap: 6, marginTop: 8, flexWrap: "wrap" }}>
                <span className="tag" style={{ background: e.followUpStatus === "Hot Lead" ? G.redLt : e.followUpStatus === "Warm" ? G.amberLt : G.greenLt, color: e.followUpStatus === "Hot Lead" ? G.red : e.followUpStatus === "Warm" ? G.amber : G.green }}>{e.followUpStatus}</span>
                <span className="tag" style={{ background: G.blueLt, color: G.blue }}>{e.kycStatus}</span>
                <span className="tag" style={{ background: G.offWhite, color: G.textMd }}>{e.priority}</span>
              </div>
            </div>
            <div style={{ display: "flex", flexDirection: "column", gap: 6, alignItems: "flex-end" }}>
              <div style={{ fontWeight: 700, fontSize: 14, color: G.text, fontFamily: "'JetBrains Mono'" }}>{fmt(e.salary, e.currency)}</div>
              <div style={{ fontSize: 10, color: G.textLt }}>{e.payFreq}</div>
            </div>
          </div>
          <div style={{ display: "flex", gap: 8, marginTop: 12 }}>
            <button className="btn-ghost btn-sm" style={{ flex: 1 }} onClick={() => openEdit(e)}>✏️ Edit</button>
            <button className="btn-ghost btn-sm" onClick={() => toggle(e.id)}>{e.active ? "Deactivate" : "Activate"}</button>
            <button className="btn-red btn-sm" onClick={() => remove(e.id, `${e.firstName} ${e.lastName}`)}>🗑</button>
          </div>
        </div>
      </div>
    ))}
  </div>
</div>

);
}

/* ══════════════════ FINANCE ADMIN ══════════════════ */ function FinanceAdmin({ finance, setFinance, totalBalance, totalPayroll, revenue, expenses, toast, addAuditLog, setModal }) { const [subTab, setSubTab] = useState(“overview”);
const profit = revenue - expenses;

const SubNav = () => (

{[“overview”, “accounts”, “payroll”, “transactions”, “budget”].map(t => ( setSubTab(t)} style={{ padding: “12px 14px”, background: “transparent”, border: “none”, borderBottom: `2.5px solid ${subTab === t ? G.green : "transparent"}`, color: subTab === t ? G.green : G.textLt, fontWeight: 700, fontSize: 12, cursor: “pointer”, whiteSpace: “nowrap”, fontFamily: “‘Plus Jakarta Sans’,sans-serif”, textTransform: “capitalize” }}> {t} ))}
);

const approvePayment = (id) => {
setFinance(p => ({ …p, payrollSchedule: p.payrollSchedule.map(r => r.id === id ? { …r, status: “Approved” } : r) })); addAuditLog(“Payment approved”, finance.payrollSchedule.find(r => r.id === id)?.name, “success”, “Finance”); toast(“Payment approved ✓”);
};

const holdPayment = (id) => {
setFinance(p => ({ …p, payrollSchedule: p.payrollSchedule.map(r => r.id === id ? { …r, status: “On Hold” } : r) })); addAuditLog(“Payment held”, finance.payrollSchedule.find(r => r.id === id)?.name, “warn”, “Finance”); toast(“Payment placed on hold”);
};

return (

Finance Control
Accounts · Payroll · Budget · Transactions
    {subTab === "overview" && (
      <div className="su">
        <div style={{ display: "grid", gridTemplateColumns: "1fr 1fr", gap: 10, marginBottom: 16 }}>
          {[
            { icon: "🏦", label: "Total Balance",   value: fmt(totalBalance), color: G.green },
            { icon: "📈", label: "Revenue MTD",     value: fmt(revenue),      color: G.blue },
            { icon: "📉", label: "Expenses MTD",    value: fmt(expenses),     color: G.red },
            { icon: "💹", label: "Net Profit MTD",  value: fmt(profit),       color: profit >= 0 ? G.green : G.red },
          ].map((k, i) => (
            <div key={i} style={{ background: G.white, border: `1px solid ${G.border}`, borderRadius: 14, padding: 16 }}>
              <div style={{ fontSize: 20, marginBottom: 6 }}>{k.icon}</div>
              <div style={{ fontSize: 10, color: G.textLt, fontWeight: 700, letterSpacing: ".5px" }}>{k.label.toUpperCase()}</div>
              <div style={{ fontSize: 20, fontWeight: 800, color: k.color, marginTop: 2 }}>{k.value}</div>
            </div>
          ))}
        </div>

        <div className="section-card" style={{ marginBottom: 14 }}>
          <div style={{ padding: "14px 16px 8px", fontWeight: 700, fontSize: 14 }}>📊 Budget Utilisation</div>
          {finance.budgetLines.map(b => {
            const pct = Math.min(100, Math.round((b.spent / b.allocated) * 100));
            const col = pct > 80 ? G.red : pct > 60 ? G.amber : G.green;
            return (
              <div key={b.id} style={{ padding: "10px 16px", borderTop: `1px solid ${G.border}` }}>
                <div style={{ display: "flex", justifyContent: "space-between", marginBottom: 4 }}>
                  <span style={{ fontSize: 13, fontWeight: 600 }}>{b.name}</span>
                  <span style={{ fontSize: 12, fontWeight: 700, color: col, fontFamily: "'JetBrains Mono'" }}>{pct}%</span>
                </div>
                <div style={{ display: "flex", justifyContent: "space-between", marginBottom: 5 }}>
                  <span style={{ fontSize: 11, color: G.textLt }}>{fmt(b.spent)} of {fmt(b.allocated)}</span>
                </div>
                <div className="stat-bar"><div className="stat-fill" style={{ width: `${pct}%`, background: col }} /></div>
              </div>
            );
          })}
        </div>

        <div className="section-card">
          <div style={{ padding: "14px 16px 8px", fontWeight: 700, fontSize: 14 }}>💳 Monthly Payroll Summary</div>
          <div style={{ padding: "10px 16px", borderTop: `1px solid ${G.border}` }}>
            <div style={{ display: "flex", justifyContent: "space-between", marginBottom: 4 }}>
              <span style={{ fontSize: 13, color: G.textMd }}>Total scheduled</span>
              <span style={{ fontSize: 14, fontWeight: 800, fontFamily: "'JetBrains Mono'" }}>{fmt(totalPayroll)}</span>
            </div>
            <div style={{ display: "flex", justifyContent: "space-between", marginBottom: 4 }}>
              <span style={{ fontSize: 13, color: G.textMd }}>Scheduled</span>
              <span style={{ fontSize: 13, color: G.green, fontWeight: 700 }}>{finance.payrollSchedule.filter(p => p.status === "Scheduled" || p.status === "Approved").length} exec</span>
            </div>
            <div style={{ display: "flex", justifyContent: "space-between" }}>
              <span style={{ fontSize: 13, color: G.textMd }}>On Hold</span>
              <span style={{ fontSize: 13, color: G.red, fontWeight: 700 }}>{finance.payrollSchedule.filter(p => p.status === "On Hold").length} exec</span>
            </div>
          </div>
        </div>
      </div>
    )}

    {subTab === "accounts" && (
      <div className="su">
        {finance.accounts.map(acc => (
          <div key={acc.id} className="section-card" style={{ marginBottom: 12 }}>
            <div style={{ padding: 16 }}>
              <div style={{ display: "flex", justifyContent: "space-between", alignItems: "flex-start", marginBottom: 10 }}>
                <div>
                  <div style={{ fontWeight: 700, fontSize: 15 }}>{acc.name}</div>
                  <div style={{ fontSize: 12, color: G.textLt }}>{acc.bank} · {acc.number}</div>
                  <span className="tag" style={{ background: G.greenLt, color: G.green, marginTop: 6, display: "inline-block" }}>{acc.type}</span>
                </div>
                <div style={{ textAlign: "right" }}>
                  <div style={{ fontSize: 22, fontWeight: 800, color: G.green, fontFamily: "'JetBrains Mono'" }}>{fmt(acc.balance, acc.currency)}</div>
                  <div style={{ fontSize: 11, color: G.textLt }}>Synced: {fmtDate(acc.lastSync)}</div>
                </div>
              </div>
              <div style={{ display: "flex", gap: 8 }}>
                <button className="btn-ghost btn-sm" style={{ flex: 1 }} onClick={() => { setFinance(p => ({ ...p, accounts: p.accounts.map(a => a.id === acc.id ? { ...a, lastSync: now() } : a) })); toast("Account synced ✓"); }}>↻ Sync</button>
                <button className="btn-ghost btn-sm" onClick={() => { addAuditLog("Account statement downloaded", acc.name, "info", "Finance"); toast("Statement downloaded"); }}>↓ Statement</button>
              </div>
            </div>
          </div>
        ))}
        <button className="btn-outline" onClick={() => { toast("Connect bank account — integrate Plaid/Mono API"); }}>+ Connect Bank Account</button>
      </div>
    )}

    {subTab === "payroll" && (
      <div className="su">
        <div style={{ background: G.amberLt, border: `1px solid ${G.amber}33`, borderRadius: 12, padding: "12px 14px", marginBottom: 14, fontSize: 13, color: G.amber, fontWeight: 600 }}>
          ⚠️ All payroll over $10,000 requires your dual approval as CFO
        </div>
        {finance.payrollSchedule.map(r => {
          const exec = SEED_EXECUTIVES.find(e => e.id === r.execId);
          const isHeld = r.status === "On Hold";
          return (
            <div key={r.id} className="section-card" style={{ marginBottom: 10, borderLeft: `3px solid ${isHeld ? G.red : G.green}` }}>
              <div style={{ padding: 14 }}>
                <div style={{ display: "flex", gap: 12, alignItems: "center", marginBottom: 10 }}>
                  {exec && <div className="av" style={{ width: 40, height: 40, fontSize: 13, color: "white", background: exec.color }}>{exec.avatar}</div>}
                  <div style={{ flex: 1 }}>
                    <div style={{ fontWeight: 700, fontSize: 14 }}>{r.name}</div>
                    <div style={{ fontSize: 12, color: G.textLt }}>{exec?.role}</div>
                  </div>
                  <div style={{ textAlign: "right" }}>
                    <div style={{ fontWeight: 800, fontSize: 16, fontFamily: "'JetBrains Mono'", color: isHeld ? G.red : G.text }}>{fmt(r.amount, r.currency)}</div>
                    <span className="badge" style={{ background: isHeld ? G.redLt : G.greenLt, color: isHeld ? G.red : G.green }}>{r.status}</span>
                  </div>
                </div>
                <div style={{ display: "flex", justifyContent: "space-between", fontSize: 12, color: G.textLt, marginBottom: 10 }}>
                  <span>Next: {fmtDate(r.nextPayDate)}</span>
                  <span>Via {r.processor}</span>
                  <span style={{ color: r.kycOk ? G.green : G.red }}>KYC: {r.kycOk ? "✓" : "✗"}</span>
                </div>
                <div style={{ display: "flex", gap: 8 }}>
                  {isHeld
                    ? <button className="btn-primary btn-sm" onClick={() => approvePayment(r.id)}>✓ Approve Payment</button>
                    : <button className="btn-amber btn-sm" onClick={() => holdPayment(r.id)}>⏸ Place on Hold</button>
                  }
                  <button className="btn-ghost btn-sm" onClick={() => { addAuditLog("Payroll receipt sent", r.name, "info", "Finance"); toast("Receipt sent"); }}>Receipt</button>
                </div>
              </div>
            </div>
          );
        })}
      </div>
    )}

    {subTab === "transactions" && (
      <div className="su">
        {finance.transactions.map(t => (
          <div key={t.id} style={{ display: "flex", gap: 12, padding: "13px 0", borderBottom: `1px solid ${G.border}`, alignItems: "center" }}>
            <div style={{ width: 40, height: 40, borderRadius: 10, background: t.amount > 0 ? G.greenLt : G.redLt, display: "flex", alignItems: "center", justifyContent: "center", fontSize: 18, flexShrink: 0 }}>
              {t.amount > 0 ? "↓" : "↑"}
            </div>
            <div style={{ flex: 1, minWidth: 0 }}>
              <div style={{ fontSize: 13, fontWeight: 600, overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap" }}>{t.desc}</div>
              <div style={{ fontSize: 11, color: G.textLt }}>{fmtDate(t.date)} · {t.category}</div>
            </div>
            <div style={{ textAlign: "right", flexShrink: 0 }}>
              <div style={{ fontWeight: 800, fontSize: 14, color: t.amount > 0 ? G.green : G.red, fontFamily: "'JetBrains Mono'" }}>{t.amount > 0 ? "+" : ""}{fmt(Math.abs(t.amount))}</div>
              <span className="badge" style={{ background: t.status === "Cleared" ? G.greenLt : G.amberLt, color: t.status === "Cleared" ? G.green : G.amber }}>{t.status}</span>
            </div>
          </div>
        ))}
      </div>
    )}

    {subTab === "budget" && (
      <div className="su">
        <div style={{ background: G.white, border: `1px solid ${G.border}`, borderRadius: 12, padding: 16, marginBottom: 14 }}>
          <div style={{ fontWeight: 700, marginBottom: 4 }}>{finance.budget.fy} Annual Budget</div>
          <div style={{ fontSize: 28, fontWeight: 800, color: G.green, fontFamily: "'JetBrains Mono'" }}>{fmt(finance.budget.total)}</div>
          <div style={{ fontSize: 13, color: G.textMd, marginTop: 4 }}>Used: {fmt(finance.budget.used)} · Remaining: {fmt(finance.budget.total - finance.budget.used)}</div>
          <div className="stat-bar" style={{ marginTop: 10 }}><div className="stat-fill" style={{ width: `${Math.round((finance.budget.used / finance.budget.total) * 100)}%`, background: G.green }} /></div>
        </div>
        {finance.budgetLines.map(b => {
          const pct = Math.min(100, Math.round((b.spent / b.allocated) * 100));
          const col = pct > 80 ? G.red : pct > 60 ? G.amber : G.green;
          return (
            <div key={b.id} className="section-card" style={{ padding: 14, marginBottom: 10 }}>
              <div style={{ display: "flex", justifyContent: "space-between", marginBottom: 6 }}>
                <span style={{ fontWeight: 700, fontSize: 14 }}>{b.name}</span>
                <span className="tag" style={{ background: G.greenLt, color: G.green }}>{b.category}</span>
              </div>
              <div style={{ display: "flex", justifyContent: "space-between", fontSize: 12, color: G.textMd, marginBottom: 6 }}>
                <span>Spent: <strong style={{ color: G.text }}>{fmt(b.spent)}</strong></span>
                <span>Allocated: <strong>{fmt(b.allocated)}</strong></span>
                <span style={{ color: col, fontWeight: 700 }}>{pct}%</span>
              </div>
              <div className="stat-bar"><div className="stat-fill" style={{ width: `${pct}%`, background: col }} /></div>
              {pct > 80 && <div style={{ marginTop: 8, fontSize: 12, color: G.red, fontWeight: 600 }}>⚠️ Budget alert — CFO review required</div>}
            </div>
          );
        })}
      </div>
    )}
  </div>
</div>

);
}

/* ══════════════════ GOVERNANCE ADMIN ══════════════════ */ function GovernanceAdmin({ governance, setGovernance, violations, heldFunds, toast, addAuditLog }) { const [subTab, setSubTab] = useState(“policies”);

const togglePolicy = (id) => {
setGovernance(p => ({ …p, policies: p.policies.map(pol => pol.id === id ? { …pol, active: !pol.active } : pol) })); toast(“Policy updated ✓”);
};

const clearViolations = (id) => {
setGovernance(p => ({ …p, policies: p.policies.map(pol => pol.id === id ? { …pol, violations: 0 } : pol) })); addAuditLog(“Violations cleared”, governance.policies.find(p => p.id === id)?.name, “info”, “Governance”); toast(“Violations cleared”);
};

const approveKyc = (id) => {
setGovernance(p => ({ …p, complianceItems: p.complianceItems.map(c => c.id === id ? { …c, status: “Approved”, fundHold: false, holdAmount: 0, amlClear: true, kycDate: now() } : c) })); addAuditLog(“KYC approved”, governance.complianceItems.find(c => c.id === id)?.entity, “success”, “Compliance”); toast(“KYC approved — funds released ✓”);
};

const sevC = { Critical: G.red, High: G.amber, Medium: G.blue, Low: G.green };

const SubNav = () => (

{[“policies”, “compliance”, “roles”, “audit”].map(t => ( setSubTab(t)} style={{ padding: “12px 14px”, background: “transparent”, border: “none”, borderBottom: `2.5px solid ${subTab === t ? G.green : "transparent"}`, color: subTab === t ? G.green : G.textLt, fontWeight: 700, fontSize: 12, cursor: “pointer”, whiteSpace: “nowrap”, fontFamily: “‘Plus Jakarta Sans’,sans-serif”, textTransform: “capitalize” }}> {t} ))}
);

return (

Governance & Compliance
Policies · KYC · Roles · Audit Log
    {subTab === "policies" && (
      <div className="su">
        {violations > 0 && (
          <div style={{ background: G.redLt, border: `1px solid ${G.red}33`, borderRadius: 12, padding: "12px 14px", marginBottom: 14, fontSize: 13, color: G.red, fontWeight: 600 }}>
            ⚠️ {violations} policy violation{violations > 1 ? "s" : ""} require your attention
          </div>
        )}
        {governance.policies.map(pol => (
          <div key={pol.id} className="section-card" style={{ marginBottom: 10, borderLeft: `3px solid ${pol.active ? (sevC[pol.severity] || G.green) : G.border}` }}>
            <div style={{ padding: 14 }}>
              <div style={{ display: "flex", justifyContent: "space-between", alignItems: "flex-start", marginBottom: 8 }}>
                <div style={{ flex: 1, paddingRight: 10 }}>
                  <div style={{ fontWeight: 700, fontSize: 14, marginBottom: 4 }}>{pol.name}</div>
                  <div style={{ fontSize: 12, color: G.textMd, lineHeight: 1.6 }}>{pol.description}</div>
                </div>
                <div className={`toggle ${pol.active ? "" : ""}`} style={{ background: pol.active ? G.green : G.border }} onClick={() => togglePolicy(pol.id)}>
                  <div className="toggle-dot" style={{ left: pol.active ? 23 : 3 }} />
                </div>
              </div>
              <div style={{ display: "flex", gap: 6, flexWrap: "wrap", marginBottom: 10 }}>
                <span className="tag" style={{ background: (sevC[pol.severity] || G.green) + "20", color: sevC[pol.severity] || G.green }}>{pol.severity}</span>
                <span className="tag" style={{ background: G.greenLt, color: G.green }}>{pol.category}</span>
                <span className="tag" style={{ background: G.offWhite, color: G.textMd }}>Owner: {pol.owner}</span>
              </div>
              <div style={{ display: "flex", justifyContent: "space-between", fontSize: 12, color: G.textLt, marginBottom: 10 }}>
                <span>Enforced: <strong style={{ color: G.green }}>{pol.enforced}×</strong></span>
                <span>Violations: <strong style={{ color: pol.violations > 0 ? G.red : G.green }}>{pol.violations}</strong></span>
                <span>Reviewed: {fmtDate(pol.lastReview)}</span>
              </div>
              {pol.violations > 0 && (
                <button className="btn-red btn-sm" on…

import { useState, useEffect, useRef } from “react”;

const FONTS = `@import url('https://fonts.googleapis.com/css2?family=Plus+Jakarta+Sans:wght@300;400;500;600;700;800&family=JetBrains+Mono:wght@400;500;600&display=swap');`;

const G = {
green:”#1B6B3A”, greenDk:”#0F4423”, greenLt:”#E8F5EE”, greenMid:”#2D8653”, greenPale:”#F0FAF4”,
white:”#FFFFFF”, offWhite:”#F8F9FA”, border:”#E5E9EB”, borderMd:”#D0D7DC”,
text:”#1A2028”, textMd:”#4A5568”, textLt:”#8A96A3”,
red:”#E53E3E”, redLt:”#FEE2E2”, amber:”#D97706”, amberLt:”#FEF3C7”,
blue:”#2563EB”, blueLt:”#EFF6FF”, purple:”#7C3AED”, purpleLt:”#EDE9FE”,
teal:”#0D9488”, tealLt:”#CCFBF1”, gold:”#B45309”, goldLt:”#FEF3C7”,
shadow:“0 2px 12px rgba(0,0,0,.08)”, shadowMd:“0 4px 24px rgba(0,0,0,.12)”,
};

const CSS = `${FONTS} *{box-sizing:border-box;margin:0;padding:0;} body{background:${G.offWhite};color:${G.text};font-family:'Plus Jakarta Sans',sans-serif;min-height:100vh;-webkit-font-smoothing:antialiased;} ::-webkit-scrollbar{width:3px;} ::-webkit-scrollbar-thumb{background:${G.greenMid}55;border-radius:2px;} .mono{font-family:'JetBrains Mono',monospace;} @keyframes slideUp{from{opacity:0;transform:translateY(16px);}to{opacity:1;transform:translateY(0);}} @keyframes fadeIn{from{opacity:0;}to{opacity:1;}} @keyframes pop{0%{transform:scale(.95);opacity:0;}100%{transform:scale(1);opacity:1;}} @keyframes pulse{0%,100%{opacity:1;}50%{opacity:.4;}} .su{animation:slideUp .3s ease both;} .fi{animation:fadeIn .2s ease both;} .pp{animation:pop .3s cubic-bezier(.34,1.56,.64,1) both;} .pulse{animation:pulse 2s infinite;} .app{max-width:430px;margin:0 auto;min-height:100vh;background:${G.white};display:flex;flex-direction:column;position:relative;box-shadow:0 0 40px rgba(0,0,0,.1);} .top-header{background:${G.green};color:white;padding:16px 20px;position:sticky;top:0;z-index:50;} .top-header-flat{background:${G.white};border-bottom:1px solid ${G.border};padding:14px 20px;position:sticky;top:0;z-index:50;display:flex;align-items:center;gap:12px;} .btn-primary{background:${G.green};color:white;border:none;border-radius:12px;padding:14px 20px;font-family:'Plus Jakarta Sans',sans-serif;font-weight:700;font-size:15px;cursor:pointer;display:flex;align-items:center;justify-content:center;gap:8px;transition:all .2s;width:100%;} .btn-primary:hover{background:${G.greenDk};} .btn-primary:active{transform:scale(.98);} .btn-outline{background:white;color:${G.green};border:1.5px solid ${G.green};border-radius:12px;padding:13px 20px;font-family:'Plus Jakarta Sans',sans-serif;font-weight:700;font-size:15px;cursor:pointer;display:flex;align-items:center;justify-content:center;gap:8px;transition:all .2s;width:100%;} .btn-outline:hover{background:${G.greenLt};} .btn-sm{padding:8px 16px!important;font-size:13px!important;border-radius:8px!important;} .btn-ghost{background:transparent;border:1px solid ${G.border};color:${G.textMd};border-radius:8px;padding:8px 14px;font-size:13px;font-weight:600;cursor:pointer;font-family:'Plus Jakarta Sans',sans-serif;transition:all .2s;} .btn-ghost:hover{border-color:${G.green};color:${G.green};} .btn-red{background:${G.redLt};color:${G.red};border:1px solid ${G.red}33;border-radius:8px;padding:8px 14px;font-size:13px;font-weight:700;cursor:pointer;font-family:'Plus Jakarta Sans',sans-serif;transition:all .2s;} .btn-red:hover{background:${G.red};color:white;} .btn-amber{background:${G.amberLt};color:${G.amber};border:1px solid ${G.amber}33;border-radius:8px;padding:8px 14px;font-size:13px;font-weight:700;cursor:pointer;font-family:'Plus Jakarta Sans',sans-serif;} .card{background:${G.white};border:1px solid ${G.border};border-radius:16px;overflow:hidden;transition:all .2s;} .section-card{background:${G.white};border:1px solid ${G.border};border-radius:14px;overflow:hidden;margin-bottom:12px;} .list-row{display:flex;align-items:center;padding:14px 20px;border-bottom:1px solid ${G.border};gap:12px;transition:background .15s;cursor:pointer;} .list-row:last-child{border-bottom:none;} .list-row:hover{background:${G.greenPale};} .inp{background:${G.white};border:1.5px solid ${G.border};color:${G.text};border-radius:10px;padding:12px 14px;font-family:'Plus Jakarta Sans',sans-serif;font-size:14px;outline:none;width:100%;transition:border .2s;} .inp:focus{border-color:${G.green};} .inp::placeholder{color:${G.textLt};} .inp-label{font-size:11px;font-weight:700;color:${G.textLt};letter-spacing:.6px;margin-bottom:5px;display:block;} select.inp{appearance:auto;} textarea.inp{resize:none;} .av{border-radius:50%;display:flex;align-items:center;justify-content:center;font-weight:800;flex-shrink:0;letter-spacing:-.5px;} .badge{display:inline-flex;align-items:center;gap:4px;padding:3px 10px;border-radius:20px;font-size:11px;font-weight:700;letter-spacing:.3px;} .tag{display:inline-flex;padding:3px 9px;border-radius:5px;font-size:11px;font-weight:700;letter-spacing:.3px;} .tab-bar{position:sticky;bottom:0;background:${G.white};border-top:1px solid ${G.border};display:flex;z-index:50;} .tab-btn{flex:1;padding:9px 2px 11px;display:flex;flex-direction:column;align-items:center;gap:2px;cursor:pointer;border:none;background:transparent;transition:all .15s;font-family:'Plus Jakarta Sans',sans-serif;} .tab-btn.on{color:${G.green};} .tab-btn.off{color:${G.textLt};} .tab-icon{font-size:19px;line-height:1;} .tab-label{font-size:9px;font-weight:700;letter-spacing:.4px;} .toast{position:fixed;bottom:80px;left:50%;transform:translateX(-50%);background:${G.greenDk};color:white;padding:11px 22px;border-radius:30px;font-size:14px;font-weight:600;z-index:999;white-space:nowrap;box-shadow:${G.shadowMd};pointer-events:none;} .modal-bg{position:fixed;inset:0;background:rgba(0,0,0,.55);z-index:200;display:flex;align-items:flex-end;justify-content:center;} .modal-sheet{background:${G.white};border-radius:20px 20px 0 0;width:100%;max-width:430px;max-height:92vh;overflow-y:auto;padding:0 0 28px;} .modal-handle{width:36px;height:4px;background:${G.border};border-radius:2px;margin:12px auto 18px;} .toggle{width:46px;height:26px;border-radius:13px;cursor:pointer;position:relative;transition:background .25s;flex-shrink:0;} .toggle-dot{position:absolute;top:3px;width:20px;height:20px;border-radius:50%;background:white;transition:left .25s;box-shadow:0 2px 5px rgba(0,0,0,.25);} .divider{height:1px;background:${G.border};margin:12px 0;} .stat-bar{height:6px;background:${G.border};border-radius:3px;overflow:hidden;margin-top:6px;} .stat-fill{height:100%;border-radius:3px;transition:width 1s ease;}`;

/* ══════════════════ CONSTANTS ══════════════════ */
const uid = () => Math.random().toString(36).slice(2, 9);
const now = () => new Date().toISOString().slice(0, 10);
const fmt = (n, c = “USD”) => { try { return new Intl.NumberFormat(“en-US”, { style: “currency”, currency: c, minimumFractionDigits: 0 }).format(n || 0); } catch { return `$${n}`; } };
const fmtDate = d => d ? new Date(d).toLocaleDateString(“en-GB”, { day: “2-digit”, month: “short”, year: “numeric” }) : “—”;

const ADMIN_PIN = “2025”;
const KEY = “exec_hub_v2”;
const save = d => { try { localStorage.setItem(KEY, JSON.stringify(d)); } catch {} };
const load = () => { try { return JSON.parse(localStorage.getItem(KEY)); } catch { return null; } };

/* ══════════════════ SEED DATA ══════════════════ */
const SEED_EXECUTIVES = [
{ id: “satya”, firstName: “Satya”, lastName: “Nadella”, role: “Chairman & CEO”, company: “Microsoft”, email: “satyan@microsoft.com”, phone: “+1 425 882 8080”, whatsapp: “”, linkedin: “linkedin.com/in/satyanadella”, avatar: “SN”, color: “#0078D4”, metAt: “Microsoft Leadership Summit”, followUpStatus: “Warm”, priority: “High”, category: “Strategy”, salary: 55000, currency: “USD”, payFreq: “Monthly”, kycStatus: “Approved”, active: true, bio: “Chairman and CEO of Microsoft. Drives company-wide vision, AI strategy, and board-level decisions.”, decisionDomains: [“Company-wide strategy”, “Major acquisitions >$100M”, “Board reporting”, “AI and cloud roadmap”], whenToContact: “Spans multiple divisions, board-level decision, strategic partnership >$100M, or company-wide direction.”, whenDone: “Written email confirmation or board minutes. All decisions >$500M documented in board minutes.”, commStyle: “Data-driven, concise. Lead with metrics and customer impact. Growth mindset framing.”, tags: [“CEO”, “Strategy”, “AI”, “Cloud”] },
{ id: “brad”, firstName: “Brad”, lastName: “Smith”, role: “Vice Chair & President”, company: “Microsoft”, email: “brsmith@microsoft.com”, phone: “+1 425 882 8080”, whatsapp: “”, linkedin: “linkedin.com/in/bradsmithpresident”, avatar: “BS”, color: “#5C2D91”, metAt: “GDPR Compliance Forum”, followUpStatus: “Hot Lead”, priority: “High”, category: “Legal”, salary: 45000, currency: “USD”, payFreq: “Monthly”, kycStatus: “Approved”, active: true, bio: “Vice Chair and President leading legal, corporate affairs, government relations, and privacy policy.”, decisionDomains: [“Legal decisions”, “GDPR/data privacy”, “Regulatory compliance”, “Antitrust matters”, “Contract review”], whenToContact: “Any legal risk, GDPR issue, contract >$1M, government engagement, or regulatory filing.”, whenDone: “Legal opinion issued in writing, contract countersigned, or DPA sign-off received.”, commStyle: “Formal, risk-aware. Lead with legal/regulatory dimension. Cite specific laws. Include risk rating.”, tags: [“Legal”, “GDPR”, “Compliance”, “Policy”] },
{ id: “judson”, firstName: “Judson”, lastName: “Althoff”, role: “EVP — Commercial Business”, company: “Microsoft”, email: “jalthoff@microsoft.com”, phone: “+1 425 882 8080”, whatsapp: “+1 425 882 8080”, linkedin: “linkedin.com/in/judsonalthoff”, avatar: “JA”, color: “#107C10”, metAt: “Microsoft Partner Summit”, followUpStatus: “Hot Lead”, priority: “High”, category: “Sales”, salary: 48000, currency: “USD”, payFreq: “Monthly”, kycStatus: “Approved”, active: true, bio: “EVP overseeing enterprise sales, partner ecosystem, and commercial go-to-market strategy globally.”, decisionDomains: [“Enterprise sales strategy”, “Commercial deal structuring”, “Partner ecosystem”, “Revenue targets”], whenToContact: “Enterprise deal needs executive sponsor, partner agreement approval, or strategic account needs C-suite.”, whenDone: “Deal logged Closed-Won in CRM, partner agreement countersigned.”, commStyle: “Energetic, metrics-oriented. Frame in revenue impact. Lead with pipeline data and ARR numbers.”, tags: [“Sales”, “Revenue”, “Enterprise”, “Partnerships”] },
{ id: “amyc”, firstName: “Amy”, lastName: “Coleman”, role: “EVP & Chief People Officer”, company: “Microsoft”, email: “acoleman@microsoft.com”, phone: “+1 425 882 8080”, whatsapp: “”, linkedin: “linkedin.com/in/amycolemanhr”, avatar: “AC”, color: “#D97706”, metAt: “Future of Work Conference”, followUpStatus: “Warm”, priority: “Medium”, category: “People”, salary: 42000, currency: “USD”, payFreq: “Monthly”, kycStatus: “Approved”, active: true, bio: “EVP and Chief People Officer leading global HR, talent, culture, DE&I, and employee experience.”, decisionDomains: [“Executive hiring”, “Compensation structure”, “Workforce planning”, “Culture programmes”, “DE&I strategy”], whenToContact: “Executive hire/termination, compensation benchmarking, org restructure >10 people, cultural issue.”, whenDone: “Offer letter in HR system, org change in HRIS, or written HR confirmation.”, commStyle: “Warm, people-centred. Lead with human impact. Frame business cases in terms of employee effect.”, tags: [“HR”, “People”, “Culture”, “Talent”] },
{ id: “kathleen”, firstName: “Kathleen”, lastName: “Hogan”, role: “EVP — Strategy & Transformation”, company: “Microsoft”, email: “kahogan@microsoft.com”, phone: “+1 425 882 8080”, whatsapp: “”, linkedin: “linkedin.com/in/kathleenhogan”, avatar: “KH”, color: “#0369A1”, metAt: “Digital Transformation Summit”, followUpStatus: “Warm”, priority: “Medium”, category: “Strategy”, salary: 44000, currency: “USD”, payFreq: “Monthly”, kycStatus: “Approved”, active: true, bio: “EVP Office of Strategy and Transformation. Leads strategic planning, OKRs, and cross-functional alignment.”, decisionDomains: [“Corporate strategic planning”, “Transformation governance”, “OKR framework”, “Cross-functional alignment”], whenToContact: “Cross-functional initiative needs governance, strategic planning input needed, OKRs to set or review.”, whenDone: “Initiative in strategic planning system, OKRs published, or programme charter with milestones issued.”, commStyle: “Strategic, outcome-oriented. Think in OKRs. Show measurable outcomes and transformation arc.”, tags: [“Strategy”, “OKRs”, “Transformation”, “Planning”] },
{ id: “takeshi”, firstName: “Takeshi”, lastName: “Numoto”, role: “EVP & Chief Marketing Officer”, company: “Microsoft”, email: “tnumoto@microsoft.com”, phone: “+1 425 882 8080”, whatsapp: “+1 425 882 8080”, linkedin: “linkedin.com/in/takeshinumoto”, avatar: “TN”, color: “#DC2626”, metAt: “Microsoft Inspire”, followUpStatus: “Warm”, priority: “Medium”, category: “Marketing”, salary: 43000, currency: “USD”, payFreq: “Monthly”, kycStatus: “Approved”, active: true, bio: “EVP and CMO leading global brand, product marketing, campaigns, and demand generation.”, decisionDomains: [“Global brand strategy”, “Campaign approval”, “Product launch marketing”, “PR & external comms”], whenToContact: “Major campaign CMO approval, product launch marketing, PR crisis, analyst/press briefing.”, whenDone: “Campaign brief signed off, press release approved, messaging framework locked.”, commStyle: “Creative, customer-story driven. Lead with customer story first. Use crisp messaging frameworks.”, tags: [“Marketing”, “Brand”, “PR”, “Campaigns”] },
];

const SEED_FINANCE = {
budget: { total: 500000, used: 187400, currency: “USD”, fy: “FY2026” },
accounts: [
{ id: uid(), name: “SwiftFund Operating”, bank: “GTBank”, number: “****4421”, balance: 124500, currency: “USD”, type: “Operating”, lastSync: now() },
{ id: uid(), name: “SwiftFund Payroll”, bank: “Access Bank”, number: “****8830”, balance: 68200, currency: “USD”, type: “Payroll”, lastSync: now() },
{ id: uid(), name: “Wise Multi-Currency”, bank: “Wise”, number: “****2291”, balance: 31400, currency: “USD”, type: “FX”, lastSync: now() },
],
transactions: [
{ id: uid(), date: “2026-03-01”, desc: “Satya Nadella — Monthly Retainer”, amount: -55000, type: “Payroll”, category: “Executive Pay”, status: “Cleared”, exec: “satya” },
{ id: uid(), date: “2026-03-01”, desc: “Brad Smith — Monthly Retainer”, amount: -45000, type: “Payroll”, category: “Executive Pay”, status: “Cleared”, exec: “brad” },
{ id: uid(), date: “2026-03-01”, desc: “Judson Althoff — Monthly Retainer”, amount: -48000, type: “Payroll”, category: “Executive Pay”, status: “Cleared”, exec: “judson” },
{ id: uid(), date: “2026-03-05”, desc: “SwiftFund SaaS Revenue — March”, amount: 28400, type: “Income”, category: “Revenue”, status: “Cleared”, exec: null },
{ id: uid(), date: “2026-03-08”, desc: “Enterprise Deal — TechCorp Ltd”, amount: 45000, type: “Income”, category: “Revenue”, status: “Cleared”, exec: null },
{ id: uid(), date: “2026-03-10”, desc: “AWS Infrastructure — March”, amount: -8200, type: “Expense”, category: “Infrastructure”, status: “Cleared”, exec: null },
{ id: uid(), date: “2026-03-12”, desc: “Legal Compliance Review — Q1”, amount: -12000, type: “Expense”, category: “Legal”, status: “Pending”, exec: “brad” },
{ id: uid(), date: “2026-03-14”, desc: “Marketing Campaign — Africa Expansion”, amount: -15000, type: “Expense”, category: “Marketing”, status: “Pending”, exec: “takeshi” },
],
budgetLines: [
{ id: uid(), name: “Executive Payroll”, allocated: 280000, spent: 131000, category: “People” },
{ id: uid(), name: “Infrastructure & Cloud”, allocated: 60000, spent: 24600, category: “Tech” },
{ id: uid(), name: “Sales & Marketing”, allocated: 80000, spent: 31800, category: “GTM” },
{ id: uid(), name: “Legal & Compliance”, allocated: 40000, spent: 12000, category: “Legal” },
{ id: uid(), name: “Operations”, allocated: 40000, spent: 18000, category: “Ops” },
],
payrollSchedule: [
{ id: uid(), execId: “satya”, name: “Satya Nadella”, amount: 55000, currency: “USD”, nextPayDate: “2026-04-01”, status: “Scheduled”, processor: “Wire”, kycOk: true },
{ id: uid(), execId: “brad”, name: “Brad Smith”, amount: 45000, currency: “USD”, nextPayDate: “2026-04-01”, status: “Scheduled”, processor: “Wire”, kycOk: true },
{ id: uid(), execId: “judson”, name: “Judson Althoff”, amount: 48000, currency: “USD”, nextPayDate: “2026-04-01”, status: “Scheduled”, processor: “Wire”, kycOk: true },
{ id: uid(), execId: “amyc”, name: “Amy Coleman”, amount: 42000, currency: “USD”, nextPayDate: “2026-04-01”, status: “On Hold”, processor: “Wire”, kycOk: true },
{ id: uid(), execId: “kathleen”, name: “Kathleen Hogan”, amount: 44000, currency: “USD”, nextPayDate: “2026-04-01”, status: “Scheduled”, processor: “Wire”, kycOk: true },
{ id: uid(), execId: “takeshi”, name: “Takeshi Numoto”, amount: 43000, currency: “USD”, nextPayDate: “2026-04-01”, status: “Scheduled”, processor: “Wire”, kycOk: true },
],
};

const SEED_GOVERNANCE = {
policies: [
{ id: uid(), name: “Executive Payment Dual Approval”, category: “Finance”, severity: “Critical”, description: “All executive payments >$10,000 require CFO sign-off before processing.”, active: true, owner: “Amy Hood”, lastReview: now(), violations: 0, enforced: 12 },
{ id: uid(), name: “GDPR Data Access Logging”, category: “Compliance”, severity: “Critical”, description: “All access to personal data must be logged with timestamp, user ID, and purpose.”, active: true, owner: “Brad Smith”, lastReview: now(), violations: 0, enforced: 847 },
{ id: uid(), name: “Legal Review — Contracts >$1M”, category: “Legal”, severity: “High”, description: “All contracts exceeding $1M must be reviewed by Brad Smith’s legal team before execution.”, active: true, owner: “Brad Smith”, lastReview: now(), violations: 1, enforced: 8 },
{ id: uid(), name: “Budget Variance Escalation”, category: “Finance”, severity: “High”, description: “Any budget line exceeding 80% utilisation triggers CFO review before further spend.”, active: true, owner: “Amy Hood”, lastReview: now(), violations: 0, enforced: 4 },
{ id: uid(), name: “KYC Before First Payment”, category: “Compliance”, severity: “Critical”, description: “No executive or contractor may receive payment before KYC is verified and approved.”, active: true, owner: “Amy Hood”, lastReview: now(), violations: 0, enforced: 6 },
{ id: uid(), name: “Quarterly OKR Review”, category: “Strategy”, severity: “Medium”, description: “All teams must submit OKR progress report to Kathleen Hogan’s office by last Friday of each quarter.”, active: true, owner: “Kathleen Hogan”, lastReview: now(), violations: 2, enforced: 4 },
{ id: uid(), name: “PR Response — 24h SLA”, category: “Communications”, severity: “High”, description: “All media and press enquiries must receive a response within 24 hours via Takeshi Numoto’s office.”, active: true, owner: “Takeshi Numoto”, lastReview: now(), violations: 0, enforced: 7 },
{ id: uid(), name: “Headcount Freeze — Unapproved Roles”, category: “People”, severity: “Medium”, description: “No new hiring may proceed without Amy Coleman’s written headcount approval.”, active: false, owner: “Amy Coleman”, lastReview: now(), violations: 0, enforced: 3 },
],
auditLog: [
{ id: uid(), ts: “10:14”, date: now(), user: “Amy Hood”, action: “Approved payment”, detail: “Satya Nadella — $55,000 March retainer”, level: “info”, category: “Finance” },
{ id: uid(), ts: “09:52”, date: now(), user: “Amy Hood”, action: “Policy enforced”, detail: “KYC Before First Payment — Amy Coleman cleared”, level: “success”, category: “Compliance” },
{ id: uid(), ts: “09:31”, date: now(), user: “System”, action: “Budget alert”, detail: “Executive Payroll line at 81% — CFO review triggered”, level: “warn”, category: “Finance” },
{ id: uid(), ts: “08:44”, date: now(), user: “Brad Smith”, action: “Legal review completed”, detail: “Q1 Compliance Review — approved”, level: “success”, category: “Legal” },
{ id: uid(), ts: “08:12”, date: now(), user: “Amy Hood”, action: “Contact updated”, detail: “Takeshi Numoto — status changed to Warm”, level: “info”, category: “CRM” },
{ id: uid(), ts: “Yesterday”, date: “2026-03-14”, user: “Judson Althoff”, action: “Deal logged”, detail: “TechCorp Ltd — $45,000 Closed-Won”, level: “success”, category: “Sales” },
{ id: uid(), ts: “Yesterday”, date: “2026-03-14”, user: “System”, action: “Policy violation”, detail: “Legal Review policy — contract submitted without review”, level: “danger”, category: “Legal” },
],
roles: [
{ id: uid(), name: “Super Admin”, description: “Full system access — Amy Hood only”, color: G.green, permissions: [“all”], assignedTo: [“Amy Hood”] },
{ id: uid(), name: “Finance Admin”, description: “Full finance and payroll access”, color: G.blue, permissions: [“finance.view”, “finance.edit”, “payroll.view”, “payroll.approve”], assignedTo: [“Amy Hood”] },
{ id: uid(), name: “Governance Admin”, description: “Policy management and audit access”, color: G.purple, permissions: [“policy.view”, “policy.edit”, “audit.view”], assignedTo: [“Brad Smith”, “Amy Hood”] },
{ id: uid(), name: “Contact Manager”, description: “View and edit all executive contacts”, color: G.amber, permissions: [“contacts.view”, “contacts.edit”], assignedTo: [“Amy Hood”] },
{ id: uid(), name: “Read Only”, description: “View contacts and reports only”, color: G.textLt, permissions: [“contacts.view”, “reports.view”], assignedTo: [] },
],
complianceItems: [
{ id: uid(), entity: “Satya Nadella”, type: “KYC”, status: “Approved”, kycDate: “2026-01-10”, expiryDate: “2027-01-10”, documents: [“Passport”, “Tax ID”], fundHold: false, holdAmount: 0, amlClear: true },
{ id: uid(), entity: “Brad Smith”, type: “KYC”, status: “Approved”, kycDate: “2026-01-08”, expiryDate: “2027-01-08”, documents: [“Passport”, “Government ID”], fundHold: false, holdAmount: 0, amlClear: true },
{ id: uid(), entity: “Judson Althoff”, type: “KYC”, status: “Approved”, kycDate: “2026-01-12”, expiryDate: “2027-01-12”, documents: [“Passport”, “Tax ID”, “Bank Letter”], fundHold: false, holdAmount: 0, amlClear: true },
{ id: uid(), entity: “Amy Coleman”, type: “KYC”, status: “Approved”, kycDate: “2026-01-15”, expiryDate: “2027-01-15”, documents: [“Passport”], fundHold: false, holdAmount: 0, amlClear: true },
{ id: uid(), entity: “Kathleen Hogan”, type: “KYC”, status: “Approved”, kycDate: “2026-01-20”, expiryDate: “2027-01-20”, documents: [“Passport”, “Tax ID”], fundHold: false, holdAmount: 0, amlClear: true },
{ id: uid(), entity: “Takeshi Numoto”, type: “KYC”, status: “Pending”, kycDate: “”, expiryDate: “”, documents: [“Passport”], fundHold: true, holdAmount: 43000, amlClear: false },
{ id: uid(), entity: “SwiftFund Ltd”, type: “KYB”, status: “Approved”, kycDate: “2025-11-01”, expiryDate: “2026-11-01”, documents: [“Certificate of Inc.”, “Director IDs”, “Bank Letter”, “Tax Clearance”], fundHold: false, holdAmount: 0, amlClear: true },
],
};

/* ══════════════════ ROOT ══════════════════ */
export default function App() {
const s = load();
const [authenticated, setAuthenticated] = useState(false);
const [tab, setTab]               = useState(“dashboard”);
const [executives, setExecutives] = useState(s?.executives || SEED_EXECUTIVES);
const [finance, setFinance]       = useState(s?.finance    || SEED_FINANCE);
const [governance, setGovernance] = useState(s?.governance || SEED_GOVERNANCE);
const [tasks, setTasks]           = useState(s?.tasks      || []);
const [toastMsg, setToastMsg]     = useState(””);
const [modal, setModal]           = useState(null); // {type, data}

useEffect(() => { save({ executives, finance, governance, tasks }); }, [executives, finance, governance, tasks]);

const toast = (msg, dur = 2800) => { setToastMsg(msg); setTimeout(() => setToastMsg(””), dur); };

const addAuditLog = (action, detail, level = “info”, category = “System”) => {
const entry = { id: uid(), ts: new Date().toLocaleTimeString([], { hour: “2-digit”, minute: “2-digit” }), date: now(), user: “Amy Hood”, action, detail, level, category };
setGovernance(p => ({ …p, auditLog: [entry, …p.auditLog.slice(0, 99)] }));
};

const totalBalance = finance.accounts.reduce((a, b) => a + b.balance, 0);
const totalPayroll = finance.payrollSchedule.reduce((a, b) => a + b.amount, 0);
const revenue = finance.transactions.filter(t => t.amount > 0).reduce((a, b) => a + b.amount, 0);
const expenses = finance.transactions.filter(t => t.amount < 0).reduce((a, b) => a + Math.abs(b.amount), 0);
const violations = governance.policies.reduce((a, b) => a + b.violations, 0);
const heldFunds = governance.complianceItems.filter(c => c.fundHold).reduce((a, b) => a + b.holdAmount, 0);

if (!authenticated) return <PinGate onUnlock={() => setAuthenticated(true)} />;

const NAV = [
{ k: “dashboard”, icon: “⬡”, label: “HOME” },
{ k: “contacts”,  icon: “👥”, label: “TEAM” },
{ k: “finance”,   icon: “💰”, label: “FINANCE” },
{ k: “govern”,    icon: “⚖️”, label: “GOVERN” },
{ k: “settings”,  icon: “⚙️”, label: “SYSTEM” },
];

return (
<div style={{ background: G.offWhite, minHeight: “100vh”, display: “flex”, justifyContent: “center” }}>
<style>{CSS}</style>
<div className="app">
{toastMsg && <div className="toast fi">✓ {toastMsg}</div>}
{modal && <ModalRouter modal={modal} setModal={setModal} executives={executives} setExecutives={setExecutives} finance={finance} setFinance={setFinance} governance={governance} setGovernance={setGovernance} toast={toast} addAuditLog={addAuditLog} />}

```
    {tab === "dashboard" && <DashboardView executives={executives} finance={{ ...finance, totalBalance, totalPayroll, revenue, expenses }} governance={{ ...governance, violations, heldFunds }} tasks={tasks} setTab={setTab} setModal={setModal} />}
    {tab === "contacts"  && <ContactsAdmin executives={executives} setExecutives={setExecutives} toast={toast} addAuditLog={addAuditLog} setModal={setModal} />}
    {tab === "finance"   && <FinanceAdmin finance={finance} setFinance={setFinance} totalBalance={totalBalance} totalPayroll={totalPayroll} revenue={revenue} expenses={expenses} toast={toast} addAuditLog={addAuditLog} setModal={setModal} />}
    {tab === "govern"    && <GovernanceAdmin governance={governance} setGovernance={setGovernance} violations={violations} heldFunds={heldFunds} toast={toast} addAuditLog={addAuditLog} />}
    {tab === "settings"  && <SystemSettings executives={executives} setExecutives={setExecutives} finance={finance} governance={governance} tasks={tasks} toast={toast} addAuditLog={addAuditLog} onLock={() => setAuthenticated(false)} />}

    <div className="tab-bar">
      {NAV.map(n => (
        <button key={n.k} className={`tab-btn ${tab === n.k ? "on" : "off"}`} onClick={() => setTab(n.k)}>
          <div className="tab-icon">{n.icon}</div>
          <div className="tab-label">{n.label}</div>
        </button>
      ))}
    </div>
  </div>
</div>
```

);
}

/* ══════════════════ PIN GATE ══════════════════ */
function PinGate({ onUnlock }) {
const [pin, setPin] = useState(””);
const [error, setError] = useState(false);
const check = (p) => { if (p === ADMIN_PIN) { onUnlock(); } else if (p.length === 4) { setError(true); setPin(””); setTimeout(() => setError(false), 1000); } };
const press = (d) => { const np = pin + d; setPin(np); if (np.length === 4) check(np); };
return (
<div style={{ background: G.green, minHeight: “100vh”, display: “flex”, alignItems: “center”, justifyContent: “center” }}>
<style>{CSS}</style>
<div style={{ background: “white”, borderRadius: 24, padding: 36, width: 340, textAlign: “center”, boxShadow: “0 20px 60px rgba(0,0,0,.2)” }} className=“pp”>
<div style={{ fontSize: 44, marginBottom: 12 }}>🔐</div>
<div style={{ fontWeight: 800, fontSize: 22, marginBottom: 4 }}>Admin Panel</div>
<div style={{ fontSize: 13, color: G.textLt, marginBottom: 28 }}>Executive Hub — SwiftFund</div>
<div style={{ display: “flex”, gap: 12, justifyContent: “center”, marginBottom: 28 }}>
{[0, 1, 2, 3].map(i => (
<div key={i} style={{ width: 16, height: 16, borderRadius: “50%”, background: pin.length > i ? (error ? G.red : G.green) : G.border, transition: “background .2s” }} />
))}
</div>
<div style={{ display: “grid”, gridTemplateColumns: “repeat(3,1fr)”, gap: 10 }}>
{[1,2,3,4,5,6,7,8,9,””,0,“⌫”].map((d, i) => (
<button key={i} onClick={() => { if (d === “⌫”) setPin(p => p.slice(0, -1)); else if (d !== “”) press(String(d)); }} style={{ padding: “16px 8px”, borderRadius: 12, border: `1px solid ${G.border}`, background: d === “” ? “transparent” : G.offWhite, fontSize: 20, fontWeight: 700, cursor: d === “” ? “default” : “pointer”, color: G.text, fontFamily: “‘Plus Jakarta Sans’,sans-serif”, transition: “all .15s” }} onMouseDown={e => { if (d !== “”) e.currentTarget.style.background = G.greenLt; }} onMouseUp={e => { if (d !== “”) e.currentTarget.style.background = G.offWhite; }}>
{d}
</button>
))}
</div>
{error && <div style={{ color: G.red, fontSize: 13, fontWeight: 700, marginTop: 16 }}>Incorrect PIN — try again</div>}
<div style={{ fontSize: 11, color: G.textLt, marginTop: 20 }}>Default PIN: 2025 — change in System settings</div>
</div>
</div>
);
}

/* ══════════════════ DASHBOARD ══════════════════ */
function DashboardView({ executives, finance, governance, tasks, setTab, setModal }) {
const pending = tasks.filter(t => !t.done);
const hotLeads = executives.filter(e => e.followUpStatus === “Hot Lead”);
const recentAudit = governance.auditLog.slice(0, 4);

const KpiCard = ({ icon, label, value, sub, color, onClick }) => (
<div onClick={onClick} style={{ background: G.white, border: `1px solid ${G.border}`, borderRadius: 14, padding: “16px 14px”, cursor: onClick ? “pointer” : “default”, transition: “all .2s” }} onMouseEnter={e => e.currentTarget.style.borderColor = color + “66”} onMouseLeave={e => e.currentTarget.style.borderColor = G.border}>
<div style={{ fontSize: 22, marginBottom: 8 }}>{icon}</div>
<div style={{ fontSize: 11, color: G.textLt, fontWeight: 700, letterSpacing: “.5px”, marginBottom: 4 }}>{label.toUpperCase()}</div>
<div style={{ fontSize: 22, fontWeight: 800, color, lineHeight: 1.1, marginBottom: 4 }}>{value}</div>
{sub && <div style={{ fontSize: 11, color: G.textLt }}>{sub}</div>}
</div>
);

return (
<div style={{ flex: 1, overflow: “auto” }}>
<div className=“top-header” style={{ paddingBottom: 20 }}>
<div style={{ display: “flex”, justifyContent: “space-between”, alignItems: “center”, marginBottom: 4 }}>
<div style={{ fontSize: 18, fontWeight: 800 }}>Admin Dashboard</div>
<div style={{ background: “rgba(255,255,255,.2)”, borderRadius: 8, padding: “4px 12px”, fontSize: 11, fontWeight: 700 }}>Amy Hood · CFO</div>
</div>
<div style={{ fontSize: 12, opacity: .75 }}>SwiftFund Executive Control Centre</div>
</div>

```
  <div style={{ padding: "16px 16px 100px" }}>
    <div style={{ display: "grid", gridTemplateColumns: "1fr 1fr", gap: 10, marginBottom: 16 }}>
      <KpiCard icon="💰" label="Total Balance" value={fmt(finance.totalBalance)} sub={`${finance.accounts.length} accounts`} color={G.green} onClick={() => setTab("finance")} />
      <KpiCard icon="📈" label="Revenue MTD" value={fmt(finance.revenue)} sub="This month" color={G.blue} onClick={() => setTab("finance")} />
      <KpiCard icon="👥" label="Executives" value={executives.filter(e => e.active).length} sub={`${executives.length} total`} color={G.amber} onClick={() => setTab("contacts")} />
      <KpiCard icon="⚠️" label="Violations" value={governance.violations} sub={`${governance.policies.filter(p => p.active).length} active policies`} color={governance.violations > 0 ? G.red : G.green} onClick={() => setTab("govern")} />
    </div>

    {governance.heldFunds > 0 && (
      <div style={{ background: G.redLt, border: `1px solid ${G.red}33`, borderRadius: 12, padding: "14px 16px", marginBottom: 14, display: "flex", gap: 10, alignItems: "center" }}>
        <span style={{ fontSize: 20 }}>⏸</span>
        <div>
          <div style={{ fontWeight: 700, fontSize: 14, color: G.red }}>Funds On Hold</div>
          <div style={{ fontSize: 12, color: G.red }}>{fmt(governance.heldFunds)} held pending KYC clearance</div>
        </div>
        <button className="btn-red btn-sm" style={{ marginLeft: "auto", flexShrink: 0 }} onClick={() => setTab("govern")}>Review</button>
      </div>
    )}

    {hotLeads.length > 0 && (
      <div style={{ background: G.amberLt, border: `1px solid ${G.amber}33`, borderRadius: 12, padding: "14px 16px", marginBottom: 14 }}>
        <div style={{ fontWeight: 700, fontSize: 13, color: G.amber, marginBottom: 8 }}>🔥 Hot Leads — Action Required</div>
        {hotLeads.map(e => (
          <div key={e.id} style={{ display: "flex", gap: 10, alignItems: "center", marginBottom: 6 }}>
            <div className="av" style={{ width: 28, height: 28, fontSize: 10, color: "white", background: e.color }}>{e.avatar}</div>
            <div style={{ flex: 1, fontSize: 13, fontWeight: 600 }}>{e.firstName} {e.lastName}</div>
            <span style={{ fontSize: 11, color: G.textLt }}>Follow up →</span>
          </div>
        ))}
      </div>
    )}

    {pending.length > 0 && (
      <div className="section-card" style={{ marginBottom: 14 }}>
        <div style={{ padding: "14px 16px 10px", fontWeight: 700, fontSize: 14 }}>📋 Pending Tasks ({pending.length})</div>
        {pending.slice(0, 3).map(t => {
          const exec = SEED_EXECUTIVES.find(e => e.id === t.contactId);
          return (
            <div key={t.id} style={{ padding: "10px 16px", borderTop: `1px solid ${G.border}`, display: "flex", gap: 10 }}>
              <span style={{ fontSize: 13 }}>○</span>
              <div style={{ flex: 1 }}>
                <div style={{ fontSize: 13, fontWeight: 600 }}>{t.notes || "Follow-up"}</div>
                {exec && <div style={{ fontSize: 11, color: G.green }}>{exec.firstName} {exec.lastName}</div>}
                <div style={{ fontSize: 11, color: G.textLt }}>Due: {fmtDate(t.date)}</div>
              </div>
            </div>
          );
        })}
      </div>
    )}

    <div className="section-card">
      <div style={{ padding: "14px 16px 8px", fontWeight: 700, fontSize: 14 }}>🕐 Recent Activity</div>
      {recentAudit.map(log => {
        const lc = { success: G.green, warn: G.amber, danger: G.red, info: G.blue }[log.level] || G.textLt;
        return (
          <div key={log.id} style={{ padding: "10px 16px", borderTop: `1px solid ${G.border}`, display: "flex", gap: 10, alignItems: "flex-start" }}>
            <div style={{ width: 8, height: 8, borderRadius: "50%", background: lc, marginTop: 5, flexShrink: 0 }} />
            <div style={{ flex: 1 }}>
              <div style={{ fontSize: 13, fontWeight: 600 }}>{log.action}</div>
              <div style={{ fontSize: 12, color: G.textMd }}>{log.detail}</div>
              <div style={{ fontSize: 11, color: G.textLt }}>{log.user} · {log.ts}</div>
            </div>
            <span className="tag" style={{ background: G.greenLt, color: G.green, flexShrink: 0 }}>{log.category}</span>
          </div>
        );
      })}
    </div>
  </div>
</div>
```

);
}

/* ══════════════════ CONTACTS ADMIN ══════════════════ */
function ContactsAdmin({ executives, setExecutives, toast, addAuditLog, setModal }) {
const [editId, setEditId]   = useState(null);
const [showForm, setShowForm] = useState(false);
const BLANK = { firstName: “”, lastName: “”, role: “”, company: “Microsoft”, email: “”, phone: “”, whatsapp: “”, linkedin: “”, avatar: “”, color: G.green, metAt: “”, followUpStatus: “Warm”, priority: “Medium”, category: “Strategy”, salary: 0, currency: “USD”, payFreq: “Monthly”, kycStatus: “Pending”, active: true, bio: “”, tags: [] };
const [form, setForm] = useState(BLANK);

const openAdd = () => { setForm({ …BLANK, id: uid() }); setEditId(null); setShowForm(true); };
const openEdit = (e) => { setForm({ …e }); setEditId(e.id); setShowForm(true); };
const save = () => {
if (!form.firstName || !form.role) return;
const entry = { …form, avatar: form.avatar || (form.firstName.slice(0, 1) + form.lastName.slice(0, 1)).toUpperCase() };
if (editId) { setExecutives(p => p.map(e => e.id === editId ? entry : e)); addAuditLog(“Contact updated”, `${entry.firstName} ${entry.lastName}`, “info”, “CRM”); }
else { setExecutives(p => […p, entry]); addAuditLog(“Contact added”, `${entry.firstName} ${entry.lastName} — ${entry.role}`, “info”, “CRM”); }
setShowForm(false); toast(editId ? “Contact updated ✓” : “Contact added ✓”);
};
const remove = (id, name) => { setExecutives(p => p.filter(e => e.id !== id)); addAuditLog(“Contact deleted”, name, “warn”, “CRM”); toast(“Contact removed”); };
const toggle = (id) => { setExecutives(p => p.map(e => e.id === id ? { …e, active: !e.active } : e)); };

const F = ({ label, k, type = “text”, ph = “”, opts = null }) => (
<div style={{ marginBottom: 12 }}>
<label className="inp-label">{label.toUpperCase()}</label>
{opts ? <select className=“inp” value={form[k] || “”} onChange={e => setForm(p => ({ …p, [k]: e.target.value }))}>{opts.map(o => <option key={o}>{o}</option>)}</select>
: type === “textarea” ? <textarea className=“inp” rows={3} placeholder={ph} value={form[k] || “”} onChange={e => setForm(p => ({ …p, [k]: e.target.value }))} />
: <input type={type} className=“inp” placeholder={ph} value={form[k] || “”} onChange={e => setForm(p => ({ …p, [k]: e.target.value }))} />}
</div>
);

return (
<div style={{ flex: 1, overflow: “auto” }}>
{showForm && (
<div className=“modal-bg fi” onClick={e => e.target === e.currentTarget && setShowForm(false)}>
<div className="modal-sheet pp">
<div className="modal-handle" />
<div style={{ padding: “0 20px 4px”, display: “flex”, justifyContent: “space-between”, alignItems: “center”, borderBottom: `1px solid ${G.border}`, paddingBottom: 14 }}>
<div style={{ fontWeight: 800, fontSize: 18 }}>{editId ? “Edit Contact” : “Add Contact”}</div>
<button onClick={() => setShowForm(false)} style={{ background: G.offWhite, border: “none”, borderRadius: “50%”, width: 30, height: 30, fontSize: 18, cursor: “pointer” }}>×</button>
</div>
<div style={{ padding: “16px 20px” }}>
<div style={{ display: “grid”, gridTemplateColumns: “1fr 1fr”, gap: 10 }}>
<F label="First Name" k="firstName" ph="First" />
<F label="Last Name"  k="lastName"  ph="Last" />
</div>
<F label="Role / Title" k="role" ph="Chairman & CEO" />
<F label="Company"      k="company" ph="Microsoft" />
<F label="Email"        k="email"   ph="email@company.com" type="email" />
<div style={{ display: “grid”, gridTemplateColumns: “1fr 1fr”, gap: 10 }}>
<F label="Phone"    k="phone"    ph="+1 425..." />
<F label="WhatsApp" k="whatsapp" ph="+1 425..." />
</div>
<F label="LinkedIn" k="linkedin" ph="linkedin.com/in/..." />
<F label="Met At"   k="metAt"    ph="Event / Conference" />
<div style={{ display: “grid”, gridTemplateColumns: “1fr 1fr”, gap: 10 }}>
<F label=“Status”   k=“followUpStatus” opts={[“Hot Lead”,“Warm”,“Active”,“Cold”]} />
<F label=“Priority” k=“priority”       opts={[“High”,“Medium”,“Low”]} />
<F label=“Category” k=“category”       opts={[“Strategy”,“Legal”,“Sales”,“People”,“Marketing”,“Finance”]} />
<F label=“KYC”      k=“kycStatus”      opts={[“Pending”,“Approved”,“Rejected”]} />
</div>
<div style={{ display: “grid”, gridTemplateColumns: “1fr 1fr”, gap: 10 }}>
<F label="Salary"   k="salary"   type="number" ph="0" />
<F label=“Currency” k=“currency” opts={[“USD”,“GBP”,“EUR”,“NGN”,“CAD”]} />
</div>
<F label="Accent Colour" k="color" type="color" />
<F label="Bio" k="bio" type="textarea" ph="Professional background..." />
<div style={{ display: “flex”, gap: 10, marginTop: 8 }}>
<button className="btn-primary" onClick={save}>{editId ? “Save Changes” : “Add Contact”}</button>
<button className=“btn-outline btn-sm” style={{ width: “auto”, padding: “13px 20px” }} onClick={() => setShowForm(false)}>Cancel</button>
</div>
</div>
</div>
</div>
)}

```
  <div className="top-header" style={{ paddingBottom: 18 }}>
    <div style={{ display: "flex", justifyContent: "space-between", alignItems: "center" }}>
      <div style={{ fontSize: 18, fontWeight: 800 }}>Team Management</div>
      <button onClick={openAdd} style={{ background: "white", color: G.green, border: "none", borderRadius: 8, padding: "8px 16px", fontWeight: 700, fontSize: 14, cursor: "pointer" }}>+ Add</button>
    </div>
    <div style={{ fontSize: 12, opacity: .75, marginTop: 4 }}>{executives.filter(e => e.active).length} active · {executives.length} total</div>
  </div>

  <div style={{ padding: "12px 16px 100px" }}>
    {executives.map((e, i) => (
      <div key={e.id} className="section-card su" style={{ animationDelay: `${i * .04}s`, opacity: e.active ? 1 : .55 }}>
        <div style={{ padding: "14px 16px" }}>
          <div style={{ display: "flex", gap: 12, alignItems: "flex-start" }}>
            <div className="av" style={{ width: 48, height: 48, fontSize: 15, color: "white", background: e.color }}>{e.avatar}</div>
            <div style={{ flex: 1, minWidth: 0 }}>
              <div style={{ display: "flex", gap: 8, alignItems: "center", marginBottom: 2 }}>
                <div style={{ fontWeight: 800, fontSize: 15 }}>{e.firstName} {e.lastName}</div>
                {!e.active && <span className="badge" style={{ background: G.redLt, color: G.red }}>Inactive</span>}
              </div>
              <div style={{ fontSize: 12, color: G.green, fontWeight: 600 }}>{e.role}</div>
              <div style={{ fontSize: 12, color: G.textLt }}>{e.company}</div>
              <div style={{ display: "flex", gap: 6, marginTop: 8, flexWrap: "wrap" }}>
                <span className="tag" style={{ background: e.followUpStatus === "Hot Lead" ? G.redLt : e.followUpStatus === "Warm" ? G.amberLt : G.greenLt, color: e.followUpStatus === "Hot Lead" ? G.red : e.followUpStatus === "Warm" ? G.amber : G.green }}>{e.followUpStatus}</span>
                <span className="tag" style={{ background: G.blueLt, color: G.blue }}>{e.kycStatus}</span>
                <span className="tag" style={{ background: G.offWhite, color: G.textMd }}>{e.priority}</span>
              </div>
            </div>
            <div style={{ display: "flex", flexDirection: "column", gap: 6, alignItems: "flex-end" }}>
              <div style={{ fontWeight: 700, fontSize: 14, color: G.text, fontFamily: "'JetBrains Mono'" }}>{fmt(e.salary, e.currency)}</div>
              <div style={{ fontSize: 10, color: G.textLt }}>{e.payFreq}</div>
            </div>
          </div>
          <div style={{ display: "flex", gap: 8, marginTop: 12 }}>
            <button className="btn-ghost btn-sm" style={{ flex: 1 }} onClick={() => openEdit(e)}>✏️ Edit</button>
            <button className="btn-ghost btn-sm" onClick={() => toggle(e.id)}>{e.active ? "Deactivate" : "Activate"}</button>
            <button className="btn-red btn-sm" onClick={() => remove(e.id, `${e.firstName} ${e.lastName}`)}>🗑</button>
          </div>
        </div>
      </div>
    ))}
  </div>
</div>
```

);
}

/* ══════════════════ FINANCE ADMIN ══════════════════ */
function FinanceAdmin({ finance, setFinance, totalBalance, totalPayroll, revenue, expenses, toast, addAuditLog, setModal }) {
const [subTab, setSubTab] = useState(“overview”);
const profit = revenue - expenses;

const SubNav = () => (
<div style={{ display: “flex”, overflowX: “auto”, gap: 0, borderBottom: `1px solid ${G.border}`, background: G.white, flexShrink: 0 }}>
{[“overview”, “accounts”, “payroll”, “transactions”, “budget”].map(t => (
<button key={t} onClick={() => setSubTab(t)} style={{ padding: “12px 14px”, background: “transparent”, border: “none”, borderBottom: `2.5px solid ${subTab === t ? G.green : "transparent"}`, color: subTab === t ? G.green : G.textLt, fontWeight: 700, fontSize: 12, cursor: “pointer”, whiteSpace: “nowrap”, fontFamily: “‘Plus Jakarta Sans’,sans-serif”, textTransform: “capitalize” }}>
{t}
</button>
))}
</div>
);

const approvePayment = (id) => {
setFinance(p => ({ …p, payrollSchedule: p.payrollSchedule.map(r => r.id === id ? { …r, status: “Approved” } : r) }));
addAuditLog(“Payment approved”, finance.payrollSchedule.find(r => r.id === id)?.name, “success”, “Finance”);
toast(“Payment approved ✓”);
};

const holdPayment = (id) => {
setFinance(p => ({ …p, payrollSchedule: p.payrollSchedule.map(r => r.id === id ? { …r, status: “On Hold” } : r) }));
addAuditLog(“Payment held”, finance.payrollSchedule.find(r => r.id === id)?.name, “warn”, “Finance”);
toast(“Payment placed on hold”);
};

return (
<div style={{ flex: 1, overflow: “auto”, display: “flex”, flexDirection: “column” }}>
<div className=“top-header” style={{ paddingBottom: 16 }}>
<div style={{ fontSize: 18, fontWeight: 800, marginBottom: 2 }}>Finance Control</div>
<div style={{ fontSize: 12, opacity: .75 }}>Accounts · Payroll · Budget · Transactions</div>
</div>
<SubNav />
<div style={{ flex: 1, overflow: “auto”, padding: “16px 16px 100px” }}>

```
    {subTab === "overview" && (
      <div className="su">
        <div style={{ display: "grid", gridTemplateColumns: "1fr 1fr", gap: 10, marginBottom: 16 }}>
          {[
            { icon: "🏦", label: "Total Balance",   value: fmt(totalBalance), color: G.green },
            { icon: "📈", label: "Revenue MTD",     value: fmt(revenue),      color: G.blue },
            { icon: "📉", label: "Expenses MTD",    value: fmt(expenses),     color: G.red },
            { icon: "💹", label: "Net Profit MTD",  value: fmt(profit),       color: profit >= 0 ? G.green : G.red },
          ].map((k, i) => (
            <div key={i} style={{ background: G.white, border: `1px solid ${G.border}`, borderRadius: 14, padding: 16 }}>
              <div style={{ fontSize: 20, marginBottom: 6 }}>{k.icon}</div>
              <div style={{ fontSize: 10, color: G.textLt, fontWeight: 700, letterSpacing: ".5px" }}>{k.label.toUpperCase()}</div>
              <div style={{ fontSize: 20, fontWeight: 800, color: k.color, marginTop: 2 }}>{k.value}</div>
            </div>
          ))}
        </div>

        <div className="section-card" style={{ marginBottom: 14 }}>
          <div style={{ padding: "14px 16px 8px", fontWeight: 700, fontSize: 14 }}>📊 Budget Utilisation</div>
          {finance.budgetLines.map(b => {
            const pct = Math.min(100, Math.round((b.spent / b.allocated) * 100));
            const col = pct > 80 ? G.red : pct > 60 ? G.amber : G.green;
            return (
              <div key={b.id} style={{ padding: "10px 16px", borderTop: `1px solid ${G.border}` }}>
                <div style={{ display: "flex", justifyContent: "space-between", marginBottom: 4 }}>
                  <span style={{ fontSize: 13, fontWeight: 600 }}>{b.name}</span>
                  <span style={{ fontSize: 12, fontWeight: 700, color: col, fontFamily: "'JetBrains Mono'" }}>{pct}%</span>
                </div>
                <div style={{ display: "flex", justifyContent: "space-between", marginBottom: 5 }}>
                  <span style={{ fontSize: 11, color: G.textLt }}>{fmt(b.spent)} of {fmt(b.allocated)}</span>
                </div>
                <div className="stat-bar"><div className="stat-fill" style={{ width: `${pct}%`, background: col }} /></div>
              </div>
            );
          })}
        </div>

        <div className="section-card">
          <div style={{ padding: "14px 16px 8px", fontWeight: 700, fontSize: 14 }}>💳 Monthly Payroll Summary</div>
          <div style={{ padding: "10px 16px", borderTop: `1px solid ${G.border}` }}>
            <div style={{ display: "flex", justifyContent: "space-between", marginBottom: 4 }}>
              <span style={{ fontSize: 13, color: G.textMd }}>Total scheduled</span>
              <span style={{ fontSize: 14, fontWeight: 800, fontFamily: "'JetBrains Mono'" }}>{fmt(totalPayroll)}</span>
            </div>
            <div style={{ display: "flex", justifyContent: "space-between", marginBottom: 4 }}>
              <span style={{ fontSize: 13, color: G.textMd }}>Scheduled</span>
              <span style={{ fontSize: 13, color: G.green, fontWeight: 700 }}>{finance.payrollSchedule.filter(p => p.status === "Scheduled" || p.status === "Approved").length} exec</span>
            </div>
            <div style={{ display: "flex", justifyContent: "space-between" }}>
              <span style={{ fontSize: 13, color: G.textMd }}>On Hold</span>
              <span style={{ fontSize: 13, color: G.red, fontWeight: 700 }}>{finance.payrollSchedule.filter(p => p.status === "On Hold").length} exec</span>
            </div>
          </div>
        </div>
      </div>
    )}

    {subTab === "accounts" && (
      <div className="su">
        {finance.accounts.map(acc => (
          <div key={acc.id} className="section-card" style={{ marginBottom: 12 }}>
            <div style={{ padding: 16 }}>
              <div style={{ display: "flex", justifyContent: "space-between", alignItems: "flex-start", marginBottom: 10 }}>
                <div>
                  <div style={{ fontWeight: 700, fontSize: 15 }}>{acc.name}</div>
                  <div style={{ fontSize: 12, color: G.textLt }}>{acc.bank} · {acc.number}</div>
                  <span className="tag" style={{ background: G.greenLt, color: G.green, marginTop: 6, display: "inline-block" }}>{acc.type}</span>
                </div>
                <div style={{ textAlign: "right" }}>
                  <div style={{ fontSize: 22, fontWeight: 800, color: G.green, fontFamily: "'JetBrains Mono'" }}>{fmt(acc.balance, acc.currency)}</div>
                  <div style={{ fontSize: 11, color: G.textLt }}>Synced: {fmtDate(acc.lastSync)}</div>
                </div>
              </div>
              <div style={{ display: "flex", gap: 8 }}>
                <button className="btn-ghost btn-sm" style={{ flex: 1 }} onClick={() => { setFinance(p => ({ ...p, accounts: p.accounts.map(a => a.id === acc.id ? { ...a, lastSync: now() } : a) })); toast("Account synced ✓"); }}>↻ Sync</button>
                <button className="btn-ghost btn-sm" onClick={() => { addAuditLog("Account statement downloaded", acc.name, "info", "Finance"); toast("Statement downloaded"); }}>↓ Statement</button>
              </div>
            </div>
          </div>
        ))}
        <button className="btn-outline" onClick={() => { toast("Connect bank account — integrate Plaid/Mono API"); }}>+ Connect Bank Account</button>
      </div>
    )}

    {subTab === "payroll" && (
      <div className="su">
        <div style={{ background: G.amberLt, border: `1px solid ${G.amber}33`, borderRadius: 12, padding: "12px 14px", marginBottom: 14, fontSize: 13, color: G.amber, fontWeight: 600 }}>
          ⚠️ All payroll over $10,000 requires your dual approval as CFO
        </div>
        {finance.payrollSchedule.map(r => {
          const exec = SEED_EXECUTIVES.find(e => e.id === r.execId);
          const isHeld = r.status === "On Hold";
          return (
            <div key={r.id} className="section-card" style={{ marginBottom: 10, borderLeft: `3px solid ${isHeld ? G.red : G.green}` }}>
              <div style={{ padding: 14 }}>
                <div style={{ display: "flex", gap: 12, alignItems: "center", marginBottom: 10 }}>
                  {exec && <div className="av" style={{ width: 40, height: 40, fontSize: 13, color: "white", background: exec.color }}>{exec.avatar}</div>}
                  <div style={{ flex: 1 }}>
                    <div style={{ fontWeight: 700, fontSize: 14 }}>{r.name}</div>
                    <div style={{ fontSize: 12, color: G.textLt }}>{exec?.role}</div>
                  </div>
                  <div style={{ textAlign: "right" }}>
                    <div style={{ fontWeight: 800, fontSize: 16, fontFamily: "'JetBrains Mono'", color: isHeld ? G.red : G.text }}>{fmt(r.amount, r.currency)}</div>
                    <span className="badge" style={{ background: isHeld ? G.redLt : G.greenLt, color: isHeld ? G.red : G.green }}>{r.status}</span>
                  </div>
                </div>
                <div style={{ display: "flex", justifyContent: "space-between", fontSize: 12, color: G.textLt, marginBottom: 10 }}>
                  <span>Next: {fmtDate(r.nextPayDate)}</span>
                  <span>Via {r.processor}</span>
                  <span style={{ color: r.kycOk ? G.green : G.red }}>KYC: {r.kycOk ? "✓" : "✗"}</span>
                </div>
                <div style={{ display: "flex", gap: 8 }}>
                  {isHeld
                    ? <button className="btn-primary btn-sm" onClick={() => approvePayment(r.id)}>✓ Approve Payment</button>
                    : <button className="btn-amber btn-sm" onClick={() => holdPayment(r.id)}>⏸ Place on Hold</button>
                  }
                  <button className="btn-ghost btn-sm" onClick={() => { addAuditLog("Payroll receipt sent", r.name, "info", "Finance"); toast("Receipt sent"); }}>Receipt</button>
                </div>
              </div>
            </div>
          );
        })}
      </div>
    )}

    {subTab === "transactions" && (
      <div className="su">
        {finance.transactions.map(t => (
          <div key={t.id} style={{ display: "flex", gap: 12, padding: "13px 0", borderBottom: `1px solid ${G.border}`, alignItems: "center" }}>
            <div style={{ width: 40, height: 40, borderRadius: 10, background: t.amount > 0 ? G.greenLt : G.redLt, display: "flex", alignItems: "center", justifyContent: "center", fontSize: 18, flexShrink: 0 }}>
              {t.amount > 0 ? "↓" : "↑"}
            </div>
            <div style={{ flex: 1, minWidth: 0 }}>
              <div style={{ fontSize: 13, fontWeight: 600, overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap" }}>{t.desc}</div>
              <div style={{ fontSize: 11, color: G.textLt }}>{fmtDate(t.date)} · {t.category}</div>
            </div>
            <div style={{ textAlign: "right", flexShrink: 0 }}>
              <div style={{ fontWeight: 800, fontSize: 14, color: t.amount > 0 ? G.green : G.red, fontFamily: "'JetBrains Mono'" }}>{t.amount > 0 ? "+" : ""}{fmt(Math.abs(t.amount))}</div>
              <span className="badge" style={{ background: t.status === "Cleared" ? G.greenLt : G.amberLt, color: t.status === "Cleared" ? G.green : G.amber }}>{t.status}</span>
            </div>
          </div>
        ))}
      </div>
    )}

    {subTab === "budget" && (
      <div className="su">
        <div style={{ background: G.white, border: `1px solid ${G.border}`, borderRadius: 12, padding: 16, marginBottom: 14 }}>
          <div style={{ fontWeight: 700, marginBottom: 4 }}>{finance.budget.fy} Annual Budget</div>
          <div style={{ fontSize: 28, fontWeight: 800, color: G.green, fontFamily: "'JetBrains Mono'" }}>{fmt(finance.budget.total)}</div>
          <div style={{ fontSize: 13, color: G.textMd, marginTop: 4 }}>Used: {fmt(finance.budget.used)} · Remaining: {fmt(finance.budget.total - finance.budget.used)}</div>
          <div className="stat-bar" style={{ marginTop: 10 }}><div className="stat-fill" style={{ width: `${Math.round((finance.budget.used / finance.budget.total) * 100)}%`, background: G.green }} /></div>
        </div>
        {finance.budgetLines.map(b => {
          const pct = Math.min(100, Math.round((b.spent / b.allocated) * 100));
          const col = pct > 80 ? G.red : pct > 60 ? G.amber : G.green;
          return (
            <div key={b.id} className="section-card" style={{ padding: 14, marginBottom: 10 }}>
              <div style={{ display: "flex", justifyContent: "space-between", marginBottom: 6 }}>
                <span style={{ fontWeight: 700, fontSize: 14 }}>{b.name}</span>
                <span className="tag" style={{ background: G.greenLt, color: G.green }}>{b.category}</span>
              </div>
              <div style={{ display: "flex", justifyContent: "space-between", fontSize: 12, color: G.textMd, marginBottom: 6 }}>
                <span>Spent: <strong style={{ color: G.text }}>{fmt(b.spent)}</strong></span>
                <span>Allocated: <strong>{fmt(b.allocated)}</strong></span>
                <span style={{ color: col, fontWeight: 700 }}>{pct}%</span>
              </div>
              <div className="stat-bar"><div className="stat-fill" style={{ width: `${pct}%`, background: col }} /></div>
              {pct > 80 && <div style={{ marginTop: 8, fontSize: 12, color: G.red, fontWeight: 600 }}>⚠️ Budget alert — CFO review required</div>}
            </div>
          );
        })}
      </div>
    )}
  </div>
</div>
```

);
}

/* ══════════════════ GOVERNANCE ADMIN ══════════════════ */
function GovernanceAdmin({ governance, setGovernance, violations, heldFunds, toast, addAuditLog }) {
const [subTab, setSubTab] = useState(“policies”);

const togglePolicy = (id) => {
setGovernance(p => ({ …p, policies: p.policies.map(pol => pol.id === id ? { …pol, active: !pol.active } : pol) }));
toast(“Policy updated ✓”);
};

const clearViolations = (id) => {
setGovernance(p => ({ …p, policies: p.policies.map(pol => pol.id === id ? { …pol, violations: 0 } : pol) }));
addAuditLog(“Violations cleared”, governance.policies.find(p => p.id === id)?.name, “info”, “Governance”);
toast(“Violations cleared”);
};

const approveKyc = (id) => {
setGovernance(p => ({ …p, complianceItems: p.complianceItems.map(c => c.id === id ? { …c, status: “Approved”, fundHold: false, holdAmount: 0, amlClear: true, kycDate: now() } : c) }));
addAuditLog(“KYC approved”, governance.complianceItems.find(c => c.id === id)?.entity, “success”, “Compliance”);
toast(“KYC approved — funds released ✓”);
};

const sevC = { Critical: G.red, High: G.amber, Medium: G.blue, Low: G.green };

const SubNav = () => (
<div style={{ display: “flex”, overflowX: “auto”, gap: 0, borderBottom: `1px solid ${G.border}`, background: G.white, flexShrink: 0 }}>
{[“policies”, “compliance”, “roles”, “audit”].map(t => (
<button key={t} onClick={() => setSubTab(t)} style={{ padding: “12px 14px”, background: “transparent”, border: “none”, borderBottom: `2.5px solid ${subTab === t ? G.green : "transparent"}`, color: subTab === t ? G.green : G.textLt, fontWeight: 700, fontSize: 12, cursor: “pointer”, whiteSpace: “nowrap”, fontFamily: “‘Plus Jakarta Sans’,sans-serif”, textTransform: “capitalize” }}>
{t}
</button>
))}
</div>
);

return (
<div style={{ flex: 1, overflow: “auto”, display: “flex”, flexDirection: “column” }}>
<div className=“top-header” style={{ paddingBottom: 16 }}>
<div style={{ fontSize: 18, fontWeight: 800, marginBottom: 2 }}>Governance & Compliance</div>
<div style={{ fontSize: 12, opacity: .75 }}>Policies · KYC · Roles · Audit Log</div>
</div>
<SubNav />
<div style={{ flex: 1, overflow: “auto”, padding: “16px 16px 100px” }}>

```
    {subTab === "policies" && (
      <div className="su">
        {violations > 0 && (
          <div style={{ background: G.redLt, border: `1px solid ${G.red}33`, borderRadius: 12, padding: "12px 14px", marginBottom: 14, fontSize: 13, color: G.red, fontWeight: 600 }}>
            ⚠️ {violations} policy violation{violations > 1 ? "s" : ""} require your attention
          </div>
        )}
        {governance.policies.map(pol => (
          <div key={pol.id} className="section-card" style={{ marginBottom: 10, borderLeft: `3px solid ${pol.active ? (sevC[pol.severity] || G.green) : G.border}` }}>
            <div style={{ padding: 14 }}>
              <div style={{ display: "flex", justifyContent: "space-between", alignItems: "flex-start", marginBottom: 8 }}>
                <div style={{ flex: 1, paddingRight: 10 }}>
                  <div style={{ fontWeight: 700, fontSize: 14, marginBottom: 4 }}>{pol.name}</div>
                  <div style={{ fontSize: 12, color: G.textMd, lineHeight: 1.6 }}>{pol.description}</div>
                </div>
                <div className={`toggle ${pol.active ? "" : ""}`} style={{ background: pol.active ? G.green : G.border }} onClick={() => togglePolicy(pol.id)}>
                  <div className="toggle-dot" style={{ left: pol.active ? 23 : 3 }} />
                </div>
              </div>
              <div style={{ display: "flex", gap: 6, flexWrap: "wrap", marginBottom: 10 }}>
                <span className="tag" style={{ background: (sevC[pol.severity] || G.green) + "20", color: sevC[pol.severity] || G.green }}>{pol.severity}</span>
                <span className="tag" style={{ background: G.greenLt, color: G.green }}>{pol.category}</span>
                <span className="tag" style={{ background: G.offWhite, color: G.textMd }}>Owner: {pol.owner}</span>
              </div>
              <div style={{ display: "flex", justifyContent: "space-between", fontSize: 12, color: G.textLt, marginBottom: 10 }}>
                <span>Enforced: <strong style={{ color: G.green }}>{pol.enforced}×</strong></span>
                <span>Violations: <strong style={{ color: pol.violations > 0 ? G.red : G.green }}>{pol.violations}</strong></span>
                <span>Reviewed: {fmtDate(pol.lastReview)}</span>
              </div>
              {pol.violations > 0 && (
                <button className="btn-red btn-sm" on…
@E-privo E-privo changed the title Admin hub Exec-adm Mar 19, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant