// flows2.jsx — Support workers (pay run) and Plan-review prep
const { useState: uS3, useEffect: uE3 } = React;

// ══════════════════════════════════════════════════════════════════
// SUPPORT WORKERS + PAY RUN
// ══════════════════════════════════════════════════════════════════
function Workers() {
  const S = useHaven();
  const sheets = S.doc.timesheets;
  const [running, setRunning] = uS3(false);
  const [addingTs, setAddingTs] = uS3(false);

  const worker = (id) => S.doc.workers.find((w) => w.id === id) || { rate: 0, name: '(removed worker)', initials: '?' };
  const pending = sheets.filter((s) => s.status === 'pending');
  const pendingTotal = pending.reduce((s, t) => s + t.hours * worker(t.worker).rate, 0);
  const pendingHours = pending.reduce((s, t) => s + t.hours, 0);

  const approve = (id) => S.approveTimesheet(id);
  const approved = sheets.filter((s) => s.status === 'approved');
  const readyTotal = approved.reduce((s, t) => s + t.hours * worker(t.worker).rate, 0);

  return (
    <div className="fade-in">
      <PageHead
        title="Support workers"
        sub={<>The people you employ directly. Approve their hours, run a pay, and Haven keeps the records the ATO and NDIS want.</>}
        right={<Button icon={Icons.card} disabled={approved.length === 0} onClick={() => setRunning(true)} style={{ opacity: approved.length ? 1 : 0.5, pointerEvents: approved.length ? 'auto' : 'none' }}>Run pay {approved.length ? `· ${fmtMoney(readyTotal, 2)}` : ''}</Button>}
      />

      {S.doc.workers.length === 0 && <Note tone="info" icon="people">No support workers yet — add the people you employ in <b>Settings</b> and their timesheets and pay runs will live here.</Note>}

      {/* worker cards */}
      <div style={{ display: 'grid', gridTemplateColumns: 'repeat(auto-fill, minmax(280px,1fr))', gap: 14, marginBottom: 26 }}>
        {S.doc.workers.map((w) => {
          const wh = sheets.filter((s) => s.worker === w.id).reduce((a, s) => a + s.hours, 0);
          return (
            <Card key={w.id} pad={18} hover>
              <div style={{ display: 'flex', gap: 13, alignItems: 'center' }}>
                <Avatar initials={w.initials} size={48} />
                <div style={{ flex: 1 }}>
                  <div style={{ fontSize: 16, fontWeight: 700 }}>{w.name}</div>
                  <div style={{ fontSize: 13, color: 'var(--ink-2)' }}>{w.role} · ${w.rate.toFixed(2)}/hr</div>
                </div>
              </div>
              <div style={{ display: 'flex', gap: 18, marginTop: 15, paddingTop: 14, borderTop: '1px solid var(--line)', fontSize: 13 }}>
                <div><div style={{ fontSize: 18, fontWeight: 700 }}>{wh}h</div><div style={{ color: 'var(--ink-3)' }}>this plan period</div></div>
                <div><div style={{ fontSize: 18, fontWeight: 700 }}>{fmtMoney(wh * w.rate)}</div><div style={{ color: 'var(--ink-3)' }}>paid + pending</div></div>
              </div>
            </Card>
          );
        })}
      </div>

      {/* timesheets to approve */}
      <SectionTitle sub="Tick these off, then run one pay for everything approved."
        action={<Button size="sm" variant="white" icon={Icons.plus} disabled={!S.doc.workers.length} onClick={() => setAddingTs(true)} style={{ opacity: S.doc.workers.length ? 1 : 0.5, pointerEvents: S.doc.workers.length ? 'auto' : 'none' }}>Add timesheet</Button>}>
        Timesheets to approve {pending.length > 0 && <span style={{ color: 'var(--amber-ink)' }}>· {pending.length}</span>}
      </SectionTitle>

      {pending.length === 0 && approved.length === 0 && <Note tone="good" icon="checkCircle">All caught up — no timesheets waiting.</Note>}

      <div style={{ display: 'flex', flexDirection: 'column', gap: 10, marginBottom: 24 }}>
        {[...pending, ...approved].map((t) => {
          const w = worker(t.worker);
          const isApproved = t.status === 'approved';
          return (
            <Card key={t.id} pad={16} style={{ display: 'flex', alignItems: 'center', gap: 14, borderColor: isApproved ? 'var(--good)' : 'var(--line)' }}>
              <Avatar initials={w.initials} size={40} bg={isApproved ? 'var(--good-soft)' : 'var(--primary-soft)'} color={isApproved ? 'var(--good)' : 'var(--primary-ink)'} />
              <div style={{ flex: 1, minWidth: 0 }}>
                <div style={{ fontSize: 14.5, fontWeight: 600 }}>{w.name} · {t.hours}h</div>
                <div style={{ fontSize: 13, color: 'var(--ink-2)' }}>{t.note}</div>
                <div style={{ fontSize: 12, color: 'var(--ink-3)' }}>{fmtDate(t.date)}</div>
              </div>
              <div style={{ fontSize: 16, fontWeight: 700, fontVariantNumeric: 'tabular-nums' }}>{fmtMoney(t.hours * w.rate, 2)}</div>
              {isApproved
                ? <Pill color="var(--good)" bg="var(--good-soft)"><Icons.check size={13} />Approved</Pill>
                : <Button size="sm" variant="soft" icon={Icons.check} onClick={() => approve(t.id)}>Approve</Button>}
            </Card>
          );
        })}
      </div>

      {/* paid history */}
      {sheets.some((s) => s.status === 'paid') && (
        <>
          <SectionTitle>Recently paid</SectionTitle>
          <Card pad={8}>
            {sheets.filter((s) => s.status === 'paid').map((t, i, arr) => {
              const w = worker(t.worker);
              return (
                <div key={t.id} style={{ display: 'flex', alignItems: 'center', gap: 13, padding: '12px 13px', borderBottom: i < arr.length - 1 ? '1px solid var(--line)' : 'none' }}>
                  <Avatar initials={w.initials} size={34} bg="var(--surface-2)" color="var(--ink-2)" />
                  <div style={{ flex: 1 }}><div style={{ fontSize: 14, fontWeight: 600 }}>{w.name} · {t.hours}h</div><div style={{ fontSize: 12, color: 'var(--ink-3)' }}>{fmtDate(t.date)} · {t.note}</div></div>
                  <span style={{ fontSize: 14, fontWeight: 600 }}>{fmtMoney(t.hours * w.rate, 2)}</span>
                  <StatusPill status="paid" />
                </div>
              );
            })}
          </Card>
        </>
      )}

      <PayRun open={running} sheets={approved} worker={worker} total={readyTotal} onClose={() => setRunning(false)} onDone={() => S.payApproved()} />
      <AddTimesheet open={addingTs} workers={S.doc.workers} onClose={() => setAddingTs(false)} onDone={(f) => { S.addTimesheet(f); setAddingTs(false); }} />
    </div>
  );
}

// ── add a timesheet ──
function AddTimesheet({ open, onClose, onDone, workers }) {
  const blankTs = { worker: '', date: '', hours: '', note: '' };
  const [f, setF] = uS3(blankTs);
  uE3(() => { if (open) setF({ worker: (workers[0] || {}).id || '', date: TODAY.toISOString().slice(0, 10), hours: '', note: '' }); }, [open]);
  const set = (k, v) => setF((x) => ({ ...x, [k]: v }));
  const inputStyle = { width: '100%', padding: '11px 13px', fontSize: 14.5, fontFamily: 'var(--sans)', border: '1px solid var(--line-2)', borderRadius: 11, background: 'var(--surface)', color: 'var(--ink)', outline: 'none', boxSizing: 'border-box' };
  const labelStyle = { fontSize: 13, fontWeight: 600, color: 'var(--ink-2)', marginBottom: 6, display: 'block' };
  const w = workers.find((x) => x.id === f.worker);
  const amt = (parseFloat(f.hours) || 0) * ((w || {}).rate || 0);
  const canSave = f.worker && parseFloat(f.hours) > 0;
  return (
    <Modal open={open} onClose={onClose} width={480} title="Add a timesheet" sub="You'll approve it before any pay run.">
      <div style={{ display: 'flex', flexDirection: 'column', gap: 14 }}>
        <div>
          <label style={labelStyle}>Who worked?</label>
          <select style={inputStyle} value={f.worker} onChange={(e) => set('worker', e.target.value)}>
            {workers.map((x) => <option key={x.id} value={x.id}>{x.name}</option>)}
          </select>
        </div>
        <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 14 }}>
          <div><label style={labelStyle}>Date</label><input type="date" style={inputStyle} value={f.date} onChange={(e) => set('date', e.target.value)} /></div>
          <div><label style={labelStyle}>Hours</label><input type="number" step="0.25" placeholder="e.g. 3" style={inputStyle} value={f.hours} onChange={(e) => set('hours', e.target.value)} /></div>
        </div>
        <div><label style={labelStyle}>What was the support? (optional)</label><input placeholder="e.g. Saturday community access — swimming" style={inputStyle} value={f.note} onChange={(e) => set('note', e.target.value)} /></div>
        {w && parseFloat(f.hours) > 0 && <Note tone="info" icon="info">{f.hours}h × ${w.rate.toFixed(2)} = <b>{fmtMoney(amt, 2)}</b></Note>}
        <div style={{ display: 'flex', justifyContent: 'flex-end', gap: 10 }}>
          <Button variant="ghost" onClick={onClose}>Cancel</Button>
          <Button icon={Icons.check} disabled={!canSave} onClick={() => onDone(f)} style={{ opacity: canSave ? 1 : 0.5, pointerEvents: canSave ? 'auto' : 'none' }}>Save timesheet</Button>
        </div>
      </div>
    </Modal>
  );
}

function PayRun({ open, onClose, onDone, sheets, worker, total }) {
  const [done, setDone] = uS3(false);
  uE3(() => { if (open) setDone(false); }, [open]);
  const tax = total * 0.18; // rough PAYG illustration
  const superAmt = total * 0.12;

  return (
    <Modal open={open} onClose={onClose} width={520} title={done ? null : 'Run pay'} sub={done ? null : 'One payment for everything approved.'}>
      {!done ? (
        <div style={{ display: 'flex', flexDirection: 'column', gap: 16 }}>
          <Card pad={16} style={{ background: 'var(--surface-2)', border: 'none' }}>
            {sheets.map((t) => { const w = worker(t.worker); return (
              <div key={t.id} style={{ display: 'flex', justifyContent: 'space-between', padding: '7px 0', fontSize: 14, borderBottom: '1px solid var(--line)' }}>
                <span>{w.name} · {t.hours}h × ${w.rate.toFixed(2)}</span><span style={{ fontWeight: 600 }}>{fmtMoney(t.hours * w.rate, 2)}</span>
              </div>
            ); })}
            <div style={{ display: 'flex', justifyContent: 'space-between', paddingTop: 11, fontSize: 17 }}>
              <span style={{ fontWeight: 600 }}>Gross pay</span><span style={{ fontWeight: 700, color: 'var(--primary)' }}>{fmtMoney(total, 2)}</span>
            </div>
          </Card>
          <Note tone="info" icon="info">
            As an employer, set aside roughly <b>PAYG tax (~{fmtMoney(tax, 0)})</b> and <b>super (~{fmtMoney(superAmt, 0)})</b> — rough guides only, not real tax tables. Haven records the pay against your budget; payslips and Single Touch Payroll still happen in your payroll software.
          </Note>
          <div style={{ display: 'flex', justifyContent: 'flex-end', gap: 10 }}>
            <Button variant="ghost" onClick={onClose}>Not yet</Button>
            <Button icon={Icons.card} onClick={() => { onDone(); setDone(true); }}>Pay {fmtMoney(total, 2)}</Button>
          </div>
        </div>
      ) : (
        <div style={{ textAlign: 'center', padding: '14px 10px 6px' }}>
          <div style={{ width: 78, height: 78, borderRadius: '50%', background: 'var(--good-soft)', color: 'var(--good)', display: 'grid', placeItems: 'center', margin: '0 auto 18px', animation: 'pop .4s ease both' }}><Icons.check size={42} stroke={2.4} /></div>
          <h3 style={{ margin: '0 0 8px', fontFamily: 'var(--serif)', fontWeight: 500, fontSize: 25 }}>Pay run done</h3>
          <p style={{ margin: '0 auto 22px', color: 'var(--ink-2)', fontSize: 14.5, maxWidth: 360, lineHeight: 1.5 }}>Pay recorded — the hours and amount have come off your Core budget. Remember payslips and Single Touch Payroll in your payroll software.</p>
          <Button onClick={onClose} full>Back to workers</Button>
        </div>
      )}
    </Modal>
  );
}

// ══════════════════════════════════════════════════════════════════
// PLAN-REVIEW PREP
// ══════════════════════════════════════════════════════════════════
function Review() {
  const S = useHaven();
  const rv = S.doc.review;
  const checks = [
    { id: 'k1', text: 'Spending summary for each category', done: true, auto: true },
    { id: 'k2', text: 'Progress notes against each goal', done: true, auto: true },
    { id: 'k3', text: 'Invoices & receipts gathered', done: true, auto: true },
    { id: 'k4', text: 'List of providers & support workers', done: true, auto: true },
    { id: 'k5', text: 'Note what worked well this year', done: rv.notes.worked.trim().length > 0 },
    { id: 'k6', text: "Note what you'd change or need more of", done: rv.notes.change.trim().length > 0 },
    { id: 'k7', text: 'Gather any new reports from therapists', done: rv.k7, toggle: true },
  ];
  const [exported, setExported] = uS3(false);
  const done = checks.filter((c) => c.done).length;
  const ready = done / checks.length;

  return (
    <div className="fade-in">
      <PageHead title="Plan review prep" sub={<>Your <PlainTip term="Plan review" /> is coming up. Haven has already pulled together most of what you'll need — add your own notes and you're ready.</>} />

      {/* hero countdown + readiness */}
      <Card pad={26} style={{ marginBottom: 22, background: 'linear-gradient(120deg, var(--primary-soft), var(--amber-soft))', border: 'none' }}>
        <div style={{ display: 'grid', gridTemplateColumns: '1fr auto', gap: 30, alignItems: 'center' }}>
          <div>
            <Pill color="var(--primary-ink)" bg="rgba(255,255,255,.6)"><Icons.calendar size={13} />{`Review around ${fmtDate(PLAN_END)}`}</Pill>
            <h2 style={{ margin: '12px 0 6px', fontFamily: 'var(--serif)', fontWeight: 500, fontSize: 30, letterSpacing: '-.02em' }}>{PLAN_DAYS_LEFT} days to go</h2>
            <p style={{ margin: 0, fontSize: 14.5, color: 'var(--ink-2)', maxWidth: 460, lineHeight: 1.5 }}>A great review is really just good records plus your story. You've got the records — let's add the story.</p>
            <div style={{ marginTop: 18 }}><Button icon={Icons.download} onClick={() => setExported(true)}>Build my review report</Button></div>
          </div>
          <Ring pct={ready} size={132} stroke={14} color="var(--primary)" track="rgba(255,255,255,.55)">
            <span style={{ fontSize: 30, fontWeight: 700 }}>{Math.round(ready * 100)}%</span>
            <span style={{ fontSize: 12, color: 'var(--ink-2)', fontWeight: 600 }}>ready</span>
          </Ring>
        </div>
      </Card>

      <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 22, alignItems: 'start' }}>
        {/* left: checklist */}
        <div>
          <SectionTitle sub="Ticked-off items are pulled together automatically.">Your checklist</SectionTitle>
          <Card pad={8}>
            {checks.map((c, i) => (
              <div key={c.id} onClick={() => c.toggle && S.setReviewK7(!rv.k7)} style={{ display: 'flex', alignItems: 'center', gap: 12, padding: '13px 13px', borderBottom: i < checks.length - 1 ? '1px solid var(--line)' : 'none', cursor: c.toggle ? 'pointer' : 'default' }}>
                <span style={{ width: 24, height: 24, borderRadius: 8, flexShrink: 0, display: 'grid', placeItems: 'center', background: c.done ? 'var(--good)' : 'var(--surface-2)', color: c.done ? '#fff' : 'var(--ink-3)', border: c.done ? 'none' : '1.5px solid var(--line-2)' }}>
                  {c.done && <Icons.check size={15} stroke={2.6} />}
                </span>
                <span style={{ flex: 1, fontSize: 14, fontWeight: 500, color: c.done ? 'var(--ink-2)' : 'var(--ink)', textDecoration: c.done && c.auto ? 'none' : 'none' }}>{c.text}</span>
                {c.auto && <Pill color="var(--primary-ink)" bg="var(--primary-soft)" style={{ fontSize: 11 }}><Icons.sparkles size={12} />Auto</Pill>}
              </div>
            ))}
          </Card>
          <div style={{ marginTop: 12 }}><Note tone="primary" icon="heart">The two notes below are the bits only you can write — they carry the most weight in a review, and they go straight into your report.</Note></div>
          <Card pad={18} style={{ marginTop: 12 }}>
            <div style={{ marginBottom: 14 }}>
              <label style={{ fontSize: 13.5, fontWeight: 700, display: 'block', marginBottom: 6 }}>What worked well this year</label>
              <textarea value={rv.notes.worked} onChange={(e) => S.setReviewNote('worked', e.target.value)} placeholder="e.g. Weekly OT made mornings calmer. The riding program became the highlight of her week…"
                style={{ width: '100%', minHeight: 76, padding: '10px 12px', fontSize: 14, fontFamily: 'var(--sans)', lineHeight: 1.5, border: '1px solid var(--line-2)', borderRadius: 10, background: 'var(--surface)', color: 'var(--ink)', outline: 'none', resize: 'vertical', boxSizing: 'border-box' }} />
            </div>
            <div>
              <label style={{ fontSize: 13.5, fontWeight: 700, display: 'block', marginBottom: 6 }}>What you'd change or need more of</label>
              <textarea value={rv.notes.change} onChange={(e) => S.setReviewNote('change', e.target.value)} placeholder="e.g. More speech sessions — the current fortnightly isn't enough to keep momentum…"
                style={{ width: '100%', minHeight: 76, padding: '10px 12px', fontSize: 14, fontFamily: 'var(--sans)', lineHeight: 1.5, border: '1px solid var(--line-2)', borderRadius: 10, background: 'var(--surface)', color: 'var(--ink)', outline: 'none', resize: 'vertical', boxSizing: 'border-box' }} />
            </div>
          </Card>
        </div>

        {/* right: goals progress */}
        <div>
          <SectionTitle sub={`How this year went against ${S.doc.child.name}'s goals.`}>Goal progress</SectionTitle>
          <div style={{ display: 'flex', flexDirection: 'column', gap: 12 }}>
            {S.doc.goals.length === 0 && <Note tone="info" icon="goal">No goals yet — add them in <b>Settings</b> and their progress will feed this review summary.</Note>}
            {S.doc.goals.map((g) => (
              <Card key={g.id} pad={16}>
                <div style={{ display: 'grid', gridTemplateColumns: '1fr auto', columnGap: 12, alignItems: 'start' }}>
                  <span style={{ fontSize: 14.5, fontWeight: 600, lineHeight: 1.3 }}>{g.text}</span>
                  <span style={{ fontSize: 14, fontWeight: 700, color: 'var(--primary)', whiteSpace: 'nowrap' }}>{Math.round(g.progress * 100)}%</span>
                </div>
                <div style={{ marginTop: 11 }}><Bar pct={g.progress} color={g.progress > 0.66 ? 'var(--good)' : 'var(--primary)'} height={8} /></div>
                <div style={{ fontSize: 12.5, color: 'var(--ink-2)', marginTop: 10, lineHeight: 1.45 }}>{g.note}</div>
                <div style={{ fontSize: 11.5, color: 'var(--ink-3)', marginTop: 5 }}>Supported by {g.supports}</div>
              </Card>
            ))}
          </div>
        </div>
      </div>

      <ReportModal open={exported} onClose={() => setExported(false)} />
    </div>
  );
}

// ── the real review report: print-ready page → Save as PDF ──
function buildReviewReport() {
  const d = Store.doc;
  const plan = Store.plan;
  const esc = (s) => String(s == null ? '' : s).replace(/&/g, '&amp;').replace(/</g, '&lt;');
  const m0 = (n) => '$' + Number(n || 0).toLocaleString('en-AU', { maximumFractionDigits: 0 });
  const m2 = (n) => '$' + Number(n || 0).toLocaleString('en-AU', { minimumFractionDigits: 2, maximumFractionDigits: 2 });
  const dt = (x) => x ? new Date(x).toLocaleDateString('en-AU', { day: 'numeric', month: 'short', year: 'numeric' }) : '—';

  const budgetRows = d.budget.map((c) => `
    <tr class="cat"><td colspan="2">${esc(c.name)}</td><td>${m0(c.budget)}</td><td>${m0(c.spent)}</td><td>${m0(c.remaining)}</td></tr>
    ${c.subs.map((s) => `<tr><td class="ind"></td><td>${esc(s.name)}</td><td>${m0(s.budget)}</td><td>${m0(s.spent)}</td><td>${m0(s.remaining)}</td></tr>`).join('')}
  `).join('');

  const goalRows = d.goals.map((g) => `
    <div class="goal">
      <div class="goal-head"><span>${esc(g.text)}</span><b>${Math.round((g.progress || 0) * 100)}%</b></div>
      <div class="bar"><i style="width:${Math.round((g.progress || 0) * 100)}%"></i></div>
      ${g.note ? `<p class="note">${esc(g.note)}</p>` : ''}
      ${g.supports ? `<p class="supports">Supported by ${esc(g.supports)}</p>` : ''}
    </div>`).join('');

  const provRows = d.providers.map((p) => `<tr><td>${esc(p.name)}</td><td>${esc(p.sub)}</td><td>${esc(p.rate)}</td><td>${dt(p.agreementEnds)}</td></tr>`).join('');
  const workerRows = d.workers.map((w) => `<tr><td>${esc(w.name)}</td><td>${esc(w.role)}</td><td>$${Number(w.rate || 0).toFixed(2)}/hr</td></tr>`).join('');
  const claimRows = d.claims.slice(0, 20).map((c) => `<tr><td>${dt(c.date)}</td><td>${esc(c.provider)}</td><td>${esc(c.sub)}</td><td>${m2(c.amount)}</td><td>${esc((STATUS[c.status] || {}).label || c.status)}</td></tr>`).join('');
  const claimTotal = d.claims.reduce((s, c) => s + (c.amount || 0), 0);

  const html = `<!DOCTYPE html><html><head><meta charset="utf-8"><title>NDIS Review Summary — ${esc(d.child.name)}</title><style>
    @page { margin: 18mm 16mm; }
    body { font-family: Georgia, 'Times New Roman', serif; color: #2c2521; margin: 0; font-size: 12pt; line-height: 1.5; }
    .head { display: flex; justify-content: space-between; align-items: flex-end; border-bottom: 3px solid #c2557a; padding-bottom: 14px; margin-bottom: 22px; }
    h1 { font-size: 23pt; margin: 0; font-weight: 500; letter-spacing: -.01em; }
    .meta { text-align: right; font-size: 10pt; color: #6d6258; font-family: Verdana, sans-serif; }
    h2 { font-size: 14pt; margin: 26px 0 8px; color: #a23d62; font-weight: 600; page-break-after: avoid; }
    table { width: 100%; border-collapse: collapse; font-family: Verdana, sans-serif; font-size: 9.5pt; }
    th { text-align: left; font-size: 8pt; text-transform: uppercase; letter-spacing: .05em; color: #9c9085; padding: 4px 8px 6px; border-bottom: 2px solid #ece2d8; }
    td { padding: 6px 8px; border-bottom: 1px solid #f0e8df; vertical-align: top; }
    td:nth-last-child(-n+3) { white-space: nowrap; }
    tr.cat td { font-weight: 700; background: #faf5f0; }
    td.ind { width: 14px; border: none; }
    .goal { margin: 0 0 14px; page-break-inside: avoid; }
    .goal-head { display: flex; justify-content: space-between; gap: 16px; font-weight: 600; font-size: 11pt; }
    .bar { height: 7px; background: #f0e8df; border-radius: 99px; margin: 5px 0; }
    .bar i { display: block; height: 100%; background: #c2557a; border-radius: 99px; }
    .note { margin: 3px 0 0; font-size: 10.5pt; }
    .supports { margin: 2px 0 0; font-size: 9pt; color: #9c9085; font-family: Verdana, sans-serif; }
    .total { font-family: Verdana, sans-serif; font-size: 10pt; margin-top: 8px; color: #6d6258; }
    .foot { margin-top: 34px; padding-top: 12px; border-top: 1px solid #ece2d8; font-size: 8.5pt; color: #9c9085; font-family: Verdana, sans-serif; }
  </style></head><body>
    <div class="head">
      <div><h1>NDIS Plan Review Summary</h1>
      <div style="font-size:12pt;color:#6d6258;margin-top:4px;">${esc(d.child.name)} · NDIS ${esc(d.child.ndis)}</div></div>
      <div class="meta">Plan period ${dt(d.planPeriod.start)} – ${dt(d.planPeriod.end)}<br>Prepared ${dt(new Date())} with Haven</div>
    </div>
    <h2>Budget summary</h2>
    <table><tr><th></th><th>Support area</th><th>Funded</th><th>Spent</th><th>Remaining</th></tr>${budgetRows}
    <tr class="cat"><td colspan="2">Whole plan</td><td>${m0(plan.total)}</td><td>${m0(plan.spent)}</td><td>${m0(plan.remaining)}</td></tr></table>
    ${d.goals.length ? `<h2>Progress toward goals</h2>${goalRows}` : ''}
    ${(d.review && (d.review.notes.worked.trim() || d.review.notes.change.trim())) ? `<h2>In your words</h2>
      ${d.review.notes.worked.trim() ? `<p style="margin:4px 0 10px;"><b>What worked well:</b> ${esc(d.review.notes.worked)}</p>` : ''}
      ${d.review.notes.change.trim() ? `<p style="margin:4px 0 10px;"><b>What to change or add:</b> ${esc(d.review.notes.change)}</p>` : ''}` : ''}
    ${d.providers.length ? `<h2>Providers used</h2><table><tr><th>Provider</th><th>Support area</th><th>Rate</th><th>Agreement ends</th></tr>${provRows}</table>` : ''}
    ${d.workers.length ? `<h2>Directly-employed support workers</h2><table><tr><th>Name</th><th>Role</th><th>Rate</th></tr>${workerRows}</table>` : ''}
    ${d.claims.length ? `<h2>Recent claims</h2><table><tr><th>Date</th><th>Provider</th><th>Support area</th><th>Amount</th><th>Status</th></tr>${claimRows}</table><p class="total">${d.claims.length} claims recorded · ${m2(claimTotal)} total</p>` : ''}
    <div class="foot">Generated by Haven ${esc(HAVEN_VERSION)} · Invoices and receipts for all claims are kept in Haven's vault as required (5 years).</div>
    <script>setTimeout(function(){ window.print(); }, 500);<\/script>
  </body></html>`;

  const w = window.open('', '_blank');
  if (!w) { alert('Your browser blocked the report window — allow pop-ups for Haven and try again.'); return; }
  w.document.write(html);
  w.document.close();
}

function ReportModal({ open, onClose }) {
  const [phase, setPhase] = uS3('build');
  uE3(() => { if (open) { setPhase('build'); const t = setTimeout(() => setPhase('done'), 1600); return () => clearTimeout(t); } }, [open]);
  return (
    <Modal open={open} onClose={onClose} width={480} title={phase === 'done' ? null : 'Building your report'}>
      {phase === 'build' ? (
        <div style={{ textAlign: 'center', padding: '30px 20px' }}>
          <div style={{ color: 'var(--primary)', marginBottom: 16 }}><Icons.sparkles size={40} /></div>
          <div style={{ fontWeight: 600, fontSize: 16 }}>Pulling 12 months together…</div>
          <div style={{ fontSize: 13.5, color: 'var(--ink-2)', marginTop: 6 }}>Spending, goals, providers and your notes.</div>
          <div style={{ height: 5, background: 'var(--surface-2)', borderRadius: 99, marginTop: 22, overflow: 'hidden' }}>
            <div style={{ height: '100%', background: 'var(--primary)', animation: 'fillbar 1.5s ease both' }} />
          </div>
        </div>
      ) : (
        <div style={{ textAlign: 'center', padding: '10px 10px 4px' }}>
          <div style={{ width: 74, height: 74, borderRadius: '50%', background: 'var(--good-soft)', color: 'var(--good)', display: 'grid', placeItems: 'center', margin: '0 auto 16px', animation: 'pop .4s ease both' }}><Icons.download size={36} stroke={2.2} /></div>
          <h3 style={{ margin: '0 0 8px', fontFamily: 'var(--serif)', fontWeight: 500, fontSize: 24 }}>Review report ready</h3>
          <p style={{ margin: '0 auto 22px', color: 'var(--ink-2)', fontSize: 14.5, maxWidth: 380, lineHeight: 1.5 }}>A tidy summary of {Store.doc.child.name}'s year — spending by category, goal progress, providers and claims. It opens in a new tab with the print box ready: choose <b>“Save as PDF”</b> as the printer.</p>
          <div style={{ display: 'flex', gap: 10, justifyContent: 'center' }}>
            <Button variant="ghost" onClick={onClose}>Close</Button>
            <Button icon={Icons.download} onClick={buildReviewReport}>Open &amp; save as PDF</Button>
          </div>
        </div>
      )}
    </Modal>
  );
}

Object.assign(window, { Workers, Review });
