/*
 * cenora-bundle-3-screens-a.tsx — auto-generated. DO NOT EDIT.
 */

/* ═════ apps/web/components/home/home.tsx ═════ */
;/*__IIFE_WRAP_START__*/(function(){
/**
 * ============================================================================
 * apps/web/components/home/home.tsx
 * ----------------------------------------------------------------------------
 * Role-aware Home / Role Centre. The user can switch role via a topbar
 * segmented control — Accountant view emphasises Finance KPIs, Procurement
 * view emphasises POs / ORs / vendors. Both share the same chrome.
 *
 * Master ref doc described this as "every user lands here; cards are pinned
 * by role + tenant" — that's what this component models.
 * ============================================================================
 */

function Home() {
  const shell = useShell()
  const { push } = useRouter()
  const [tab, setTab] = React.useState<"dashboard" | "feed">("dashboard")
  const t = useTranslations("home")
  const tNav = useTranslations("nav")
  const { code: localeCode } = useLocale()

  const greeting = (() => {
    const h = new Date().getHours()
    return h < 12 ? t("greeting_morning") : h < 17 ? t("greeting_afternoon") : t("greeting_evening")
  })()
  const userFirst = shell.role.id === "accountant" ? "Maria" : "Maya"
  const userFull  = shell.role.id === "accountant" ? "Maria A." : "Maya C."
  const roleLabel = shell.role.id === "accountant" ? t("role_accountant_label") : t("role_procurement_label")

  return (
    <>
      <TopBar
        breadcrumb={[]}
      />

      <div className="flex-1 overflow-y-auto bg-app">
        <div className="max-w-[1440px] mx-auto p-6 space-y-5">

          {/* Greeting */}
          <header className="flex items-start justify-between gap-6">
            <div>
              <h1 className="font-serif text-[28px] text-ink leading-none">{greeting}, {userFirst}.</h1>
              <p className="text-[13px] text-ink-mute mt-2">
                {formatDateI18n(new Date(), localeCode, { weekday: "long", day: "numeric", month: "long", year: "numeric" })} · <strong className="text-ink-soft">{shell.entity.code}</strong> · April {t("period_open")} · {t("items_attention", { count: 4 })}
              </p>
            </div>
            <Badge variant="brand" className="mt-1">{userFull} · {roleLabel}</Badge>
          </header>

          {/* Tab toggle (Dashboard / AI Feed) */}
          <div className="inline-flex bg-cream p-0.5 rounded-md border border-divider">
            {(["dashboard", "feed"] as const).map(tab_id => (
              <button key={tab_id} onClick={() => setTab(tab_id)}
                className={cn(
                  "px-4 h-7 rounded-[5px] text-[12px] font-semibold transition-colors",
                  tab === tab_id ? "bg-surface text-ink shadow-sm" : "text-ink-mute hover:text-ink"
                )}>
                {tab_id === "dashboard" ? t("tab_dashboard") : t("tab_feed")}
              </button>
            ))}
          </div>

          {tab === "dashboard" && <MyUsageWidget push={push} />}
          {tab === "dashboard" && (shell.role.id === "accountant" ? <AccountantHome push={push} /> : <ProcurementHome push={push} />)}
          {tab === "feed"      && <UnifiedFeed />}
        </div>
      </div>
    </>
  )
}

/* ─── Role toggle ───────────────────────────────────────────────────────── */
function RoleToggle({ value, onChange }: { value: string; onChange: (v: any) => void }) {
  const t = useTranslations("home")
  return (
    <div className="inline-flex h-8 items-center gap-0.5 rounded-md bg-cream p-0.5 border border-divider">
      {[
        { value: "accountant",  label: t("role_accountant") },
        { value: "procurement", label: t("role_procurement") },
      ].map(o => {
        const active = value === o.value
        return (
          <button key={o.value} onClick={() => onChange(o.value)}
            className={cn(
              "inline-flex items-center gap-1 rounded-[5px] px-2.5 h-7 text-[11px] font-semibold transition-colors",
              active ? "bg-brand text-white shadow-sm" : "text-ink-mute hover:text-ink"
            )}>
            {o.label}
          </button>
        )
      })}
    </div>
  )
}

/* ─── Accountant role centre ────────────────────────────────────────────── */
function AccountantHome({ push }: { push: (h: string) => void }) {
  return (
    <>
      {/* KPI tiles */}
      <div className="grid grid-cols-4 gap-3">
        <KpiTile accent="success" label="Cash Position" value="$284.5k"  sub="Across 4 accounts" delta="↑ 12.4%" deltaDir="up" />
        <KpiTile accent="danger"  label="AP Overdue"    value="$41.2k"   sub="3 vendors · oldest 38 days" delta="↑ $8.1k" deltaDir="down" />
        <KpiTile accent="warn"    label="AR Outstanding" value="$127.8k" sub="7 customers · 2 overdue" delta="↑ $22.0k" deltaDir="down" />
        <KpiTile accent="brand"   label="April Revenue" value="$198.4k" sub="vs $210k budget" delta="94.5% of target" deltaDir="up" />
      </div>

      {/* Two-col */}
      <div className="grid grid-cols-[1fr_360px] gap-4">
        <div className="space-y-4">
          <ARAgingCard onOpen={() => push("/reports/library")} />
          <RevenueTrendCard />
        </div>
        <div className="space-y-4">
          <CashAccountsCard onOpen={() => push("/finance/bank-recon")} />
          <AISuggestionsCard />
        </div>
      </div>

      {/* Quick links row */}
      <QuickLinksRow links={[
        { icon: "calendar",    label: "Month-End Close",  hint: "4 / 12 steps", href: "/finance/month-end" },
        { icon: "credit-card", label: "Bank Reconciliation", hint: "5 unmatched", href: "/finance/bank-recon" },
        { icon: "doc",         label: "Trial Balance",    hint: "Apr period",  href: "/reports/library" },
        { icon: "globe",       label: "Consolidated",     hint: "4 entities",   href: "/entities/consolidated" },
      ]} push={push} />
    </>
  )
}

/* ─── Procurement role centre ───────────────────────────────────────────── */
function ProcurementHome({ push }: { push: (h: string) => void }) {
  const t = useTranslations("home")
  return (
    <>
      <div className="grid grid-cols-4 gap-3">
        <KpiTile accent="warn"   label={t("kpi_pos_overdue")}      value="2"      sub={t("kpi_pos_overdue_sub")} delta={t("kpi_pos_overdue_delta")}  deltaDir="down" />
        <KpiTile accent="info"   label={t("kpi_awaiting_approval")} value="5"     sub={t("kpi_oldest_28h")} delta={t("kpi_2_vs_mon")} deltaDir="down" />
        <KpiTile accent="brand"  label={t("kpi_open_pos")}          value="14"    sub={t("kpi_open_pos_sub")} />
        <KpiTile accent="success" label={t("kpi_vendor_on_time")}   value="86%"   sub={t("kpi_industry_avg")} delta={t("kpi_2pp")} deltaDir="up" />
      </div>

      <div className="grid grid-cols-[1fr_360px] gap-4">
        <div className="space-y-4">
          <ApprovalsCard onOpen={() => push("/approvals/inbox")} push={push} />
          <SpendByVendorCard push={push} />
        </div>
        <div className="space-y-4">
          <PipelineCard push={push} />
          <AISuggestionsCard mode="procurement" />
        </div>
      </div>

      <QuickLinksRow links={[
        { icon: "plus",        label: "New PO",                  hint: "Cmd+Shift+P", href: "/procurement/po/new" },
        { icon: "tag",         label: "Item Requests",           hint: "9 active",     href: "/catalogue/irq" },
        { icon: "box",         label: "Item Receipts",           hint: "3 to verify",  href: "/procurement/ir/IR-HVPH-1001" },
        { icon: "users",       label: "Vendors",                 hint: "8 active",     href: "/procurement/vendors" },
      ]} push={push} />
    </>
  )
}

/* ─── AR aging card ────────────────────────────────────────────────────── */
function ARAgingCard({ onOpen }: { onOpen: () => void }) {
  return (
    <Card>
      <CardHeader>
        <CardTitle>AR Aging Summary</CardTitle>
        <div className="flex items-center gap-2">
          <Badge variant="brand">Apr 2026</Badge>
          <button onClick={onOpen} className="text-[11px] text-brand font-semibold hover:underline">View all →</button>
        </div>
      </CardHeader>
      <table className="w-full text-[12px]">
        <thead>
          <tr className="bg-cream text-left text-[10px] font-bold uppercase tracking-wider text-ink-mute">
            <th className="px-4 py-2">Customer</th>
            <th className="px-3 text-right">Current</th>
            <th className="px-3 text-right">1–30d</th>
            <th className="px-3 text-right">31–60d</th>
            <th className="px-3 text-right">60d+</th>
          </tr>
        </thead>
        <tbody>
          {AR_AGING.map(r => (
            <tr key={r.customer} className="border-t border-divider-soft">
              <td className="px-4 py-2 font-medium text-ink">{r.customer}</td>
              <td className={cn("px-3 text-right font-mono", r.current ? "text-success font-semibold" : "text-ink-faint")}>{r.current ? formatCurrency(r.current) : "—"}</td>
              <td className={cn("px-3 text-right font-mono", r.b30 ? "text-success font-semibold" : "text-ink-faint")}>{r.b30 ? formatCurrency(r.b30) : "—"}</td>
              <td className={cn("px-3 text-right font-mono", r.b60 ? "text-danger font-semibold" : "text-ink-faint")}>{r.b60 ? formatCurrency(r.b60) : "—"}</td>
              <td className={cn("px-3 text-right font-mono", r.b90 ? "text-danger font-semibold" : "text-ink-faint")}>{r.b90 ? formatCurrency(r.b90) : "—"}</td>
            </tr>
          ))}
        </tbody>
      </table>
    </Card>
  )
}

/* ─── Revenue trend card ───────────────────────────────────────────────── */
function RevenueTrendCard() {
  const max = Math.max(...REVENUE_TREND.map(r => Math.max(r.value, r.budget)))
  const cur = REVENUE_TREND.find(r => r.current)!
  return (
    <Card>
      <CardHeader>
        <CardTitle>Monthly Revenue Trend</CardTitle>
        <button className="text-[11px] text-brand font-semibold hover:underline">Full report →</button>
      </CardHeader>
      <div className="px-4 pt-3 pb-2 flex items-end gap-3 h-32">
        {REVENUE_TREND.map(r => {
          const h = (r.value / max) * 100
          const bh = (r.budget / max) * 100
          return (
            <div key={r.month} className="flex-1 flex flex-col items-center gap-1.5">
              <div className="w-full flex items-end gap-px h-24 justify-center">
                <div className="w-1.5 rounded-t-sm bg-divider-strong" style={{ height: `${bh}%` }} title={`Budget: ${formatCurrency(r.budget)}`} />
                <div className={cn("w-4 rounded-t-sm", r.current ? "bg-accent" : "bg-brand")} style={{ height: `${h}%` }} title={`Revenue: ${formatCurrency(r.value)}`} />
              </div>
              <div className={cn("text-[10px]", r.current ? "text-accent-deep font-bold" : "text-ink-mute")}>{r.month}</div>
            </div>
          )
        })}
      </div>
      <div className="px-4 pb-3 pt-1 flex items-center gap-4 text-[11px]">
        <span className="text-ink-mute">Revenue <strong className="text-ink ml-1 font-mono">{formatCurrency(cur.value)}</strong></span>
        <span className="text-ink-mute">Budget <strong className="text-ink ml-1 font-mono">{formatCurrency(cur.budget)}</strong></span>
        <span className="text-ink-mute">Gross Margin <strong className="text-success ml-1 font-mono">43.4%</strong></span>
        <span className="ml-auto flex items-center gap-1.5">
          <span className="size-2 rounded-sm bg-brand" /><span className="text-[10px] text-ink-mute">Actual</span>
          <span className="size-2 rounded-sm bg-divider-strong ml-2" /><span className="text-[10px] text-ink-mute">Budget</span>
        </span>
      </div>
    </Card>
  )
}

/* ─── Cash accounts card ───────────────────────────────────────────────── */
function CashAccountsCard({ onOpen }: { onOpen: () => void }) {
  const totalUSD = CASH_ACCOUNTS.reduce((s, a) => s + a.balanceUSD, 0)
  return (
    <Card>
      <CardHeader>
        <CardTitle>Cash Accounts</CardTitle>
        <button onClick={onOpen} className="text-[11px] text-brand font-semibold hover:underline">Bank recon →</button>
      </CardHeader>
      <div className="p-4 space-y-3">
        <div className="flex items-center justify-between text-[11px] text-ink-mute">
          <span>Total (USD equiv)</span>
          <strong className="font-serif text-xl text-ink">{formatCurrency(totalUSD)}</strong>
        </div>
        <div className="h-2 bg-cream-deep rounded-full overflow-hidden">
          <div className="h-full bg-gradient-to-r from-brand to-brand-light rounded-full" style={{ width: "71%" }} />
        </div>
        <div className="space-y-0 divide-y divide-divider-soft">
          {CASH_ACCOUNTS.map(a => (
            <div key={a.acct} className="flex items-center justify-between py-2 text-[12px]">
              <div>
                <div className="font-medium text-ink">{a.label} <span className="text-[10px] text-ink-mute ml-1">{a.currency}</span></div>
                <div className="text-[10px] text-ink-mute">{a.acct}</div>
              </div>
              <div className="font-serif text-base text-ink">{formatCurrency(a.balance, a.currency)}</div>
            </div>
          ))}
        </div>
      </div>
    </Card>
  )
}

/* ─── AI suggestions card ──────────────────────────────────────────────── */
function AISuggestionsCard({ mode = "accountant" }: { mode?: "accountant" | "procurement" }) {
  const { openAI } = useShell()
  const t = useTranslations("home")
  const items = mode === "accountant" ? FIN_AI_FEED : [
    { dot: "alert",  text: "**PO-HVPH-1089** (Steel Rebar) was expected 3 days ago. No IR recorded. SteelMark not responded.", time: "AI flagged · overdue", chip: { tone: "danger" as const, label: "Chase supplier" } },
    { dot: "warn",   text: "**5 approvals** pending over 24 hrs. 2 items flagged as urgent by requestors.", time: "Oldest: OR-2041", chip: { tone: "warn" as const, label: "Review now" } },
    { dot: "action", text: "Solar inverter OR-2038 — AI found **3 alternative vendors** 12–18% cheaper than last quote.", time: "Based on item history", chip: { tone: "info" as const, label: "Compare" } },
    { dot: "ok",     text: "IR-HVPH-1001 matched PO fully. **Three-way match passed.** Ready to forward to finance.", time: "Apr 16", chip: { tone: "success" as const, label: "View receipt" } },
  ]
  const dotColor: any = { alert: "bg-danger", warn: "bg-warn", action: "bg-info", ok: "bg-success" }
  return (
    <Card>
      <CardHeader>
        <CardTitle><span className="text-accent-deep mr-1">✦</span> {t("card_ai_suggestions")}</CardTitle>
        <button onClick={openAI} className="text-[11px] text-brand font-semibold hover:underline">{t("link_open_chat")} →</button>
      </CardHeader>
      <div className="divide-y divide-divider-soft">
        {items.map((f, i) => (
          <button key={i} onClick={openAI} className="w-full text-left px-4 py-2.5 flex gap-3 items-start hover:bg-cream transition-colors">
            <span className={cn("size-2 rounded-full mt-1.5 shrink-0", dotColor[f.dot])} />
            <div className="flex-1 min-w-0">
              <div className="text-[12px] text-ink leading-relaxed" dangerouslySetInnerHTML={{ __html: f.text.replace(/\*\*(.+?)\*\*/g, '<strong class="font-semibold">$1</strong>') }} />
              <div className="text-[10px] text-ink-mute mt-1 flex items-center gap-2">
                <span>{f.time}</span>
                {f.chip && <Badge variant={f.chip.tone}>{f.chip.label}</Badge>}
              </div>
            </div>
          </button>
        ))}
      </div>
    </Card>
  )
}

/* ─── Approvals card (procurement) ─────────────────────────────────────── */
function ApprovalsCard({ onOpen, push }: { onOpen: () => void; push: (h: string) => void }) {
  const t = useTranslations("home")
  const rows = [
    { id: "OR-HVPH-2041", title: "Hard Hats Yellow × 200pc", requestor: "Pedro S.", amount: 14200, hours: 28, urgent: true },
    { id: "OR-HVPH-2040", title: "Office Chairs × 12 units",  requestor: "Hannah R.", amount: 9600, hours: 22, urgent: false },
    { id: "OR-HVPH-2039", title: "Diesel Generator 15kVA",    requestor: "Warren C.", amount: 88000, hours: 18, urgent: true },
    { id: "OR-HVPH-2038", title: "Solar Inverter 5kW",        requestor: "Sam V.", amount: 24000, hours: 14, urgent: false },
    { id: "OR-HVPH-2037", title: "Audit Engagement FY26",     requestor: "Olivia P.", amount: 38000, hours: 6, urgent: false },
  ]
  return (
    <Card>
      <CardHeader>
        <CardTitle>{t("card_approvals_awaiting")}</CardTitle>
        <button onClick={onOpen} className="text-[11px] text-brand font-semibold hover:underline">{t("link_all_approvals")} →</button>
      </CardHeader>
      <table className="w-full text-[12px]">
        <thead>
          <tr className="bg-cream text-left text-[10px] font-bold uppercase tracking-wider text-ink-mute">
            <th className="px-4 py-2">{t("col_or_num")}</th>
            <th>{t("col_item")}</th>
            <th>{t("col_requestor")}</th>
            <th className="text-right">{t("col_amount")}</th>
            <th className="text-right">{t("col_waiting")}</th>
            <th></th>
          </tr>
        </thead>
        <tbody>
          {rows.map(r => (
            <tr key={r.id} className="border-t border-divider-soft hover:bg-cream/60 cursor-pointer" onClick={() => push("/procurement/order-requests")}>
              <td className="px-4 py-2.5 font-mono font-bold text-brand-mid text-[11px]">{r.id}</td>
              <td>{r.title}{r.urgent && <Badge variant="danger" className="ml-2">{t("badge_urgent")}</Badge>}</td>
              <td className="text-ink-soft">{r.requestor}</td>
              <td className="text-right font-mono">{formatCurrency(r.amount, "PHP")}</td>
              <td className="text-right text-ink-mute">{r.hours}h</td>
              <td className="pr-4 text-right">
                <button
                  onClick={() => (window as any).cenoraToast?.(`Approved · ${r.id}`, { variant: "success", sub: `${r.title} · next step: route to ${r.amount > 50000 ? "CFO" : "buyer"}` })}
                  className="text-success font-bold text-[11px] hover:underline">{t("action_approve")}</button>
              </td>
            </tr>
          ))}
        </tbody>
      </table>
    </Card>
  )
}

/* ─── Spend by vendor card ─────────────────────────────────────────────── */
function SpendByVendorCard({ push }: { push: (h: string) => void }) {
  const t = useTranslations("home")
  const rows = [
    { name: "SteelMark Industries",   pct: 100, amount: 31200 },
    { name: "Pacific Solar PH",       pct: 70,  amount: 22000 },
    { name: "Apex Kitchen Supplies",  pct: 50,  amount: 15400 },
    { name: "UniOffice Manila",       pct: 29,  amount: 9200 },
    { name: "TechNet Solutions",      pct: 19,  amount: 6100 },
    { name: "Chem Supplies Corp",     pct: 14,  amount: 4600 },
  ]
  return (
    <Card>
      <CardHeader>
        <CardTitle>{t("card_top_spend_april")}</CardTitle>
        <button onClick={() => push("/procurement/vendors")} className="text-[11px] text-brand font-semibold hover:underline">{t("link_vendors")} →</button>
      </CardHeader>
      <div className="p-4 space-y-2.5">
        {rows.map(r => (
          <div key={r.name} className="grid grid-cols-[140px_1fr_auto] gap-3 items-center text-[12px]">
            <span className="text-ink truncate">{r.name}</span>
            <div className="h-2 rounded-full bg-cream-deep overflow-hidden">
              <div className="h-full rounded-full bg-gradient-to-r from-brand to-brand-light" style={{ width: `${r.pct}%` }} />
            </div>
            <span className="font-mono font-semibold text-ink">{formatCurrency(r.amount)}</span>
          </div>
        ))}
      </div>
    </Card>
  )
}

/* ─── Pipeline card (procurement) ───────────────────────────────────────── */
function PipelineCard({ push }: { push: (h: string) => void }) {
  const t = useTranslations("home")
  const stages = [
    { label: t("stage_drafted_ors"),    value: 6, hint: "₱24k", color: "bg-divider-strong" },
    { label: t("stage_in_approval"),    value: 5, hint: t("stage_awaiting_me"), color: "bg-info" },
    { label: t("stage_pos_open"),       value: 14, hint: "₱118k", color: "bg-brand" },
    { label: t("stage_awaiting_ir"),    value: 8, hint: t("stage_2_overdue"), color: "bg-warn" },
    { label: t("stage_matched_ir"),     value: 12, hint: t("stage_apr_only"), color: "bg-success" },
  ]
  return (
    <Card>
      <CardHeader>
        <CardTitle>{t("card_procurement_pipeline")}</CardTitle>
        <button onClick={() => push("/procurement/po")} className="text-[11px] text-brand font-semibold hover:underline">{t("link_pos")} →</button>
      </CardHeader>
      <div className="p-4 space-y-2.5">
        {stages.map(s => (
          <div key={s.label} className="grid grid-cols-[1fr_auto] items-center gap-2">
            <div className="flex items-center gap-2 text-[12px]">
              <span className={cn("size-2.5 rounded-full", s.color)} />
              <span className="text-ink">{s.label}</span>
              <span className="text-[10px] text-ink-mute">{s.hint}</span>
            </div>
            <span className="font-serif text-base text-ink tabular-nums">{s.value}</span>
          </div>
        ))}
      </div>
    </Card>
  )
}

/* ─── Quick links row ──────────────────────────────────────────────────── */
function QuickLinksRow({ links, push }: { links: { icon: string; label: string; hint: string; href: string }[]; push: (h: string) => void }) {
  return (
    <div className="grid grid-cols-4 gap-3">
      {links.map(l => (
        <button key={l.href} onClick={() => push(l.href)}
          className="bg-surface border border-divider rounded-lg p-3 flex items-center gap-3 hover:border-brand-mid hover:bg-brand-soft/40 transition-colors text-left">
          <span className="size-9 rounded-md bg-cream text-brand flex items-center justify-center shrink-0">
            <Icon name={l.icon as any} size={16} />
          </span>
          <div className="flex-1 min-w-0">
            <div className="text-[12.5px] font-semibold text-ink truncate">{l.label}</div>
            <div className="text-[10.5px] text-ink-mute truncate">{l.hint}</div>
          </div>
          <Icon name="arrow-right" size={12} className="text-ink-mute" />
        </button>
      ))}
    </div>
  )
}

/* ─── Unified AI feed (alternate tab) ──────────────────────────────────── */
function UnifiedFeed() {
  const all = [...FIN_AI_FEED.map(f => ({ ...f, source: "Finance" as const })), ...[
    { dot: "alert" as const,  text: "**PO-HVPH-1089** expected 3 days ago. SteelMark not responded.",                                       time: "AI flagged · 14m ago", chip: { tone: "danger" as const,  label: "Chase" },     source: "Procurement" as const },
    { dot: "warn"  as const,  text: "Cement stock **below reorder point** — 18 bags on hand, threshold 30. Suggest PO to RhinoCast.",        time: "Now · Inventory",      chip: { tone: "warn" as const,    label: "Draft PO" },  source: "Inventory"   as const },
    { dot: "action" as const, text: "**Rex S. probation** ends Apr 30 — confirmation review form is unfinished.",                            time: "HRIS · 2h ago",        chip: { tone: "info" as const,    label: "Open form" }, source: "HRIS"        as const },
  ]]
  const dotColor: any = { alert: "bg-danger", warn: "bg-warn", action: "bg-info", ok: "bg-success" }
  return (
    <Card>
      <CardHeader>
        <CardTitle><span className="text-accent-deep mr-1">✦</span> AI Feed — Across All Modules</CardTitle>
        <Badge variant="accent">7 new today</Badge>
      </CardHeader>
      <div className="divide-y divide-divider-soft">
        {all.map((f, i) => (
          <div key={i} className="px-4 py-3 flex gap-3 items-start hover:bg-cream/50">
            <span className={cn("size-2 rounded-full mt-1.5 shrink-0", dotColor[f.dot])} />
            <div className="flex-1 min-w-0">
              <div className="text-[12px] text-ink leading-relaxed" dangerouslySetInnerHTML={{ __html: f.text.replace(/\*\*(.+?)\*\*/g, '<strong class="font-semibold">$1</strong>') }} />
              <div className="text-[10px] text-ink-mute mt-1 flex items-center gap-2">
                <Badge variant="outline">{(f as any).source}</Badge>
                <span>{f.time}</span>
                {f.chip && <Badge variant={f.chip.tone as any}>{f.chip.label}</Badge>}
              </div>
            </div>
          </div>
        ))}
      </div>
    </Card>
  )
}

// SANDBOX
;(globalThis as any).Home = Home

})();/*__IIFE_WRAP_END__*/

/* ═════ apps/web/components/irq/irq-card.tsx ═════ */
;/*__IIFE_WRAP_START__*/(function(){
/**
 * ============================================================================
 * apps/web/components/irq/irq-card.tsx
 * ----------------------------------------------------------------------------
 * Single kanban card. Keeps a stable surface area so the kanban column and a
 * future list view can both reuse it.
 * ============================================================================
 */

interface IRQCardProps {
  d: any /* IRQ from lib/mock/irq */
  onClick?: () => void
}

function IRQCard({ d, onClick }: IRQCardProps) {
  return (
    <article
      tabIndex={0}
      onClick={onClick}
      onKeyDown={e => { if (e.key === "Enter" || e.key === " ") { e.preventDefault(); onClick?.() } }}
      className="cn-grab group relative bg-surface border border-divider rounded-md p-3 hover:shadow-md hover:-translate-y-px hover:border-divider-strong transition-all focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-accent">

      {d.aiFlag && (
        <span className="absolute top-2.5 right-2.5 size-5 rounded-full bg-gradient-to-br from-brand-soft to-accent-soft text-accent-deep border border-accent/30 flex items-center justify-center">
          <Icon name="sparkle" size={10} strokeWidth={2.5} />
        </span>
      )}

      <div className="text-[10px] font-bold text-brand-mid tracking-wider">{d.id}</div>
      <h4 className="text-xs font-semibold text-ink mt-1 leading-snug pr-6 font-sans">{d.title}</h4>

      <div className="flex items-center gap-1.5 mt-2 flex-wrap">
        <Badge variant="brand">{d.family}</Badge>
        <Badge variant="outline">{d.itemCount} {d.itemCount === 1 ? "item" : "items"}</Badge>
        <span className="text-[10px] text-ink-mute ml-auto">{d.date}</span>
      </div>

      {d.aiFlag && (
        <div className="mt-2 text-[10px] font-semibold bg-warn-soft text-warn px-2 py-1 rounded-sm inline-flex items-center gap-1.5">
          <Icon name="sparkle" size={10} strokeWidth={2.5} />
          AI: {d.aiFlag}
        </div>
      )}
      {d.pendingThread && (
        <div className="mt-2 text-[10px] font-semibold bg-warn-soft text-warn px-2 py-1 rounded-sm flex items-start gap-1.5">
          <Icon name="pause" size={10} strokeWidth={2} className="mt-0.5 shrink-0" />
          <span className="truncate">Pending: "{d.pendingThread[0].message}" — {d.pendingThread[0].from.split(" · ")[0]}</span>
        </div>
      )}
      {d.itemCode && (
        <div className="mt-2 text-[10px] font-bold bg-success-soft text-success px-2 py-1 rounded-sm inline-flex items-center gap-1.5 font-mono tracking-wide">
          <Icon name="check" size={10} strokeWidth={3} />
          Code: {d.itemCode}
        </div>
      )}
      {d.rejection && (
        <div className="mt-2 text-[10px] font-semibold bg-danger-soft text-danger px-2 py-1 rounded-sm inline-flex items-center gap-1.5">
          <Icon name="x" size={10} strokeWidth={3} />
          Rejected: {d.rejection}
        </div>
      )}

      <div className="flex items-center justify-between mt-2.5 pt-2 border-t border-divider-soft">
        <span className="text-[10px] text-ink-mute">by {d.requestor.name}</span>
        {d.approvers && <AvatarStack people={d.approvers} max={3} size="xs" />}
      </div>
    </article>
  )
}

// SANDBOX
;(globalThis as any).IRQCard = IRQCard

})();/*__IIFE_WRAP_END__*/

/* ═════ apps/web/components/irq/irq-kanban.tsx ═════ */
;/*__IIFE_WRAP_START__*/(function(){
/**
 * ============================================================================
 * apps/web/components/irq/irq-kanban.tsx
 * ----------------------------------------------------------------------------
 * Screen 04 — IRQ Kanban board. 5 columns by approval stage.
 * Click a card → opens IRQApprovalSheet.
 * Filter chips actually filter the data.
 * View toggle switches to IRQ list view.
 * "+ New IRQ" → navigates to /catalogue/irq/new
 * ============================================================================
 */

const STAGES_ORDER: any[] = ["draft", "submitted", "review", "approved", "rejected"]

function IRQKanban() {
  const { push } = useRouter()
  const [filter, setFilter] = React.useState<"all" | "mine" | "awaiting" | "month" | "cons">("all")
  const [view, setView] = React.useState<"list" | "kanban">("kanban")
  const [openId, setOpenId] = React.useState<string | null>(null)
  const [query, setQuery] = React.useState("")

  const filtered = React.useMemo(() => {
    return (IRQ_DATA as any[]).filter(d => {
      /* Filter chips */
      if (filter === "mine"     && d.requestor.initials !== "KL") return false
      if (filter === "awaiting" && (!d.approvers || !d.approvers.some((a: any) => a.initials === "KL"))) return false
      if (filter === "cons"     && d.family !== "Construction") return false
      /* Month: April only — all our data is April; pass through */
      /* Search */
      if (query && !(d.title + " " + d.id).toLowerCase().includes(query.toLowerCase())) return false
      return true
    })
  }, [filter, query])

  const openIRQ = (IRQ_BY_ID as any)[openId ?? ""]

  return (
    <>
      <TopBar
        breadcrumb={[{ label: "Products" }, { label: "Item Requests" }]}
        leading={
          <ViewToggle value={view} onChange={(v) => setView(v as any)}
            options={[
              { value: "list",   label: "List",   icon: "list" },
              { value: "kanban", label: "Kanban", icon: "columns" },
            ]} />
        }
        actions={
          <>
            <Button variant="ghost" leadingIcon="download">Export</Button>
            <Button variant="primary" leadingIcon="plus" onClick={() => push("/catalogue/irq/new")}>New IRQ</Button>
          </>
        }
      />

      <Subheader right={<SearchBox value={query} onChange={setQuery} placeholder="Search IRQs…" className="w-56" />}>
        <FilterChip active={filter === "all"}      onClick={() => setFilter("all")}>All Requests</FilterChip>
        <FilterChip active={filter === "mine"}     onClick={() => setFilter("mine")} count={3}>Mine</FilterChip>
        <FilterChip active={filter === "awaiting"} onClick={() => setFilter("awaiting")} count={2}>Awaiting Me</FilterChip>
        <FilterChip active={filter === "month"}    onClick={() => setFilter("month")}>This Month</FilterChip>
        <FilterChip active={filter === "cons"}     onClick={() => setFilter("cons")} icon="building">Construction</FilterChip>
      </Subheader>

      {view === "kanban" ? (
        <div className="flex-1 overflow-x-auto overflow-y-hidden bg-app">
          <div className="flex gap-3 p-5 h-full items-start">
            {STAGES_ORDER.map((stage: any) => {
              const stageMeta = (STAGE_TONES as any)[stage]
              const stageLabel = (STAGE_LABELS as any)[stage]
              const cards = filtered.filter((d: any) => d.stage === stage)
              const extra = stage === "approved" ? 6 : 0
              return (
                <section key={stage} className="w-[268px] shrink-0 flex flex-col">
                  <header className="bg-surface border border-divider border-b-0 rounded-t-md px-3 py-2 flex items-center gap-2">
                    <span className={cn("size-2 rounded-full", stageMeta.dot)} />
                    <span className="text-xs font-bold text-ink">{stageLabel}</span>
                    <span className="ml-auto text-[11px] font-semibold text-ink-mute bg-cream px-2 py-px rounded-full">
                      {cards.length + extra}
                    </span>
                  </header>
                  <div className={cn(
                    "bg-surface/55 border border-divider border-t-2 rounded-b-md p-2 flex flex-col gap-2 min-h-[220px] max-h-[calc(100vh-220px)] overflow-y-auto",
                    stage === "draft"     && "border-t-divider-strong",
                    stage === "submitted" && "border-t-info",
                    stage === "review"    && "border-t-warn",
                    stage === "approved"  && "border-t-success",
                    stage === "rejected"  && "border-t-danger",
                  )}>
                    {cards.map((d: any) => (
                      <IRQCard key={d.id} d={d} onClick={() => setOpenId(d.id)} />
                    ))}
                    {extra > 0 && (
                      <div className="text-[11px] text-ink-mute text-center py-2">+ {extra} more approved this month</div>
                    )}
                    {stage === "draft" && (
                      <button onClick={() => push("/catalogue/irq/new")}
                        className="flex items-center justify-center gap-1.5 py-2 border border-dashed border-divider rounded-md text-[11px] font-semibold text-ink-mute hover:border-brand-mid hover:text-brand hover:bg-brand-soft transition-colors">
                        <Icon name="plus" size={11} strokeWidth={2.5} />
                        New request
                      </button>
                    )}
                  </div>
                </section>
              )
            })}
          </div>
        </div>
      ) : (
        <IRQListView rows={filtered} onOpen={setOpenId} />
      )}

      <IRQApprovalSheet
        irq={openIRQ}
        open={!!openId}
        onOpenChange={(o) => { if (!o) setOpenId(null) }}
      />
    </>
  )
}

/* List view — same data, table layout. */
function IRQListView({ rows, onOpen }: { rows: any[]; onOpen: (id: string) => void }) {
  return (
    <div className="flex-1 overflow-y-auto bg-surface">
      <table className="w-full text-sm">
        <thead className="bg-cream sticky top-0 border-b-2 border-divider">
          <tr className="text-left text-[10px] font-bold uppercase tracking-wider text-ink-mute">
            <th className="px-5 py-2.5">IRQ #</th>
            <th className="px-4">Title</th>
            <th className="px-4">Family</th>
            <th className="px-4">Requestor</th>
            <th className="px-4">Stage</th>
            <th className="px-4">Date</th>
            <th className="px-5"></th>
          </tr>
        </thead>
        <tbody>
          {rows.map(d => (
            <tr key={d.id} onClick={() => onOpen(d.id)}
              className="border-b border-divider cursor-pointer hover:bg-brand-soft transition-colors">
              <td className="px-5 py-2.5 font-bold text-brand-mid text-xs">{d.id}</td>
              <td className="px-4 text-sm">{d.title}</td>
              <td className="px-4"><Badge variant="brand">{d.family}</Badge></td>
              <td className="px-4 text-xs text-ink-soft">{d.requestor.name}</td>
              <td className="px-4">
                <Badge variant={(STAGE_TONES as any)[d.stage].badge} dot>
                  {(STAGE_LABELS as any)[d.stage]}
                </Badge>
              </td>
              <td className="px-4 text-xs text-ink-mute">{d.date}</td>
              <td className="px-5 text-ink-mute"><Icon name="chevron-right" size={14} /></td>
            </tr>
          ))}
        </tbody>
      </table>
    </div>
  )
}

// SANDBOX
;(globalThis as any).IRQKanban = IRQKanban
;(globalThis as any).IRQListView = IRQListView

})();/*__IIFE_WRAP_END__*/

/* ═════ apps/web/components/irq/irq-approval-sheet.tsx ═════ */
;/*__IIFE_WRAP_START__*/(function(){
/**
 * ============================================================================
 * apps/web/components/irq/irq-approval-sheet.tsx
 * ----------------------------------------------------------------------------
 * Screen 06 — right-side slide-out panel triggered by clicking an IRQ card
 * on the kanban. Shows item summary, the 3-step approval trail, the full
 * Pending conversation thread, and footer actions (Approve / Reject /
 * Pending).
 *
 * Local state for the demo:
 *   - reply textarea content
 *   - submitted flag (shows confirmation banner after Approve/Reject)
 * In production this dispatches to the workflow service.
 * ============================================================================
 */

interface IRQApprovalSheetProps {
  irq?: any
  open: boolean
  onOpenChange: (open: boolean) => void
}

function IRQApprovalSheet({ irq, open, onOpenChange }: IRQApprovalSheetProps) {
  const [reply, setReply] = React.useState("")
  const [done, setDone] = React.useState<null | "approved" | "rejected" | "pending">(null)
  React.useEffect(() => { if (open) { setReply(""); setDone(null) } }, [open, irq?.id])

  if (!irq) return null

  const stageBadge = (STAGE_TONES as any)[irq.stage]?.badge ?? "neutral"
  const stageLabel = (STAGE_LABELS as any)[irq.stage] ?? irq.stage

  /* 3-step trail data — derived from stage */
  const trail = [
    { step: "Draft created",    by: irq.requestor.name, on: irq.date,
      state: "done" },
    { step: "Submitted for review", by: irq.requestor.name, on: irq.date,
      state: irq.stage === "draft" ? "future" : "done" },
    { step: irq.stage === "approved" ? "Approved" : irq.stage === "rejected" ? "Rejected" : "Approval decision",
      by: irq.stage === "approved" ? "Maya C." : irq.stage === "rejected" ? "Maya C." : "—",
      on:  (irq.stage === "approved" || irq.stage === "rejected") ? irq.date : "pending",
      state: irq.stage === "approved" ? "done" : irq.stage === "rejected" ? "danger" : irq.stage === "review" ? "active" : "future" },
  ]

  return (
    <Sheet open={open} onOpenChange={onOpenChange}>
      <SheetHeader>
        <div className="min-w-0 flex-1">
          <div className="flex items-center gap-2 mb-1.5">
            <span className="font-mono text-[11px] font-bold text-brand-mid tracking-wider">{irq.id}</span>
            <Badge variant={stageBadge} dot>{stageLabel}</Badge>
          </div>
          <SheetTitle>{irq.title}</SheetTitle>
          <SheetDescription>
            {irq.family} · {irq.itemCount} {irq.itemCount === 1 ? "item" : "items"} · Requested by {irq.requestor.name} on {irq.date}
          </SheetDescription>
        </div>
        <SheetClose onClick={() => onOpenChange(false)} />
      </SheetHeader>

      <SheetBody>
        {done && (
          <div className={cn(
            "rounded-md px-3 py-2.5 mb-4 text-xs font-semibold flex items-center gap-2",
            done === "approved" && "bg-success-soft text-success",
            done === "rejected" && "bg-danger-soft text-danger",
            done === "pending"  && "bg-warn-soft text-warn",
          )}>
            <Icon name={done === "approved" ? "check" : done === "rejected" ? "x" : "pause"} size={13} strokeWidth={2.5} />
            {done === "approved" && "Approved. Item code will be auto-generated."}
            {done === "rejected" && "Rejected. Requestor has been notified."}
            {done === "pending"  && "Marked Pending. Conversation continues below."}
          </div>
        )}

        {irq.itemCode && (
          <div className="bg-success-soft border border-success/20 rounded-md p-3 mb-5 flex items-center gap-3">
            <div className="size-8 rounded-md bg-success text-white flex items-center justify-center"><Icon name="check" size={15} strokeWidth={3} /></div>
            <div>
              <div className="text-[10px] font-bold text-success uppercase tracking-wider">Assigned item code</div>
              <div className="font-mono font-bold text-base text-success tracking-wide">{irq.itemCode}</div>
            </div>
          </div>
        )}
        {irq.rejection && (
          <div className="bg-danger-soft border border-danger/20 rounded-md p-3 mb-5">
            <div className="text-[10px] font-bold text-danger uppercase tracking-wider">Rejection reason</div>
            <div className="text-xs text-ink-soft mt-1">{irq.rejection}</div>
          </div>
        )}

        {/* APPROVAL TRAIL */}
        <section className="mb-6">
          <h3 className="text-[10px] font-bold uppercase tracking-wider text-ink-mute mb-3">Approval Trail</h3>
          <ol className="relative">
            {trail.map((t, i) => (
              <li key={i} className="flex gap-3 pb-3 last:pb-0 relative">
                <div className="flex flex-col items-center">
                  <div className={cn(
                    "size-6 rounded-full flex items-center justify-center text-[10px] font-bold shrink-0",
                    t.state === "done"   && "bg-success text-white",
                    t.state === "active" && "bg-brand text-white",
                    t.state === "danger" && "bg-danger text-white",
                    t.state === "future" && "bg-divider text-ink-mute",
                  )}>
                    {t.state === "done"   && <Icon name="check" size={11} strokeWidth={3} />}
                    {t.state === "danger" && <Icon name="x" size={11} strokeWidth={3} />}
                    {(t.state === "active" || t.state === "future") && (i + 1)}
                  </div>
                  {i < trail.length - 1 && <div className={cn("w-px flex-1 mt-1", t.state === "done" ? "bg-success" : "bg-divider")} />}
                </div>
                <div className="flex-1 min-w-0 pb-2">
                  <div className="text-xs font-semibold text-ink">{t.step}</div>
                  <div className="text-[11px] text-ink-mute">
                    {t.by !== "—" && <>{t.by} · </>}{t.on}
                  </div>
                </div>
              </li>
            ))}
          </ol>
        </section>

        {/* LINE ITEMS */}
        {irq.lines && irq.lines.length > 0 && (
          <section className="mb-6">
            <h3 className="text-[10px] font-bold uppercase tracking-wider text-ink-mute mb-2">Line Items ({irq.lines.length})</h3>
            <div className="border border-divider rounded-md overflow-hidden">
              {irq.lines.map((line: any, i: number) => (
                <div key={i} className={cn("p-3 flex items-start gap-3", i > 0 && "border-t border-divider")}>
                  <span className="text-[10px] font-mono text-ink-mute pt-0.5">{String(line.line).padStart(2, "0")}</span>
                  <div className="flex-1 min-w-0">
                    <div className="text-xs font-semibold text-ink">{line.itemName}</div>
                    <div className="flex flex-wrap gap-x-3 gap-y-0.5 mt-1 text-[11px] text-ink-mute">
                      {line.qty && <span>Qty: <span className="text-ink-soft">{line.qty} {line.uom}</span></span>}
                      {line.brand && <span>Brand: <span className="text-ink-soft">{line.brand}</span></span>}
                      {line.specification && <span>Spec: <span className="text-ink-soft">{line.specification}</span></span>}
                      {line.material && <span>Material: <span className="text-ink-soft">{line.material}</span></span>}
                      {line.variant && <span>Variant: <span className="text-ink-soft">{line.variant}</span></span>}
                    </div>
                  </div>
                </div>
              ))}
            </div>
          </section>
        )}

        {/* CONVERSATION THREAD */}
        {irq.pendingThread && (
          <section className="mb-6">
            <h3 className="text-[10px] font-bold uppercase tracking-wider text-ink-mute mb-3 flex items-center gap-2">
              <Icon name="message" size={11} strokeWidth={2} />
              Conversation
            </h3>
            <div className="space-y-3">
              {irq.pendingThread.map((msg: any, i: number) => {
                const isApprover = msg.from.toLowerCase().includes("approver")
                return (
                  <div key={i} className={cn("flex gap-2.5", isApprover && "flex-row-reverse")}>
                    <Avatar
                      initials={msg.from.split(" ").map((s: string) => s[0]).slice(0, 2).join("").toUpperCase()}
                      tone={isApprover ? "teal" : "sand"} size="sm" />
                    <div className={cn("flex-1 min-w-0", isApprover && "text-right")}>
                      <div className="text-[11px] font-semibold text-ink">{msg.from}</div>
                      <div className={cn(
                        "mt-1 inline-block text-left rounded-md px-3 py-2 text-xs leading-relaxed",
                        isApprover ? "bg-brand-soft text-ink-soft" : "bg-cream text-ink-soft"
                      )}>{msg.message}</div>
                    </div>
                  </div>
                )
              })}
            </div>
          </section>
        )}

        {/* REPLY */}
        {irq.stage !== "approved" && irq.stage !== "rejected" && (
          <section>
            <h3 className="text-[10px] font-bold uppercase tracking-wider text-ink-mute mb-2">Add comment</h3>
            <Textarea value={reply} onChange={e => setReply(e.target.value)}
              placeholder="Ask for clarification, note a concern, or describe your decision…" rows={3} />
          </section>
        )}
      </SheetBody>

      <SheetFooter>
        {irq.stage === "approved" || irq.stage === "rejected" ? (
          <>
            <Button variant="ghost" leadingIcon="external">Open full record</Button>
            <Button variant="primary" onClick={() => onOpenChange(false)} className="ml-auto">Close</Button>
          </>
        ) : (
          <>
            <Button variant="danger"  leadingIcon="x"     onClick={() => setDone("rejected")}>Reject</Button>
            <Button variant="ghost"   leadingIcon="pause" onClick={() => setDone("pending")}>Pending</Button>
            <Button variant="primary" leadingIcon="check" onClick={() => setDone("approved")} className="ml-auto">Approve</Button>
          </>
        )}
      </SheetFooter>
    </Sheet>
  )
}

// SANDBOX
;(globalThis as any).IRQApprovalSheet = IRQApprovalSheet

})();/*__IIFE_WRAP_END__*/

/* ═════ apps/web/components/irq/irq-form.tsx ═════ */
;/*__IIFE_WRAP_START__*/(function(){
/**
 * ============================================================================
 * apps/web/components/irq/irq-form.tsx
 * ----------------------------------------------------------------------------
 * Screen 05 — New IRQ wizard (4 steps). All interactive:
 *   1. Request Info — auto IRQ number, requestor, date, dimensions
 *   2. Item Details — 4-level cascading category picker, item name + AI
 *      duplicate check (fires on blur), UoM, est. cost, min order qty
 *   3. Attributes — 7-attribute panel + tracking flags + attribute-set badge
 *   4. Review & Submit
 *
 * State held locally for the prototype. Real Next.js: useForm (react-hook-form
 * + zod) and a `POST /api/irq` action.
 * ============================================================================
 */

const STEPS = ["Request Info", "Item Details", "Attributes", "Review & Submit"] as const

/* ─── 4-level taxonomy (excerpt) ─────────────────────────────────────────── */
const TAXONOMY: Record<string, Record<string, Record<string, string[]>>> = {
  "01 · General": {
    "0101 · IT & Office": {
      "010103 · Networking": ["010103-01 · Switches", "010103-02 · Routers", "010103-03 · APs"],
      "010104 · Compute":   ["010104-01 · Laptops", "010104-02 · Desktops"],
    },
  },
  "02 · Construction": {
    "0201 · Structural Materials": {
      "020101 · Steel & Rebar":     ["02010101 · I-Beam", "02010102 · Rebar", "02010103 · Plate"],
      "020102 · Concrete":          ["02010201 · Ready-mix", "02010202 · Precast"],
    },
    "0202 · Finishes": {
      "020201 · Coatings":          ["02020101 · Sealants", "02020102 · Paint"],
    },
  },
  "13 · Tools & Equipment": {
    "1302 · Power Tools": {
      "130202 · Grinders":          ["13020201 · Angle Grinder"],
    },
  },
}

function IRQForm() {
  const { push } = useRouter()
  const [current, setCurrent] = React.useState(0)
  /* Step 1 */
  const [project, setProject]   = React.useState("Calamba Phase 2")
  const [activity, setActivity] = React.useState("Structural framing")
  /* Step 2 */
  const [family, setFamily]   = React.useState<string | null>("02 · Construction")
  const [classn, setClassn]   = React.useState<string | null>("0201 · Structural Materials")
  const [category, setCategory] = React.useState<string | null>("020101 · Steel & Rebar")
  const [subcat, setSubcat]   = React.useState<string | null>(null)
  const [itemName, setItemName] = React.useState("Structural Steel I-Beam 200×100mm Grade 50")
  const [uom,   setUom]       = React.useState("PC")
  const [cost,  setCost]      = React.useState("")
  const [moq,   setMoq]       = React.useState("")
  const [shortDesc, setShortDesc] = React.useState("")
  const [longDesc,  setLongDesc]  = React.useState("")
  /* Step 3 */
  const [brand, setBrand]     = React.useState("")
  const [spec,  setSpec]      = React.useState("Grade 50 · ASTM A992")
  const [colour, setColour]   = React.useState("")
  const [material, setMaterial] = React.useState("Structural Steel")
  const [variant, setVariant] = React.useState("")
  const [notes, setNotes]     = React.useState("")
  const [tracking, setTracking] = React.useState<Set<string>>(new Set(["lot"]))
  /* AI */
  const [aiDismissed, setAIDismissed] = React.useState(false)
  const [showAI, setShowAI] = React.useState(true)
  const triggerAI = () => { if (!aiDismissed) setShowAI(true) }

  const next = () => setCurrent(c => Math.min(c + 1, STEPS.length - 1))
  const prev = () => setCurrent(c => Math.max(c - 1, 0))
  const submit = () => { alert("Submitted. (In production: POST /api/irq → workflow service)"); push("/catalogue/irq") }

  const trackingDescriptor = tracking.has("lot") && tracking.has("expiry")
    ? "V12 · Lot + Expiry"
    : tracking.has("lot")    ? "V9 · Lot Tracked"
    : tracking.has("serial") ? "V14 · Serialized"
    : "V1 · Basic"

  return (
    <>
      <TopBar
        breadcrumb={[
          { label: "Item Requests", href: "/catalogue/irq" },
          { label: "New Request — IRQ-0212" },
        ]}
        onNavigate={push}
        actions={
          <>
            <Button variant="ghost" onClick={() => push("/catalogue/irq")}>Save Draft</Button>
            <Button variant="primary" trailingIcon="arrow-right" onClick={submit}>Submit for Review</Button>
          </>
        }
      />

      <div className="shrink-0 bg-surface border-b border-divider px-6 py-3.5">
        <Stepper steps={STEPS as any} current={current} />
      </div>

      <div className="flex-1 overflow-y-auto bg-app">
        <div className="max-w-[1200px] mx-auto p-6 grid grid-cols-[1fr_320px] gap-5">
          <div className="flex flex-col gap-4 min-w-0">

            {/* STEP 1 */}
            {current === 0 && (
              <Card>
                <CardHeader><CardTitle>Request Info</CardTitle></CardHeader>
                <CardContent className="space-y-4">
                  <div className="grid grid-cols-3 gap-3">
                    <div className="space-y-1.5">
                      <Label>IRQ Number</Label>
                      <Input value="IRQ-0212" disabled />
                    </div>
                    <div className="space-y-1.5">
                      <Label>Requestor</Label>
                      <Input value="Maya C." disabled />
                    </div>
                    <div className="space-y-1.5">
                      <Label>Date</Label>
                      <Input value="Apr 17, 2026" disabled />
                    </div>
                  </div>
                  <div className="grid grid-cols-2 gap-3">
                    <div className="space-y-1.5">
                      <Label required>Project</Label>
                      <Select value={project} onChange={e => setProject(e.target.value)}>
                        <option>Calamba Phase 2</option>
                        <option>BGC Tower Fit-Out</option>
                        <option>Manila HQ Refurb</option>
                        <option>(none)</option>
                      </Select>
                    </div>
                    <div className="space-y-1.5">
                      <Label>Activity</Label>
                      <Select value={activity} onChange={e => setActivity(e.target.value)}>
                        <option>Structural framing</option>
                        <option>Civil works</option>
                        <option>MEP installation</option>
                        <option>Finishes</option>
                      </Select>
                    </div>
                  </div>
                  <div className="space-y-1.5">
                    <Label>Header description</Label>
                    <Textarea placeholder="What is this request for at a high level?" rows={3}
                      defaultValue={`${project} — additional structural materials for foundation tie-in.`} />
                  </div>
                </CardContent>
              </Card>
            )}

            {/* STEP 2 */}
            {current === 1 && (
              <>
                <Card>
                  <CardHeader><CardTitle>Category — 4-Level Picker</CardTitle></CardHeader>
                  <CardContent>
                    <div className="grid grid-cols-2 gap-3">
                      <CascadeStep label="Family" value={family} onClear={() => { setFamily(null); setClassn(null); setCategory(null); setSubcat(null) }}
                        options={Object.keys(TAXONOMY)} onPick={(v) => { setFamily(v); setClassn(null); setCategory(null); setSubcat(null) }} required />
                      <CascadeStep label="Classification" value={classn} onClear={() => { setClassn(null); setCategory(null); setSubcat(null) }}
                        options={family ? Object.keys(TAXONOMY[family] ?? {}) : []}
                        onPick={(v) => { setClassn(v); setCategory(null); setSubcat(null) }} required />
                      <CascadeStep label="Category" value={category} onClear={() => { setCategory(null); setSubcat(null) }}
                        options={family && classn ? Object.keys(TAXONOMY[family]?.[classn] ?? {}) : []}
                        onPick={(v) => { setCategory(v); setSubcat(null) }} required />
                      <CascadeStep label="Subcategory" value={subcat} onClear={() => setSubcat(null)}
                        options={family && classn && category ? (TAXONOMY[family]?.[classn]?.[category] ?? []) : []}
                        onPick={setSubcat} required highlight />
                    </div>
                    <p className="text-[11px] text-ink-mute mt-3">
                      Item code will be auto-generated: <span className="font-mono font-bold text-brand-mid">0201010X-NNN</span> on final approval
                    </p>
                  </CardContent>
                </Card>

                <Card>
                  <CardHeader><CardTitle>Item Name & Duplicate Check</CardTitle></CardHeader>
                  <CardContent className="space-y-4">
                    <div className="space-y-1.5">
                      <Label required>Item Name</Label>
                      <Input value={itemName} onChange={e => setItemName(e.target.value)} onBlur={triggerAI}
                        className="font-semibold" />
                      <p className="text-[11px] text-ink-mute">Be specific — include grade, size, and type. AI checks for duplicates on blur.</p>
                    </div>

                    {showAI && !aiDismissed && itemName.length > 8 && (
                      <AICallout
                        title="AI Duplicate Check — 2 possible matches found"
                        body="The name you entered is semantically similar to existing catalogue items. Please review before proceeding."
                        matches={[
                          { code: "02010101-008", name: "Steel I-Beam 203×102mm Grade 50 — SteelMark", pct: 91 },
                          { code: "02010101-009", name: "I-Beam Structural Steel 200mm Wide Flange", pct: 74 },
                        ]}
                        onUseExisting={(m) => { alert(`Will use existing code ${m.code}`); setAIDismissed(true) }}
                        onDismiss={() => { setAIDismissed(true); setShowAI(false) }}
                        onProceed={() => { alert("Selecting existing item is the recommended path"); setAIDismissed(true) }}
                      />
                    )}

                    <div className="grid grid-cols-3 gap-3">
                      <div className="space-y-1.5"><Label required>Unit of Measure</Label>
                        <Select value={uom} onChange={e => setUom(e.target.value)}>
                          <option value="PC">PC — Piece</option>
                          <option value="MT">MT — Metric Ton</option>
                          <option value="LM">LM — Linear Meter</option>
                          <option value="SQM">SQM — Square Meter</option>
                          <option value="KG">KG — Kilogram</option>
                        </Select>
                      </div>
                      <div className="space-y-1.5"><Label>Estimated Unit Cost</Label>
                        <Input value={cost} onChange={e => setCost(e.target.value)} placeholder="0.00 USD" />
                      </div>
                      <div className="space-y-1.5"><Label>Minimum Order Qty</Label>
                        <Input value={moq} onChange={e => setMoq(e.target.value)} placeholder="1" />
                      </div>
                    </div>
                    <div className="space-y-1.5"><Label>Short Description</Label>
                      <Input value={shortDesc} onChange={e => setShortDesc(e.target.value)}
                        placeholder="Used for structural framing on construction projects…" />
                    </div>
                    <div className="space-y-1.5"><Label>Long Description / Notes</Label>
                      <Textarea value={longDesc} onChange={e => setLongDesc(e.target.value)} rows={3}
                        placeholder="Include installation guidance, compliance notes, or procurement requirements…" />
                    </div>
                  </CardContent>
                </Card>
              </>
            )}

            {/* STEP 3 */}
            {current === 2 && (
              <Card>
                <CardHeader><CardTitle>Item Attributes (7-Attribute Framework)</CardTitle></CardHeader>
                <CardContent className="space-y-3">
                  <div className="grid grid-cols-2 gap-3">
                    <div className="space-y-1.5"><Label>Brand / Manufacturer</Label>
                      <Input value={brand} onChange={e => setBrand(e.target.value)} placeholder="e.g. SteelMark, BlueStar" />
                    </div>
                    <div className="space-y-1.5"><Label>Spec / Grade</Label>
                      <Input value={spec} onChange={e => setSpec(e.target.value)} />
                    </div>
                    <div className="space-y-1.5"><Label>Colour</Label>
                      <Input value={colour} onChange={e => setColour(e.target.value)} placeholder="e.g. Mill finish, galvanised" />
                    </div>
                    <div className="space-y-1.5"><Label>Material</Label>
                      <Input value={material} onChange={e => setMaterial(e.target.value)} />
                    </div>
                    <div className="space-y-1.5"><Label>Variant / Model</Label>
                      <Input value={variant} onChange={e => setVariant(e.target.value)} placeholder="e.g. W8×31, IPE200" />
                    </div>
                    <div className="space-y-1.5"><Label>Notes</Label>
                      <Input value={notes} onChange={e => setNotes(e.target.value)} placeholder="Handling or procurement notes" />
                    </div>
                  </div>
                  <div className="space-y-1.5"><Label>Long description</Label>
                    <Textarea rows={4}
                      defaultValue="Hot-rolled structural steel I-beam, suitable for primary load-bearing applications. Conforms to ASTM A992. Mill finish; galvanising available on request with 14-day lead time." />
                  </div>
                </CardContent>
              </Card>
            )}

            {/* STEP 4 */}
            {current === 3 && (
              <Card>
                <CardHeader><CardTitle>Review & Submit</CardTitle></CardHeader>
                <CardContent className="space-y-4">
                  <ReviewRow label="IRQ Number"   value="IRQ-0212" mono />
                  <ReviewRow label="Project / Activity" value={`${project} · ${activity}`} />
                  <ReviewRow label="Category"     value={[family, classn, category, subcat].filter(Boolean).join(" › ")} />
                  <ReviewRow label="Item Name"    value={itemName} strong />
                  <ReviewRow label="Unit of measure" value={uom} />
                  {brand    && <ReviewRow label="Brand"    value={brand} />}
                  {spec     && <ReviewRow label="Spec"     value={spec} />}
                  {material && <ReviewRow label="Material" value={material} />}
                  {variant  && <ReviewRow label="Variant"  value={variant} />}
                  <ReviewRow label="Tracking" value={
                    <span className="inline-flex items-center gap-1.5">
                      {[...tracking].map(t => <Badge key={t} variant="brand">{t}</Badge>)}
                      <Badge variant="accent">{trackingDescriptor}</Badge>
                    </span>
                  } />

                  <div className="bg-brand-soft border border-brand/15 rounded-md px-3 py-2.5 text-[12px] text-brand-mid flex items-center gap-2 mt-2">
                    <Icon name="info" size={13} strokeWidth={2} />
                    On submit, this request enters the <strong className="font-semibold">Under Review</strong> queue and notifies the assigned Product Manager.
                  </div>
                </CardContent>
              </Card>
            )}

            <div className="flex items-center gap-2">
              {current > 0 && <Button variant="ghost" leadingIcon="chevron-left" onClick={prev}>Previous</Button>}
              {current < STEPS.length - 1
                ? <Button variant="primary" trailingIcon="chevron-right" onClick={next} className="ml-auto">Continue</Button>
                : <Button variant="primary" leadingIcon="check" onClick={submit} className="ml-auto">Submit for Review</Button>
              }
            </div>
          </div>

          {/* SIDE PANEL */}
          <aside className="flex flex-col gap-3 min-w-0">
            <Card>
              <CardHeader><CardTitle>Tracking & Attribute Set</CardTitle></CardHeader>
              <CardContent className="space-y-3">
                <div>
                  <Label className="mb-2 block">Tracking flags</Label>
                  <div className="flex flex-wrap gap-1.5">
                    {(["serial", "lot", "expiry"] as const).map(k => (
                      <FilterChip key={k} active={tracking.has(k)}
                        onClick={() => {
                          const n = new Set(tracking); n.has(k) ? n.delete(k) : n.add(k); setTracking(n)
                        }}>
                        {k === "serial" ? "Serialized" : k === "lot" ? "Lot Tracked" : "Expiry Date"}
                      </FilterChip>
                    ))}
                  </div>
                </div>
                <div className="bg-brand-soft text-brand-mid font-bold text-[11px] py-2 rounded-md text-center">
                  Auto-assigned: {trackingDescriptor}
                </div>
                <div className="text-[10px] text-ink-mute text-center">Based on selected tracking flags</div>
              </CardContent>
            </Card>

            <Card>
              <CardHeader><CardTitle>Request Info</CardTitle></CardHeader>
              <CardContent className="space-y-2 text-xs">
                <SideRow label="IRQ Number" value={<span className="font-mono font-bold text-brand-mid">IRQ-0212</span>} />
                <SideRow label="Requestor"  value="Maya C." />
                <SideRow label="Date"       value="Apr 17, 2026" />
                <SideRow label="Status"     value={<Badge variant="info" dot>Draft</Badge>} />
                <SideRow label="Items"      value="1 of up to 20" />
              </CardContent>
            </Card>
          </aside>
        </div>
      </div>
    </>
  )
}

/* ─── Cascading picker step ──────────────────────────────────────────────── */
function CascadeStep({ label, value, options, onPick, onClear, required, highlight }: {
  label: string; value: string | null; options: string[];
  onPick: (v: string) => void; onClear: () => void; required?: boolean; highlight?: boolean;
}) {
  const [open, setOpen] = React.useState(false)
  React.useEffect(() => {
    if (!open) return
    const close = () => setOpen(false)
    const t = setTimeout(() => window.addEventListener("click", close, { once: true }), 0)
    return () => { clearTimeout(t); window.removeEventListener("click", close) }
  }, [open])

  return (
    <div className="relative">
      <Label className="mb-1 block" required={required}>{label}</Label>
      <button
        onClick={(e) => { e.stopPropagation(); setOpen(o => !o) }}
        disabled={options.length === 0}
        className={cn(
          "w-full text-left flex items-center justify-between gap-2 h-9 px-3 rounded-md border text-[13px] transition-colors",
          value
            ? "bg-brand-soft border-brand-mid text-brand-mid font-semibold"
            : highlight
              ? "bg-surface border-brand-mid text-ink-mute"
              : "bg-surface border-divider text-ink-mute hover:border-divider-strong",
          options.length === 0 && "opacity-40 cursor-not-allowed",
        )}>
        <span className="truncate">{value ?? `Select ${label.toLowerCase()}…`}</span>
        <Icon name="chevron-down" size={13} />
      </button>
      {open && options.length > 0 && (
        <div className="absolute z-10 mt-1 w-full bg-surface border border-divider rounded-md shadow-lg max-h-60 overflow-y-auto py-1">
          {value && (
            <button onClick={(e) => { e.stopPropagation(); onClear(); setOpen(false) }}
              className="w-full text-left px-3 py-1.5 text-[11px] text-ink-mute hover:bg-cream border-b border-divider">
              Clear selection
            </button>
          )}
          {options.map(o => (
            <button key={o} onClick={(e) => { e.stopPropagation(); onPick(o); setOpen(false) }}
              className={cn(
                "w-full text-left px-3 py-2 text-xs hover:bg-brand-soft",
                value === o && "bg-brand-soft text-brand-mid font-semibold"
              )}>
              {o}
            </button>
          ))}
        </div>
      )}
    </div>
  )
}

function SideRow({ label, value }: { label: string; value: React.ReactNode }) {
  return (
    <div className="flex justify-between items-center gap-2">
      <span className="text-ink-mute">{label}</span>
      <span>{value}</span>
    </div>
  )
}
function ReviewRow({ label, value, mono, strong }: { label: string; value: React.ReactNode; mono?: boolean; strong?: boolean }) {
  return (
    <div className="grid grid-cols-[160px_1fr] gap-3 py-1.5 border-b border-divider-soft last:border-0">
      <span className="text-[11px] uppercase tracking-wider font-bold text-ink-mute">{label}</span>
      <span className={cn("text-sm", mono && "font-mono", strong && "font-semibold")}>{value}</span>
    </div>
  )
}

// SANDBOX
;(globalThis as any).IRQForm = IRQForm

})();/*__IIFE_WRAP_END__*/

/* ═════ apps/web/components/procurement/pr-list.tsx ═════ */
;/*__IIFE_WRAP_START__*/(function(){
/**
 * ============================================================================
 * apps/web/components/procurement/pr-list.tsx
 * ----------------------------------------------------------------------------
 * Order Requests — the upstream of POs. Pipeline view of the
 * cnr_purchaserequest table, grouped by status. Each row shows the
 * requestor, what's wanted, urgency, and where it is in the workflow.
 *
 * Interactions:
 *   • Tab between "Pipeline" (status pills inline) and "Pipeline grid"
 *   • Status filter chips at top
 *   • Click row → opens detail slideout with approval chain + actions
 *   • Approved PRs have a "Convert to PO" action that routes to PO form
 * ============================================================================
 */

function PRList() {
  const { push } = useRouter()
  const [statusFilter, setStatusFilter] = React.useState<"all" | "open" | PR["status"]>("open")
  const [mine, setMine] = React.useState(false)
  const [search, setSearch] = React.useState("")
  const [selected, setSelected] = React.useState<PR | null>(null)
  const [colFilters, setColFilters] = React.useState<Record<string, { values: string[]; sort?: "asc" | "desc" } | undefined>>({})
  const [formOpen, setFormOpen] = React.useState(false)

  const counts = React.useMemo(() => {
    const c: Record<string, number> = { all: PRS.length, open: 0 }
    for (const p of PRS) {
      c[p.status] = (c[p.status] ?? 0) + 1
      if (p.status !== "converted" && p.status !== "rejected") c.open++
    }
    return c
  }, [])

  /* Distinct values for column filters */
  const distinctDept = React.useMemo(() => Array.from(new Set(PRS.map(p => p.department))), [])
  const distinctRequestor = React.useMemo(() => Array.from(new Set(PRS.map(p => p.requestor.name))), [])

  const rows = React.useMemo(() => {
    let r = PRS
    if (statusFilter === "open")    r = r.filter(p => p.status !== "converted" && p.status !== "rejected")
    else if (statusFilter !== "all") r = r.filter(p => p.status === statusFilter)
    if (mine) r = r.filter(p => p.requestor.initials === "KL" || (p.approvers?.some(a => a.initials === "KL")))
    if (search.trim()) {
      const q = search.toLowerCase()
      r = r.filter(p => p.id.toLowerCase().includes(q) || p.title.toLowerCase().includes(q) || p.itemSummary.toLowerCase().includes(q) || p.requestor.name.toLowerCase().includes(q))
    }
    /* Apply column-header (Excel-style) filters */
    r = r.filter(p => applyExcelFilters(p as any, colFilters, [
      { key: "department" },
      { key: "requestor", accessor: (x: any) => x.requestor.name },
    ]))
    return r
  }, [statusFilter, mine, search, colFilters])

  /* Pipeline grid columns */
  const pipelineStages: PR["status"][] = ["submitted", "review", "approved", "sourced", "converted"]

  /* ── Real handlers (replace safety-net classification) ─────────────── */
  const onExport = () => {
    if (typeof window !== "undefined" && (window as any).cenoraToast) {
      (window as any).cenoraToast("Exported", { variant: "success", sub: `${rows.length} order requests · CSV downloaded` })
    }
  }
  const onNewOR = () => setFormOpen(true)

  return (
    <>
      <TopBar
        breadcrumb={[{ label: "Procurement · P2P" }, { label: "Order Requests" }]}
      />

      <ActionBar
        title="Order Requests"
        status={<><span className="font-mono">cnr_purchaserequest</span> · {counts.open} open · {counts.submitted ?? 0} awaiting approval · <span className="text-warn font-semibold">{(PRS.filter(p => p.urgent && (p.status !== "converted" && p.status !== "rejected"))).length} urgent</span></>}
        search={
          <div className="relative">
            <input
              value={search} onChange={e => setSearch(e.target.value)}
              placeholder="Search OR # or title…"
              className="w-56 h-8 pl-8 pr-3 bg-cream border border-divider rounded-md text-[12px] placeholder:text-ink-faint focus:border-brand-mid"
            />
            <Icon name="search" size={13} className="absolute left-2.5 top-1/2 -translate-y-1/2 text-ink-mute" />
          </div>
        }
        extras={
          <button onClick={() => setMine(m => !m)}
            className={cn(
              "h-8 px-2.5 rounded-md text-[11.5px] font-semibold inline-flex items-center gap-1.5 border transition-colors",
              mine ? "bg-brand text-white border-brand" : "bg-surface border-divider text-ink-soft hover:border-divider-strong"
            )}>
            <Icon name="user" size={12} /> Mine
          </button>
        }
        secondary={<Button variant="ghost" leadingIcon="download" onClick={onExport}>Export</Button>}
        primary={<Button variant="primary" leadingIcon="plus" onClick={onNewOR}>New OR</Button>}
        filters={
          <>
            <FilterChip active={statusFilter === "open"} onClick={() => setStatusFilter("open")} count={counts.open} tone="info">Open</FilterChip>
            <FilterChip active={statusFilter === "all"} onClick={() => setStatusFilter("all")} count={counts.all}>All</FilterChip>
            <span className="w-px h-5 bg-divider mx-1" />
            {(["submitted", "review", "approved", "sourced", "converted", "rejected"] as const).map(s => {
              const c = counts[s] ?? 0
              if (c === 0) return null
              return (
                <FilterChip key={s} active={statusFilter === s} onClick={() => setStatusFilter(s)} count={c} tone={PR_STATUS_TONE[s] as any}>
                  {PR_STATUS_LABEL[s]}
                </FilterChip>
              )
            })}
          </>
        }
      />

      <div className="flex-1 overflow-y-auto bg-app">
        <div className="max-w-[1440px] mx-auto p-6 space-y-4">

          {/* Pipeline mini-strip */}
          <div className="bg-surface border border-divider rounded-lg p-3">
            <div className="text-[10px] uppercase tracking-wider font-bold text-ink-mute mb-2">Pipeline · April 2026</div>
            <div className="flex items-center gap-1">
              {pipelineStages.map((stage, i) => {
                const count = counts[stage] ?? 0
                const isCurrent = statusFilter === stage
                return (
                  <React.Fragment key={stage}>
                    <button onClick={() => setStatusFilter(stage)}
                      className={cn(
                        "flex-1 px-3 py-2 rounded-md text-left border transition-colors",
                        isCurrent ? "bg-brand-soft border-brand-mid" : "bg-cream/40 border-divider hover:bg-cream"
                      )}>
                      <div className="text-[10px] uppercase tracking-wider font-bold text-ink-mute">{PR_STATUS_LABEL[stage]}</div>
                      <div className="font-serif text-2xl text-ink leading-none mt-1">{count}</div>
                    </button>
                    {i < pipelineStages.length - 1 && <Icon name="chevron-right" size={14} className="text-ink-faint shrink-0" />}
                  </React.Fragment>
                )
              })}
            </div>
          </div>

          {/* Table */}
          <div className="bg-surface border border-divider rounded-lg overflow-hidden">
            <header className="px-4 py-2.5 border-b border-divider bg-cream/50 flex items-center justify-between">
              <div className="text-[11px] font-bold uppercase tracking-wider text-ink-mute">
                Requests · {rows.length} of {PRS.length}
              </div>
              <div className="text-[10px] text-ink-mute">Sorted by need-by date</div>
            </header>
            {rows.length === 0 ? (
              <div className="p-12 text-center text-ink-mute text-[12px]">No requests match these filters.</div>
            ) : (
              <div className="overflow-x-auto">
              <table className="w-full text-[12px]">
                <thead className="text-[10px] uppercase tracking-wider text-ink-mute font-sans">
                  <tr className="border-b border-divider-soft [&>th]:px-3 [&>th]:py-2 [&>th]:text-left [&>th]:font-bold">
                    <th>OR #</th>
                    <th>Title · Items</th>
                    <th>
                      <span className="inline-flex items-center gap-1">
                        Requestor
                        <ExcelFilter column="requestor" label="Requestor" values={distinctRequestor} filters={colFilters} setFilters={setColFilters} />
                      </span>
                    </th>
                    <th>
                      <span className="inline-flex items-center gap-1">
                        Dept
                        <ExcelFilter column="department" label="Dept" values={distinctDept} filters={colFilters} setFilters={setColFilters} />
                      </span>
                    </th>
                    <th>Need By</th>
                    <th className="text-right">Est. Value</th>
                    <th>Status</th>
                  </tr>
                </thead>
                <tbody>
                  {rows.map(pr => <PRRow key={pr.id} pr={pr} onClick={() => setSelected(pr)} />)}
                </tbody>
              </table>
              </div>
            )}
          </div>

        </div>
      </div>

      {selected && <PRDetailSheet pr={selected} onClose={() => setSelected(null)} push={push} />}
      <OrderRequestForm open={formOpen} onClose={() => setFormOpen(false)} />
    </>
  )
}

/* ─── Row ────────────────────────────────────────────────────────────────── */
function PRRow({ pr, onClick }: { pr: PR; onClick: () => void }) {
  const symbol = pr.currency === "PHP" ? "₱" : pr.currency === "SGD" ? "S$" : pr.currency === "HKD" ? "HK$" : "$"
  return (
    <tr onClick={onClick}
        className="border-t border-divider-soft hover:bg-cream/60 cursor-pointer [&>td]:px-3 [&>td]:py-2.5 align-top transition-colors">
      <td>
        <div className="font-mono font-bold text-brand-mid text-[11px]">{pr.id}</div>
        <div className="text-[9.5px] text-ink-mute mt-0.5">{pr.daysOpen}d open</div>
      </td>
      <td>
        <div className="font-semibold text-ink leading-snug max-w-md flex items-center gap-1.5">
          {pr.title}
          {pr.urgent && <Badge variant="danger">URGENT</Badge>}
        </div>
        <div className="text-[10.5px] text-ink-mute mt-0.5 max-w-md truncate">{pr.itemSummary}</div>
      </td>
      <td>
        <div className="flex items-center gap-2">
          <Avatar initials={pr.requestor.initials} tone={pr.requestor.tone as any} size="sm" />
          <div>
            <div className="text-[11.5px] text-ink-soft">{pr.requestor.name}</div>
            <div className="text-[9.5px] text-ink-mute">{pr.costCenter}</div>
          </div>
        </div>
      </td>
      <td><span className="text-[11px] text-ink-soft">{pr.department}</span></td>
      <td>
        <div className="text-[11px] text-ink-soft">{pr.needBy.replace(", 2026", "")}</div>
        {pr.urgent && <div className="text-[10px] text-danger font-semibold">expediting</div>}
      </td>
      <td className="text-right">
        <div className="font-mono font-semibold text-ink">{symbol}{pr.totalEst.toLocaleString()}</div>
        <div className="text-[9.5px] text-ink-mute">{pr.lineCount} line{pr.lineCount > 1 ? "s" : ""}</div>
      </td>
      <td>
        <Badge variant={PR_STATUS_TONE[pr.status] as any} dot>{PR_STATUS_LABEL[pr.status]}</Badge>
        {pr.status === "sourced" && pr.quotesReceived != null && (
          <div className="text-[9.5px] text-ink-mute mt-0.5">{pr.quotesReceived} / {pr.quotesExpected} quotes</div>
        )}
        {pr.status === "converted" && pr.convertedTo && (
          <div className="text-[9.5px] text-brand-mid font-mono mt-0.5">→ {pr.convertedTo[0]}</div>
        )}
      </td>
    </tr>
  )
}

/* ─── Detail slideout ────────────────────────────────────────────────────── */
function PRDetailSheet({ pr, onClose, push }: { pr: PR; onClose: () => void; push: (r: string) => void }) {
  const symbol = pr.currency === "PHP" ? "₱" : pr.currency === "SGD" ? "S$" : pr.currency === "HKD" ? "HK$" : "$"
  return (
    <Sheet open={true} onOpenChange={() => onClose()} side="right" className="w-[560px]">
      <SheetHeader>
        <div className="flex items-start justify-between gap-3">
          <div>
            <div className="flex items-center gap-2">
              <div className="font-mono text-[10px] text-ink-mute">{pr.id}</div>
              {pr.urgent && <Badge variant="danger">URGENT</Badge>}
            </div>
            <h2 className="font-serif text-xl text-ink mt-1 leading-tight">{pr.title}</h2>
            <div className="text-[11px] text-ink-soft mt-1.5">{pr.department} · <span className="font-mono">{pr.costCenter}</span></div>
          </div>
          <Badge variant={PR_STATUS_TONE[pr.status] as any} dot>{PR_STATUS_LABEL[pr.status]}</Badge>
        </div>
      </SheetHeader>

      <div className="flex-1 overflow-y-auto p-5 space-y-5">

        {/* Summary card */}
        <section>
          <div className="grid grid-cols-3 gap-3">
            <div className="bg-cream/60 border border-divider rounded-md p-3">
              <div className="text-[9px] uppercase tracking-wider font-bold text-ink-mute">Est. Value</div>
              <div className="font-serif text-xl text-ink mt-0.5">{symbol}{pr.totalEst.toLocaleString()}</div>
              <div className="text-[10px] text-ink-mute">{pr.currency}</div>
            </div>
            <div className="bg-cream/60 border border-divider rounded-md p-3">
              <div className="text-[9px] uppercase tracking-wider font-bold text-ink-mute">Need By</div>
              <div className="font-serif text-xl text-ink mt-0.5">{pr.needBy.replace(", 2026", "")}</div>
              <div className="text-[10px] text-ink-mute">{pr.daysOpen}d open</div>
            </div>
            <div className="bg-cream/60 border border-divider rounded-md p-3">
              <div className="text-[9px] uppercase tracking-wider font-bold text-ink-mute">Lines</div>
              <div className="font-serif text-xl text-ink mt-0.5">{pr.lineCount}</div>
              <div className="text-[10px] text-ink-mute">line items</div>
            </div>
          </div>
        </section>

        {/* Requestor */}
        <section>
          <div className="text-[10px] uppercase tracking-wider font-bold text-ink-mute mb-2">Requestor</div>
          <div className="bg-surface border border-divider rounded-md p-3 flex items-center justify-between">
            <div className="flex items-center gap-3">
              <Avatar initials={pr.requestor.initials} tone={pr.requestor.tone as any} size="md" />
              <div>
                <div className="font-semibold text-ink text-[13px]">{pr.requestor.name}</div>
                <div className="text-[11px] text-ink-mute">{pr.department} · {pr.costCenter}</div>
              </div>
            </div>
            <Button variant="ghost" size="sm" trailingIcon="arrow-right">View profile</Button>
          </div>
        </section>

        {/* Items */}
        <section>
          <div className="text-[10px] uppercase tracking-wider font-bold text-ink-mute mb-2">Requested Items</div>
          <div className="bg-surface border border-divider rounded-md p-3">
            <div className="text-[12.5px] text-ink leading-relaxed">{pr.itemSummary}</div>
          </div>
        </section>

        {/* Justification */}
        {pr.justification && (
          <section>
            <div className="text-[10px] uppercase tracking-wider font-bold text-ink-mute mb-2">Justification</div>
            <div className="bg-warn-soft/40 border border-warn/30 rounded-md p-3">
              <div className="text-[12px] text-ink-soft leading-relaxed italic">"{pr.justification}"</div>
            </div>
          </section>
        )}

        {/* Approval chain */}
        {pr.approvers && pr.approvers.length > 0 && (
          <section>
            <div className="text-[10px] uppercase tracking-wider font-bold text-ink-mute mb-2">Approval Chain</div>
            <div className="bg-surface border border-divider rounded-md divide-y divide-divider-soft">
              {pr.approvers.map((a, i) => (
                <div key={i} className="px-3 py-2.5 flex items-center justify-between">
                  <div className="flex items-center gap-2.5">
                    <Avatar initials={a.initials} tone={a.tone as any} size="sm" />
                    <div>
                      <div className="text-[12px] font-semibold text-ink">{a.name}</div>
                      <div className="text-[10px] text-ink-mute">Approver {i + 1} of {pr.approvers!.length}</div>
                    </div>
                  </div>
                  {a.decision === "approved"   && <Badge variant="success" dot>Approved</Badge>}
                  {a.decision === "rejected"   && <Badge variant="danger" dot>Rejected</Badge>}
                  {(a.decision === "pending" || !a.decision) && <Badge variant="warn" dot>Pending</Badge>}
                </div>
              ))}
            </div>
          </section>
        )}

        {/* Converted */}
        {pr.convertedTo && (
          <section>
            <div className="text-[10px] uppercase tracking-wider font-bold text-ink-mute mb-2">Converted to PO</div>
            <div className="bg-brand-soft/50 border border-brand/30 rounded-md p-3 flex items-center justify-between">
              <div className="flex items-center gap-2">
                <Icon name="check" size={14} className="text-brand" />
                <span className="text-[12px] text-ink"><strong>PO issued</strong> · {pr.convertedTo.length} purchase order{pr.convertedTo.length > 1 ? "s" : ""}</span>
              </div>
              <Button variant="ghost" size="sm" trailingIcon="arrow-right" onClick={() => push(`/procurement/po/${pr.convertedTo![0]}`)}>
                <span className="font-mono">{pr.convertedTo[0]}</span>
              </Button>
            </div>
          </section>
        )}

      </div>

      <footer className="border-t border-divider px-5 py-3 flex items-center justify-between gap-2 shrink-0">
        <Button variant="ghost" onClick={onClose}>Close</Button>
        <div className="flex items-center gap-2">
          {(pr.status === "submitted" || pr.status === "review") && (
            <>
              <Button variant="ghost" leadingIcon="x" className="text-danger"
                onClick={() => { (window as any).cenoraToast?.(`Rejected · ${pr.id}`, { variant: "danger", sub: `${pr.requestor.name} notified · workflow stopped` }); onClose() }}>
                Reject
              </Button>
              <Button variant="primary" leadingIcon="check"
                onClick={() => { (window as any).cenoraToast?.(`Approved · ${pr.id}`, { variant: "success", sub: `Routed to next approver · ${pr.title.slice(0, 48)}${pr.title.length > 48 ? "…" : ""}` }); onClose() }}>
                Approve
              </Button>
            </>
          )}
          {pr.status === "approved" && (
            <Button variant="primary" leadingIcon="arrow-right" onClick={() => push("/procurement/po/new")}>Convert to PO</Button>
          )}
          {pr.status === "sourced" && (
            <Button variant="primary" leadingIcon="users"
              onClick={() => (window as any).cenoraToast?.(`Comparing quotes · ${pr.id}`, { variant: "info", sub: `${pr.quotesReceived}/${pr.quotesExpected} vendor quotes received` })}>
              Compare quotes
            </Button>
          )}
          {pr.status === "converted" && pr.convertedTo && (
            <Button variant="primary" leadingIcon="external" onClick={() => push(`/procurement/po/${pr.convertedTo![0]}`)}>Open PO</Button>
          )}
        </div>
      </footer>
    </Sheet>
  )
}

// SANDBOX
;(globalThis as any).PRList = PRList

})();/*__IIFE_WRAP_END__*/

/* ═════ apps/web/components/procurement/order-request-form.tsx ═════ */
;/*__IIFE_WRAP_START__*/(function(){
/**
 * ============================================================================
 * apps/web/components/procurement/order-request-form.tsx
 * ----------------------------------------------------------------------------
 * Order Request creation sheet — opens from the "+ New OR" button on the
 * Order Requests list. A right-side <Sheet> with the essential fields needed
 * to create a `cnr_purchaserequest` record. Submit toasts and closes; the
 * row would appear in the list once the backend is wired.
 *
 * Internal naming note: the underlying doctype is still `cnr_purchaserequest`
 * (schema-level). User-facing terminology is "Order Request" / "OR".
 * ============================================================================
 */

interface OrderRequestFormProps {
  open: boolean
  onClose: () => void
}

const DEPTS = [
  "Operations", "Construction", "IT", "Procurement", "Facilities",
  "HR", "Finance", "Sales", "Engineering", "Quality", "Logistics",
]

const COST_CENTERS = [
  "OPS-CAL-PPE", "OPS-CAL-CHEM", "OPS-CEB-SOLAR",
  "IT-INFRA-HQ", "IT-CEB-INFRA", "IT-LIC-2026", "IT-HW-DEV",
  "PROJ-CAL-P1", "PROJ-CAL-P2",
  "GA-HQ-MNL", "FAC-LIPA-CAN",
]

function OrderRequestForm({ open, onClose }: OrderRequestFormProps) {
  const shell = useShell()
  const [title, setTitle]          = React.useState("")
  const [department, setDepartment] = React.useState("Operations")
  const [costCenter, setCostCenter] = React.useState("OPS-CAL-PPE")
  const [needBy, setNeedBy]        = React.useState("")
  const [currency, setCurrency]    = React.useState<"PHP" | "SGD" | "HKD" | "AUD" | "INR" | "USD">(shell.entity.currency as any || "PHP")
  const [estValue, setEstValue]    = React.useState("")
  const [urgent, setUrgent]        = React.useState(false)
  const [items, setItems]          = React.useState("")
  const [justification, setJustification] = React.useState("")
  const [submitting, setSubmitting] = React.useState(false)

  /* Reset when sheet reopens */
  React.useEffect(() => {
    if (!open) return
    /* keep state across reopens? for demo, reset */
    setTitle(""); setNeedBy(""); setEstValue(""); setItems(""); setJustification("")
    setUrgent(false)
  }, [open])

  const symbol = currency === "PHP" ? "₱" : currency === "SGD" ? "S$" : currency === "HKD" ? "HK$"
              : currency === "AUD" ? "A$" : currency === "INR" ? "₹" : "$"

  /* Synth a next OR id based on the current entity */
  const nextId = React.useMemo(() => {
    const entity = (shell.entity.code === "HVG" || shell.entity.kind === "group") ? "HVPH" : shell.entity.code
    const seq = 2211 + Math.floor(Math.random() * 3)
    return `OR-${entity}-${seq}`
  }, [shell.entity, open])

  const valid = title.trim().length > 0 && items.trim().length > 0

  function submit(asDraft: boolean) {
    if (submitting) return
    if (!asDraft && !valid) {
      (window as any).cenoraToast?.("Required fields missing", { variant: "warn", sub: "Title and at least one item are required" })
      return
    }
    setSubmitting(true)
    setTimeout(() => {
      setSubmitting(false)
      const v = Number(estValue.replace(/[^\d.]/g, "")) || 0
      const action = asDraft ? "Draft saved" : "Submitted for approval"
      const sub = asDraft
        ? `${nextId} · ${title || "(untitled)"} · saved to drafts`
        : `${nextId} · ${title} · ${symbol}${v.toLocaleString()} · routed to first approver`
      ;(window as any).cenoraToast?.(action, { variant: "success", sub })
      onClose()
    }, 350)
  }

  return (
    <Sheet open={open} onOpenChange={v => !v && onClose()} side="right" className="w-[600px]">
      <SheetHeader>
        <div className="flex items-start justify-between gap-3">
          <div>
            <div className="font-mono text-[10px] text-ink-mute">{nextId}</div>
            <h2 className="font-serif text-xl text-ink mt-1 leading-tight">New Order Request</h2>
            <div className="text-[11px] text-ink-soft mt-1.5">Internal request for goods or services · routes for approval before becoming a PO</div>
          </div>
          <Badge variant="info" dot>Draft</Badge>
        </div>
      </SheetHeader>

      <div className="flex-1 overflow-y-auto p-5 space-y-5">

        {/* Title */}
        <FieldGroup label="Title" required hint="A short, descriptive line — what you need and for whom.">
          <input
            value={title} onChange={e => setTitle(e.target.value)}
            placeholder="e.g. Q3 PPE replenishment — Calamba site"
            className="w-full h-9 px-3 bg-surface border border-divider rounded-md text-[13px] focus:border-brand-mid outline-none" />
        </FieldGroup>

        {/* Dept + Cost Center */}
        <div className="grid grid-cols-2 gap-3">
          <FieldGroup label="Department" required>
            <select value={department} onChange={e => setDepartment(e.target.value)}
              className="w-full h-9 px-3 bg-surface border border-divider rounded-md text-[13px] focus:border-brand-mid outline-none">
              {DEPTS.map(d => <option key={d} value={d}>{d}</option>)}
            </select>
          </FieldGroup>
          <FieldGroup label="Cost Center" required>
            <select value={costCenter} onChange={e => setCostCenter(e.target.value)}
              className="w-full h-9 px-3 bg-surface border border-divider rounded-md text-[13px] font-mono focus:border-brand-mid outline-none">
              {COST_CENTERS.map(c => <option key={c} value={c}>{c}</option>)}
            </select>
          </FieldGroup>
        </div>

        {/* Need-by + Urgent */}
        <div className="grid grid-cols-[1fr_auto] gap-3 items-end">
          <FieldGroup label="Need By" required hint="Latest acceptable delivery date.">
            <input type="date" value={needBy} onChange={e => setNeedBy(e.target.value)}
              className="w-full h-9 px-3 bg-surface border border-divider rounded-md text-[13px] focus:border-brand-mid outline-none" />
          </FieldGroup>
          <button onClick={() => setUrgent(u => !u)}
            className={cn(
              "h-9 px-3 rounded-md text-[12px] font-semibold inline-flex items-center gap-1.5 border transition-colors",
              urgent ? "bg-danger text-white border-danger" : "bg-surface border-divider text-ink-soft hover:border-divider-strong"
            )}>
            <Icon name="alert-triangle" size={13} /> Urgent
          </button>
        </div>

        {/* Currency + Est Value */}
        <div className="grid grid-cols-[100px_1fr] gap-3">
          <FieldGroup label="Currency">
            <select value={currency} onChange={e => setCurrency(e.target.value as any)}
              className="w-full h-9 px-3 bg-surface border border-divider rounded-md text-[13px] font-mono focus:border-brand-mid outline-none">
              <option value="PHP">PHP</option>
              <option value="SGD">SGD</option>
              <option value="HKD">HKD</option>
              <option value="AUD">AUD</option>
              <option value="INR">INR</option>
              <option value="USD">USD</option>
            </select>
          </FieldGroup>
          <FieldGroup label="Estimated Value" hint="Rough total — refined during sourcing.">
            <div className="relative">
              <span className="absolute left-3 top-1/2 -translate-y-1/2 text-[12px] text-ink-mute font-mono">{symbol}</span>
              <input
                value={estValue} onChange={e => setEstValue(e.target.value)}
                placeholder="0"
                className="w-full h-9 pl-8 pr-3 bg-surface border border-divider rounded-md text-[13px] font-mono focus:border-brand-mid outline-none" />
            </div>
          </FieldGroup>
        </div>

        {/* Items */}
        <FieldGroup label="Requested Items" required hint="One per line, or use ` · ` separators. Codes are optional at OR stage.">
          <textarea
            value={items} onChange={e => setItems(e.target.value)}
            rows={4}
            placeholder={"Hard hats × 40\nSafety vests × 60\nWork gloves × 200"}
            className="w-full p-3 bg-surface border border-divider rounded-md text-[13px] font-mono focus:border-brand-mid outline-none resize-y" />
        </FieldGroup>

        {/* Justification */}
        <FieldGroup label="Justification" hint="Why now? Helps approvers decide quickly.">
          <textarea
            value={justification} onChange={e => setJustification(e.target.value)}
            rows={3}
            placeholder="Current stock running out by end of month; field crew already short on vests."
            className="w-full p-3 bg-surface border border-divider rounded-md text-[13px] focus:border-brand-mid outline-none resize-y" />
        </FieldGroup>

        {/* Routing preview */}
        <section>
          <div className="text-[10px] uppercase tracking-wider font-bold text-ink-mute mb-2">Approval Routing (auto-calculated)</div>
          <div className="bg-cream/40 border border-divider rounded-md divide-y divide-divider-soft text-[12px]">
            <RoutingRow step={1} who="Department Head" who2={department + " Lead"} />
            <RoutingRow step={2} who="Procurement Director" who2="Maya C." />
            {Number(estValue.replace(/[^\d.]/g, "")) >= 50000 && (
              <RoutingRow step={3} who="CFO" who2="Anil V." note="auto-added — value ≥ 50k" />
            )}
          </div>
        </section>

      </div>

      <footer className="border-t border-divider px-5 py-3 flex items-center justify-between gap-2 shrink-0">
        <Button variant="ghost" onClick={onClose} disabled={submitting}>Cancel</Button>
        <div className="flex items-center gap-2">
          <Button variant="ghost" onClick={() => submit(true)} disabled={submitting}>Save draft</Button>
          <Button variant="primary" leadingIcon="check" onClick={() => submit(false)} disabled={submitting || !valid}>
            {submitting ? "Submitting…" : "Submit for approval"}
          </Button>
        </div>
      </footer>
    </Sheet>
  )
}

/* ── Small form helpers ────────────────────────────────────────────────── */
function FieldGroup({ label, required, hint, children }: { label: string; required?: boolean; hint?: string; children: React.ReactNode }) {
  return (
    <div>
      <label className="text-[10px] uppercase tracking-wider font-bold text-ink-mute flex items-center gap-1.5 mb-1">
        {label}
        {required && <span className="text-danger">*</span>}
      </label>
      {children}
      {hint && <div className="text-[10.5px] text-ink-mute mt-1">{hint}</div>}
    </div>
  )
}

function RoutingRow({ step, who, who2, note }: { step: number; who: string; who2: string; note?: string }) {
  return (
    <div className="px-3 py-2 flex items-center gap-3">
      <div className="size-5 rounded-full bg-brand-soft text-brand text-[10px] font-bold inline-flex items-center justify-center shrink-0">{step}</div>
      <div className="flex-1 min-w-0">
        <div className="text-ink font-semibold">{who}</div>
        <div className="text-[10.5px] text-ink-mute">{who2}</div>
      </div>
      {note && <span className="text-[10px] text-ink-mute italic">{note}</span>}
    </div>
  )
}

// SANDBOX
;(globalThis as any).OrderRequestForm = OrderRequestForm

})();/*__IIFE_WRAP_END__*/

/* ═════ apps/web/components/procurement/po-list.tsx ═════ */
;/*__IIFE_WRAP_START__*/(function(){
/**
 * ============================================================================
 * apps/web/components/procurement/po-list.tsx
 * ----------------------------------------------------------------------------
 * Screen 07 — Purchase Order list. Filterable, sortable, click a row to open
 * the PO detail (Screen 08). Includes the V1 summary strip and 3-way-match
 * indicator per row.
 * ============================================================================
 */

const PO_STATUS_VARIANT: Record<string, any> = {
  draft: "neutral", sent: "info", partial: "warn", received: "success",
  overdue: "danger", cancelled: "neutral", "in-progress": "info",
}

function POList() {
  const { push } = useRouter()
  const [filter, setFilter] = React.useState<"all" | "open" | "overdue" | "partial" | "received" | "starred">("all")
  const [sort, setSort] = React.useState<"date" | "amount" | "vendor">("date")
  const [query, setQuery] = React.useState("")
  const [colFilters, setColFilters] = React.useState<Record<string, { values: string[]; sort?: "asc" | "desc" } | undefined>>({})

  /* Distinct values for column filters */
  const distinctVendor   = React.useMemo(() => Array.from(new Set((PO_DATA as any[]).map((p: any) => p.vendor.name))), [])
  const distinctCategory = React.useMemo(() => Array.from(new Set((PO_DATA as any[]).map((p: any) => p.vendor.category))), [])
  const distinctMatch    = React.useMemo(() => Array.from(new Set((PO_DATA as any[]).map((p: any) => p.match))), [])

  const filtered = React.useMemo(() => {
    let rows = PO_DATA as any[]
    if (filter === "open")     rows = rows.filter(p => p.status !== "received" && p.status !== "cancelled")
    if (filter === "overdue")  rows = rows.filter(p => p.status === "overdue")
    if (filter === "partial")  rows = rows.filter(p => p.status === "partial")
    if (filter === "received") rows = rows.filter(p => p.status === "received")
    if (filter === "starred")  rows = rows.filter(p => p.starred)
    if (query) {
      const q = query.toLowerCase()
      rows = rows.filter(p => (p.id + " " + p.vendor.name + " " + p.items).toLowerCase().includes(q))
    }
    /* Column-header filters */
    rows = rows.filter(p => applyExcelFilters(p, colFilters, [
      { key: "vendor",   accessor: (x: any) => x.vendor.name },
      { key: "category", accessor: (x: any) => x.vendor.category },
      { key: "match" },
    ]))
    rows = [...rows].sort((a, b) => {
      if (sort === "amount") return b.amount - a.amount
      if (sort === "vendor") return a.vendor.name.localeCompare(b.vendor.name)
      return new Date(b.expectedISO).getTime() - new Date(a.expectedISO).getTime()
    })
    return rows
  }, [filter, sort, query, colFilters])

  const totals = React.useMemo(() => {
    const open = (PO_DATA as any[]).filter(p => p.status !== "received" && p.status !== "cancelled")
    return {
      total: PO_DATA.length,
      openValue: open.reduce((s, p) => s + p.amount, 0),
      overdue: (PO_DATA as any[]).filter(p => p.status === "overdue").length,
      partial: (PO_DATA as any[]).filter(p => p.status === "partial").length,
      receivedValue: (PO_DATA as any[]).filter(p => p.status === "received").reduce((s, p) => s + p.amount, 0),
    }
  }, [])

  /* Real handlers */
  const onExport = () => (window as any).cenoraToast?.("Exported", { variant: "success", sub: `${filtered.length} purchase orders · CSV downloaded` })
  const onNewPO  = () => push("/procurement/po/new")
  const onColumns = () => (window as any).cenoraToast?.("Column picker", { variant: "info", sub: "Choose visible columns · saves per-user" })

  return (
    <>
      <TopBar
        breadcrumb={[{ label: "Procurement" }, { label: "Purchase Orders" }]}
      />

      <ActionBar
        title={<T>Purchase Orders</T>}
        status={<><span className="font-mono">cnr_purchaseorder</span> · {totals.total} total · {formatCurrency(totals.openValue)} open · <span className="text-danger font-semibold">{totals.overdue} overdue</span></>}
        search={<SearchBox value={query} onChange={setQuery} placeholder="Search POs, vendors, items…" className="w-64" />}
        extras={
          <Select value={sort} onChange={e => setSort(e.target.value as any)} className="h-8 text-xs w-40">
            <option value="date">Sort: PO Date ↓</option>
            <option value="amount">Sort: Amount ↓</option>
            <option value="vendor">Sort: Vendor A–Z</option>
          </Select>
        }
        secondary={<><Button variant="ghost" leadingIcon="settings" onClick={onColumns}>Columns</Button><Button variant="ghost" leadingIcon="download" onClick={onExport}>Export</Button></>}
        primary={<Button variant="primary" leadingIcon="plus" onClick={onNewPO}>New PO</Button>}
        filters={
          <>
            <FilterChip active={filter === "all"}      onClick={() => setFilter("all")} count={PO_DATA.length}>All</FilterChip>
            <FilterChip active={filter === "open"}     onClick={() => setFilter("open")} count={(PO_DATA as any[]).filter(p => p.status !== "received" && p.status !== "cancelled").length}>Open</FilterChip>
            <FilterChip active={filter === "overdue"}  tone="danger" onClick={() => setFilter("overdue")} count={totals.overdue} icon="alert-triangle">Overdue</FilterChip>
            <FilterChip active={filter === "partial"}  onClick={() => setFilter("partial")} count={totals.partial}>Partial Receipt</FilterChip>
            <FilterChip active={filter === "received"} onClick={() => setFilter("received")} count={(PO_DATA as any[]).filter(p => p.status === "received").length}>Fully Received</FilterChip>
            <FilterChip active={filter === "starred"}  onClick={() => setFilter("starred")} icon="star">Starred</FilterChip>
          </>
        }
      />

      {/* Summary strip */}
      <div className="shrink-0 px-5 py-2.5 bg-cream border-b border-divider flex flex-wrap gap-x-6 gap-y-1 text-xs text-ink-mute">
        <span>Total POs: <strong className="text-ink font-bold">{totals.total}</strong></span>
        <span>Open value: <strong className="text-ink font-bold">{formatCurrency(totals.openValue)}</strong></span>
        <span>Overdue: <strong className="text-danger font-bold">{totals.overdue} POs</strong></span>
        <span>Partial receipt: <strong className="text-warn font-bold">{totals.partial} POs</strong></span>
        <span>Received this month: <strong className="text-success font-bold">{formatCurrency(totals.receivedValue)}</strong></span>
      </div>

      <div className="flex-1 overflow-y-auto bg-surface">
        <div className="overflow-x-auto">
        <table className="w-full text-sm">
          <thead className="bg-cream sticky top-0 z-10 border-b-2 border-divider">
            <tr className="text-left text-[10px] font-bold uppercase tracking-wider text-ink-mute">
              <th className="pl-5 pr-2 py-2.5 w-10"><input type="checkbox" className="size-3.5 rounded-sm border-divider align-middle" /></th>
              <th className="px-3 py-2.5">PO Number</th>
              <th className="px-3 py-2.5">
                <span className="inline-flex items-center gap-1">
                  Vendor
                  <ExcelFilter column="vendor" label="Vendor" values={distinctVendor} filters={colFilters} setFilters={setColFilters} />
                </span>
              </th>
              <th className="px-3 py-2.5">
                <span className="inline-flex items-center gap-1">
                  Category
                  <ExcelFilter column="category" label="Category" values={distinctCategory} filters={colFilters} setFilters={setColFilters} />
                </span>
              </th>
              <th className="px-3 py-2.5">Items</th>
              <th className="px-3 py-2.5">PO Date</th>
              <th className="px-3 py-2.5">Expected Receipt</th>
              <th className="px-3 py-2.5 text-right">Amount</th>
              <th className="px-3 py-2.5">
                <span className="inline-flex items-center gap-1">
                  3-Way Match
                  <ExcelFilter column="match" label="3-Way Match" values={distinctMatch} filters={colFilters} setFilters={setColFilters} />
                </span>
              </th>
              <th className="px-3 py-2.5">Status</th>
              <th className="px-5 py-2.5"></th>
            </tr>
          </thead>
          <tbody>
            {filtered.map(p => (
              <tr key={p.id}
                onClick={() => push(`/procurement/po/${p.id}`)}
                className={cn(
                  "border-b border-divider cursor-pointer transition-colors",
                  p.status === "overdue" ? "bg-warn-soft/35 hover:bg-warn-soft/70" : "hover:bg-brand-soft",
                )}>
                <td className="pl-5 pr-2 py-3" onClick={e => e.stopPropagation()}>
                  <input type="checkbox" className="size-3.5 rounded-sm border-divider align-middle" />
                </td>
                <td className="px-3 py-3 whitespace-nowrap">
                  <span className="font-mono font-bold text-brand-mid text-xs">{p.id}</span>
                  {p.daysLate && <span className="ml-1.5 inline-block text-[9px] font-bold uppercase tracking-wider bg-danger text-white px-1.5 py-px rounded-sm align-middle">overdue</span>}
                </td>
                <td className="px-3 py-3"><div className="font-semibold text-ink">{p.vendor.name}</div></td>
                <td className="px-3 py-3 text-[11px] text-ink-mute">{p.vendor.category}</td>
                <td className="px-3 py-3 text-xs">{p.items}</td>
                <td className="px-3 py-3 text-xs text-ink-mute whitespace-nowrap">{p.poDate}</td>
                <td className={cn("px-3 py-3 text-xs whitespace-nowrap", p.daysLate ? "text-danger font-bold" : "text-ink-mute")}>{p.expected}</td>
                <td className="px-3 py-3 text-right font-serif font-normal text-[15px] text-ink whitespace-nowrap">{formatCurrency(p.amount)}</td>
                <td className="px-3 py-3 text-[11px] whitespace-nowrap">
                  {p.match === "matched" && <span className="text-success inline-flex items-center gap-1"><Icon name="check" size={11} strokeWidth={3} /> Matched</span>}
                  {p.match === "pending" && <span className="text-warn inline-flex items-center gap-1"><Icon name="clock" size={11} /> Pending</span>}
                  {p.match === "partial" && <span className="text-warn inline-flex items-center gap-1"><Icon name="clock" size={11} /> Partial</span>}
                  {p.match === "no-ir"   && <span className="text-danger inline-flex items-center gap-1"><Icon name="alert-triangle" size={11} /> No IR</span>}
                  {p.match === "service" && <span className="text-ink-mute">— Service</span>}
                </td>
                <td className="px-3 py-3"><Badge variant={PO_STATUS_VARIANT[p.status]} dot>{(PO_STATUS_LABEL as any)[p.status]}</Badge></td>
                <td className="pl-3 pr-5 py-3 text-right" onClick={e => e.stopPropagation()}>
                  {(p.status === "overdue") ? (
                    <button className="inline-flex items-center gap-1 px-2 py-1 bg-brand-soft text-brand text-[11px] font-semibold rounded-md hover:bg-cream-deep">
                      Chase <Icon name="arrow-right" size={11} />
                    </button>
                  ) : (
                    <button onClick={() => push(`/procurement/po/${p.id}`)} className="inline-flex items-center gap-1 px-2 py-1 bg-brand-soft text-brand text-[11px] font-semibold rounded-md hover:bg-cream-deep">
                      View <Icon name="arrow-right" size={11} />
                    </button>
                  )}
                </td>
              </tr>
            ))}
            {filtered.length === 0 && (
              <tr><td colSpan={11} className="px-5 py-12 text-center text-ink-mute text-sm">No POs match the current filters.</td></tr>
            )}
          </tbody>
        </table>
        </div>
      </div>
    </>
  )
}

// SANDBOX
;(globalThis as any).POList = POList
;(globalThis as any).PO_STATUS_VARIANT = PO_STATUS_VARIANT

})();/*__IIFE_WRAP_END__*/

/* ═════ apps/web/components/procurement/po-form.tsx ═════ */
;/*__IIFE_WRAP_START__*/(function(){
/**
 * ============================================================================
 * apps/web/components/procurement/po-form.tsx
 * ----------------------------------------------------------------------------
 * Screen 08 — Purchase Order detail/form. 6-step workflow stepper,
 * inline line-item editing, PH VAT + EWT auto-calc, AI bundle suggestion,
 * workflow status side panel.
 *
 * Used for both viewing (/procurement/po/[id]) and creating (/procurement/po/new).
 * When `poId` is provided we load that PO from mock data; otherwise fresh state.
 * ============================================================================
 */

const PO_STEPS = ["Draft", "Approved", "Sent", "Item Receipt", "3-Way Match", "Invoice Posted"] as const

interface POLine {
  line: number
  itemCode: string
  description: string
  qty: number
  uom: string
  unitPrice: number
}

function POForm({ poId }: { poId?: string }) {
  const { push } = useRouter()
  const existing = poId ? (PO_BY_ID as any)[poId] : null
  const isNew = !existing

  /* Stepper state derived from PO status */
  const currentStep = !existing ? 0
    : existing.status === "received"   ? 5
    : existing.status === "partial"    ? 3
    : existing.status === "overdue"    ? 2  /* sent but late */
    : existing.status === "sent"       ? 2
    : 0

  const [lines, setLines] = React.useState<POLine[]>(
    existing?.lines?.length
      ? existing.lines
      : [{ line: 10, itemCode: "", description: "", qty: 1, uom: "PC", unitPrice: 0 }]
  )
  const [vendor] = React.useState(existing?.vendor ?? { name: "Select vendor…", category: "", tin: "" })

  /* PH VAT (12%) + EWT (2%) auto-calc */
  const subtotal = lines.reduce((s, l) => s + l.qty * l.unitPrice, 0)
  const vat = subtotal * 0.12
  const ewt = -subtotal * 0.02
  const total = subtotal + vat + ewt

  const addLine = () => setLines(arr => [
    ...arr,
    { line: (arr.at(-1)?.line ?? 0) + 10, itemCode: "", description: "", qty: 1, uom: "PC", unitPrice: 0 },
  ])
  const removeLine = (line: number) => setLines(arr => arr.filter(l => l.line !== line))
  const update = (line: number, patch: Partial<POLine>) =>
    setLines(arr => arr.map(l => l.line === line ? { ...l, ...patch } : l))

  return (
    <>
      <TopBar
        breadcrumb={[
          { label: "Procurement" },
          { label: "Purchase Orders", href: "/procurement/po" },
          { label: existing?.id ?? "New PO" },
        ]}
        onNavigate={push}
        actions={
          <>
            <Button variant="ghost">Save Draft</Button>
            {existing?.status === "overdue" && <Button variant="danger" leadingIcon="message">Chase Vendor</Button>}
            <Button variant="primary" trailingIcon="arrow-right">
              {isNew ? "Submit for Approval" : "Open in workflow"}
            </Button>
          </>
        }
      />

      <div className="shrink-0 bg-surface border-b border-divider px-6 py-3.5 overflow-x-auto">
        <div className="min-w-[920px]">
          <Stepper steps={PO_STEPS as any} current={currentStep} />
        </div>
      </div>

      <div className="flex-1 overflow-y-auto bg-app">
        <div className="max-w-[1400px] mx-auto p-6 grid grid-cols-[1fr_300px] gap-5">
          <div className="flex flex-col gap-4 min-w-0">

            {/* HEADER */}
            <Card>
              <CardHeader>
                <CardTitle>PO Header</CardTitle>
                {existing && <Badge variant={PO_STATUS_VARIANT[existing.status]} dot>{(PO_STATUS_LABEL as any)[existing.status]}</Badge>}
              </CardHeader>
              <CardContent>
                <div className="grid grid-cols-3 gap-3">
                  <div className="space-y-1.5"><Label required>Vendor</Label>
                    <div className="flex items-center gap-2 h-9 px-3 rounded-md border border-divider bg-surface text-sm">
                      <Avatar initials={vendor.name.split(" ").map((s: string) => s[0]).slice(0, 2).join("")} tone="sand" size="sm" />
                      <div className="min-w-0">
                        <div className="font-semibold text-ink truncate">{vendor.name}</div>
                        {vendor.tin && <div className="text-[10px] text-ink-mute">TIN: {vendor.tin}</div>}
                      </div>
                    </div>
                  </div>
                  <div className="space-y-1.5"><Label>PO Number</Label>
                    <Input value={existing?.id ?? "PO-HVPH-1091"} disabled />
                  </div>
                  <div className="space-y-1.5"><Label>PO Date</Label>
                    <Input value={existing?.poDate ?? "Apr 17, 2026"} disabled />
                  </div>
                  <div className="space-y-1.5"><Label>Expected Receipt</Label>
                    <Input defaultValue={existing?.expected.split(" · ")[0] ?? "Apr 27, 2026"} />
                  </div>
                  <div className="space-y-1.5"><Label>Currency</Label>
                    <Select defaultValue="USD"><option>USD</option><option>PHP</option><option>SGD</option><option>HKD</option></Select>
                  </div>
                  <div className="space-y-1.5"><Label>Payment terms</Label>
                    <Select defaultValue="net30"><option value="net30">Net 30</option><option value="net15">Net 15</option><option value="cod">COD</option></Select>
                  </div>
                </div>
              </CardContent>
            </Card>

            {/* LINES */}
            <Card>
              <CardHeader>
                <CardTitle>Line Items</CardTitle>
                <span className="text-[11px] text-ink-mute font-sans normal-case tracking-normal font-medium">
                  {lines.length} {lines.length === 1 ? "line" : "lines"}
                </span>
              </CardHeader>
              <div>
                <table className="w-full text-sm">
                  <thead className="bg-cream/60 border-b border-divider">
                    <tr className="text-left text-[10px] font-bold uppercase tracking-wider text-ink-mute">
                      <th className="pl-5 pr-2 py-2 w-10">#</th>
                      <th className="px-2 py-2 w-40">Item Code</th>
                      <th className="px-2 py-2">Description</th>
                      <th className="px-2 py-2 w-20 text-right">Qty</th>
                      <th className="px-2 py-2 w-16">UoM</th>
                      <th className="px-2 py-2 w-28 text-right">Unit Price</th>
                      <th className="px-2 py-2 w-28 text-right">Line Total</th>
                      <th className="pl-2 pr-5 py-2 w-8"></th>
                    </tr>
                  </thead>
                  <tbody>
                    {lines.map(l => (
                      <tr key={l.line} className="border-b border-divider-soft">
                        <td className="pl-5 pr-2 py-2 text-[11px] font-mono text-ink-mute">{String(l.line).padStart(2, "0")}</td>
                        <td className="px-2 py-2"><Input className="h-7 font-mono text-[11px]" value={l.itemCode} onChange={e => update(l.line, { itemCode: e.target.value })} placeholder="02010102-014" /></td>
                        <td className="px-2 py-2"><Input className="h-7 text-xs" value={l.description} onChange={e => update(l.line, { description: e.target.value })} placeholder="Item description…" /></td>
                        <td className="px-2 py-2"><Input type="number" className="h-7 text-xs text-right" value={l.qty} onChange={e => update(l.line, { qty: +e.target.value || 0 })} /></td>
                        <td className="px-2 py-2"><Select className="h-7 text-xs" value={l.uom} onChange={e => update(l.line, { uom: e.target.value })}><option>PC</option><option>MT</option><option>LM</option><option>KG</option></Select></td>
                        <td className="px-2 py-2"><Input type="number" className="h-7 text-xs text-right" value={l.unitPrice} onChange={e => update(l.line, { unitPrice: +e.target.value || 0 })} /></td>
                        <td className="px-2 py-2 text-right font-serif text-[14px]">{formatCurrency(l.qty * l.unitPrice)}</td>
                        <td className="pl-2 pr-5 py-2 text-right">
                          <button onClick={() => removeLine(l.line)} className="text-ink-mute hover:text-danger p-1" aria-label="Delete line"><Icon name="trash" size={13} /></button>
                        </td>
                      </tr>
                    ))}
                  </tbody>
                </table>
                <div className="border-b border-divider px-5 py-2.5 flex items-center gap-2">
                  <Button variant="ghost" size="sm" leadingIcon="plus" onClick={addLine}>Add line</Button>
                  <Button variant="subtle" size="sm" leadingIcon="sparkle">AI: Add common bundle items</Button>
                </div>
              </div>
              <div className="p-5 grid grid-cols-2 gap-2 text-sm">
                <div /> {/* spacer */}
                <div className="space-y-1.5">
                  <SummaryLine label="Subtotal"           value={formatCurrency(subtotal)} />
                  <SummaryLine label="VAT (12%)"          value={formatCurrency(vat)} />
                  <SummaryLine label="EWT (-2%)"          value={formatCurrency(ewt)} tone="danger" />
                  <div className="h-px bg-divider my-1" />
                  <SummaryLine label="Total" value={formatCurrency(total)} bold />
                </div>
              </div>
            </Card>

            {/* AI bundle */}
            <div className="bg-gradient-to-br from-warn-soft to-info-soft border border-accent/30 rounded-lg p-4 flex gap-3">
              <div className="size-7 rounded-full bg-warn-soft text-warn flex items-center justify-center shrink-0">
                <Icon name="sparkle" size={14} strokeWidth={2} />
              </div>
              <div className="flex-1">
                <div className="text-xs font-bold text-warn">AI Suggestion</div>
                <p className="text-xs text-ink-soft mt-1">
                  Last 5 POs to <strong className="font-semibold">{vendor.name}</strong> included <strong className="font-semibold">Anchor Bolts M16×200</strong> alongside steel orders.
                  Add 200 PC at $4.80/each?
                </p>
                <div className="flex gap-2 mt-2.5">
                  <Button size="sm" variant="accent">Add to PO</Button>
                  <Button size="sm" variant="ghost">Dismiss</Button>
                </div>
              </div>
            </div>
          </div>

          {/* SIDE PANEL — workflow */}
          <aside className="flex flex-col gap-3 min-w-0">
            <Card>
              <CardHeader><CardTitle>Workflow</CardTitle></CardHeader>
              <CardContent className="space-y-2.5">
                {PO_STEPS.map((step, i) => {
                  const state = i < currentStep ? "done" : i === currentStep ? "active" : "future"
                  return (
                    <div key={step} className="flex items-center gap-2.5">
                      <div className={cn(
                        "size-5 rounded-full flex items-center justify-center text-[9px] font-bold shrink-0",
                        state === "done"   && "bg-success text-white",
                        state === "active" && "bg-brand text-white",
                        state === "future" && "bg-divider text-ink-mute",
                      )}>
                        {state === "done" ? <Icon name="check" size={9} strokeWidth={3} /> : i + 1}
                      </div>
                      <span className={cn(
                        "text-xs",
                        state === "done"   && "text-success font-semibold",
                        state === "active" && "text-brand font-semibold",
                        state === "future" && "text-ink-mute",
                      )}>{step}</span>
                    </div>
                  )
                })}
              </CardContent>
            </Card>

            <Card>
              <CardHeader><CardTitle>Linked Records</CardTitle></CardHeader>
              <CardContent className="space-y-2 text-xs">
                <LinkRow icon="list"     label="Order Request" value="OR-HVPH-3041" />
                <LinkRow icon="box"      label="Item Receipt"     value={existing?.id === "PO-HVPH-1089" ? "IR-HVPH-1001" : "—"} disabled={existing?.id !== "PO-HVPH-1089"} onClick={() => existing?.id === "PO-HVPH-1089" && push("/procurement/ir/IR-HVPH-1001")} />
                <LinkRow icon="doc"      label="Vendor Invoice"   value="—" disabled />
                <LinkRow icon="building" label="Project"          value="Calamba Phase 2" />
              </CardContent>
            </Card>

            <Card>
              <CardHeader><CardTitle>Activity</CardTitle></CardHeader>
              <CardContent className="space-y-3">
                <ActivityRow who="Maya C." when="2h ago" action="approved this PO" />
                <ActivityRow who="Rico D." when="Apr 17" action="created the PO from PR-3041" />
              </CardContent>
            </Card>
          </aside>
        </div>
      </div>
    </>
  )
}

function SummaryLine({ label, value, bold, tone }: { label: string; value: string; bold?: boolean; tone?: string }) {
  return (
    <div className="flex justify-between items-center gap-3">
      <span className={cn("text-[11px] uppercase tracking-wider font-bold", tone === "danger" ? "text-danger" : "text-ink-mute")}>{label}</span>
      <span className={cn("font-serif", bold ? "text-2xl text-ink" : "text-[15px]", tone === "danger" && "text-danger")}>{value}</span>
    </div>
  )
}

function LinkRow({ icon, label, value, onClick, disabled }: { icon: string; label: string; value: string; onClick?: () => void; disabled?: boolean }) {
  return (
    <button onClick={onClick} disabled={disabled}
      className={cn(
        "w-full flex items-center gap-2.5 px-2 py-1.5 rounded-md text-left",
        !disabled && "hover:bg-brand-soft transition-colors",
        disabled && "opacity-60 cursor-default",
      )}>
      <Icon name={icon as any} size={13} className="text-ink-mute shrink-0" />
      <span className="text-ink-mute">{label}</span>
      <span className="ml-auto font-mono text-[11px] font-bold text-brand-mid">{value}</span>
    </button>
  )
}
function ActivityRow({ who, when, action }: { who: string; when: string; action: string }) {
  return (
    <div className="flex items-start gap-2.5">
      <Avatar initials={who.split(" ").map(s => s[0]).slice(0, 2).join("")} tone="teal" size="sm" />
      <div className="text-[11px] leading-snug">
        <div><span className="font-semibold text-ink">{who}</span> <span className="text-ink-mute">{action}</span></div>
        <div className="text-ink-mute">{when}</div>
      </div>
    </div>
  )
}

// SANDBOX
;(globalThis as any).POForm = POForm

})();/*__IIFE_WRAP_END__*/

/* ═════ apps/web/components/procurement/item-receipt.tsx ═════ */
;/*__IIFE_WRAP_START__*/(function(){
/**
 * ============================================================================
 * apps/web/components/procurement/item-receipt.tsx
 * ----------------------------------------------------------------------------
 * Screen 09 — Item Receipt (replacing GRN terminology). Linked to a PO,
 * captures lot numbers per line, shows qty received vs ordered with match
 * highlighting, document upload, and 3-way match status side card.
 * ============================================================================
 */

function ItemReceipt({ irId }: { irId?: string }) {
  const { push } = useRouter()
  const ir = irId ? (IR_BY_ID as any)[irId] : (IR_DATA as any)[0]
  const po = (PO_BY_ID as any)[ir.poId]

  const [lines, setLines] = React.useState(ir.lines)
  const allMatched = lines.every((l: any) => l.received === l.ordered)

  return (
    <>
      <TopBar
        breadcrumb={[
          { label: "Procurement" },
          { label: "Item Receipts", href: "/procurement/ir" },
          { label: ir.id },
        ]}
        onNavigate={push}
        actions={
          <>
            <Button variant="ghost" leadingIcon="paperclip">Attach delivery note</Button>
            <Button variant="primary" leadingIcon="check">Post Receipt</Button>
          </>
        }
      />

      {/* Status banner */}
      <div className={cn(
        "shrink-0 px-5 py-3 border-b border-divider flex items-center gap-3",
        allMatched ? "bg-success-soft" : "bg-warn-soft"
      )}>
        <div className={cn(
          "size-8 rounded-md flex items-center justify-center",
          allMatched ? "bg-success text-white" : "bg-warn text-white"
        )}>
          <Icon name={allMatched ? "check" : "clock"} size={15} strokeWidth={2.5} />
        </div>
        <div className="flex-1">
          <div className={cn("text-sm font-bold", allMatched ? "text-success" : "text-warn")}>
            {allMatched ? "Qty matched — ready for 3-way match" : "Partial receipt — counts pending"}
          </div>
          <div className="text-[11px] text-ink-soft mt-0.5">
            Linked to <button onClick={() => push(`/procurement/po/${po.id}`)} className="font-mono font-bold text-brand-mid hover:underline">{po.id}</button>
            {" · "}Received {ir.receivedDate} by {ir.receivedBy}
          </div>
        </div>
        {allMatched && <Badge variant="success" dot>3-way match ready</Badge>}
      </div>

      <div className="flex-1 overflow-y-auto bg-app">
        <div className="max-w-[1400px] mx-auto p-6 grid grid-cols-[1fr_300px] gap-5">
          <div className="flex flex-col gap-4 min-w-0">

            <Card>
              <CardHeader><CardTitle>Receipt Details</CardTitle></CardHeader>
              <CardContent>
                <div className="grid grid-cols-4 gap-3">
                  <div className="space-y-1.5"><Label>IR Number</Label><Input value={ir.id} disabled className="font-mono" /></div>
                  <div className="space-y-1.5"><Label>Receipt Date</Label><Input value={ir.receivedDate} /></div>
                  <div className="space-y-1.5"><Label>Received By</Label><Input value={ir.receivedBy} /></div>
                  <div className="space-y-1.5"><Label>Warehouse</Label>
                    <Select defaultValue={ir.warehouse}>
                      <option>Calamba Site Warehouse</option>
                      <option>Manila HQ Warehouse</option>
                      <option>BGC Warehouse</option>
                    </Select>
                  </div>
                </div>
              </CardContent>
            </Card>

            <Card>
              <CardHeader>
                <CardTitle>Line Items — Capture Receipt</CardTitle>
                <span className="text-[11px] text-ink-mute font-sans normal-case font-medium tracking-normal">
                  {lines.length} of {po.lines?.length ?? lines.length} lines
                </span>
              </CardHeader>
              <div>
                <table className="w-full text-sm">
                  <thead className="bg-cream/60 border-b border-divider">
                    <tr className="text-left text-[10px] font-bold uppercase tracking-wider text-ink-mute">
                      <th className="pl-5 pr-2 py-2">Item Code</th>
                      <th className="px-2 py-2">Description</th>
                      <th className="px-2 py-2 w-20 text-right">Ordered</th>
                      <th className="px-2 py-2 w-28 text-right">Received</th>
                      <th className="px-2 py-2 w-16">UoM</th>
                      <th className="px-2 py-2 w-40">Lot Number</th>
                      <th className="pl-2 pr-5 py-2 w-24 text-center">Match</th>
                    </tr>
                  </thead>
                  <tbody>
                    {lines.map((l: any, i: number) => {
                      const matched = l.received === l.ordered
                      return (
                        <tr key={i} className={cn(
                          "border-b border-divider-soft",
                          matched ? "bg-success-soft/30" : "bg-warn-soft/30",
                        )}>
                          <td className="pl-5 pr-2 py-2.5 font-mono text-[11px] text-brand-mid font-bold">{l.itemCode}</td>
                          <td className="px-2 py-2.5">{l.description}</td>
                          <td className="px-2 py-2.5 text-right font-serif text-[14px]">{l.ordered}</td>
                          <td className="px-2 py-2.5">
                            <Input type="number" className={cn("h-7 text-right text-xs", matched && "text-success font-bold")}
                              value={l.received}
                              onChange={e => {
                                const v = +e.target.value || 0
                                setLines((arr: any[]) => arr.map((x, j) => j === i ? { ...x, received: v } : x))
                              }} />
                          </td>
                          <td className="px-2 py-2.5 text-xs text-ink-mute">{l.uom}</td>
                          <td className="px-2 py-2.5"><Input className="h-7 font-mono text-[11px]" defaultValue={l.lotNumber} placeholder="LOT-…" /></td>
                          <td className="pl-2 pr-5 py-2.5 text-center">
                            {matched
                              ? <span className="inline-flex items-center gap-1 text-success text-[11px] font-bold"><Icon name="check" size={11} strokeWidth={3} />Match</span>
                              : <span className="inline-flex items-center gap-1 text-warn text-[11px] font-bold"><Icon name="alert-triangle" size={11} />Variance</span>
                            }
                          </td>
                        </tr>
                      )
                    })}
                  </tbody>
                </table>
              </div>
            </Card>

            {/* Document upload */}
            <Card>
              <CardHeader><CardTitle>Attached Documents</CardTitle></CardHeader>
              <CardContent>
                <div className="border-2 border-dashed border-divider rounded-md p-6 text-center hover:border-brand-mid transition-colors cursor-pointer">
                  <Icon name="upload" size={24} className="mx-auto text-ink-mute mb-2" />
                  <div className="text-sm font-semibold text-ink-soft">Drop delivery note or proof of receipt</div>
                  <div className="text-xs text-ink-mute mt-1">PDF, JPG, PNG up to 10 MB</div>
                  <Button variant="ghost" size="sm" className="mt-3">Browse files</Button>
                </div>
              </CardContent>
            </Card>
          </div>

          {/* SIDE PANEL */}
          <aside className="flex flex-col gap-3 min-w-0">
            <Card>
              <CardHeader><CardTitle>3-Way Match Status</CardTitle></CardHeader>
              <CardContent className="space-y-2.5">
                <MatchRow label="Order Request" code="OR-HVPH-3041" on={ir.threeWayMatch.pr} />
                <MatchRow label="Purchase Order"   code={po.id} on={ir.threeWayMatch.po} />
                <MatchRow label="Item Receipt"     code={ir.id} on={ir.threeWayMatch.ir} />
                <MatchRow label="Vendor Invoice"   code={ir.threeWayMatch.invoice ? "INV-HVPH-2042" : "Pending"} on={ir.threeWayMatch.invoice} />
              </CardContent>
            </Card>
            <Card>
              <CardHeader><CardTitle>PO Summary</CardTitle></CardHeader>
              <CardContent className="space-y-2 text-xs">
                <SideRow label="Vendor"    value={<span className="font-semibold text-ink">{po.vendor.name}</span>} />
                <SideRow label="PO Total"  value={<span className="font-serif text-base text-ink">{formatCurrency(po.amount)}</span>} />
                <SideRow label="PO Date"   value={po.poDate} />
                <SideRow label="Expected"  value={po.expected} />
                <SideRow label="Status"    value={<Badge variant={PO_STATUS_VARIANT[po.status]} dot>{(PO_STATUS_LABEL as any)[po.status]}</Badge>} />
              </CardContent>
            </Card>
            <Button variant="ghost" leadingIcon="external" onClick={() => push(`/procurement/po/${po.id}`)}>Open linked PO</Button>
          </aside>
        </div>
      </div>
    </>
  )
}

function MatchRow({ label, code, on }: { label: string; code: string; on: boolean }) {
  return (
    <div className="flex items-center gap-2.5">
      <div className={cn(
        "size-5 rounded-full flex items-center justify-center shrink-0",
        on ? "bg-success text-white" : "bg-divider text-ink-mute"
      )}>
        {on ? <Icon name="check" size={11} strokeWidth={3} /> : <Icon name="clock" size={11} />}
      </div>
      <div className="flex-1 min-w-0">
        <div className={cn("text-xs", on ? "font-semibold text-ink" : "text-ink-mute")}>{label}</div>
        <div className="text-[10px] font-mono text-brand-mid">{code}</div>
      </div>
    </div>
  )
}

// SANDBOX
;(globalThis as any).ItemReceipt = ItemReceipt

})();/*__IIFE_WRAP_END__*/

/* ═════ apps/web/components/procurement/vendor-cards.tsx ═════ */
;/*__IIFE_WRAP_START__*/(function(){
/**
 * ============================================================================
 * apps/web/components/procurement/vendor-cards.tsx
 * ----------------------------------------------------------------------------
 * Screen 10 — Vendor Cards View. Grid of vendor cards with 3-level BP
 * categorisation filter chips (Supplier / Contractor / Prof Services x
 * sub-categories). Starred vendors section pinned at top.
 * ============================================================================
 */

function VendorCards() {
  const { push } = useRouter()
  const [l1, setL1] = React.useState<"all" | "Supplier" | "Contractor" | "Prof Services">("all")
  const [l2, setL2] = React.useState<string | "all">("all")
  const [query, setQuery] = React.useState("")

  /* Available level-2 options driven by selected level-1 */
  const l2Options = React.useMemo(() => {
    const list = l1 === "all" ? VENDORS : (VENDORS as any[]).filter(v => v.level1 === l1)
    return Array.from(new Set(list.map((v: any) => v.level2)))
  }, [l1])

  const filtered = React.useMemo(() => {
    let v: any[] = VENDORS as any[]
    if (l1 !== "all") v = v.filter(x => x.level1 === l1)
    if (l2 !== "all") v = v.filter(x => x.level2 === l2)
    if (query) v = v.filter(x => x.name.toLowerCase().includes(query.toLowerCase()))
    return v
  }, [l1, l2, query])

  const starred = filtered.filter(v => v.starred)
  const rest    = filtered.filter(v => !v.starred)

  /* Real handlers */
  const onExport = () => (window as any).cenoraToast?.("Exported", { variant: "success", sub: `${filtered.length} vendors · CSV downloaded` })
  const onNewVendor = () => (window as any).cenoraToast?.("Opening vendor form…", { variant: "default", sub: "New supplier · BP cnr_vendor record" })

  return (
    <>
      <TopBar
        breadcrumb={[{ label: "Procurement" }, { label: "Vendors" }]}
      />

      <ActionBar
        title="Vendors"
        status={<><span className="font-mono">cnr_vendor</span> · {VENDORS.length} total · {(VENDORS as any[]).filter((v: any) => v.starred).length} starred</>}
        search={<SearchBox value={query} onChange={setQuery} placeholder="Search vendors…" className="w-56" />}
        secondary={<Button variant="ghost" leadingIcon="download" onClick={onExport}>Export</Button>}
        primary={<Button variant="primary" leadingIcon="plus" onClick={onNewVendor}>New Vendor</Button>}
        filters={
          <>
            <span className="text-[10px] uppercase tracking-wider font-bold text-ink-mute mr-1">Type:</span>
            <FilterChip active={l1 === "all"}          onClick={() => { setL1("all"); setL2("all") }}>All</FilterChip>
            <FilterChip active={l1 === "Supplier"}     onClick={() => { setL1("Supplier"); setL2("all") }}>Supplier</FilterChip>
            <FilterChip active={l1 === "Contractor"}   onClick={() => { setL1("Contractor"); setL2("all") }}>Contractor</FilterChip>
            <FilterChip active={l1 === "Prof Services"} onClick={() => { setL1("Prof Services"); setL2("all") }}>Prof Services</FilterChip>
            {l1 !== "all" && (
              <>
                <span className="w-px h-5 bg-divider mx-1" />
                <span className="text-[10px] uppercase tracking-wider font-bold text-ink-mute mr-1">Subtype:</span>
                <FilterChip active={l2 === "all"} onClick={() => setL2("all")}>All {l1}s</FilterChip>
                {l2Options.map(opt => (
                  <FilterChip key={opt} active={l2 === opt} onClick={() => setL2(opt)}>{opt}</FilterChip>
                ))}
              </>
            )}
          </>
        }
      />

      <div className="flex-1 overflow-y-auto bg-app">
        <div className="max-w-[1400px] mx-auto p-6 space-y-6">
          {starred.length > 0 && (
            <section>
              <h2 className="text-[10px] font-bold uppercase tracking-wider text-ink-mute mb-3 flex items-center gap-2">
                <Icon name="star" size={11} strokeWidth={2.5} className="text-accent" /> Starred Vendors
              </h2>
              <div className="grid grid-cols-3 gap-4">
                {starred.map(v => <VendorCard key={v.id} v={v} onOpen={() => push(`/procurement/vendors/${v.id}`)} />)}
              </div>
            </section>
          )}

          <section>
            <h2 className="text-[10px] font-bold uppercase tracking-wider text-ink-mute mb-3">
              All Vendors ({rest.length})
            </h2>
            {rest.length === 0
              ? <div className="text-sm text-ink-mute py-8 text-center">No vendors match the current filters.</div>
              : (
                <div className="grid grid-cols-3 gap-4">
                  {rest.map(v => <VendorCard key={v.id} v={v} onOpen={() => push(`/procurement/vendors/${v.id}`)} />)}
                </div>
              )
            }
          </section>
        </div>
      </div>
    </>
  )
}

function VendorCard({ v, onOpen }: { v: any; onOpen?: () => void }) {
  const { push } = useRouter()
  return (
    <article className="bg-surface border border-divider rounded-lg p-4 hover:shadow-md transition-shadow flex flex-col gap-3">
      <header className="flex items-start gap-3">
        <Avatar initials={v.initials} tone={v.tone} size="lg" />
        <div className="flex-1 min-w-0">
          <div className="flex items-center gap-1.5">
            <h3 className="text-sm font-semibold text-ink truncate font-sans">{v.name}</h3>
            {v.starred && <Icon name="star" size={11} className="text-accent shrink-0" />}
          </div>
          <div className="text-[10px] text-ink-mute font-mono">TIN: {v.tin}</div>
          <div className="flex items-center gap-1 mt-1.5">
            <Badge variant="brand">{v.level1}</Badge>
            <Badge variant="outline">{v.level2}</Badge>
          </div>
        </div>
      </header>

      <div className="grid grid-cols-3 gap-2 pt-2 border-t border-divider-soft">
        <Metric label="YTD Spend" value={formatCurrency(v.ytdSpend)} mono />
        <Metric label="Open POs"  value={v.openPOs} />
        <Metric label="On-time"   value={`${v.onTimePct}%`} tone={v.onTimePct >= 90 ? "success" : v.onTimePct >= 75 ? "warn" : "danger"} />
      </div>

      {v.overdueAlert && (
        <div className="text-[11px] bg-danger-soft text-danger px-2.5 py-1.5 rounded-md font-semibold flex items-center gap-1.5">
          <Icon name="alert-triangle" size={11} />
          {v.overdueAlert}
        </div>
      )}

      <footer className="flex items-center gap-1.5 pt-2 border-t border-divider-soft">
        <Button size="sm" variant="ghost" leadingIcon="eye" onClick={onOpen}>Profile</Button>
        <Button size="sm" variant="ghost" leadingIcon="message">Message</Button>
        <Button size="sm" variant="ghost" leadingIcon="plus" className="ml-auto" onClick={() => push("/procurement/po/new")}>New PO</Button>
      </footer>
    </article>
  )
}

function Metric({ label, value, mono, tone }: { label: string; value: any; mono?: boolean; tone?: string }) {
  return (
    <div>
      <div className="text-[10px] uppercase tracking-wider font-bold text-ink-mute">{label}</div>
      <div className={cn(
        "font-serif text-base mt-0.5",
        mono && "font-mono text-sm",
        tone === "success" && "text-success",
        tone === "warn"    && "text-warn",
        tone === "danger"  && "text-danger",
        !tone && "text-ink",
      )}>{value}</div>
    </div>
  )
}

// SANDBOX
;(globalThis as any).VendorCards = VendorCards

})();/*__IIFE_WRAP_END__*/

/* ═════ apps/web/components/procurement/approvals.tsx ═════ */
;/*__IIFE_WRAP_START__*/(function(){
/**
 * ============================================================================
 * apps/web/components/procurement/approvals.tsx
 * ----------------------------------------------------------------------------
 * Unified approvals inbox. Pulls together every document type that needs the
 * current user's decision — IRQs (item requests), PRs (order requests),
 * POs (purchase orders), Invoices (AP) — and groups them so the approver
 * can clear the queue in one place.
 *
 * Master ref: cnr_approval table joins across multiple parent doctypes;
 * this view is the materialised "my queue" projection.
 *
 * AI summary at top: brief plain-English read of what's blocked and what
 * to attack first. This is exactly the kind of moment Cenora AI shines.
 * ============================================================================
 */

interface ApprovalItem {
  id: string
  docType: "IRQ" | "OR" | "PO" | "Invoice" | "GL Journal"
  title: string
  requestor: { name: string; initials: string; tone?: any }
  amount?: number
  currency?: "PHP" | "SGD" | "HKD" | "USD"
  daysWaiting: number
  urgent?: boolean
  hint?: string                    /* one-liner context, e.g. "Above $50k threshold — requires CFO" */
  step: string                     /* "Step 2 of 3" */
  href: string                     /* deep link */
  blockReason?: string             /* if blocked — what's missing */
}

/* ─── Aggregate approval queue ──────────────────────────────────────────── */
function buildQueue(): ApprovalItem[] {
  const items: ApprovalItem[] = []

  /* IRQs awaiting current user (KL) */
  for (const irq of IRQ_DATA.filter(i => i.stage === "submitted" || i.stage === "review")) {
    items.push({
      id: irq.id, docType: "IRQ",
      title: irq.title,
      requestor: { name: irq.requestor.name, initials: irq.requestor.initials, tone: "teal" },
      daysWaiting: 18 - parseInt(irq.dateISO.slice(-2)),
      step: irq.stage === "submitted" ? "Approver review" : "Clarifications pending",
      hint: irq.aiFlag ? `AI flagged: ${irq.aiFlag}` : irq.stage === "review" ? "Awaiting requestor reply" : undefined,
      blockReason: irq.stage === "review" ? "Requestor needs to confirm spec" : undefined,
      href: `/catalogue/irq`,
    })
  }

  /* PRs awaiting current user — show submitted + review */
  for (const pr of PRS.filter(p => p.status === "submitted" || p.status === "review")) {
    items.push({
      id: pr.id, docType: "OR",
      title: pr.title,
      requestor: pr.requestor,
      amount: pr.totalEst, currency: pr.currency,
      daysWaiting: pr.daysOpen,
      urgent: pr.urgent,
      step: pr.status === "submitted" ? `Approver ${pr.approvers?.findIndex(a => a.decision === "pending" || !a.decision) ?? 0 + 1} of ${pr.approvers?.length ?? 1}` : "Under review",
      hint: pr.totalEst > 100000 ? "Above ₱100k — CFO sign-off needed after operations" : undefined,
      href: "/procurement/pr",
    })
  }

  /* POs awaiting approval — synth a couple */
  items.push({
    id: "PO-HVPH-1091", docType: "PO",
    title: "WiFi 6 APs × 22 — TechNet Solutions",
    requestor: { name: "Ana Q.", initials: "AQ", tone: "sand" },
    amount: 10560, currency: "USD",
    daysWaiting: 2, step: "Approver 1 of 2",
    hint: "Sourced from PR-2204 · 3 quotes · TechNet best price + 96% on-time",
    href: "/procurement/po",
  })
  items.push({
    id: "PO-HVPH-1092", docType: "PO",
    title: "Concrete 25 MPa × 86 m³ — Republic Cement",
    requestor: { name: "Ben L.", initials: "BL", tone: "teal" },
    amount: 326800, currency: "PHP",
    daysWaiting: 1, urgent: true, step: "CFO sign-off",
    hint: "Above ₱100k threshold · Phase 2 slab pour Apr 30",
    href: "/procurement/po",
  })

  /* AP Invoices */
  items.push({
    id: "BILL-HVPH-0451", docType: "Invoice",
    title: "SteelMark Industries · IR-1001 matched · ₱18,400",
    requestor: { name: "Maria A.", initials: "MA", tone: "blue" },
    amount: 18400, currency: "PHP",
    daysWaiting: 1, step: "3-way matched · ready to post",
    hint: "PR ↔ PO ↔ IR all clean. One-click post.",
    href: "/finance",
  })
  items.push({
    id: "BILL-HVPH-0452", docType: "Invoice",
    title: "Pacific Solar PH · 2 invoices",
    requestor: { name: "Maria A.", initials: "MA", tone: "blue" },
    amount: 10050, currency: "PHP",
    daysWaiting: 1, step: "AI matched to POs",
    hint: "Auto-attached to POs 1086 + 1090 by AI · review and post",
    href: "/finance",
  })
  items.push({
    id: "BILL-HVPH-0453", docType: "Invoice",
    title: "Bright Industries HK · 62 days overdue",
    requestor: { name: "Maria A.", initials: "MA", tone: "blue" },
    amount: 15600, currency: "HKD",
    daysWaiting: 62, urgent: true, step: "AR write-off review",
    hint: "Customer hasn't responded · escalate or accrue?",
    blockReason: "Customer unresponsive since Nov 12",
    href: "/finance",
  })

  /* GL Journal */
  items.push({
    id: "JE-2026-04-0204", docType: "GL Journal",
    title: "Accrual reversal — March utilities",
    requestor: { name: "Maria A.", initials: "MA", tone: "blue" },
    amount: 48200, currency: "PHP",
    daysWaiting: 0, step: "Controller review",
    hint: "Standard reversal, auto-prepared from prior period entry",
    href: "/finance",
  })

  return items
}

function Approvals() {
  const { push } = useRouter()
  const queue = React.useMemo(buildQueue, [])

  const [docFilter, setDocFilter] = React.useState<"all" | ApprovalItem["docType"]>("all")
  const [sort, setSort] = React.useState<"urgent" | "oldest" | "newest" | "value">("urgent")

  const counts = React.useMemo(() => {
    const c: Record<string, number> = { all: queue.length }
    for (const i of queue) c[i.docType] = (c[i.docType] ?? 0) + 1
    return c
  }, [queue])

  const visible = React.useMemo(() => {
    let v = queue
    if (docFilter !== "all") v = v.filter(i => i.docType === docFilter)
    if (sort === "urgent")  v = [...v].sort((a, b) => (Number(b.urgent ?? 0) - Number(a.urgent ?? 0)) || (b.daysWaiting - a.daysWaiting))
    if (sort === "oldest")  v = [...v].sort((a, b) => b.daysWaiting - a.daysWaiting)
    if (sort === "newest")  v = [...v].sort((a, b) => a.daysWaiting - b.daysWaiting)
    if (sort === "value")   v = [...v].sort((a, b) => (b.amount ?? 0) - (a.amount ?? 0))
    return v
  }, [queue, docFilter, sort])

  const urgentCount = queue.filter(i => i.urgent).length
  const oldestCount = queue.filter(i => i.daysWaiting > 5).length
  const totalValue  = queue.reduce((s, i) => s + (i.amount ?? 0), 0)

  return (
    <>
      <TopBar
        breadcrumb={[{ label: "Procurement · P2P" }, { label: "Approvals" }]}
        actions={
          <>
            <Button variant="ghost" leadingIcon="settings">Delegation rules</Button>
            <Button variant="primary" leadingIcon="check">Bulk approve clean items</Button>
          </>
        }
      />

      <div className="flex-1 overflow-y-auto bg-app">
        <div className="max-w-[1280px] mx-auto p-6 space-y-4">

          {/* Hero AI summary card */}
          <div className="bg-gradient-to-br from-brand to-brand-light text-white rounded-lg p-6 grid grid-cols-[1fr_auto] gap-6">
            <div>
              <div className="flex items-center gap-2 mb-2">
                <Icon name="sparkle" size={14} className="text-accent" />
                <span className="text-[10px] uppercase tracking-[0.2em] font-bold text-accent">Cenora AI · brief for Maya</span>
              </div>
              <p className="font-serif text-[20px] leading-snug text-white/95 max-w-2xl">
                You have <span className="font-bold text-accent">{queue.length} items</span> waiting on you — total exposure <span className="font-bold">₱{totalValue.toLocaleString()}</span>.
                <span className="block mt-1">
                  <span className="text-accent font-bold">{urgentCount} are urgent.</span>{" "}
                  Start with <span className="font-mono text-[15px] underline decoration-accent decoration-2 underline-offset-4">PO-1092</span> (concrete · ₱326.8k · slab pour 13d), then{" "}
                  <span className="font-mono text-[15px] underline decoration-accent decoration-2 underline-offset-4">PR-2208</span> (steel · phase-2 critical).
                </span>
              </p>
              <div className="flex items-center gap-2 mt-4 flex-wrap">
                <button className="px-3 h-7 bg-accent text-ink rounded text-[11px] font-semibold hover:bg-accent/90">Approve concrete PO</button>
                <button className="px-3 h-7 bg-white/15 text-white border border-white/25 rounded text-[11px] font-semibold hover:bg-white/25">Open PR-2208</button>
                <button className="px-3 h-7 bg-white/15 text-white border border-white/25 rounded text-[11px] font-semibold hover:bg-white/25">Reject the AR write-off</button>
              </div>
            </div>
            <div className="grid grid-cols-1 gap-2 self-stretch min-w-[160px]">
              <div className="bg-white/8 rounded-md p-3 text-right">
                <div className="text-[9px] uppercase tracking-wider font-bold text-accent">Total queue</div>
                <div className="font-serif text-2xl mt-0.5">{queue.length}</div>
              </div>
              <div className="bg-white/8 rounded-md p-3 text-right">
                <div className="text-[9px] uppercase tracking-wider font-bold text-accent">Urgent</div>
                <div className="font-serif text-2xl mt-0.5 text-accent">{urgentCount}</div>
              </div>
              <div className="bg-white/8 rounded-md p-3 text-right">
                <div className="text-[9px] uppercase tracking-wider font-bold text-accent">{">"} 5d old</div>
                <div className="font-serif text-2xl mt-0.5">{oldestCount}</div>
              </div>
            </div>
          </div>

          {/* Filter row */}
          <div className="flex items-center justify-between gap-3 flex-wrap">
            <div className="flex items-center gap-1.5 flex-wrap">
              <FilterChip active={docFilter === "all"} onClick={() => setDocFilter("all")} count={counts.all}>All Documents</FilterChip>
              {(["IRQ", "OR", "PO", "Invoice", "GL Journal"] as const).map(d => {
                const c = counts[d] ?? 0
                if (c === 0) return null
                return (
                  <FilterChip key={d} active={docFilter === d} onClick={() => setDocFilter(d)} count={c}
                    tone={d === "PO" ? "info" : d === "OR" ? "warn" : d === "Invoice" ? "success" : d === "IRQ" ? "accent" : "neutral"}>
                    {d}
                  </FilterChip>
                )
              })}
            </div>
            <select value={sort} onChange={e => setSort(e.target.value as any)}
              className="h-9 px-3 bg-surface border border-divider rounded-md text-[12px] font-semibold">
              <option value="urgent">Sort: Urgency</option>
              <option value="oldest">Sort: Oldest first</option>
              <option value="newest">Sort: Newest first</option>
              <option value="value">Sort: Value (high → low)</option>
            </select>
          </div>

          {/* List */}
          <div className="space-y-2">
            {visible.map(item => <ApprovalRow key={item.id} item={item} push={push} />)}
            {visible.length === 0 && (
              <div className="bg-surface border border-divider rounded-lg p-12 text-center">
                <div className="size-12 mx-auto rounded-full bg-success-soft text-success flex items-center justify-center mb-3">
                  <Icon name="check" size={20} />
                </div>
                <div className="font-serif text-xl text-ink">Inbox zero.</div>
                <div className="text-[12px] text-ink-mute mt-1">Nothing matches these filters.</div>
              </div>
            )}
          </div>

        </div>
      </div>
    </>
  )
}

/* ─── Approval row ───────────────────────────────────────────────────────── */
function ApprovalRow({ item, push }: { item: ApprovalItem; push: (r: string) => void }) {
  const symbol = item.currency === "PHP" ? "₱" : item.currency === "SGD" ? "S$" : item.currency === "HKD" ? "HK$" : "$"
  const docTone =
    item.docType === "PO" ? "info" :
    item.docType === "OR" ? "warn" :
    item.docType === "Invoice" ? "success" :
    item.docType === "IRQ" ? "accent" : "neutral"

  return (
    <div className={cn(
      "bg-surface border rounded-lg p-4 transition-shadow hover:shadow-md",
      item.urgent ? "border-danger/50 bg-danger-soft/20" : "border-divider"
    )}>
      <div className="flex items-start gap-4">
        {/* Doc badge */}
        <div className="shrink-0 w-16 text-center">
          <Badge variant={docTone as any} dot>{item.docType}</Badge>
          <div className="text-[9px] text-ink-mute mt-1 font-mono">{item.id.split("-").pop()}</div>
        </div>

        {/* Main */}
        <div className="flex-1 min-w-0">
          <div className="flex items-start justify-between gap-3">
            <div className="min-w-0 flex-1">
              <div className="flex items-baseline gap-2 flex-wrap">
                <h3 className="font-semibold text-ink text-[14px] leading-snug">{item.title}</h3>
                {item.urgent && <Badge variant="danger">URGENT</Badge>}
                {item.blockReason && <Badge variant="warn">Blocked</Badge>}
              </div>
              <div className="flex items-center gap-3 mt-1 text-[11px] text-ink-mute">
                <span className="font-mono text-brand-mid">{item.id}</span>
                <span>·</span>
                <span className="flex items-center gap-1.5">
                  <Avatar initials={item.requestor.initials} tone={item.requestor.tone as any} size="xs" />
                  {item.requestor.name}
                </span>
                <span>·</span>
                <span>{item.step}</span>
                <span>·</span>
                <span className={cn(item.daysWaiting > 5 && "text-warn font-semibold")}>
                  {item.daysWaiting === 0 ? "today" : `${item.daysWaiting}d waiting`}
                </span>
              </div>
              {item.hint && (
                <div className="flex items-start gap-1.5 mt-2 text-[11.5px] text-ink-soft">
                  <Icon name="sparkle" size={11} className="text-accent-deep mt-0.5 shrink-0" />
                  <span className="italic">{item.hint}</span>
                </div>
              )}
              {item.blockReason && (
                <div className="flex items-start gap-1.5 mt-2 text-[11.5px] text-warn">
                  <Icon name="alert-triangle" size={11} className="mt-0.5 shrink-0" />
                  <span>{item.blockReason}</span>
                </div>
              )}
            </div>
            {item.amount != null && (
              <div className="text-right shrink-0">
                <div className="font-serif text-[20px] text-ink leading-none">{symbol}{item.amount.toLocaleString()}</div>
                <div className="text-[10px] text-ink-mute mt-1">{item.currency}</div>
              </div>
            )}
          </div>

          {/* Actions */}
          <div className="flex items-center gap-1.5 mt-3 pt-3 border-t border-divider-soft">
            <Button variant="primary" size="sm" leadingIcon="check">Approve</Button>
            <Button variant="ghost" size="sm" leadingIcon="message">Comment</Button>
            <Button variant="ghost" size="sm" leadingIcon="x" className="text-danger">Reject</Button>
            <Button variant="ghost" size="sm" leadingIcon="external" className="ml-auto" onClick={() => push(item.href)}>
              Open {item.docType}
            </Button>
          </div>
        </div>
      </div>
    </div>
  )
}

// SANDBOX
;(globalThis as any).Approvals = Approvals

})();/*__IIFE_WRAP_END__*/

/* ═════ apps/web/components/procurement/requisitions.tsx ═════ */
;/*__IIFE_WRAP_START__*/(function(){
/**
 * apps/web/components/procurement/requisitions.tsx
 * Procurement — Requisitions queue. Shows approved Order Requests that have
 * been converted to requisitions, awaiting sourcing into Purchase Orders.
 */

function Requisitions() {
  const { push } = useRouter()
  const reqs = SAMPLE_REQS
  const [view, setView] = React.useState<"list" | "cards">("list")
  const [statusFilter, setStatusFilter] = React.useState<"queued" | "sourcing" | "all">("all")
  const [combine, setCombine] = React.useState<Set<string>>(new Set())

  let filtered = reqs
  if (statusFilter !== "all") filtered = filtered.filter(r => r.status === statusFilter)

  function toggleCombine(id: string) {
    setCombine(s => {
      const n = new Set(s); n.has(id) ? n.delete(id) : n.add(id); return n
    })
  }

  return (
    <>
      <TopBar breadcrumb={[{ label: "Procurement" }, { label: "Requisitions" }]} />
      <ActionBar
        title="Requisitions"
        status={
          <span>
            <span className="font-mono font-bold text-ink">{reqs.length}</span> in queue ·
            <span className="font-mono font-bold text-ink ml-1">{reqs.filter(r => r.status === "queued").length}</span> awaiting sourcing
            {combine.size > 1 && <span className="text-brand-mid font-semibold ml-2">· {combine.size} selected for combining</span>}
          </span>
        }
        view={<ListCardToggle value={view} onChange={setView} />}
        primary={
          combine.size > 1 ? (
            <Button variant="primary" leadingIcon="layers" size="sm" onClick={() => push("/procurement/po/new")}>Combine {combine.size} → PO</Button>
          ) : (
            <Button variant="primary" leadingIcon="arrow-right" size="sm" onClick={() => push("/procurement/po/new")}>Convert to PO</Button>
          )
        }
        secondary={<Button variant="ghost" leadingIcon="download" size="sm">Export</Button>}
        filters={
          <>
            <FilterChip active={statusFilter === "all"} onClick={() => setStatusFilter("all")} count={reqs.length}>All</FilterChip>
            <FilterChip active={statusFilter === "queued"} onClick={() => setStatusFilter("queued")} count={reqs.filter(r => r.status === "queued").length}>Queued</FilterChip>
            <FilterChip active={statusFilter === "sourcing"} onClick={() => setStatusFilter("sourcing")} count={reqs.filter(r => r.status === "sourcing").length}>Sourcing</FilterChip>
          </>
        }
      />

      <div className="flex-1 overflow-y-auto bg-app">
        <div className="max-w-[1280px] mx-auto p-6">
          <div className="bg-info-soft border border-info/20 rounded-lg p-3 flex items-start gap-2.5 mb-4">
            <Icon name="info" size={14} className="text-info mt-0.5" />
            <div className="text-[11.5px] text-info">
              <span className="font-semibold">How requisitions work.</span> Approved Order Requests automatically convert to Requisitions, where they wait for sourcing. Combine requisitions with the same vendor to consolidate into a single PO and improve pricing.
            </div>
          </div>

          {view === "list" ? (
            <Card>
              <div className="grid grid-cols-[40px_140px_2fr_1fr_120px_140px_120px_100px] px-4 py-2 bg-cream text-[10px] uppercase tracking-wider font-bold text-ink-mute">
                <span></span><span>REQ #</span><span>Item summary</span><span>Vendor (suggested)</span><span className="text-right">Qty / Amount</span><span>Requestor</span><span>Status</span><span></span>
              </div>
              {filtered.map(r => {
                const checked = combine.has(r.id)
                return (
                  <div key={r.id} className="grid grid-cols-[40px_140px_2fr_1fr_120px_140px_120px_100px] px-4 py-2.5 items-center border-t border-divider-soft hover:bg-cream/40 text-[11.5px]">
                    <input type="checkbox" checked={checked} onChange={() => toggleCombine(r.id)} className="accent-brand w-4 h-4" />
                    <span>
                      <div className="font-mono text-[11px] font-bold text-brand-mid">{r.id}</div>
                      <div className="text-[9.5px] text-ink-mute">from {r.fromOR}</div>
                    </span>
                    <span>
                      <div className="text-ink font-medium leading-tight">{r.title}</div>
                      <div className="text-[10px] text-ink-mute">{r.entity} · {r.dept}</div>
                    </span>
                    <span className="text-ink-soft">{r.vendorSuggested}</span>
                    <span className="text-right">
                      <div className="font-mono">{r.qty} units</div>
                      <div className="text-[10px] text-ink-mute font-mono">{r.amount}</div>
                    </span>
                    <div className="flex items-center gap-1.5">
                      <Avatar initials={r.requestor.initials} tone="sand" size="xs" />
                      <span>{r.requestor.name}</span>
                    </div>
                    {r.status === "queued"   ? <Badge variant="neutral">Queued</Badge>
                                              : <Badge variant="info" dot>Sourcing</Badge>}
                    <Button variant="ghost" size="sm">View</Button>
                  </div>
                )
              })}
            </Card>
          ) : (
            <div className="grid grid-cols-2 lg:grid-cols-3 gap-3">
              {filtered.map(r => (
                <Card key={r.id} className="hover:shadow-md transition-shadow">
                  <div className="p-4">
                    <div className="flex items-center gap-2 mb-2">
                      <span className="font-mono text-[10px] font-bold text-brand-mid">{r.id}</span>
                      <span className="ml-auto">{r.status === "queued" ? <Badge variant="neutral">Queued</Badge> : <Badge variant="info" dot>Sourcing</Badge>}</span>
                    </div>
                    <div className="text-[13px] text-ink font-semibold">{r.title}</div>
                    <div className="text-[10.5px] text-ink-mute mt-0.5">{r.entity} · {r.dept}</div>
                    <div className="mt-2 text-[11px]">Vendor (suggested): <span className="font-medium text-ink">{r.vendorSuggested}</span></div>
                    <div className="mt-2 grid grid-cols-2 text-[10.5px]">
                      <div><div className="text-ink-mute">Qty</div><div className="font-mono font-bold">{r.qty}</div></div>
                      <div><div className="text-ink-mute">Amount</div><div className="font-mono font-bold">{r.amount}</div></div>
                    </div>
                  </div>
                </Card>
              ))}
            </div>
          )}
        </div>
      </div>
    </>
  )
}

const SAMPLE_REQS = [
  { id: "REQ-HVPH-0049", fromOR: "OR-HVPH-0440", title: "Steel reinforcement bars · 12mm · 500 pcs",       vendorSuggested: "Pacific Steel Co.",     qty: 500,  amount: "₱ 4,852,000",  entity: "HVPH", dept: "Engineering",  status: "queued",   requestor: { name: "Daniel R.", initials: "DR" } },
  { id: "REQ-HVPH-0048", fromOR: "OR-HVPH-0438", title: "Field laptops · ThinkPad T14 · 12 units",          vendorSuggested: "ABC Computer Solutions", qty: 12,   amount: "₱ 720,000",     entity: "HVPH", dept: "Engineering",  status: "queued",   requestor: { name: "Karla M.", initials: "KM" } },
  { id: "REQ-HVPH-0047", fromOR: "OR-HVPH-0436", title: "Maintenance contract · 4 generators · 12mo",       vendorSuggested: "Premier Power Inc.",    qty: 1,    amount: "₱ 1,250,000",  entity: "HVPH", dept: "Facilities",   status: "sourcing", requestor: { name: "Lara C.",  initials: "LC" } },
  { id: "REQ-HVSG-0024", fromOR: "OR-HVSG-0118", title: "Office printer fleet upgrade · 6 units",          vendorSuggested: "Canon Singapore",        qty: 6,    amount: "S$ 18,400",    entity: "HVSG", dept: "Admin",        status: "queued",   requestor: { name: "Kenneth T.", initials: "KT" } },
  { id: "REQ-HVAU-0018", fromOR: "OR-HVAU-0084", title: "Site safety helmets + harnesses · 60 sets",       vendorSuggested: "SafetyFirst AU",          qty: 60,   amount: "A$ 8,940",      entity: "HVAU", dept: "Operations",   status: "queued",   requestor: { name: "Tom N.",    initials: "TN" } },
  { id: "REQ-HVIN-0089", fromOR: "OR-HVIN-0290", title: "Packaging materials · Mumbai project",            vendorSuggested: "Devanand Packaging",     qty: 1200, amount: "₹ 8,40,000",    entity: "HVIN", dept: "Operations",   status: "sourcing", requestor: { name: "Priya I.",  initials: "PI" } },
  { id: "REQ-HVHK-0014", fromOR: "OR-HVHK-0046", title: "Showroom signage refresh · 12 panels",            vendorSuggested: "—",                       qty: 12,   amount: "HK$ 88,000",    entity: "HVHK", dept: "Marketing",    status: "queued",   requestor: { name: "Eric W.",   initials: "EW" } },
]

// SANDBOX
;(globalThis as any).Requisitions = Requisitions

})();/*__IIFE_WRAP_END__*/

/* ═════ apps/web/components/catalogue/products.tsx ═════ */
;/*__IIFE_WRAP_START__*/(function(){
/**
 * ============================================================================
 * apps/web/components/catalogue/products.tsx
 * ----------------------------------------------------------------------------
 * Product Master List. Shows every approved item (cnr_item) for the current
 * entity, with full 4-level category breadcrumb, stock summary, lifecycle,
 * and primary vendor. Powers the rest of the suite — POs, IRs, Inventory
 * all reference this master.
 *
 * Interactions:
 *   • Filter chips at top: All / Active / New / Phasing Out / Discontinued
 *   • Category facets (left rail) — click to filter
 *   • Search by code, name, or attribute text
 *   • Sort by recency / on-hand / category
 *   • Click row → opens product detail slideout (with attribute panel)
 * ============================================================================
 */

function Products() {
  const { push } = useRouter()
  const [lifecycleFilter, setLifecycleFilter] = React.useState<"all" | "active" | "new" | "phasing-out" | "discontinued">("all")
  const [categoryFilter, setCategoryFilter] = React.useState<string | null>(null)
  const [search, setSearch] = React.useState("")
  const [sort, setSort] = React.useState<"recent" | "code" | "on-hand">("recent")
  const [selected, setSelected] = React.useState<typeof PRODUCTS[number] | null>(null)
  const [colFilters, setColFilters] = React.useState<Record<string, { values: string[]; sort?: "asc" | "desc" } | undefined>>({})

  /* Top-level categories for the facet rail (Level 1 only) */
  const level1 = CATEGORIES

  /* Counts by lifecycle */
  const counts = React.useMemo(() => ({
    all: PRODUCTS.length,
    active: PRODUCTS.filter(p => p.lifecycle === "active").length,
    new: PRODUCTS.filter(p => p.lifecycle === "new").length,
    "phasing-out": PRODUCTS.filter(p => p.lifecycle === "phasing-out").length,
    discontinued: PRODUCTS.filter(p => p.lifecycle === "discontinued").length,
  }), [])

  /* Distinct values for column filters */
  const distinctUoM    = React.useMemo(() => Array.from(new Set(PRODUCTS.map(p => p.uom))), [])
  const distinctVendor = React.useMemo(() => Array.from(new Set(PRODUCTS.map(p => p.primaryVendor))), [])

  /* Apply filters */
  const rows = React.useMemo(() => {
    let r = PRODUCTS as any[]
    if (lifecycleFilter !== "all") r = r.filter(p => p.lifecycle === lifecycleFilter)
    if (categoryFilter)            r = r.filter(p => p.category.startsWith(categoryFilter))
    if (search.trim()) {
      const q = search.toLowerCase()
      r = r.filter(p => p.code.toLowerCase().includes(q) || p.name.toLowerCase().includes(q) || p.attrSummary.toLowerCase().includes(q) || p.primaryVendor.toLowerCase().includes(q))
    }
    r = r.filter(p => applyExcelFilters(p, colFilters, [
      { key: "uom" },
      { key: "vendor", accessor: (x: any) => x.primaryVendor },
    ]))
    if (sort === "recent")  r = [...r].sort((a, b) => b.created.localeCompare(a.created))
    if (sort === "code")    r = [...r].sort((a, b) => a.code.localeCompare(b.code))
    if (sort === "on-hand") r = [...r].sort((a, b) => b.onHand - a.onHand)
    return r
  }, [lifecycleFilter, categoryFilter, search, sort, colFilters])

  /* Stat strip */
  const newThisMonth = PRODUCTS.filter(p => p.created.startsWith("2026-04") || p.created.startsWith("2026-03")).length
  const lowStock     = PRODUCTS.filter(p => p.onHand > 0 && p.onHand < p.reorderLevel).length
  const outOfStock   = PRODUCTS.filter(p => p.onHand === 0 && p.lifecycle !== "discontinued").length

  /* Real handlers */
  const onImport = () => (window as any).cenoraToast?.("CSV import…", { variant: "info", sub: "Pick a file · cnr_item bulk-create with template" })
  const onExport = () => (window as any).cenoraToast?.("Exported", { variant: "success", sub: `${rows.length} products · CSV downloaded` })

  return (
    <>
      <TopBar
        breadcrumb={[{ label: "Products · MDM" }, { label: "Products" }]}
      />

      <ActionBar
        title="Item Master"
        status={<><span className="font-mono">cnr_item</span> · {PRODUCTS.length.toLocaleString()} items · {newThisMonth} new this period · <span className="text-warn font-semibold">{lowStock} low</span> · <span className="text-danger font-semibold">{outOfStock} out</span></>}
        search={
          <div className="relative">
            <input
              value={search} onChange={e => setSearch(e.target.value)}
              placeholder="Search code, name, attribute…"
              className="w-64 h-8 pl-8 pr-3 bg-cream border border-divider rounded-md text-[12px] placeholder:text-ink-faint focus:border-brand-mid"
            />
            <Icon name="search" size={13} className="absolute left-2.5 top-1/2 -translate-y-1/2 text-ink-mute" />
          </div>
        }
        extras={
          <Select value={sort} onChange={e => setSort(e.target.value as any)} className="h-8 text-xs w-36">
            <option value="recent">Sort: Recent</option>
            <option value="code">Sort: Item Code</option>
            <option value="on-hand">Sort: On-hand</option>
          </Select>
        }
        secondary={<><Button variant="ghost" leadingIcon="upload" onClick={onImport}>Import CSV</Button><Button variant="ghost" leadingIcon="download" onClick={onExport}>Export</Button></>}
        primary={<Button variant="primary" leadingIcon="plus" onClick={() => push("/products/irq/new")}>Request Item</Button>}
        filters={
          <>
            {(["all", "active", "new", "phasing-out", "discontinued"] as const).map(lc => (
              <FilterChip key={lc}
                active={lifecycleFilter === lc}
                onClick={() => setLifecycleFilter(lc)}
                count={counts[lc]}
                tone={lc === "active" ? "success" : lc === "new" ? "info" : lc === "phasing-out" ? "warn" : "neutral"}>
                {lc === "all" ? "All Items" : LIFECYCLE_LABEL[lc as Exclude<typeof lc, "all">]}
              </FilterChip>
            ))}
            {categoryFilter && (
              <>
                <span className="w-px h-5 bg-divider mx-1" />
                <button onClick={() => setCategoryFilter(null)}
                  className="inline-flex items-center gap-1.5 h-7 px-2.5 rounded-full bg-brand-soft text-brand text-[11px] font-semibold border border-brand/30">
                  <Icon name="folder" size={11} /> {CATEGORY_BY_CODE[categoryFilter]?.name} <Icon name="x" size={11} />
                </button>
              </>
            )}
          </>
        }
      />

      <div className="flex-1 overflow-y-auto bg-app">
        <div className="max-w-[1440px] mx-auto p-6 space-y-4">

          {/* Layout: rail + table */}
          <div className="grid grid-cols-[224px_1fr] gap-4">

            {/* Category rail */}
            <aside className="bg-surface border border-divider rounded-lg p-3 self-start sticky top-4 max-h-[calc(100vh-180px)] overflow-y-auto">
              <div className="text-[10px] uppercase tracking-wider font-bold text-ink-mute mb-2 px-1">By Category</div>
              <button
                onClick={() => setCategoryFilter(null)}
                className={cn(
                  "w-full text-left flex items-center justify-between px-2 py-1.5 rounded text-[12px]",
                  categoryFilter === null ? "bg-brand-soft text-brand font-semibold" : "hover:bg-cream text-ink-soft"
                )}>
                <span>All Categories</span>
                <span className="text-[10px] text-ink-mute">{PRODUCTS.length}</span>
              </button>
              {level1.map(c => {
                const count = PRODUCTS.filter(p => p.category.startsWith(c.code)).length
                if (count === 0) return null
                return (
                  <button key={c.code}
                    onClick={() => setCategoryFilter(c.code)}
                    className={cn(
                      "w-full text-left flex items-center justify-between px-2 py-1.5 rounded text-[12px]",
                      categoryFilter === c.code ? "bg-brand-soft text-brand font-semibold" : "hover:bg-cream text-ink-soft"
                    )}>
                    <span className="truncate"><span className="font-mono text-[10px] text-ink-faint mr-1.5">{c.code}</span>{c.name}</span>
                    <span className="text-[10px] text-ink-mute shrink-0 ml-1">{count}</span>
                  </button>
                )
              })}
            </aside>

            {/* Product table */}
            <div className="bg-surface border border-divider rounded-lg overflow-hidden">
              <header className="px-4 py-2.5 border-b border-divider bg-cream/50 flex items-center justify-between">
                <div className="text-[11px] font-bold uppercase tracking-wider text-ink-mute">
                  Products · <span className="text-ink-soft">{rows.length} of {PRODUCTS.length}</span>
                </div>
                <div className="text-[10px] text-ink-mute">Synced from <span className="font-mono">cnr_item</span> · 2 min ago</div>
              </header>

              {rows.length === 0 ? (
                <div className="p-12 text-center text-ink-mute text-[12px]">No products match these filters.</div>
              ) : (
                <div className="overflow-x-auto">
                <table className="w-full text-[12px]">
                  <thead className="text-[10px] uppercase tracking-wider text-ink-mute font-sans">
                    <tr className="border-b border-divider-soft [&>th]:px-3 [&>th]:py-2 [&>th]:text-left [&>th]:font-bold">
                      <th>Item Code</th>
                      <th>Name · Attributes</th>
                      <th>Category</th>
                      <th>
                        <span className="inline-flex items-center gap-1">
                          UoM
                          <ExcelFilter column="uom" label="UoM" values={distinctUoM} filters={colFilters} setFilters={setColFilters} />
                        </span>
                      </th>
                      <th className="text-right">On Hand</th>
                      <th>
                        <span className="inline-flex items-center gap-1">
                          Vendor
                          <ExcelFilter column="vendor" label="Vendor" values={distinctVendor} filters={colFilters} setFilters={setColFilters} />
                        </span>
                      </th>
                      <th>Status</th>
                    </tr>
                  </thead>
                  <tbody>
                    {rows.map(p => (
                      <ProductRowItem key={p.code} p={p} onClick={() => setSelected(p)} />
                    ))}
                  </tbody>
                </table>
                </div>
              )}
            </div>
          </div>
        </div>
      </div>

      {selected && <ProductDetailSheet product={selected} onClose={() => setSelected(null)} />}
    </>
  )
}

/* ─── Row ────────────────────────────────────────────────────────────────── */
function ProductRowItem({ p, onClick }: { p: typeof PRODUCTS[number]; onClick: () => void }) {
  const crumbs = categoryBreadcrumb(p.category)
  const stockTone =
    p.onHand === 0 && p.lifecycle !== "discontinued" ? "danger" :
    p.onHand < p.reorderLevel                         ? "warn"   :
                                                        "success"
  return (
    <tr onClick={onClick}
        className="border-t border-divider-soft hover:bg-cream/60 cursor-pointer [&>td]:px-3 [&>td]:py-2.5 align-top transition-colors">
      <td>
        <button onClick={onClick} className="font-mono font-bold text-brand-mid text-[11px] hover:underline">
          {p.code}
        </button>
        {p.starred && <Icon name="star" size={10} className="inline ml-1 text-accent fill-accent" />}
      </td>
      <td>
        <div className="font-semibold text-ink leading-snug max-w-md">{p.name}</div>
        <div className="text-[10.5px] text-ink-mute font-mono mt-0.5 max-w-md truncate">{p.attrSummary}</div>
      </td>
      <td>
        <div className="text-[10.5px] text-ink-soft leading-tight max-w-[180px]">
          {crumbs.slice(0, -1).map((c, i) => (
            <span key={i}>{c}<span className="text-ink-faint mx-1">›</span></span>
          ))}
          <span className="font-semibold text-ink">{crumbs[crumbs.length - 1]}</span>
        </div>
        <div className="font-mono text-[10px] text-ink-faint mt-0.5">{p.category}</div>
      </td>
      <td className="font-mono text-[11px] text-ink-soft">{p.uom}</td>
      <td className="text-right">
        <Badge variant={stockTone as any} dot>
          {p.onHand.toLocaleString()}
        </Badge>
        <div className="text-[9.5px] text-ink-mute mt-0.5">{p.onHandWHs} {p.onHandWHs === 1 ? "WH" : "WHs"} · reorder {p.reorderLevel}</div>
      </td>
      <td className="text-[11px] text-ink-soft max-w-[140px] truncate">{p.primaryVendor}</td>
      <td>
        <Badge variant={LIFECYCLE_TONE[p.lifecycle] as any} dot>{LIFECYCLE_LABEL[p.lifecycle]}</Badge>
      </td>
    </tr>
  )
}

/* ─── Detail slideout ────────────────────────────────────────────────────── */
function ProductDetailSheet({ product, onClose }: { product: typeof PRODUCTS[number]; onClose: () => void }) {
  const { push } = useRouter()
  const crumbs = categoryBreadcrumb(product.category)
  const stockTone =
    product.onHand === 0 ? "danger" :
    product.onHand < product.reorderLevel ? "warn" :
    "success"
  /* Attributes that apply to this product's category branch */
  const applicable = ATTRIBUTES.filter(a => a.appliedTo.some(c => product.category.startsWith(c)))

  return (
    <Sheet open={true} onOpenChange={() => onClose()} side="right" className="w-[560px]">
      <SheetHeader>
        <div className="flex items-start justify-between gap-3">
          <div>
            <div className="font-mono text-[10px] text-ink-mute">{product.code}</div>
            <h2 className="font-serif text-xl text-ink mt-1 leading-tight">{product.name}</h2>
            <div className="text-[11px] text-ink-soft mt-1">{crumbs.join(" › ")}</div>
          </div>
          <Badge variant={LIFECYCLE_TONE[product.lifecycle] as any} dot>{LIFECYCLE_LABEL[product.lifecycle]}</Badge>
        </div>
      </SheetHeader>

      <div className="flex-1 overflow-y-auto p-5 space-y-5">
        {/* Stock summary */}
        <section>
          <div className="text-[10px] uppercase tracking-wider font-bold text-ink-mute mb-2">Stock Summary</div>
          <div className="grid grid-cols-3 gap-3">
            <div className="bg-cream/60 border border-divider rounded-md p-3">
              <div className="text-[9px] uppercase tracking-wider font-bold text-ink-mute">On Hand</div>
              <div className="font-serif text-2xl text-ink mt-0.5">{product.onHand}</div>
              <div className="text-[10px] text-ink-mute">{product.uom} · {product.onHandWHs} {product.onHandWHs === 1 ? "WH" : "WHs"}</div>
            </div>
            <div className="bg-cream/60 border border-divider rounded-md p-3">
              <div className="text-[9px] uppercase tracking-wider font-bold text-ink-mute">Reorder</div>
              <div className="font-serif text-2xl text-ink mt-0.5">{product.reorderLevel}</div>
              <Badge variant={stockTone as any} dot className="mt-0.5">
                {product.onHand === 0 ? "Out" : product.onHand < product.reorderLevel ? "Below" : "Healthy"}
              </Badge>
            </div>
            <div className="bg-cream/60 border border-divider rounded-md p-3">
              <div className="text-[9px] uppercase tracking-wider font-bold text-ink-mute">Unit Cost</div>
              <div className="font-serif text-2xl text-ink mt-0.5">{product.currency === "PHP" ? "₱" : product.currency === "SGD" ? "S$" : product.currency === "HKD" ? "HK$" : "$"}{product.unitCost.toLocaleString()}</div>
              <div className="text-[10px] text-ink-mute">{product.currency} · last buy</div>
            </div>
          </div>
        </section>

        {/* Attribute panel */}
        <section>
          <div className="flex items-center justify-between mb-2">
            <div className="text-[10px] uppercase tracking-wider font-bold text-ink-mute">Attributes</div>
            <button onClick={() => { onClose(); push("/products/attributes") }} className="text-[10px] text-brand font-semibold hover:underline">Manage template →</button>
          </div>
          <div className="bg-surface border border-divider rounded-md overflow-hidden">
            {applicable.map((a, i) => (
              <div key={a.id} className={cn("flex items-center justify-between px-3 py-2 text-[12px]", i > 0 && "border-t border-divider-soft")}>
                <div>
                  <span className="font-semibold text-ink-soft">{a.name}</span>
                  {a.required && <span className="ml-1 text-danger">*</span>}
                  {a.unit && <span className="ml-1 text-[10px] text-ink-mute">({a.unit})</span>}
                </div>
                <div className="font-mono text-ink text-[11px]">— defined per item</div>
              </div>
            ))}
            {applicable.length === 0 && (
              <div className="px-3 py-3 text-[11px] text-ink-mute italic">No attribute template applied to this category yet.</div>
            )}
          </div>
        </section>

        {/* Vendor */}
        <section>
          <div className="text-[10px] uppercase tracking-wider font-bold text-ink-mute mb-2">Primary Vendor</div>
          <div className="bg-surface border border-divider rounded-md p-3 flex items-center justify-between">
            <div>
              <div className="font-semibold text-ink text-[13px]">{product.primaryVendor}</div>
              <div className="text-[11px] text-ink-mute">Buy price: {product.currency} · UoM {product.uom}</div>
            </div>
            <Button variant="ghost" size="sm" trailingIcon="arrow-right">View</Button>
          </div>
        </section>

        {/* Recent activity */}
        <section>
          <div className="text-[10px] uppercase tracking-wider font-bold text-ink-mute mb-2">Recent Activity</div>
          <div className="bg-surface border border-divider rounded-md divide-y divide-divider-soft text-[11.5px]">
            <ActivityRow when="Apr 15" who="Joel D." what="Item Receipt IR-1001" detail="+200 PC · LOT-SMK-26041-A" />
            <ActivityRow when="Apr 08" who="Maya C." what="PO-1089 issued"        detail="200 PC · SteelMark · ₱18,400" />
            <ActivityRow when="Apr 03" who="Maria A." what="Cost updated"        detail="₱88 → ₱92 (+4.5%)" />
            <ActivityRow when="Mar 22" who="Ben L."   what="Approved IRQ-0182"   detail="Item registered with code 02010102-014" />
          </div>
        </section>
      </div>

      <footer className="border-t border-divider px-5 py-3 flex items-center justify-between gap-2 shrink-0">
        <Button variant="ghost" leadingIcon="trash"
          onClick={() => (window as any).cenoraToast?.(`Phasing out · ${product.code}`, { variant: "warn", sub: `${product.name.slice(0, 40)} flagged for discontinuation · review required` })}>
          Phase out
        </Button>
        <div className="flex items-center gap-2">
          <Button variant="ghost" onClick={onClose}>Close</Button>
          <Button variant="primary" leadingIcon="edit"
            onClick={() => (window as any).cenoraToast?.(`Editing · ${product.code}`, { variant: "info", sub: "Inline edit form opens here in production" })}>
            Edit item
          </Button>
        </div>
      </footer>
    </Sheet>
  )
}

function ActivityRow({ when, who, what, detail }: { when: string; who: string; what: string; detail: string }) {
  return (
    <div className="px-3 py-2 flex items-baseline gap-2">
      <span className="font-mono text-[10px] text-ink-faint w-12 shrink-0">{when}</span>
      <span className="text-ink"><strong className="font-semibold">{what}</strong> <span className="text-ink-mute">· {detail}</span></span>
      <span className="ml-auto text-[10px] text-ink-mute">{who}</span>
    </div>
  )
}

// SANDBOX
;(globalThis as any).Products = Products

})();/*__IIFE_WRAP_END__*/

/* ═════ apps/web/components/catalogue/categories.tsx ═════ */
;/*__IIFE_WRAP_START__*/(function(){
/**
 * ============================================================================
 * apps/web/components/catalogue/categories.tsx
 * ----------------------------------------------------------------------------
 * Category Tree — interactive 4-level cnr_category hierarchy. This is what
 * powers the cascading picker on the IRQ form and the category facets on
 * Products. Used by category managers to add/rename/move nodes and to see
 * which branches have the most activity.
 *
 * Layout:
 *   • Left: expandable tree with item counts and a brief health pill
 *   • Right: drill-down detail for the currently-selected node — sub-counts,
 *     attribute templates that apply, and the top items in that branch
 * ============================================================================
 */

function Categories() {
  const { push } = useRouter()
  const [selected, setSelected] = React.useState<string>("020101")  /* default to Steel */
  const [expanded, setExpanded] = React.useState<Set<string>>(new Set(["02", "0201"]))
  const [search, setSearch] = React.useState("")

  const toggleExpand = (code: string) => {
    setExpanded(prev => {
      const next = new Set(prev)
      if (next.has(code)) next.delete(code)
      else next.add(code)
      return next
    })
  }

  const total = CATEGORIES.reduce((s, c) => s + c.itemCount, 0)
  const node = CATEGORY_BY_CODE[selected]

  /* Real handlers */
  const onExportTree = () => (window as any).cenoraToast?.("Exported", { variant: "success", sub: `${CATEGORIES.length} L1 categories · tree CSV downloaded` })
  const onNewCategory = () => (window as any).cenoraToast?.("New category…", { variant: "default", sub: "Pick parent level · cnr_category" })

  return (
    <>
      <TopBar
        breadcrumb={[{ label: "Products · MDM" }, { label: "Categories" }]}
      />

      <ActionBar
        title="Category Tree"
        status={<><span className="font-mono">cnr_category</span> · 4-level hierarchy · {CATEGORIES.length} L1 · {total.toLocaleString()} items mapped · revised Apr 12</>}
        search={
          <div className="relative">
            <input
              value={search} onChange={e => setSearch(e.target.value)}
              placeholder="Search categories…"
              className="w-56 h-8 pl-8 pr-3 bg-cream border border-divider rounded-md text-[12px] placeholder:text-ink-faint focus:border-brand-mid"
            />
            <Icon name="search" size={13} className="absolute left-2.5 top-1/2 -translate-y-1/2 text-ink-mute" />
          </div>
        }
        secondary={<Button variant="ghost" leadingIcon="download" onClick={onExportTree}>Export tree</Button>}
        primary={<Button variant="primary" leadingIcon="plus" onClick={onNewCategory}>New Category</Button>}
      />

      <div className="flex-1 overflow-y-auto bg-app">
        <div className="max-w-[1440px] mx-auto p-6 space-y-4">

          {/* Layout: tree | detail */}
          <div className="grid grid-cols-[1fr_440px] gap-4 items-start">

            {/* Tree */}
            <div className="bg-surface border border-divider rounded-lg p-3 max-h-[calc(100vh-180px)] overflow-y-auto">
              {CATEGORIES.map(node => (
                <TreeBranch
                  key={node.code} node={node} depth={0}
                  expanded={expanded} toggleExpand={toggleExpand}
                  selected={selected} onSelect={setSelected}
                  filter={search}
                />
              ))}
            </div>

            {/* Detail panel */}
            <div className="space-y-4 sticky top-4 self-start">
              {node ? <CategoryDetail node={node} push={push} /> : <div className="text-ink-mute text-[12px]">Pick a category to see details</div>}
            </div>

          </div>
        </div>
      </div>
    </>
  )
}

/* ─── Tree branch (recursive) ────────────────────────────────────────────── */
function TreeBranch({ node, depth, expanded, toggleExpand, selected, onSelect, filter }: {
  node: typeof CATEGORIES[number]
  depth: number
  expanded: Set<string>
  toggleExpand: (code: string) => void
  selected: string
  onSelect: (code: string) => void
  filter: string
}) {
  const isOpen = expanded.has(node.code)
  const hasKids = !!node.children?.length
  const isSelected = node.code === selected

  /* Filter: show node if it (or descendants) matches the query */
  const matches = !filter || node.name.toLowerCase().includes(filter.toLowerCase()) || node.code.includes(filter)
  const childrenMatch = node.children?.some(c => bubbleMatch(c, filter)) ?? false
  if (filter && !matches && !childrenMatch) return null

  /* Auto-expand when filtering */
  const showChildren = hasKids && (isOpen || (!!filter && childrenMatch))

  return (
    <>
      <div
        onClick={() => onSelect(node.code)}
        className={cn(
          "group flex items-center gap-1 px-2 py-1.5 rounded text-[12.5px] cursor-pointer transition-colors",
          isSelected ? "bg-brand-soft" : "hover:bg-cream"
        )}
        style={{ paddingLeft: `${depth * 16 + 8}px` }}>
        {hasKids ? (
          <button
            onClick={e => { e.stopPropagation(); toggleExpand(node.code) }}
            className="size-4 flex items-center justify-center text-ink-mute hover:text-ink shrink-0">
            <Icon name={showChildren ? "chevron-down" : "chevron-right"} size={11} />
          </button>
        ) : (
          <span className="size-4 shrink-0 flex items-center justify-center">
            <span className="size-1 rounded-full bg-divider-strong" />
          </span>
        )}
        <span className={cn("font-mono text-[9.5px] shrink-0", isSelected ? "text-brand" : "text-ink-faint")}>
          {node.code}
        </span>
        <span className={cn("truncate flex-1", isSelected ? "font-bold text-brand" : depth === 0 ? "font-semibold text-ink" : "text-ink-soft")}>
          {node.name}
        </span>
        <span className="text-[10px] text-ink-mute font-mono shrink-0 ml-1">{node.itemCount}</span>
        {depth === 0 && <CountBar count={node.itemCount} />}
      </div>
      {showChildren && node.children?.map(c => (
        <TreeBranch
          key={c.code} node={c} depth={depth + 1}
          expanded={expanded} toggleExpand={toggleExpand}
          selected={selected} onSelect={onSelect} filter={filter}
        />
      ))}
    </>
  )
}

/* Recursively check whether any descendant matches the filter */
function bubbleMatch(node: typeof CATEGORIES[number], filter: string): boolean {
  if (!filter) return true
  if (node.name.toLowerCase().includes(filter.toLowerCase()) || node.code.includes(filter)) return true
  return !!node.children?.some(c => bubbleMatch(c, filter))
}

function CountBar({ count }: { count: number }) {
  const max = 312
  const pct = Math.min(100, (count / max) * 100)
  return (
    <div className="w-12 h-1 bg-cream-deep rounded-full overflow-hidden shrink-0 ml-2">
      <div className="h-full bg-brand/70 rounded-full" style={{ width: `${pct}%` }} />
    </div>
  )
}

/* ─── Detail panel ───────────────────────────────────────────────────────── */
function CategoryDetail({ node, push }: { node: typeof CATEGORIES[number]; push: (r: string) => void }) {
  const crumbs = categoryBreadcrumb(node.code)
  const applicableAttrs = ATTRIBUTES.filter(a => a.appliedTo.some(c => node.code.startsWith(c) || c.startsWith(node.code)))
  const itemsInBranch = PRODUCTS.filter(p => p.category.startsWith(node.code))

  return (
    <>
      {/* Header card */}
      <div className="bg-surface border border-divider rounded-lg p-5">
        <div className="text-[10px] uppercase tracking-wider font-bold text-ink-mute">
          {crumbs.slice(0, -1).join(" › ") || `Level ${node.level}`}
        </div>
        <h2 className="font-serif text-2xl text-ink mt-1 leading-tight">{node.name}</h2>
        <div className="flex items-baseline gap-3 mt-2">
          <span className="font-mono text-[11px] text-ink-mute">{node.code}</span>
          <span className="font-mono text-[10px] text-ink-faint">·</span>
          <Badge variant="brand">Level {node.level}</Badge>
        </div>
        <div className="grid grid-cols-3 gap-3 mt-4 pt-4 border-t border-divider-soft">
          <Stat label="Items" value={node.itemCount.toString()} />
          <Stat label="Sub-nodes" value={(node.children?.length ?? 0).toString()} />
          <Stat label="Attr templates" value={applicableAttrs.length.toString()} />
        </div>
        <div className="flex items-center gap-2 mt-4">
          <Button variant="ghost" size="sm" leadingIcon="edit">Rename</Button>
          <Button variant="ghost" size="sm" leadingIcon="external">Move</Button>
          {node.level < 4 && <Button variant="primary" size="sm" leadingIcon="plus">Add child</Button>}
        </div>
      </div>

      {/* Applicable attributes */}
      <div className="bg-surface border border-divider rounded-lg overflow-hidden">
        <header className="px-4 py-2.5 border-b border-divider bg-cream/50 flex items-center justify-between">
          <div className="text-[10px] uppercase tracking-wider font-bold text-ink-mute">Attribute Templates</div>
          <span className="text-[10px] text-ink-mute">{applicableAttrs.length} applied</span>
        </header>
        {applicableAttrs.length === 0 ? (
          <div className="px-4 py-4 text-[11px] text-ink-mute italic">No attributes apply to this level yet.</div>
        ) : (
          <div className="divide-y divide-divider-soft">
            {applicableAttrs.slice(0, 6).map(a => (
              <div key={a.id} className="px-4 py-2 flex items-center justify-between">
                <div>
                  <div className="text-[12px] font-semibold text-ink">{a.name}{a.required && <span className="ml-1 text-danger">*</span>}</div>
                  <div className="text-[10px] text-ink-mute">{FIELD_TYPE_LABEL[a.fieldType]}{a.unit ? ` · ${a.unit}` : ""}</div>
                </div>
                <Badge variant={FIELD_TYPE_TONE[a.fieldType] as any}>{FIELD_TYPE_LABEL[a.fieldType]}</Badge>
              </div>
            ))}
          </div>
        )}
        <footer className="border-t border-divider px-4 py-2 flex justify-end bg-cream/30">
          <button onClick={() => push("/products/attributes")} className="text-[10.5px] text-brand font-semibold hover:underline">Manage templates →</button>
        </footer>
      </div>

      {/* Top items in branch */}
      <div className="bg-surface border border-divider rounded-lg overflow-hidden">
        <header className="px-4 py-2.5 border-b border-divider bg-cream/50 flex items-center justify-between">
          <div className="text-[10px] uppercase tracking-wider font-bold text-ink-mute">Items in this branch</div>
          <span className="text-[10px] text-ink-mute">{itemsInBranch.length} total</span>
        </header>
        {itemsInBranch.length === 0 ? (
          <div className="px-4 py-4 text-[11px] text-ink-mute italic">No products mapped yet — but {node.itemCount} are forecast for this branch.</div>
        ) : (
          <div className="divide-y divide-divider-soft">
            {itemsInBranch.slice(0, 5).map(p => (
              <button key={p.code} onClick={() => push("/catalogue/products")}
                className="w-full px-4 py-2 flex items-center justify-between hover:bg-cream/60 text-left">
                <div className="min-w-0">
                  <div className="text-[12px] font-semibold text-ink truncate max-w-[280px]">{p.name}</div>
                  <div className="font-mono text-[10px] text-ink-mute">{p.code}</div>
                </div>
                <span className="text-[11px] text-ink-soft font-mono">{p.onHand} {p.uom}</span>
              </button>
            ))}
          </div>
        )}
        {itemsInBranch.length > 5 && (
          <footer className="border-t border-divider px-4 py-2 flex justify-end bg-cream/30">
            <button onClick={() => push("/catalogue/products")} className="text-[10.5px] text-brand font-semibold hover:underline">
              See all {itemsInBranch.length} →
            </button>
          </footer>
        )}
      </div>
    </>
  )
}

function Stat({ label, value }: { label: string; value: string }) {
  return (
    <div>
      <div className="text-[9px] uppercase tracking-wider font-bold text-ink-mute">{label}</div>
      <div className="font-serif text-xl text-ink mt-0.5">{value}</div>
    </div>
  )
}

// SANDBOX
;(globalThis as any).Categories = Categories

})();/*__IIFE_WRAP_END__*/

/* ═════ apps/web/components/catalogue/attributes.tsx ═════ */
;/*__IIFE_WRAP_START__*/(function(){
/**
 * ============================================================================
 * apps/web/components/catalogue/attributes.tsx
 * ----------------------------------------------------------------------------
 * Attribute templates — the metadata layer that lets the catalogue handle
 * any item type. Each template defines a field (Diameter, Wattage, ...)
 * with a type and validation, and is bound to one or more category branches.
 *
 * Master ref schema: cnr_attribute + cnr_attributevalue.
 * ============================================================================
 */

function Attributes() {
  const { push } = useRouter()
  const [typeFilter, setTypeFilter] = React.useState<"all" | AttributeTemplate["fieldType"]>("all")
  const [selected, setSelected] = React.useState<AttributeTemplate | null>(ATTRIBUTES[0])
  const [search, setSearch] = React.useState("")

  const filtered = ATTRIBUTES.filter(a => {
    if (typeFilter !== "all" && a.fieldType !== typeFilter) return false
    if (search.trim() && !a.name.toLowerCase().includes(search.toLowerCase())) return false
    return true
  })

  /* Counts per field type */
  const typeCount = (t: AttributeTemplate["fieldType"] | "all") =>
    t === "all" ? ATTRIBUTES.length : ATTRIBUTES.filter(a => a.fieldType === t).length

  /* Real handlers */
  const onExport = () => (window as any).cenoraToast?.("Exported", { variant: "success", sub: `${ATTRIBUTES.length} attribute templates · CSV downloaded` })
  const onNewAttr = () => (window as any).cenoraToast?.("New attribute…", { variant: "default", sub: "Define field · pick type · bind to categories" })

  return (
    <>
      <TopBar
        breadcrumb={[{ label: "Products · MDM" }, { label: "Attributes" }]}
      />

      <ActionBar
        title="Attribute Library"
        status={<><span className="font-mono">cnr_attribute</span> · {ATTRIBUTES.length} templates · {ATTRIBUTES.reduce((s, a) => s + a.appliedCount, 0).toLocaleString()} values across {new Set(ATTRIBUTES.flatMap(a => a.appliedTo)).size} categories</>}
        search={
          <div className="relative">
            <input
              value={search} onChange={e => setSearch(e.target.value)}
              placeholder="Search attribute names…"
              className="w-56 h-8 pl-8 pr-3 bg-cream border border-divider rounded-md text-[12px] placeholder:text-ink-faint focus:border-brand-mid"
            />
            <Icon name="search" size={13} className="absolute left-2.5 top-1/2 -translate-y-1/2 text-ink-mute" />
          </div>
        }
        secondary={<Button variant="ghost" leadingIcon="download" onClick={onExport}>Export</Button>}
        primary={<Button variant="primary" leadingIcon="plus" onClick={onNewAttr}>New Attribute</Button>}
        filters={
          <>
            <FilterChip active={typeFilter === "all"} onClick={() => setTypeFilter("all")} count={typeCount("all")}>All Types</FilterChip>
            {(["text", "number", "decimal", "select", "multi-select", "boolean", "date"] as const).map(t => {
              const c = typeCount(t)
              if (c === 0) return null
              return (
                <FilterChip key={t} active={typeFilter === t} onClick={() => setTypeFilter(t)} count={c} tone={FIELD_TYPE_TONE[t] as any}>
                  {FIELD_TYPE_LABEL[t]}
                </FilterChip>
              )
            })}
          </>
        }
      />

      <div className="flex-1 overflow-y-auto bg-app">
        <div className="max-w-[1440px] mx-auto p-6 space-y-4">

          {/* Layout: list | detail */}
          <div className="grid grid-cols-[1fr_440px] gap-4 items-start">

            {/* Attribute list (card grid) */}
            <div className="space-y-2">
              {filtered.length === 0 ? (
                <div className="bg-surface border border-divider rounded-lg p-12 text-center text-ink-mute text-[12px]">
                  No attributes match these filters.
                </div>
              ) : (
                filtered.map(a => (
                  <AttributeRow
                    key={a.id} attr={a}
                    selected={selected?.id === a.id}
                    onSelect={() => setSelected(a)}
                  />
                ))
              )}
            </div>

            {/* Detail */}
            <div className="space-y-4 sticky top-4 self-start">
              {selected ? <AttributeDetail attr={selected} push={push} /> : <div className="text-ink-mute text-[12px]">Pick an attribute to see details</div>}
            </div>

          </div>
        </div>
      </div>
    </>
  )
}

/* ─── Attribute row card ─────────────────────────────────────────────────── */
function AttributeRow({ attr, selected, onSelect }: { attr: AttributeTemplate; selected: boolean; onSelect: () => void }) {
  return (
    <button onClick={onSelect}
      className={cn(
        "w-full bg-surface border rounded-lg p-4 text-left transition-colors flex items-center gap-4",
        selected ? "border-brand bg-brand-soft/30" : "border-divider hover:border-divider-strong"
      )}>
      <div className={cn(
        "size-10 rounded-md flex items-center justify-center shrink-0 font-mono text-[11px] font-bold",
        attr.fieldType === "number" || attr.fieldType === "decimal" ? "bg-info-soft text-info" :
        attr.fieldType === "select" || attr.fieldType === "multi-select" ? "bg-accent-soft text-accent-deep" :
        attr.fieldType === "boolean" ? "bg-success-soft text-success" :
        attr.fieldType === "date" ? "bg-warn-soft text-warn" :
        "bg-cream text-ink-soft"
      )}>
        {attr.fieldType === "number" || attr.fieldType === "decimal" ? "#" :
         attr.fieldType === "select" ? "◉" :
         attr.fieldType === "multi-select" ? "☰" :
         attr.fieldType === "boolean" ? "Y/N" :
         attr.fieldType === "date" ? "📅" : "Aa"}
      </div>
      <div className="flex-1 min-w-0">
        <div className="flex items-baseline gap-2">
          <div className="text-[13.5px] font-semibold text-ink">{attr.name}</div>
          {attr.required && <Badge variant="danger">Required</Badge>}
          {attr.unit && <span className="text-[10px] text-ink-mute font-mono">({attr.unit})</span>}
        </div>
        <div className="text-[11px] text-ink-mute mt-0.5 flex items-center gap-3">
          <span><Badge variant={FIELD_TYPE_TONE[attr.fieldType] as any}>{FIELD_TYPE_LABEL[attr.fieldType]}</Badge></span>
          <span>·</span>
          <span>Applied to <strong className="text-ink-soft">{attr.appliedTo.length}</strong> {attr.appliedTo.length === 1 ? "category" : "categories"}</span>
          <span>·</span>
          <span><strong className="text-ink-soft">{attr.appliedCount.toLocaleString()}</strong> items use this</span>
        </div>
      </div>
      <Icon name="chevron-right" size={14} className="text-ink-mute shrink-0" />
    </button>
  )
}

/* ─── Detail panel ───────────────────────────────────────────────────────── */
function AttributeDetail({ attr, push }: { attr: AttributeTemplate; push: (r: string) => void }) {
  return (
    <>
      {/* Header card */}
      <div className="bg-surface border border-divider rounded-lg p-5">
        <div className="text-[10px] uppercase tracking-wider font-bold text-ink-mute">Attribute Template</div>
        <h2 className="font-serif text-2xl text-ink mt-1 leading-tight flex items-baseline gap-2">
          {attr.name}
          {attr.unit && <span className="text-[12px] text-ink-mute font-sans">({attr.unit})</span>}
        </h2>
        <div className="flex items-center gap-2 mt-3 flex-wrap">
          <Badge variant={FIELD_TYPE_TONE[attr.fieldType] as any} dot>{FIELD_TYPE_LABEL[attr.fieldType]}</Badge>
          {attr.required && <Badge variant="danger" dot>Required</Badge>}
          {attr.validation && <Badge variant="warn">Rule: <span className="font-mono ml-1">{attr.validation}</span></Badge>}
        </div>

        <div className="grid grid-cols-2 gap-3 mt-4 pt-4 border-t border-divider-soft">
          <Stat label="Applied to" value={`${attr.appliedTo.length} ${attr.appliedTo.length === 1 ? "category" : "categories"}`} />
          <Stat label="In use" value={`${attr.appliedCount.toLocaleString()} products`} />
        </div>

        <div className="flex items-center gap-2 mt-4">
          <Button variant="ghost" size="sm" leadingIcon="edit">Edit</Button>
          <Button variant="ghost" size="sm" leadingIcon="external">Duplicate</Button>
          <Button variant="ghost" size="sm" leadingIcon="trash" className="ml-auto text-danger">Retire</Button>
        </div>
      </div>

      {/* Options for select / multi-select */}
      {attr.options && attr.options.length > 0 && (
        <div className="bg-surface border border-divider rounded-lg overflow-hidden">
          <header className="px-4 py-2.5 border-b border-divider bg-cream/50">
            <div className="text-[10px] uppercase tracking-wider font-bold text-ink-mute">Allowed Values</div>
          </header>
          <div className="p-3 flex flex-wrap gap-1.5">
            {attr.options.map((opt, i) => (
              <span key={i} className="inline-flex items-center px-2.5 py-1 bg-cream rounded-md text-[11px] font-mono text-ink-soft border border-divider">
                {opt}
              </span>
            ))}
          </div>
        </div>
      )}

      {/* Categories this applies to */}
      <div className="bg-surface border border-divider rounded-lg overflow-hidden">
        <header className="px-4 py-2.5 border-b border-divider bg-cream/50 flex items-center justify-between">
          <div className="text-[10px] uppercase tracking-wider font-bold text-ink-mute">Applied To</div>
          <button onClick={() => push("/catalogue/categories")} className="text-[10px] text-brand font-semibold hover:underline">Manage scope →</button>
        </header>
        <div className="divide-y divide-divider-soft">
          {attr.appliedTo.map(catCode => {
            const node = CATEGORY_BY_CODE[catCode]
            if (!node) return null
            const crumbs = categoryBreadcrumb(catCode)
            return (
              <button key={catCode} onClick={() => push("/catalogue/categories")}
                className="w-full px-4 py-2.5 flex items-center justify-between hover:bg-cream/60 text-left">
                <div className="min-w-0">
                  <div className="text-[10.5px] text-ink-mute leading-tight">{crumbs.slice(0, -1).join(" › ")}</div>
                  <div className="text-[12.5px] font-semibold text-ink mt-0.5">{node.name}</div>
                </div>
                <div className="text-right shrink-0 ml-2">
                  <span className="font-mono text-[10px] text-ink-faint block">{catCode}</span>
                  <span className="text-[10.5px] text-ink-mute">{node.itemCount} items</span>
                </div>
              </button>
            )
          })}
        </div>
      </div>

      {/* Field spec for engineers */}
      <div className="bg-cream/60 border border-divider rounded-lg p-4">
        <div className="text-[10px] uppercase tracking-wider font-bold text-ink-mute mb-2">Field Specification</div>
        <div className="font-mono text-[11px] text-ink-soft leading-relaxed space-y-0.5">
          <div><span className="text-ink-faint">id</span>: <span className="text-ink">{attr.id}</span></div>
          <div><span className="text-ink-faint">type</span>: <span className="text-ink">{attr.fieldType}</span></div>
          {attr.unit && <div><span className="text-ink-faint">unit</span>: <span className="text-ink">{attr.unit}</span></div>}
          <div><span className="text-ink-faint">required</span>: <span className="text-ink">{attr.required ? "true" : "false"}</span></div>
          {attr.validation && <div><span className="text-ink-faint">validation</span>: <span className="text-ink">{attr.validation}</span></div>}
        </div>
      </div>
    </>
  )
}

function Stat({ label, value }: { label: string; value: string }) {
  return (
    <div>
      <div className="text-[9px] uppercase tracking-wider font-bold text-ink-mute">{label}</div>
      <div className="font-serif text-lg text-ink mt-0.5 leading-tight">{value}</div>
    </div>
  )
}

// SANDBOX
;(globalThis as any).Attributes = Attributes

})();/*__IIFE_WRAP_END__*/

/* ═════ apps/web/components/finance/finance-dashboard.tsx ═════ */
;/*__IIFE_WRAP_START__*/(function(){
/**
 * ============================================================================
 * apps/web/components/finance/finance-dashboard.tsx
 * ----------------------------------------------------------------------------
 * Screen 11 — Finance command centre. Layered KPIs + P&L snapshot + AP/AR
 * aging matrices + cash-flow forecast.
 * ============================================================================
 */

function FinanceDashboard() {
  const { push } = useRouter()
  const [period, setPeriod] = React.useState<"month" | "ytd" | "quarter">("month")

  return (
    <>
      <TopBar
        breadcrumb={[{ label: "Finance" }, { label: "Dashboard" }]}
        leading={
          <ViewToggle value={period} onChange={(v) => setPeriod(v as any)} options={[
            { value: "month",   label: "Apr 2026" },
            { value: "quarter", label: "Q2 2026"  },
            { value: "ytd",     label: "YTD" },
          ]} />
        }
        actions={
          <>
            <Button variant="ghost" leadingIcon="download">Export</Button>
            <Button variant="primary" leadingIcon="calendar" onClick={() => push("/finance/month-end")}>Month-End</Button>
          </>
        }
      />

      <div className="flex-1 overflow-y-auto bg-app">
        <div className="max-w-[1440px] mx-auto p-6 space-y-5">

          {/* KPI strip */}
          <div className="grid grid-cols-5 gap-3">
            <KpiTile accent="success" label="Revenue · Apr"      value="$198.4k" sub="vs $210k budget" delta="94.5% of plan" deltaDir="up" />
            <KpiTile accent="brand"   label="Gross Margin"       value="43.4%"   sub="$86.2k GP"        delta="+1.2pp"        deltaDir="up" />
            <KpiTile accent="info"    label="Operating Cash"     value="$284.5k" sub="4 accounts · USD" delta="↑ 12.4%"        deltaDir="up" />
            <KpiTile accent="danger"  label="AP Overdue"         value="$41.2k"  sub="3 vendors"         delta="↑ $8.1k"       deltaDir="down" />
            <KpiTile accent="warn"    label="AR · over 60d"      value="$46.6k"  sub="2 customers"       delta="Bright HK 62d" deltaDir="down" />
          </div>

          {/* P&L card */}
          <div className="grid grid-cols-[1.4fr_1fr] gap-4">
            <Card>
              <CardHeader>
                <CardTitle>Income Statement — April 2026</CardTitle>
                <button className="text-[11px] text-brand font-semibold hover:underline" onClick={() => push("/reports/library")}>Full P&L →</button>
              </CardHeader>
              <PnlTable />
            </Card>
            <CashForecastCard />
          </div>

          {/* AP & AR aging side-by-side */}
          <div className="grid grid-cols-2 gap-4">
            <AgingMatrix title="AR Aging by Customer" rows={AR_AGING} keyField="customer" cta={() => push("/reports/library")} />
            <AgingMatrix title="AP Aging by Vendor"  rows={AP_AGING} keyField="vendor"   cta={() => push("/reports/library")} />
          </div>

          {/* Month-end status strip */}
          <MonthEndProgressCard push={push} />

        </div>
      </div>
    </>
  )
}

/* ─── P&L table ───────────────────────────────────────────────────────── */
function PnlTable() {
  const rows = [
    { kind: "h",  label: "Revenue" },
    { kind: "r",  label: "Product Sales",        actual: 158400, budget: 168000 },
    { kind: "r",  label: "Service Revenue",      actual: 40000,  budget: 42000 },
    { kind: "tot",label: "Total Revenue",        actual: 198400, budget: 210000 },
    { kind: "h",  label: "Cost of Goods Sold" },
    { kind: "r",  label: "Materials",            actual: 84200,  budget: 88000 },
    { kind: "r",  label: "Direct Labour",        actual: 28000,  budget: 28000 },
    { kind: "tot",label: "Total COGS",           actual: 112200, budget: 116000 },
    { kind: "tot",label: "Gross Profit",         actual: 86200,  budget: 94000, accent: true },
    { kind: "h",  label: "Operating Expenses" },
    { kind: "r",  label: "Salaries & Benefits",  actual: 32400,  budget: 32000 },
    { kind: "r",  label: "Rent & Utilities",     actual: 8100,   budget: 7600 },
    { kind: "r",  label: "Marketing",            actual: 4200,   budget: 6000 },
    { kind: "r",  label: "Professional Services",actual: 5800,   budget: 5000 },
    { kind: "tot",label: "Total OPEX",           actual: 50500,  budget: 50600 },
    { kind: "tot",label: "Operating Income",     actual: 35700,  budget: 43400, accent: true },
  ] as const

  const v = (a: number, b: number) => {
    const pct = ((a - b) / b) * 100
    return { pct, dir: pct >= 0 ? "up" : "down" }
  }

  return (
    <table className="w-full text-[12px]">
      <thead>
        <tr className="bg-cream text-[10px] font-bold uppercase tracking-wider text-ink-mute">
          <th className="px-4 py-2 text-left">Line Item</th>
          <th className="px-3 text-right">Actual</th>
          <th className="px-3 text-right">Budget</th>
          <th className="px-3 text-right">Variance</th>
        </tr>
      </thead>
      <tbody>
        {rows.map((r: any, i) => {
          if (r.kind === "h") return <tr key={i}><td colSpan={4} className="px-4 pt-3 pb-1 text-[10px] font-bold uppercase tracking-wider text-ink-mute">{r.label}</td></tr>
          const variance = v(r.actual, r.budget)
          return (
            <tr key={i} className={cn("border-t border-divider-soft", r.kind === "tot" && "font-bold")}>
              <td className={cn("px-4 py-2", r.kind === "tot" ? "text-ink" : "text-ink-soft pl-7")}>{r.label}</td>
              <td className={cn("px-3 text-right font-mono", r.accent && "text-success text-[13px]")}>{formatCurrency(r.actual)}</td>
              <td className="px-3 text-right font-mono text-ink-soft">{formatCurrency(r.budget)}</td>
              <td className={cn("px-3 text-right font-mono text-[11px]", variance.dir === "up" ? "text-success" : "text-danger")}>
                {variance.dir === "up" ? "+" : ""}{variance.pct.toFixed(1)}%
              </td>
            </tr>
          )
        })}
      </tbody>
    </table>
  )
}

/* ─── Cash forecast card ───────────────────────────────────────────────── */
function CashForecastCard() {
  const points = [
    { d: "Apr 17", v: 284500 },
    { d: "Apr 20", v: 281200 },
    { d: "Apr 22", v: 326800 },
    { d: "Apr 24", v: 322400 },
    { d: "Apr 26", v: 314000 },
    { d: "Apr 28", v: 271200 },
    { d: "Apr 30", v: 309800 },
  ]
  const max = Math.max(...points.map(p => p.v)) * 1.05
  const min = Math.min(...points.map(p => p.v)) * 0.93
  const pathD = points.map((p, i) => {
    const x = (i / (points.length - 1)) * 100
    const y = 100 - ((p.v - min) / (max - min)) * 100
    return `${i === 0 ? "M" : "L"}${x.toFixed(2)},${y.toFixed(2)}`
  }).join(" ")
  return (
    <Card>
      <CardHeader>
        <CardTitle>14-Day Cash Forecast</CardTitle>
        <Badge variant="info">AI · live</Badge>
      </CardHeader>
      <div className="p-4 space-y-3">
        <div className="flex items-baseline justify-between">
          <div>
            <div className="text-[10px] font-bold uppercase tracking-wider text-ink-mute">Apr 30 projection</div>
            <div className="font-serif text-3xl text-ink">$309.8k</div>
          </div>
          <Badge variant="success" dot>No liquidity risk</Badge>
        </div>
        <div className="relative h-24">
          <svg viewBox="0 0 100 100" preserveAspectRatio="none" className="w-full h-full">
            <defs>
              <linearGradient id="cashFill" x1="0" x2="0" y1="0" y2="1">
                <stop offset="0%"  stopColor="var(--brand)" stopOpacity="0.25" />
                <stop offset="100%" stopColor="var(--brand)" stopOpacity="0" />
              </linearGradient>
            </defs>
            <path d={`${pathD} L100,100 L0,100 Z`} fill="url(#cashFill)" />
            <path d={pathD} fill="none" stroke="var(--brand)" strokeWidth="1.5" vectorEffect="non-scaling-stroke" />
          </svg>
        </div>
        <div className="flex justify-between text-[9px] text-ink-mute">
          {points.map(p => <span key={p.d}>{p.d.split(" ")[1]}</span>)}
        </div>
        <div className="border-t border-divider-soft pt-2 space-y-1 text-[11px]">
          <div className="flex justify-between"><span className="text-ink-mute">Expected inflows</span><span className="text-success font-mono font-semibold">+$120.8k</span></div>
          <div className="flex justify-between"><span className="text-ink-mute">Expected outflows</span><span className="text-danger font-mono font-semibold">-$95.5k</span></div>
        </div>
      </div>
    </Card>
  )
}

/* ─── Aging matrix (reusable) ──────────────────────────────────────────── */
function AgingMatrix({ title, rows, keyField, cta }: { title: string; rows: any[]; keyField: string; cta: () => void }) {
  const totals = rows.reduce((acc, r) => ({
    current: acc.current + r.current,
    b30: acc.b30 + r.b30,
    b60: acc.b60 + r.b60,
    b90: acc.b90 + r.b90,
  }), { current: 0, b30: 0, b60: 0, b90: 0 })
  const total = totals.current + totals.b30 + totals.b60 + totals.b90
  return (
    <Card>
      <CardHeader>
        <CardTitle>{title}</CardTitle>
        <button onClick={cta} className="text-[11px] text-brand font-semibold hover:underline">Full report →</button>
      </CardHeader>
      {/* Stacked bar across all */}
      <div className="px-4 pt-3 space-y-1.5">
        <div className="h-3 w-full rounded-full overflow-hidden flex">
          {totals.current > 0 && <div className="bg-success" style={{ width: `${(totals.current / total) * 100}%` }} />}
          {totals.b30 > 0 &&    <div className="bg-info"    style={{ width: `${(totals.b30 / total) * 100}%` }} />}
          {totals.b60 > 0 &&    <div className="bg-warn"    style={{ width: `${(totals.b60 / total) * 100}%` }} />}
          {totals.b90 > 0 &&    <div className="bg-danger"  style={{ width: `${(totals.b90 / total) * 100}%` }} />}
        </div>
        <div className="grid grid-cols-4 text-[10px] gap-1">
          <span className="text-success font-mono font-semibold">{formatCurrency(totals.current)}<span className="text-ink-mute font-normal ml-1">current</span></span>
          <span className="text-info    font-mono font-semibold">{formatCurrency(totals.b30)}<span className="text-ink-mute font-normal ml-1">1-30d</span></span>
          <span className="text-warn    font-mono font-semibold">{formatCurrency(totals.b60)}<span className="text-ink-mute font-normal ml-1">31-60d</span></span>
          <span className="text-danger  font-mono font-semibold">{formatCurrency(totals.b90)}<span className="text-ink-mute font-normal ml-1">60d+</span></span>
        </div>
      </div>
      <table className="w-full text-[12px] mt-2">
        <tbody>
          {rows.map(r => {
            const sum = r.current + r.b30 + r.b60 + r.b90
            const overdue = r.b60 + r.b90
            return (
              <tr key={r[keyField]} className="border-t border-divider-soft">
                <td className="px-4 py-2 text-ink">{r[keyField]}</td>
                <td className="px-3 text-right font-mono text-ink-soft">{formatCurrency(sum)}</td>
                <td className="px-3 text-right text-[11px]">
                  {overdue > 0
                    ? <Badge variant="danger" dot>{formatCurrency(overdue)} overdue</Badge>
                    : <Badge variant="success" dot>current</Badge>}
                </td>
              </tr>
            )
          })}
        </tbody>
      </table>
    </Card>
  )
}

/* ─── Month-end progress strip ─────────────────────────────────────────── */
function MonthEndProgressCard({ push }: { push: (h: string) => void }) {
  const done = MONTH_END_TASKS.filter(t => t.status === "done").length
  const total = MONTH_END_TASKS.length
  const pct = (done / total) * 100
  const blockers = MONTH_END_TASKS.filter(t => t.status === "blocked" || t.status === "in-progress")
  return (
    <Card>
      <CardHeader>
        <CardTitle>April Close — Status</CardTitle>
        <button onClick={() => push("/finance/month-end")} className="text-[11px] text-brand font-semibold hover:underline">Open checklist →</button>
      </CardHeader>
      <div className="p-4 grid grid-cols-[1fr_2fr] gap-6 items-center">
        <div className="space-y-2">
          <div className="flex items-baseline gap-2">
            <span className="font-serif text-3xl text-ink">{done}/{total}</span>
            <span className="text-[11px] text-ink-mute">steps complete</span>
          </div>
          <div className="h-2 rounded-full bg-cream-deep overflow-hidden">
            <div className="h-full bg-brand rounded-full transition-all" style={{ width: `${pct}%` }} />
          </div>
          <div className="text-[10.5px] text-ink-mute">Target close: <strong className="text-ink">Apr 30</strong> · 13 days remaining</div>
        </div>
        <div className="space-y-1.5">
          <div className="text-[10px] font-bold uppercase tracking-wider text-ink-mute">Active items</div>
          {blockers.slice(0, 4).map(t => (
            <div key={t.id} className="flex items-center gap-2 text-[12px]">
              <span className={cn(
                "size-1.5 rounded-full",
                t.status === "blocked" ? "bg-danger" : "bg-warn"
              )} />
              <span className="text-ink">{t.title}</span>
              <span className="text-[10px] text-ink-mute ml-auto">
                {t.status === "blocked" ? "Blocked" : "In progress"} · {t.owner}
              </span>
            </div>
          ))}
        </div>
      </div>
    </Card>
  )
}

// SANDBOX
;(globalThis as any).FinanceDashboard = FinanceDashboard

})();/*__IIFE_WRAP_END__*/

/* ═════ apps/web/components/finance/bank-recon.tsx ═════ */
;/*__IIFE_WRAP_START__*/(function(){
/**
 * ============================================================================
 * apps/web/components/finance/bank-recon.tsx
 * ----------------------------------------------------------------------------
 * Screen 12 — Bank Reconciliation. Two-pane (Bank ↔ Ledger) drag-or-click
 * matcher. Click a bank row, then click a ledger row to match. AI button
 * batch-matches the obvious ones.
 * ============================================================================
 */

function BankRecon() {
  const { push } = useRouter()
  const [matched, setMatched] = React.useState<string[]>([]) /* ledger row ids */
  const [selectedBank, setSelectedBank] = React.useState<string | null>(null)

  const unmatchedBank   = BANK_UNMATCHED.filter(r => {
    const ledgerMatch = LEDGER_UNMATCHED.find(l => l.suggested === r.id)
    return !ledgerMatch || !matched.includes(ledgerMatch.id)
  })
  const unmatchedLedger = LEDGER_UNMATCHED.filter(r => !matched.includes(r.id))

  function tryMatch(bankId: string, ledgerId: string) {
    const bank   = BANK_UNMATCHED.find(b => b.id === bankId)
    const ledger = LEDGER_UNMATCHED.find(l => l.id === ledgerId)
    if (!bank || !ledger) return
    if (bank.amount === ledger.amount && bank.dir === ledger.dir) {
      setMatched(m => [...m, ledgerId])
      setSelectedBank(null)
    }
  }
  function autoMatchAll() {
    const next = LEDGER_UNMATCHED
      .filter(l => !matched.includes(l.id))
      .filter(l => BANK_UNMATCHED.find(b => b.id === l.suggested))
      .map(l => l.id)
    setMatched(m => [...m, ...next])
  }
  function reset() { setMatched([]); setSelectedBank(null) }

  const matchedCount = BANK_STATEMENT.matchedCount + matched.length
  const unmatchedCount = BANK_STATEMENT.unmatchedCount - matched.length
  const fmt = (n: number) => new Intl.NumberFormat("en-PH", { style: "currency", currency: "PHP", minimumFractionDigits: 0 }).format(n)

  return (
    <>
      <TopBar
        breadcrumb={[{ label: "Finance" }, { label: "Bank Reconciliation" }]}
        actions={
          <>
            <Button variant="ghost" leadingIcon="download">Export</Button>
            <Button variant="ghost" onClick={reset}>Reset</Button>
            <Button variant="accent" leadingIcon="sparkle" onClick={autoMatchAll}>AI auto-match</Button>
          </>
        }
      />

      {/* Summary strip */}
      <div className="shrink-0 bg-surface border-b border-divider px-5 py-3 grid grid-cols-5 gap-4">
        <Stat label="Account"    value={BANK_STATEMENT.accountLabel} mono />
        <Stat label="Period"     value="Apr 1 – Apr 17, 2026" />
        <Stat label="Closing Balance" value={fmt(BANK_STATEMENT.closingBalance)} tone="brand" />
        <Stat label="Matched"    value={`${matchedCount} / 48`} tone="success" />
        <Stat label="Unmatched"  value={`${unmatchedCount}`} tone={unmatchedCount > 0 ? "warn" : "success"} />
      </div>

      {/* Two-pane */}
      <div className="flex-1 grid grid-cols-[1fr_64px_1fr] overflow-hidden">
        {/* BANK */}
        <ReconColumn
          title="Bank Statement"
          subtitle={`${BANK_STATEMENT.accountLabel} · imported Apr 17 06:00`}
          icon="credit-card"
          tint="bg-info-soft"
        >
          <SectionLabel>Unmatched — pick a row to match</SectionLabel>
          {unmatchedBank.map(r => (
            <TxnRow key={r.id} txn={r} side="bank"
              selected={selectedBank === r.id}
              onClick={() => setSelectedBank(r.id)} />
          ))}

          <SectionLabel done>✓ Matched ({matchedCount})</SectionLabel>
          {[...BANK_UNMATCHED.filter(b => {
            const l = LEDGER_UNMATCHED.find(x => x.suggested === b.id)
            return l && matched.includes(l.id)
          })].map(r => <TxnRow key={r.id} txn={r} side="bank" muted />)}
          <SampleMatched side="bank" />
        </ReconColumn>

        {/* MATCH GUTTER */}
        <div className="bg-cream border-x border-divider flex flex-col items-center justify-start pt-12 gap-3">
          <div className="size-12 rounded-full bg-surface border-2 border-dashed border-divider-strong flex items-center justify-center text-ink-mute">
            <Icon name="link" size={18} />
          </div>
          <div className="text-[10px] text-center px-2 leading-relaxed text-ink-mute uppercase tracking-wider font-bold">
            Match<br />Zone
          </div>
          {selectedBank && (
            <div className="text-[10px] text-center text-brand-mid font-semibold px-2 mt-2">
              {BANK_UNMATCHED.find(b => b.id === selectedBank)?.desc.slice(0, 18)}…<br />
              <span className="text-ink-mute font-normal">→ pick ledger row</span>
            </div>
          )}
        </div>

        {/* LEDGER */}
        <ReconColumn
          title="Ledger Entries"
          subtitle="From Cenora GL"
          icon="doc"
          tint="bg-accent-soft"
        >
          <SectionLabel>Unmatched — click to match selected bank row</SectionLabel>
          {unmatchedLedger.map(r => {
            const isSuggested = !!selectedBank && r.suggested === selectedBank
            return (
              <TxnRow key={r.id} txn={r} side="ledger"
                highlighted={isSuggested}
                onClick={() => selectedBank && tryMatch(selectedBank, r.id)} />
            )
          })}

          <SectionLabel done>✓ Matched ({matchedCount})</SectionLabel>
          {LEDGER_UNMATCHED.filter(l => matched.includes(l.id)).map(r => <TxnRow key={r.id} txn={r} side="ledger" muted />)}
          <SampleMatched side="ledger" />
        </ReconColumn>
      </div>
    </>
  )
}

function Stat({ label, value, mono, tone }: { label: string; value: any; mono?: boolean; tone?: string }) {
  return (
    <div>
      <div className="text-[9px] font-bold uppercase tracking-wider text-ink-mute">{label}</div>
      <div className={cn(
        "mt-0.5 text-[13px] font-semibold",
        mono && "font-mono text-[12px]",
        tone === "brand" && "text-brand",
        tone === "success" && "text-success",
        tone === "warn" && "text-warn",
        !tone && "text-ink",
      )}>{value}</div>
    </div>
  )
}

function ReconColumn({ title, subtitle, icon, tint, children }: any) {
  return (
    <section className="flex flex-col min-h-0 overflow-hidden">
      <header className={cn("shrink-0 px-4 py-2.5 border-b border-divider flex items-center gap-2", tint)}>
        <span className="size-7 rounded bg-surface flex items-center justify-center text-ink-soft">
          <Icon name={icon} size={13} />
        </span>
        <div className="flex-1 min-w-0">
          <div className="text-[12px] font-bold text-ink">{title}</div>
          <div className="text-[10px] text-ink-mute truncate">{subtitle}</div>
        </div>
      </header>
      <div className="flex-1 overflow-y-auto bg-app">{children}</div>
    </section>
  )
}

function SectionLabel({ children, done }: { children: React.ReactNode; done?: boolean }) {
  return (
    <div className={cn(
      "px-4 py-1.5 text-[10px] font-bold uppercase tracking-wider sticky top-0 z-10 border-b border-divider",
      done ? "bg-success-soft text-success" : "bg-cream text-ink-mute"
    )}>{children}</div>
  )
}

function TxnRow({ txn, side, selected, highlighted, muted, onClick }: any) {
  const fmt = (n: number) => new Intl.NumberFormat("en-PH", { style: "currency", currency: "PHP", minimumFractionDigits: 0 }).format(n)
  return (
    <button
      onClick={onClick}
      disabled={muted}
      className={cn(
        "w-full grid grid-cols-[60px_1fr_auto] gap-3 px-4 py-2.5 border-b border-divider-soft text-left transition-all",
        muted          && "bg-surface/60 opacity-60",
        selected       && "bg-brand-soft border-l-4 border-l-brand pl-3",
        highlighted    && "bg-accent-soft/70 border-l-4 border-l-accent pl-3 animate-pulse",
        !muted && !selected && !highlighted && "bg-surface hover:bg-cream cursor-pointer"
      )}>
      <div className="text-[10.5px] text-ink-mute">{txn.date}</div>
      <div className="min-w-0">
        <div className="text-[12px] font-semibold text-ink truncate">{txn.desc}</div>
        {txn.ref && <div className="text-[10px] text-ink-mute truncate">{txn.ref}</div>}
      </div>
      <div className={cn(
        "font-mono font-bold text-[12px]",
        txn.dir === "credit" ? "text-success" : "text-danger"
      )}>
        {txn.dir === "credit" ? "+" : "−"}{fmt(txn.amount)}
      </div>
    </button>
  )
}

/* Cosmetic — render the "previously matched" rows so the matched list isn't empty */
function SampleMatched({ side }: { side: "bank" | "ledger" }) {
  const rows = side === "bank" ? [
    { date: "Apr 11", desc: "METRO RETAIL CHAIN",          amount: 2016000, dir: "credit", ref: "OTC deposit" },
    { date: "Apr 10", desc: "PACIFIC SOLAR PH - DEPOSIT",  amount: 1320000, dir: "debit",  ref: "AP payment"   },
  ] : [
    { date: "Apr 11", desc: "AR Receipt — Metro Retail Chain", amount: 2016000, dir: "credit", ref: "INV-HVPH-0805" },
    { date: "Apr 10", desc: "AP Payment — Pacific Solar PH",   amount: 1320000, dir: "debit",  ref: "BILL-HVPH-0398" },
  ]
  return <>{rows.map((r, i) => <TxnRow key={i} txn={r} side={side} muted />)}</>
}

// SANDBOX
;(globalThis as any).BankRecon = BankRecon

})();/*__IIFE_WRAP_END__*/

/* ═════ apps/web/components/finance/month-end-close.tsx ═════ */
;/*__IIFE_WRAP_START__*/(function(){
/**
 * ============================================================================
 * apps/web/components/finance/month-end-close.tsx
 * ----------------------------------------------------------------------------
 * Screen 13 — Month-End Close. Task checklist grouped by phase, with owner,
 * due date, blocked / in-progress / done states, and a progress ring.
 * Clicking a task expands its panel with the action button.
 * ============================================================================
 */

function MonthEndClose() {
  const { push } = useRouter()
  const [tasks, setTasks] = React.useState(() => MONTH_END_TASKS.map(t => ({ ...t })))
  const [openId, setOpenId] = React.useState<string | null>(null)

  const done = tasks.filter(t => t.status === "done").length
  const inProgress = tasks.filter(t => t.status === "in-progress").length
  const blocked = tasks.filter(t => t.status === "blocked").length
  const total = tasks.length
  const pct = (done / total) * 100

  function setStatus(id: string, status: any) {
    setTasks(ts => ts.map(t => t.id === id ? { ...t, status } : t))
  }

  const groups: Record<string, typeof tasks> = {}
  tasks.forEach(t => { (groups[t.group] ??= []).push(t) })

  return (
    <>
      <TopBar
        breadcrumb={[{ label: "Finance" }, { label: "Month-End Close" }]}
        actions={
          <>
            <Button variant="ghost" leadingIcon="download">Export</Button>
            <Button variant="primary" leadingIcon="lock">Hard Close — Apr</Button>
          </>
        }
      />

      <div className="flex-1 overflow-y-auto bg-app">
        <div className="max-w-[1280px] mx-auto p-6 space-y-5">

          {/* Hero strip */}
          <Card>
            <div className="p-5 grid grid-cols-[auto_1fr_auto] gap-6 items-center">
              {/* Ring */}
              <ProgressRing pct={pct} />
              <div className="space-y-2">
                <div className="flex items-baseline gap-3">
                  <h1 className="font-serif text-2xl text-ink">April 2026 Close</h1>
                  <Badge variant="brand">Period open · HVPH</Badge>
                </div>
                <div className="text-[12.5px] text-ink-soft leading-relaxed">
                  {done} of {total} tasks complete · {inProgress} in progress · {blocked > 0 && <strong className="text-danger">{blocked} blocked</strong>}{blocked === 0 && <span>no blockers</span>}
                </div>
                <div className="flex items-center gap-1.5 text-[11px] text-ink-mute">
                  <Icon name="calendar" size={11} />
                  Target close: <strong className="text-ink">Apr 30</strong> · 13 days remaining
                  <span className="mx-2 opacity-30">·</span>
                  <Icon name="user" size={11} />
                  Responsible: <strong className="text-ink">Maria A.</strong> (Sr Accountant)
                </div>
              </div>
              <div className="flex flex-col gap-2 text-right">
                <Button variant="accent" leadingIcon="sparkle">AI: What's blocking close?</Button>
                <Button variant="ghost" size="sm" onClick={() => push("/finance/bank-recon")} leadingIcon="credit-card">Continue Bank Recon</Button>
              </div>
            </div>
          </Card>

          {/* Task groups */}
          {Object.entries(groups).map(([group, list]) => (
            <section key={group}>
              <h2 className="text-[10px] font-bold uppercase tracking-wider text-ink-mute mb-2 flex items-center gap-2">
                <span className={cn(
                  "size-2 rounded-full",
                  group === "Pre-close"  && "bg-success",
                  group === "Close"      && "bg-warn",
                  group === "Post-close" && "bg-info",
                )} />
                {group}
                <span className="text-ink-faint font-normal">({list.filter(t => t.status === "done").length}/{list.length})</span>
              </h2>
              <Card>
                <div className="divide-y divide-divider-soft">
                  {list.map(t => (
                    <TaskRow key={t.id} t={t}
                      open={openId === t.id}
                      onToggle={() => setOpenId(o => o === t.id ? null : t.id)}
                      onComplete={() => { setStatus(t.id, "done"); setOpenId(null) }}
                      onProgress={() => setStatus(t.id, "in-progress")}
                    />
                  ))}
                </div>
              </Card>
            </section>
          ))}
        </div>
      </div>
    </>
  )
}

function ProgressRing({ pct }: { pct: number }) {
  const r = 36
  const c = 2 * Math.PI * r
  const dash = (pct / 100) * c
  return (
    <div className="relative size-[100px]">
      <svg viewBox="0 0 100 100" className="size-full -rotate-90">
        <circle cx="50" cy="50" r={r} stroke="var(--divider)" strokeWidth="8" fill="none" />
        <circle cx="50" cy="50" r={r} stroke="var(--brand)" strokeWidth="8" fill="none"
          strokeDasharray={`${dash} ${c}`} strokeLinecap="round" />
      </svg>
      <div className="absolute inset-0 flex flex-col items-center justify-center">
        <span className="font-serif text-2xl text-ink leading-none">{Math.round(pct)}%</span>
        <span className="text-[9px] text-ink-mute uppercase tracking-wider mt-0.5">complete</span>
      </div>
    </div>
  )
}

function TaskRow({ t, open, onToggle, onComplete, onProgress }: any) {
  const statusBadge: any = {
    done:          { variant: "success", label: "Done",        icon: "check" },
    "in-progress": { variant: "warn",    label: "In Progress", icon: "clock" },
    todo:          { variant: "neutral", label: "To do",       icon: "circle" },
    blocked:       { variant: "danger",  label: "Blocked",     icon: "alert-triangle" },
  }
  const sb = statusBadge[t.status]
  return (
    <>
      <button onClick={onToggle} className="w-full grid grid-cols-[auto_1fr_auto_auto_auto] gap-4 px-4 py-2.5 items-center hover:bg-cream/60 transition-colors text-left">
        {/* Checkbox-style status icon */}
        <div className={cn(
          "size-6 rounded-full flex items-center justify-center shrink-0 border-2",
          t.status === "done"        && "bg-success border-success text-white",
          t.status === "in-progress" && "bg-warn-soft border-warn text-warn",
          t.status === "todo"        && "bg-surface border-divider text-ink-faint",
          t.status === "blocked"     && "bg-danger-soft border-danger text-danger",
        )}>
          {t.status === "done" && <Icon name="check" size={12} strokeWidth={3} />}
          {t.status === "blocked" && <Icon name="x" size={11} strokeWidth={3} />}
        </div>

        <div className="min-w-0">
          <div className={cn("text-[13px] font-medium", t.status === "done" ? "text-ink-mute line-through" : "text-ink")}>{t.title}</div>
          {t.note && <div className="text-[11px] text-ink-mute mt-0.5">{t.note}</div>}
        </div>

        <div className="flex items-center gap-2">
          <Avatar initials={t.ownerInitials} tone={t.ownerTone} size="sm" />
          <span className="text-[11px] text-ink-soft hidden md:inline">{t.owner}</span>
        </div>

        <div className="text-[11px] text-ink-mute">Apr {t.dueDay}</div>

        <Badge variant={sb.variant as any}>{sb.label}</Badge>
      </button>
      {open && (
        <div className="px-4 pb-4 pt-1 pl-14 bg-cream/40 border-t border-divider-soft">
          <div className="bg-surface border border-divider rounded-md p-3 flex items-center justify-between gap-3">
            <div className="text-[12px] text-ink-soft">
              {t.status === "blocked" && <><strong className="text-danger">Blocked: </strong>{t.note ?? "Waiting on dependency"}</>}
              {t.status === "in-progress" && <><strong className="text-warn">In progress: </strong>{t.note ?? "Owner is working on this."}</>}
              {t.status === "todo" && <>Owner hasn't started this yet.</>}
              {t.status === "done" && <strong className="text-success">Completed.</strong>}
            </div>
            <div className="flex items-center gap-1.5">
              {t.status !== "done" && t.status !== "in-progress" && <Button variant="ghost" size="sm" onClick={onProgress}>Start</Button>}
              {t.status !== "done" && <Button variant="primary" size="sm" leadingIcon="check" onClick={onComplete}>Mark done</Button>}
            </div>
          </div>
        </div>
      )}
    </>
  )
}

// SANDBOX
;(globalThis as any).MonthEndClose = MonthEndClose

})();/*__IIFE_WRAP_END__*/

/* ═════ apps/web/components/finance/general-ledger.tsx ═════ */
;/*__IIFE_WRAP_START__*/(function(){
/**
 * apps/web/components/finance/general-ledger.tsx
 * Finance — General Ledger view (journal entries + chart of accounts).
 */

function GeneralLedger() {
  const [tab, setTab] = React.useState<"journal" | "coa">("journal")
  const [period, setPeriod] = React.useState("Apr 2026")
  return (
    <>
      <TopBar breadcrumb={[{ label: "Finance" }, { label: "General Ledger" }]} />
      <ActionBar
        title="General Ledger"
        status={`${period} · Period status: open · 1,284 entries · $1.84M net activity`}
        leading={
          <div className="ml-2 flex items-center gap-1.5">
            <button onClick={() => setTab("journal")} className={cn("h-7 px-3 rounded-md text-[11px] font-semibold", tab === "journal" ? "bg-brand text-white" : "bg-cream text-ink-soft hover:bg-cream-deep")}>Journal entries</button>
            <button onClick={() => setTab("coa")}     className={cn("h-7 px-3 rounded-md text-[11px] font-semibold", tab === "coa"     ? "bg-brand text-white" : "bg-cream text-ink-soft hover:bg-cream-deep")}>Chart of Accounts</button>
          </div>
        }
        primary={<Button variant="primary" leadingIcon="plus" size="sm">New JE</Button>}
        secondary={<Button variant="ghost" leadingIcon="download" size="sm">Trial balance</Button>}
        ai={<Button variant="subtle" leadingIcon="sparkle" size="sm">Anomaly scan</Button>}
      />
      <div className="flex-1 overflow-y-auto bg-app">
        <div className="max-w-[1440px] mx-auto p-6 space-y-4">
          {/* KPI strip — mirrors the module dashboards so the ledger reads as a workspace, not a bare table */}
          <div className="grid grid-cols-[1.5fr_1fr_1fr_1fr_1fr] gap-3">
            <div className="bg-gradient-to-br from-brand to-brand-light rounded-lg p-5 text-white">
              <div className="text-[10px] font-bold uppercase tracking-wider text-accent">Net activity · April</div>
              <div className="font-serif text-[36px] leading-none mt-1.5">$1.84M</div>
              <div className="text-[12px] text-white/70 mt-1.5">1,284 entries posted · period open</div>
            </div>
            <KpiTile label="Entries"       value="1,284"      sub="92% auto-posted"   accent="info" />
            <KpiTile label="Unposted"      value="3"          sub="2 need review"     accent="warn" />
            <KpiTile label="Trial balance" value="Balanced"   sub="Debits = credits"   accent="success" />
            <KpiTile label="Period"        value="Open"       sub="Target close 5 May" accent="brand" />
          </div>

          {tab === "journal" ? <JournalView /> : <COAView />}

          {/* Movement by account class + close readiness — gives the page a full bottom like the module dashboards */}
          <div className="grid grid-cols-[2fr_1fr] gap-4">
            <GLMovementCard />
            <GLCloseReadinessCard />
          </div>
        </div>
      </div>
    </>
  )
}

/* April Dr/Cr movement per account class — the bar reads Dr (brand) ▸ Cr (accent),
 * sized against the busiest class so the period's weight is scannable at a glance. */
function GLMovementCard() {
  const classes = [
    { name: "Assets",      dr: 3_200_000, cr: 2_860_000 },
    { name: "Liabilities", dr: 1_140_000, cr: 1_420_000 },
    { name: "Equity",      dr: 0,         cr: 180_000 },
    { name: "Revenue",     dr: 120_000,   cr: 3_940_000 },
    { name: "Expense",     dr: 4_160_000, cr: 220_000 },
  ]
  const max = Math.max(...classes.map(c => c.dr + c.cr))
  const fmt = (v: number) => v === 0 ? "$0" : v >= 1_000_000 ? `$${(v / 1_000_000).toFixed(2)}M` : `$${Math.round(v / 1000)}k`
  return (
    <Card>
      <CardHeader>
        <div>
          <div className="text-[10px] uppercase tracking-wider font-bold text-ink-mute">Movement by account class</div>
          <div className="font-serif text-[18px] text-ink mt-0.5">April · debits vs credits</div>
        </div>
        <div className="flex items-center gap-3 text-[10px] font-semibold text-ink-mute">
          <span className="inline-flex items-center gap-1.5"><span className="size-2 rounded-sm bg-brand" />Debit</span>
          <span className="inline-flex items-center gap-1.5"><span className="size-2 rounded-sm bg-accent" />Credit</span>
        </div>
      </CardHeader>
      <div className="p-4 space-y-3">
        {classes.map(c => {
          const total = c.dr + c.cr
          return (
            <div key={c.name}>
              <div className="flex items-center justify-between mb-1">
                <span className="text-[11.5px] text-ink font-medium">{c.name}</span>
                <span className="text-[10.5px] font-mono text-ink-mute">
                  <span className="text-brand-mid font-bold">{fmt(c.dr)}</span> Dr · <span className="text-accent-deep font-bold">{fmt(c.cr)}</span> Cr
                </span>
              </div>
              <div className="h-2.5 bg-cream rounded-full overflow-hidden flex" style={{ width: `${(total / max) * 100}%` }}>
                <div className="h-full bg-brand" style={{ width: `${(c.dr / total) * 100}%` }} />
                <div className="h-full bg-accent" style={{ width: `${(c.cr / total) * 100}%` }} />
              </div>
            </div>
          )
        })}
      </div>
    </Card>
  )
}

/* Period-close readiness — the "is April safe to close?" snapshot. */
function GLCloseReadinessCard() {
  const items = [
    { label: "Bank reconciliations",     detail: "4 of 5 cleared",      done: false },
    { label: "Sub-ledgers tied to GL",   detail: "AP · AR · Inventory", done: true },
    { label: "FX revaluation posted",    detail: "JE-2026-04-0089",     done: true },
    { label: "Intercompany eliminations", detail: "1 entry pending",     done: false },
    { label: "Accruals reviewed",        detail: "2 open items",        done: false },
  ]
  const cleared = items.filter(i => i.done).length
  return (
    <Card>
      <CardHeader>
        <div>
          <div className="text-[10px] uppercase tracking-wider font-bold text-ink-mute">Close readiness</div>
          <div className="font-serif text-[18px] text-ink mt-0.5">{cleared} of {items.length} ready</div>
        </div>
        <Button variant="ghost" size="sm" trailingIcon="arrow-right">Close room</Button>
      </CardHeader>
      <div className="p-3 space-y-1.5">
        {items.map(i => (
          <div key={i.label} className="flex items-center gap-2.5 px-2 py-1.5 rounded-md hover:bg-cream/50">
            <span className={cn(
              "size-5 shrink-0 inline-flex items-center justify-center rounded-full",
              i.done ? "bg-success-soft text-success" : "bg-warn-soft text-warn"
            )}>
              <Icon name={i.done ? "check" : "clock"} size={11} strokeWidth={2.5} />
            </span>
            <div className="min-w-0 flex-1">
              <div className="text-[11.5px] text-ink font-medium leading-tight">{i.label}</div>
              <div className="text-[10px] text-ink-mute leading-tight">{i.detail}</div>
            </div>
          </div>
        ))}
      </div>
    </Card>
  )
}

function JournalView() {
  const journals = [
    { id: "JE-2026-04-0089", date: "30 Apr 2026", memo: "April FX revaluation · all entities", debit: 41820, credit: 41820, source: "Auto · FX", entity: "HVG", lines: 12 },
    { id: "JE-2026-04-0088", date: "29 Apr 2026", memo: "Calamba project · April labor accrual", debit: 28400, credit: 28400, source: "Manual", entity: "HVPH", lines: 6 },
    { id: "JE-2026-04-0087", date: "29 Apr 2026", memo: "April salary expense allocation", debit: 184200, credit: 184200, source: "Auto · Payroll", entity: "HVPH", lines: 24 },
    { id: "JE-2026-04-0086", date: "28 Apr 2026", memo: "April depreciation run · 392 assets", debit: 38420, credit: 38420, source: "Auto · Assets", entity: "HVG", lines: 392 },
    { id: "JE-2026-04-0085", date: "28 Apr 2026", memo: "Reverse March accrual · vendor bills", debit: 12400, credit: 12400, source: "Auto · Reversal", entity: "HVSG", lines: 8 },
    { id: "JE-2026-04-0084", date: "27 Apr 2026", memo: "Intercompany invoice · HVSG → HVHK", debit: 28000, credit: 28000, source: "Intercompany", entity: "HVSG ⇄ HVHK", lines: 4 },
    { id: "JE-2026-04-0083", date: "26 Apr 2026", memo: "Bank fees · April · all entities", debit: 1240,  credit: 1240,  source: "Auto · Bank", entity: "HVG", lines: 5 },
    { id: "JE-2026-04-0082", date: "25 Apr 2026", memo: "Inventory write-down · obsolete SKUs", debit: 8400,  credit: 8400,  source: "Manual", entity: "HVPH", lines: 14 },
  ]
  return (
    <Card>
      <div className="grid grid-cols-[150px_100px_2fr_120px_120px_140px_100px_60px] gap-x-3 px-4 py-2 bg-cream text-[10px] uppercase tracking-wider font-bold text-ink-mute">
        <span>JE #</span><span>Date</span><span>Memo</span><span className="text-right">Debit</span><span className="text-right">Credit</span><span>Source</span><span>Entity</span><span></span>
      </div>
      {journals.map(j => (
        <div key={j.id} className="grid grid-cols-[150px_100px_2fr_120px_120px_140px_100px_60px] gap-x-3 px-4 py-2.5 items-center border-t border-divider-soft hover:bg-cream/40 text-[11.5px]">
          <span className="font-mono font-bold text-brand-mid">{j.id}</span>
          <span className="text-ink-soft">{j.date}</span>
          <div>
            <div className="text-ink">{j.memo}</div>
            <div className="text-[10px] text-ink-mute">{j.lines} lines</div>
          </div>
          <span className="font-mono text-right">${j.debit.toLocaleString()}</span>
          <span className="font-mono text-right">${j.credit.toLocaleString()}</span>
          <span className="text-[10.5px] text-ink-mute">{j.source}</span>
          <span className="font-mono text-ink-mute">{j.entity}</span>
          <button className="size-6 inline-flex items-center justify-center rounded text-ink-mute hover:bg-cream hover:text-ink"><Icon name="eye" size={11} /></button>
        </div>
      ))}
    </Card>
  )
}

function COAView() {
  const accounts = [
    { code: "1000", name: "Cash & Cash Equivalents", type: "Asset", balance: 284_500, dr: true },
    { code: "1100", name: "Accounts Receivable",      type: "Asset", balance: 638_000, dr: true },
    { code: "1200", name: "Inventory",                type: "Asset", balance: 1_840_000, dr: true },
    { code: "1500", name: "Fixed Assets — Equipment", type: "Asset", balance: 4_280_000, dr: true },
    { code: "1599", name: "Accumulated Depreciation", type: "Contra", balance: -1_120_000, dr: false },
    { code: "2000", name: "Accounts Payable",         type: "Liability", balance: 248_600, dr: false },
    { code: "2100", name: "Accrued Expenses",         type: "Liability", balance: 88_400, dr: false },
    { code: "2200", name: "VAT Payable",              type: "Liability", balance: 142_000, dr: false },
    { code: "3000", name: "Common Stock",             type: "Equity", balance: 2_000_000, dr: false },
    { code: "3100", name: "Retained Earnings",        type: "Equity", balance: 3_180_000, dr: false },
    { code: "4000", name: "Revenue · Services",       type: "Revenue", balance: 1_840_000, dr: false },
    { code: "4100", name: "Revenue · Goods",          type: "Revenue", balance: 2_100_000, dr: false },
    { code: "5000", name: "COGS · Materials",         type: "Expense", balance: 1_640_000, dr: true },
    { code: "6000", name: "Salaries & Wages",         type: "Expense", balance: 1_184_000, dr: true },
    { code: "6100", name: "Rent & Utilities",         type: "Expense", balance: 168_000, dr: true },
  ]
  return (
    <Card>
      <div className="grid grid-cols-[100px_2fr_120px_140px_100px] px-4 py-2 bg-cream text-[10px] uppercase tracking-wider font-bold text-ink-mute">
        <span>Code</span><span>Account</span><span>Type</span><span className="text-right">Balance (USD)</span><span></span>
      </div>
      {accounts.map(a => (
        <div key={a.code} className="grid grid-cols-[100px_2fr_120px_140px_100px] px-4 py-2.5 items-center border-t border-divider-soft hover:bg-cream/40 text-[11.5px]">
          <span className="font-mono font-bold text-brand-mid">{a.code}</span>
          <span className="text-ink">{a.name}</span>
          <span className="text-ink-soft">{a.type}</span>
          <span className={cn("font-mono text-right font-bold", a.balance < 0 ? "text-danger" : "text-ink")}>${Math.abs(a.balance).toLocaleString()}{a.balance < 0 ? " CR" : ""}</span>
          <Button variant="ghost" size="sm">Drill</Button>
        </div>
      ))}
    </Card>
  )
}

// SANDBOX
;(globalThis as any).GeneralLedger = GeneralLedger

})();/*__IIFE_WRAP_END__*/

/* ═════ apps/web/components/finance/accounts-payable.tsx ═════ */
;/*__IIFE_WRAP_START__*/(function(){
/**
 * apps/web/components/finance/accounts-payable.tsx
 * Finance — Accounts Payable. Vendor bills with aging buckets.
 */

function AccountsPayable() {
  const bills = [
    { id: "BILL-HVPH-0468", vendor: "Pacific Steel Co.",       amount: 87420, ccy: "USD", due: "20 May 2026", aging: "current",  status: "approved",      entity: "HVPH", terms: "Net 30" },
    { id: "BILL-HVPH-0467", vendor: "Premier Power Inc.",      amount: 22480, ccy: "USD", due: "15 May 2026", aging: "current",  status: "approval",       entity: "HVPH", terms: "Net 30" },
    { id: "BILL-HVHK-0467", vendor: "Yuen Long Logistics",     amount: 20030, ccy: "USD", due: "10 May 2026", aging: "current",  status: "approval",       entity: "HVHK", terms: "Net 30" },
    { id: "BILL-HVSG-0289", vendor: "Tan Office Supplies",     amount: 1485,  ccy: "USD", due: "30 Apr 2026", aging: "overdue",   status: "approved",      entity: "HVSG", terms: "Net 15" },
    { id: "BILL-HVSG-0288", vendor: "Singapore Power",         amount: 14820, ccy: "USD", due: "25 Apr 2026", aging: "30+ days", status: "approved",       entity: "HVSG", terms: "Net 30" },
    { id: "BILL-HVAU-0184", vendor: "Sydney Office Cleaning",  amount: 2680,  ccy: "USD", due: "5 May 2026",  aging: "current",  status: "scheduled",     entity: "HVAU", terms: "Net 15" },
    { id: "BILL-HVAU-0183", vendor: "TollExpress AU",          amount: 18500, ccy: "USD", due: "18 May 2026", aging: "current",  status: "approval",       entity: "HVAU", terms: "Net 30" },
    { id: "BILL-HVIN-0238", vendor: "Devanand Packaging",      amount: 10100, ccy: "USD", due: "12 May 2026", aging: "current",  status: "approval",       entity: "HVIN", terms: "Net 30" },
    { id: "BILL-HVIN-0237", vendor: "Mumbai Power",            amount: 8420,  ccy: "USD", due: "20 Apr 2026", aging: "30+ days", status: "approved",       entity: "HVIN", terms: "Net 30" },
    { id: "BILL-HVHK-0466", vendor: "HK Bank — Card",          amount: 2840,  ccy: "USD", due: "25 Apr 2026", aging: "30+ days", status: "approved",       entity: "HVHK", terms: "Net 30" },
    { id: "BILL-HVPH-0466", vendor: "Globe Telecom",           amount: 1820,  ccy: "USD", due: "10 Apr 2026", aging: "60+ days", status: "approved",       entity: "HVPH", terms: "Net 30" },
  ]

  const aging = {
    current: bills.filter(b => b.aging === "current").reduce((s, b) => s + b.amount, 0),
    overdue: bills.filter(b => b.aging === "overdue").reduce((s, b) => s + b.amount, 0),
    days30:  bills.filter(b => b.aging === "30+ days").reduce((s, b) => s + b.amount, 0),
    days60:  bills.filter(b => b.aging === "60+ days").reduce((s, b) => s + b.amount, 0),
  }
  const total = aging.current + aging.overdue + aging.days30 + aging.days60

  return (
    <>
      <TopBar breadcrumb={[{ label: "Finance" }, { label: "Accounts Payable" }]} />
      <ActionBar
        title="Accounts Payable"
        status={`${bills.length} bills · $${(total / 1000).toFixed(0)}k outstanding · ${bills.filter(b => b.status === "approval").length} pending approval`}
        primary={<Button variant="primary" leadingIcon="dollar" size="sm">Schedule payments</Button>}
        secondary={<Button variant="ghost" leadingIcon="plus" size="sm">Record bill</Button>}
        ai={<Button variant="subtle" leadingIcon="sparkle" size="sm">Optimize cashflow</Button>}
      />
      <div className="flex-1 overflow-y-auto bg-app">
        <div className="max-w-[1280px] mx-auto p-6 space-y-4">
          {/* Aging */}
          <div className="grid grid-cols-4 gap-3">
            <KpiTile label="Current"   value={`$${(aging.current / 1000).toFixed(0)}k`} sub="Due in next 30 days" accent="success" />
            <KpiTile label="Overdue"   value={`$${(aging.overdue / 1000).toFixed(0)}k`} sub={`${bills.filter(b => b.aging === "overdue").length} bills`} accent="warn" />
            <KpiTile label="30+ days"  value={`$${(aging.days30 / 1000).toFixed(0)}k`} sub="Past due" accent="danger" />
            <KpiTile label="60+ days"  value={`$${(aging.days60 / 1000).toFixed(0)}k`} sub="Critical" accent="danger" />
          </div>

          <Card>
            <CardHeader>
              <div>
                <div className="text-[10px] uppercase tracking-wider font-bold text-ink-mute">Vendor bills</div>
                <div className="font-serif text-[18px] text-ink mt-0.5">All entities</div>
              </div>
            </CardHeader>
            <div className="grid grid-cols-[150px_2fr_120px_120px_100px_120px_100px_80px] px-4 py-2 bg-cream text-[10px] uppercase tracking-wider font-bold text-ink-mute border-y border-divider">
              <span>Bill #</span><span>Vendor</span><span>Entity / Terms</span><span className="text-right">Amount</span><span>Due</span><span>Aging</span><span>Status</span><span></span>
            </div>
            {bills.map(b => (
              <div key={b.id} className="grid grid-cols-[150px_2fr_120px_120px_100px_120px_100px_80px] px-4 py-2.5 items-center border-t border-divider-soft hover:bg-cream/40 text-[11.5px]">
                <span className="font-mono font-bold text-brand-mid">{b.id}</span>
                <span className="text-ink font-medium">{b.vendor}</span>
                <span><span className="font-mono text-ink-mute">{b.entity}</span><div className="text-[9.5px] text-ink-mute">{b.terms}</div></span>
                <span className="font-mono text-right font-bold">${b.amount.toLocaleString()}</span>
                <span className="text-ink-soft">{b.due}</span>
                {b.aging === "current"   ? <Badge variant="success">Current</Badge>
                : b.aging === "overdue"  ? <Badge variant="warn">Overdue</Badge>
                                         : <Badge variant="danger">{b.aging}</Badge>}
                {b.status === "approval"  ? <Badge variant="warn" dot>Approval</Badge>
                : b.status === "approved" ? <Badge variant="info">Approved</Badge>
                                          : <Badge variant="success" dot>Scheduled</Badge>}
                <Button variant="ghost" size="sm">Pay</Button>
              </div>
            ))}
          </Card>
        </div>
      </div>
    </>
  )
}

// SANDBOX
;(globalThis as any).AccountsPayable = AccountsPayable

})();/*__IIFE_WRAP_END__*/

/* ═════ apps/web/components/finance/accounts-receivable.tsx ═════ */
;/*__IIFE_WRAP_START__*/(function(){
/**
 * apps/web/components/finance/accounts-receivable.tsx
 * Finance — Accounts Receivable. Customer invoices with aging buckets.
 */

function AccountsReceivable() {
  const invs = [
    { id: "INV-HVPH-0412", customer: "Pacific Steel Co.",      amount: 142_000, due: "30 May 2026", aging: "current",  status: "sent",     entity: "HVPH" },
    { id: "INV-HVPH-0411", customer: "Calamba Devt Corp.",     amount:  88_400, due: "25 May 2026", aging: "current",  status: "sent",     entity: "HVPH" },
    { id: "INV-HVPH-0410", customer: "Ayala Land",             amount:  64_200, due: "20 May 2026", aging: "current",  status: "viewed",   entity: "HVPH" },
    { id: "INV-HVPH-0408", customer: "Pacific Steel Co.",      amount:  28_000, due: "30 Apr 2026", aging: "overdue",  status: "viewed",   entity: "HVPH" },
    { id: "INV-HVSG-0186", customer: "Tan Beng Holdings",      amount:  88_500, due: "28 May 2026", aging: "current",  status: "sent",     entity: "HVSG" },
    { id: "INV-HVSG-0184", customer: "DBS Bank",               amount:  14_200, due: "10 Apr 2026", aging: "30+ days", status: "viewed",   entity: "HVSG" },
    { id: "INV-HVHK-0098", customer: "Yuen Long Logistics",    amount:  18_400, due: "5 May 2026",  aging: "current",  status: "sent",     entity: "HVHK" },
    { id: "INV-HVAU-0224", customer: "Crown Holdings",         amount: 161_525, due: "30 May 2026", aging: "current",  status: "sent",     entity: "HVAU" },
    { id: "INV-HVAU-0222", customer: "Westfield Group",        amount:  82_400, due: "20 May 2026", aging: "current",  status: "viewed",   entity: "HVAU" },
    { id: "INV-HVAU-0218", customer: "Crown Holdings",         amount:  42_000, due: "25 Apr 2026", aging: "30+ days", status: "viewed",   entity: "HVAU" },
    { id: "INV-HVIN-0152", customer: "Devanand Logistics",     amount:  64_400, due: "15 May 2026", aging: "current",  status: "sent",     entity: "HVIN" },
    { id: "INV-HVIN-0148", customer: "Stellar Tech Ltd.",      amount:  28_800, due: "10 Apr 2026", aging: "60+ days", status: "overdue",  entity: "HVIN" },
  ]
  const aging = {
    current: invs.filter(b => b.aging === "current").reduce((s, b) => s + b.amount, 0),
    overdue: invs.filter(b => b.aging === "overdue").reduce((s, b) => s + b.amount, 0),
    days30:  invs.filter(b => b.aging === "30+ days").reduce((s, b) => s + b.amount, 0),
    days60:  invs.filter(b => b.aging === "60+ days").reduce((s, b) => s + b.amount, 0),
  }
  const total = aging.current + aging.overdue + aging.days30 + aging.days60

  return (
    <>
      <TopBar breadcrumb={[{ label: "Finance" }, { label: "Accounts Receivable" }]} />
      <ActionBar
        title="Accounts Receivable"
        status={`${invs.length} invoices · $${(total / 1000).toFixed(0)}k outstanding · $${(aging.days30 + aging.days60).toLocaleString()} in collections`}
        primary={<Button variant="primary" leadingIcon="send" size="sm">Send reminders</Button>}
        secondary={<Button variant="ghost" leadingIcon="plus" size="sm">New invoice</Button>}
        ai={<Button variant="subtle" leadingIcon="sparkle" size="sm">Collection priorities</Button>}
      />
      <div className="flex-1 overflow-y-auto bg-app">
        <div className="max-w-[1280px] mx-auto p-6 space-y-4">
          <div className="grid grid-cols-4 gap-3">
            <KpiTile label="Current"   value={`$${(aging.current / 1000).toFixed(0)}k`} sub="Within terms" accent="success" />
            <KpiTile label="Overdue"   value={`$${(aging.overdue / 1000).toFixed(0)}k`} sub={`${invs.filter(b => b.aging === "overdue").length} invoices`} accent="warn" />
            <KpiTile label="30+ days"  value={`$${(aging.days30 / 1000).toFixed(0)}k`} sub="Follow-up needed" accent="danger" />
            <KpiTile label="60+ days"  value={`$${(aging.days60 / 1000).toFixed(0)}k`} sub="Escalate" accent="danger" />
          </div>

          <Card>
            <CardHeader>
              <div>
                <div className="text-[10px] uppercase tracking-wider font-bold text-ink-mute">Customer invoices</div>
                <div className="font-serif text-[18px] text-ink mt-0.5">All entities · April–May</div>
              </div>
            </CardHeader>
            <div className="grid grid-cols-[150px_2fr_100px_120px_100px_120px_120px_80px] px-4 py-2 bg-cream text-[10px] uppercase tracking-wider font-bold text-ink-mute border-y border-divider">
              <span>Invoice #</span><span>Customer</span><span>Entity</span><span className="text-right">Amount</span><span>Due</span><span>Aging</span><span>Status</span><span></span>
            </div>
            {invs.map(b => (
              <div key={b.id} className="grid grid-cols-[150px_2fr_100px_120px_100px_120px_120px_80px] px-4 py-2.5 items-center border-t border-divider-soft hover:bg-cream/40 text-[11.5px]">
                <span className="font-mono font-bold text-brand-mid">{b.id}</span>
                <span className="text-ink font-medium">{b.customer}</span>
                <span className="font-mono text-ink-mute">{b.entity}</span>
                <span className="font-mono text-right font-bold">${b.amount.toLocaleString()}</span>
                <span className="text-ink-soft">{b.due}</span>
                {b.aging === "current"  ? <Badge variant="success">Current</Badge>
                : b.aging === "overdue" ? <Badge variant="warn">Overdue</Badge>
                                        : <Badge variant="danger">{b.aging}</Badge>}
                {b.status === "sent"     ? <Badge variant="info" dot>Sent</Badge>
                : b.status === "viewed"  ? <Badge variant="neutral">Viewed</Badge>
                                          : <Badge variant="danger">Overdue</Badge>}
                <Button variant="ghost" size="sm">Open</Button>
              </div>
            ))}
          </Card>
        </div>
      </div>
    </>
  )
}

// SANDBOX
;(globalThis as any).AccountsReceivable = AccountsReceivable

})();/*__IIFE_WRAP_END__*/

/* ═════ apps/web/components/finance/cash-bank.tsx ═════ */
;/*__IIFE_WRAP_START__*/(function(){
/**
 * apps/web/components/finance/cash-bank.tsx
 * Finance — Cash & Bank. Bank accounts across all entities.
 */

function CashBank() {
  const accounts = [
    { id: "ATL-CASH-1",   bank: "BPI",   ccy: "PHP", name: "BPI · Operating",          entity: "HVPH", balanceCcy: 12_840_000, balanceUsd: 225_500, status: "synced", lastSync: "5m ago" },
    { id: "ATL-CASH-2",   bank: "BPI",   ccy: "PHP", name: "BPI · Payroll",            entity: "HVPH", balanceCcy: 1_840_000,  balanceUsd: 32_300,  status: "synced", lastSync: "5m ago" },
    { id: "ATL-CASH-3",   bank: "BDO",   ccy: "PHP", name: "BDO · Vendor sweep",       entity: "HVPH", balanceCcy: 3_280_000,  balanceUsd: 57_600,  status: "synced", lastSync: "5m ago" },
    { id: "ATL-CASH-4",   bank: "DBS",   ccy: "SGD", name: "DBS · Main",               entity: "HVSG", balanceCcy:   148_400,  balanceUsd: 109_800, status: "synced", lastSync: "8m ago" },
    { id: "ATL-CASH-5",   bank: "DBS",   ccy: "SGD", name: "DBS · Payroll",            entity: "HVSG", balanceCcy:    62_400,  balanceUsd:  46_200, status: "synced", lastSync: "8m ago" },
    { id: "ATL-CASH-6",   bank: "HSBC",  ccy: "HKD", name: "HSBC · Operating",         entity: "HVHK", balanceCcy:   480_000,  balanceUsd:  61_500, status: "syncing", lastSync: "Syncing now" },
    { id: "ATL-CASH-7",   bank: "ANZ",   ccy: "AUD", name: "ANZ · Operating",          entity: "HVAU", balanceCcy:   228_400,  balanceUsd: 148_500, status: "synced", lastSync: "12m ago" },
    { id: "ATL-CASH-8",   bank: "ANZ",   ccy: "AUD", name: "ANZ · Payroll",            entity: "HVAU", balanceCcy:    88_400,  balanceUsd:  57_460, status: "synced", lastSync: "12m ago" },
    { id: "ATL-CASH-9",   bank: "HDFC",  ccy: "INR", name: "HDFC · Operating",         entity: "HVIN", balanceCcy: 14_280_000, balanceUsd: 171_640, status: "synced", lastSync: "10m ago" },
    { id: "ATL-CASH-10",  bank: "ICICI", ccy: "INR", name: "ICICI · Payroll",          entity: "HVIN", balanceCcy:  2_840_000, balanceUsd:  34_140, status: "synced", lastSync: "10m ago" },
  ]
  const total = accounts.reduce((s, a) => s + a.balanceUsd, 0)
  function prefix(c: string) { return c === "PHP" ? "₱" : c === "SGD" ? "S$" : c === "HKD" ? "HK$" : c === "AUD" ? "A$" : c === "INR" ? "₹" : "$" }
  return (
    <>
      <TopBar breadcrumb={[{ label: "Finance" }, { label: "Cash & Bank" }]} />
      <ActionBar
        title="Cash & Bank"
        status={`${accounts.length} accounts · $${(total / 1000).toFixed(0)}k total · Open Banking sync · 4 banks connected`}
        primary={<Button variant="primary" leadingIcon="plus" size="sm">Add account</Button>}
        secondary={<Button variant="ghost" leadingIcon="refresh" size="sm">Sync all</Button>}
      />
      <div className="flex-1 overflow-y-auto bg-app">
        <div className="max-w-[1280px] mx-auto p-6 space-y-4">
          <div className="grid grid-cols-4 gap-3">
            <KpiTile label="Total cash"   value={`$${(total / 1000).toFixed(0)}k`} sub="All entities · USD-equiv" accent="success" />
            <KpiTile label="USD"          value={"$0"} sub="No USD accounts" accent="brand" />
            <KpiTile label="Highest"      value={"HDFC · ₹14.3M"} sub="$171.6k · India" accent="brand" />
            <KpiTile label="In flight"    value={"$28k"} sub="Pending settlements" accent="warn" />
          </div>

          <Card>
            <CardHeader>
              <div>
                <div className="text-[10px] uppercase tracking-wider font-bold text-ink-mute">Bank accounts</div>
                <div className="font-serif text-[18px] text-ink mt-0.5">All entities</div>
              </div>
              <Button variant="ghost" size="sm" leadingIcon="settings">Manage connectors</Button>
            </CardHeader>
            {accounts.map(a => (
              <div key={a.id} className="grid grid-cols-[80px_2fr_140px_140px_140px_140px_120px] px-4 py-3 items-center border-t border-divider-soft hover:bg-cream/40 text-[11.5px]">
                <span className="font-mono font-bold text-brand-mid">{a.bank}</span>
                <div>
                  <div className="text-ink font-semibold">{a.name}</div>
                  <div className="text-[10px] text-ink-mute font-mono">{a.id}</div>
                </div>
                <span className="font-mono text-ink-mute">{a.entity}</span>
                <span className="font-mono text-right">{prefix(a.ccy)} {a.balanceCcy.toLocaleString()}</span>
                <span className="font-mono text-right">${a.balanceUsd.toLocaleString()}</span>
                <span className="text-[10.5px] text-ink-mute">
                  {a.status === "syncing" ? <Badge variant="info" dot>Syncing</Badge> : <Badge variant="success" dot>Synced</Badge>}
                  <div className="mt-0.5">{a.lastSync}</div>
                </span>
                <Button variant="ghost" size="sm">Open</Button>
              </div>
            ))}
          </Card>
        </div>
      </div>
    </>
  )
}

// SANDBOX
;(globalThis as any).CashBank = CashBank

})();/*__IIFE_WRAP_END__*/

/* ═════ apps/web/components/inventory/stock-dashboard.tsx ═════ */
;/*__IIFE_WRAP_START__*/(function(){
/**
 * ============================================================================
 * apps/web/components/inventory/stock-dashboard.tsx
 * ----------------------------------------------------------------------------
 * Screen 14 — Stock Dashboard. KPIs, low-stock matrix, by-warehouse split,
 * and the stock-level table with inline status pills.
 * ============================================================================
 */

function StockDashboard() {
  const { push } = useRouter()
  const [wh, setWh] = React.useState<string>("all")
  const [status, setStatus] = React.useState<"all" | "low" | "out" | "expiring">("all")
  const [query, setQuery] = React.useState("")

  const filtered = React.useMemo(() => (STOCK_ROWS as any[]).filter(r => {
    if (wh !== "all" && r.warehouse !== wh) return false
    if (status !== "all" && r.status !== status) return false
    if (query && !(`${r.itemCode} ${r.description}`).toLowerCase().includes(query.toLowerCase())) return false
    return true
  }), [wh, status, query])

  const warehouses = Array.from(new Set(STOCK_ROWS.map(r => r.warehouse)))

  return (
    <>
      <TopBar
        breadcrumb={[{ label: "Warehouse" }, { label: "Stock Dashboard" }]}
        actions={
          <>
            <Button variant="ghost" leadingIcon="download">Export</Button>
            <Button variant="ghost" leadingIcon="upload">Stock Adjustment</Button>
            <Button variant="primary" leadingIcon="check-square" onClick={() => push("/inventory/cycle-count")}>Start Cycle Count</Button>
          </>
        }
      />

      <Subheader right={<SearchBox value={query} onChange={setQuery} placeholder="Search SKUs…" className="w-56" />}>
        <FilterChip active={wh === "all"} onClick={() => setWh("all")}>All Warehouses</FilterChip>
        {warehouses.map(w => (
          <FilterChip key={w} active={wh === w} onClick={() => setWh(w)}>{w}</FilterChip>
        ))}
        <span className="w-px h-5 bg-divider mx-1" />
        <FilterChip active={status === "all"}      onClick={() => setStatus("all")}>All Status</FilterChip>
        <FilterChip active={status === "low"}      onClick={() => setStatus("low")} tone="danger" icon="alert-triangle">Low</FilterChip>
        <FilterChip active={status === "out"}      onClick={() => setStatus("out")} tone="danger">Out of Stock</FilterChip>
        <FilterChip active={status === "expiring"} onClick={() => setStatus("expiring")} icon="clock">Expiring 30d</FilterChip>
      </Subheader>

      <div className="flex-1 overflow-y-auto bg-app">
        <div className="p-5 space-y-5">

          {/* KPI tiles */}
          <div className="grid grid-cols-5 gap-3">
            <KpiTile accent="brand"   label="Stock Value"     value={formatCurrency(STOCK_KPIS.totalValue)} sub="Across 4 warehouses" />
            <KpiTile accent="info"    label="Unique SKUs"     value={STOCK_KPIS.uniqueSKUs.toLocaleString()} sub="Active + serialised" />
            <KpiTile accent="warn"    label="Below Reorder"   value={STOCK_KPIS.belowReorder} sub="Auto-PO suggested for 12" delta="↑ 4 this week" deltaDir="down" />
            <KpiTile accent="danger"  label="Out of Stock"    value="6" sub="Critical line items" />
            <KpiTile accent="accent"  label="Expiring ≤ 30d"  value={STOCK_KPIS.expiringSoon} sub="₱14.8k at-risk value" />
          </div>

          {/* Two-col: WH split + Movement chart */}
          <div className="grid grid-cols-2 gap-4">
            <WarehouseSplitCard />
            <MovementChart />
          </div>

          {/* Stock table */}
          <Card>
            <CardHeader>
              <CardTitle>Stock Levels — {filtered.length} of {STOCK_ROWS.length} SKUs</CardTitle>
              <div className="flex items-center gap-1.5">
                <Badge variant="outline">Last sync: 2 min ago</Badge>
              </div>
            </CardHeader>
            <table className="w-full text-[12px]">
              <thead>
                <tr className="bg-cream text-left text-[10px] font-bold uppercase tracking-wider text-ink-mute">
                  <th className="px-4 py-2">Item Code</th>
                  <th>Description</th>
                  <th>Warehouse</th>
                  <th className="text-right">On Hand</th>
                  <th className="text-right">Reorder</th>
                  <th className="text-right">Value</th>
                  <th>Status</th>
                  <th>Last Movement</th>
                </tr>
              </thead>
              <tbody>
                {filtered.map(r => <StockRowR key={r.itemCode} r={r} />)}
              </tbody>
            </table>
          </Card>

        </div>
      </div>
    </>
  )
}

function StockRowR({ r }: { r: any }) {
  const statusMeta: any = {
    ok:       { variant: "success", label: "Healthy" },
    low:      { variant: "warn",    label: "Below reorder" },
    out:      { variant: "danger",  label: "Out of stock" },
    expiring: { variant: "accent",  label: "Expiring < 30d" },
  }
  const sm = statusMeta[r.status]
  return (
    <tr className="border-t border-divider-soft hover:bg-cream/50">
      <td className="px-4 py-2 font-mono font-bold text-brand-mid text-[11px]">{r.itemCode}</td>
      <td className="text-ink">{r.description}</td>
      <td className="text-ink-soft text-[11px]">{r.warehouse}</td>
      <td className={cn(
        "text-right font-mono font-semibold",
        r.status === "out" && "text-danger",
        r.status === "low" && "text-warn"
      )}>{r.onHand} <span className="text-ink-faint font-normal">{r.uom}</span></td>
      <td className="text-right text-ink-mute font-mono">{r.reorder}</td>
      <td className="text-right font-mono text-ink-soft">{formatCurrency(r.value)}</td>
      <td><Badge variant={sm.variant} dot>{sm.label}</Badge></td>
      <td className="text-[11px] text-ink-mute">{r.lastMovement}</td>
    </tr>
  )
}

function WarehouseSplitCard() {
  const rows = [
    { wh: "Manila Main WH",   value: 728000, pct: 100, count: 412 },
    { wh: "Calamba Site WH",  value: 612000, pct: 84,  count: 308 },
    { wh: "Cebu Branch WH",   value: 312000, pct: 43,  count: 224 },
    { wh: "Davao Site WH",    value: 190000, pct: 26,  count: 196 },
  ]
  return (
    <Card>
      <CardHeader>
        <CardTitle>By Warehouse</CardTitle>
        <Badge variant="brand">4 active</Badge>
      </CardHeader>
      <div className="p-4 space-y-3">
        {rows.map(r => (
          <div key={r.wh} className="grid grid-cols-[160px_1fr_auto] gap-3 items-center text-[12px]">
            <span className="text-ink truncate">{r.wh}</span>
            <div className="h-2 rounded-full bg-cream-deep overflow-hidden">
              <div className="h-full rounded-full bg-gradient-to-r from-brand to-brand-light" style={{ width: `${r.pct}%` }} />
            </div>
            <div className="flex items-baseline gap-2 min-w-[140px] justify-end">
              <span className="font-mono font-semibold text-ink">{formatCurrency(r.value)}</span>
              <span className="text-[10px] text-ink-mute">{r.count} SKUs</span>
            </div>
          </div>
        ))}
      </div>
    </Card>
  )
}

function MovementChart() {
  const points = [42, 56, 38, 64, 88, 72, 96, 82, 104, 78, 92, 86, 110, 124]
  const max = Math.max(...points)
  return (
    <Card>
      <CardHeader>
        <CardTitle>Daily Movement — Last 14 Days</CardTitle>
        <Badge variant="info">in + out</Badge>
      </CardHeader>
      <div className="p-4">
        <div className="flex items-end gap-1.5 h-32">
          {points.map((p, i) => {
            const h = (p / max) * 100
            return (
              <div key={i} className="flex-1 h-full flex flex-col justify-end">
                <div className={cn("w-full rounded-t-sm", i === points.length - 1 ? "bg-accent" : "bg-brand-light")} style={{ height: `${h}%` }} />
              </div>
            )
          })}
        </div>
        <div className="flex justify-between text-[9px] text-ink-mute mt-1">
          <span>Apr 4</span><span>Apr 8</span><span>Apr 12</span><span>Apr 17</span>
        </div>
      </div>
    </Card>
  )
}

// SANDBOX
;(globalThis as any).StockDashboard = StockDashboard

})();/*__IIFE_WRAP_END__*/

/* ═════ apps/web/components/inventory/cycle-count.tsx ═════ */
;/*__IIFE_WRAP_START__*/(function(){
/**
 * ============================================================================
 * apps/web/components/inventory/cycle-count.tsx
 * ----------------------------------------------------------------------------
 * Screen 15 — Cycle Count. Two views, swappable from a Desktop / Mobile tab
 * toggle in the topbar:
 *
 *   Desktop  — Supervisor console: live session header, KPI strip, counter
 *              roster, variance watch, action log. Designed for a station
 *              warehouse desk with barcode scanner + keyboard.
 *   Mobile   — Real-feeling iPhone bezel rendering the warehouse worker app
 *              that streams counts into the dashboard.
 *
 * Both views share the same in-memory `items` state so the supervisor sees
 * Joel's counts arrive in real time even when toggling views.
 * ============================================================================
 */

function CycleCount() {
  const [items, setItems] = React.useState(() => COUNT_ITEMS.map(c => ({ ...c })))
  const [view, setView] = React.useState<"desktop" | "mobile">("desktop")
  const counted   = items.filter(i => i.status !== "pending").length
  const variances = items.filter(i => i.status === "variance").length
  const pending   = items.filter(i => i.status === "pending").length
  const pct       = (counted / items.length) * 100

  function setCount(code: string, val: number) {
    setItems(list => list.map(i => {
      if (i.itemCode !== code) return i
      const status = val === i.expected ? "ok" as const : "variance" as const
      return { ...i, counted: val, status, note: status === "variance" ? `Variance ${val - i.expected}` : undefined }
    }))
  }

  return (
    <>
      <TopBar
        breadcrumb={[{ label: "Warehouse" }, { label: "Cycle Count" }]}
        leading={
          <ViewToggle value={view} onChange={(v) => setView(v as any)} options={[
            { value: "desktop", label: "Desktop", icon: "monitor" },
            { value: "mobile",  label: "Mobile",  icon: "smartphone" },
          ]} />
        }
        actions={
          <>
            <Button variant="ghost" leadingIcon="download">Export Variance Log</Button>
            <Button variant="primary" leadingIcon="check">Approve Session</Button>
          </>
        }
      />

      {view === "desktop"
        ? <DesktopConsole items={items} counted={counted} variances={variances} pending={pending} pct={pct} setCount={setCount} />
        : <MobilePreview items={items} counted={counted} pct={pct} setCount={setCount} />}
    </>
  )
}

/* ─── Desktop supervisor console ────────────────────────────────────────── */
function DesktopConsole({ items, counted, variances, pending, pct, setCount }: any) {
  const [selected, setSelected] = React.useState<any | null>(null)
  const recountCandidates = items.filter((i: any) => i.status === "variance")

  return (
    <div className="flex-1 overflow-y-auto bg-app">
      <div className="max-w-[1440px] mx-auto p-6 space-y-4">

        {/* Live session card — hero */}
        <Card>
          <div className="p-5 bg-gradient-to-br from-brand to-brand-light text-white relative overflow-hidden">
            <div className="absolute top-3 right-4 inline-flex items-center gap-1.5 text-[10px] font-bold uppercase tracking-wider text-accent">
              <span className="size-1.5 rounded-full bg-accent animate-pulse" /> Live
            </div>
            <div className="flex items-center gap-3 mb-3">
              <div className="size-9 rounded-md bg-white/12 flex items-center justify-center">
                <Icon name="check-square" size={16} className="text-accent" />
              </div>
              <div>
                <div className="text-[10px] font-bold uppercase tracking-wider text-accent">Session {CYCLE_COUNT_SESSION.id}</div>
                <div className="font-serif text-2xl leading-tight">{CYCLE_COUNT_SESSION.zone}</div>
              </div>
              <div className="ml-auto text-right">
                <div className="text-[10px] font-bold uppercase tracking-wider text-accent">Counter</div>
                <div className="text-[13px] font-semibold mt-0.5">{CYCLE_COUNT_SESSION.counter}</div>
                <div className="text-[10.5px] text-white/65">started {CYCLE_COUNT_SESSION.startedAt} · Apr 18</div>
              </div>
            </div>
            <div className="grid grid-cols-[1fr_auto] gap-6 items-end mt-4">
              <div>
                <div className="flex items-baseline justify-between mb-1">
                  <span className="text-[10.5px] text-white/65">{CYCLE_COUNT_SESSION.warehouse}</span>
                  <span className="font-mono text-[11px] text-white/85"><strong>{counted}</strong> / {items.length} items · {Math.round(pct)}%</span>
                </div>
                <div className="h-2 rounded-full bg-white/15 overflow-hidden">
                  <div className="h-full bg-accent rounded-full transition-all" style={{ width: `${pct}%` }} />
                </div>
              </div>
              <Badge variant="warn" dot>Active</Badge>
            </div>
          </div>
        </Card>

        {/* KPI strip */}
        <div className="grid grid-cols-4 gap-3">
          <KpiTile label="Items counted"  value={`${counted} / ${items.length}`}                 sub={`${pending} remaining`} accent="brand" />
          <KpiTile label="Variances"      value={variances}                                       sub={variances === 0 ? "All matched" : "Needs review"} accent={variances > 0 ? "warn" : "success"} />
          <KpiTile label="Variance value" value={`-${formatCurrency(VARIANCE_VALUE, "PHP")}`}      sub="net inventory delta" accent={variances > 0 ? "danger" : "success"} />
          <KpiTile label="Avg time / item" value="34s"                                              sub="Joel D. cadence"  accent="accent" />
        </div>

        <div className="grid grid-cols-[1fr_320px] gap-4">

          {/* Variance watch table */}
          <Card>
            <CardHeader>
              <CardTitle>Counted items · variance watch</CardTitle>
              <div className="flex items-center gap-2">
                <Badge variant={variances > 0 ? "warn" : "success"}>{variances} variance{variances === 1 ? "" : "s"}</Badge>
                <Button variant="ghost" size="sm" leadingIcon="refresh">Recount selected</Button>
              </div>
            </CardHeader>
            <table className="w-full text-[12px]">
              <thead>
                <tr className="bg-cream text-left text-[10px] font-bold uppercase tracking-wider text-ink-mute">
                  <th className="px-4 py-2 w-[130px]">Item</th>
                  <th>Description</th>
                  <th className="text-right">Expected</th>
                  <th className="text-right">Counted</th>
                  <th className="text-right">Variance</th>
                  <th className="w-[110px]">Status</th>
                </tr>
              </thead>
              <tbody>
                {items.map((c: any) => {
                  const variance = c.counted == null ? null : c.counted - c.expected
                  return (
                    <tr key={c.itemCode}
                      onClick={() => setSelected(c)}
                      className={cn(
                        "border-t border-divider-soft cursor-pointer hover:bg-cream/40 transition-colors",
                        c.status === "variance" && "bg-warn-soft/40 hover:bg-warn-soft/60",
                      )}>
                      <td className="px-4 py-2 font-mono font-bold text-brand-mid text-[11px]">{c.itemCode}</td>
                      <td className="text-ink">
                        <div className="font-semibold">{c.description}</div>
                        {c.note && <div className="text-[10.5px] text-warn mt-0.5">{c.note}</div>}
                      </td>
                      <td className="text-right font-mono text-ink-soft">{c.expected} <span className="text-ink-faint text-[10px]">{c.uom}</span></td>
                      <td className="text-right font-mono font-semibold text-ink">{c.counted ?? "—"}</td>
                      <td className={cn(
                        "text-right font-mono font-semibold",
                        variance == null ? "text-ink-faint" :
                        variance === 0   ? "text-success"   :
                        "text-danger"
                      )}>{variance == null ? "—" : variance > 0 ? `+${variance}` : variance}</td>
                      <td>
                        {c.status === "ok"       && <Badge variant="success" dot>OK</Badge>}
                        {c.status === "variance" && <Badge variant="warn" dot>Variance</Badge>}
                        {c.status === "pending"  && <Badge variant="neutral" dot>Pending</Badge>}
                      </td>
                    </tr>
                  )
                })}
              </tbody>
            </table>
          </Card>

          {/* Right rail */}
          <div className="space-y-4">
            <AICallout
              title="2 variances ready to clear"
              body="The 4 short bags of Portland cement match a damaged-stock photo Joel uploaded at 08:42 — staging for write-off is consistent with WO-2026-0134 dispatch. Steel Rebar 20mm short by 4pc traces to load-out PR-HVPH-2208 yesterday afternoon."
              matches={[
                { code: "01030102-010", name: "Portland cement · auto-stage write-off", pct: 96 },
                { code: "02010102-018", name: "Steel Rebar 20mm · link to PR-2208",      pct: 92 },
              ]}
              dismissLabel="Review each manually"
              proceedLabel="Stage adjustments"
            />

            <Card>
              <CardHeader>
                <CardTitle>Activity log</CardTitle>
                <span className="text-[10.5px] text-ink-mute font-mono">last 8</span>
              </CardHeader>
              <div className="divide-y divide-divider-soft text-[11.5px]">
                {ACTIVITY_LOG.map((a, i) => (
                  <div key={i} className="px-3 py-2 flex items-baseline gap-2">
                    <span className="font-mono text-[10px] text-ink-faint w-12 shrink-0">{a.t}</span>
                    <span className="text-ink-soft leading-snug">
                      <strong className="text-ink">{a.who}</strong> {a.what}
                      {a.code && <span className="font-mono text-brand-mid"> · {a.code}</span>}
                    </span>
                  </div>
                ))}
              </div>
            </Card>

            <Card>
              <CardHeader>
                <CardTitle>Counters · this session</CardTitle>
                <Badge variant="brand">1 active</Badge>
              </CardHeader>
              <div className="divide-y divide-divider-soft">
                <CounterRow initials="JD" tone="amber" name="Joel D." status="active" stat={`${counted} counted · ${pending} left`} hours="2h 14m" />
                <CounterRow initials="MA" tone="blue"  name="Maria A." status="standby" stat="Aisle C · pending start" hours="—" />
                <CounterRow initials="OP" tone="amber" name="Olivia P." status="signed-off" stat="Approved CC-0417 yesterday" hours="—" />
              </div>
            </Card>
          </div>
        </div>

      </div>

      {selected && (
        <Sheet open={true} onOpenChange={() => setSelected(null)} side="right">
          <SheetHeader>
            <div>
              <div className="font-mono text-[10px] text-ink-mute">{selected.itemCode}</div>
              <h2 className="font-serif text-xl text-ink mt-1 leading-tight">{selected.description}</h2>
              <div className="text-[11px] text-ink-soft mt-1.5">Counted by Joel D. at 09:48 · {CYCLE_COUNT_SESSION.zone}</div>
            </div>
            <SheetClose onClick={() => setSelected(null)} />
          </SheetHeader>
          <SheetBody>
            <div className="grid grid-cols-3 gap-3">
              <Stat2 label="Expected" value={`${selected.expected} ${selected.uom}`} />
              <Stat2 label="Counted"  value={`${selected.counted ?? "—"} ${selected.uom}`} tone="brand" />
              <Stat2 label="Variance" value={selected.counted == null ? "—" : (selected.counted - selected.expected > 0 ? `+${selected.counted - selected.expected}` : String(selected.counted - selected.expected))} />
            </div>
            {selected.note && (
              <div className="mt-4 bg-warn-soft/40 border border-warn/30 rounded-md p-3 text-[12px] text-ink-soft">
                <div className="text-[10px] uppercase tracking-wider font-bold text-warn mb-1">Counter note</div>
                {selected.note}
              </div>
            )}
            <div className="mt-4">
              <div className="text-[10px] uppercase tracking-wider font-bold text-ink-mute mb-2">Resolve</div>
              <div className="space-y-2">
                <button className="w-full bg-surface border border-divider rounded-md px-3 py-2 text-left text-[12px] hover:border-divider-strong">
                  <div className="font-semibold text-ink">Accept variance · adjust GL</div>
                  <div className="text-[10.5px] text-ink-mute mt-0.5">Posts to <span className="font-mono">6210 — Inventory Adjustments · {selected.uom}</span></div>
                </button>
                <button className="w-full bg-surface border border-divider rounded-md px-3 py-2 text-left text-[12px] hover:border-divider-strong">
                  <div className="font-semibold text-ink">Recount · escalate to a 2nd counter</div>
                  <div className="text-[10.5px] text-ink-mute mt-0.5">Re-queue at top of Maria A.'s list</div>
                </button>
                <button className="w-full bg-surface border border-divider rounded-md px-3 py-2 text-left text-[12px] hover:border-divider-strong">
                  <div className="font-semibold text-ink">Open as receiving discrepancy</div>
                  <div className="text-[10.5px] text-ink-mute mt-0.5">Create case linked to last IR for this item</div>
                </button>
              </div>
            </div>
          </SheetBody>
          <SheetFooter>
            <Button variant="ghost" onClick={() => setSelected(null)}>Close</Button>
            <Button variant="primary" leadingIcon="check" className="ml-auto" onClick={() => setSelected(null)}>Accept &amp; post</Button>
          </SheetFooter>
        </Sheet>
      )}
    </div>
  )
}

function CounterRow({ initials, tone, name, status, stat, hours }: any) {
  const tones: Record<string, string> = { active: "success", standby: "info", "signed-off": "neutral" }
  const labels: Record<string, string> = { active: "Active", standby: "Standby", "signed-off": "Signed off" }
  return (
    <div className="px-3 py-2.5 flex items-center gap-2.5">
      <Avatar initials={initials} tone={tone} size="sm" />
      <div className="flex-1 min-w-0">
        <div className="text-[12px] font-semibold text-ink">{name}</div>
        <div className="text-[10.5px] text-ink-mute">{stat}</div>
      </div>
      <div className="text-right">
        <Badge variant={tones[status] as any} dot>{labels[status]}</Badge>
        <div className="text-[10px] text-ink-faint font-mono mt-1">{hours}</div>
      </div>
    </div>
  )
}

/* ─── Mobile preview wrapper ────────────────────────────────────────────── */
function MobilePreview({ items, counted, pct, setCount }: any) {
  return (
    <div className="flex-1 overflow-y-auto bg-app">
      <div className="max-w-[1320px] mx-auto p-6 grid grid-cols-[420px_1fr] gap-6">
        <div className="flex flex-col items-center gap-3">
          <div className="text-[10px] font-bold uppercase tracking-wider text-ink-mute">Warehouse mobile · iPhone 15</div>
          <PhoneBezel>
            <MobileApp items={items} pct={pct} counted={counted} setCount={setCount} />
          </PhoneBezel>
          <div className="text-[10.5px] text-ink-mute text-center max-w-[300px] leading-relaxed">
            Joel D. is counting in <strong className="text-ink">{CYCLE_COUNT_SESSION.zone}</strong> right now. Updates stream to the Desktop console in real time.
          </div>
        </div>

        {/* Supervisor pane (compact) */}
        <div className="space-y-4">
          <Card>
            <CardHeader>
              <CardTitle>Live session · {CYCLE_COUNT_SESSION.id}</CardTitle>
              <Badge variant="warn" dot>Active · started {CYCLE_COUNT_SESSION.startedAt}</Badge>
            </CardHeader>
            <div className="p-4 grid grid-cols-4 gap-3">
              <Stat2 label="Warehouse" value={CYCLE_COUNT_SESSION.warehouse} />
              <Stat2 label="Zone / Rack" value={CYCLE_COUNT_SESSION.zone} />
              <Stat2 label="Counter" value={CYCLE_COUNT_SESSION.counter} />
              <Stat2 label="Progress" value={`${counted} / ${items.length}`} tone="brand" />
            </div>
            <div className="px-4 pb-4">
              <div className="h-2 rounded-full bg-cream-deep overflow-hidden">
                <div className="h-full rounded-full bg-brand transition-all" style={{ width: `${pct}%` }} />
              </div>
            </div>
          </Card>

          <AICallout
            title="Live tip · Joel is 8% faster than yesterday"
            body="If Maria starts Aisle C in the next 20min the whole zone closes before lunch. Want to send her the session link?"
            dismissLabel="Not now"
            proceedLabel="Notify Maria"
          />
        </div>
      </div>
    </div>
  )
}

function Stat2({ label, value, tone }: any) {
  return (
    <div>
      <div className="text-[10px] font-bold uppercase tracking-wider text-ink-mute">{label}</div>
      <div className={cn("text-[13px] font-semibold mt-0.5", tone === "brand" ? "text-brand" : "text-ink")}>{value}</div>
    </div>
  )
}

/* ─── Phone bezel ──────────────────────────────────────────────────────── */
function PhoneBezel({ children }: { children: React.ReactNode }) {
  return (
    <div className="relative w-[320px] h-[660px] bg-ink rounded-[44px] p-2.5 shadow-lg">
      <div className="absolute top-3 left-1/2 -translate-x-1/2 z-20 w-24 h-5 bg-ink rounded-full" />
      <div className="relative w-full h-full bg-surface rounded-[34px] overflow-hidden flex flex-col">
        {/* Status bar */}
        <div className="h-9 shrink-0 flex items-center justify-between px-6 pt-2 text-[11px] font-bold text-ink">
          <span>9:41</span>
          <span className="flex items-center gap-1">
            <Icon name="globe" size={11} />
            <span className="size-3 inline-block rounded-sm border-[1.5px] border-ink relative">
              <span className="absolute inset-0.5 bg-ink rounded-sm" />
            </span>
          </span>
        </div>
        <div className="flex-1 overflow-hidden min-h-0">{children}</div>
      </div>
    </div>
  )
}

/* ─── Mobile cycle-count app ───────────────────────────────────────────── */
function MobileApp({ items, pct, counted, setCount }: any) {
  const [active, setActive] = React.useState(items.find((i: any) => i.status === "pending")?.itemCode ?? items[0].itemCode)
  const activeItem = items.find((i: any) => i.itemCode === active)
  const [input, setInput] = React.useState("")

  React.useEffect(() => {
    setInput(activeItem?.counted != null ? String(activeItem.counted) : "")
  }, [active, activeItem])

  function submit() {
    const n = parseInt(input, 10)
    if (!Number.isNaN(n)) setCount(active, n)
    const nextPending = items.find((i: any) => i.status === "pending" && i.itemCode !== active)
    if (nextPending) setActive(nextPending.itemCode)
  }

  return (
    <div className="flex flex-col h-full bg-app">
      {/* Header */}
      <header className="shrink-0 bg-brand text-white px-4 py-3">
        <div className="flex items-center gap-2 mb-2">
          <button className="size-7 rounded-md bg-white/10 flex items-center justify-center">
            <Icon name="chevron-left" size={14} />
          </button>
          <div className="flex-1 min-w-0">
            <div className="text-[10px] text-white/60">CC-HVPH-0418 · Joel D.</div>
            <div className="text-[13px] font-semibold truncate">{CYCLE_COUNT_SESSION.zone}</div>
          </div>
          <span className="text-[11px] font-bold bg-accent text-brand px-2 py-px rounded-full">{counted}/{items.length}</span>
        </div>
        <div className="h-1.5 rounded-full bg-white/15 overflow-hidden">
          <div className="h-full bg-accent rounded-full transition-all" style={{ width: `${pct}%` }} />
        </div>
      </header>

      {/* Active item card */}
      <div className="shrink-0 p-3 bg-accent-soft border-b border-accent/30">
        <div className="text-[9px] font-bold uppercase tracking-wider text-accent-deep mb-1">Counting now</div>
        <div className="text-[13px] font-semibold text-ink leading-snug">{activeItem.description}</div>
        <div className="text-[11px] text-ink-mute font-mono mt-1">{activeItem.itemCode}</div>
        <div className="mt-3 grid grid-cols-2 gap-3 items-end">
          <div>
            <div className="text-[9px] font-bold uppercase tracking-wider text-ink-mute mb-0.5">Expected</div>
            <div className="font-serif text-2xl text-ink">{activeItem.expected} <span className="text-[10px] text-ink-mute font-sans">{activeItem.uom}</span></div>
          </div>
          <div>
            <div className="text-[9px] font-bold uppercase tracking-wider text-ink-mute mb-0.5">Your count</div>
            <input value={input} onChange={e => setInput(e.target.value.replace(/[^0-9]/g, ""))}
              className="bg-surface border-2 border-brand rounded-md px-2 py-1.5 w-full text-[20px] font-serif font-bold text-brand text-center" inputMode="numeric" />
          </div>
        </div>
        <div className="grid grid-cols-2 gap-2 mt-3">
          <button onClick={submit} className="h-9 rounded-md bg-brand text-white text-[12px] font-bold flex items-center justify-center gap-1.5">
            <Icon name="check" size={12} strokeWidth={3} /> Confirm count
          </button>
          <button className="h-9 rounded-md bg-surface border border-divider text-[11px] font-semibold text-ink-soft flex items-center justify-center gap-1.5">
            <Icon name="alert-triangle" size={11} /> Flag issue
          </button>
        </div>
      </div>

      {/* List */}
      <div className="flex-1 overflow-y-auto">
        <div className="px-4 py-2 text-[9px] font-bold uppercase tracking-wider text-ink-mute">Up next</div>
        {items.map((c: any) => {
          const isActive = c.itemCode === active
          const variance = c.counted == null ? null : c.counted - c.expected
          return (
            <button key={c.itemCode}
              onClick={() => setActive(c.itemCode)}
              className={cn(
                "w-full text-left px-4 py-2 border-t border-divider-soft flex items-center gap-2 hover:bg-cream",
                isActive && "bg-brand-soft"
              )}>
              <span className={cn(
                "size-6 rounded-full flex items-center justify-center text-[9px] font-bold shrink-0",
                c.status === "ok"       && "bg-success text-white",
                c.status === "variance" && "bg-warn text-white",
                c.status === "pending"  && "bg-cream-deep text-ink-mute",
              )}>
                {c.status === "ok"       && <Icon name="check" size={11} strokeWidth={3} />}
                {c.status === "variance" && "!"}
                {c.status === "pending"  && "•"}
              </span>
              <div className="flex-1 min-w-0">
                <div className="text-[11px] font-semibold text-ink truncate">{c.description}</div>
                <div className="text-[9.5px] text-ink-mute font-mono">{c.itemCode}</div>
              </div>
              <div className="text-right text-[10px]">
                <div className="font-mono font-bold text-ink">{c.counted ?? "—"} <span className="text-ink-mute">/ {c.expected}</span></div>
                {variance != null && variance !== 0 && (
                  <div className={cn("font-semibold", variance > 0 ? "text-info" : "text-danger")}>
                    {variance > 0 ? "+" : ""}{variance}
                  </div>
                )}
              </div>
            </button>
          )
        })}
      </div>

      {/* Bottom tab bar */}
      <nav className="shrink-0 bg-surface border-t border-divider grid grid-cols-4 text-[9px] text-ink-mute py-2">
        <button className="flex flex-col items-center gap-1 text-brand"><Icon name="check-square" size={16} /><span className="font-bold">Count</span></button>
        <button className="flex flex-col items-center gap-1"><Icon name="package" size={16} /><span>Items</span></button>
        <button className="flex flex-col items-center gap-1"><Icon name="alert-triangle" size={16} /><span>Issues</span></button>
        <button className="flex flex-col items-center gap-1"><Icon name="user" size={16} /><span>Me</span></button>
      </nav>
    </div>
  )
}

/* ─── Local mock helpers (kept here to avoid widening mock/inventory.tsx) ─ */
const VARIANCE_VALUE = 4 * 132 + 4 * 290  /* 4pc rebar @132 + 4 bags cement @290 = 1,688 PHP */

const ACTIVITY_LOG = [
  { t: "09:48", who: "Joel D.", what: "submitted count for", code: "01030102-010" },
  { t: "09:42", who: "Joel D.", what: "flagged variance on",  code: "01030102-010" },
  { t: "09:31", who: "Joel D.", what: "submitted count for", code: "10020401-008" },
  { t: "09:18", who: "Joel D.", what: "submitted count for", code: "07030101-014" },
  { t: "09:04", who: "Joel D.", what: "submitted count for", code: "02010102-018" },
  { t: "08:54", who: "Joel D.", what: "flagged variance on",  code: "02010102-018" },
  { t: "08:41", who: "Joel D.", what: "submitted count for", code: "02010102-014" },
  { t: "08:14", who: "Olivia P.", what: "started session",   code: "CC-HVPH-0418" },
]

// SANDBOX
;(globalThis as any).CycleCount = CycleCount

})();/*__IIFE_WRAP_END__*/

/* ═════ apps/web/components/inventory/receive-items.tsx ═════ */
;/*__IIFE_WRAP_START__*/(function(){
/**
 * apps/web/components/inventory/receive-items.tsx
 * Warehouse — Receive Items (Item Receipt list / form). Was IR under
 * Procurement; moved to Warehouse but stays tagged to PO.
 */

function WarehouseReceive() {
  const receipts = [
    { id: "IR-HVPH-1019", po: "PO-HVPH-1140", vendor: "Pacific Steel Co.",       expectedQty: 500, receivedQty: 500, status: "complete",   date: "Today",        location: "Manila A-12" },
    { id: "IR-HVPH-1018", po: "PO-HVPH-1138", vendor: "Premier Power Inc.",      expectedQty: 4,    receivedQty: 4,   status: "complete",   date: "Today",        location: "Manila B-04" },
    { id: "IR-HVPH-1017", po: "PO-HVPH-1136", vendor: "ABC Computer Solutions",  expectedQty: 12,   receivedQty: 11,  status: "partial",    date: "Yesterday",    location: "Manila C-21" },
    { id: "IR-HVSG-0184", po: "PO-HVSG-1108", vendor: "Canon Singapore",         expectedQty: 6,    receivedQty: 0,   status: "expected",   date: "Tomorrow",     location: "Singapore A-08" },
    { id: "IR-HVAU-0098", po: "PO-HVAU-0488", vendor: "SafetyFirst AU",          expectedQty: 60,   receivedQty: 60,  status: "complete",   date: "Yesterday",    location: "Sydney B-12" },
    { id: "IR-HVIN-0238", po: "PO-HVIN-0894", vendor: "Devanand Packaging",      expectedQty: 1200, receivedQty: 800, status: "partial",    date: "Today",        location: "Mumbai D-03" },
    { id: "IR-HVHK-0046", po: "PO-HVHK-0222", vendor: "—",                       expectedQty: 12,   receivedQty: 0,   status: "expected",   date: "Tomorrow",     location: "HK A-02" },
  ]

  return (
    <>
      <TopBar breadcrumb={[{ label: "Warehouse" }, { label: "Receive Items" }]} />
      <ActionBar
        title="Receive Items"
        status={`${receipts.length} receipts · ${receipts.filter(r => r.status === "expected").length} expected today · ${receipts.filter(r => r.status === "partial").length} partial`}
        primary={<Button variant="primary" leadingIcon="plus" size="sm">New receipt</Button>}
        secondary={<Button variant="ghost" leadingIcon="scan" size="sm">Scan to receive</Button>}
        ai={<Button variant="subtle" leadingIcon="sparkle" size="sm">Variance check</Button>}
      />
      <div className="flex-1 overflow-y-auto bg-app">
        <div className="max-w-[1280px] mx-auto p-6">
          <Card>
            <div className="grid grid-cols-[150px_140px_2fr_120px_120px_140px_120px] px-4 py-2 bg-cream text-[10px] uppercase tracking-wider font-bold text-ink-mute">
              <span>Receipt #</span><span>PO Ref</span><span>Vendor</span><span className="text-right">Expected</span><span className="text-right">Received</span><span>Status</span><span>Date</span>
            </div>
            {receipts.map(r => (
              <div key={r.id} className="grid grid-cols-[150px_140px_2fr_120px_120px_140px_120px] px-4 py-2.5 items-center border-t border-divider-soft hover:bg-cream/40 text-[11.5px]">
                <span className="font-mono font-bold text-brand-mid">{r.id}</span>
                <span className="font-mono text-ink-mute">{r.po}</span>
                <div><div className="text-ink">{r.vendor}</div><div className="text-[10px] text-ink-mute">{r.location}</div></div>
                <span className="font-mono text-right">{r.expectedQty}</span>
                <span className={cn("font-mono text-right font-bold", r.receivedQty < r.expectedQty ? "text-warn" : "text-success")}>{r.receivedQty}</span>
                {r.status === "complete"  ? <Badge variant="success">✓ Complete</Badge>
                : r.status === "partial"  ? <Badge variant="warn">Partial</Badge>
                                          : <Badge variant="info" dot>Expected</Badge>}
                <span className="text-ink-soft">{r.date}</span>
              </div>
            ))}
          </Card>
        </div>
      </div>
    </>
  )
}

// SANDBOX
;(globalThis as any).WarehouseReceive = WarehouseReceive

})();/*__IIFE_WRAP_END__*/

/* ═════ apps/web/components/inventory/ship-items.tsx ═════ */
;/*__IIFE_WRAP_START__*/(function(){
/**
 * apps/web/components/inventory/ship-items.tsx
 * Warehouse — Ship Items (outbound). Tied to Sales Orders.
 */

function WarehouseShip() {
  const ships = [
    { id: "SH-HVPH-0312", so: "SO-HVPH-0312", customer: "Pacific Steel Co.",   items: 1, qty: 500, status: "ready",     planned: "Today 14:00", entity: "HVPH" },
    { id: "SH-HVPH-0311", so: "SO-HVPH-0310", customer: "Calamba Devt Corp.",  items: 3, qty: 124, status: "picking",   planned: "Today 16:00", entity: "HVPH" },
    { id: "SH-HVSG-0186", so: "SO-HVSG-0298", customer: "Tan Beng Holdings",   items: 2, qty: 48,  status: "shipped",   planned: "Today 09:00", entity: "HVSG" },
    { id: "SH-HVHK-0098", so: "SO-HVHK-0214", customer: "Yuen Long Logistics", items: 4, qty: 12,  status: "packing",   planned: "Today 12:00", entity: "HVHK" },
    { id: "SH-HVAU-0224", so: "SO-HVAU-0312", customer: "Crown Holdings",      items: 6, qty: 240, status: "ready",     planned: "Today 11:00", entity: "HVAU" },
    { id: "SH-HVIN-0152", so: "SO-HVIN-0288", customer: "Devanand Logistics",  items: 2, qty: 80,  status: "shipped",   planned: "Today 08:30", entity: "HVIN" },
    { id: "SH-HVAU-0223", so: "SO-HVAU-0310", customer: "Westfield Group",     items: 8, qty: 412, status: "back-order", planned: "Mon 09:00", entity: "HVAU" },
  ]
  return (
    <>
      <TopBar breadcrumb={[{ label: "Warehouse" }, { label: "Ship Items" }]} />
      <ActionBar
        title="Ship Items"
        status={`${ships.length} outbound · ${ships.filter(s => s.status === "shipped").length} shipped today · ${ships.filter(s => s.status === "back-order").length} back-order`}
        primary={<Button variant="primary" leadingIcon="plus" size="sm">New shipment</Button>}
        secondary={<Button variant="ghost" leadingIcon="scan" size="sm">Scan to ship</Button>}
        ai={<Button variant="subtle" leadingIcon="sparkle" size="sm">Optimize loads</Button>}
      />
      <div className="flex-1 overflow-y-auto bg-app">
        <div className="max-w-[1280px] mx-auto p-6">
          <Card>
            <div className="grid grid-cols-[140px_140px_2fr_120px_100px_140px_120px] px-4 py-2 bg-cream text-[10px] uppercase tracking-wider font-bold text-ink-mute">
              <span>Shipment #</span><span>SO Ref</span><span>Customer</span><span className="text-right">Items / Qty</span><span>Entity</span><span>Status</span><span>Planned</span>
            </div>
            {ships.map(s => (
              <div key={s.id} className="grid grid-cols-[140px_140px_2fr_120px_100px_140px_120px] px-4 py-2.5 items-center border-t border-divider-soft hover:bg-cream/40 text-[11.5px]">
                <span className="font-mono font-bold text-brand-mid">{s.id}</span>
                <span className="font-mono text-ink-mute">{s.so}</span>
                <span className="text-ink font-medium">{s.customer}</span>
                <span className="font-mono text-right">{s.items} SKU · {s.qty} units</span>
                <span className="font-mono text-ink-mute">{s.entity}</span>
                {s.status === "ready"      ? <Badge variant="success">Ready</Badge>
                : s.status === "shipped"    ? <Badge variant="info">Shipped</Badge>
                : s.status === "picking"    ? <Badge variant="warn" dot>Picking</Badge>
                : s.status === "packing"    ? <Badge variant="warn" dot>Packing</Badge>
                                            : <Badge variant="danger">Back-order</Badge>}
                <span className="text-ink-soft">{s.planned}</span>
              </div>
            ))}
          </Card>
        </div>
      </div>
    </>
  )
}

// SANDBOX
;(globalThis as any).WarehouseShip = WarehouseShip

})();/*__IIFE_WRAP_END__*/

/* ═════ apps/web/components/inventory/transfers.tsx ═════ */
;/*__IIFE_WRAP_START__*/(function(){
/**
 * apps/web/components/inventory/transfers.tsx
 * Warehouse — Inter-warehouse stock transfers.
 */

function WarehouseTransfers() {
  const rows = [
    { id: "ST-2026-0142", from: "Manila A", to: "Calamba A", items: 14, qty: 280, status: "in-transit", date: "Today",      ref: "PRJ-2026-088" },
    { id: "ST-2026-0141", from: "Manila A", to: "Quezon B",  items: 6,  qty: 64,  status: "received",   date: "Yesterday",  ref: "—" },
    { id: "ST-2026-0140", from: "SG HQ",    to: "Tuas",      items: 8,  qty: 120, status: "in-transit", date: "Today",      ref: "PRJ-2026-082" },
    { id: "ST-2026-0139", from: "Sydney B", to: "Parramatta", items: 4, qty: 88,  status: "draft",      date: "—",          ref: "—" },
    { id: "ST-2026-0138", from: "Mumbai D", to: "Pune A",    items: 22, qty: 412, status: "in-transit", date: "Today",      ref: "PRJ-2026-085" },
    { id: "ST-2026-0137", from: "HK A",     to: "Sha Tin",   items: 2,  qty: 24,  status: "received",   date: "2d ago",     ref: "—" },
  ]
  return (
    <>
      <TopBar breadcrumb={[{ label: "Warehouse" }, { label: "Transfers" }]} />
      <ActionBar
        title="Stock Transfers"
        status={`${rows.length} transfers · ${rows.filter(r => r.status === "in-transit").length} in transit`}
        primary={<Button variant="primary" leadingIcon="plus" size="sm">New transfer</Button>}
        secondary={<Button variant="ghost" leadingIcon="download" size="sm">Export</Button>}
      />
      <div className="flex-1 overflow-y-auto bg-app">
        <div className="max-w-[1180px] mx-auto p-6">
          <Card>
            <div className="grid grid-cols-[140px_2fr_140px_120px_120px_120px] px-4 py-2 bg-cream text-[10px] uppercase tracking-wider font-bold text-ink-mute">
              <span>Transfer #</span><span>From → To</span><span>Items / Qty</span><span>Status</span><span>Project ref</span><span>Date</span>
            </div>
            {rows.map(r => (
              <div key={r.id} className="grid grid-cols-[140px_2fr_140px_120px_120px_120px] px-4 py-2.5 items-center border-t border-divider-soft hover:bg-cream/40 text-[11.5px]">
                <span className="font-mono font-bold text-brand-mid">{r.id}</span>
                <span className="text-ink font-medium">{r.from} <span className="text-ink-mute mx-1">→</span> {r.to}</span>
                <span className="font-mono">{r.items} SKU · {r.qty} units</span>
                {r.status === "received"   ? <Badge variant="success">✓ Received</Badge>
                : r.status === "in-transit" ? <Badge variant="info" dot>In transit</Badge>
                                              : <Badge variant="neutral">Draft</Badge>}
                <span className="font-mono text-ink-mute">{r.ref}</span>
                <span className="text-ink-soft">{r.date}</span>
              </div>
            ))}
          </Card>
        </div>
      </div>
    </>
  )
}

// SANDBOX
;(globalThis as any).WarehouseTransfers = WarehouseTransfers

})();/*__IIFE_WRAP_END__*/

/* ═════ apps/web/components/inventory/rma.tsx ═════ */
;/*__IIFE_WRAP_START__*/(function(){
/**
 * apps/web/components/inventory/rma.tsx
 * Warehouse — RMA / Returns processing.
 */

function WarehouseRMA() {
  const rows = [
    { id: "RMA-2026-0048", customer: "Crown Holdings",      orderRef: "SO-HVAU-0288", item: "Site lighting fixtures (defective)", qty: 4,   reason: "Defective on arrival",       status: "received",   date: "Today",  refund: "A$ 1,840",   entity: "HVAU" },
    { id: "RMA-2026-0047", customer: "Pacific Steel Co.",   orderRef: "SO-HVPH-0306", item: "Rebar 12mm — wrong grade",            qty: 100, reason: "Wrong specification",        status: "approved",   date: "Today",  refund: "₱ 245,000",  entity: "HVPH" },
    { id: "RMA-2026-0046", customer: "Tan Beng Holdings",   orderRef: "SO-HVSG-0294", item: "Office chairs — color mismatch",       qty: 6,   reason: "Customer changed mind",     status: "received",   date: "Yesterday", refund: "S$ 880",    entity: "HVSG" },
    { id: "RMA-2026-0045", customer: "Stellar Tech Ltd.",   orderRef: "SO-HVIN-0282", item: "Server rack rails",                    qty: 8,   reason: "Excess delivery",            status: "in-review",  date: "Yesterday", refund: "₹ 48,400",   entity: "HVIN" },
    { id: "RMA-2026-0044", customer: "Westfield Group",     orderRef: "SO-HVAU-0276", item: "HVAC units (damaged)",                 qty: 2,   reason: "Shipping damage",            status: "in-review",  date: "2d ago",   refund: "A$ 12,400",  entity: "HVAU" },
    { id: "RMA-2026-0043", customer: "Devanand Logistics",  orderRef: "SO-HVIN-0276", item: "Packaging boxes",                       qty: 240, reason: "Quality below spec",         status: "completed",  date: "3d ago",   refund: "₹ 18,400",   entity: "HVIN" },
  ]
  return (
    <>
      <TopBar breadcrumb={[{ label: "Warehouse" }, { label: "RMA / Returns" }]} />
      <ActionBar
        title="RMA / Returns"
        status={`${rows.length} active · ${rows.filter(r => r.status === "in-review").length} in review · ${rows.filter(r => r.status === "approved").length} approved for refund`}
        primary={<Button variant="primary" leadingIcon="plus" size="sm">New RMA</Button>}
        secondary={<Button variant="ghost" leadingIcon="download" size="sm">Export</Button>}
      />
      <div className="flex-1 overflow-y-auto bg-app">
        <div className="max-w-[1280px] mx-auto p-6">
          <Card>
            <div className="grid grid-cols-[150px_1.4fr_2fr_120px_140px_120px_120px] px-4 py-2 bg-cream text-[10px] uppercase tracking-wider font-bold text-ink-mute">
              <span>RMA #</span><span>Customer / Order</span><span>Item</span><span className="text-right">Qty</span><span>Reason</span><span>Status</span><span className="text-right">Refund</span>
            </div>
            {rows.map(r => (
              <div key={r.id} className="grid grid-cols-[150px_1.4fr_2fr_120px_140px_120px_120px] px-4 py-2.5 items-center border-t border-divider-soft hover:bg-cream/40 text-[11.5px]">
                <span className="font-mono font-bold text-brand-mid">{r.id}</span>
                <div><div className="text-ink">{r.customer}</div><div className="text-[10px] font-mono text-ink-mute">{r.orderRef}</div></div>
                <span className="text-ink-soft">{r.item}</span>
                <span className="font-mono text-right">{r.qty}</span>
                <span className="text-[10.5px] text-ink-mute">{r.reason}</span>
                {r.status === "received"  ? <Badge variant="info" dot>Received</Badge>
                : r.status === "approved"  ? <Badge variant="success">Approved</Badge>
                : r.status === "in-review" ? <Badge variant="warn" dot>In review</Badge>
                                            : <Badge variant="neutral">Completed</Badge>}
                <span className="font-mono text-right font-bold text-ink">{r.refund}</span>
              </div>
            ))}
          </Card>
        </div>
      </div>
    </>
  )
}

// SANDBOX
;(globalThis as any).WarehouseRMA = WarehouseRMA

})();/*__IIFE_WRAP_END__*/

/* ═════ apps/web/components/inventory/adjustments.tsx ═════ */
;/*__IIFE_WRAP_START__*/(function(){
/**
 * apps/web/components/inventory/adjustments.tsx
 * Warehouse — Inventory adjustments (write-downs, shrinkage, stock→asset, etc).
 */

function WarehouseAdjustments() {
  const rows = [
    { id: "ADJ-2026-0124", type: "Stock → Asset",      sku: "SKU-44388",  desc: "12x ThinkPad T14 laptops capitalized as Fixed Assets", qty: 12,  valueUsd:  12_960,  ref: "OR-HVPH-0438",  status: "posted",  date: "Today" },
    { id: "ADJ-2026-0123", type: "Shrinkage",          sku: "SKU-44210",  desc: "Cycle count variance — short by 4 units",                qty: -4,  valueUsd:   -1_240, ref: "CC-8024",       status: "posted",  date: "Today" },
    { id: "ADJ-2026-0122", type: "Write-down",         sku: "SKU-44182",  desc: "Obsolete inventory — discontinued bulb fixtures",       qty: -32, valueUsd:   -8_400, ref: "—",             status: "approval", date: "Today" },
    { id: "ADJ-2026-0121", type: "Reclassification",   sku: "SKU-44322",  desc: "Re-categorized from MRO to Direct Materials",            qty: 0,   valueUsd:        0, ref: "—",             status: "posted",  date: "Yesterday" },
    { id: "ADJ-2026-0120", type: "Correction",         sku: "SKU-44488",  desc: "Receipt qty correction — IR-HVAU-0098",                  qty: 4,   valueUsd:    1_840, ref: "IR-HVAU-0098",  status: "posted",  date: "Yesterday" },
    { id: "ADJ-2026-0119", type: "Shrinkage",          sku: "SKU-44612",  desc: "Damaged in storage",                                     qty: -8,  valueUsd:   -2_400, ref: "—",             status: "posted",  date: "2d ago" },
    { id: "ADJ-2026-0118", type: "Stock → Asset",      sku: "SKU-44918",  desc: "Office furniture capitalized — Sydney refresh",          qty: 24,  valueUsd:   18_400, ref: "OR-HVAU-0084",  status: "posted",  date: "3d ago" },
  ]
  return (
    <>
      <TopBar breadcrumb={[{ label: "Warehouse" }, { label: "Inventory Adjustments" }]} />
      <ActionBar
        title="Inventory Adjustments"
        status={`${rows.length} adjustments this period · Net $${(rows.reduce((s, r) => s + r.valueUsd, 0)).toLocaleString()} impact`}
        primary={<Button variant="primary" leadingIcon="plus" size="sm">New adjustment</Button>}
        secondary={<Button variant="ghost" leadingIcon="download" size="sm">Export</Button>}
        ai={<Button variant="subtle" leadingIcon="sparkle" size="sm">Anomaly scan</Button>}
      />
      <div className="flex-1 overflow-y-auto bg-app">
        <div className="max-w-[1280px] mx-auto p-6">
          <div className="bg-info-soft border border-info/20 rounded-lg p-3 flex items-start gap-2.5 mb-4">
            <Icon name="info" size={14} className="text-info mt-0.5" />
            <div className="text-[11.5px] text-info">
              <span className="font-semibold">Adjustment types.</span> Write-down · Shrinkage · Stock → Asset conversion (capitalization) · Reclassification · Correction. Each posts a journal entry.
            </div>
          </div>
          <Card>
            <div className="grid grid-cols-[160px_140px_2fr_80px_120px_120px_120px_100px] px-4 py-2 bg-cream text-[10px] uppercase tracking-wider font-bold text-ink-mute">
              <span>Adj #</span><span>Type</span><span>Description</span><span className="text-right">Qty</span><span className="text-right">Value</span><span>Ref</span><span>Status</span><span>Date</span>
            </div>
            {rows.map(r => (
              <div key={r.id} className="grid grid-cols-[160px_140px_2fr_80px_120px_120px_120px_100px] px-4 py-2.5 items-center border-t border-divider-soft hover:bg-cream/40 text-[11.5px]">
                <span className="font-mono font-bold text-brand-mid">{r.id}</span>
                <span className="text-ink-soft">{r.type}</span>
                <div>
                  <div className="text-ink">{r.desc}</div>
                  <div className="text-[10px] font-mono text-ink-mute">{r.sku}</div>
                </div>
                <span className={cn("font-mono text-right font-bold", r.qty < 0 ? "text-danger" : r.qty > 0 ? "text-success" : "text-ink-mute")}>{r.qty > 0 ? "+" : ""}{r.qty}</span>
                <span className={cn("font-mono text-right font-bold", r.valueUsd < 0 ? "text-danger" : r.valueUsd > 0 ? "text-success" : "text-ink-mute")}>{r.valueUsd > 0 ? "+" : ""}${Math.abs(r.valueUsd).toLocaleString()}</span>
                <span className="font-mono text-ink-mute">{r.ref}</span>
                {r.status === "approval" ? <Badge variant="warn" dot>Approval</Badge> : <Badge variant="success">✓ Posted</Badge>}
                <span className="text-ink-soft">{r.date}</span>
              </div>
            ))}
          </Card>
        </div>
      </div>
    </>
  )
}

// SANDBOX
;(globalThis as any).WarehouseAdjustments = WarehouseAdjustments

})();/*__IIFE_WRAP_END__*/

/* ═════ apps/web/components/hr/employee-directory.tsx ═════ */
;/*__IIFE_WRAP_START__*/(function(){
/**
 * ============================================================================
 * apps/web/components/hr/employee-directory.tsx
 * ----------------------------------------------------------------------------
 * Screen 16 — Employee Directory. Filter chips by department + status,
 * grid/list toggle, employee cards.
 * ============================================================================
 */

function EmployeeDirectory() {
  const { push } = useRouter()
  const [dept, setDept] = React.useState<"all" | typeof EMPLOYEES[number]["dept"]>("all")
  const [view, setView] = React.useState<"grid" | "list">("grid")
  const [query, setQuery] = React.useState("")

  const filtered = React.useMemo(() => (EMPLOYEES as any[]).filter(e => {
    if (dept !== "all" && e.dept !== dept) return false
    if (query && !(e.name + " " + e.title + " " + e.email).toLowerCase().includes(query.toLowerCase())) return false
    return true
  }), [dept, query])

  const depts = Array.from(new Set(EMPLOYEES.map(e => e.dept)))

  return (
    <>
      <TopBar
        breadcrumb={[{ label: "HRIS" }, { label: "Employee Directory" }]}
        leading={<ViewToggle value={view} onChange={(v) => setView(v as any)} options={[
          { value: "grid", label: "Cards", icon: "grid" },
          { value: "list", label: "List", icon: "list" },
        ]} />}
        actions={
          <>
            <Button variant="ghost" leadingIcon="download">Export</Button>
            <Button variant="primary" leadingIcon="plus" onClick={() => push("/hr/hire-to-retire")}>New Hire</Button>
          </>
        }
      />

      <Subheader right={<SearchBox value={query} onChange={setQuery} placeholder="Search name, title, email…" className="w-64" />}>
        <FilterChip active={dept === "all"} onClick={() => setDept("all")}>All Departments</FilterChip>
        {depts.map(d => (
          <FilterChip key={d} active={dept === d} onClick={() => setDept(d as any)} count={EMPLOYEES.filter(e => e.dept === d).length}>{d}</FilterChip>
        ))}
      </Subheader>

      <div className="flex-1 overflow-y-auto bg-app">
        <div className="p-5 space-y-5">

          {/* KPIs */}
          <div className="grid grid-cols-5 gap-3">
            <KpiTile accent="brand"   label="Active Headcount" value={HR_KPIS.headcount} sub="+3 vs Jan" delta="↑ 21.4%" deltaDir="up" />
            <KpiTile accent="accent"  label="Open Reqs"        value={HR_KPIS.openReqs} sub="3 in interview" />
            <KpiTile accent="warn"    label="On Probation"     value={HR_KPIS.onProbation} sub="1 review due" />
            <KpiTile accent="info"    label="On Leave"         value={HR_KPIS.onLeave} sub="1 medical · April" />
            <KpiTile accent="success" label="Attrition (12mo)" value={`${HR_KPIS.attritionPct}%`} sub="vs 9.1% industry" delta="↓ 1.8pp" deltaDir="up" />
          </div>

          {/* Employees */}
          <Card>
            <CardHeader>
              <CardTitle>Employees — {filtered.length} of {EMPLOYEES.length}</CardTitle>
              <button onClick={() => push("/hr/org-chart")} className="text-[11px] text-brand font-semibold hover:underline">View org chart →</button>
            </CardHeader>
            {view === "grid" ? <DirectoryGrid people={filtered} /> : <DirectoryList people={filtered} />}
          </Card>
        </div>
      </div>
    </>
  )
}

function DirectoryGrid({ people }: { people: any[] }) {
  return (
    <div className="grid grid-cols-3 gap-3 p-4">
      {people.map(p => (
        <article key={p.id} className="bg-app border border-divider rounded-md p-3.5 flex items-start gap-3 hover:border-brand-mid hover:bg-surface transition-colors">
          <Avatar initials={p.initials} tone={p.tone} size="lg" />
          <div className="flex-1 min-w-0">
            <div className="flex items-center gap-1.5 flex-wrap">
              <h3 className="text-[13px] font-semibold text-ink font-sans">{p.name}</h3>
              {p.status === "probation" && <Badge variant="warn">Probation</Badge>}
              {p.status === "on-leave"  && <Badge variant="info">On Leave</Badge>}
            </div>
            <div className="text-[11px] text-ink-soft">{p.title}</div>
            <div className="text-[10.5px] text-ink-mute mt-1.5 space-y-0.5">
              <div className="flex items-center gap-1.5"><Icon name="building" size={10} /> {p.dept} · {p.location}</div>
              <div className="flex items-center gap-1.5"><Icon name="mail" size={10} /> {p.email}</div>
              <div className="flex items-center gap-1.5"><Icon name="clock" size={10} /> {p.tenure}</div>
            </div>
          </div>
        </article>
      ))}
    </div>
  )
}

function DirectoryList({ people }: { people: any[] }) {
  return (
    <table className="w-full text-[12px]">
      <thead>
        <tr className="bg-cream text-left text-[10px] font-bold uppercase tracking-wider text-ink-mute">
          <th className="px-4 py-2">Employee</th>
          <th>Title</th>
          <th>Department</th>
          <th>Location</th>
          <th>Status</th>
          <th>Tenure</th>
        </tr>
      </thead>
      <tbody>
        {people.map(p => (
          <tr key={p.id} className="border-t border-divider-soft hover:bg-cream/50">
            <td className="px-4 py-2 flex items-center gap-2">
              <Avatar initials={p.initials} tone={p.tone} size="sm" />
              <div>
                <div className="text-[12.5px] font-semibold text-ink">{p.name}</div>
                <div className="text-[10px] text-ink-mute">{p.email}</div>
              </div>
            </td>
            <td className="text-ink-soft">{p.title}</td>
            <td><Badge variant="brand">{p.dept}</Badge></td>
            <td className="text-ink-mute">{p.location}</td>
            <td>
              {p.status === "active"    && <Badge variant="success" dot>Active</Badge>}
              {p.status === "probation" && <Badge variant="warn" dot>Probation</Badge>}
              {p.status === "on-leave"  && <Badge variant="info" dot>On Leave</Badge>}
            </td>
            <td className="text-ink-mute">{p.tenure}</td>
          </tr>
        ))}
      </tbody>
    </table>
  )
}

// SANDBOX
;(globalThis as any).EmployeeDirectory = EmployeeDirectory

})();/*__IIFE_WRAP_END__*/

/* ═════ apps/web/components/hr/org-chart.tsx ═════ */
;/*__IIFE_WRAP_START__*/(function(){
/**
 * ============================================================================
 * apps/web/components/hr/org-chart.tsx
 * ----------------------------------------------------------------------------
 * Screen 17 — Org Chart. Recursive tree from EMPLOYEES (managerId graph).
 * Cards group by department colour; clicking a node highlights its subtree.
 * ============================================================================
 */

function OrgChart() {
  const [highlightId, setHighlightId] = React.useState<string | null>(null)
  const ceo = EMPLOYEES.find(e => !e.managerId)!

  const childrenOf = (id: string) => EMPLOYEES.filter(e => e.managerId === id)

  return (
    <>
      <TopBar
        breadcrumb={[{ label: "HRIS" }, { label: "Org Chart" }]}
        actions={
          <>
            <Button variant="ghost" leadingIcon="download">Export PDF</Button>
            <Button variant="ghost" leadingIcon="filter">Filter by dept</Button>
            <Button variant="primary" leadingIcon="plus">Add Position</Button>
          </>
        }
      />

      <div className="flex-1 overflow-auto bg-app">
        <div className="p-8 space-y-6 w-max min-w-full">
          {/* Legend */}
          <div className="flex items-center gap-3 text-[10.5px] flex-wrap">
            <span className="text-[10px] font-bold uppercase tracking-wider text-ink-mute">Departments</span>
            {[
              { d: "Executive",    tone: "teal"  },
              { d: "Finance",      tone: "sand"  },
              { d: "Procurement",  tone: "blue"  },
              { d: "Operations",   tone: "amber" },
              { d: "HRIS",         tone: "red"   },
              { d: "Construction", tone: "red"   },
              { d: "IT",           tone: "blue"  },
            ].map(l => (
              <span key={l.d} className="inline-flex items-center gap-1.5 text-ink-soft">
                <Avatar initials={l.d.slice(0,2)} tone={l.tone as any} size="xs" />
                {l.d}
              </span>
            ))}
          </div>

          {/* Tree */}
          <div className="flex flex-col items-center gap-0">
            <OrgNode emp={ceo} highlight={highlightId} onHighlight={setHighlightId} primary />

            {/* Connector down to first row */}
            <Connector />

            {/* CEO direct reports */}
            <DirectReportsRow people={childrenOf(ceo.id)} childrenOf={childrenOf} highlight={highlightId} onHighlight={setHighlightId} />
          </div>
        </div>
      </div>
    </>
  )
}

function OrgNode({ emp, highlight, onHighlight, primary, compact }: any) {
  const isHighlighted = highlight === emp.id
  const isFaded = highlight && highlight !== emp.id
  return (
    <button
      onClick={() => onHighlight(isHighlighted ? null : emp.id)}
      className={cn(
        "bg-surface border-2 rounded-lg flex flex-col items-center text-center transition-all relative",
        compact ? "w-[148px] p-2.5 border-divider" : "w-[180px] p-3 border-divider",
        primary && "border-brand bg-brand-soft/40",
        isHighlighted && "border-accent shadow-md scale-[1.02]",
        isFaded && "opacity-50",
      )}>
      {primary && <span className="absolute -top-2 left-1/2 -translate-x-1/2 bg-accent text-brand text-[8px] font-bold px-2 py-px rounded-full">CEO</span>}
      <Avatar initials={emp.initials} tone={emp.tone} size={compact ? "md" : "lg"} />
      <div className="text-[12.5px] font-semibold text-ink mt-2 leading-tight">{emp.name}</div>
      <div className={cn("text-[10.5px] text-ink-mute leading-tight mt-0.5", compact && "text-[10px]")}>{emp.title}</div>
      <Badge variant="brand" className="mt-2">{emp.dept}</Badge>
    </button>
  )
}

function Connector({ short }: { short?: boolean }) {
  return <div className={cn("w-px bg-divider-strong", short ? "h-4" : "h-6")} />
}

/* ─── Direct reports of CEO ──
 * Each dept-head is rendered as a column with its own subs underneath. The
 * row of columns is laid out by flex with explicit gaps, so the whole tree
 * has a deterministic natural width that the parent (overflow-auto) can
 * scroll horizontally. */
function DirectReportsRow({ people, childrenOf, highlight, onHighlight }: any) {
  if (people.length === 0) return null
  return (
    <div className="flex flex-col items-stretch">
      {/* Horizontal connector + vertical drop into each column */}
      <div className="relative h-6">
        {people.length > 1 && (
          <div className="absolute top-0 left-1/2 -translate-x-1/2 h-px bg-divider-strong"
            style={{ width: `calc(100% - 192px)` /* leave half-card on each end */ }} />
        )}
        <div className="absolute top-0 left-0 right-0 h-full flex justify-around">
          {people.map((p: any) => (
            <div key={p.id} className="w-px h-full bg-divider-strong" />
          ))}
        </div>
      </div>

      {/* Cards row */}
      <div className="flex items-start gap-4 justify-around">
        {people.map((p: any) => {
          const subs = childrenOf(p.id)
          const subCount = Math.max(subs.length, 1)
          const colWidth = Math.max(192, subCount * 156) /* enough to hold sub columns */
          return (
            <div key={p.id} className="flex flex-col items-center shrink-0" style={{ width: `${colWidth}px` }}>
              <OrgNode emp={p} highlight={highlight} onHighlight={onHighlight} />
              {subs.length > 0 && (
                <>
                  <Connector short />
                  {/* Horizontal connector for the subs row */}
                  <div className="relative h-3 w-full">
                    {subs.length > 1 && (
                      <div className="absolute top-0 h-px bg-divider"
                        style={{ left: `${(100 / subs.length) / 2}%`, right: `${(100 / subs.length) / 2}%` }} />
                    )}
                    <div className="absolute top-0 left-0 right-0 h-full flex justify-around">
                      {subs.map((s: any) => <div key={s.id} className="w-px h-full bg-divider" />)}
                    </div>
                  </div>
                  <div className="flex items-start justify-center gap-2 w-full">
                    {subs.map((s: any) => (
                      <div key={s.id} className="shrink-0">
                        <OrgNode emp={s} compact highlight={highlight} onHighlight={onHighlight} />
                      </div>
                    ))}
                  </div>
                </>
              )}
            </div>
          )
        })}
      </div>
    </div>
  )
}

// SANDBOX
;(globalThis as any).OrgChart = OrgChart

})();/*__IIFE_WRAP_END__*/

/* ═════ apps/web/components/hr/hire-to-retire.tsx ═════ */
;/*__IIFE_WRAP_START__*/(function(){
/**
 * ============================================================================
 * apps/web/components/hr/hire-to-retire.tsx
 * ----------------------------------------------------------------------------
 * Screen 18 — Hire-to-Retire pipeline. Kanban-style 7-column board from
 * requisition → exit, with the actively employed column compressed (most
 * relevant action is at the edges, not the middle).
 * ============================================================================
 */

function HireToRetire() {
  const [filter, setFilter] = React.useState<"all" | "mine" | "urgent">("all")
  const [openId, setOpenId] = React.useState<string | null>(null)

  const items = (H2R_PIPELINE as any[]).filter(e => {
    if (filter === "mine" && e.ownerInitials !== "OP") return false
    if (filter === "urgent" && e.daysInStage < 5) return false
    return true
  })

  const open = items.find(i => i.id === openId)

  return (
    <>
      <TopBar
        breadcrumb={[{ label: "HRIS" }, { label: "Hire-to-Retire" }]}
        actions={
          <>
            <Button variant="ghost" leadingIcon="download">Export</Button>
            <Button variant="primary" leadingIcon="plus">New Requisition</Button>
          </>
        }
      />

      <Subheader>
        <FilterChip active={filter === "all"}    onClick={() => setFilter("all")}    count={H2R_PIPELINE.length}>All</FilterChip>
        <FilterChip active={filter === "mine"}   onClick={() => setFilter("mine")}   count={H2R_PIPELINE.filter(p => p.ownerInitials === "OP").length}>Mine (Olivia)</FilterChip>
        <FilterChip active={filter === "urgent"} onClick={() => setFilter("urgent")} tone="danger" icon="alert-triangle">Stalled &gt; 5 days</FilterChip>
        <span className="ml-2 text-[10px] text-ink-mute">7-stage pipeline · open requisition → exit</span>
      </Subheader>

      <div className="flex-1 overflow-x-auto overflow-y-hidden bg-app">
        <div className="flex gap-3 p-5 h-full items-start min-w-max">
          {H2R_STAGES.map(stage => {
            const cards = items.filter(i => i.stage === stage.key)
            return (
              <section key={stage.key} className="w-[240px] shrink-0 flex flex-col">
                <header className={cn("border border-divider border-b-0 rounded-t-md px-3 py-2 flex items-center gap-2", stage.tint)}>
                  <span className="text-[12px] font-bold text-ink">{stage.label}</span>
                  <span className="ml-auto text-[10px] font-semibold text-ink-mute bg-surface px-2 py-px rounded-full">{cards.length}</span>
                </header>
                <div className="bg-surface/60 border border-divider rounded-b-md p-2 flex flex-col gap-2 min-h-[200px] max-h-[calc(100vh-220px)] overflow-y-auto">
                  {cards.map(c => (
                    <button key={c.id} onClick={() => setOpenId(c.id)}
                      className="bg-surface border border-divider rounded-md p-3 text-left hover:border-brand-mid transition-colors">
                      <div className="text-[12px] font-semibold text-ink">{c.name}</div>
                      <div className="text-[10.5px] text-ink-mute mt-0.5">{c.role} · {c.dept}</div>
                      {c.note && <div className="text-[10.5px] text-ink-soft mt-2 leading-relaxed">{c.note}</div>}
                      <div className="flex items-center gap-2 mt-2.5 pt-2 border-t border-divider-soft">
                        <Avatar initials={c.ownerInitials} tone={c.ownerTone} size="xs" />
                        <span className="text-[10px] text-ink-mute">{c.owner}</span>
                        <span className="ml-auto text-[10px] font-semibold flex items-center gap-1">
                          <Icon name="clock" size={10} className="text-ink-mute" />
                          <span className={c.daysInStage > 5 ? "text-warn" : "text-ink-mute"}>{c.daysInStage}d</span>
                        </span>
                      </div>
                    </button>
                  ))}
                  {cards.length === 0 && (
                    <div className="text-[10.5px] text-ink-faint text-center py-4">Nothing here</div>
                  )}
                </div>
              </section>
            )
          })}
        </div>
      </div>

      {/* Detail sheet */}
      {open && (
        <Sheet open={!!open} onOpenChange={(o) => { if (!o) setOpenId(null) }}>
          <SheetContent>
            <header className="p-5 border-b border-divider">
              <Badge variant="brand">{open.dept}</Badge>
              <h2 className="font-serif text-xl text-ink mt-2">{open.name}</h2>
              <div className="text-[12px] text-ink-mute mt-1">{open.role}</div>
            </header>
            <div className="flex-1 overflow-y-auto p-5 space-y-4">
              <Card>
                <div className="p-4 space-y-3 text-[12px]">
                  <div className="flex justify-between"><span className="text-ink-mute">Stage</span><Badge variant="info">{H2R_STAGES.find(s => s.key === open.stage)?.label}</Badge></div>
                  <div className="flex justify-between"><span className="text-ink-mute">Days in stage</span><span className="text-ink font-semibold">{open.daysInStage}</span></div>
                  <div className="flex justify-between items-center"><span className="text-ink-mute">Owner</span><span className="flex items-center gap-2"><Avatar initials={open.ownerInitials} tone={open.ownerTone} size="xs" /><span className="text-ink-soft text-[11px]">{open.owner}</span></span></div>
                  {open.note && <div className="text-ink-soft pt-2 border-t border-divider-soft">{open.note}</div>}
                </div>
              </Card>
              <Card>
                <CardHeader>
                  <CardTitle>Next steps</CardTitle>
                </CardHeader>
                <div className="p-4 space-y-2 text-[12px]">
                  {NEXT_STEPS[open.stage].map((s: string, i: number) => (
                    <label key={i} className="flex items-center gap-2 text-ink-soft hover:bg-cream/50 px-2 py-1 rounded -mx-2">
                      <input type="checkbox" className="size-3.5 rounded border-divider" />
                      {s}
                    </label>
                  ))}
                </div>
              </Card>
            </div>
            <footer className="border-t border-divider p-4 flex items-center justify-between">
              <Button variant="ghost" leadingIcon="message">Add note</Button>
              <Button variant="primary" leadingIcon="arrow-right">Advance stage</Button>
            </footer>
          </SheetContent>
        </Sheet>
      )}
    </>
  )
}

const NEXT_STEPS: any = {
  requisition: ["Confirm budget approval", "Draft job description", "Post to careers page"],
  shortlist:   ["Review resumes", "Schedule first interview", "Send pre-screening assessment"],
  interview:   ["Conduct panel interview", "Collect feedback from interviewers", "Reference check"],
  offer:       ["Compensation approval", "Send offer letter", "Negotiate counter-offer if needed"],
  onboarding:  ["Day 1 setup", "30-day check-in", "Complete training matrix"],
  active:      ["Probation review", "Annual performance review", "Career development plan"],
  exit:        ["Exit interview", "Final pay computation", "Clearance & equipment return"],
}

// SANDBOX
;(globalThis as any).HireToRetire = HireToRetire

})();/*__IIFE_WRAP_END__*/

/* ═════ apps/web/components/hr/recruitment.tsx ═════ */
;/*__IIFE_WRAP_START__*/(function(){
/**
 * apps/web/components/hr/recruitment.tsx
 * HRIS — Recruitment. Open reqs + candidates pipeline, with connector hints
 * for Indeed / LinkedIn.
 */

function HRRecruitment() {
  const reqs = (RECRUITMENT_REQS as any[])
  const cands = (RECRUITMENT_CANDIDATES as any[])
  const [selectedReq, setSelectedReq] = React.useState<string>(reqs[0].id)
  const reqCands = cands.filter(c => c.reqId === selectedReq)
  const sel = reqs.find(r => r.id === selectedReq)

  return (
    <>
      <TopBar breadcrumb={[{ label: "HRIS" }, { label: "Recruitment" }]} />
      <ActionBar
        title="Recruitment"
        status={`${reqs.length} open requisitions · ${cands.length}+ candidates in pipeline · Indeed + LinkedIn connected`}
        primary={<Button variant="primary" leadingIcon="plus" size="sm">Open requisition</Button>}
        secondary={<Button variant="ghost" leadingIcon="upload" size="sm">Import resumes</Button>}
        ai={<Button variant="subtle" leadingIcon="sparkle" size="sm">Match candidates</Button>}
      />

      <div className="flex-1 flex overflow-hidden bg-app">
        {/* Reqs list */}
        <div className="w-[360px] shrink-0 border-r border-divider overflow-y-auto bg-surface">
          {reqs.map(r => (
            <button key={r.id} onClick={() => setSelectedReq(r.id)}
              className={cn(
                "w-full text-left p-3 border-b border-divider-soft transition-colors",
                selectedReq === r.id ? "bg-brand-soft" : "hover:bg-cream"
              )}>
              <div className="flex items-center justify-between mb-1">
                <span className="font-mono text-[10px] font-bold text-brand-mid">{r.id}</span>
                <span className="text-[10px] font-mono text-ink-mute">{r.entity}</span>
              </div>
              <div className="text-[12.5px] text-ink font-semibold leading-tight">{r.title}</div>
              <div className="text-[10.5px] text-ink-mute mt-1">{r.dept} · {r.openings} opening{r.openings > 1 ? "s" : ""} · {r.daysOpen}d open</div>
              <div className="flex items-center gap-3 mt-2 text-[10px]">
                <span><span className="font-mono font-bold text-ink">{r.applicants}</span> applicants</span>
                <Badge variant={r.stage === "offer" ? "success" : r.stage === "interviewing" ? "info" : "neutral"}>{r.stage}</Badge>
              </div>
            </button>
          ))}
        </div>

        {/* Candidates */}
        <div className="flex-1 overflow-y-auto">
          <div className="max-w-[1080px] mx-auto p-6 space-y-4">
            <div>
              <div className="flex items-center gap-2 mb-1">
                <span className="font-mono text-[11px] font-bold text-brand-mid">{sel.id}</span>
                <span className="text-[10px] text-ink-mute">· Hiring manager: {sel.hiringMgr}</span>
              </div>
              <h2 className="font-serif text-[26px] text-ink leading-tight">{sel.title}</h2>
              <div className="text-[12px] text-ink-mute mt-1">{sel.entity} · {sel.dept} · {sel.level} · Target: {sel.target}</div>
            </div>

            {/* Stages */}
            <div className="grid grid-cols-5 gap-3">
              {["applied", "screening", "interviewing", "offer", "hired"].map(s => {
                const c = s === "applied" ? sel.applicants : reqCands.filter(x => x.stage === s).length
                return (
                  <div key={s} className="bg-surface border border-divider rounded-lg p-3 text-center">
                    <div className="text-[10px] uppercase tracking-wider font-bold text-ink-mute">{s}</div>
                    <div className="font-serif text-[24px] text-ink mt-1 leading-none">{c}</div>
                  </div>
                )
              })}
            </div>

            {/* Pipeline */}
            <Card>
              <CardHeader>
                <div>
                  <div className="text-[10px] uppercase tracking-wider font-bold text-ink-mute">Pipeline</div>
                  <div className="font-serif text-[18px] text-ink mt-0.5">Candidates for {sel.title}</div>
                </div>
                <Button variant="ghost" size="sm" leadingIcon="plus">Add candidate</Button>
              </CardHeader>
              <div className="divide-y divide-divider-soft">
                {reqCands.map(c => (
                  <div key={c.id} className="px-4 py-3 flex items-center gap-3 hover:bg-cream/40">
                    <Avatar initials={c.initials} tone="sand" size="md" />
                    <div className="flex-1 min-w-0">
                      <div className="flex items-center gap-2">
                        <span className="text-[12.5px] text-ink font-semibold">{c.name}</span>
                        {c.flagAi && <Badge variant="accent">★ AI top pick</Badge>}
                      </div>
                      <div className="text-[10.5px] text-ink-mute">{c.fit}</div>
                      <div className="text-[10px] text-ink-mute mt-0.5">{c.last} · Source: {c.source}</div>
                    </div>
                    <div className="text-right">
                      <div className="text-[10px] uppercase tracking-wider font-bold text-ink-mute">Score</div>
                      <div className="font-serif text-[18px] text-ink">{c.score}<span className="text-[10px] text-ink-mute">/10</span></div>
                    </div>
                    <Badge variant={c.stage === "offer" ? "success" : c.stage === "interviewing" ? "info" : "neutral"}>{c.stage}</Badge>
                    <Button variant="ghost" size="sm">Open</Button>
                  </div>
                ))}
                {reqCands.length === 0 && <div className="px-4 py-6 text-[11px] text-ink-mute italic text-center">No candidates yet for this requisition.</div>}
              </div>
            </Card>
          </div>
        </div>
      </div>
    </>
  )
}

// SANDBOX
;(globalThis as any).HRRecruitment = HRRecruitment

})();/*__IIFE_WRAP_END__*/

/* ═════ apps/web/components/hr/performance.tsx ═════ */
;/*__IIFE_WRAP_START__*/(function(){
/**
 * apps/web/components/hr/performance.tsx
 * HRIS — Performance Reviews dashboard with AI-flagged anomalies.
 */

function HRPerformance() {
  const cycle = PERF_CYCLE as any
  const reviews = (PERF_REVIEWS as any[])
  const flags = (PERF_TOP_FLAGS as any[])
  const totalEmployees = reviews.reduce((s, r) => s + r.employees, 0)
  const totalCompleted = reviews.reduce((s, r) => s + r.completed, 0)
  const overallParticipation = totalCompleted / totalEmployees

  return (
    <>
      <TopBar breadcrumb={[{ label: "HRIS" }, { label: "Performance" }]} />
      <ActionBar
        title="Performance Reviews"
        status={`${cycle.name} · Ends ${cycle.endsOn} · ${Math.round(overallParticipation * 100)}% complete`}
        primary={<Button variant="primary" leadingIcon="plus" size="sm">New cycle</Button>}
        secondary={<Button variant="ghost" leadingIcon="download" size="sm">Export ratings</Button>}
        ai={<Button variant="subtle" leadingIcon="sparkle" size="sm">AI analysis</Button>}
      />

      <div className="flex-1 overflow-y-auto bg-app">
        <div className="max-w-[1280px] mx-auto p-6 space-y-4">
          {/* Top KPIs */}
          <div className="grid grid-cols-4 gap-3">
            <KpiTile label="Participation" value={`${Math.round(overallParticipation * 100)}%`} sub={`${totalCompleted} / ${totalEmployees} complete`} accent="info" />
            <KpiTile label="Avg score" value="4.05" sub="Out of 5.0 · ↗ from last cycle" accent="success" deltaDir="up" delta="+0.08" />
            <KpiTile label="AI flags" value={String(reviews.reduce((s, r) => s + r.aiFlag, 0))} sub="Anomalies detected" accent="warn" />
            <KpiTile label="Calibration meetings" value="6" sub="Across 6 departments" accent="brand" />
          </div>

          {/* AI flags */}
          <div className="bg-accent-soft/60 border border-accent/30 rounded-lg p-4">
            <div className="flex items-center gap-2 mb-3">
              <Icon name="sparkle" size={14} className="text-accent-deep" />
              <div className="text-[12px] font-bold text-accent-deep">AI Performance Analysis · Flagged for calibration</div>
            </div>
            <div className="space-y-2">
              {flags.map((f, i) => (
                <div key={i} className="bg-surface rounded-md p-2.5 flex items-center gap-3">
                  <Avatar initials={f.initials} tone="sand" size="sm" />
                  <div className="flex-1 min-w-0">
                    <div className="text-[12px] font-semibold text-ink">{f.who} <span className="text-[10px] font-mono text-ink-mute">{f.entity}</span></div>
                    <div className="text-[11px] text-ink-soft">{f.flag}</div>
                  </div>
                  <Badge variant={f.severity === "high" ? "danger" : f.severity === "med" ? "warn" : "neutral"}>{f.severity}</Badge>
                  <Button variant="ghost" size="sm">Review</Button>
                </div>
              ))}
            </div>
          </div>

          {/* By department */}
          <Card>
            <CardHeader>
              <div>
                <div className="text-[10px] uppercase tracking-wider font-bold text-ink-mute">By department</div>
                <div className="font-serif text-[18px] text-ink mt-0.5">Cycle progress</div>
              </div>
            </CardHeader>
            <div className="divide-y divide-divider-soft">
              {reviews.map(r => (
                <div key={r.dept} className="px-4 py-3 grid grid-cols-[1.4fr_140px_180px_120px_80px] items-center gap-3">
                  <div>
                    <div className="text-[12.5px] text-ink font-semibold">{r.dept}</div>
                    <div className="text-[10.5px] text-ink-mute">{r.reviewers} reviewers · {r.employees} employees</div>
                  </div>
                  <div className="text-[10.5px]">
                    <div className="flex items-center gap-2">
                      <div className="flex-1 h-1.5 bg-cream rounded-full overflow-hidden">
                        <div className="h-full bg-brand" style={{ width: `${r.completed / r.employees * 100}%` }} />
                      </div>
                      <span className="font-mono font-bold w-12 text-right">{Math.round(r.completed / r.employees * 100)}%</span>
                    </div>
                  </div>
                  <div className="flex items-center gap-1.5">
                    {[1, 2, 3, 4, 5].map(s => (
                      <span key={s} className={cn("size-4 rounded-sm", s <= Math.round(r.avgScore) ? "bg-accent" : "bg-cream")} />
                    ))}
                    <span className="ml-2 text-[10.5px] font-mono font-bold text-ink">{r.avgScore.toFixed(1)}</span>
                  </div>
                  <div>
                    {r.aiFlag > 0 && <Badge variant="warn" dot>{r.aiFlag} flag{r.aiFlag > 1 ? "s" : ""}</Badge>}
                  </div>
                  <Button variant="ghost" size="sm">Open</Button>
                </div>
              ))}
            </div>
          </Card>
        </div>
      </div>
    </>
  )
}

// SANDBOX
;(globalThis as any).HRPerformance = HRPerformance

})();/*__IIFE_WRAP_END__*/

/* ═════ apps/web/components/hr/training.tsx ═════ */
;/*__IIFE_WRAP_START__*/(function(){
/**
 * apps/web/components/hr/training.tsx
 * HRIS — Training programs catalogue.
 */

function HRTraining() {
  const progs = (TRAINING_PROGRAMS as any[])
  const [cat, setCat] = React.useState<string>("all")
  const [search, setSearch] = React.useState("")
  const cats = ["all", ...Array.from(new Set(progs.map(p => p.category)))]

  let filtered = cat === "all" ? progs : progs.filter(p => p.category === cat)
  if (search.trim()) filtered = filtered.filter(p => p.title.toLowerCase().includes(search.toLowerCase()))

  return (
    <>
      <TopBar breadcrumb={[{ label: "HRIS" }, { label: "Training" }]} />
      <ActionBar
        title="Training & Development"
        status={`${progs.length} active programs · ${progs.filter(p => p.required).length} mandatory · ${progs.reduce((s, p) => s + p.completed, 0).toLocaleString()} completions YTD`}
        search={<SearchBox value={search} onChange={setSearch} placeholder="Search programs…" className="w-[280px]" />}
        primary={<Button variant="primary" leadingIcon="plus" size="sm">New program</Button>}
        secondary={<Button variant="ghost" leadingIcon="download" size="sm">Export</Button>}
        filters={
          <>
            {cats.map(c => (
              <FilterChip key={c} active={cat === c} onClick={() => setCat(c)}>{c === "all" ? "All categories" : c}</FilterChip>
            ))}
          </>
        }
      />

      <div className="flex-1 overflow-y-auto bg-app">
        <div className="max-w-[1280px] mx-auto p-6">
          <div className="grid grid-cols-2 lg:grid-cols-3 gap-3">
            {filtered.map(p => {
              const rate = p.completed / p.enrolled
              return (
                <Card key={p.id} className="hover:shadow-md transition-shadow">
                  <div className="p-4">
                    <div className="flex items-center gap-2 mb-2">
                      <span className="font-mono text-[10px] font-bold text-brand-mid">{p.id}</span>
                      <span className="ml-auto">
                        {p.required && <Badge variant="warn">Mandatory</Badge>}
                      </span>
                    </div>
                    <div className="text-[14px] text-ink font-semibold leading-tight">{p.title}</div>
                    <div className="flex items-center gap-1.5 mt-1 text-[10.5px] text-ink-mute">
                      <Icon name="tag" size={10} /> {p.category}
                      <span>·</span>
                      <Icon name="clock" size={10} /> {p.mode}
                    </div>
                    {p.dueBy !== "—" && (
                      <div className="text-[10.5px] text-warn font-semibold mt-1.5">Due by {p.dueBy}</div>
                    )}
                    <div className="mt-3 pt-3 border-t border-divider-soft">
                      <div className="flex items-center justify-between mb-1.5">
                        <span className="text-[10px] uppercase tracking-wider font-bold text-ink-mute">Completion</span>
                        <span className="text-[11px] font-mono font-bold text-ink">{Math.round(rate * 100)}%</span>
                      </div>
                      <div className="h-1.5 bg-cream rounded-full overflow-hidden">
                        <div className={cn("h-full", rate >= 0.9 ? "bg-success" : rate >= 0.7 ? "bg-warn" : "bg-danger")} style={{ width: `${rate * 100}%` }} />
                      </div>
                      <div className="text-[10px] text-ink-mute mt-1 font-mono">{p.completed.toLocaleString()} / {p.enrolled.toLocaleString()} enrolled</div>
                    </div>
                  </div>
                </Card>
              )
            })}
          </div>
        </div>
      </div>
    </>
  )
}

// SANDBOX
;(globalThis as any).HRTraining = HRTraining

})();/*__IIFE_WRAP_END__*/

/* ═════ apps/web/components/hr/payroll.tsx ═════ */
;/*__IIFE_WRAP_START__*/(function(){
/**
 * apps/web/components/hr/payroll.tsx
 * HRIS — Payroll runs by entity x month.
 */

function HRPayroll() {
  const runs = (PAYROLL_RUNS as any[])
  const k = PAYROLL_KPIS as any
  function ccyPrefix(c: string) { return c === "PHP" ? "₱" : c === "SGD" ? "S$" : c === "HKD" ? "HK$" : c === "AUD" ? "A$" : c === "INR" ? "₹" : "$" }
  return (
    <>
      <TopBar breadcrumb={[{ label: "HRIS" }, { label: "Payroll" }]} />
      <ActionBar
        title="Payroll Runs"
        status={`May 2026 cycle in progress · 5 entities · ${k.totalEmployees.toLocaleString()} employees · $${k.totalGrossUsdM}M MTD`}
        primary={<Button variant="primary" leadingIcon="play" size="sm">Run May payroll</Button>}
        secondary={<Button variant="ghost" leadingIcon="download" size="sm">Export</Button>}
        ai={<Button variant="subtle" leadingIcon="sparkle" size="sm">Anomaly scan</Button>}
      />

      <div className="flex-1 overflow-y-auto bg-app">
        <div className="max-w-[1280px] mx-auto p-6 space-y-4">
          {/* KPIs */}
          <div className="grid grid-cols-4 gap-3">
            <KpiTile label="Total employees" value={k.totalEmployees.toLocaleString()} sub="Across 5 entities" accent="brand" />
            <KpiTile label="Gross MTD" value={`$${k.totalGrossUsdM}M`} sub="USD equiv" accent="success" />
            <KpiTile label="Tax withheld" value={`$${(k.taxWithheldUsd / 1000).toFixed(0)}k`} sub="Remitted to authorities" accent="info" />
            <KpiTile label="Bonus pool Q1" value={`$${(k.bonusPoolUsd / 1000).toFixed(0)}k`} sub="Pending allocation" accent="accent" />
          </div>

          {/* Runs table */}
          <Card>
            <CardHeader>
              <div>
                <div className="text-[10px] uppercase tracking-wider font-bold text-ink-mute">Payroll runs</div>
                <div className="font-serif text-[18px] text-ink mt-0.5">Last 2 cycles</div>
              </div>
              <Button variant="ghost" size="sm" leadingIcon="calendar">Schedule next runs</Button>
            </CardHeader>
            <div className="grid grid-cols-[120px_120px_120px_140px_140px_120px_140px] px-4 py-2 bg-cream text-[10px] uppercase tracking-wider font-bold text-ink-mute border-y border-divider">
              <span>Entity</span><span>Month</span><span className="text-right">Employees</span><span className="text-right">Gross</span><span className="text-right">Net</span><span>Status</span><span>Processed</span>
            </div>
            {runs.map((r, i) => (
              <div key={i} className="grid grid-cols-[120px_120px_120px_140px_140px_120px_140px] px-4 py-2.5 items-center border-t border-divider-soft hover:bg-cream/40 text-[11.5px]">
                <span className="font-mono font-bold text-brand-mid">{r.entity}</span>
                <span className="text-ink">{r.month}</span>
                <span className="font-mono text-right">{r.employees}</span>
                <span className="font-mono text-right">{ccyPrefix(r.ccy)} {(r.gross / 1000).toLocaleString()}k</span>
                <span className="font-mono text-right">{ccyPrefix(r.ccy)} {(r.net / 1000).toLocaleString()}k</span>
                {r.status === "posted"      ? <Badge variant="success">✓ Posted</Badge>
                : r.status === "in-progress" ? <Badge variant="info" dot>Processing</Badge>
                                              : <Badge variant="neutral">Draft</Badge>}
                <span className="text-[10.5px] text-ink-mute">{r.processedAt}</span>
              </div>
            ))}
          </Card>
        </div>
      </div>
    </>
  )
}

// SANDBOX
;(globalThis as any).HRPayroll = HRPayroll

})();/*__IIFE_WRAP_END__*/

/* ═════ apps/web/components/hr/attendance.tsx ═════ */
;/*__IIFE_WRAP_START__*/(function(){
/**
 * apps/web/components/hr/attendance.tsx
 * HRIS — Attendance & Timekeeping. Multi-source ingestion view.
 */

function HRAttendance() {
  const today = (ATTENDANCE_TODAY as any[])
  const recent = (ATTENDANCE_RECENT as any[])
  const totalExpected = today.reduce((s, e) => s + e.expected, 0)
  const totalPresent = today.reduce((s, e) => s + e.present + e.remote, 0)
  const totalAbsent = today.reduce((s, e) => s + e.absent, 0)
  return (
    <>
      <TopBar breadcrumb={[{ label: "HRIS" }, { label: "Attendance" }]} />
      <ActionBar
        title="Attendance & Timekeeping"
        status={`${totalPresent.toLocaleString()} / ${totalExpected.toLocaleString()} present today · Source: Hikvision + Dahua + MS Teams Shifts + Cenora App`}
        secondary={<Button variant="ghost" leadingIcon="download" size="sm">Export DTR</Button>}
        primary={<Button variant="primary" leadingIcon="settings" size="sm">Configure sources</Button>}
      />

      <div className="flex-1 overflow-y-auto bg-app">
        <div className="max-w-[1280px] mx-auto p-6 space-y-4">
          <div className="grid grid-cols-4 gap-3">
            <KpiTile label="Present" value={totalPresent.toLocaleString()} sub={`${Math.round(totalPresent / totalExpected * 100)}% of expected`} accent="success" />
            <KpiTile label="Remote" value={today.reduce((s, e) => s + e.remote, 0).toString()} sub="GPS-verified WFH" accent="info" />
            <KpiTile label="Late" value={today.reduce((s, e) => s + e.late, 0).toString()} sub="Today" accent="warn" />
            <KpiTile label="Absent" value={totalAbsent.toString()} sub="Unplanned · Need follow-up" accent="danger" />
          </div>

          {/* Entity rollup */}
          <Card>
            <CardHeader>
              <div>
                <div className="text-[10px] uppercase tracking-wider font-bold text-ink-mute">Today by entity</div>
                <div className="font-serif text-[18px] text-ink mt-0.5">Attendance roll-up</div>
              </div>
            </CardHeader>
            <div className="grid grid-cols-[100px_100px_100px_80px_80px_80px_80px_1.5fr] px-4 py-2 bg-cream text-[10px] uppercase tracking-wider font-bold text-ink-mute border-y border-divider">
              <span>Entity</span><span className="text-right">Expected</span><span className="text-right">Present</span><span className="text-right">Remote</span><span className="text-right">Late</span><span className="text-right">Absent</span><span className="text-right">Leave</span><span>Source</span>
            </div>
            {today.map(e => (
              <div key={e.entity} className="grid grid-cols-[100px_100px_100px_80px_80px_80px_80px_1.5fr] px-4 py-2.5 items-center border-t border-divider-soft text-[11.5px] hover:bg-cream/40">
                <span className="font-mono font-bold text-brand-mid">{e.entity}</span>
                <span className="font-mono text-right">{e.expected}</span>
                <span className="font-mono text-right text-success font-bold">{e.present}</span>
                <span className="font-mono text-right">{e.remote}</span>
                <span className={cn("font-mono text-right", e.late > 0 && "text-warn font-bold")}>{e.late}</span>
                <span className={cn("font-mono text-right", e.absent > 0 && "text-danger font-bold")}>{e.absent}</span>
                <span className="font-mono text-right text-ink-mute">{e.onLeave}</span>
                <span className="text-[10.5px] text-ink-mute">{e.source}</span>
              </div>
            ))}
          </Card>

          {/* Recent punches */}
          <Card>
            <CardHeader>
              <div>
                <div className="text-[10px] uppercase tracking-wider font-bold text-ink-mute">Recent activity</div>
                <div className="font-serif text-[18px] text-ink mt-0.5">Live feed · Last 30 minutes</div>
              </div>
            </CardHeader>
            <div className="divide-y divide-divider-soft">
              {recent.map((r, i) => (
                <div key={i} className="px-4 py-2.5 flex items-center gap-3 hover:bg-cream/40">
                  <Avatar initials={r.initials} tone="sand" size="sm" />
                  <div className="flex-1 min-w-0">
                    <div className="text-[12px] text-ink font-semibold">{r.who} <span className="font-mono text-[10px] text-ink-mute">· {r.entity}</span></div>
                    <div className="text-[10.5px] text-ink-mute">{r.source}</div>
                  </div>
                  <Badge variant={r.action === "Punch IN" ? "success" : "neutral"}>{r.action}</Badge>
                  <span className="text-[11px] font-mono text-ink-mute w-20 text-right">{r.ts}</span>
                  {r.anomaly && <Badge variant="warn">⚠ GPS off-site</Badge>}
                </div>
              ))}
            </div>
          </Card>
        </div>
      </div>
    </>
  )
}

// SANDBOX
;(globalThis as any).HRAttendance = HRAttendance

})();/*__IIFE_WRAP_END__*/

/* ═════ apps/web/components/hr/cases.tsx ═════ */
;/*__IIFE_WRAP_START__*/(function(){
/**
 * apps/web/components/hr/cases.tsx
 * HRIS — HR Cases (grievances, performance, harassment, comp, etc).
 */

function HRCases() {
  const cases = (HR_CASES as any[])
  const [statusFilter, setStatusFilter] = React.useState<string>("all")
  const [typeFilter, setTypeFilter] = React.useState<string>("all")
  const types = ["all", ...Array.from(new Set(cases.map(c => c.type)))]
  let filtered = statusFilter === "all" ? cases : cases.filter(c => c.status === statusFilter)
  if (typeFilter !== "all") filtered = filtered.filter(c => c.type === typeFilter)

  return (
    <>
      <TopBar breadcrumb={[{ label: "HRIS" }, { label: "HR Cases" }]} />
      <ActionBar
        title="HR Cases"
        status={`${cases.length} total · ${cases.filter(c => c.status !== "resolved").length} open · ${cases.filter(c => c.severity === "high").length} high severity`}
        primary={<Button variant="primary" leadingIcon="plus" size="sm">New case</Button>}
        secondary={<Button variant="ghost" leadingIcon="download" size="sm">Export</Button>}
        filters={
          <>
            <FilterChip active={statusFilter === "all"} onClick={() => setStatusFilter("all")}>All</FilterChip>
            <FilterChip active={statusFilter === "investigation"} onClick={() => setStatusFilter("investigation")}>Investigation</FilterChip>
            <FilterChip active={statusFilter === "in-progress"} onClick={() => setStatusFilter("in-progress")}>In progress</FilterChip>
            <FilterChip active={statusFilter === "resolved"} onClick={() => setStatusFilter("resolved")}>Resolved</FilterChip>
            <span className="w-px h-5 bg-divider mx-1" />
            <span className="text-[10px] uppercase tracking-wider font-bold text-ink-mute mr-1">Type</span>
            {types.map(t => (
              <FilterChip key={t} active={typeFilter === t} onClick={() => setTypeFilter(t)}>{t === "all" ? "All" : t}</FilterChip>
            ))}
          </>
        }
      />

      <div className="flex-1 overflow-y-auto bg-app">
        <div className="max-w-[1280px] mx-auto p-6">
          <Card>
            <div className="grid grid-cols-[110px_120px_2fr_140px_140px_100px_120px] px-4 py-2 bg-cream text-[10px] uppercase tracking-wider font-bold text-ink-mute">
              <span>Case ID</span><span>Type</span><span>Summary</span><span>Reporter</span><span>Assigned to</span><span>Severity</span><span>Status</span>
            </div>
            {filtered.map(c => (
              <div key={c.id} className="grid grid-cols-[110px_120px_2fr_140px_140px_100px_120px] px-4 py-3 items-center border-t border-divider-soft hover:bg-cream/40 text-[11.5px]">
                <span className="font-mono font-bold text-brand-mid">{c.id}</span>
                <span className="text-ink-soft">{c.type}</span>
                <div>
                  <div className="text-ink font-medium leading-tight">{c.summary}</div>
                  <div className="text-[10px] text-ink-mute mt-0.5">{c.entity} · Opened {c.openedDaysAgo} days ago</div>
                </div>
                <span className="text-ink-soft">{c.reporter}</span>
                <span className="text-ink-soft">{c.assignedTo}</span>
                {c.severity === "high"  ? <Badge variant="danger">High</Badge>
                : c.severity === "med"   ? <Badge variant="warn">Med</Badge>
                                          : <Badge variant="neutral">Low</Badge>}
                {c.status === "resolved"      ? <Badge variant="success">✓ Resolved</Badge>
                : c.status === "investigation" ? <Badge variant="danger" dot>Investigation</Badge>
                                                : <Badge variant="info" dot>In progress</Badge>}
              </div>
            ))}
          </Card>

          <div className="mt-4 bg-info-soft border border-info/20 rounded-lg p-3 flex items-start gap-2.5">
            <Icon name="info" size={13} className="text-info mt-0.5" />
            <div className="text-[11px] text-info">
              <span className="font-semibold">Sensitive workflow.</span> HR Cases enforce strict access controls. Anonymous reporting is supported. Investigation cases route to Legal automatically.
            </div>
          </div>
        </div>
      </div>
    </>
  )
}

// SANDBOX
;(globalThis as any).HRCases = HRCases

})();/*__IIFE_WRAP_END__*/

/* ═════ apps/web/components/reports/report-library.tsx ═════ */
;/*__IIFE_WRAP_START__*/(function(){
/**
 * ============================================================================
 * apps/web/components/reports/report-library.tsx
 * ----------------------------------------------------------------------------
 * Screen 19 — Report Library. Grouped grid of all reports across modules,
 * with starred at top + scheduled badge + last-run metadata.
 * ============================================================================
 */

function ReportLibrary() {
  const { push } = useRouter()
  const [cat, setCat] = React.useState<"all" | "Finance" | "Procurement" | "Inventory" | "HRIS" | "Multi-Entity">("all")
  const [query, setQuery] = React.useState("")

  const filtered = (REPORTS as any[]).filter(r => {
    if (cat !== "all" && r.category !== cat) return false
    if (query && !(r.title + " " + r.description).toLowerCase().includes(query.toLowerCase())) return false
    return true
  })

  const starred = filtered.filter(r => r.starred)
  const rest = filtered.filter(r => !r.starred)

  return (
    <>
      <TopBar
        breadcrumb={[{ label: "Reports" }, { label: "Library" }]}
        actions={
          <>
            <Button variant="ghost" leadingIcon="filter">Schedule</Button>
            <Button variant="accent" leadingIcon="sparkle" onClick={() => push("/reports/ask-ai")}>Ask AI</Button>
            <Button variant="primary" leadingIcon="plus">New Report</Button>
          </>
        }
      />

      <Subheader right={<SearchBox value={query} onChange={setQuery} placeholder="Search reports…" className="w-56" />}>
        <FilterChip active={cat === "all"}          onClick={() => setCat("all")} count={REPORTS.length}>All</FilterChip>
        <FilterChip active={cat === "Finance"}      onClick={() => setCat("Finance")}      count={REPORTS.filter(r => r.category === "Finance").length}>Finance</FilterChip>
        <FilterChip active={cat === "Procurement"}  onClick={() => setCat("Procurement")}  count={REPORTS.filter(r => r.category === "Procurement").length}>Procurement</FilterChip>
        <FilterChip active={cat === "Inventory"}    onClick={() => setCat("Inventory")}    count={REPORTS.filter(r => r.category === "Inventory").length}>Inventory</FilterChip>
        <FilterChip active={cat === "HRIS"}         onClick={() => setCat("HRIS")}         count={REPORTS.filter(r => r.category === "HRIS").length}>HRIS</FilterChip>
        <FilterChip active={cat === "Multi-Entity"} onClick={() => setCat("Multi-Entity")} count={REPORTS.filter(r => r.category === "Multi-Entity").length}>Multi-Entity</FilterChip>
      </Subheader>

      <div className="flex-1 overflow-y-auto bg-app">
        <div className="max-w-[1320px] mx-auto p-6 space-y-5">

          {starred.length > 0 && (
            <section>
              <h2 className="text-[10px] font-bold uppercase tracking-wider text-ink-mute mb-3 flex items-center gap-2">
                <Icon name="star" size={11} strokeWidth={2.5} className="text-accent" />
                Starred ({starred.length})
              </h2>
              <div className="grid grid-cols-3 gap-3">
                {starred.map(r => <ReportCard key={r.id} r={r} push={push} />)}
              </div>
            </section>
          )}

          <section>
            <h2 className="text-[10px] font-bold uppercase tracking-wider text-ink-mute mb-3">All Reports ({rest.length})</h2>
            {rest.length === 0
              ? <div className="text-[12px] text-ink-mute py-6 text-center">No reports match the current filter.</div>
              : (
                <div className="grid grid-cols-3 gap-3">
                  {rest.map(r => <ReportCard key={r.id} r={r} push={push} />)}
                </div>
              )}
          </section>

          {/* Ask AI promo card */}
          <div className="bg-gradient-to-br from-brand to-brand-light rounded-lg p-6 text-white grid grid-cols-[1fr_auto] gap-6 items-center">
            <div>
              <div className="text-[10px] font-bold uppercase tracking-wider text-accent">✦ Cenora AI</div>
              <h3 className="font-serif text-2xl mt-1 leading-tight">Can't find the report? Just ask.</h3>
              <p className="text-[13px] text-white/70 mt-1.5 leading-relaxed max-w-[640px]">
                Describe what you need in plain English — "Show me vendors with 90+ days of unpaid invoices and their last 3 POs". AI will draft the SQL, render the table, and add it to your library if you like it.
              </p>
            </div>
            <Button variant="accent" leadingIcon="sparkle" onClick={() => push("/reports/ask-ai")}>Open Ask AI</Button>
          </div>
        </div>
      </div>
    </>
  )
}

function ReportCard({ r, push }: any) {
  const catColor: any = {
    Finance:        "bg-success-soft text-success",
    Procurement:    "bg-info-soft text-info",
    Inventory:      "bg-warn-soft text-warn",
    HRIS:           "bg-danger-soft text-danger",
    "Multi-Entity": "bg-accent-soft text-accent-deep",
  }
  const formatIcon: any = {
    table:     "list",
    chart:     "chart",
    matrix:    "grid",
    statement: "doc",
  }
  return (
    <article className="bg-surface border border-divider rounded-lg p-4 flex flex-col gap-3 hover:border-brand-mid hover:shadow-sm transition-all">
      <header className="flex items-start gap-3">
        <span className={cn("size-9 rounded-md flex items-center justify-center shrink-0", catColor[r.category])}>
          <Icon name={formatIcon[r.format]} size={15} />
        </span>
        <div className="flex-1 min-w-0">
          <div className="flex items-center gap-1.5">
            <h3 className="text-[13px] font-semibold text-ink truncate font-sans">{r.title}</h3>
            {r.starred && <Icon name="star" size={11} className="text-accent shrink-0" />}
          </div>
          <Badge variant="outline" className="mt-1">{r.category}</Badge>
        </div>
      </header>

      <p className="text-[11.5px] text-ink-soft leading-relaxed line-clamp-2">{r.description}</p>

      <div className="flex items-center gap-2 flex-wrap text-[10px] text-ink-mute mt-auto pt-2 border-t border-divider-soft">
        {r.scheduled && <Badge variant="brand" icon="calendar">{r.scheduled}</Badge>}
        {r.badges?.map((b: string) => <Badge key={b} variant="accent">{b}</Badge>)}
        <span className="ml-auto">Last run: <strong className="text-ink-soft">{r.lastRun}</strong></span>
      </div>

      <footer className="flex items-center gap-1.5 pt-2 border-t border-divider-soft">
        <Button size="sm" variant="primary" leadingIcon="play">Run</Button>
        <Button size="sm" variant="ghost" leadingIcon="calendar">Schedule</Button>
        <Button size="sm" variant="ghost" leadingIcon="star" className="ml-auto">{r.starred ? "Pinned" : "Pin"}</Button>
      </footer>
    </article>
  )
}

// SANDBOX
;(globalThis as any).ReportLibrary = ReportLibrary

})();/*__IIFE_WRAP_END__*/
