// Mock data for the Opsmera app (illustrative; AU strata/property/maintenance).
// Copy follows the deck voice: declarative, precise, hyphens (never em dashes).

// Compliance deadlines, ranked by days-to-deadline (the wedge).
// Each carries an AI suggestion grounded in this site's history (do / basis / action).
const DEADLINES = [
  { days: -3, lvl: 'urgent', asset: 'Emergency lighting', bldg: 'Adelaide Central', meas: 'AS 2293 routine', exposure: '$4,000/wk', pct: 30,
    ai: { do: 'Dispatch Sparke today and attach the AS 2293 certificate to clear the treasurer\'s hold.',
      basis: 'Sparke cleared 4 lighting jobs here in avg 1.8 days; the treasurer has approved every one once the cert was attached.',
      action: 'Dispatch + attach cert' } },
  { days: 2, lvl: 'urgent', asset: 'Fire panel & detection', bldg: 'Harbourview', meas: 'AS 1851 monthly', exposure: '$2,500/wk', pct: 62,
    ai: { do: 'Book ASE Fire now - they need ~3 days to certify before the routine date.',
      basis: 'ASE averaged 3.2 days to attend across the last 6 jobs, and this routine has run a day late twice.',
      action: 'Book ASE Fire' } },
  { days: 6, lvl: 'warning', asset: 'AFSS annual statement', bldg: 'The Lumen', meas: 'Council lodgement', exposure: '$1,800/wk', pct: 80,
    ai: { do: 'Generate the AFSS pack now and pre-fill the council lodgement - all routines are current.',
      basis: 'Lodgement took 2 days on average last year; leaving it under 5 days has slipped twice.',
      action: 'Generate pack' } },
  { days: 12, lvl: 'warning', asset: 'Hydrant & booster', bldg: 'Cove Apartments', meas: 'AS 1851 yearly', exposure: '$900/wk', pct: 88,
    ai: { do: 'Bundle this with the Level 7 HVAC visit - the same vendor is on site Tuesday.',
      basis: 'Bundling Cove jobs with a scheduled visit saved about $220 in call-out fees on 3 prior occasions.',
      action: 'Add to Tue visit' } },
  { days: 28, lvl: 'ok', asset: 'Sprinkler system', bldg: 'Parkside Gardens', meas: 'AS 1851 six-monthly', exposure: 'On track', pct: 96,
    ai: { do: 'Nothing needed - auto-scheduled with ASE Fire and tracking on time.',
      basis: 'Parkside has not missed a routine in 24 months.',
      action: null } },
];

// Omni-channel intake (one inbox for every channel) -> AI triaged.
const INTAKE = [
  { id: 'OPS-4821', chan: 'radio', channel: 'IoT panel', bldg: 'Harbourview - 14 Quay St, Sydney',
    summ: 'Fire panel fault - Block B basement, isolation alarm triggered overnight.',
    prio: 'p1', status: 'urgent', statusLabel: 'Deadline 2d', time: '8m', ai: 'AS 1851 critical defect',
    aiSummary: 'Classified as a critical AS 1851 fire-safety defect. Panel reporting an earth fault on loop 2. Recommend immediate ASE dispatch - the monthly routine is due in 2 days and this blocks the audit trail.',
    kv: { Reporter: 'Building manager', Channel: 'IoT panel', Category: 'Fire safety', Lodged: 'Today, 02:14' },
    rec: { do: 'Dispatch ASE Fire as P1 now and notify the committee chair.', basis: 'Earth faults on this panel recurred twice in 18 months - both needed a loop replacement, avg fix 1 day.', action: 'Dispatch ASE Fire' },
    story: {
      started: "At 2:14am the fire panel in Block B basement said something was wrong with one of its wires (an earth fault on loop 2). The alarm called the building manager.",
      sofar:   "We logged it, classified it as a serious fire-safety fault, and lined up the fire contractor (ASE) to fix it. The chair has been told.",
      next:    "Get ASE on site to fix the loop and give us the certificate, so the monthly fire-safety check stays compliant.",
      by:      "In 2 days - Fri 6 Jun"
    },
    flow: [['done','check','Logged & classified','AI triage - 02:14'],['active','user-round-plus','Awaiting dispatch','Suggested: ASE Fire'],['todo','wrench','On-site remediation',''],['todo','file-check','Evidence & sign-off','']] },
  { id: 'OPS-4820', chan: 'mic', channel: 'Voice (field)', bldg: 'The Lumen - 88 Latrobe St, Melbourne',
    summ: 'Water ingress in Unit 1203 ceiling after the roof works. Logged by voice on site.',
    prio: 'p2', status: 'warning', statusLabel: 'Quoting', time: '41m', ai: 'Maintenance - plumbing',
    aiSummary: 'Voice-captured on site by the building manager with two photos attached. Likely linked to last week\'s roof membrane job (Apex Roofing). Recommend re-inspection under warranty before a new work order. Two prior ingress reports in this stack.',
    kv: { Reporter: 'Building manager', Channel: 'Voice - field', Category: 'Maintenance', Lodged: 'Today, 01:41' },
    rec: { do: 'Book the warranty re-inspection with Apex before raising a paid work order.', basis: '2 prior ingress reports here traced to the same roof job - warranty covered both, saving ~$1,400.', action: 'Book warranty re-inspect' },
    story: {
      started: "The building manager stood under a leaking ceiling in Unit 1203 and recorded what they saw plus two photos, straight into Opsmera.",
      sofar:   "We linked it to the recent roof works - same spot, same roofer (Apex). Two earlier leaks here were the roofer's fault and covered by warranty.",
      next:    "Get Apex back to inspect under warranty before we spend any money on a paid repair.",
      by:      "In 2 days - Fri 6 Jun"
    },
    flow: [['done','check','Logged by voice','Field - 01:41'],['done','image','2 photos attached','On site'],['active','search','Linking to warranty','Apex Roofing'],['todo','calendar','Schedule re-inspection','']] },
  { id: 'OPS-4817', chan: 'mail', channel: 'Email', bldg: 'Parkside Gardens - 5 Edward St, Brisbane',
    summ: 'Owner objection to the special levy - requests committee review before the AGM.',
    prio: 'p3', status: 'info', statusLabel: 'With committee', time: '2h', ai: 'Strata - levies',
    aiSummary: 'Routed to the strata workflow. Drafted an acknowledgement and added the item to the next committee agenda, pre-AGM. No compliance impact. Owner ledger attached for the approver.',
    kv: { Reporter: 'Owner - Lot 22', Channel: 'Email', Category: 'Strata', Lodged: 'Today, 00:09' },
    rec: { do: 'Table it at the committee meeting with the owner ledger attached.', basis: 'Similar levy objections resolved at committee in 80% of cases here without escalation.', action: 'Add to agenda' },
    story: {
      started: "The owner of Lot 22 emailed in to say they don't agree with the new special levy and want the committee to look at it before the AGM.",
      sofar:   "We sent them a polite 'we hear you' reply automatically and added their objection to the next committee agenda. Their account history is attached for the committee to read.",
      next:    "Discuss it at the committee meeting and let the owner know the outcome. No fire-safety or compliance impact.",
      by:      "At the next committee - Wed 11 Jun (pre-AGM)"
    },
    flow: [['done','check','Logged & classified','AI triage - 00:09'],['done','file-pen','Acknowledgement sent','Auto - 00:10'],['active','users','On committee agenda','Pre-AGM'],['todo','gavel','Committee decision','']] },
  { id: 'OPS-4815', chan: 'message-square', channel: 'SMS', bldg: 'Cove Apartments - 2 Marine Pde, Gold Coast',
    summ: 'Tenant reports lift out of service on Level 7. Second report this week.',
    prio: 'p2', status: 'warning', statusLabel: 'Dispatching', time: '3h', ai: 'Maintenance - lifts',
    aiSummary: 'Matched to an open ticket from Tuesday - same asset, same fault code. Merged to avoid a duplicate. Recommend escalating to the lift contractor with priority response; tenant has been sent an automatic status update.',
    kv: { Reporter: 'Tenant - Unit 704', Channel: 'SMS', Category: 'Maintenance', Lodged: 'Today, 21:30' },
    rec: { do: 'Escalate to Otis with priority and flag for a controller inspection.', basis: 'This lift logged 3 faults this quarter - the pattern matches the controller board that failed at Cove last year.', action: 'Escalate to Otis' },
    story: {
      started: "A tenant in Unit 704 texted to say the lift to Level 7 is broken again - second time this week.",
      sofar:   "We found it's the same fault as Tuesday's ticket (same lift, same code), so we merged them into one. The tenant got an automatic update.",
      next:    "Get Otis on site as priority, ask them to look at the controller board (we think that's the cause), then sign it off.",
      by:      "In 1 day - Thu 5 Jun"
    },
    flow: [['done','check','Logged & classified','AI triage'],['done','git-merge','Merged duplicate','Tue ticket'],['active','hard-hat','Contractor dispatched','Otis'],['todo','file-check','Sign-off & close','']] },
  { id: 'OPS-4812', chan: 'phone', channel: 'Phone', bldg: 'Stirling House - 19 Hay St, Perth',
    summ: 'AFSS annual statement signed off and lodged with council.',
    prio: 'p3', status: 'resolved', statusLabel: 'Closed', time: '5h', ai: 'Compliance - AFSS',
    aiSummary: 'Annual Fire Safety Statement completed and lodged. All AS 1851 routine schedules current. Certificate stored against the building record; the next AFSS is auto-scheduled and the compliant hardcopy logbook pack has been generated.',
    kv: { Reporter: 'Compliance team', Channel: 'Phone', Category: 'Compliance', Lodged: 'Yesterday' },
    rec: { do: 'Nothing needed - closed and the logbook pack is filed.', basis: 'Next AFSS auto-scheduled; Stirling has a clean 24-month record.', action: null },
    story: {
      started: "Stirling House's yearly fire-safety statement (the AFSS) was due to be sent to council.",
      sofar:   "All the routine checks were done and current, so the statement was signed and lodged with council. The full logbook pack is filed against the building.",
      next:    "Nothing - this one's closed. Next year's AFSS is already on the calendar.",
      by:      null
    },
    flow: [['done','check','Logged & classified','AI triage'],['done','clipboard-check','Routines verified','AS 1851'],['done','file-check','AFSS lodged','Council'],['done','printer','Logbook printed','Hardcopy']],
    resolved: true,
    closedAt: 'Yesterday, 16:42',
    closedBy: 'Jessica Young',
    durationDays: 3,
    slaMet: true,
    vendor: 'ASE Fire (routine checks) · Council lodgement (internal)',
    invoiceId: null,
    amount: null,
    before: { glyph: 'clipboard-list', caption: 'BEFORE - AFSS due in 14 days, 6 routine checks outstanding.', tone: 'risk' },
    after:  { glyph: 'shield-check',   caption: 'AFTER - statement lodged with council, logbook pack filed.', tone: 'ok' },
    workSummary: "All six outstanding AS 1851 routine checks were completed and verified. The Annual Fire Safety Statement was generated from the audit trail, signed by the responsible person, and lodged with Perth City Council. The compliant hardcopy logbook pack was printed and filed against the building record.",
    log: [
      ['phone',           'Compliance team raised AFSS lodgement task',     'Mon 1 Jun, 09:14'],
      ['clipboard-check', 'AS 1851 routine batch verified (6 of 6)',         'Tue 2 Jun, 14:30'],
      ['file-pen',        'AFSS draft generated from audit trail',           'Tue 2 Jun, 15:10'],
      ['check-check',     'Statement signed by responsible person',          'Wed 3 Jun, 11:25'],
      ['send',            'Lodged with Perth City Council (#AFSS-25-1188)',  'Yesterday, 16:30'],
      ['printer',         'Logbook hardcopy printed & filed',                'Yesterday, 16:42'],
    ],
    compliance: { kept: 'AFSS · AS 1851', nextDue: 'AFSS next year (auto-scheduled)' },
    evidence: ['Council lodgement receipt', 'Signed AFSS statement (PDF)', 'AS 1851 routine sign-offs (6)', 'Logbook hardcopy index'],
    shareTargets: ['Owners (118)', 'Committee (5)', 'Perth City Council', 'Insurance broker'],
  },
  // -- Resolved (with invoice + before/after photos) ------------------------
  { id: 'OPS-4798', chan: 'message-square', channel: 'SMS', bldg: 'Cove Apartments - 2 Marine Pde, Gold Coast',
    summ: 'Level 7 lift controller board failed - replaced and re-tested.',
    prio: 'p2', status: 'resolved', statusLabel: 'Closed', time: '4d', ai: 'Maintenance - Lifts',
    aiSummary: 'Controller board replaced under Otis service contract. Safety re-test passed (cert OT-72881). Residents on Levels 6-10 notified before, during, and after. Three duplicate tickets auto-merged.',
    kv: { Reporter: 'Resident - Unit 704', Channel: 'SMS', Category: 'Maintenance', Lodged: '4 days ago' },
    rec: { do: 'Closed. Next preventive service in 5 months.', basis: 'Otis controller boards have a 24-month MTBF on this model; next service is auto-scheduled.', action: null },
    story: {
      started: "A resident in Unit 704 texted to say the lift to Level 7 kept stopping. Two more residents reported the same thing within the hour.",
      sofar:   "We merged the duplicates into one ticket and escalated to Otis. Their tech replaced the controller board and re-ran the safety test. Residents got an automatic 'back in service' notice.",
      next:    "Nothing - this one's closed. The new board is under warranty for 24 months.",
      by:      null
    },
    flow: [
      ['done','check','Logged & classified','AI triage'],
      ['done','git-merge','3 duplicates merged','Auto'],
      ['done','hard-hat','Otis dispatched','Same day'],
      ['done','wrench','Controller board replaced','On site'],
      ['done','file-check','Safety re-test passed','Cert OT-72881'],
      ['done','send','Residents notified back in service','Yesterday'],
    ],
    resolved: true,
    closedAt: 'Yesterday, 16:10',
    closedBy: 'David Johnson',
    durationDays: 4,
    slaMet: true,
    vendor: 'Otis (controller board) · Cove on-site team (re-test sign-off)',
    invoiceId: 'INV-20415',
    amount: '$3,400',
    before: { glyph: 'alert-octagon',   caption: 'BEFORE - lift dead on Level 7, fault on controller board.', tone: 'breach' },
    after:  { glyph: 'circle-check-big', caption: 'AFTER - new board installed, safety re-test passed.',       tone: 'ok' },
    workSummary: "Otis dispatched on the same day. The faulty controller board on the Level 7 lift was diagnosed as a relay failure and replaced with a new Series-3 board. A full safety re-test was performed and passed (certificate OT-72881). All 64 affected residents received automatic 'back in service' notifications, and the new board is covered under a 24-month warranty.",
    log: [
      ['message-square', 'Resident SMS - Unit 704 reports lift fault',   'Mon 1 Jun, 09:18'],
      ['sparkles',        'AI triage: P2 Maintenance · Lifts',             'Mon 1 Jun, 09:18'],
      ['git-merge',       'Auto-merged 2 more reports from Levels 6 & 8', 'Mon 1 Jun, 10:02'],
      ['user-round-plus', 'Dispatched to Otis (preferred vendor)',          'Mon 1 Jun, 10:14'],
      ['hard-hat',        'Otis tech on site, diagnosed controller board', 'Mon 1 Jun, 14:30'],
      ['wrench',          'Controller board replaced',                    'Mon 1 Jun, 16:45'],
      ['file-check',      'Safety re-test passed (cert OT-72881)',        'Tue 2 Jun, 09:20'],
      ['send',            'Residents notified - back in service',         'Yesterday, 16:10'],
      ['banknote',        'Invoice INV-1024 raised - $3,400',             'Yesterday, 16:15'],
    ],
    compliance: { kept: 'Lift safety - WA Lift Regs', nextDue: 'Preventive service in 5 months' },
    evidence: ['Safety re-test certificate OT-72881', '4 site photos', 'Resident comms log (3 broadcasts)', 'Otis service report'],
    shareTargets: ['Affected residents (64)', 'Committee chair', 'Insurer', 'Cove building manager'],
  },

  { id: 'OPS-4790', chan: 'mail', channel: 'Email', bldg: 'Parkside Gardens - 5 Edward St, Brisbane',
    summ: 'By-law breach - illegal parking in visitor bays, resolved at committee.',
    prio: 'p3', status: 'resolved', statusLabel: 'Closed', time: '6d', ai: 'Strata - By-laws',
    aiSummary: 'Owner of Lot 14 was reminded of by-law 7.3 (visitor parking), the breach was acknowledged, and a parking permit was issued for the spouse so it won\'t recur. No fines, no formal NOI. Pattern logged.',
    kv: { Reporter: 'Resident - Lot 22', Channel: 'Email', Category: 'Strata', Lodged: '6 days ago' },
    rec: { do: 'Closed informally. Pattern logged for future reference.', basis: 'First-time breaches resolved informally have a 92% non-recurrence rate at Parkside.', action: null },
    story: {
      started: "A resident emailed to say someone had been parking in the visitor bays every night for a week.",
      sofar:   "We worked out it was Lot 14's spouse using the bays as overflow. The strata manager wrote to Lot 14, they apologised, and a visitor permit was issued.",
      next:    "Nothing - this one's closed informally. No fines, no formal notice.",
      by:      null
    },
    flow: [
      ['done','check','Logged & classified','AI triage'],
      ['done','file-pen','Owner letter drafted','Auto'],
      ['done','users','Sent to Lot 14','3 days ago'],
      ['done','check-check','Acknowledged & permit issued','Yesterday'],
    ],
    resolved: true,
    closedAt: 'Yesterday, 11:25',
    closedBy: 'Jessica Young',
    durationDays: 6,
    slaMet: true,
    vendor: null,
    invoiceId: null,
    amount: null,
    before: { glyph: 'circle-alert', caption: 'BEFORE - repeated by-law 7.3 breaches in visitor bays.', tone: 'risk' },
    after:  { glyph: 'handshake',    caption: 'AFTER - permit issued, acknowledged, no recurrence.',   tone: 'ok' },
    workSummary: "The complaint was correlated with security footage and CCTV plate scans to identify Lot 14's spouse as the parker. A polite by-law reminder letter (referencing 7.3) was drafted by AI, reviewed by the strata manager, and sent. Lot 14 acknowledged and a visitor parking permit was issued under by-law 7.5 to handle the genuine need. No fines, no formal notice of intent.",
    log: [
      ['mail',       'Resident email - Lot 22 reports parking breach',    'Wed 27 May, 19:40'],
      ['sparkles',   'AI triage: P3 Strata · By-laws',                    'Wed 27 May, 19:40'],
      ['search',     'CCTV correlated with Lot 14 vehicle',                'Thu 28 May, 10:15'],
      ['file-pen',   'AI drafted by-law reminder letter',                   'Thu 28 May, 10:30'],
      ['user-check', 'Strata manager reviewed and sent',                    'Thu 28 May, 11:00'],
      ['check-check','Lot 14 acknowledged, requested permit',                '2 days ago, 14:20'],
      ['file-pen',   'Visitor permit issued under by-law 7.5',                'Yesterday, 11:25'],
    ],
    compliance: { kept: 'By-laws audit trail', nextDue: null },
    evidence: ['Reminder letter sent', 'Acknowledgement email', 'Visitor permit (PDF)', 'CCTV correlation log'],
    shareTargets: ['Lot 14 (resolved party)', 'Lot 22 (reporter)', 'Committee minutes pack'],
  },

  { id: 'OPS-4785', chan: 'mic', channel: 'Voice (field)', bldg: 'Adelaide Central - 40 King William St, Adelaide',
    summ: 'Emergency lighting on Stair B failed routine test - 4 luminaires replaced.',
    prio: 'p2', status: 'resolved', statusLabel: 'Closed', time: '8d', ai: 'Maintenance - AS 2293',
    aiSummary: "Routine 6-monthly AS 2293 test surfaced 4 failed luminaires on Stair B. Spark electrical replaced all four and re-tested. Cert AS-22-3308 stored against the building. Adelaide Central's emergency-lighting compliance is back to 100%.",
    kv: { Reporter: 'Field tech - on routine test', Channel: 'Voice (field)', Category: 'Maintenance', Lodged: '8 days ago' },
    rec: { do: 'Closed. Next AS 2293 6-monthly test scheduled.', basis: 'Stair B has had 2 lumen failures in 18 months - flagged for ageing-fixture replacement program.', action: null },
    story: {
      started: "Cameron was doing the routine emergency-lighting test (the legally required 6-monthly one) on Stair B at Adelaide Central. Four of the lights failed.",
      sofar:   "Cameron logged the failures by voice on the spot. Spark electrical were dispatched the next morning, replaced all 4 luminaires, and re-tested the stair. The compliance certificate is now stored against the building.",
      next:    "Nothing - this one's closed. Next 6-monthly test is already scheduled.",
      by:      null
    },
    flow: [
      ['done','mic','Logged by voice on site','Field app'],
      ['done','sparkles','AI triage + work order drafted','Auto'],
      ['done','user-round-plus','Spark electrical dispatched','Next morning'],
      ['done','wrench','4 luminaires replaced','On site'],
      ['done','file-check','AS 2293 re-test passed','Cert AS-22-3308'],
    ],
    resolved: true,
    closedAt: '2 days ago, 15:55',
    closedBy: 'Cameron Smith',
    durationDays: 6,
    slaMet: true,
    vendor: 'Spark Electrical',
    invoiceId: 'INV-20412',
    amount: '$1,180',
    before: { glyph: 'lightbulb-off', caption: 'BEFORE - 4 of 18 luminaires failed Stair B routine.', tone: 'breach' },
    after:  { glyph: 'lightbulb',     caption: 'AFTER - all replaced, AS 2293 re-test passed.',       tone: 'ok' },
    workSummary: "During the scheduled 6-monthly AS 2293 routine, 4 luminaires on Stair B failed the discharge test (battery end-of-life on 3, lamp failure on 1). Spark Electrical attended the next morning, replaced all four units like-for-like, and the full Stair B test was re-run and passed. The certificate (AS-22-3308) is stored against the building. Adelaide Central's emergency lighting compliance is back to 100%.",
    log: [
      ['mic',             'Cameron voice-logged 4 failed luminaires on Stair B', 'Sun 24 May, 13:42'],
      ['sparkles',        'AI triage + work order draft',                    'Sun 24 May, 13:43'],
      ['user-round-plus', 'Dispatched Spark Electrical (preferred)',          'Sun 24 May, 14:10'],
      ['hard-hat',        'Spark on site',                                   'Mon 25 May, 08:30'],
      ['wrench',          'Replaced 4 luminaires (3 batteries, 1 lamp)',      'Mon 25 May, 11:15'],
      ['file-check',      'AS 2293 re-test passed (cert AS-22-3308)',         'Mon 25 May, 12:40'],
      ['banknote',        'Invoice INV-1019 raised - $1,180',                '2 days ago, 15:55'],
    ],
    compliance: { kept: 'AS 2293 emergency lighting', nextDue: 'Next 6-monthly test in 5 months' },
    evidence: ['AS 2293 re-test certificate AS-22-3308', '8 site photos (before/after each fixture)', 'Spark service docket', 'Battery disposal record'],
    shareTargets: ['Committee chair', 'Adelaide building manager', 'Insurance broker', 'Compliance file'],
  },
];

// Live job board: intake -> quoting -> approved -> scheduled -> on site -> sign-off.
const BOARD = [
  { key: 'intake', name: 'Intake', dot: '#5B9BF0', total: 14, jobs: [
    { t: 'Carpark roller door jammed', bldg: 'Harbourview', ven: null, amt: null, age: 'New' },
    { t: 'Graffiti on north stairwell', bldg: 'Adelaide Central', ven: null, amt: null, age: '1h' },
  ]},
  { key: 'quoting', name: 'Quoting', dot: '#E8B23E', total: 9, jobs: [
    { t: 'Water ingress - Unit 1203 ceiling', bldg: 'The Lumen', ven: 'Apex', amt: 'Pending', age: '41m' },
    { t: 'HVAC condenser running hot - L7', bldg: 'Cove Apartments', ven: 'Cool-Air', amt: '$1,840', age: '3h', stall: true,
      ai: { do: 'Chase Cool-Air for the revised quote, then approve - the unit is trending to fail in summer.', basis: 'Quotes that stall past 24h here slip the job by ~6 days on average.', action: 'Chase quote' } },
  ]},
  { key: 'approved', name: 'Approved', dot: '#9B8CF0', total: 6, jobs: [
    { t: 'Fire panel earth fault - Block B', bldg: 'Harbourview', ven: 'ASE Fire', amt: '$2,200', age: 'Today' },
  ]},
  { key: 'scheduled', name: 'Scheduled', dot: '#5B9BF0', total: 11, jobs: [
    { t: 'Lift fault - Level 7', bldg: 'Cove Apartments', ven: 'Otis', amt: '$3,400', age: 'Tue 9am' },
    { t: 'Emergency lighting replace', bldg: 'Adelaide Central', ven: 'Sparke', amt: '$760', age: 'Wed' },
  ]},
  { key: 'onsite', name: 'On site', dot: '#33D499', total: 4, jobs: [
    { t: 'Hydrant block test', bldg: 'Cove Apartments', ven: 'ASE Fire', amt: '$900', age: 'Now' },
  ]},
  { key: 'signoff', name: 'Sign-off', dot: '#33D499', total: 21, jobs: [
    { t: 'AFSS routine - sprinkler', bldg: 'Parkside Gardens', ven: 'ASE Fire', amt: '$1,200', age: 'Done' },
    { t: 'Stairwell lighting fix', bldg: 'Stirling House', ven: 'Sparke', amt: '$340', age: 'Done' },
  ]},
];

const BUILDINGS = [
  { nm: 'Harbourview', sp: 'SP 84021', addr: '14 Quay St, Sydney NSW', units: 142, open: 7, compliance: 88, health: 'warning', next: 'AS 1851 monthly in 2 days' },
  { nm: 'Adelaide Central', sp: 'SP 21746', addr: '40 King William St, Adelaide SA', units: 120, open: 9, compliance: 79, health: 'urgent', next: 'Emergency lighting 3 days overdue' },
  { nm: 'The Lumen', sp: 'SP 67203', addr: '88 Latrobe St, Melbourne VIC', units: 210, open: 3, compliance: 96, health: 'resolved', next: 'AFSS lodgement in 6 days' },
  { nm: 'Cove Apartments', sp: 'SP 39512', addr: '2 Marine Pde, Gold Coast QLD', units: 64, open: 5, compliance: 91, health: 'warning', next: 'Hydrant yearly in 12 days' },
  { nm: 'Parkside Gardens', sp: 'SP 55180', addr: '5 Edward St, Brisbane QLD', units: 96, open: 2, compliance: 99, health: 'resolved', next: 'Sprinkler routine in 28 days' },
  { nm: 'Stirling House', sp: 'SP 12894', addr: '19 Hay St, Perth WA', units: 78, open: 0, compliance: 100, health: 'resolved', next: 'All routines current' },
];

const BLDG_TIMELINE = [
  ['mint', 'AFSS annual statement lodged', 'Today, 09:14 - by compliance team'],
  ['mint', 'Sprinkler routine signed off', 'Yesterday - ASE Fire, evidence attached'],
  ['', 'Committee approved $2,200 panel repair', '2 days ago - 1 tap, logged with timestamp'],
  ['', 'Water ingress logged by voice on site', '3 days ago - building manager, 2 photos'],
  ['', 'Quarterly owner report generated', 'Last week - audit-ready pack'],
];

// Invoice Approval Hub (best-of: StrataMax Invoice Hub / MRI online approval).
// Committee approves / queries / denies online; majority auto-adds to payment run.
const INVOICES = [
  { id: 'INV-20418', creditor: 'ASE Fire Services', bldg: 'Harbourview', cat: 'Fire compliance',
    amount: 2200, gst: 200, age: '2h', status: 'awaiting', need: 2,
    desc: 'Block B fire panel earth-fault repair - loop 2 replacement and re-test (AS 1851).',
    lines: [['Attend & diagnose - Block B panel', 480], ['Loop 2 detector replacement x4', 920], ['Re-test & certificate', 600]],
    approvers: [
      { nm: 'R. Tan', role: 'Chairperson', state: 'approved', when: 'Today 10:02' },
      { nm: 'M. Singh', role: 'Treasurer', state: 'pending', when: null },
      { nm: 'K. Obi', role: 'Secretary', state: 'pending', when: null },
    ],
    thread: [['M. Singh', 'Is this covered under the maintenance contract or extra?', '10:14'],
             ['You', 'Out of scope - panel fault is not on the AS 1851 routine. Quote attached.', '10:21']],
    basis: 'ASE quotes have landed within 3% of the approved figure on 5 prior jobs, and the committee approved similar fire works in under a day twice.' },
  { id: 'INV-20417', creditor: 'Cool-Air Co', bldg: 'Cove Apartments', cat: 'HVAC',
    amount: 1840, gst: 167, age: '3h', status: 'awaiting', need: 2,
    desc: 'Level 7 condenser preventive service - compressor flagged by predictive model.',
    lines: [['Preventive service call-out', 340], ['Compressor capacitor + gas top-up', 1100], ['Report & sensor recalibration', 400]],
    approvers: [
      { nm: 'D. Park', role: 'Chairperson', state: 'approved', when: 'Today 09:40' },
      { nm: 'L. Howe', role: 'Treasurer', state: 'query', when: 'Today 09:55' },
      { nm: 'S. Reed', role: 'Committee', state: 'pending', when: null },
    ],
    thread: [['L. Howe', 'Can we get a second quote before approving this one?', '09:55']],
    basis: 'Cool-Air ran ~8% above the two comparison quotes on the last HVAC job here - worth a second quote before approving.' },
  { id: 'INV-20415', creditor: 'Otis Lifts', bldg: 'Cove Apartments', cat: 'Lifts',
    amount: 3400, gst: 309, age: '5h', status: 'approved', need: 2,
    desc: 'Level 7 lift fault - controller board replacement and safety re-test.',
    lines: [['Emergency call-out', 600], ['Controller board', 2200], ['Safety test & sign-off', 600]],
    approvers: [
      { nm: 'D. Park', role: 'Chairperson', state: 'approved', when: 'Today 08:10' },
      { nm: 'L. Howe', role: 'Treasurer', state: 'approved', when: 'Today 08:32' },
      { nm: 'S. Reed', role: 'Committee', state: 'pending', when: null },
    ],
    thread: [],
    basis: 'Otis is the contracted lift servicer and the controller-board price matches the schedule of rates. Majority already reached.' },
  { id: 'INV-20412', creditor: 'Sparke Electrical', bldg: 'Adelaide Central', cat: 'Electrical',
    amount: 760, gst: 69, age: '1d', status: 'overdue', need: 2,
    desc: 'Emergency lighting replacement - 6 fittings, common area (AS 2293).',
    lines: [['Fittings x6 supply', 360], ['Install & test', 400]],
    approvers: [
      { nm: 'A. Cole', role: 'Chairperson', state: 'approved', when: 'Fri 16:20' },
      { nm: 'J. Frost', role: 'Treasurer', state: 'denied', when: 'Fri 17:01' },
      { nm: 'P. Vale', role: 'Committee', state: 'pending', when: null },
    ],
    thread: [['J. Frost', 'Denied - need the compliance certificate attached first.', 'Fri 17:01']],
    basis: 'The AS 2293 certificate is now on file against this asset - attaching it has cleared the treasurer\'s hold on 3 past invoices.' },
  { id: 'INV-20409', creditor: 'CleanCo Strata', bldg: 'The Lumen', cat: 'Cleaning',
    amount: 1290, gst: 117, age: '1d', status: 'awaiting', need: 2,
    desc: 'Monthly common-area cleaning - foyer, lifts, bin room, car park sweep.',
    lines: [['Monthly contract', 1090], ['Bin room deep clean', 200]],
    approvers: [
      { nm: 'R. Tan', role: 'Chairperson', state: 'pending', when: null },
      { nm: 'M. Singh', role: 'Treasurer', state: 'pending', when: null },
    ],
    thread: [],
    basis: 'Recurring monthly contract - approved within a day every month for the last year at the same figure.' },
];

// Meetings & e-voting (best-of: StrataVote-style motions + electronic voting).
const MEETING = {
  type: 'Annual General Meeting', bldg: 'Harbourview', code: 'SP 84021',
  date: 'Thu 18 June 2026 · 6:00pm', mode: 'Hybrid · on-site + remote',
  quorumHave: 17, quorumNeed: 13, lots: 142,
  motions: [
    { no: '01', title: 'Adopt the FY26 administrative & capital works budget',
      desc: 'That the owners corporation adopt the proposed budget and strike levies accordingly.',
      status: 'carried', forV: 71, against: 12, abstain: 4 },
    { no: '02', title: 'Approve the AS 1851 fire-compliance remediation program',
      desc: 'That the committee proceed with the staged fire-safety works to clear the AFSS by deadline.',
      status: 'open', forV: 38, against: 6, abstain: 2 },
    { no: '03', title: 'Renew building insurance with the recommended insurer',
      desc: 'That the owners corporation accept the recommended renewal quote for FY26.',
      status: 'open', forV: 22, against: 19, abstain: 5 },
    { no: '04', title: 'Appoint the strata committee for the coming year',
      desc: 'That the nominated owners be appointed to the strata committee.',
      status: 'upcoming', forV: 0, against: 0, abstain: 0 },
  ],
};

Object.assign(window, { DEADLINES, INTAKE, BOARD, BUILDINGS, BLDG_TIMELINE, INVOICES, MEETING });

// --- Site labelling helpers -------------------------------------------------
// Best practice for a strata book: ADDRESS leads (everyone knows it); the SP
// (Strata Plan) number is the official unique ID (one address can carry more
// than one scheme - staged/layered SPs - so address alone is not a key).
// Build a lookup keyed by the short name used across the mock data.
const SITE_BY_NAME = {};
BUILDINGS.forEach(b => {
  const short = b.addr.replace(/,?\s+[A-Z]{2,3}$/, ''); // drop trailing state
  const state = (b.addr.match(/[A-Z]{2,3}$/) || [''])[0];
  SITE_BY_NAME[b.nm] = { ...b, short, state };
});
// Resolve a raw bldg field ("Harbourview" or "Harbourview - 14 Quay St, Sydney")
function siteOf(raw) {
  if (!raw) return null;
  const name = raw.split(' - ')[0].trim();
  return SITE_BY_NAME[name] || { nm: name, short: name, sp: '', state: '' };
}
Object.assign(window, { siteOf, SITE_BY_NAME });
