/* ============ Sample dataset (Admin POV) ============ */

/* Users — extended with login/audit fields for the Users & Roles screen.
   `username` is the login handle, `password` is masked in UI (POC only — never store plain text in production). */
const USERS = [
  { id:"U-AD1", name:"Praewa Saetang",   username:"praewa",    password:"••••••••", role:"Admin",      email:"praewa@tumweb.co.th",    active:true, createdBy:"U-AD1", createdAt:"2024-01-15T09:00:00", lastEditBy:"U-AD1", lastEditAt:"2024-01-15T09:00:00" },
  { id:"U-AD2", name:"Korn Vichitchai",  username:"korn.v",    password:"••••••••", role:"Admin",      email:"korn@tumweb.co.th",      active:true, createdBy:"U-AD1", createdAt:"2024-02-08T14:22:11", lastEditBy:"U-AD1", lastEditAt:"2024-02-08T14:22:11" },
  { id:"U-SV1", name:"Sarah Mitchell",   username:"sarah.m",   password:"••••••••", role:"Supervisor", email:"sarah.m@tumweb.co.th",   active:true, createdBy:"U-AD1", createdAt:"2024-03-12T10:14:00", lastEditBy:"U-AD2", lastEditAt:"2025-08-04T11:30:00" },
  { id:"U-SV2", name:"Tanaporn Suthep",  username:"tanaporn",  password:"••••••••", role:"Supervisor", email:"tanaporn.s@tumweb.co.th",active:true, createdBy:"U-AD1", createdAt:"2024-05-20T15:00:00", lastEditBy:"U-AD1", lastEditAt:"2024-05-20T15:00:00" },
  { id:"U-SV3", name:"James Khatri",     username:"james.k",   password:"••••••••", role:"Supervisor", email:"james.k@tumweb.co.th",   active:true, createdBy:"U-AD2", createdAt:"2024-09-01T09:00:00", lastEditBy:"U-AD1", lastEditAt:"2025-11-22T10:08:00" },
  { id:"U-ST1", name:"Ana Pereira",      username:"ana.p",     password:"••••••••", role:"Staff",      email:"ana.p@tumweb.co.th",     active:true, createdBy:"U-SV1", createdAt:"2024-11-04T11:00:00", lastEditBy:"U-SV1", lastEditAt:"2024-11-04T11:00:00" },
  { id:"U-ST2", name:"Marcus Wong",      username:"marcus.w",  password:"••••••••", role:"Staff",      email:"marcus.w@tumweb.co.th",  active:true, createdBy:"U-SV1", createdAt:"2025-01-08T09:30:00", lastEditBy:"U-AD1", lastEditAt:"2026-02-14T13:45:00" },
  { id:"U-ST3", name:"Nattanan Chai",    username:"nattanan",  password:"••••••••", role:"Staff",      email:"nattanan.c@tumweb.co.th",active:true, createdBy:"U-SV2", createdAt:"2025-03-22T14:11:00", lastEditBy:"U-SV2", lastEditAt:"2025-03-22T14:11:00" },
  { id:"U-ST4", name:"Veerayut Pansri",  username:"veerayut",  password:"••••••••", role:"Staff",      email:"veerayut.p@tumweb.co.th",active:true, createdBy:"U-SV3", createdAt:"2025-06-09T10:00:00", lastEditBy:"U-AD2", lastEditAt:"2026-04-30T16:20:00" },
  { id:"U-ST5", name:"Lin Wei",          username:"lin.w",     password:"••••••••", role:"Staff",      email:"lin.w@tumweb.co.th",     active:true, createdBy:"U-SV1", createdAt:"2025-09-15T08:45:00", lastEditBy:"U-SV1", lastEditAt:"2025-09-15T08:45:00" },
  /* Inactive example — left the firm; account kept per MTG4 §2.2 (never delete, audit trail preserved) */
  { id:"U-ST6", name:"Pimchanok Srisuwan", username:"pimchanok", password:"••••••••", role:"Staff",      email:"pimchanok.s@tumweb.co.th", active:false, createdBy:"U-SV2", createdAt:"2024-07-01T09:00:00", lastEditBy:"U-AD1", lastEditAt:"2026-03-31T17:00:00" },
  { id:"U-GS1", name:"Apinya Tantip (Regulator)", username:"sec.reviewer", password:"••••••••", role:"Guest", email:"a.tantip@sec.or.th",  active:true, createdBy:"U-AD1", createdAt:"2026-04-20T10:00:00", lastEditBy:"U-AD1", lastEditAt:"2026-04-20T10:00:00" },
  { id:"U-GS2", name:"KK Auditors (External)",     username:"kk.external",  password:"••••••••", role:"Guest", email:"audit@kkco.co.th",     active:true, createdBy:"U-AD2", createdAt:"2026-05-08T14:00:00", lastEditBy:"U-AD2", lastEditAt:"2026-05-08T14:00:00" },
];

/* Mutable so the Login screen can switch the active persona (Admin / Supervisor / Staff).
   Components read the bare `CURRENT_ADMIN` global, so reassigning it before re-render
   swaps the logged-in user app-wide. Defaults to Praewa (Admin). */
let CURRENT_ADMIN = USERS[0]; // Praewa
const setCurrentUser = (u) => { CURRENT_ADMIN = u; };

/* Service Types — per Proud Workpapers PDF slide 3 + MTG4 §2.1
   Each type has a 3-letter Condense code, description, sub-detail options.
   Admin can add / edit / delete / set description (MTG4). */
const SERVICE_TYPE_CATALOG = [
  { code:"AUD", name:"Audit",                  details:["Year", "6 months", "For the period…", "Special Purpose Audits"], desc:"Full statutory financial-statement audit — issues an audit opinion under TSA/ISA standards." },
  { code:"LMR", name:"Limited Review",         details:["Quarterly", "Half Year"], desc:"Interim review providing limited assurance — reduced sampling vs. full audit." },
  { code:"AUP", name:"Agreed-Upon Procedures", details:["Due Diligence", "Stock Observation", "BOI"], desc:"Procedures agreed with the client; no opinion expressed — only findings reported." },
  { code:"OTH", name:"Others",                 details:[], desc:"Other engagement types not covered above — Admin specifies scope per project." },
];
/* Backward-compat flat array for callers that just want the name list */
const SERVICE_TYPES = SERVICE_TYPE_CATALOG.map(s => s.name);
/* Lookup helpers */
const serviceTypeByName = (n) => SERVICE_TYPE_CATALOG.find(s => s.name === n) || null;
const serviceTypeByCode = (c) => SERVICE_TYPE_CATALOG.find(s => s.code === c) || null;

/* Category definitions — official wording per Proud Workpapers PDF slide 2.
   Drives sampling depth, EQR triggers, partner review requirements, and
   regulatory reporting under ก.ล.ต. rules. */
const CATEGORY_INFO = {
  A: {
    label: "Category A",
    short: "Public Interest Entity (PIE)",
    desc:  "Public Interest Entity (PIE) — listed entities; OR assurance assignments where the firm is the principal auditor and the client has components representing more than 50% of the consolidated group's assets, revenues, and net income that are audited by other firms. Applies to both listed and non-listed entities.",
  },
  B: {
    label: "Category B",
    short: "Progressing to Category A within 18 months",
    desc:  "Companies with the stated intention of progressing into Category A within eighteen months, and the financial position / prospects to make the intention credible.",
  },
  C: {
    label: "Category C",
    short: "Borrowings > ฿200M or Audit Fees > ฿1,000k",
    desc:  "Companies with borrowings or institutional investments exceeding ฿200 million, OR Audit Fees exceeding ฿1,000k — if not already categorised as A or B above.",
  },
  D: {
    label: "Category D",
    short: "All other companies",
    desc:  "Companies that are not in Category A–C.",
  },
};

/* Risk Level — required field per ก.ล.ต. (SEC) requirement.
   Drives sampling intensity, EQR triggers, and partner review depth. */
const RISK_LEVELS = [
  { v: "High",     label: "High",     tone: "danger", desc: "Listed entity, regulator scrutiny, complex group, or known fraud risk indicators." },
  { v: "Moderate", label: "Moderate", tone: "warn",   desc: "Group consolidation, multi-segment operations, or first-year engagement." },
  { v: "Low",      label: "Low",      tone: "ok",     desc: "Standalone entity, stable business, prior-year clean opinion, low public interest." },
];
const RISK_INFO = Object.fromEntries(RISK_LEVELS.map(r => [r.v, r]));

/* SOP Template descriptions — for Tooltip when selecting template */
const TEMPLATE_INFO = {
  "T-FS-STD":    "Standard statutory FS audit — 5 folders / 74 WPIDs. Use for most FS audits across industries.",
  "T-INT-QTR":   "Quarterly interim review — 3 folders / 21 WPIDs. Focus on cut-off testing and aging.",
  "T-TAX-PND50": "Thai PND50 corporate tax filing — 4 folders / 32 WPIDs. Annual filing for fiscal year-end.",
  "T-IC-SOX":    "SOX-lite walkthrough — 6 folders / 58 WPIDs. Covers revenue, treasury, payroll controls.",
};

/* Entities — 3 fields only: Name, Tax ID, Description */
const ENTITIES_SEED = [
  { id:"E-001", code:"NWI", color:"a0", name:"Northwind Industrial Co., Ltd.",  taxId:"0105556012345", desc:"Manufacturing client since 2019. Renamed from Northwind Mfg in 2021.", archived:false, creators:["U-SV1","U-SV2"] },
  { id:"E-002", code:"HLC", color:"a1", name:"Harbor Logistics Co., Ltd.",      taxId:"0105561023987", desc:"Logistics & cold-chain. Group consolidation with HLC Holdings.",           archived:false, creators:["U-SV1"] },
  { id:"E-003", code:"KFG", color:"a4", name:"Kalama Foods Group",              taxId:"0105559871234", desc:"F&B holding. Includes 4 subsidiaries (audited separately).",              archived:false, creators:["U-SV3"] },
  { id:"E-004", code:"OCP", color:"a3", name:"Orion Capital Holdings PLC",      taxId:"0107554003221", desc:"Listed financial holding. Regulated by SEC.",                              archived:false, creators:["U-SV1","U-SV3"] },
  { id:"E-005", code:"SLR", color:"a5", name:"Solaris Energy PLC",              taxId:"0107558112004", desc:"Renewables. New client onboarded Q1/2026.",                                archived:false, creators:[] },
  { id:"E-006", code:"MHT", color:"a6", name:"Meridian Hospitality Trust",      taxId:"0105549004567", desc:"Hospitality REIT. Wound down 2024 — archive only.",                       archived:true,  creators:[] },
  { id:"E-007", code:"TPB", color:"a2", name:"Thaipan Beverages Public Co.",    taxId:"0107562778899", desc:"Beverage manufacturing. SET listed.",                                       archived:false, creators:["U-SV2"] },
];

/* Projects — status: draft / active / archived  (per MTG3: pending merged into draft).
   A draft with `submittedAt` set means the Project Creator has handed it over to Admin
   for activation (shows up in Approval Center). Drafts without submittedAt are still
   being worked on by the Creator. */
const PROJECTS_SEED = [
  // Awaiting Admin activation — Approval Center (submittedAt set, status=draft)
  { id:"P-2026-014", entityId:"E-002", name:"Annual Audit FY2026",
    serviceType:"Audit", serviceDetail:"Year", periodStart:"2026-01-01", periodEnd:"2026-12-31", category:"A", riskLevel:"High",
    status:"draft",  description:"FY2026 statutory audit. Group consolidation with HLC Holdings; includes cold-chain subsidiary.",
    members:["U-SV1","U-ST2","U-ST3"], templateId:"T-FS-STD", folders:5, files:74,
    createdBy:"U-SV1", createdAt:"2026-05-21T16:32:11", submittedAt:"2026-05-22T09:14:42", lastEditBy:"U-SV1", lastEditAt:"2026-05-22T09:14:42" },

  { id:"P-2026-015", entityId:"E-001", name:"Q4 Interim Review FY2026",
    serviceType:"Limited Review", serviceDetail:"Quarterly", periodStart:"2026-04-01", periodEnd:"2026-06-30", category:"B", riskLevel:"Moderate",
    status:"draft",  description:"Pre-year-end interim. Focus on revenue cut-off & receivables aging.",
    members:["U-SV3","U-ST1","U-ST5"], templateId:"T-INT-QTR", folders:3, files:21,
    createdBy:"U-SV3", createdAt:"2026-05-20T11:08:00", submittedAt:"2026-05-21T16:32:11", lastEditBy:"U-AD1", lastEditAt:"2026-05-21T16:30:02" },

  { id:"P-2026-016", entityId:"E-003", name:"Tax Compliance PND50",
    serviceType:"Others", serviceDetail:"Tax Filing", periodStart:"2025-01-01", periodEnd:"2025-12-31", category:"C", riskLevel:"Low",
    status:"draft",  description:"Annual tax filing PND50 for fiscal year ended 31 Dec 2025.",
    members:["U-SV1","U-ST1"], templateId:"T-TAX-PND50", folders:4, files:32,
    createdBy:"U-SV1", createdAt:"2026-05-19T10:02:34", submittedAt:"2026-05-20T15:00:00", lastEditBy:"U-SV1", lastEditAt:"2026-05-20T14:58:50" },

  { id:"P-2026-017", entityId:"E-004", name:"Internal Control Walkthrough",
    serviceType:"Agreed-Upon Procedures", serviceDetail:"Due Diligence", periodStart:"2026-01-01", periodEnd:"2026-06-30", category:"D", riskLevel:"Moderate",
    status:"draft",  description:"SOX-lite control walkthrough across revenue, treasury, payroll.",
    members:["U-SV3","U-ST2","U-ST4","U-ST5"], templateId:"T-IC-SOX", folders:6, files:58,
    createdBy:"U-SV3", createdAt:"2026-05-18T09:11:10", submittedAt:"2026-05-19T17:42:08", lastEditBy:"U-SV3", lastEditAt:"2026-05-19T17:42:08" },

  // Working drafts — Creator still editing (no submittedAt yet)
  { id:"P-2026-018", entityId:"E-005", name:"Annual Audit FY2026",
    serviceType:"Audit", serviceDetail:"Year", periodStart:"2026-01-01", periodEnd:"2026-12-31", category:"A", riskLevel:"High",
    status:"draft",    description:"First-year audit. Use FS Standard template + add ESG schedule (TBD).",
    members:["U-SV2","U-ST3"], templateId:"T-FS-STD", folders:5, files:74,
    createdBy:"U-SV2", createdAt:"2026-05-22T08:40:00", submittedAt:null, lastEditBy:"U-SV2", lastEditAt:"2026-05-22T09:55:18" },

  { id:"P-2026-019", entityId:"E-007", name:"Annual Audit FY2026",
    serviceType:"Audit", serviceDetail:"Year", periodStart:"2026-01-01", periodEnd:"2026-12-31", category:"A", riskLevel:"Moderate",
    status:"draft",    description:"Group audit. Coordination required with KK Auditors for component.",
    members:["U-SV2","U-ST1","U-ST4"], templateId:null, folders:0, files:0,
    createdBy:"U-SV2", createdAt:"2026-05-22T09:30:11", submittedAt:null, lastEditBy:"U-SV2", lastEditAt:"2026-05-22T09:31:00" },

  { id:"P-2026-013", entityId:"E-001", name:"SOX Control Walkthrough",
    serviceType:"Agreed-Upon Procedures", serviceDetail:"Stock Observation", periodStart:"2026-03-01", periodEnd:"2026-03-31", category:"D", riskLevel:"Low",
    status:"draft", description:"Internal-control walkthrough for revenue & treasury.",
    members:["U-SV1","U-ST2"], templateId:"T-IC-SOX", folders:6, files:58,
    createdBy:"U-SV1", createdAt:"2026-05-12T10:00:00", submittedAt:null,
    lastEditBy:"U-SV1", lastEditAt:"2026-05-16T11:00:00" },

  // Active (approved) — live projects
  /* Default rich demo workspace — reviews still running, so the
     "Set Report Date" button stays DISABLED here (guard §4.12). */
  { id:"P-2025-008", entityId:"E-001", name:"Annual Audit FY2025",
    serviceType:"Audit", serviceDetail:"Year", periodStart:"2026-01-01", periodEnd:"2026-12-31", category:"A", riskLevel:"High",
    status:"active",   description:"FY2025 statutory audit.",
    members:["U-SV1","U-ST1","U-ST2","U-ST3"], templateId:"T-FS-STD", folders:5, files:74,
    /* Reviewer roles assigned (user request 2026-06-12) — WPIDs without an
       explicit per-WPID chain inherit these names instead of "Unassigned" */
    reviewerSlots:[
      { role:"In-Charge", required:true,  userId:"U-ST1" },
      { role:"Manager",   required:true,  userId:"U-SV1" },
      { role:"Director",  required:false, userId:null },
      { role:"Partner",   required:true,  userId:"U-AD2" },
      { role:"EQR",       required:false, userId:null },
    ],
    createdBy:"U-SV1", createdAt:"2025-10-04T09:14:00", submittedAt:"2025-10-08T11:00:00",
    approvedAt:"2025-10-08T14:30:00", approvedBy:"U-AD1",
    lastEditBy:"U-SV1", lastEditAt:"2026-05-21T15:30:00" },

  /* Soft Lock — CRITICAL countdown (T-3 days). All sign-offs were completed
     before T0 was set, so its per-project seeds below are fully signed. */
  { id:"P-2025-009", entityId:"E-003", name:"Annual Audit FY2025",
    serviceType:"Audit", serviceDetail:"Year", periodStart:"2026-01-01", periodEnd:"2026-12-31", category:"A", riskLevel:"Moderate",
    status:"active",   description:"FY2025 statutory audit for Kalama Foods.",
    auditorReportDate:"2026-03-26",   /* → T-3 days (CRITICAL: ≤7d) */
    members:["U-SV3","U-ST1","U-ST2"], templateId:"T-FS-STD", folders:5, files:74,
    createdBy:"U-SV3", createdAt:"2025-11-12T10:00:00", submittedAt:"2025-11-13T09:30:00",
    approvedAt:"2025-11-13T11:00:00", approvedBy:"U-AD2",
    lastEditBy:"U-SV3", lastEditAt:"2026-05-19T14:08:00" },

  /* γ-flow showcase — every WPID has its Required slots signed, so the
     "Set Report Date" button is ENABLED here (no T0 yet). Click it to
     walk the full Soft Lock → Archive demo. */
  { id:"P-2025-010", entityId:"E-004", name:"Annual Audit FY2025",
    serviceType:"Audit", serviceDetail:"Year", periodStart:"2026-01-01", periodEnd:"2026-12-31", category:"A", riskLevel:"High",
    status:"active",   description:"FY2025 audit for Orion Capital Holdings.",
    members:["U-SV1","U-SV3","U-ST2","U-ST5"], templateId:"T-FS-STD", folders:5, files:74,
    createdBy:"U-SV1", createdAt:"2025-09-01T10:00:00", submittedAt:"2025-09-04T09:00:00",
    approvedAt:"2025-09-04T16:00:00", approvedBy:"U-AD1",
    lastEditBy:"U-SV1", lastEditAt:"2026-05-22T08:00:00" },

  /* Soft Lock — APPROACHING countdown (T-23 days, warn tone ≤30d). */
  { id:"P-2025-011", entityId:"E-007", name:"Annual Audit FY2025",
    serviceType:"Audit", serviceDetail:"Year", periodStart:"2025-01-01", periodEnd:"2025-12-31", category:"A", riskLevel:"Moderate",
    status:"active",   description:"FY2025 statutory audit for Thaipan Beverages.",
    auditorReportDate:"2026-04-15",   /* → T-23 days (WARN: ≤30d) */
    members:["U-SV2","U-ST3","U-ST4"], templateId:"T-FS-STD", folders:5, files:74,
    createdBy:"U-SV2", createdAt:"2025-10-01T10:00:00", submittedAt:"2025-10-03T09:00:00",
    approvedAt:"2025-10-03T11:00:00", approvedBy:"U-AD1",
    lastEditBy:"U-SV2", lastEditAt:"2026-04-30T09:00:00" },

  { id:"P-2024-002", entityId:"E-006", name:"FY2024 (final)",
    serviceType:"Audit", serviceDetail:"Year", periodStart:"2026-01-01", periodEnd:"2026-12-31", category:"A", riskLevel:"Moderate",
    status:"archived", description:"Final year before wind-down.",
    members:["U-SV1","U-ST2"], templateId:"T-FS-STD", folders:5, files:74,
    createdBy:"U-SV1", createdAt:"2024-09-01T10:00:00", submittedAt:"2024-09-05T09:00:00",
    approvedAt:"2024-09-05T11:00:00", approvedBy:"U-AD1",
    auditorReportDate:"2025-02-01",
    archivedAt:"2025-04-01T00:00:00", archivedBy:"U-AD1", archiveReason:"manual",
    archiveHash:"sha256:9f2a…b4c1",
    lastEditBy:"U-SV1", lastEditAt:"2025-04-01T00:00:00" },

  { id:"P-2023-005", entityId:"E-001", name:"Annual Audit FY2023",
    serviceType:"Audit", serviceDetail:"Year", periodStart:"2026-01-01", periodEnd:"2026-12-31", category:"A", riskLevel:"High",
    status:"archived", description:"FY2023 statutory audit — sealed at T-0.",
    members:["U-SV1","U-ST1","U-ST2"], templateId:"T-FS-STD", folders:5, files:74,
    createdBy:"U-SV1", createdAt:"2023-09-01T10:00:00", submittedAt:"2023-09-04T09:00:00",
    approvedAt:"2023-09-04T11:00:00", approvedBy:"U-AD1",
    auditorReportDate:"2024-03-15",
    archivedAt:"2024-05-14T00:00:00", archivedBy:"U-AD2", archiveReason:"auto-lock",
    archiveHash:"sha256:7e1c…3a82",
    lastEditBy:"U-SV1", lastEditAt:"2024-05-14T00:00:00" },

  { id:"P-2023-007", entityId:"E-003", name:"Tax Compliance FY2023",
    serviceType:"Others", serviceDetail:"Tax Filing", periodStart:"2025-01-01", periodEnd:"2025-12-31", category:"C", riskLevel:"Low",
    status:"archived", description:"Closed by Admin after final regulator filing.",
    members:["U-SV3","U-ST1"], templateId:"T-TAX-PND50", folders:4, files:32,
    createdBy:"U-SV3", createdAt:"2023-10-20T09:00:00", submittedAt:"2023-10-22T10:00:00",
    approvedAt:"2023-10-22T14:00:00", approvedBy:"U-AD1",
    auditorReportDate:"2024-02-28",
    archivedAt:"2024-04-29T00:00:00", archivedBy:"U-AD1", archiveReason:"auto-lock",
    archiveHash:"sha256:3b5d…f1a7",
    lastEditBy:"U-SV3", lastEditAt:"2024-04-29T00:00:00" },

  { id:"P-2022-003", entityId:"E-004", name:"Annual Audit FY2022",
    serviceType:"Audit", serviceDetail:"Year", periodStart:"2026-01-01", periodEnd:"2026-12-31", category:"A", riskLevel:"High",
    status:"archived", description:"Pre-IPO audit — sealed per regulatory filing.",
    members:["U-SV1","U-ST2","U-ST3"], templateId:"T-FS-STD", folders:5, files:74,
    createdBy:"U-SV1", createdAt:"2022-08-01T10:00:00", submittedAt:"2022-08-05T09:00:00",
    approvedAt:"2022-08-05T11:00:00", approvedBy:"U-AD1",
    auditorReportDate:"2023-03-10",
    archivedAt:"2023-05-09T00:00:00", archivedBy:"U-AD1", archiveReason:"auto-lock",
    archiveHash:"sha256:c8a4…d6b9",
    lastEditBy:"U-SV1", lastEditAt:"2023-05-09T00:00:00" },
];

/* ============================================================
   ARCHIVE-RELATED DATA
   ============================================================ */

/* Post-archive transactions — per Proud Workpapers PDF slide 6.
   After a project is archived, additional transactions (e.g. subsequent events,
   regulator-mandated corrections) can be recorded as APPEND-ONLY entries that
   don't modify the original sealed workpapers. */
const POST_ARCHIVE_TRANSACTIONS = [
  { id:"PAT-001", projectId:"P-2024-002", type:"subsequent-event",
    title:"Bankruptcy filing notice — Meridian Hospitality",
    detail:"Insolvency filed 12 May 2025. Disclosure note added per ISA 560 (subsequent events after report date).",
    submittedBy:"U-AD1", submittedAt:"2025-06-10T11:00:00",
    status:"approved", approvedBy:"U-AD2", approvedAt:"2025-06-11T14:30:00",
    hash:"sha256:e4f7…aa21" },
  { id:"PAT-002", projectId:"P-2023-005", type:"regulator-request",
    title:"SEC Thailand — supplementary disclosure on revenue recognition",
    detail:"Per regulator request dated 2 May 2026 — providing additional support for revenue cut-off testing.",
    submittedBy:"U-SV1", submittedAt:"2026-05-10T09:15:00",
    status:"pending" },
  { id:"PAT-003", projectId:"P-2023-007", type:"document-correction",
    title:"Tax assessment letter received from Revenue Dept.",
    detail:"PND50 assessment letter received 18 May 2026. Filing as post-archive evidence — no recomputation needed.",
    submittedBy:"U-SV3", submittedAt:"2026-05-18T16:20:00",
    status:"pending" },
];

const POST_ARCHIVE_TYPES = [
  { v:"subsequent-event",   label:"Subsequent Event",        desc:"Event occurring after the auditor's report date (ISA 560)." },
  { v:"regulator-request",  label:"Regulator Request",       desc:"Documentation in response to a regulator inquiry (SEC, SET, Revenue Dept., etc.)." },
  { v:"document-correction",label:"Document Correction",     desc:"Correction or supplementary evidence — does NOT change original audit opinion." },
  { v:"client-letter",      label:"Client Letter / Notice",  desc:"Communication from client received after archive." },
  { v:"other",              label:"Other",                   desc:"Other post-archive recording with reason." },
];

/* Archive extension requests — pre-T-0 extensions per ISA 230 (60-day rule) */
const ARCHIVE_EXTENSIONS = [
  { id:"AE-001", projectId:"P-2025-009", days:14, reason:"Awaiting signed board minutes from year-end meeting — client confirmed delivery by 8 Jun.",
    requestedBy:"U-SV3", requestedAt:"2026-05-21T09:30:00", status:"pending" },
];

/* Lock-rule constants — per Proud Workpapers / ISA 230 */
const ARCHIVE_RULES = {
  LOCK_DAYS: 60,           /* T-Lock period from auditor report date */
  CRITICAL_DAYS: 7,        /* ≤ this many days → red badge */
  WARN_DAYS: 30,           /* ≤ this many days → yellow badge */
  MAX_EXTENSION_DAYS: 30,  /* extension request cap per cycle */
};

/* Per user clarification (rev. MTG3) — ALL drafts go to Approval Center;
   there is no "submitted vs not-submitted" sub-state. The helper now simply
   means "this project is a draft and shows in the Approval Center queue". */
const isAwaitingActivation = (p) => p.status === "draft";

/* Web-based edit (MTG3 §2.1) — file types editable directly in browser.
   Other types (PDF/image) get preview/download only. */
const WEB_EDITABLE_TYPES = new Set(["docx","xlsx","xlsm","xls","csv","txt"]);
const isWebEditable = (type) => WEB_EDITABLE_TYPES.has((type||"").toLowerCase());

/* Lock helper — returns { locked, byName, byUserId, when, isMe } */
const lockInfo = (wp, me) => {
  if (!wp || !wp.lockedBy) return { locked: false };
  return {
    locked: true,
    byUserId: wp.lockedBy,
    byName: wp.lockedByName || (USERS.find(u => u.id === wp.lockedBy)?.name) || wp.lockedBy,
    when: wp.lockedAt,
    isMe: me && me === wp.lockedBy,
  };
};

/* Access requests */
const ACCESS_REQUESTS_SEED = [
  { id:"AR-208", userId:"U-ST3", projectId:"P-2025-008", reason:"Need to upload Q4 supporting docs",                requestedAt:"2026-05-22T09:42:11", status:"pending" },
  { id:"AR-207", userId:"U-ST4", projectId:"P-2025-010", reason:"Reassigned to Orion engagement — need full access",  requestedAt:"2026-05-21T17:21:55", status:"pending" },
  { id:"AR-206", userId:"U-ST5", projectId:"P-2025-009", reason:"—",                                                  requestedAt:"2026-05-20T14:08:00", status:"pending" },
  { id:"AR-205", userId:"U-ST1", projectId:"P-2025-010", reason:"Need access to inventory workpapers",                requestedAt:"2026-05-19T11:20:00", status:"granted",  decidedBy:"U-AD1", decidedAt:"2026-05-19T13:05:18", note:"Approved — assigned to inventory section" },
  { id:"AR-204", userId:"U-ST2", projectId:"P-2025-008", reason:"Need to view priors",                                requestedAt:"2026-05-18T08:42:11", status:"declined", decidedBy:"U-AD2", decidedAt:"2026-05-18T10:14:33", note:"Already a member of P-2026-014; declined to limit cross-engagement scope" },
  { id:"AR-203", userId:"U-ST5", projectId:"P-2025-008", reason:"Helping with sampling",                              requestedAt:"2026-05-17T15:00:00", status:"granted",  decidedBy:"U-AD1", decidedAt:"2026-05-17T15:30:00", note:"Granted as Reviewer" },
  { id:"AR-202", userId:"U-ST4", projectId:"P-2025-009", reason:"Mistaken project",                                   requestedAt:"2026-05-15T10:00:00", status:"declined", decidedBy:"U-AD1", decidedAt:"2026-05-15T10:08:14", note:"Requested wrong project — user notified to re-request P-2025-010" },
];

/* Active access grants on ARCHIVED projects (Hard-Locked). These are people who
   were granted post-archive access — regulators, successor auditors, or staff
   assisting a response — and remain visible here so Admin can revoke later.
   `scope`: "preview" (view only) | "download" (preview + download) | "reviewer". */
const ARCHIVE_ACCESS_SEED = [
  { id:"AX-301", userId:"U-GS1", projectId:"P-2024-002", scope:"preview",  grantedBy:"U-AD1", grantedAt:"2026-05-10T09:20:00", expiresAt:"2026-06-10", reason:"SEC inquiry — review FY2024 subsequent events" },
  { id:"AX-302", userId:"U-GS2", projectId:"P-2023-005", scope:"download", grantedBy:"U-AD2", grantedAt:"2026-04-28T14:05:00", expiresAt:"2026-05-28", reason:"Successor auditor — opening-balance review" },
  { id:"AX-303", userId:"U-ST5", projectId:"P-2024-002", scope:"reviewer", grantedBy:"U-AD1", grantedAt:"2026-05-15T11:00:00", expiresAt:null,         reason:"Assisting the regulator response" },
  { id:"AX-304", userId:"U-GS1", projectId:"P-2023-007", scope:"preview",  grantedBy:"U-AD1", grantedAt:"2026-05-18T16:30:00", expiresAt:"2026-06-18", reason:"Revenue Dept. cross-check" },
];
const ARCHIVE_ACCESS_SCOPES = {
  preview:  { label:"Preview only",      cls:"" },
  download: { label:"Preview + Download", cls:"accent" },
  reviewer: { label:"Reviewer",          cls:"warn" },
};

/* WPID File Lifecycle — 4 states per requirement v5.0 §4.5.
   pending        = empty container from SOP Template, no upload yet
   in-progress    = first file uploaded, prep still ongoing
   in-review      = preparer flipped the switch; reviewer slots are live
                    (each slot has its own sub-state: รอรีวิว / Q&A ค้าง / Sign-off)
   done           = all Required slots signed (Optional doesn't block)

   Each state has tone (color), icon, label, and Thai detail. */
const WPID_STATUS_META = {
  "pending":     { tone:"draft",  icon:"file",         label:"Pending",       detail:"รออัปไฟล์" },
  "in-progress": { tone:"accent", icon:"pencil",       label:"In Progress",   detail:"อยู่ระหว่างการจัดทำ" },
  "in-review":   { tone:"warn",   icon:"eye",          label:"In Review",     detail:"อยู่ระหว่างตรวจรับ / Sign-off" },
  "done":        { tone:"ok",     icon:"check-circle", label:"Done",          detail:"Required Sign-off ครบแล้ว" },
};
const WPID_STATUS_KEYS = ["pending", "in-progress", "in-review", "done"];

/* SOP Templates */
const TEMPLATES = [
  { id:"T-FS-STD",    name:"FS Audit — Standard",        v:"v4.2", folders:5, wpids:74, active:true },
  { id:"T-INT-QTR",   name:"Interim Review — Quarterly", v:"v3.0", folders:3, wpids:21, active:true },
  { id:"T-TAX-PND50", name:"Tax Compliance — Thai PND50",v:"v2.1", folders:4, wpids:32, active:true },
  { id:"T-IC-SOX",    name:"Internal Control — SOX-lite",v:"v1.0", folders:6, wpids:58, active:true },
];

/* Project Structure — official folders per Proud Workpapers PDF slide 7
   01-CA / 02-RA / 03-RAR / 04-AC / 05-AR */
const TEMPLATE_PREVIEW = [
  { id:"1000", name:"01 — Client Acceptance (CA)", n:8, kids:[
    { id:"1100", name:"01.1 — Independence Check",     n:3 },
    { id:"1200", name:"01.2 — Engagement Letter",      n:5 },
  ]},
  { id:"2000", name:"02 — Risk Assessment (RA)", n:12, kids:[
    { id:"2100", name:"02.1 — Strategy & Risk Memo",   n:2 },
    { id:"2200", name:"02.2 — Materiality",            n:6 },
    { id:"2300", name:"02.3 — Risk Identification",    n:4 },
  ]},
  { id:"3000", name:"03 — Response to Assessed Risks (RAR)", n:28, kids:[
    { id:"3100", name:"03.1 — Revenue",      n:7 },
    { id:"3200", name:"03.2 — Inventory",    n:5 },
    { id:"3300", name:"03.3 — Receivables",  n:6 },
    { id:"3400", name:"03.4 — Payables",     n:4 },
    { id:"3500", name:"03.5 — Tax",          n:6 },
  ]},
  { id:"4000", name:"04 — Audit Conclusion (AC)",  n:15, kids:[
    { id:"4100", name:"04.1 — Subsequent Events",  n:6 },
    { id:"4200", name:"04.2 — Going Concern",      n:5 },
    { id:"4300", name:"04.3 — Final Analytics",    n:4 },
  ]},
  { id:"5000", name:"05 — Audit Reporting (AR)",   n:11, kids:[
    { id:"5100", name:"05.1 — Audit Report",       n:7 },
    { id:"5200", name:"05.2 — Management Letter",  n:4 },
  ]},
];

/* Entity edit history */
const ENTITY_HISTORY = {
  "E-001":[
    { ts:"2026-05-15T11:20:14", actor:"U-AD1", action:"add_creator", detail:"Added Sarah Mitchell as Project Creator" },
    { ts:"2024-03-02T14:10:00", actor:"U-AD2", action:"edit",        detail:"Renamed: Northwind Mfg Co., Ltd. → Northwind Industrial Co., Ltd." },
    { ts:"2024-03-02T14:09:55", actor:"U-AD2", action:"edit",        detail:"Description updated" },
    { ts:"2019-06-01T09:00:00", actor:"U-AD1", action:"create",      detail:"Entity created" },
  ],
  "E-002":[
    { ts:"2026-05-18T10:00:00", actor:"U-AD1", action:"add_creator", detail:"Added Sarah Mitchell as Project Creator" },
    { ts:"2022-01-12T11:30:00", actor:"U-AD1", action:"create",      detail:"Entity created" },
  ],
  "E-005":[
    { ts:"2026-02-08T13:42:08", actor:"U-AD1", action:"create",      detail:"Entity created (new client onboarded Q1/2026)" },
  ],
};

/* Project approval timeline */
const PROJECT_TIMELINE = {
  "P-2026-014":[
    { ts:"2026-05-21T16:32:11", actor:"U-SV1", kind:"create",  text:"Draft created from FS Audit Standard v4.2 template" },
    { ts:"2026-05-22T08:50:08", actor:"U-SV1", kind:"edit",    text:"Added members: Marcus Wong, Nattanan Chai" },
    { ts:"2026-05-22T09:14:42", actor:"U-SV1", kind:"submit",  text:"Submitted for approval" },
  ],
  "P-2026-013":[
    { ts:"2026-05-12T10:00:00", actor:"U-SV1", kind:"create",  text:"Draft created" },
  ],
  "P-2025-008":[
    { ts:"2025-10-04T09:14:00", actor:"U-SV1", kind:"create",  text:"Draft created" },
    { ts:"2025-10-08T11:00:00", actor:"U-SV1", kind:"submit",  text:"Submitted for approval" },
    { ts:"2025-10-08T14:30:00", actor:"U-AD1", kind:"approve", text:"Approved — Project published" },
  ],
};

/* ============================================================
   PROJECT WORKSPACE DATA (Structure / WPID / Sign-off / Team)
   ============================================================ */

/* Workspace folder tree — official 5-section structure per Proud Workpapers PDF slide 7.
   IDs are internal only (F-022 keeps backward compat as the active demo folder). */
const PROJECT_STRUCTURE = [
  { id:"F-01", name:"01 — Client Acceptance (CA)", items:4, children:[
    { id:"F-011", name:"01.1 — Independence Check",   items:2 },
    { id:"F-012", name:"01.2 — Engagement Letter",    items:2 },
  ]},
  { id:"F-02", name:"02 — Risk Assessment (RA)", items:9, open:true, children:[
    { id:"F-021", name:"02.1 — Strategy & Risk Memo",  items:2 },
    { id:"F-022", name:"02.2 — Materiality",           items:6, active:true },
    { id:"F-023", name:"02.3 — Risk Identification",   items:1 },
  ]},
  { id:"F-03", name:"03 — Response to Assessed Risks (RAR)", items:22, children:[
    { id:"F-031", name:"03.1 — Revenue",       items:7 },
    { id:"F-032", name:"03.2 — Inventory",     items:5 },
    { id:"F-033", name:"03.3 — Receivables",   items:6 },
    { id:"F-034", name:"03.4 — Payables",      items:4 },
  ]},
  { id:"F-04", name:"04 — Audit Conclusion (AC)",  items:6 },
  { id:"F-05", name:"05 — Audit Reporting (AR)",   items:3 },
];

/* WPIDs for folder F-022 (Audit plan) — 4-status lifecycle
   previewUrl → real sample file served from /poc-test-files/ for live rendering */
const WPIDS_2200 = [
  { id:"2201", name:"Overall audit strategy memo",   type:"docx", status:"done",      owner:"SM", v:"v4",  updated:"20/05/2026 10:00:00",  size:"48 KB",  previewUrl:"poc-test-files/sample.docx",
    preparedBy:"U-SV1", preparedByName:"Sarah Mitchell", preparedAt:"2026-05-15T10:30:00" },
  { id:"2202", name:"Materiality calculation",        type:"xlsx", status:"in-review",    owner:"MW", v:"v3",  updated:"22/05/2026 09:30:00", size:"86 KB",  previewUrl:"poc-test-files/sample.xlsx", active:true,
    preparedBy:"U-ST2", preparedByName:"Marcus Wong", preparedAt:"2026-05-20T09:14:22" },
  { id:"2203", name:"Risk & response matrix",         type:"xlsm", status:"in-progress",    owner:"MW", v:"v3d", updated:"22/05/2026 09:40:00", size:"124 KB", previewUrl:"poc-test-files/sample.xlsm",
    lockedBy:"U-ST2", lockedByName:"Marcus Wong", lockedAt:"2026-05-22T09:48:00",
    preparedBy:"U-ST2", preparedByName:"Marcus Wong", preparedAt:"2026-05-22T08:45:00" },
  { id:"2204", name:"Team briefing minutes",          type:"pdf",  status:"done",      owner:"AP", v:"v1",  updated:"17/05/2026 10:00:00",  size:"210 KB", previewUrl:"poc-test-files/sample.pdf",
    preparedBy:"U-ST1", preparedByName:"Ana Pereira", preparedAt:"2026-05-17T14:00:00" },
  /* Dangling web-edit draft demo — Sarah closed the editor without saving a
     version: others can't web-edit (1 file = 1 person) but CAN upload;
     only Sarah continues the draft, Admin may discard it. */
  { id:"2205", name:"Prior year engagement summary",  type:"docx", status:"in-review",   owner:"SM", v:"v2",  updated:"15/05/2026 10:00:00",  size:"62 KB",  previewUrl:"poc-test-files/sample.docx",
    preparedBy:"U-SV1", preparedByName:"Sarah Mitchell", preparedAt:"2026-05-14T09:00:00",
    draftBy:"U-SV1", draftByName:"Sarah Mitchell", draftAt:"21/05/2026 16:00:00", draftBaseV:"v2" },
  { id:"2206", name:"Client org chart",               type:"pdf",  status:"in-review", owner:"AP", v:"v1",  updated:"19/05/2026 10:00:00",  size:"82 KB",  previewUrl:"poc-test-files/sample.pdf",
    preparedBy:"U-ST1", preparedByName:"Ana Pereira", preparedAt:"2026-05-19T11:20:00" },
  /* Pending example — empty Smart Container from the SOP template, no upload
     yet (first state of the 4-status lifecycle, req §4.5) */
  { id:"2207", name:"Segment materiality breakdown",  type:"xlsx", status:"pending",   owner:"—",  v:"—",   updated:"—",       size:"—" },
];

/* Default sample mapping for newly-added WPIDs (so demo preview always has something) */
const SAMPLE_BY_TYPE = {
  xlsx: "poc-test-files/sample.xlsx",
  xlsm: "poc-test-files/sample.xlsm",
  xlsb: "poc-test-files/sample.xlsb",
  xls:  "poc-test-files/sample.xls",
  csv:  "poc-test-files/sample.csv",
  tsv:  "poc-test-files/sample.tsv",
  txt:  "poc-test-files/sample.txt",
  pdf:  "poc-test-files/sample.pdf",
  docx: "poc-test-files/sample.docx",
  doc:  "poc-test-files/sample.doc",
  png:  "poc-test-files/sample.png",
  jpg:  "poc-test-files/sample.jpg",
  jpeg: "poc-test-files/sample.jpeg",
};

/* Sample WPIDs for EVERY folder of the default workspace — each folder gets
   a mixed lifecycle spread (pending = empty container with no file yet,
   in-progress, in-review, done) so the demo shows all 4 states everywhere. */
const PREP_BY_INITIALS = {
  SM: ["U-SV1","Sarah Mitchell"], JK: ["U-SV3","James Khatri"],
  AP: ["U-ST1","Ana Pereira"],    MW: ["U-ST2","Marcus Wong"],
  KV: ["U-AD2","Korn Vichitchai"],
};
const mkWp = (id, name, type, status, owner, v, updated, size) => {
  if (status === "pending") return { id, name, type, status, owner:"—", v:"—", updated:"—", size:"—" };
  const [uid, uname] = PREP_BY_INITIALS[owner] || [null, owner];
  const [d, m, rest] = updated.split("/");
  const [y, time] = rest.split(" ");
  return { id, name, type, status, owner, v, updated, size,
    previewUrl: SAMPLE_BY_TYPE[type],
    preparedBy: uid, preparedByName: uname, preparedAt: `${y}-${m}-${d}T${time}` };
};
const DEFAULT_WPIDS_BY_FOLDER = {
  /* 01.1, 03.2, 03.3 and 04 are FULLY Done — they demo the folder-level
     "all complete" check mark in the structure tree */
  "F-011": [
    mkWp("1101","Independence questionnaire",        "docx","done",       "SM","v2","12/05/2026 10:00:00","36 KB"),
    mkWp("1102","Conflict-of-interest scan",         "pdf", "done",       "AP","v1","18/05/2026 11:30:00","112 KB"),
  ],
  "F-012": [
    mkWp("1201","Signed engagement letter",          "pdf", "done",       "SM","v1","10/05/2026 09:00:00","240 KB"),
    mkWp("1202","Fee & scope confirmation",          "docx","pending"),
  ],
  "F-021": [
    mkWp("2101","Audit strategy memo (draft)",       "docx","in-progress","MW","v1d","21/05/2026 16:20:00","44 KB"),
    mkWp("2102","Entity risk overview",              "xlsx","done",       "JK","v2","16/05/2026 13:00:00","58 KB"),
  ],
  "F-022": WPIDS_2200,
  "F-023": [
    mkWp("2301","Risk register",                     "xlsx","in-review",  "MW","v2","20/05/2026 15:10:00","72 KB"),
    mkWp("2302","Fraud risk brainstorm notes",       "docx","in-progress","AP","v1d","22/05/2026 08:50:00","31 KB"),
    mkWp("2303","IT general controls scoping",       "xlsx","pending"),
  ],
  "F-031": [
    mkWp("3101","Revenue walkthrough",               "docx","done",       "AP","v2","14/05/2026 10:00:00","52 KB"),
    mkWp("3102","Cut-off testing",                   "xlsx","in-review",  "MW","v1","19/05/2026 14:40:00","66 KB"),
    mkWp("3103","Revenue analytics",                 "xlsx","in-progress","MW","v2d","22/05/2026 09:10:00","81 KB"),
    mkWp("3104","Deferred income testing",           "xlsx","pending"),
  ],
  "F-032": [
    mkWp("3201","Inventory count sheets",            "xlsx","done",       "AP","v1","13/05/2026 09:30:00","94 KB"),
    mkWp("3202","NRV testing",                       "xlsx","done",       "AP","v2","21/05/2026 17:05:00","47 KB"),
    mkWp("3203","Obsolescence provision memo",       "docx","done",       "SM","v1","19/05/2026 14:20:00","38 KB"),
  ],
  "F-033": [
    mkWp("3301","AR confirmation control",           "xlsx","done",       "SM","v2","20/05/2026 11:25:00","63 KB"),
    mkWp("3302","Subsequent receipts testing",       "xlsx","done",       "AP","v1","17/05/2026 15:00:00","49 KB"),
    mkWp("3303","ECL provision assessment",          "xlsx","done",       "MW","v3","21/05/2026 09:45:00","71 KB"),
  ],
  "F-034": [
    mkWp("3401","Supplier statement reconciliation", "xlsx","in-progress","MW","v1d","22/05/2026 08:30:00","58 KB"),
    mkWp("3402","Unrecorded liabilities search",     "xlsx","pending"),
  ],
  "F-04": [
    mkWp("4001","Summary of misstatements",          "xlsx","done",       "SM","v3","21/05/2026 10:15:00","39 KB"),
    mkWp("4002","Going concern assessment",          "docx","done",       "JK","v2","21/05/2026 14:50:00","57 KB"),
    mkWp("4003","Management representation letter",  "docx","done",       "KV","v1","22/05/2026 09:05:00","44 KB"),
  ],
  "F-05": [
    mkWp("5001","Draft auditor's report",            "docx","in-progress","JK","v1d","22/05/2026 09:55:00","41 KB"),
    mkWp("5002","Key audit matters note",            "docx","pending"),
  ],
};

/* Version history for WP-2202 (current active WPID in demo) */
const WP2202_VERSIONS = [
  { v:"v3 (current)", who:"MW", t:"22/05/2026 09:30:00",  note:"Revised benchmark to 5% PBT · added segment materiality table" },
  { v:"v2",           who:"MW", t:"20/05/2026 10:00:00",   note:"Added overall materiality section" },
  { v:"v1",           who:"AP", t:"15/05/2026 10:00:00",   note:"Initial draft from FS Audit Standard template" },
];

/* Sign-off chain for WP-2202 — MTG4 §2.2: 6 review roles
   (Preparer / In-Charge / Manager / Director / Partner / EQR), each Required or Optional per project.
   stale=true means signed on older version, notification sent. */
const SIGN_CHAIN_2202 = [
  { role:"Preparer",  required:true,  userId:"U-ST2", name:"Marcus Wong",     initials:"MW", status:"signed",   version:"v1", signedAt:"20/05/2026 10:00:00",  stale:true },
  { role:"In-Charge", required:true,  userId:"U-ST1", name:"Ana Pereira",     initials:"AP", status:"pending" },
  { role:"Manager",   required:true,  userId:"U-SV1", name:"Sarah Mitchell",  initials:"SM", status:"signed",   version:"v1", signedAt:"21/05/2026 10:00:00",  stale:true },
  { role:"Director",  required:false, userId:null,    name:null,              initials:null, status:"skipped",  note:"Optional — not required for Category A" },
  { role:"Partner",   required:true,  userId:"U-AD2", name:"Korn Vichitchai", initials:"KV", status:"pending" },
  { role:"EQR",       required:false, userId:null,    name:null,              initials:null, status:"optional", note:"Optional — not assigned" },
];

/* Per-WPID chains for the default demo workspace (P-2025-008 / folder F-022).
   Gives every WPID an explicit slot state so the §4.12 readiness counter
   ("N/6 WPIDs ready") reads real data: 2201 + 2204 are fully Required-signed,
   the rest are still in flight → "Set Report Date" stays disabled here. */
const SIGN_CHAINS_2200 = {
  "2201": [
    { role:"Preparer",  required:true,  userId:"U-SV1", name:"Sarah Mitchell",  initials:"SM", status:"signed", version:"v4", signedAt:"20/05/2026 10:00:00" },
    { role:"In-Charge", required:true,  userId:"U-ST1", name:"Ana Pereira",     initials:"AP", status:"signed", version:"v4", signedAt:"20/05/2026 10:00:00" },
    { role:"Manager",   required:true,  userId:"U-SV3", name:"James Khatri",    initials:"JK", status:"signed", version:"v4", signedAt:"21/05/2026 10:00:00" },
    { role:"Director",  required:false, userId:null,    name:null,              initials:null, status:"skipped",  note:"Optional — not required for Category A" },
    { role:"Partner",   required:true,  userId:"U-AD2", name:"Korn Vichitchai", initials:"KV", status:"signed", version:"v4", signedAt:"21/05/2026 10:00:00" },
    { role:"EQR",       required:false, userId:null,    name:null,              initials:null, status:"optional", note:"Optional — not assigned" },
  ],
  "2202": SIGN_CHAIN_2202,
  "2204": [
    { role:"Preparer",  required:true,  userId:"U-ST1", name:"Ana Pereira",     initials:"AP", status:"signed", version:"v1", signedAt:"17/05/2026 10:00:00" },
    { role:"In-Charge", required:true,  userId:"U-ST2", name:"Marcus Wong",     initials:"MW", status:"signed", version:"v1", signedAt:"18/05/2026 10:00:00" },
    { role:"Manager",   required:true,  userId:"U-SV1", name:"Sarah Mitchell",  initials:"SM", status:"signed", version:"v1", signedAt:"18/05/2026 10:00:00" },
    { role:"Director",  required:false, userId:null,    name:null,              initials:null, status:"skipped",  note:"Optional — not required for Category A" },
    { role:"Partner",   required:true,  userId:"U-AD2", name:"Korn Vichitchai", initials:"KV", status:"signed", version:"v1", signedAt:"19/05/2026 10:00:00" },
    { role:"EQR",       required:false, userId:null,    name:null,              initials:null, status:"optional", note:"Optional — not assigned" },
  ],
  "2205": [
    { role:"Preparer",  required:true,  userId:"U-SV1", name:"Sarah Mitchell",  initials:"SM", status:"signed", version:"v2", signedAt:"15/05/2026 10:00:00" },
    { role:"In-Charge", required:true,  userId:"U-ST1", name:"Ana Pereira",     initials:"AP", status:"pending" },
    { role:"Manager",   required:true,  userId:"U-SV3", name:"James Khatri",    initials:"JK", status:"pending" },
    { role:"Director",  required:false, userId:null,    name:null,              initials:null, status:"skipped",  note:"Optional — not required for Category A" },
    { role:"Partner",   required:true,  userId:"U-AD2", name:"Korn Vichitchai", initials:"KV", status:"pending" },
    { role:"EQR",       required:false, userId:null,    name:null,              initials:null, status:"optional", note:"Optional — not assigned" },
  ],
  "2206": [
    { role:"Preparer",  required:true,  userId:"U-ST1", name:"Ana Pereira",     initials:"AP", status:"signed", version:"v1", signedAt:"19/05/2026 10:00:00" },
    { role:"In-Charge", required:true,  userId:"U-ST2", name:"Marcus Wong",     initials:"MW", status:"signed", version:"v1", signedAt:"20/05/2026 10:00:00" },
    { role:"Manager",   required:true,  userId:"U-SV1", name:"Sarah Mitchell",  initials:"SM", status:"pending" },
    { role:"Director",  required:false, userId:null,    name:null,              initials:null, status:"skipped",  note:"Optional — not required for Category A" },
    { role:"Partner",   required:true,  userId:"U-AD2", name:"Korn Vichitchai", initials:"KV", status:"pending" },
    { role:"EQR",       required:false, userId:null,    name:null,              initials:null, status:"optional", note:"Optional — not assigned" },
  ],
  /* 2203 (in-progress) intentionally has no chain yet — it hasn't been
     submitted for review, so it inherits the project's pending slots. */
};

/* ============================================================
   PER-PROJECT WORKSPACE SEEDS — γ-flow (§4.12) demo coverage
   ============================================================
   Projects listed here get their own WPID set + sign chains so the
   "Set Report Date" guard reads real data per project:

   · P-2025-010 (Orion)   → ALL Required slots signed → button ENABLED.
       WP-9102's Partner slot is signed by Praewa (CURRENT_ADMIN) so the
       "Cancel sign-off (before T0)" path is demoable too. EQR is an
       unsigned Optional slot → shows "Optional doesn't block Done".
   · P-2025-009 (Kalama)  → Soft Lock T-3 — chains fully signed (coherent:
       T0 could only have been set after Required sign-offs completed).
   · P-2025-011 (Thaipan) → Soft Lock T-23 — same, fully signed.
   Projects NOT listed fall back to WPIDS_2200 / SIGN_CHAINS_2200. */

const WPIDS_OCP_READY = [
  { id:"9101", name:"Planning memorandum",       type:"docx", status:"done", owner:"JK", v:"v2", updated:"16/05/2026 10:00:00", size:"54 KB", previewUrl:"poc-test-files/sample.docx",
    preparedBy:"U-SV3", preparedByName:"James Khatri", preparedAt:"2026-05-02T10:00:00" },
  { id:"9102", name:"Materiality & scoping",     type:"xlsx", status:"done", owner:"MW", v:"v3", updated:"17/05/2026 10:00:00", size:"91 KB", previewUrl:"poc-test-files/sample.xlsx", active:true,
    preparedBy:"U-ST2", preparedByName:"Marcus Wong", preparedAt:"2026-05-04T14:30:00" },
  { id:"9103", name:"Revenue walkthrough",       type:"xlsx", status:"done", owner:"LW", v:"v2", updated:"18/05/2026 10:00:00", size:"77 KB", previewUrl:"poc-test-files/sample.xlsx",
    preparedBy:"U-ST5", preparedByName:"Lin Wei", preparedAt:"2026-05-06T09:00:00" },
];
const SIGN_CHAINS_OCP = {
  "9101": [
    { role:"Preparer",  required:true,  userId:"U-SV3", name:"James Khatri",    initials:"JK", status:"signed", version:"v2", signedAt:"16/05/2026 10:00:00" },
    { role:"In-Charge", required:true,  userId:"U-ST2", name:"Marcus Wong",     initials:"MW", status:"signed", version:"v2", signedAt:"17/05/2026 10:00:00" },
    { role:"Manager",   required:true,  userId:"U-SV1", name:"Sarah Mitchell",  initials:"SM", status:"signed", version:"v2", signedAt:"17/05/2026 10:00:00" },
    { role:"Partner",   required:true,  userId:"U-AD2", name:"Korn Vichitchai", initials:"KV", status:"signed", version:"v2", signedAt:"18/05/2026 10:00:00" },
    { role:"EQR",       required:false, userId:null,    name:null,              initials:null, status:"optional", note:"Optional — unsigned, does not block Done" },
  ],
  "9102": [
    { role:"Preparer",  required:true,  userId:"U-ST2", name:"Marcus Wong",     initials:"MW", status:"signed", version:"v3", signedAt:"17/05/2026 10:00:00" },
    { role:"In-Charge", required:true,  userId:"U-ST5", name:"Lin Wei",         initials:"LW", status:"signed", version:"v3", signedAt:"17/05/2026 10:00:00" },
    { role:"Manager",   required:true,  userId:"U-SV3", name:"James Khatri",    initials:"JK", status:"signed", version:"v3", signedAt:"18/05/2026 10:00:00" },
    { role:"Partner",   required:true,  userId:"U-AD1", name:"Praewa Saetang",  initials:"PS", status:"signed", version:"v3", signedAt:"18/05/2026 10:00:00" },
    { role:"EQR",       required:false, userId:null,    name:null,              initials:null, status:"optional", note:"Optional — unsigned, does not block Done" },
  ],
  "9103": [
    { role:"Preparer",  required:true,  userId:"U-ST5", name:"Lin Wei",         initials:"LW", status:"signed", version:"v2", signedAt:"18/05/2026 10:00:00" },
    { role:"In-Charge", required:true,  userId:"U-ST2", name:"Marcus Wong",     initials:"MW", status:"signed", version:"v2", signedAt:"18/05/2026 10:00:00" },
    { role:"Manager",   required:true,  userId:"U-SV1", name:"Sarah Mitchell",  initials:"SM", status:"signed", version:"v2", signedAt:"19/05/2026 10:00:00" },
    { role:"Partner",   required:true,  userId:"U-AD2", name:"Korn Vichitchai", initials:"KV", status:"signed", version:"v2", signedAt:"19/05/2026 10:00:00" },
    { role:"EQR",       required:false, userId:null,    name:null,              initials:null, status:"optional", note:"Optional — unsigned, does not block Done" },
  ],
};

/* Compact fully-signed sets for the two soft-locked projects */
const WPIDS_KFG_LOCKED = [
  { id:"8101", name:"Audit strategy & materiality", type:"xlsx", status:"done", owner:"JK", v:"v4", updated:"20/03/2026 10:00:00", size:"88 KB", previewUrl:"poc-test-files/sample.xlsx", active:true,
    preparedBy:"U-SV3", preparedByName:"James Khatri", preparedAt:"2026-02-10T10:00:00" },
  { id:"8102", name:"Receivables confirmation",     type:"xlsx", status:"done", owner:"AP", v:"v2", updated:"20/03/2026 10:00:00", size:"64 KB", previewUrl:"poc-test-files/sample.xlsx",
    preparedBy:"U-ST1", preparedByName:"Ana Pereira", preparedAt:"2026-02-18T11:00:00" },
  { id:"8103", name:"Final analytics memo",         type:"docx", status:"done", owner:"MW", v:"v3", updated:"27/03/2026 10:00:00", size:"51 KB", previewUrl:"poc-test-files/sample.docx",
    preparedBy:"U-ST2", preparedByName:"Marcus Wong", preparedAt:"2026-03-01T09:30:00" },
];
const mkSignedChain = (preparer, inCharge, manager) => ([
  { role:"Preparer",  required:true,  userId:preparer[0],  name:preparer[1],  initials:preparer[2],  status:"signed", version:"final", signedAt:"20/03/2026 10:00:00" },
  { role:"In-Charge", required:true,  userId:inCharge[0],  name:inCharge[1],  initials:inCharge[2],  status:"signed", version:"final", signedAt:"20/03/2026 10:00:00" },
  { role:"Manager",   required:true,  userId:manager[0],   name:manager[1],   initials:manager[2],   status:"signed", version:"final", signedAt:"27/03/2026 10:00:00" },
  { role:"Partner",   required:true,  userId:"U-AD2",      name:"Korn Vichitchai", initials:"KV",    status:"signed", version:"final", signedAt:"27/03/2026 10:00:00" },
  { role:"EQR",       required:false, userId:null,         name:null,         initials:null,         status:"optional", note:"Optional — not assigned" },
]);
const SIGN_CHAINS_KFG = {
  "8101": mkSignedChain(["U-SV3","James Khatri","JK"], ["U-ST1","Ana Pereira","AP"], ["U-SV3","James Khatri","JK"]),
  "8102": mkSignedChain(["U-ST1","Ana Pereira","AP"],  ["U-ST2","Marcus Wong","MW"], ["U-SV3","James Khatri","JK"]),
  "8103": mkSignedChain(["U-ST2","Marcus Wong","MW"],  ["U-ST1","Ana Pereira","AP"], ["U-SV3","James Khatri","JK"]),
};
const WPIDS_TPB_LOCKED = [
  { id:"7101", name:"Audit plan & risk matrix", type:"xlsx", status:"done", owner:"TS", v:"v3", updated:"17/04/2026 10:00:00", size:"72 KB", previewUrl:"poc-test-files/sample.xlsx", active:true,
    preparedBy:"U-SV2", preparedByName:"Tanaporn Suthep", preparedAt:"2026-03-12T10:00:00" },
  { id:"7102", name:"Inventory count summary",  type:"docx", status:"done", owner:"NC", v:"v2", updated:"17/04/2026 10:00:00", size:"45 KB", previewUrl:"poc-test-files/sample.docx",
    preparedBy:"U-ST3", preparedByName:"Nattanan Chai", preparedAt:"2026-03-20T14:00:00" },
];
const SIGN_CHAINS_TPB = {
  "7101": mkSignedChain(["U-SV2","Tanaporn Suthep","TS"], ["U-ST3","Nattanan Chai","NC"], ["U-SV2","Tanaporn Suthep","TS"]),
  "7102": mkSignedChain(["U-ST3","Nattanan Chai","NC"],   ["U-ST4","Veerayut Pansri","VP"], ["U-SV2","Tanaporn Suthep","TS"]),
};

/* Version history for EVERY uploaded WPID (any status except pending) —
   derived from each WPID's current version number so the Version History
   panel and Compare button always have demo data. WP-2202 keeps its
   hand-written history. */
const DEFAULT_VERSIONS_BY_WPID = (() => {
  const shiftDays = (updated, days) => {
    const [d, m, rest] = updated.split("/");
    const [y, time] = rest.split(" ");
    const dt = new Date(`${y}-${m}-${d}T${time || "10:00:00"}`);
    dt.setDate(dt.getDate() - days);
    const pad = n => String(n).padStart(2, "0");
    return `${pad(dt.getDate())}/${pad(dt.getMonth()+1)}/${dt.getFullYear()} ${time || "10:00:00"}`;
  };
  const out = { "2202": WP2202_VERSIONS };
  const addFrom = (list) => list.forEach(w => {
    if (out[w.id] || !w.updated || w.updated === "—") return;
    const num = Math.max(1, parseInt(String(w.v).replace(/\D/g, ""), 10) || 1);
    out[w.id] = Array.from({ length: Math.min(num, 3) }, (_, i) => {
      const vn = num - i;
      return {
        v: `v${vn}${i === 0 ? " (current)" : ""}`,
        who: w.owner,
        t: i === 0 ? w.updated : shiftDays(w.updated, i * 3),
        note: vn === 1 ? "Initial draft from SOP template"
            : i === 0  ? "Latest revision after review"
            :            "Incorporated review comments",
      };
    });
  });
  Object.values(DEFAULT_WPIDS_BY_FOLDER).forEach(addFrom);
  [WPIDS_OCP_READY, WPIDS_KFG_LOCKED, WPIDS_TPB_LOCKED].forEach(addFrom);
  return out;
})();

const WPID_SEEDS_BY_PROJECT = {
  "P-2025-010": { "F-022": WPIDS_OCP_READY },
  "P-2025-009": { "F-022": WPIDS_KFG_LOCKED },
  "P-2025-011": { "F-022": WPIDS_TPB_LOCKED },
};
const CHAIN_SEEDS_BY_PROJECT = {
  "P-2025-010": SIGN_CHAINS_OCP,
  "P-2025-009": SIGN_CHAINS_KFG,
  "P-2025-011": SIGN_CHAINS_TPB,
};

/* Review Sheets for WP-2202 — per req v5.0 §4.6 + §4.9.
   Each sheet is keyed by reviewer slot index; each sheet holds an
   ordered list of Q&A rounds (Q1-A1, Q2-A2, ...). For POC the slot
   indices align with SIGN_CHAIN_2202 order. */
const REVIEW_SHEETS_2202 = {
  /* Slot 1 = In-Charge (Ana Pereira) — has one open question */
  1: [
    { id:"QA-1-1",
      qBy:"U-ST1", qByName:"Ana Pereira", qAt:"22/05/2026 07:00:00",
      q:"Please verify the benchmark percentage — should it be **5% of PBT** or **2% of revenue**? See row 8 of strategy memo.",
      aBy:"U-ST2", aByName:"Marcus Wong", aAt:"22/05/2026 09:00:00",
      a:"Confirmed 5% of PBT. Updated row 8 to match. Also added segment materiality table in rows 14–18.",
    },
    { id:"QA-1-2",
      qBy:"U-ST1", qByName:"Ana Pereira", qAt:"22/05/2026 09:15:00",
      q:"Add **comparative prior-year figures** in the summary table (top-of-sheet). Match the FY2024 layout please.",
      /* no answer yet — waiting */
    },
  ],
  /* Slot 4 = Partner (Korn Vichitchai) — no Q&A yet, not signed */
  4: [],
};

/* Review Notes (Task) for WP-2202 — legacy flat thread, kept for KanbanBoard
   open-note count until that view migrates to Review Sheets too.
   Extended fields: subject, assignee, rich content, screenshot attachments,
   WPID reassign history. 1 WPID = 1 Task timeline. */
const REVIEW_NOTES_2202 = [
  { id:"RN-001", type:"note",    userId:"U-SV1", name:"Sarah Mitchell",  initials:"SM",
    subject:"Materiality benchmark check",
    text:"Please verify the benchmark percentage — should be **5% of PBT** per the audit strategy memo.\n\nSee row 8 of the strategy memo for the source.",
    assigneeId:"U-ST2", assigneeName:"Marcus Wong",
    screenshots:[],
    wpidHistory:[{wpid:"2202", at:"20/05/2026 10:00:00"}],
    ts:"20/05/2026 10:00:00", resolved:true },
  { id:"RN-002", type:"reply",   userId:"U-ST2", name:"Marcus Wong",     initials:"MW",
    text:"Updated to 5% PBT. Also added segment-level materiality for all 3 business units in rows 14–18.",
    ts:"20/05/2026 10:00:00", resolved:true },
  { id:"RN-003", type:"resolve", userId:"U-SV1", name:"Sarah Mitchell",  initials:"SM",
    text:"Confirmed ✓ — resolved.", ts:"21/05/2026 10:00:00", resolved:true },
  { id:"RN-004", type:"note",    userId:"U-SV1", name:"Sarah Mitchell",  initials:"SM",
    subject:"Prior year comparatives",
    text:"Please add **comparative prior year figures** in the summary table (top-of-sheet).\n\nThis should match the format we used in FY2024.",
    assigneeId:"U-ST2", assigneeName:"Marcus Wong",
    screenshots:[{name:"pasted-image-1.png", dataUrl:null, w:280, h:160}],
    wpidHistory:[
      {wpid:"2201", at:"22/05/2026 09:15:00", note:"initially attached to strategy memo"},
      {wpid:"2202", at:"22/05/2026 09:30:00", note:"reassigned by Sarah — belongs here instead"},
    ],
    ts:"22/05/2026 09:30:00", resolved:false },
];

/* Project workspace team — IDs align with USERS schema */
const PROJECT_TEAM = [
  { id:"U-SV1", name:"Sarah Mitchell", role:"Supervisor", initials:"SM" },
  { id:"U-SV3", name:"James Khatri",   role:"Supervisor", initials:"JK" },
  { id:"U-ST1", name:"Ana Pereira",    role:"Staff",      initials:"AP" },
  { id:"U-ST2", name:"Marcus Wong",    role:"Staff",      initials:"MW" },
];

/* Per-project metadata for active workspace */
const PROJECT_META = {
  "P-2025-008": { stage:"Fieldwork",  prog:62,  lead:"SM", openNotes:4, due:"Mar 31, 2026" },
  "P-2025-009": { stage:"Sign-off",   prog:100, lead:"JK", openNotes:0, due:"Feb 28, 2026" },
  "P-2025-010": { stage:"Sign-off",   prog:96,  lead:"JK", openNotes:0, due:"Apr 30, 2026" },
  "P-2025-011": { stage:"Sign-off",   prog:100, lead:"TS", openNotes:0, due:"Jun 14, 2026" },
};

/* Recycle Bin items (demo data) — per MTG3: scoped per-project, no permanent-delete button.
   `folderExists:false` triggers the "select restore location" picker on restore. */
const RECYCLE_BIN = [
  { id:"RB-001", type:"wpid", name:"Draft risk assessment v0", folder:"02.2 — Materiality", folderExists:true,
    project:"P-2025-008", projectName:"Annual Audit FY2025", deletedBy:"U-ST2", deletedByName:"Marcus Wong", deletedAt:"2026-05-25T14:22:00", size:"34 KB" },
  { id:"RB-002", type:"wpid", name:"Preliminary engagement checklist", folder:"01.1 — Independence Check", folderExists:true,
    project:"P-2025-008", projectName:"Annual Audit FY2025", deletedBy:"U-ST1", deletedByName:"Ana Pereira", deletedAt:"2026-05-24T10:05:00", size:"12 KB" },
  { id:"RB-003", type:"file", name:"client_data_raw_v0.xlsx", folder:"03.2 — Inventory (deleted)", folderExists:false,
    project:"P-2025-009", projectName:"Annual Audit FY2025 (KFG)", deletedBy:"U-SV3", deletedByName:"James Khatri", deletedAt:"2026-05-20T09:30:00", size:"281 KB" },
  { id:"RB-004", type:"folder", name:"04.2 — Drafts (old)", folder:"04 — Audit Conclusion (AC)", folderExists:true,
    project:"P-2025-008", projectName:"Annual Audit FY2025", deletedBy:"U-SV1", deletedByName:"Sarah Mitchell", deletedAt:"2026-05-23T16:11:00", size:"4 items" },
  { id:"RB-005", type:"wpid", name:"Sample selection v0", folder:"03.1 — Revenue", folderExists:true,
    project:"P-2025-010", projectName:"Annual Audit FY2025 (OCP)", deletedBy:"U-ST2", deletedByName:"Marcus Wong", deletedAt:"2026-05-22T11:02:00", size:"56 KB" },
];

/* ============================================================
   HOME (My Workspace) DATA — recent files + cross-project to-do
   ============================================================
   The Home page is a personal pulse, not an Approval-Center mirror.
   - RECENT_FILES_SEED  → files I (or anyone) recently opened/edited/reviewed
   - HOME_TODO_SEED     → things waiting on a specific user across projects

   These two seeds intentionally span MULTIPLE projects so the Home page
   demo isn't dependent on WPIDS_2200 (which only exists for P-2025-008). */

const HOME_ACTIONS = {
  edited:   { tone:"accent", icon:"edit-3",       label:"Edited"   },
  viewed:   { tone:"draft",  icon:"eye",          label:"Viewed"   },
  reviewed: { tone:"warn",   icon:"check-circle", label:"Reviewed" },
  uploaded: { tone:"ok",     icon:"plus",         label:"Uploaded" },
  signed:   { tone:"ok",     icon:"check",        label:"Signed"   },
};

/* Recent files — across the demo system. Mix of viewers + editors per file.
   `accessedBy` is the user who touched it; `accessedAt` is anchored relative
   to DEMO_TODAY so timestamps stay stable. Action is what they did with it. */
const RECENT_FILES_SEED = [
  { id:"RF-001", fileName:"Materiality calculation",     type:"xlsx", wpidId:"2202", wpidName:"Materiality calculation",
    projectId:"P-2025-008", folderPath:"02 RA › 02.2 Materiality",
    accessedBy:"U-AD1", accessedAt:"2026-05-22T09:42:00", action:"reviewed" },
  { id:"RF-002", fileName:"Overall audit strategy memo", type:"docx", wpidId:"2201", wpidName:"Overall audit strategy memo",
    projectId:"P-2025-008", folderPath:"02 RA › 02.1 Strategy",
    accessedBy:"U-AD1", accessedAt:"2026-05-22T08:55:00", action:"edited" },
  { id:"RF-003", fileName:"Risk & response matrix",      type:"xlsm", wpidId:"2203", wpidName:"Risk & response matrix",
    projectId:"P-2025-008", folderPath:"02 RA › 02.2 Materiality",
    accessedBy:"U-AD1", accessedAt:"2026-05-21T16:20:00", action:"viewed" },
  { id:"RF-004", fileName:"Engagement letter — Northwind FY2026", type:"pdf", wpidId:"1201", wpidName:"Engagement letter",
    projectId:"P-2026-015", folderPath:"01 CA › 01.2 Engagement",
    accessedBy:"U-AD1", accessedAt:"2026-05-21T14:11:00", action:"viewed" },
  { id:"RF-005", fileName:"Revenue cut-off sample selection", type:"xlsx", wpidId:"3101", wpidName:"Revenue cut-off sample",
    projectId:"P-2025-010", folderPath:"03 RAR › 03.1 Revenue",
    accessedBy:"U-AD1", accessedAt:"2026-05-20T11:30:00", action:"reviewed" },
  { id:"RF-006", fileName:"Independence checklist signed", type:"pdf", wpidId:"1101", wpidName:"Independence checklist",
    projectId:"P-2025-009", folderPath:"01 CA › 01.1 Independence",
    accessedBy:"U-AD1", accessedAt:"2026-05-19T09:14:00", action:"signed" },
  { id:"RF-007", fileName:"Going concern memo",          type:"docx", wpidId:"4201", wpidName:"Going concern memo",
    projectId:"P-2025-010", folderPath:"04 AC › 04.2 Going Concern",
    accessedBy:"U-AD1", accessedAt:"2026-05-18T15:45:00", action:"viewed" },
  { id:"RF-008", fileName:"Subsequent events checklist", type:"docx", wpidId:"4101", wpidName:"Subsequent events checklist",
    projectId:"P-2025-008", folderPath:"04 AC › 04.1 Subsequent Events",
    accessedBy:"U-AD1", accessedAt:"2026-05-17T13:08:00", action:"viewed" },
  /* Other users' recents — for "View as" demo */
  { id:"RF-009", fileName:"Materiality calculation",     type:"xlsx", wpidId:"2202", wpidName:"Materiality calculation",
    projectId:"P-2025-008", folderPath:"02 RA › 02.2 Materiality",
    accessedBy:"U-ST2", accessedAt:"2026-05-22T09:48:00", action:"edited" },
  { id:"RF-010", fileName:"Risk & response matrix",      type:"xlsm", wpidId:"2203", wpidName:"Risk & response matrix",
    projectId:"P-2025-008", folderPath:"02 RA › 02.2 Materiality",
    accessedBy:"U-ST2", accessedAt:"2026-05-22T09:38:00", action:"edited" },
  { id:"RF-011", fileName:"Client org chart",            type:"pdf",  wpidId:"2206", wpidName:"Client org chart",
    projectId:"P-2025-008", folderPath:"02 RA › 02.2 Materiality",
    accessedBy:"U-SV1", accessedAt:"2026-05-22T08:40:00", action:"reviewed" },
];

/* My to-do — cross-project pending actions, keyed to a specific assignee.
   Kinds:
     work-on      → WPID assigned to me, status in-progress / rn-rejected (I prepare)
     review       → WPID waiting for my review (status waiting-review, reviewer = me)
     respond-rn   → Review Note assigned to me, not resolved (I am the assignee)
     sign-off     → Sign-off chain row where userId = me, status pending */
const HOME_TODO_SEED = [
  /* Praewa (U-AD1) — Admin signs as Partner / approves */
  { id:"TD-001", kind:"sign-off", assignee:"U-AD1", role:"Partner",
    wpidId:"2202", wpidName:"Materiality calculation", projectId:"P-2025-008",
    folderPath:"02 RA › 02.2 Materiality", priority:"high", flaggedAt:"2026-05-21T16:00:00" },
  { id:"TD-002", kind:"review", assignee:"U-AD1",
    wpidId:"2206", wpidName:"Client org chart", projectId:"P-2025-008",
    folderPath:"02 RA › 02.2 Materiality", status:"in-review",
    priority:"normal", flaggedAt:"2026-05-19T11:20:00" },
  { id:"TD-003", kind:"sign-off", assignee:"U-AD1", role:"Director",
    wpidId:"4201", wpidName:"Going concern memo", projectId:"P-2025-010",
    folderPath:"04 AC › 04.2 Going Concern", priority:"high", flaggedAt:"2026-05-21T10:14:00" },
  { id:"TD-004", kind:"respond-rn", assignee:"U-AD1",
    rnId:"RN-PA-01", rnSubject:"Re-verify SEC filing disclosure note",
    wpidId:"5101", wpidName:"Audit report — final draft", projectId:"P-2025-010",
    folderPath:"05 AR › 05.1 Audit Report",
    askedBy:"U-SV1", askedByName:"Sarah Mitchell", askedAt:"2026-05-21T14:30:00" },

  /* Sarah Mitchell (U-SV1) — Manager-level supervisor */
  { id:"TD-005", kind:"review", assignee:"U-SV1",
    wpidId:"2206", wpidName:"Client org chart", projectId:"P-2025-008",
    folderPath:"02 RA › 02.2 Materiality", status:"in-review",
    priority:"normal", flaggedAt:"2026-05-19T11:20:00" },
  { id:"TD-006", kind:"work-on", assignee:"U-SV1",
    wpidId:"5202", wpidName:"Management letter draft", projectId:"P-2025-008",
    folderPath:"05 AR › 05.2 Management Letter", status:"in-progress",
    priority:"normal", flaggedAt:"2026-05-22T08:00:00" },
  { id:"TD-007", kind:"sign-off", assignee:"U-SV1", role:"Manager",
    wpidId:"3301", wpidName:"Receivables circularisation", projectId:"P-2025-010",
    folderPath:"03 RAR › 03.3 Receivables", priority:"normal", flaggedAt:"2026-05-20T16:00:00" },

  /* Marcus Wong (U-ST2) — Staff */
  { id:"TD-008", kind:"work-on", assignee:"U-ST2",
    wpidId:"2203", wpidName:"Risk & response matrix", projectId:"P-2025-008",
    folderPath:"02 RA › 02.2 Materiality", status:"in-progress",
    priority:"high", flaggedAt:"2026-05-22T09:48:00" },
  { id:"TD-009", kind:"respond-rn", assignee:"U-ST2",
    rnId:"RN-004", rnSubject:"Prior year comparatives",
    wpidId:"2202", wpidName:"Materiality calculation", projectId:"P-2025-008",
    folderPath:"02 RA › 02.2 Materiality",
    askedBy:"U-SV1", askedByName:"Sarah Mitchell", askedAt:"2026-05-22T08:30:00" },

  /* Ana Pereira (U-ST1) */
  { id:"TD-010", kind:"work-on", assignee:"U-ST1",
    wpidId:"3201", wpidName:"Inventory observation sheet", projectId:"P-2025-008",
    folderPath:"03 RAR › 03.2 Inventory", status:"in-progress", reopened:true,
    priority:"high", flaggedAt:"2026-05-21T17:00:00" },
];

/* Default Reviewer Slots for a new project — per req v5.0 §4.6.
   A "Slot" is one seat in the review chain held by a single reviewer
   (e.g. Manager #1 and Manager #2 are two distinct slots even though
   they share the role name). Preparer is intentionally excluded —
   it's the person who actually prepared the WPID, auto-stamped on
   the file, so no project-level pre-assignment is needed.
   These 5 seed slots start unassigned (userId:null); the form lets
   the user rename, toggle Required ↔ Optional, pick a person, add a
   duplicate "#2" slot, or remove rows. */
const DEFAULT_REVIEWER_SLOTS = [
  { role:"In-Charge", required:true,  userId:null },
  { role:"Manager",   required:true,  userId:null },
  { role:"Director",  required:false, userId:null },
  { role:"Partner",   required:true,  userId:null },
  { role:"EQR",       required:false, userId:null },
];

/* Entity description cap — sized to stay tidy where it renders
   (entity header subtitle, max-width 760px ≈ 1 line). */
const ENTITY_DESC_MAX = 100;

/* ---- Cloud-storage usage (mock) ----
   Per-project MB figures for the demo (workpapers are documents — hundreds of
   MB per engagement is the realistic scale); entity usage = sum of its
   projects. Known projects get curated values; anything else gets a stable
   hash-derived fallback. Display unit is MB everywhere (user decision). */
const PROJECT_STORAGE_MB = {
  "P-2025-008": 820,  // NWI Annual Audit FY2025 (active, rich)
  "P-2025-009": 540,  // KFG Annual Audit FY2025
  "P-2025-010": 470,  // OCP Annual Audit FY2025
  "P-2025-011": 385,  // TPB Annual Audit FY2025
};
const projectStorageMB = (id) => {
  if (PROJECT_STORAGE_MB[id] != null) return PROJECT_STORAGE_MB[id];
  let h = 0;
  for (const ch of String(id)) h = (h * 31 + ch.charCodeAt(0)) % 997;
  return 40 + (h % 280); // stable 40–319 MB
};
const entityStorageMB = (entityId, projects) =>
  (projects || []).filter(p => p.entityId === entityId)
    .reduce((sum, p) => sum + projectStorageMB(p.id), 0);
const fmtMB = (mb) => `${Math.round(mb).toLocaleString()} MB`;

/* Helpers */
const userById     = (id) => USERS.find(u=>u.id===id) || { id, name:"Unknown", role:"" };
const entityById   = (id) => ENTITIES_SEED.find(e=>e.id===id);
const projectById  = (id) => PROJECTS_SEED.find(p=>p.id===id);
const templateById = (id) => TEMPLATES.find(t=>t.id===id);
const projectsByEntity = (eid) => PROJECTS_SEED.filter(p=>p.entityId===eid);

/* Demo "today" — anchored to 2026-05-22 so countdown numbers stay stable. */
const DEMO_TODAY = new Date('2026-05-22T10:00:00');

/* Days until project is auto-archived (T-Lock countdown).
   Returns null if no auditorReportDate, negative if past T-0. */
const daysToAutoArchive = (project) => {
  if (!project?.auditorReportDate) return null;
  const reportDate = new Date(project.auditorReportDate);
  const lockDate = new Date(reportDate.getTime() + ARCHIVE_RULES.LOCK_DAYS * 86400000);
  return Math.ceil((lockDate - DEMO_TODAY) / 86400000);
};

/* Classify approach state per Proud Workpapers spec */
const archiveTone = (days) => {
  if (days == null) return null;
  if (days <= ARCHIVE_RULES.CRITICAL_DAYS) return "danger";
  if (days <= ARCHIVE_RULES.WARN_DAYS)     return "warn";
  return "info";
};

Object.assign(window, {
  USERS, CURRENT_ADMIN, setCurrentUser,
  SERVICE_TYPES, SERVICE_TYPE_CATALOG, serviceTypeByName, serviceTypeByCode,
  CATEGORY_INFO, RISK_LEVELS, RISK_INFO, TEMPLATE_INFO,
  ENTITIES_SEED, PROJECTS_SEED, ACCESS_REQUESTS_SEED, ARCHIVE_ACCESS_SEED, ARCHIVE_ACCESS_SCOPES,
  TEMPLATES, TEMPLATE_PREVIEW, ENTITY_HISTORY, PROJECT_TIMELINE,
  PROJECT_STRUCTURE, WPIDS_2200, DEFAULT_WPIDS_BY_FOLDER, WP2202_VERSIONS, DEFAULT_VERSIONS_BY_WPID,
  SIGN_CHAIN_2202, SIGN_CHAINS_2200, REVIEW_NOTES_2202, REVIEW_SHEETS_2202,
  WPID_SEEDS_BY_PROJECT, CHAIN_SEEDS_BY_PROJECT,
  PROJECT_TEAM, PROJECT_META,
  RECYCLE_BIN, SAMPLE_BY_TYPE,
  userById, entityById, projectById, templateById, projectsByEntity,
  isAwaitingActivation, isWebEditable, lockInfo, WEB_EDITABLE_TYPES,
  WPID_STATUS_META, WPID_STATUS_KEYS,
  POST_ARCHIVE_TRANSACTIONS, POST_ARCHIVE_TYPES,
  ARCHIVE_EXTENSIONS, ARCHIVE_RULES,
  DEMO_TODAY, daysToAutoArchive, archiveTone,
  RECENT_FILES_SEED, HOME_TODO_SEED, HOME_ACTIONS,
  DEFAULT_REVIEWER_SLOTS, ENTITY_DESC_MAX,
  projectStorageMB, entityStorageMB, fmtMB,
});
