// App shell — AppState context + reducer, auth gate, toast/modal mounts, tweaks panel.
const TWEAKS_DEFAULTS = /*EDITMODE-BEGIN*/{
  "density": "balanced",
  "copilotDefault": true,
  "showTweaksOpen": false
}/*EDITMODE-END*/;

const STORAGE_KEY = "nuco:state";
const AUTH_KEY = "nuco:auth";

const AppStateContext = React.createContext(null);
const useApp = () => React.useContext(AppStateContext);

const deepClone = (x) => JSON.parse(JSON.stringify(x));
const uid = (() => { let n = 0; return (p = "id") => `${p}-${Date.now().toString(36)}-${++n}`; })();

function initialState() {
  const authRaw = localStorage.getItem(AUTH_KEY);
  const authed = !!authRaw;
  const user = authRaw || "";
  const base = {
    authed,
    user,
    page: localStorage.getItem("nuco:page") || "dashboard",
    copilotOpen: TWEAKS_DEFAULTS.copilotDefault,
    density: TWEAKS_DEFAULTS.density,
    staff: deepClone(STAFF),
    exceptions: deepClone(EXCEPTIONS),
    rosterRows: deepClone(ROSTER_ROWS),
    compliance: deepClone(COMPLIANCE),
    expiries: deepClone(EXPIRIES),
    payrollOpen: deepClone(PAYROLL_OPEN),
    payrollAuto: deepClone(PAYROLL_AUTO_INITIAL),
    payrollRunComplete: false,
    activity: deepClone(AGENT_ACTIVITY),
    plans: deepClone(AI_PLANS),
    facilities: deepClone(FACILITIES),
    activeFacility: "F-WGV",
    agencies: deepClone(AGENCIES),
    leaveRequests: deepClone(LEAVE_REQUESTS),
    leaveBalances: deepClone(LEAVE_BALANCES),
    regulatoryBundles: deepClone(REGULATORY_BUNDLES),
    submittedBundles: [],
    auditEvents: deepClone(AUDIT_EVENTS),
    rosterWeekMode: false,
    dashboardPersona: "coordinator",
    view: "manager",
    essPersonId: "E-1042",
    agents: deepClone(AGENTS),
    dataSources: deepClone(DATA_SOURCES),
    essMessages: [
      { id: uid("em"), role: "ai", text: "Hey Priya 👋 — your next shift is Tue 21 Apr 07:00–15:00 (Banksia). Need anything? Try 'I need Thursday off' or ask about your pay." },
    ],
    messages: [{ id: uid("msg"), role: "ai", text: "Morning Jess. I'm watching Wattlegrove. 5 items need you — compliance is the most urgent. Ask me anything or say 'plan my day'." }],
    filters: {
      dashboardTimeRange: "today",
      dashboardException: "all",
      rosterRole: "all",
      rosterView: "staff",
      rosterAIOn: true,
      leaveTab: "pending",
      auditModule: "all",
      peopleSearch: "",
      peopleRole: "all",
      payrollTab: "open",
      complianceTab: "workforce",
      complianceCategory: "all",
      copilotTab: "activity",
    },
    selected: { shift: null, employeeId: "E-1205" },
    modal: null,
    toasts: [],
    typing: false,
  };
  // Rehydrate demo snapshot. Shallow-merge at the root, then merge known nested
  // objects (filters, selected) so newly-introduced defaults are preserved when
  // an older snapshot lacks them — otherwise a stale filters blob wipes defaults
  // like `leaveTab`/`auditModule` and leaves UI in an "empty queue" state.
  try {
    const raw = localStorage.getItem(STORAGE_KEY);
    if (raw) {
      const saved = JSON.parse(raw);
      if (saved && typeof saved === "object") {
        return {
          ...base,
          ...saved,
          filters: { ...base.filters, ...(saved.filters || {}) },
          selected: { ...base.selected, ...(saved.selected || {}) },
          authed, user,
          modal: null, toasts: [], typing: false,
        };
      }
    }
  } catch (e) { /* ignore */ }
  return base;
}

function logEvent(state, event) {
  return [{ id: uid("EV"), ts: new Date().toLocaleString("en-AU", { hour12: false }).replace(",", ""), actor: state.user || "jess.palmer", ...event }, ...state.auditEvents].slice(0, 200);
}

function reducer(state, action) {
  switch (action.type) {
    case "AUTH_LOGIN":
      localStorage.setItem(AUTH_KEY, action.user);
      return { ...state, authed: true, user: action.user };
    case "AUTH_LOGOUT":
      localStorage.removeItem(AUTH_KEY);
      return { ...state, authed: false, user: "" };
    case "RESET_DEMO": {
      localStorage.removeItem(STORAGE_KEY);
      localStorage.removeItem("nuco:page");
      const fresh = initialState();
      return { ...fresh, authed: state.authed, user: state.user, toasts: [{ id: uid("t"), tone: "ok", text: "Demo reset — all scenes restored." }] };
    }
    case "SET_PAGE":
      localStorage.setItem("nuco:page", action.page);
      return { ...state, page: action.page };
    case "SET_COPILOT":
      return { ...state, copilotOpen: action.open };
    case "SET_DENSITY":
      return { ...state, density: action.density };
    case "SET_FILTER":
      return { ...state, filters: { ...state.filters, [action.key]: action.value } };
    case "SELECT_SHIFT":
      return { ...state, selected: { ...state.selected, shift: action.shift } };
    case "SELECT_EMPLOYEE":
      return { ...state, selected: { ...state.selected, employeeId: action.employeeId } };
    case "OPEN_MODAL":
      return { ...state, modal: action.modal };
    case "CLOSE_MODAL":
      return { ...state, modal: null };
    case "PUSH_TOAST":
      return { ...state, toasts: [...state.toasts, { id: uid("t"), ...action.toast }] };
    case "DISMISS_TOAST":
      return { ...state, toasts: state.toasts.filter(t => t.id !== action.id) };
    case "COPILOT_MSG":
      return { ...state, messages: [...state.messages, { id: uid("msg"), ...action.msg }] };
    case "SET_TYPING":
      return { ...state, typing: action.on };
    case "ASSIGN_SHIFT": {
      // Replace an open/ai row with a staff member (accept AI suggestion or reassign).
      const rosterRows = state.rosterRows.map((row, i) => {
        if (i !== action.rowIndex) return row;
        return {
          ...row,
          staff: action.newStaff,
          shifts: row.shifts.map(s => ({ ...s, kind: action.kind || "agency", label: action.label || s.label })),
        };
      });
      return { ...state, rosterRows, auditEvents: logEvent(state, { module: "Roster", action: "Filled shift", detail: `${action.newStaff.name} · ${action.label || "shift"}`, tone: "ok" }) };
    }
    case "REMOVE_ROSTER_ROW": {
      const rosterRows = state.rosterRows.filter((_, i) => i !== action.rowIndex);
      return { ...state, rosterRows };
    }
    case "TOGGLE_AI_ROSTER":
      return { ...state, filters: { ...state.filters, rosterAIOn: !state.filters.rosterAIOn } };
    case "DISMISS_EXCEPTION":
      return { ...state, exceptions: state.exceptions.filter(e => e.id !== action.id), auditEvents: logEvent(state, { module: "HR", action: "Dismissed exception", detail: action.id, tone: "ok" }) };
    case "RESOLVE_EXCEPTION": {
      const exceptions = state.exceptions.map(e => e.id === action.id ? { ...e, tone: "ok", kind: "Resolved", action: "View", body: "Resolved by NuCo · " + (action.body || e.body) } : e);
      return { ...state, exceptions, auditEvents: logEvent(state, { module: "HR", action: "Resolved exception", detail: action.id, tone: "ok" }) };
    }
    case "RESOLVE_PAYROLL_ROW": {
      const row = state.payrollOpen.find(r => r.id === action.id);
      if (!row) return state;
      const payrollOpen = state.payrollOpen.filter(r => r.id !== action.id);
      const payrollAuto = [{ id: uid("A"), text: row.type + " · " + row.detail.split(" ").slice(0, 5).join(" ") + "…", note: row.impact }, ...state.payrollAuto];
      return { ...state, payrollOpen, payrollAuto, auditEvents: logEvent(state, { module: "Payroll", action: "Resolved exception", detail: `${row.type} · ${row.impact}`, tone: "ok" }) };
    }
    case "RUN_PAYROLL":
      return { ...state, payrollRunComplete: true, auditEvents: logEvent(state, { module: "Payroll", action: "Pay run complete", detail: "143 payees · STP lodged", tone: "ok" }) };
    case "RENEW_CREDENTIAL": {
      const staff = state.staff.map(s => s.id === action.employeeId ? { ...s, status: "ok", hours: s.hours || 32, expired: undefined, expiring: undefined } : s);
      const exceptions = state.exceptions.filter(e => !(e.meta && e.meta.includes(action.employeeId)));
      const expiries = state.expiries.filter(x => !(x.name && action.matchName && x.name === action.matchName));
      const person = state.staff.find(s => s.id === action.employeeId);
      return { ...state, staff, exceptions, expiries, auditEvents: logEvent(state, { module: "Compliance", action: "Credential renewed", detail: `${person ? person.name : action.employeeId} · AHPRA`, tone: "ok" }) };
    }
    case "DISMISS_EXPIRY":
      return { ...state, expiries: state.expiries.filter(x => x.id !== action.id) };
    case "SET_FACILITY":
      return { ...state, activeFacility: action.facilityId };
    case "APPROVE_LEAVE": {
      const req = state.leaveRequests.find(l => l.id === action.id);
      const person = req && state.staff.find(s => s.id === req.personId);
      return { ...state, leaveRequests: state.leaveRequests.map(l => l.id === action.id ? { ...l, status: "approved" } : l), auditEvents: logEvent(state, { module: "HR", action: "Approved leave", detail: `${person ? person.name : action.id} · ${req ? req.type : ""}`, tone: "ok" }) };
    }
    case "DECLINE_LEAVE": {
      const req = state.leaveRequests.find(l => l.id === action.id);
      const person = req && state.staff.find(s => s.id === req.personId);
      return { ...state, leaveRequests: state.leaveRequests.map(l => l.id === action.id ? { ...l, status: "declined" } : l), auditEvents: logEvent(state, { module: "HR", action: "Declined leave", detail: `${person ? person.name : action.id} · ${req ? req.type : ""}`, tone: "warn" }) };
    }
    case "SUBMIT_BUNDLE": {
      const bundle = state.regulatoryBundles.find(b => b.id === action.id);
      return { ...state, submittedBundles: [...state.submittedBundles, action.id], auditEvents: logEvent(state, { module: "Compliance", action: "Regulatory submission", detail: bundle ? bundle.title : action.id, tone: "ok" }) };
    }
    case "LOG_AUDIT":
      return { ...state, auditEvents: [{ id: uid("EV"), ts: new Date().toLocaleString("en-AU", { hour12: false }).replace(",", ""), actor: state.user || "jess.palmer", ...action.event }, ...state.auditEvents].slice(0, 200) };
    case "SET_ROSTER_WEEK":
      return { ...state, rosterWeekMode: action.on };
    case "SET_DASHBOARD_PERSONA":
      return { ...state, dashboardPersona: action.persona };
    case "SET_VIEW":
      return { ...state, view: action.view };
    case "SET_ESS_PERSON":
      return { ...state, essPersonId: action.personId };
    case "ESS_MSG":
      return { ...state, essMessages: [...state.essMessages, { id: uid("em"), ...action.msg }] };
    case "NEW_LEAVE_REQUEST": {
      const req = { id: uid("L"), status: "pending", ...action.payload };
      return {
        ...state,
        leaveRequests: [req, ...state.leaveRequests],
        auditEvents: logEvent(state, {
          module: "HR",
          action: "Leave request submitted (ESS)",
          detail: `${action.payload.personName || ""} · ${action.payload.type} · ${action.payload.start} → ${action.payload.end}`,
          tone: "ok",
        }),
      };
    }
    case "SYNC_DATA_SOURCE": {
      const dataSources = state.dataSources.map(d => d.id === action.id ? { ...d, freshness: "just now", health: "ok" } : d);
      const src = state.dataSources.find(d => d.id === action.id);
      return {
        ...state,
        dataSources,
        auditEvents: logEvent(state, { module: "Compliance", action: "Data source sync", detail: src ? src.name : action.id, tone: "ok" }),
      };
    }
    case "APPROVE_AI_PLAN": {
      const plan = state.plans.find(p => p.id === action.planId);
      if (!plan) return state;
      let next = { ...state, plans: state.plans.filter(p => p.id !== action.planId) };
      if (plan.activity) {
        next.activity = [{ ...plan.activity, time: "just now" }, ...next.activity];
      }
      // If roster plan, flip any open/ai rows into assigned rows.
      if (action.planId === "PL-001") {
        next.rosterRows = state.rosterRows.map(row => {
          if (row.staff.open) {
            const ai = state.staff.find(s => s.id === "A-2017") || state.staff[8];
            return { ...row, staff: ai, shifts: row.shifts.map(s => ({ ...s, kind: "agency", label: "Night · Agency RN" })) };
          }
          if (row.staff.ai) return null;
          return row;
        }).filter(Boolean);
      }
      return next;
    }
    default:
      return state;
  }
}

// Persist a trimmed snapshot so transient UI (modal, toasts) doesn't leak across reloads.
function persistSnapshot(state) {
  const { modal, toasts, typing, authed, user, ...rest } = state;
  try { localStorage.setItem(STORAGE_KEY, JSON.stringify(rest)); } catch (e) { /* ignore */ }
}

function AppProvider({ children }) {
  const [state, dispatch] = React.useReducer(reducer, null, initialState);

  // Persist snapshot on change.
  React.useEffect(() => { persistSnapshot(state); }, [state]);

  // Density attr.
  React.useEffect(() => { document.documentElement.setAttribute("data-density", state.density); }, [state.density]);

  // Auto-dismiss toasts after 3.5s.
  React.useEffect(() => {
    if (!state.toasts.length) return;
    const timers = state.toasts.map(t => setTimeout(() => dispatch({ type: "DISMISS_TOAST", id: t.id }), 3500));
    return () => timers.forEach(clearTimeout);
  }, [state.toasts]);

  const value = React.useMemo(() => ({ state, dispatch }), [state]);
  return <AppStateContext.Provider value={value}>{children}</AppStateContext.Provider>;
}

function App() {
  return (
    <AppProvider>
      <Shell />
    </AppProvider>
  );
}

function Shell() {
  const { state, dispatch } = useApp();
  const [tweaksOpen, setTweaksOpen] = React.useState(TWEAKS_DEFAULTS.showTweaksOpen || false);
  const [editMode, setEditMode] = React.useState(false);

  // Tweaks protocol (Cowork edit mode).
  React.useEffect(() => {
    function onMsg(e) {
      if (!e.data || typeof e.data !== "object") return;
      if (e.data.type === "__activate_edit_mode") { setEditMode(true); setTweaksOpen(true); }
      if (e.data.type === "__deactivate_edit_mode") { setEditMode(false); setTweaksOpen(false); }
    }
    window.addEventListener("message", onMsg);
    window.parent.postMessage({ type: "__edit_mode_available" }, "*");
    return () => window.removeEventListener("message", onMsg);
  }, []);
  function persist(edits) { window.parent.postMessage({ type: "__edit_mode_set_keys", edits }, "*"); }

  if (!state.authed) {
    return <Login onAuth={(user) => dispatch({ type: "AUTH_LOGIN", user })} />;
  }

  // ESS view takes over the shell — no sidebar, no topbar-coordinator chrome.
  if (state.view === "ess") {
    return (
      <>
        <EmployeeApp />
        <GlobalModal />
        <ToastStack toasts={state.toasts} onDismiss={(id) => dispatch({ type: "DISMISS_TOAST", id })} />
      </>
    );
  }

  const pageEl = {
    dashboard:  <Dashboard />,
    roster:     <Roster />,
    people:     <People />,
    leave:      <Leave />,
    payroll:    <Payroll />,
    compliance: <Compliance />,
    agents:     <Agents />,
    data:       <DataSources />,
    audit:      <Audit />,
    reports:    <Reports />,
    settings:   <Placeholder title="Settings" />,
  }[state.page];

  return (
    <>
      <div className="app" data-copilot={state.copilotOpen ? "open" : "closed"} data-screen-label={`NuCo · ${state.page}`}>
        <Sidebar />
        <main className="main">
          <Topbar />
          {pageEl}
        </main>
        {state.copilotOpen && <Copilot onClose={() => dispatch({ type: "SET_COPILOT", open: false })} />}
      </div>

      <GlobalModal />
      <ToastStack toasts={state.toasts} onDismiss={(id) => dispatch({ type: "DISMISS_TOAST", id })} />

      <div className="tweaks" data-open={tweaksOpen}>
        <div className="hstack" style={{ justifyContent: "space-between", marginBottom: 4 }}>
          <h4 style={{ margin: 0 }}>Tweaks</h4>
          <button className="icon-btn" style={{ width: 22, height: 22 }} onClick={() => setTweaksOpen(false)}><Icon name="x" size={11} /></button>
        </div>
        <div className="tweak-row">
          <span>Density</span>
          <div className="seg">
            {["spacious","balanced","dense"].map(d => (
              <button key={d} data-active={state.density === d} onClick={() => { dispatch({ type: "SET_DENSITY", density: d }); persist({ density: d }); }}>
                {d[0].toUpperCase() + d.slice(1)}
              </button>
            ))}
          </div>
        </div>
        <div className="tweak-row">
          <span>Copilot open by default</span>
          <button className="chip" data-active={state.copilotOpen} onClick={() => { const v = !state.copilotOpen; dispatch({ type: "SET_COPILOT", open: v }); persist({ copilotDefault: v }); }}>
            {state.copilotOpen ? "On" : "Off"}
          </button>
        </div>
        <div className="divider" />
        <div className="sub" style={{ fontSize: 11 }}>Toggle Tweaks from the toolbar to show/hide this panel. Changes persist.</div>
      </div>
    </>
  );
}

// Centralised modal host — reads state.modal and renders the right dialog.
function GlobalModal() {
  const { state, dispatch } = useApp();
  if (!state.modal) return null;
  const close = () => dispatch({ type: "CLOSE_MODAL" });

  if (state.modal.kind === "payroll-resolve") {
    const row = state.modal.row;
    const person = state.staff.find(s => s.id === row.personId);
    return (
      <Modal open={true} onClose={close} title={`Resolve · ${row.type}`} width={580}
        footer={<>
          <button className="btn" onClick={close}>Cancel</button>
          {row.tone === "block" ? (
            <button className="btn" disabled>Cannot auto-resolve</button>
          ) : (
            <button className="btn sage" onClick={() => {
              dispatch({ type: "RESOLVE_PAYROLL_ROW", id: row.id });
              dispatch({ type: "PUSH_TOAST", toast: { tone: "ok", text: `Resolved · ${row.type} · ${row.impact}` } });
              close();
            }}>Apply fix<Icon name="check" size={12} /></button>
          )}
        </>}>
        <div className="vstack" style={{ gap: 12 }}>
          <div>
            <div className="eyebrow">Context</div>
            {person && <div className="hstack" style={{ gap: 10, marginTop: 6 }}><Person name={person.name} meta={`${person.id} · ${person.ward}`} tone={person.tone} /></div>}
          </div>
          <div>
            <div className="eyebrow" style={{ marginBottom: 6 }}>Impact chain</div>
            <Chain steps={row.chain} />
          </div>
          <div style={{ background: "var(--sage-wash)", border: "1px solid var(--sage)", borderRadius: 8, padding: 12 }}>
            <div className="hstack" style={{ gap: 8, marginBottom: 6 }}>
              <Icon name="sparkle" size={14} /> <strong style={{ fontSize: 12, color: "var(--sage-ink)" }}>NuCo suggests</strong>
            </div>
            <div style={{ fontSize: 13, color: "var(--sage-ink)" }}>{row.aiFix}</div>
          </div>
          <div className="hstack" style={{ justifyContent: "space-between", fontSize: 12 }}>
            <span className="sub">Estimated impact</span>
            <span className="mono" style={{ fontWeight: 600 }}>{row.impact}</span>
          </div>
        </div>
      </Modal>
    );
  }

  if (state.modal.kind === "payroll-run") {
    const complete = state.payrollRunComplete;
    return (
      <Modal open={true} onClose={close} title="Run payroll · period 2026-04-04 → 17"
        footer={complete ? (
          <button className="btn primary" onClick={close}>Done</button>
        ) : (
          <>
            <button className="btn" onClick={close}>Cancel</button>
            <button className="btn primary" onClick={() => {
              dispatch({ type: "RUN_PAYROLL" });
              dispatch({ type: "PUSH_TOAST", toast: { tone: "ok", text: "Pay run complete · STP lodged · 143 payees" } });
            }}>Confirm & run<Icon name="arrowRight" size={12} /></button>
          </>
        )}>
        {complete ? (
          <div className="vstack" style={{ gap: 10, alignItems: "center", padding: 20 }}>
            <div style={{ width: 56, height: 56, borderRadius: 28, background: "var(--sage-wash)", display: "grid", placeItems: "center", color: "var(--sage-ink)" }}>
              <Icon name="check" size={28} stroke={2} />
            </div>
            <div className="serif" style={{ fontSize: 22 }}>Pay run complete</div>
            <div className="sub" style={{ textAlign: "center" }}>STP lodged with ATO · 143 payees paid · $298,410 net released.</div>
          </div>
        ) : (
          <div className="vstack" style={{ gap: 10, fontSize: 12.5 }}>
            <div className="sub">NuCo will settle pay for 143 employees. Review the summary before confirming.</div>
            <div className="vstack" style={{ gap: 6, padding: 10, background: "var(--bone)", borderRadius: 6 }}>
              <div className="hstack" style={{ justifyContent: "space-between" }}><span>Gross</span><span className="mono">$421,850</span></div>
              <div className="hstack" style={{ justifyContent: "space-between" }}><span>Net</span><span className="mono">$298,410</span></div>
              <div className="hstack" style={{ justifyContent: "space-between" }}><span>Open exceptions</span><span className="mono">{state.payrollOpen.filter(r => r.tone !== "block").length}</span></div>
              <div className="hstack" style={{ justifyContent: "space-between" }}><span>Compliance holds</span><span className="mono">{state.payrollOpen.filter(r => r.tone === "block").length}</span></div>
            </div>
            <div className="sub" style={{ fontSize: 11 }}>Held items remain excluded from this run and will release automatically once compliance clears.</div>
          </div>
        )}
      </Modal>
    );
  }

  if (state.modal.kind === "plan-review") {
    const plan = state.plans.find(p => p.id === state.modal.planId);
    if (!plan) { close(); return null; }
    return (
      <Modal open={true} onClose={close} title={plan.title} width={640}
        footer={<>
          <button className="btn" onClick={close}>Cancel</button>
          <button className="btn sage" onClick={() => {
            dispatch({ type: "APPROVE_AI_PLAN", planId: plan.id });
            dispatch({ type: "PUSH_TOAST", toast: { tone: "ok", text: `AI plan applied · ${plan.steps.length} changes` } });
            close();
          }}><Icon name="sparkle" size={12} /> Approve & apply</button>
        </>}>
        <div className="vstack" style={{ gap: 10 }}>
          <div className="sub">{plan.summary}</div>
          <div>
            {plan.steps.map((s, i) => (
              <div key={i} className="diff-row">
                <div className="diff-before">{s.before}</div>
                <div className="diff-arrow"><Icon name="arrowRight" size={13} /></div>
                <div className="diff-after">{s.after}</div>
              </div>
            ))}
          </div>
        </div>
      </Modal>
    );
  }

  if (state.modal.kind === "guardrails") {
    const agent = state.agents.find(a => a.id === state.modal.agentId);
    if (!agent) { close(); return null; }
    return (
      <Modal open={true} onClose={close} title={`Guardrails · ${agent.name}`} width={560}
        footer={<button className="btn primary" onClick={close}>Close</button>}>
        <div className="vstack" style={{ gap: 12 }}>
          <div className="hstack" style={{ gap: 10, flexWrap: "wrap" }}>
            <TierBadge tier={agent.tier} />
            <ConfidencePill value={agent.confidence} />
            <Badge tone="ai" dot>Guardrails active</Badge>
          </div>
          <div className="sub">{agent.scope.join(" · ")}</div>
          <div style={{ fontSize: 12.5 }}>
            <strong>Human in the loop:</strong> {agent.approver}
          </div>
          <div>
            <div className="eyebrow" style={{ marginBottom: 6 }}>Policy rules · read-only</div>
            <div className="vstack" style={{ gap: 6 }}>
              {agent.guardrails.map((g, i) => (
                <div key={i} className="hstack" style={{ gap: 10, padding: 10, background: "var(--bone)", border: "1px solid var(--line)", borderRadius: 6, fontSize: 12.5 }}>
                  <Icon name={g.tone === "block" ? "lock" : g.tone === "warn" ? "alert" : "check"} size={13} />
                  <div style={{ flex: 1 }}>{g.rule}</div>
                  <Badge tone={g.tone} dot>{g.tone === "block" ? "hard stop" : g.tone === "warn" ? "escalate" : "allow"}</Badge>
                </div>
              ))}
            </div>
          </div>
          <div className="sub" style={{ fontSize: 11 }}>Guardrail config is controlled via policy, not chat. Changes require a signed policy update from the DoN or Finance delegate.</div>
        </div>
      </Modal>
    );
  }

  if (state.modal.kind === "visa-review") {
    const item = state.expiries.find(e => e.id === state.modal.expiryId);
    if (!item) { close(); return null; }
    const person = state.staff.find(s => s.name === item.name);
    const [step, setStep] = [state.modal.step || 0, (n) => dispatch({ type: "OPEN_MODAL", modal: { ...state.modal, step: n } })];
    const steps = [
      { k: "Working rights check",      detail: "Verify via VEVO (Visa Entitlement Verification Online)", status: step > 0 ? "ok" : "pending" },
      { k: "Condition 8107 (work)",     detail: "40-hour fortnightly cap check (aged care exemption applies)", status: step > 1 ? "ok" : "pending" },
      { k: "Sponsor obligations",       detail: "Employer attestation on file · renewed 2026-01-14", status: step > 2 ? "ok" : "pending" },
      { k: "Extension in progress",     detail: "NuCo detects lodged 482 extension · 31d to lapse", status: step > 3 ? "warn" : "pending" },
    ];
    return (
      <Modal open={true} onClose={close} title={`Visa review · ${item.name}`} width={560}
        footer={step < steps.length ? (
          <>
            <button className="btn" onClick={close}>Close</button>
            <button className="btn sage" onClick={() => setStep(step + 1)}><Icon name="check" size={12} /> {step === steps.length - 1 ? "Approve extension" : "Continue"}</button>
          </>
        ) : (
          <button className="btn primary" onClick={() => {
            dispatch({ type: "DISMISS_EXPIRY", id: item.id });
            dispatch({ type: "PUSH_TOAST", toast: { tone: "ok", text: `Working rights cleared · ${item.name}` } });
            dispatch({ type: "LOG_AUDIT", event: { module: "Compliance", action: "Working rights verified", detail: `${item.name} · Visa 482 extension accepted`, tone: "ok" } });
            close();
          }}>Done</button>
        )}>
        <div className="vstack" style={{ gap: 12 }}>
          {person && <div className="hstack" style={{ gap: 10 }}><AvatarInitials name={person.name} tone={person.tone} size={40} /><div><div style={{ fontWeight: 600 }}>{person.name}</div><div className="sub">{person.grade} · {person.ward} · {person.id}</div></div></div>}
          <div className="sub" style={{ fontSize: 12.5 }}>Visa 482 · expires in {item.day}d · last synced hourly via VEVO. NuCo walks through each working-rights check before re-approving eligibility.</div>
          <div className="vstack" style={{ gap: 8 }}>
            {steps.map((s, i) => (
              <div key={i} className="hstack" style={{ gap: 10, padding: 10, background: "var(--bone)", borderRadius: 6, border: "1px solid var(--line)" }}>
                <span style={{
                  width: 22, height: 22, borderRadius: 11,
                  display: "grid", placeItems: "center",
                  background: i < step ? "var(--sage-wash)" : i === step ? "var(--ink)" : "var(--paper-2)",
                  color: i < step ? "var(--sage-ink)" : i === step ? "var(--paper)" : "var(--ink-4)",
                  fontSize: 11, fontWeight: 600,
                }}>{i < step ? <Icon name="check" size={11} /> : (i + 1)}</span>
                <div style={{ flex: 1 }}>
                  <div style={{ fontWeight: 500, fontSize: 12.5 }}>{s.k}</div>
                  <div className="sub" style={{ fontSize: 11 }}>{s.detail}</div>
                </div>
                {i < step && <Badge tone="ok" dot>verified</Badge>}
                {i === step && step < steps.length && <Badge dot>next</Badge>}
              </div>
            ))}
          </div>
        </div>
      </Modal>
    );
  }

  if (state.modal.kind === "submit-bundle") {
    const bundle = state.regulatoryBundles.find(b => b.id === state.modal.bundleId);
    if (!bundle) { close(); return null; }
    const submitted = state.submittedBundles.includes(bundle.id);
    return (
      <Modal open={true} onClose={close} title={`Submit · ${bundle.title}`} width={560}
        footer={submitted ? (
          <button className="btn primary" onClick={close}>Done</button>
        ) : (
          <>
            <button className="btn" onClick={close}>Cancel</button>
            <button className="btn sage" disabled={bundle.readiness < 1}
              onClick={() => {
                dispatch({ type: "SUBMIT_BUNDLE", id: bundle.id });
                dispatch({ type: "PUSH_TOAST", toast: { tone: "ok", text: `Lodged · ${bundle.title.split(" ").slice(0,3).join(" ")}…` } });
                close();
              }}><Icon name="check" size={12} /> Lodge submission</button>
          </>
        )}>
        <div className="vstack" style={{ gap: 12 }}>
          <div className="sub">{bundle.body}</div>
          <div className="hstack" style={{ justifyContent: "space-between" }}>
            <span className="sub">Due</span><span className="mono">{bundle.due}</span>
          </div>
          <div className="hstack" style={{ justifyContent: "space-between" }}>
            <span className="sub">Readiness</span>
            <span className="mono" style={{ color: bundle.readiness < 1 ? "var(--amber-ink)" : "var(--sage-ink)", fontWeight: 600 }}>{Math.round(bundle.readiness*100)}%</span>
          </div>
          <div className="divider" />
          <div className="eyebrow">Bundle contents</div>
          <div className="vstack" style={{ gap: 6 }}>
            {bundle.items.map((it, i) => (
              <div key={i} className="hstack" style={{ justifyContent: "space-between", padding: "6px 0", borderBottom: i < bundle.items.length - 1 ? "1px dashed var(--line)" : "none", fontSize: 12.5 }}>
                <span>{it.name}</span>
                <Badge tone={it.state} dot>{it.state === "ok" ? "Ready" : "Attention"}</Badge>
              </div>
            ))}
          </div>
          {bundle.readiness < 1 && <div style={{ padding: 10, background: "var(--amber-wash)", color: "var(--amber-ink)", borderRadius: 6, fontSize: 12 }}>Bundle is not fully ready. Complete outstanding items before lodging.</div>}
        </div>
      </Modal>
    );
  }

  if (state.modal.kind === "renew-credential") {
    const person = state.staff.find(s => s.id === state.modal.employeeId);
    const [busy, setBusy] = [state.modal.busy, (v) => dispatch({ type: "OPEN_MODAL", modal: { ...state.modal, busy: v } })];
    return (
      <Modal open={true} onClose={busy ? () => {} : close} title={`Verify via AHPRA · ${person ? person.name : ""}`}
        footer={!busy ? (
          <>
            <button className="btn" onClick={close}>Cancel</button>
            <button className="btn sage" onClick={() => {
              setBusy(true);
              setTimeout(() => {
                dispatch({ type: "RENEW_CREDENTIAL", employeeId: person.id, matchName: person.name });
                dispatch({ type: "DISMISS_EXPIRY", id: "EXP-01" });
                dispatch({ type: "PUSH_TOAST", toast: { tone: "ok", text: `Credential valid · ${person.name} cleared to roster` } });
                close();
              }, 1200);
            }}><Icon name="shield" size={12} /> Verify now</button>
          </>
        ) : null}>
        {busy ? (
          <div className="vstack" style={{ gap: 10, alignItems: "center", padding: 20 }}>
            <div className="typing"><i /><i /><i /></div>
            <div className="sub">Calling AHPRA registry…</div>
          </div>
        ) : (
          <div className="vstack" style={{ gap: 10, fontSize: 13 }}>
            <div className="sub">NuCo will query the AHPRA public register using the saved registration number and update eligibility if a current registration is found.</div>
            <div style={{ padding: 12, background: "var(--bone)", borderRadius: 8, fontFamily: "var(--font-mono)", fontSize: 12 }}>
              <div>AHPRA: <strong>{person ? person.ahpra : "—"}</strong></div>
              <div>Subject: <strong>{person ? person.name : "—"}</strong></div>
            </div>
          </div>
        )}
      </Modal>
    );
  }

  return null;
}

function Placeholder({ title }) {
  return (
    <div className="page">
      <div className="page-head">
        <div>
          <div className="eyebrow">Module</div>
          <h1 className="page-title" style={{ marginTop: 4 }}>{title}</h1>
          <div className="page-sub">Not part of this prototype's hero flow — see Dashboard, Roster, People, Payroll, Compliance.</div>
        </div>
      </div>
      <div className="card" style={{ padding: 40, textAlign: "center" }}>
        <div className="eyebrow" style={{ marginBottom: 6 }}>Placeholder</div>
        <div className="serif" style={{ fontSize: 22 }}>Drop real {title} content here</div>
      </div>
    </div>
  );
}

Object.assign(window, { useApp, AppStateContext });

ReactDOM.createRoot(document.getElementById("root")).render(<App />);
