import React, { useState, useEffect, useRef } from "react";
import { createRoot } from "react-dom/client";
import {
  LayoutDashboard,
  Package,
  ScanLine,
  ArrowLeftRight,
  ClipboardCheck,
  ShoppingCart,
  CalendarClock,
  ChartNoAxesCombined,
  Settings,
  HelpCircle,
  Search,
  Plus,
  ArrowUpRight,
  ArrowRight,
  ArrowDownToLine,
  ChevronRight,
  ChevronDown,
  X,
  Menu,
  Bell,
  LogOut,
  Check,
  CheckCircle2,
  CircleAlert,
  MapPin,
  Truck,
  Boxes,
  ShieldCheck,
  RefreshCw,
  WifiOff,
  Leaf,
  MoreHorizontal,
  Download,
  Printer,
  Users,
  History,
  Building2,
  KeyRound,
  Eye,
  Sprout,
  CircleDot,
  FileUp,
  Activity,
} from "lucide-react";
import "./style.css";
import "./identity.css";
import { DemoWelcome, DemoShelf, DemoHint, Barcode } from './demo.jsx';
const money = (n, precise = false) =>
  new Intl.NumberFormat("en-US", {
    style: "currency",
    currency: "USD",
    minimumFractionDigits: precise ? 2 : 0,
    maximumFractionDigits: precise ? 2 : 0,
  }).format(n / 100);
const number = (n) =>
  new Intl.NumberFormat("en-US", { maximumFractionDigits: 1 }).format(n || 0);
const today = () => new Date().toISOString().slice(0, 10);
const day = (n) =>
  new Date(Date.now() + n * 86400000).toISOString().slice(0, 10);
const dateLabel = (d) =>
  d
    ? new Date(d + "T12:00:00").toLocaleDateString("en-US", {
        month: "short",
        day: "numeric",
      })
    : "No expiry";
const nav = [
  ["overview", "Overview", LayoutDashboard],
  ["inventory", "Inventory", Package],
  ["receive", "Receive & scan", ScanLine],
  ["transfers", "Transfers", ArrowLeftRight],
  ["counts", "Cycle counts", ClipboardCheck],
  ["purchasing", "Purchasing", ShoppingCart],
  ["expiry", "Expiry & waste", CalendarClock],
  ["sales", "Sales & reconciliation", ArrowDownToLine],
  ["reports", "Reports & planning", ChartNoAxesCombined],
  ["locations", "Locations & suppliers", Building2],
];
async function api(url, body, method = "POST", key) {
  let storageKey;
  if (body !== undefined && !key && !url.startsWith("/auth")) {
    const bytes = new TextEncoder().encode(url + method + JSON.stringify(body));
    const fingerprint = Array.from(
      new Uint8Array(await crypto.subtle.digest("SHA-256", bytes)),
      (b) => b.toString(16).padStart(2, "0"),
    ).join("");
    storageKey = "stockroom-pending-" + fingerprint;
    key = sessionStorage.getItem(storageKey) || crypto.randomUUID();
    sessionStorage.setItem(storageKey, key);
  }
  const res = await fetch("/api" + url, {
    method: body === undefined ? "GET" : method,
    headers: {
      "Content-Type": "application/json",
      "X-Stockroom-Client": "web",
      ...(body === undefined
        ? {}
        : { "Idempotency-Key": key || crypto.randomUUID() }),
    },
    body: body === undefined ? undefined : JSON.stringify(body),
  });
  const data = await res.json();
  if (storageKey && res.status < 500) sessionStorage.removeItem(storageKey);
  if (!res.ok)
    throw Object.assign(new Error(data.error || "Request failed"), {
      status: res.status,
    });
  return data;
}
function Brand({ light = false, small = false }) {
  return (
    <div className={`brand ${light ? "light" : ""} ${small ? "small" : ""}`}>
      <img src="/brand/stockroom-mark.png" alt="Stockroom mark" />
      <div>
        <strong>stock<span className="wordmark-room">room</span></strong>
        <small>BY GLASS HOUSE TECHNOLOGIES</small>
      </div>
    </div>
  );
}
function Button({ children, icon: Icon, variant = "", ...props }) {
  return (
    <button className={`button ${variant}`} {...props}>
      {Icon && <Icon size={17} />} {children}
    </button>
  );
}
function Tag({ children, tone = "" }) {
  return <span className={`tag ${tone}`}>{children}</span>;
}
function Field({ label, name, type = "text", options, children, ...props }) {
  return (
    <label className="field">
      <span>{label}</span>
      {options ? (
        <select aria-label={label} name={name} {...props}>
          {options.map((o) => (
            <option key={o.value ?? o} value={o.value ?? o}>
              {o.label ?? o}
            </option>
          ))}
        </select>
      ) : type === "textarea" ? (
        <textarea aria-label={label} name={name} {...props} />
      ) : (
        <input aria-label={label} name={name} type={type} {...props} />
      )}{" "}
      {children}
    </label>
  );
}
function Empty({
  title = "Nothing here yet",
  text = "Create your first record to get started.",
  action,
}) {
  return (
    <div className="empty">
      <Boxes size={30} />
      <h3>{title}</h3>
      <p>{text}</p>
      {action}
    </div>
  );
}
function Table({ heads, rows, empty, compact = false }) {
  return rows.length ? (
    <div className={`table-wrap ${compact ? "compact" : ""}`}>
      <table>
        <thead>
          <tr>
            {heads.map((h, i) => (
              <th key={i}>{h}</th>
            ))}
          </tr>
        </thead>
        <tbody>
          {rows.map((r, i) => (
            <tr key={i}>
              {r.map((c, j) => (
                <td key={j}>{c}</td>
              ))}
            </tr>
          ))}
        </tbody>
      </table>
    </div>
  ) : (
    <Empty {...empty} />
  );
}
function Modal({ title, subtitle, children, onClose }) {
  const ref = useRef();
  useEffect(() => {
    const previous = document.activeElement;
    ref.current.showModal();
    return () => previous?.focus();
  }, []);
  return (
    <dialog
      ref={ref}
      onCancel={onClose}
      onClick={(e) => {
        if (e.target === e.currentTarget) onClose();
      }}
    >
      <div className="modal-head">
        <div>
          <h2>{title}</h2>
          {subtitle && <p>{subtitle}</p>}
        </div>
        <button
          className="icon-button"
          onClick={onClose}
          aria-label="Close dialog"
        >
          <X />
        </button>
      </div>
      {children}
    </dialog>
  );
}
function MiniChart({ values, large = false }) {
  const max = Math.max(...values, 1);
  return (
    <div
      className={`chart ${large ? "large" : ""}`}
      aria-label="Daily sales quantities"
    >
      <div className="chart-axis">
        <span>{number(max)}</span>
        <span>{number(max / 2)}</span>
        <span>0</span>
      </div>
      <div className="bars">
        {values.map((v, i) => (
          <div
            className="bar-slot"
            key={i}
            title={`${day(i - values.length)}: ${v} units`}
          >
            <div
              style={{ height: `${Math.max(2, (v / max) * 100)}%` }}
              className={i >= values.length - 7 ? "recent" : ""}
            />
          </div>
        ))}
      </div>
    </div>
  );
}
function Auth({ onLogin }) {
  const [sandbox, setSandbox] = useState(false);
  useEffect(() => {
    api("/config")
      .then((c) => setSandbox(c.sandbox))
      .catch(() => {});
  }, []);
  const [mode, setMode] = useState("login"),
    [busy, setBusy] = useState(false),
    [error, setError] = useState(""),
    [recovery, setRecovery] = useState("");
  async function submit(e) {
    e.preventDefault();
    const b = Object.fromEntries(new FormData(e.currentTarget));
    setBusy(true);
    setError("");
    try {
      const r = await api("/auth/" + mode, b);
      if (mode === "recover") {
        setRecovery(r.recovery);
        setMode("recovered");
      } else if (r.recovery) {
        setRecovery(r.recovery);
        setMode("created");
      } else onLogin();
    } catch (e) {
      setError(e.message);
    } finally {
      setBusy(false);
    }
  }
  async function demo(target = 'overview') {
    setBusy(true);
    setError("");
    try {
      await api("/auth/demo", {});
      location.hash = typeof target === 'string' ? target : 'overview';
      onLogin();
    } catch (e) {
      setError(e.message);
    } finally {
      setBusy(false);
    }
  }
  return (
    <>
    {sandbox && <DemoWelcome start={demo} busy={busy} error={error}/>}
    <div className="auth" id="signin">
      <section className="auth-story">
        <Brand light />
        <div className="story-main">
          <div className="eyebrow">EVERY ITEM. EVERY MOVE.</div>
          <h1>
            Inventory.
            <br />
            In your
            <br />
            <em>control.</em>
          </h1>
          <p>
            From the receiving dock to the last shelf.
            <br />
            One clear view of everything that moves.
          </p>
          <div className="identity-emblem"><img src="/brand/stockroom-mark.png" alt="Stockroom's blue and gold inventory mark"/><div><span>ONE CONNECTED OPERATION</span><strong>Receive.<br/>Move.<br/>Account for it.</strong></div></div>
          <div className="identity-flow"><span><ScanLine size={15}/>RECEIVE</span><ArrowRight size={14}/><span><ArrowLeftRight size={15}/>MOVE</span><ArrowRight size={14}/><span><ClipboardCheck size={15}/>VERIFY</span></div>
        </div>
        <div className="auth-foot">
          Built by Glass House Technologies <span>Huntsville, Alabama ↗</span>
        </div>
      </section>
      <section className="auth-form">
        <div className="auth-top">
          <Tag tone="gold">CUSTOMER PREVIEW · v1.0</Tag>
          <a
            href="https://ght.network/business-solutions"
            target="_blank"
            rel="noreferrer"
          >
            Meet GHT <ArrowUpRight size={14} />
          </a>
        </div>
        <div className="auth-form-inner">
          {["created", "recovered"].includes(mode) ? (
            <>
              <ShieldCheck size={36} />
              <h2>Save your recovery code.</h2>
              <p>
                This code can reset your password. Store it securely; it is
                shown only here. No recovery email is sent.
              </p>
              <code className="recovery">{recovery}</code>
              <Button
                onClick={() =>
                  mode === "created" ? onLogin() : setMode("login")
                }
                icon={ArrowRight}
              >
                I saved it · continue
              </Button>
            </>
          ) : (
            <>
              <div className="eyebrow">YOUR OPERATION, IN VIEW</div>
              <h2>
                {mode === "register"
                  ? "Make room for better."
                  : mode === "recover"
                    ? "Recover your account."
                    : "Welcome to Stockroom."}
              </h2>
              <p>
                {mode === "login"
                  ? sandbox
                    ? "Sign in to your workspace or take the full product for a spin."
                    : "Sign in with the account provided by your workspace administrator."
                  : mode === "register"
                    ? "Create a private test workspace filled with fictional grocery inventory."
                    : "Use the recovery code saved when your account was created. An administrator can also provision a replacement account."}
              </p>
              {error && (
                <div role="alert" className="notice error">
                  {error}
                </div>
              )}
              <form onSubmit={submit}>
                {mode === "register" && (
                  <>
                    <Field
                      label="Your name"
                      name="name"
                      autoComplete="name"
                      required
                    />
                    <Field label="Business name" name="business" required />
                  </>
                )}
                <Field
                  label="Email address"
                  name="email"
                  type="email"
                  autoComplete="username"
                  placeholder="you@company.com"
                  required
                />
                {mode === "recover" && (
                  <Field label="Recovery code" name="recovery" required />
                )}
                <Field
                  label={mode === "recover" ? "New password" : "Password"}
                  name="password"
                  type="password"
                  autoComplete={
                    mode === "login" ? "current-password" : "new-password"
                  }
                  minLength={mode === "login" ? 1 : 12}
                  maxLength={128}
                  placeholder={
                    mode === "login"
                      ? "Your password"
                      : "At least 12 characters"
                  }
                  required
                />
                <Button disabled={busy} icon={ArrowRight}>
                  {busy
                    ? "Opening workspace…"
                    : mode === "login"
                      ? "Sign in"
                      : mode === "register"
                        ? "Create test workspace"
                        : "Reset password"}
                </Button>
              </form>
              <div className="auth-links">
                {sandbox && (
                  <button
                    onClick={() => {
                      setMode(mode === "register" ? "login" : "register");
                      setError("");
                    }}
                  >
                    {mode === "register"
                      ? "Already have an account? Sign in"
                      : "Create a test workspace"}
                  </button>
                )}
                <button
                  onClick={() => {
                    setMode(mode === "recover" ? "login" : "recover");
                    setError("");
                  }}
                >
                  {mode === "recover" ? "Back to sign in" : "Forgot password?"}
                </button>
              </div>
              {sandbox && (
                <>
                  <div className="divider">
                    <span>OR EXPLORE FIRST</span>
                  </div>
                  <Button
                    variant="secondary demo-button"
                    onClick={demo}
                    disabled={busy}
                    icon={Boxes}
                  >
                    Open a fresh live demo <ArrowUpRight size={17} />
                  </Button>
                  <p className="fine">
                    No signup required. Your own isolated sample data. Every
                    stock action is real inside your demo. Save an account to
                    return from another device.
                  </p>
                </>
              )}
            </>
          )}
        </div>
        <div className="auth-security">
          <ShieldCheck size={16} />
          Role-based access <span>·</span>Full audit history <span>·</span>Built
          for your infrastructure
        </div>
      </section>
    </div>
    </>
  );
}
function App() {
  const [me, setMe] = useState(null),
    [state, setState] = useState(null),
    [loading, setLoading] = useState(true),
    [page, setPage] = useState(location.hash.slice(1) || "overview"),
    [query, setQuery] = useState(""),
    [menu, setMenu] = useState(false),
    [modal, setModal] = useState(null),
    [toast, setToast] = useState(""),
    [error, setError] = useState(""),
    [online, setOnline] = useState(navigator.onLine),
    [busy, setBusy] = useState(false),
    [locationFilter, setLocationFilter] = useState("all"),
    [category, setCategory] = useState("all"),
    [stockFilter, setStockFilter] = useState("all"),
    [selected, setSelected] = useState(null),
    [scan, setScan] = useState(""),
    [queue, setQueue] = useState([]),
    [orderLines, setOrderLines] = useState([{ product: "", quantity: 12 }]),
    [orderSupplier, setOrderSupplier] = useState(""),
    [saleText, setSaleText] = useState(""),
    [formError, setFormError] = useState(""),
    [secretResult, setSecretResult] = useState("");
  const canManage = me && ["admin", "manager"].includes(me.user.role),
    canOperate = me && me.user.role !== "viewer";
  async function load(initial = false) {
    try {
      const [m, s] = await Promise.all([api("/me"), api("/state")]);
      setMe(m);
      setState(s);
      setError("");
      const q = JSON.parse(
        localStorage.getItem(`stockroom-queue-${m.user.tenant}-${m.user.id}`) ||
          "[]",
      );
      setQueue(q);
    } catch (e) {
      if (e.status === 401) {
        setMe(null);
        setState(null);
      } else setError(e.message);
    } finally {
      if (initial) setLoading(false);
    }
  }
  useEffect(() => {
    load(true);
    const hash = () => {
      setPage(location.hash.slice(1) || "overview");
      setMenu(false);
      setQuery("");
    };
    const network = () => setOnline(navigator.onLine);
    addEventListener("hashchange", hash);
    addEventListener("online", network);
    addEventListener("offline", network);
    const timer = setInterval(() => {
      if (document.visibilityState === "visible" && navigator.onLine) load();
    }, 60000);
    return () => {
      removeEventListener("hashchange", hash);
      removeEventListener("online", network);
      removeEventListener("offline", network);
      clearInterval(timer);
    };
  }, []);
  useEffect(() => {
    if (!toast) return;
    const t = setTimeout(() => setToast(""), 6000);
    return () => clearTimeout(t);
  }, [toast]);
  function go(p) {
    location.hash = p;
    setPage(p);
    setMenu(false);
  }
  function open(type, data) {
    setFormError("");
    setSecretResult("");
    setModal({
      type,
      data:
        type === "count" ? { lots: state.lots.map((l) => ({ ...l })) } : data,
    });
    if (type === "order") {
      setOrderSupplier(String(data?.supplier || state.suppliers[0]?.id || ""));
      setOrderLines(data?.items || [{ product: "", quantity: 12 }]);
    }
  }
  function saveQueue(q) {
    setQueue(q);
    localStorage.setItem(
      `stockroom-queue-${me.user.tenant}-${me.user.id}`,
      JSON.stringify(q),
    );
  }
  async function act(
    url,
    body,
    message = "Saved successfully",
    method = "POST",
  ) {
    setBusy(true);
    setFormError("");
    try {
      const result = await api(url, body, method);
      await load();
      setModal(null);
      setToast(message);
      return result;
    } catch (e) {
      setFormError(e.message);
      setError(e.message);
      return null;
    } finally {
      setBusy(false);
    }
  }
  async function submitForm(e, url, transform = (x) => x, message) {
    e.preventDefault();
    await act(
      url,
      transform(Object.fromEntries(new FormData(e.currentTarget))),
      message,
    );
  }
  if (loading)
    return (
      <div className="boot">
        <Brand />
        <p>Opening your workspace…</p>
      </div>
    );
  if (!me || !state) return <Auth onLogin={() => load()} />;
  const {
    products,
    locations,
    suppliers,
    lots,
    orders,
    orderItems,
    counts,
    movements,
    sales,
    audit,
    users,
  } = state;
  const product = (id) => products.find((p) => p.id === Number(id)) || {},
    loc = (id) => locations.find((l) => l.id === Number(id)) || {},
    supplier = (id) => suppliers.find((s) => s.id === Number(id)) || {};
  const pOptions = products.map((p) => ({
      value: p.id,
      label: `${p.name} · ${p.sku}`,
    })),
    lOptions = locations.map((l) => ({
      value: l.id,
      label: `${l.name} · ${l.site}`,
    })),
    sOptions = suppliers.map((s) => ({ value: s.id, label: s.name }));
  const low = products.filter((p) => p.stock <= p.reorder),
    expiring = lots.filter(
      (l) => l.quantity > 0 && l.expiry && l.expiry <= day(7),
    ),
    pending = counts.filter((c) => c.status === "pending"),
    exceptions = sales.filter((s) => s.status === "exception"),
    openOrders = orders.filter((o) =>
      ["ordered", "partial"].includes(o.status),
    );
  const totalUnits = products.reduce((s, p) => s + p.stock, 0),
    value = products.reduce((s, p) => s + p.stock * p.cost, 0),
    waste = movements
      .filter((m) => m.type === "waste")
      .reduce((s, m) => s - m.quantity * product(m.product).cost, 0);
  const history = Array.from({ length: 28 }, (_, i) =>
    sales
      .filter(
        (s) =>
          s.sold_at.slice(0, 10) === day(i - 28) && s.status !== "exception",
      )
      .reduce((sum, s) => sum + s.quantity, 0),
  );
  const filtered = products.filter(
    (p) =>
      (category === "all" || p.category === category) &&
      (stockFilter === "all" ||
        (stockFilter === "low" && p.stock <= p.reorder)) &&
      [p.name, p.sku, p.barcode, p.category].some((x) =>
        x.toLowerCase().includes(query.toLowerCase()),
      ) &&
      (locationFilter === "all" ||
        lots.some(
          (l) =>
            l.product === p.id &&
            l.location === Number(locationFilter) &&
            l.quantity > 0,
        )),
  );
  const productCell = (p) => (
    <button className="product-link" onClick={() => open("product", p)}>
      <span className={`product-icon ${p.category?.toLowerCase()}`}>
        <Package size={19} />
      </span>
      <span>
        <strong>{p.name}</strong>
        <small>
          {p.sku} · per {p.unit}
        </small>
      </span>
    </button>
  );
  const pageInfo = {
    overview: [
      "A clear view of your operation.",
      "Your stock, your next move, all in one place.",
    ],
    inventory: [
      "Inventory",
      "Every product. Every location. One source of truth.",
    ],
    receive: [
      "Receive & scan",
      "Scan a barcode, check the delivery, and put stock where it belongs.",
    ],
    transfers: [
      "Move stock with confidence.",
      "Transfer between shelves, stockrooms, and stores without losing lot history.",
    ],
    counts: [
      "Make every count count.",
      "Capture a physical count. Review the difference before stock changes.",
    ],
    purchasing: [
      "Stay one order ahead.",
      "Plan replenishment, prepare supplier orders, and track each receipt.",
    ],
    expiry: [
      "Freshness, in focus.",
      "Act on ageing stock and understand the cost of waste.",
    ],
    sales: [
      "Close the loop on every sale.",
      "Import sales, deduct stock, and work through exceptions.",
    ],
    reports: [
      "Turn yesterday into a better tomorrow.",
      "Inventory value, sales trends, and practical replenishment planning.",
    ],
    locations: [
      "A place for everything.",
      "Manage the locations and suppliers behind your operation.",
    ],
    settings: [
      "Your workspace, your way.",
      "Team access, account security, workspace settings, and data exports.",
    ],
    help: [
      "Meet your new Stockroom.",
      "A working guide for your customer test drive.",
    ],
  };
  function makeReorder(p) {
    const inbound = orderItems
      .filter(
        (i) =>
          i.product === p.id && openOrders.some((o) => o.id === i.order_id),
      )
      .reduce((s, i) => s + i.quantity - i.received, 0);
    return Math.max(0, p.target - p.stock - inbound);
  }
  function formFooter(label = "Save changes") {
    return (
      <>
        {formError && (
          <div className="notice error" role="alert">
            {formError}
          </div>
        )}
        <div className="modal-actions">
          <Button
            type="button"
            variant="secondary"
            onClick={() => setModal(null)}
          >
            Cancel
          </Button>
          <Button disabled={busy || !online} icon={Check}>
            {busy ? "Saving…" : label}
          </Button>
        </div>
      </>
    );
  }
  function lotOptions() {
    return lots
      .filter((l) => l.quantity > 0)
      .map((l) => ({
        value: l.id,
        label: `${product(l.product).name} · ${loc(l.location).name} · ${l.code} · ${l.quantity} available`,
      }));
  }
  return (
    <div className="app">
      <aside className={menu ? "sidebar open" : "sidebar"}>
        <Brand light small />
        <button className="icon-button sidebar-close" aria-label="Close navigation" onClick={()=>setMenu(false)}><X size={20}/></button>
        <button className="workspace-button" onClick={() => go("settings")}>
          <span className="workspace-initial">
            {me.workspace.name === "Oak & Field Market"
              ? "O&F"
              : me.workspace.name
                  .split(" ")
                  .map((n) => n[0])
                  .slice(0, 3)
                  .join("")}
          </span>
          <span>
            <strong>{me.workspace.name}</strong>
            <small>
              {me.workspace.demo
                ? "Customer test workspace"
                : "Business workspace"}
            </small>
          </span>
          <ChevronDown size={15} />
        </button>
        <div className="nav-label">WORKSPACE</div>
        <nav>
          {nav.map(([key, label, Icon], i) => (
            <React.Fragment key={key}>
              {i === 7 && (
                <div className="nav-label second">INSIGHTS & OPERATIONS</div>
              )}
              <button
                className={page === key ? "active" : ""}
                onClick={() => go(key)}
              >
                <Icon size={18} />
                <span>{label}</span>
                {key === "counts" && pending.length > 0 && (
                  <b>{pending.length}</b>
                )}
                {key === "expiry" && expiring.length > 0 && <i />}
              </button>
            </React.Fragment>
          ))}
        </nav>
        <div className="sidebar-bottom">
          <button
            onClick={() => go("help")}
            className={page === "help" ? "active" : ""}
          >
            <HelpCircle size={18} />
            Demo guide
            <ArrowUpRight size={15} />
          </button>
          <button
            onClick={() => go("settings")}
            className={page === "settings" ? "active" : ""}
          >
            <Settings size={18} />
            Settings
          </button>
          <div className="profile">
            <span className="avatar">
              {me.user.name
                .split(" ")
                .map((n) => n[0])
                .slice(0, 2)
                .join("")}
            </span>
            <span>
              <strong>{me.user.name}</strong>
              <small>{me.user.role} access</small>
            </span>
            <button
              aria-label="Sign out"
              className="icon-button"
              onClick={async () => {
                try {
                  await api("/auth/logout", {});
                  setMe(null);
                  setState(null);
                } catch (e) {
                  setError(e.message);
                }
              }}
            >
              <LogOut size={17} />
            </button>
          </div>
        </div>
      </aside>
      {menu && (
        <button
          className="scrim"
          aria-label="Dismiss navigation backdrop"
          onClick={() => setMenu(false)}
        />
      )}
      <div className="main">
        <header className="topbar">
          <div className="breadcrumb">
            <button
              className="icon-button mobile-menu"
              aria-label="Open navigation"
              onClick={() => setMenu(true)}
            >
              <Menu />
            </button>
            <span>Workspace</span>
            <ChevronRight size={14} />
            <strong>{nav.find((n) => n[0] === page)?.[1] || page}</strong>
          </div>
          <div className="top-actions">
            <span className="connection">
              <i className={online ? "" : "offline"} />
              {online ? "Connected" : "Offline"}
            </span>
            <button
              className="icon-button"
              aria-label="View alerts"
              onClick={() => open("alerts")}
            >
              <Bell size={19} />
              <i className="notification-dot" />
            </button>
            <span className="avatar top-avatar">{me.user.name[0]}</span>
          </div>
        </header>
        {me.workspace.demo === 1 && (
          <div className="demo-strip">
            <span>
              <Sprout size={15} />
              <strong>Your own test workspace.</strong> Explore freely — all
              records are fictional.
            </span>
            <button onClick={() => go("help")}>
              Take the guided tour <ArrowRight size={14} />
            </button>
          </div>
        )}
        <main>
          <div className="page-header">
            <div>
              <div className="eyebrow">
                {page === "overview"
                  ? `${new Date().toLocaleDateString("en-US", { weekday: "long", month: "long", day: "numeric" })} / OVERVIEW`
                  : "STOCKROOM / " +
                    (nav.find((n) => n[0] === page)?.[1] || page).toUpperCase()}
              </div>
              <h1>{(pageInfo[page] || pageInfo.overview)[0]}</h1>
              <p>{(pageInfo[page] || pageInfo.overview)[1]}</p>
            </div>
            <div className="header-buttons">
              <Button
                variant="secondary"
                icon={RefreshCw}
                onClick={() => load()}
              >
                Refresh
              </Button>
              {canOperate && page !== "receive" && (
                <Button icon={ScanLine} onClick={() => go("receive")}>
                  Receive stock
                </Button>
              )}
            </div>
          </div>
          {!online && (
            <div className="notice warning">
              <WifiOff size={18} />
              You’re offline. Stock views may be out of date. Receipts can be
              saved as drafts below; other changes need a connection.
            </div>
          )}
          {me.workspace.demo === 1 && <DemoHint page={page} go={go}/>}
          {error && (
            <div className="notice error" role="alert">
              <CircleAlert size={18} />
              {error}
              <button aria-label="Dismiss error" onClick={() => setError("")}>
                <X size={16} />
              </button>
            </div>
          )}
          {queue.length > 0 && (
            <div className="notice warning">
              <ScanLine size={18} />
              {queue.length} receipt draft{queue.length > 1 ? "s" : ""} waiting
              to be synced.
              <Button variant="text" onClick={() => go("receive")}>
                Review drafts
              </Button>
            </div>
          )}
          {page === "overview" && (
            <>
              <section className="metrics">
                <Metric
                  label="Inventory value"
                  value={money(value)}
                  icon={Boxes}
                  note="At current product cost"
                />
                <Metric
                  label="Units on hand"
                  value={number(totalUnits)}
                  icon={Package}
                  note={`${products.length} products across ${locations.length} locations`}
                />
                <Metric
                  label="Need replenishment"
                  value={low.length}
                  icon={ShoppingCart}
                  note="Products at or below reorder point"
                  onClick={() => {
                    setStockFilter("low");
                    go("inventory");
                  }}
                  accent
                />
                <Metric
                  label="Expiring within 7 days"
                  value={expiring.length}
                  icon={CalendarClock}
                  note="Lots to review for rotation"
                  onClick={() => go("expiry")}
                />
              </section>
              <div className="overview-grid">
                <section className="panel sales-panel">
                  <div className="panel-head">
                    <div>
                      <div className="eyebrow">
                        A LITTLE FORESIGHT GOES A LONG WAY
                      </div>
                      <h2>Know the rhythm of your store.</h2>
                      <p>Sales volume · last 28 complete days</p>
                    </div>
                    <Tag>Units sold</Tag>
                  </div>
                  <div className="chart-total">
                    {number(history.reduce((s, v) => s + v, 0))}
                    <span>units recorded</span>
                    <span className="chart-note">
                      <i />
                      Fictional sales history
                    </span>
                  </div>
                  <MiniChart values={history} />
                  <div className="chart-dates">
                    <span>{dateLabel(day(-28))}</span>
                    <span>{dateLabel(day(-21))}</span>
                    <span>{dateLabel(day(-14))}</span>
                    <span>{dateLabel(day(-7))}</span>
                    <span>{dateLabel(day(-1))}</span>
                  </div>
                  <div className="panel-footer">
                    <span>Decisions grounded in your sales history.</span>
                    <button onClick={() => go("reports")}>
                      Explore planning <ArrowUpRight size={16} />
                    </button>
                  </div>
                </section>
                <section className="attention">
                  <div className="eyebrow">YOUR NEXT BEST MOVES</div>
                  <h2>
                    A little attention.
                    <br />A smoother day.
                  </h2>
                  <button onClick={() => go("purchasing")}>
                    <span className="attention-icon">
                      <ShoppingCart size={20} />
                    </span>
                    <span>
                      <strong>{low.length} products running low</strong>
                      <small>Review replenishment suggestions</small>
                    </span>
                    <ArrowUpRight size={18} />
                  </button>
                  <button onClick={() => go("expiry")}>
                    <span className="attention-icon">
                      <CalendarClock size={20} />
                    </span>
                    <span>
                      <strong>{expiring.length} lots approaching expiry</strong>
                      <small>Rotate, transfer, or record waste</small>
                    </span>
                    <ArrowUpRight size={18} />
                  </button>
                  <button onClick={() => go("counts")}>
                    <span className="attention-icon">
                      <ClipboardCheck size={20} />
                    </span>
                    <span>
                      <strong>
                        {pending.length} count{pending.length !== 1 ? "s" : ""}{" "}
                        awaiting review
                      </strong>
                      <small>Resolve inventory differences</small>
                    </span>
                    <ArrowUpRight size={18} />
                  </button>
                  <div className="attention-bottom">
                    <ShieldCheck size={18} />
                    Every adjustment leaves a trail.
                  </div>
                </section>
              </div>
              <section className="panel">
                <div className="panel-head">
                  <div>
                    <h2>Keep the shelves ready.</h2>
                    <p>Replenishment priorities across your locations</p>
                  </div>
                  <button className="text-link" onClick={() => go("inventory")}>
                    All inventory <ArrowUpRight size={16} />
                  </button>
                </div>
                <Table
                  heads={[
                    "PRODUCT",
                    "ON HAND",
                    "REORDER POINT",
                    "STATUS",
                    "NEXT MOVE",
                  ]}
                  rows={low.slice(0, 5).map((p) => [
                    productCell(p),
                    <strong>
                      {p.stock} <small>{p.unit}s</small>
                    </strong>,
                    p.reorder,
                    <Tag tone="amber">Low stock</Tag>,
                    <button
                      className="text-link"
                      disabled={!canManage}
                      onClick={() =>
                        open("order", {
                          supplier: p.supplier,
                          items: [
                            {
                              product: p.id,
                              quantity: Math.max(1, makeReorder(p)),
                            },
                          ],
                        })
                      }
                    >
                      Draft order <ArrowUpRight size={15} />
                    </button>,
                  ])}
                />
              </section>
              <div className="two-col">
                <section className="panel">
                  <div className="panel-head">
                    <h2>On the way</h2>
                    <Tag>{openOrders.length} open orders</Tag>
                  </div>
                  {openOrders.slice(0, 3).map((o) => (
                    <button
                      key={o.id}
                      className="list-row"
                      onClick={() => open("order-detail", o)}
                    >
                      <span className="row-icon">
                        <Truck size={20} />
                      </span>
                      <span>
                        <strong>{supplier(o.supplier).name}</strong>
                        <small>
                          PO-{o.id} · Expected {dateLabel(o.expected)}
                        </small>
                      </span>
                      <Tag>{o.status}</Tag>
                      <ChevronRight size={16} />
                    </button>
                  ))}
                </section>
                <section className="panel">
                  <div className="panel-head">
                    <h2>Latest activity</h2>
                    <History size={18} />
                  </div>
                  {audit.slice(0, 3).map((a) => (
                    <div className="list-row" key={a.id}>
                      <span className="activity-dot" />
                      <span>
                        <strong>{a.action}</strong>
                        <small>
                          {a.actor} · {a.detail}
                        </small>
                      </span>
                    </div>
                  ))}
                </section>
              </div>
            </>
          )}
          {page === "inventory" && (
            <section className="panel">
              <div className="filterbar">
                <div className="search-field">
                  <Search size={18} />
                  <input
                    aria-label="Search inventory"
                    placeholder="Search products, SKU, or scan barcode…"
                    value={query}
                    onChange={(e) => setQuery(e.target.value)}
                  />
                </div>
                <select
                  aria-label="Category"
                  value={category}
                  onChange={(e) => setCategory(e.target.value)}
                >
                  <option value="all">All categories</option>
                  {[...new Set(products.map((p) => p.category))].map((c) => (
                    <option key={c}>{c}</option>
                  ))}
                </select>
                <select
                  aria-label="Location filter"
                  value={locationFilter}
                  onChange={(e) => setLocationFilter(e.target.value)}
                >
                  <option value="all">All locations</option>
                  {lOptions.map((o) => (
                    <option key={o.value} value={o.value}>
                      {o.label}
                    </option>
                  ))}
                </select>
                <select
                  aria-label="Stock status"
                  value={stockFilter}
                  onChange={(e) => setStockFilter(e.target.value)}
                >
                  <option value="all">All stock</option>
                  <option value="low">Low stock</option>
                </select>
                {canManage && (
                  <Button icon={Plus} onClick={() => open("new-product")}>
                    Add product
                  </Button>
                )}
              </div>
              <Table
                heads={[
                  "PRODUCT",
                  "CATEGORY",
                  "ON HAND",
                  "COST / UNIT",
                  "STOCK HEALTH",
                  "SUPPLIER",
                  "",
                ]}
                rows={filtered.map((p) => [
                  productCell(p),
                  p.category,
                  <strong>
                    {locationFilter === "all"
                      ? p.stock
                      : lots
                          .filter(
                            (l) =>
                              l.product === p.id &&
                              l.location === Number(locationFilter),
                          )
                          .reduce((s, l) => s + l.quantity, 0)}{" "}
                    <small>{p.unit}s</small>
                  </strong>,
                      money(p.cost, true),
                  <Tag tone={p.stock <= p.reorder ? "amber" : ""}>
                    {p.stock <= p.reorder ? "Reorder soon" : "In stock"}
                  </Tag>,
                  p.supplier_name,
                  <button
                    className="icon-button"
                    aria-label={`View ${p.name}`}
                    onClick={() => open("product", p)}
                  >
                    <ChevronRight size={18} />
                  </button>,
                ])}
                empty={{
                  title: "No matching products",
                  text: "Try another search, location, or category.",
                }}
              />
              <div className="panel-footer">
                <span>
                  {filtered.length} of {products.length} products · quantities
                  use the unit shown for each product
                </span>
                <button
                  onClick={() =>
                    downloadCSV(
                      "inventory.csv",
                      [
                        "SKU",
                        "Product",
                        "Category",
                        "Unit",
                        "On hand",
                        "Cost cents",
                        "Reorder",
                      ],
                      filtered.map((p) => [
                        p.sku,
                        p.name,
                        p.category,
                        p.unit,
                        p.stock,
                        p.cost,
                        p.reorder,
                      ]),
                    )
                  }
                >
                  <Download size={15} />
                  Export CSV
                </button>
              </div>
            </section>
          )}
          {page === "receive" && (
            <>
            {me.workspace.demo === 1 && <DemoShelf products={products} select={p=>{setSelected(p.id);setScan(p.barcode);setError('');setToast(`${p.name} found · simulated scan`);document.querySelector('.scan-box')?.scrollIntoView({behavior:'smooth',block:'center'});}} onError={setError}/>}
            <div className="receive-grid">
              <section className="panel receive-panel">
                <div className="panel-head">
                  <div>
                    <h2>One scan. Stock received.</h2>
                    <p>Use a handheld scanner or enter a SKU / barcode.</p>
                  </div>
                  <ScanLine size={25} />
                </div>
                <form
                  className="scan-box"
                  onSubmit={(e) => {
                    e.preventDefault();
                    const p = products.find(
                      (p) =>
                        p.barcode === scan.trim() ||
                        p.sku.toLowerCase() === scan.trim().toLowerCase(),
                    );
                    if (p) {
                      setSelected(p.id);
                      setError("");
                      setToast(`${p.name} found`);
                    } else {
                      setSelected(null);
                      setError(
                        "Barcode not found. Check the code or ask a manager to add the product.",
                      );
                    }
                  }}
                >
                  <ScanLine size={24} />
                  <input
                    aria-label="Scan barcode"
                    autoFocus
                    value={scan}
                    onChange={(e) => setScan(e.target.value)}
                    placeholder="Scan a barcode or enter SKU"
                  />
                  <Button variant="secondary">Find</Button>
                </form>
                <form
                  className="form-body"
                  onSubmit={async (e) => {
                    e.preventDefault();
                    const b = Object.fromEntries(new FormData(e.currentTarget));
                    const id = crypto.randomUUID();
                    if (!online) {
                      saveQueue([
                        ...queue,
                        { id, body: b, created: new Date().toISOString() },
                      ]);
                      setToast(
                        "Receipt saved as an offline draft. Stock has not changed.",
                      );
                      return;
                    }
                    const result = await act(
                      "/receive",
                      b,
                      "Stock received. Inventory and movement history updated.",
                    );
                    if (result) {
                      setScan("");
                    }
                  }}
                >
                  <div className="form-grid">
                    <Field
                      label="Product"
                      name="product"
                      options={[
                        { value: "", label: "Select a product" },
                        ...pOptions,
                      ]}
                      value={selected || ""}
                      onChange={(e) => setSelected(Number(e.target.value))}
                      required
                    />
                    <Field
                      label="Receive into"
                      name="location"
                      options={lOptions}
                      required
                    />
                    <Field
                      label="Quantity (product units)"
                      name="quantity"
                      type="number"
                      min="1"
                      max="1000000"
                      defaultValue="12"
                      required
                    />
                    <Field
                      label="Lot / batch code"
                      name="code"
                      placeholder="e.g. VF-SEP-204"
                      defaultValue={me.workspace.demo === 1 ? `DEMO-${today()}` : ''}
                      required
                      maxLength={80}
                    />
                    <Field
                      label="Expiry date (optional)"
                      name="expiry"
                      type="date"
                      min={today()}
                    />
                    <Field
                      label="Delivery reference"
                      name="reference"
                      placeholder="Packing slip or delivery number"
                      defaultValue={me.workspace.demo === 1 ? `PRACTICE-${today()}` : ''}
                      required
                      maxLength={80}
                    />
                    <Field
                      label="Purchase order line (optional)"
                      name="order_item"
                      options={[
                        { value: "", label: "Unplanned delivery" },
                        ...orderItems
                          .filter(
                            (i) =>
                              i.product === Number(selected) &&
                              i.received < i.quantity &&
                              openOrders.some((o) => o.id === i.order_id),
                          )
                          .map((i) => ({
                            value: i.id,
                            label: `PO-${i.order_id} · ${i.quantity - i.received} remaining`,
                          })),
                      ]}
                    />
                    <Field
                      label="Delivery note (optional)"
                      name="note"
                      placeholder="Condition, temperature, or exceptions"
                      maxLength={500}
                    />
                  </div>
                  <div className="notice subtle">
                    <ShieldCheck size={18} />
                    Each receipt records who received it, where it went, and its
                    lot history. Duplicate request retries are safe.
                  </div>
                  <Button
                    disabled={busy || !canOperate}
                    icon={online ? Check : Download}
                  >
                    {busy
                      ? "Receiving…"
                      : online
                        ? "Confirm receipt"
                        : "Save offline receipt draft"}
                  </Button>
                  {!canOperate && (
                    <p className="fine">
                      Viewer access: ask a manager for stock operation
                      permissions.
                    </p>
                  )}
                </form>
              </section>
              <div>
                <section className="scan-guide">
                  <div className="eyebrow">TRY YOUR FIRST SCAN</div>
                  <h2>Meet Honeycrisp.</h2>
                  <p>A sample product, ready to receive.</p>
                  <div className="sample-product">
                    <Leaf size={44} />
                    <strong>Honeycrisp apples</strong>
                    <span>Produce · case</span>
                    <Barcode value="200000001001" />
                    <code>200000001001</code>
                  </div>
                  <Button
                    variant="secondary"
                    disabled={!products.some(p=>p.sku==='SR-1001')}
                    onClick={() => {
                      setScan("200000001001");
                      setSelected(
                        products.find((p) => p.sku === "SR-1001")?.id,
                      );
                    }}
                  >
                    Use this sample barcode <ArrowRight size={16} />
                  </Button>
                  <p className="fine">
                    This is a real Code 128 sample barcode. Print a practice
                    label above, or simulate a scan without any hardware.
                  </p>
                </section>
                <section className="panel compact-info">
                  <h3>Handheld ready</h3>
                  <p>
                    Zebra DataWedge keyboard output can enter the barcode and
                    append Enter. Keep the scan field focused.
                  </p>
                  <button className="text-link" onClick={() => go("help")}>
                    Device setup notes <ArrowUpRight size={15} />
                  </button>
                </section>
              </div>
              {queue.length > 0 && (
                <section className="panel full-width">
                  <div className="panel-head">
                    <h2>Offline receipt drafts</h2>
                    <Tag tone="amber">Stock not yet updated</Tag>
                  </div>
                  {queue.map((q) => (
                    <div className="list-row" key={q.id}>
                      <span>
                        <strong>
                          {product(q.body.product).name} · {q.body.quantity}{" "}
                          units
                        </strong>
                        <small>
                          {q.body.code} · {q.body.reference}
                        </small>
                      </span>
                      <Button
                        disabled={!online || busy}
                        onClick={async () => {
                          setBusy(true);
                          try {
                            await api("/receive", q.body, "POST", q.id);
                            saveQueue(queue.filter((x) => x.id !== q.id));
                            await load();
                            setToast("Draft received and synced once.");
                          } catch (e) {
                            setError(e.message);
                          } finally {
                            setBusy(false);
                          }
                        }}
                      >
                        Sync receipt
                      </Button>
                      <Button
                        variant="secondary"
                        onClick={() => open("discard-draft", q)}
                      >
                        Discard
                      </Button>
                    </div>
                  ))}
                </section>
              )}
            </div>
            </>
          )}
          {page === "transfers" && (
            <>
              <div className="action-banner">
                <div>
                  <ArrowLeftRight size={26} />
                  <span>
                    <h2>Right stock. Right place.</h2>
                    <p>
                      Transfers preserve lot codes and expiry dates, with linked
                      entries at both locations.
                    </p>
                  </span>
                </div>
                {canOperate && (
                  <Button icon={Plus} onClick={() => open("transfer")}>
                    New transfer
                  </Button>
                )}
              </div>
              <section className="panel">
                <div className="panel-head">
                  <h2>Transfer history</h2>
                  <Tag>Across all locations</Tag>
                </div>
                <Table
                  heads={[
                    "PRODUCT",
                    "MOVEMENT",
                    "LOCATION",
                    "QUANTITY",
                    "REFERENCE",
                    "BY",
                  ]}
                  rows={movements
                    .filter((m) => m.type.startsWith("transfer"))
                    .map((m) => [
                      productCell(product(m.product)),
                      <Tag>
                        {m.type === "transfer-in" ? "Received" : "Sent"}
                      </Tag>,
                      loc(m.location).name,
                      <strong>
                        {m.quantity > 0 ? "+" : ""}
                        {m.quantity}
                      </strong>,
                      m.reference,
                      m.actor,
                    ])}
                  empty={{
                    title: "Your first move starts here",
                    text: "Move stock between locations; both sides appear in this history.",
                    action: canOperate && (
                      <Button onClick={() => open("transfer")}>
                        Transfer stock
                      </Button>
                    ),
                  }}
                />
              </section>
            </>
          )}
          {page === "counts" && (
            <>
              <div className="action-banner">
                <div>
                  <ClipboardCheck size={26} />
                  <span>
                    <h2>A second look, before stock changes.</h2>
                    <p>
                      Operators submit counts. Managers review variances.
                      Changed stock requires a fresh count.
                    </p>
                  </span>
                </div>
                {canOperate && (
                  <Button icon={Plus} onClick={() => open("count")}>
                    Start a count
                  </Button>
                )}
              </div>
              <section className="panel">
                <div className="panel-head">
                  <h2>Count review</h2>
                  <Tag tone="amber">{pending.length} awaiting review</Tag>
                </div>
                <Table
                  heads={[
                    "PRODUCT / LOT",
                    "LOCATION",
                    "EXPECTED",
                    "COUNTED",
                    "VARIANCE",
                    "STATUS",
                    "REVIEW",
                  ]}
                  rows={counts.map((c) => {
                    const l = lots.find((l) => l.id === c.lot) || {};
                    return [
                      <div>
                        <strong>{product(l.product).name}</strong>
                        <small>
                          {l.code} · {c.actor}
                        </small>
                      </div>,
                      loc(l.location).name,
                      c.expected,
                      c.counted,
                      <strong
                        className={c.counted !== c.expected ? "text-amber" : ""}
                      >
                        {c.counted - c.expected > 0 ? "+" : ""}
                        {c.counted - c.expected}
                      </strong>,
                      <Tag tone={c.status === "pending" ? "amber" : ""}>
                        {c.status}
                      </Tag>,
                      c.status === "pending" && canManage ? (
                        <div className="inline-actions">
                          <Button
                            variant="secondary"
                            onClick={() =>
                              open("count-review", { ...c, action: "reject" })
                            }
                          >
                            Reject
                          </Button>
                          <Button
                            onClick={() =>
                              open("count-review", { ...c, action: "approve" })
                            }
                          >
                            Review
                          </Button>
                        </div>
                      ) : (
                        <span className="muted">{c.note}</span>
                      ),
                    ];
                  })}
                />
              </section>
            </>
          )}
          {page === "purchasing" && (
            <>
              <section className="panel">
                <div className="panel-head">
                  <div>
                    <h2>Suggested replenishment</h2>
                    <p>
                      Target stock minus on-hand and outstanding supplier
                      orders. Review before ordering.
                    </p>
                  </div>
                  {canManage && (
                    <Button icon={Plus} onClick={() => open("order")}>
                      New purchase order
                    </Button>
                  )}
                </div>
                <Table
                  heads={[
                    "PRODUCT",
                    "ON HAND",
                    "INBOUND",
                    "SUGGESTED",
                    "SUPPLIER",
                    "",
                  ]}
                  rows={low.map((p) => [
                    productCell(p),
                    p.stock,
                    orderItems
                      .filter(
                        (i) =>
                          i.product === p.id &&
                          openOrders.some((o) => o.id === i.order_id),
                      )
                      .reduce((s, i) => s + i.quantity - i.received, 0),
                    <strong>
                      {makeReorder(p)} {p.unit}s
                    </strong>,
                    p.supplier_name,
                    canManage && (
                      <Button
                        variant="secondary"
                        disabled={!makeReorder(p)}
                        onClick={() =>
                          open("order", {
                            supplier: p.supplier,
                            items: [
                              { product: p.id, quantity: makeReorder(p) },
                            ],
                          })
                        }
                      >
                        Draft order
                      </Button>
                    ),
                  ])}
                />
              </section>
              <section className="panel">
                <div className="panel-head">
                  <h2>Purchase orders</h2>
                  <Tag>{orders.length} orders</Tag>
                </div>
                <Table
                  heads={[
                    "ORDER",
                    "SUPPLIER",
                    "EXPECTED",
                    "STATUS",
                    "TOTAL",
                    "",
                  ]}
                  rows={orders.map((o) => [
                    <strong>PO-{o.id}</strong>,
                    supplier(o.supplier).name,
                    dateLabel(o.expected),
                    <Tag tone={o.status === "draft" ? "amber" : ""}>
                      {o.status}
                    </Tag>,
                    money(
                      orderItems
                        .filter((i) => i.order_id === o.id)
                        .reduce((s, i) => s + i.quantity * i.cost, 0),
                    ),
                    <button
                      className="text-link"
                      onClick={() => open("order-detail", o)}
                    >
                      View order <ArrowUpRight size={15} />
                    </button>,
                  ])}
                />
              </section>
            </>
          )}
          {page === "expiry" && (
            <>
              <section className="metrics three">
                <Metric
                  label="Lots needing attention"
                  value={expiring.length}
                  icon={CalendarClock}
                  note="Expires within 7 days or already expired"
                />
                <Metric
                  label="Stock value at risk"
                  value={money(
                    expiring.reduce(
                      (s, l) => s + l.quantity * product(l.product).cost,
                      0,
                    ),
                  )}
                  icon={Package}
                  note="Current cost of flagged lots"
                  accent
                />
                <Metric
                  label="Waste recorded"
                  value={money(waste)}
                  icon={Leaf}
                  note="All recorded waste at current product cost"
                />
              </section>
              <section className="panel">
                <div className="panel-head">
                  <div>
                    <h2>Rotate first. Waste less.</h2>
                    <p>
                      Lots sorted by expiry. Expired lots are excluded from
                      sales reconciliation.
                    </p>
                  </div>
                  <Tag>Next 7 days</Tag>
                </div>
                <Table
                  heads={[
                    "PRODUCT",
                    "LOT",
                    "LOCATION",
                    "EXPIRES",
                    "QUANTITY",
                    "ACTION",
                  ]}
                  rows={expiring.map((l) => [
                    productCell(product(l.product)),
                    l.code,
                    loc(l.location).name,
                    <Tag tone={l.expiry < today() ? "red" : "amber"}>
                      {l.expiry < today() ? "Expired · " : ""}
                      {dateLabel(l.expiry)}
                    </Tag>,
                    l.quantity,
                    <div className="inline-actions">
                      {canOperate && (
                        <Button
                          variant="secondary"
                          onClick={() => open("transfer", l)}
                        >
                          Transfer
                        </Button>
                      )}
                      {canManage && (
                        <Button variant="text" onClick={() => open("waste", l)}>
                          Record waste
                        </Button>
                      )}
                    </div>,
                  ])}
                  empty={{
                    title: "Freshness looks good",
                    text: "No stocked lots expire within the next seven days.",
                  }}
                />
              </section>
              <section className="panel">
                <div className="panel-head">
                  <h2>Waste history</h2>
                </div>
                <Table
                  heads={["PRODUCT", "UNITS", "REASON", "BY"]}
                  rows={movements
                    .filter((m) => m.type === "waste")
                    .map((m) => [
                      product(m.product).name,
                      -m.quantity,
                      m.note,
                      m.actor,
                    ])}
                  empty={{
                    title: "No waste recorded",
                    text: "When a manager records spoilage or damage, the reason and quantity appear here.",
                  }}
                />
              </section>
            </>
          )}
          {page === "sales" && (
            <>
              <div className="notice subtle">
                <FileUp size={20} />
                <span>
                  <strong>File-based POS import is ready.</strong>{" "}
                  Vendor-specific live connectors are not connected. Imports use
                  your location IDs and deduct the earliest unexpired lots
                  first.
                </span>
              </div>
              <div className="two-col">
                <section className="panel">
                  <div className="panel-head">
                    <div>
                      <h2>Bring in sales</h2>
                      <p>
                        CSV columns: external_id, sku, location, quantity,
                        revenue, date. Revenue is in cents.
                      </p>
                    </div>
                  </div>
                  <div className="form-body">
                    <label className="file-input">
                      Choose sales CSV
                      <input
                        aria-label="Upload sales CSV"
                        type="file"
                        accept=".csv,text/csv"
                        disabled={!canManage}
                        onChange={async (e) => {
                          const file = e.target.files[0];
                          if (file) {
                            if (file.size > 900000) {
                              setError("Choose a CSV smaller than 900 KB.");
                              return;
                            }
                            setSaleText(await file.text());
                          }
                        }}
                      />
                    </label>
                    <textarea
                      aria-label="Sales CSV data"
                      className="csv-input"
                      placeholder="external_id,sku,location,quantity,revenue,date"
                      value={saleText}
                      onChange={(e) => setSaleText(e.target.value)}
                    />
                    <div className="inline-actions">
                      <Button
                        disabled={!canManage || !online || !saleText}
                        icon={Eye}
                        onClick={() => {
                          try {
                            const rows = parseCSV(saleText);
                            open("sales-preview", rows);
                          } catch (e) {
                            setError(e.message);
                          }
                        }}
                      >
                        Review import
                      </Button>
                      <Button
                        variant="secondary"
                        onClick={() => {
                          const p = products.find(p=>lots.some(l=>l.product===p.id&&l.quantity>0)),
                            l = lots.find(
                              (l) => l.product === p?.id && l.quantity > 0,
                            );
                          if(!p||!l){setError('Add a product and receive stock before loading a sample sale.');return;}
                          setSaleText(
                            `external_id,sku,location,quantity,revenue,date\nDEMO-${Date.now()},${p.sku},${l.location},1,${p.price},${today()}`,
                          );
                        }}
                      >
                        Use sample sale
                      </Button>
                    </div>
                    <p className="fine">
                      Duplicate references with identical values are skipped.
                      Conflicting duplicates and unknown SKUs reject the whole
                      batch.
                    </p>
                  </div>
                </section>
                <section className="panel">
                  <div className="panel-head">
                    <h2>Reconciliation exceptions</h2>
                    <Tag tone="amber">{exceptions.length} to resolve</Tag>
                  </div>
                  {exceptions.length ? (
                    exceptions.map((s) => (
                      <div className="exception" key={s.id}>
                        <strong>
                          {s.external_id} · {product(s.product).name}
                        </strong>
                        <p>{s.error}</p>
                        <small>
                          {s.quantity} units · {loc(s.location).name}
                        </small>
                        <Button
                          disabled={!canManage}
                          onClick={() =>
                            act(
                              `/sales/${s.id}/retry`,
                              {},
                              "Sale reconciled and stock deducted.",
                            )
                          }
                        >
                          Retry reconciliation
                        </Button>
                      </div>
                    ))
                  ) : (
                    <Empty
                      title="All caught up"
                      text="Sales that cannot be fulfilled appear here without creating negative stock."
                    />
                  )}
                </section>
              </div>
              <section className="panel">
                <div className="panel-head">
                  <h2>Recent sales</h2>
                  <Tag>Latest 50</Tag>
                </div>
                <Table
                  heads={[
                    "REFERENCE",
                    "PRODUCT",
                    "DATE",
                    "QUANTITY",
                    "SALES",
                    "STATUS",
                  ]}
                  rows={sales
                    .slice(0, 50)
                    .map((s) => [
                      s.external_id,
                      product(s.product).name,
                      dateLabel(s.sold_at.slice(0, 10)),
                      s.quantity,
                      money(s.revenue, true),
                      <Tag tone={s.status === "exception" ? "amber" : ""}>
                        {s.status === "historical"
                          ? "Sample history"
                          : s.status}
                      </Tag>,
                    ])}
                />
              </section>
            </>
          )}
          {page === "reports" && (
            <>
              <div className="demo-report-grid">
                <section className="panel"><div className="panel-head"><div><h2>Stock by category</h2><p>Current quantities and inventory value at cost.</p></div><Button variant="secondary" icon={Download} onClick={()=>downloadCSV('stock-by-category.csv',['Category','Units','Value in cents'],[...new Set(products.map(p=>p.category))].map(c=>[c,products.filter(p=>p.category===c).reduce((n,p)=>n+p.stock,0),products.filter(p=>p.category===c).reduce((n,p)=>n+p.stock*p.cost,0)]))}>Export category report</Button></div><Table heads={['CATEGORY','UNITS','VALUE']} rows={[...new Set(products.map(p=>p.category))].map(c=>[c,number(products.filter(p=>p.category===c).reduce((n,p)=>n+p.stock,0)),money(products.filter(p=>p.category===c).reduce((n,p)=>n+p.stock*p.cost,0))])}/></section>
                <section className="panel"><div className="panel-head"><div><h2>Stock by location</h2><p>See where your stock and its value are held.</p></div><Button variant="secondary" icon={Download} onClick={()=>downloadCSV('stock-by-location.csv',['Location','Units','Value in cents'],locations.map(l=>[l.name,lots.filter(x=>x.location===l.id).reduce((n,x)=>n+x.quantity,0),lots.filter(x=>x.location===l.id).reduce((n,x)=>n+x.quantity*product(x.product).cost,0)]))}>Export location report</Button></div><Table heads={['LOCATION','UNITS','VALUE']} rows={locations.map(l=>[l.name,number(lots.filter(x=>x.location===l.id).reduce((n,x)=>n+x.quantity,0)),money(lots.filter(x=>x.location===l.id).reduce((n,x)=>n+x.quantity*product(x.product).cost,0))])}/></section>
              </div>
              <section className="metrics three">
                <Metric
                  label="Inventory value"
                  value={money(value)}
                  icon={Boxes}
                  note="On hand × current product cost"
                />
                <Metric
                  label="28-day recorded sales"
                  value={money(
                    sales
                      .filter(
                        (s) =>
                          s.status !== "exception" && s.sold_at >= day(-28),
                      )
                      .reduce((s, r) => s + r.revenue, 0),
                  )}
                  icon={ChartNoAxesCombined}
                  note="Includes fictional sample history"
                />
                <Metric
                  label="Waste recorded"
                  value={money(waste)}
                  icon={Leaf}
                  note="At current product cost"
                />
              </section>
              <section className="panel">
                <div className="panel-head">
                  <div>
                    <h2>Demand planning</h2>
                    <p>
                      28-day average daily units × 7 for a weekly baseline.
                      Planning support, not a guaranteed forecast.
                    </p>
                  </div>
                  <Button
                    variant="secondary"
                    icon={Download}
                    onClick={() =>
                      downloadCSV(
                        "demand-plan.csv",
                        [
                          "SKU",
                          "Product",
                          "Daily average",
                          "7-day baseline",
                          "Days of cover",
                          "Reorder suggestion",
                        ],
                        products.map((p) => [
                          p.sku,
                          p.name,
                          p.daily.toFixed(2),
                          Math.ceil(p.daily * 7),
                          p.daily ? (p.stock / p.daily).toFixed(1) : "",
                          makeReorder(p),
                        ]),
                      )
                    }
                  >
                    Export plan
                  </Button>
                </div>
                <MiniChart values={history} large />
                <div className="chart-dates">
                  <span>{dateLabel(day(-28))}</span>
                  <span>Recorded sales volume</span>
                  <span>{dateLabel(day(-1))}</span>
                </div>
                <Table
                  heads={[
                    "PRODUCT",
                    "DAILY AVG",
                    "7-DAY BASELINE",
                    "DAYS OF COVER",
                    "LEAD TIME",
                    "SUGGESTED ORDER",
                  ]}
                  rows={[...products]
                    .sort(
                      (a, b) =>
                        a.stock / Math.max(a.daily, 0.1) -
                        b.stock / Math.max(b.daily, 0.1),
                    )
                    .map((p) => [
                      productCell(p),
                      number(p.daily),
                      Math.ceil(p.daily * 7),
                      <Tag
                        tone={
                          p.stock / Math.max(p.daily, 0.1) <=
                          supplier(p.supplier).lead_days
                            ? "amber"
                            : ""
                        }
                      >
                        {p.daily ? number(p.stock / p.daily) : "—"} days
                      </Tag>,
                      `${supplier(p.supplier).lead_days} days`,
                      `${makeReorder(p)} ${p.unit}s`,
                    ])}
                />
              </section>
            </>
          )}
          {page === "locations" && (
            <>
              <section className="panel">
                <div className="panel-head">
                  <div>
                    <h2>Locations</h2>
                    <p>Separate places, shared visibility.</p>
                  </div>
                  {canManage && (
                    <Button icon={Plus} onClick={() => open("location")}>
                      Add location
                    </Button>
                  )}
                </div>
                <div className="location-grid">
                  {locations.map((l) => (
                    <button
                      className="location-card"
                      key={l.id}
                      onClick={() => {
                        setLocationFilter(String(l.id));
                        go("inventory");
                      }}
                    >
                      <MapPin size={24} />
                      <h3>{l.name}</h3>
                      <p>{l.site}</p>
                      <Tag>{l.type}</Tag>
                      <div>
                        <strong>
                          {number(
                            lots
                              .filter((x) => x.location === l.id)
                              .reduce((s, x) => s + x.quantity, 0),
                          )}
                        </strong>
                        <span>units on hand</span>
                        <ArrowUpRight size={19} />
                      </div>
                    </button>
                  ))}
                </div>
              </section>
              <section className="panel">
                <div className="panel-head">
                  <h2>Suppliers</h2>
                  {canManage && (
                    <Button
                      variant="secondary"
                      icon={Plus}
                      onClick={() => open("supplier")}
                    >
                      Add supplier
                    </Button>
                  )}
                </div>
                <Table
                  heads={[
                    "SUPPLIER",
                    "ORDER CONTACT",
                    "LEAD TIME",
                    "PRODUCTS",
                    "OPEN ORDERS",
                  ]}
                  rows={suppliers.map((s) => [
                    <strong>{s.name}</strong>,
                    s.email,
                    `${s.lead_days} days`,
                    products.filter((p) => p.supplier === s.id).length,
                    openOrders.filter((o) => o.supplier === s.id).length,
                  ])}
                />
              </section>
            </>
          )}
          {page === "settings" && (
            <>
              <div className="two-col">
                <section className="panel">
                  <div className="panel-head">
                    <h2>Workspace</h2>
                    <Building2 size={20} />
                  </div>
                  <form
                    className="form-body"
                    onSubmit={(e) => {
                      e.preventDefault();
                      act(
                        "/workspace",
                        Object.fromEntries(new FormData(e.currentTarget)),
                        "Workspace updated.",
                        "PATCH",
                      );
                    }}
                  >
                    <Field
                      label="Workspace name"
                      name="name"
                      defaultValue={me.workspace.name}
                      required
                      disabled={me.user.role !== "admin"}
                    />
                    <Button disabled={me.user.role !== "admin" || busy}>
                      Save workspace
                    </Button>
                    <p className="fine">
                      Workspace {me.user.tenant} · Isolated demonstration data.
                      Contact GHT to commission a clean production installation.
                    </p>
                  </form>
                </section>
                <section className="panel">
                  <div className="panel-head">
                    <h2>Account & security</h2>
                    <ShieldCheck size={20} />
                  </div>
                  <div className="form-body">
                    <strong>{me.user.name}</strong>
                    <p>{me.user.email}</p>
                    <Tag>{me.user.role} access</Tag>
                    <div className="stack-actions">
                      <Button
                        variant="secondary"
                        icon={KeyRound}
                        onClick={() => open("password")}
                      >
                        Change password
                      </Button>
                      <Button
                        variant="secondary"
                        icon={ShieldCheck}
                        onClick={() => open("recovery")}
                      >
                        Generate recovery code
                      </Button>
                    </div>
                    <p className="fine">
                      Quick demos use a generated account. Create a named
                      workspace from the sign-in screen for permanent
                      cross-device access.
                    </p>
                  </div>
                </section>
              </div>
              {me.user.role === "admin" && (
                <section className="panel">
                  <div className="panel-head">
                    <div>
                      <h2>Your team</h2>
                      <p>
                        Provision an account, then share its credentials through
                        your approved secure channel.
                      </p>
                    </div>
                    <Button icon={Plus} onClick={() => open("user")}>
                      Add team member
                    </Button>
                  </div>
                  <Table
                    heads={["NAME", "EMAIL", "ROLE", "STATUS", ""]}
                    rows={users.map((u) => [
                      u.name,
                      u.email,
                      <Tag>{u.role}</Tag>,
                      u.active ? "Active" : "Disabled",
                      u.id !== me.user.id ? (
                        <button
                          className="text-link"
                          onClick={() => open("user-edit", u)}
                        >
                          Manage access
                        </button>
                      ) : (
                        "You"
                      ),
                    ])}
                  />
                  <div className="panel-footer">
                    <span>
                      Admin: all settings · Manager: stock approvals and
                      purchasing · Operator: receive, transfer, count · Viewer:
                      read only
                    </span>
                  </div>
                </section>
              )}
              <div className="two-col">
                <section className="panel compact-info">
                  <h2>Your data travels with you.</h2>
                  <p>
                    Export operational records as JSON for analysis and
                    migration. User credentials and sessions are excluded.
                    Server database backups are a separate administrator task.
                  </p>
                  <Button
                    variant="secondary"
                    icon={Download}
                    disabled={!canManage}
                    onClick={() => {
                      location.href = "/api/export";
                    }}
                  >
                    Export workspace data
                  </Button>
                </section>
                <section className="panel compact-info">
                  <h2>Always on the current release.</h2>
                  <p>
                    Stockroom is delivered through your browser. Reload to fetch
                    the installed server version. On-premise server updates
                    follow the release and rollback runbook.
                  </p>
                  <Tag>1.0.0-preview.2</Tag>
                  <Button
                    variant="secondary"
                    icon={RefreshCw}
                    onClick={() => location.reload()}
                  >
                    Reload application
                  </Button>
                </section>
              </div>
              <section className="panel">
                <div className="panel-head">
                  <h2>Audit trail</h2>
                  <Tag>Latest 200 events</Tag>
                </div>
                <Table
                  heads={["WHEN", "WHO", "ACTION", "DETAIL"]}
                  rows={audit.map((a) => [
                    a.created,
                    a.actor,
                    a.action,
                    a.detail,
                  ])}
                />
              </section>
            </>
          )}
          {page === "help" && (
            <>
              <section className="welcome-guide">
                <div>
                  <div className="eyebrow">YOUR FIRST TEN MINUTES</div>
                  <h2>
                    A full operation.
                    <br />
                    Ready for a test drive.
                  </h2>
                  <p>
                    Oak & Field Market is fictional. The workflows are
                    functional. Follow an item from delivery to sale, then look
                    back at its history.
                  </p>
                  <div className="demo-guide-actions"><Button icon={ScanLine} onClick={()=>go('receive')}>Start with a scan</Button><Button variant="secondary" icon={ChartNoAxesCombined} onClick={()=>go('reports')}>Browse sample reports</Button></div>
                </div>
                <div className="guide-stat">
                  <strong>36</strong>
                  <span>products to explore</span>
                  <strong>5</strong>
                  <span>places to put them</span>
                </div>
              </section>
              {me.workspace.demo === 1 && <DemoShelf products={products} select={p=>{setSelected(p.id);setScan(p.barcode);setError('');go('receive');setToast(`${p.name} found · simulated scan`);}} onError={setError}/>}
              <div className="tour-grid">
                {[
                  [
                    "01",
                    "Receive a delivery",
                    "Open receiving. Use the sample Honeycrisp barcode. Receive 12 cases with a new lot code and delivery reference.",
                    "receive",
                    ScanLine,
                  ],
                  [
                    "02",
                    "Move it to the shelf",
                    "Create a transfer. Choose a stocked lot, a different location, and a quantity. Both movement entries appear together.",
                    "transfers",
                    ArrowLeftRight,
                  ],
                  [
                    "03",
                    "Check a physical count",
                    "Submit a count against a lot. As a manager, review the variance and approve it. Try a stale count after moving stock.",
                    "counts",
                    ClipboardCheck,
                  ],
                  [
                    "04",
                    "Plan your next purchase",
                    "Review low stock, draft an order, mark it ordered, and receive against its remaining quantities.",
                    "purchasing",
                    ShoppingCart,
                  ],
                  [
                    "05",
                    "Connect the sale",
                    "Load the sample sale, review its rows, then import. Reimport the same file to see duplicate protection.",
                    "sales",
                    ArrowDownToLine,
                  ],
                  [
                    "06",
                    "See the whole picture",
                    "Look at value, demand, expiry, and audit records. Invite an operator or viewer to test role boundaries.",
                    "reports",
                    ChartNoAxesCombined,
                  ],
                ].map(([n, title, text, target, Icon]) => (
                  <button
                    className="tour-card"
                    key={n}
                    onClick={() => go(target)}
                  >
                    <div>
                      <span>{n}</span>
                      <Icon size={24} />
                    </div>
                    <h3>{title}</h3>
                    <p>{text}</p>
                    <span className="text-link">
                      Try this workflow <ArrowRight size={16} />
                    </span>
                  </button>
                ))}
              </div>
              <section className="panel compact-info">
                <h2>Built for the infrastructure we install.</h2>
                <div className="three-col">
                  <div>
                    <h3>Your own practice store</h3>
                    <p>
                      Every visitor gets separate sample records. Explore all
                      the workflows without touching another store. Your quick
                      demo returns in this browser while its session is active.
                      Create a named test workspace from the sign-in page for
                      access across devices; it starts with a fresh sample store.
                    </p>
                  </div>
                  <div>
                    <h3>Scanners & labels</h3>
                    <p>
                      Start with an on-screen simulated scan, or print a real
                      practice label. A keyboard-style scanner can enter its
                      code into the receiving field. Save a receipt and open
                      the product to trace the new stock. No hardware is needed
                      to explore the rest of the system.
                    </p>
                  </div>
                  <div>
                    <h3>Reports that respond</h3>
                    <p>
                      Reports begin with fictional sales and inventory, then
                      reflect your saved changes. Use the sample CSV sale to
                      see stock reconciliation. Live POS connections are scoped
                      for each customer; none are connected to this demo.
                      Demand planning uses a 28-day average of recorded sales.
                    </p>
                  </div>
                </div>
                <a
                  className="text-link"
                  href="https://ght.network/business-solutions"
                  target="_blank"
                  rel="noreferrer"
                >
                  Explore GHT business solutions <ArrowUpRight size={16} />
                </a>
              </section>
            </>
          )}
          <footer className="app-footer">
            <span>
              STOCKROOM <i>/</i> BY GLASS HOUSE TECHNOLOGIES
            </span>
            <span>Every item. Every move. Accounted for.</span>
            <a href="/downloads/">Downloads &amp; installation ↗</a>
            <span>Preview 1.0</span>
          </footer>
        </main>
      </div>
      {toast && (
        <div className="toast" role="status">
          <CheckCircle2 size={19} />
          {toast}
          <button
            onClick={() => setToast("")}
            aria-label="Dismiss notification"
          >
            <X size={16} />
          </button>
        </div>
      )}
      {modal && (
        <Modal
          title={
            {
              product: modal.data?.name,
              "new-product": "Add a product",
              "edit-product": "Edit product",
              transfer: "Transfer stock",
              count: "Count a lot",
              "count-review": "Review physical count",
              waste: "Record waste",
              order: "Create purchase order",
              "order-detail": `Purchase order PO-${modal.data?.id}`,
              "cancel-order": "Cancel purchase order",
              location: "Add location",
              supplier: "Add supplier",
              "sales-preview": "Review sales import",
              user: "Add team member",
              "user-edit": "Manage team access",
              password: "Change password",
              recovery: "Generate recovery code",
              alerts: "Your attention list",
              "discard-draft": "Discard receipt draft",
            }[modal.type]
          }
          onClose={() => setModal(null)}
        >
          {modal.type === "product" && (
            <div className="modal-body">
              <div className="product-summary">
                <span className="product-icon large">
                  <Package size={32} />
                </span>
                <div>
                  <Tag>{modal.data.category}</Tag>
                  <p>
                    {modal.data.sku} · Barcode {modal.data.barcode}
                  </p>
                  <strong>
                    {product(modal.data.id).stock} {modal.data.unit}s on hand
                  </strong>
                </div>
              </div>
              <div className="inline-actions">
                <Button
                  variant="secondary"
                  icon={Printer}
                  onClick={() => printLabel(modal.data)}
                >
                  Print barcode label
                </Button>
                {canManage && (
                  <Button
                    variant="secondary"
                    onClick={() => open("edit-product", product(modal.data.id))}
                  >
                    Edit product
                  </Button>
                )}
                <Button
                  onClick={() => {
                    setSelected(modal.data.id);
                    setModal(null);
                    go("receive");
                  }}
                >
                  Receive this product
                </Button>
              </div>
              <h3>Stock by lot & location</h3>
              <Table
                heads={["LOCATION", "LOT", "EXPIRES", "ON HAND"]}
                rows={lots
                  .filter((l) => l.product === modal.data.id)
                  .map((l) => [
                    loc(l.location).name,
                    l.code,
                    dateLabel(l.expiry),
                    l.quantity,
                  ])}
              />
              <h3>Movement history</h3>
              <Table
                heads={["WHEN", "TYPE", "CHANGE", "REFERENCE"]}
                rows={movements
                  .filter((m) => m.product === modal.data.id)
                  .slice(0, 30)
                  .map((m) => [
                    m.created,
                    m.type,
                    <strong>
                      {m.quantity > 0 ? "+" : ""}
                      {m.quantity}
                    </strong>,
                    m.reference,
                  ])}
              />
            </div>
          )}
          {["new-product", "edit-product"].includes(modal.type) && (
            <form
              className="modal-body"
              onSubmit={(e) => {
                e.preventDefault();
                const b = Object.fromEntries(new FormData(e.currentTarget));
                b.cost = Math.round(Number(b.cost) * 100);
                b.price = Math.round(Number(b.price) * 100);
                act(
                  modal.type === "new-product"
                    ? "/products"
                    : `/products/${modal.data.id}`,
                  b,
                  "Product saved.",
                  modal.type === "new-product" ? "POST" : "PATCH",
                );
              }}
            >
              <div className="form-grid">
                <Field
                  label="Product name"
                  name="name"
                  defaultValue={modal.data?.name}
                  required
                />
                {modal.type === "new-product" && (
                  <>
                    <Field label="SKU" name="sku" required maxLength={50} />
                    <Field
                      label="Barcode"
                      name="barcode"
                      required
                      maxLength={80}
                    />
                  </>
                )}
                <Field
                  label="Category"
                  name="category"
                  defaultValue={modal.data?.category || "Pantry"}
                  required
                />
                <Field
                  label="Stock unit"
                  name="unit"
                  options={["case", "unit", "bag", "box", "pallet"]}
                  defaultValue={modal.data?.unit || "case"}
                />
                <Field
                  label="Unit cost ($)"
                  name="cost"
                  type="number"
                  min="0"
                  step="0.01"
                  defaultValue={(modal.data?.cost || 0) / 100}
                  required
                />
                <Field
                  label="Sale price per unit ($)"
                  name="price"
                  type="number"
                  min="0"
                  step="0.01"
                  defaultValue={(modal.data?.price || 0) / 100}
                  required
                />
                <Field
                  label="Reorder point"
                  name="reorder"
                  type="number"
                  min="0"
                  defaultValue={modal.data?.reorder ?? 10}
                  required
                />
                <Field
                  label="Target stock"
                  name="target"
                  type="number"
                  min="0"
                  defaultValue={modal.data?.target ?? 30}
                  required
                />
                <Field
                  label="Supplier"
                  name="supplier"
                  options={sOptions}
                  defaultValue={modal.data?.supplier}
                />
              </div>
              {formFooter("Save product")}
            </form>
          )}
          {modal.type === "transfer" && (
            <form
              className="modal-body"
              onSubmit={(e) =>
                submitForm(
                  e,
                  "/transfer",
                  (x) => x,
                  "Transfer complete. Both locations updated.",
                )
              }
            >
              <Field
                label="Source lot"
                name="lot"
                options={lotOptions()}
                defaultValue={modal.data?.id}
                required
              />
              <Field
                label="Destination"
                name="destination"
                options={lOptions}
                required
              />
              <Field
                label="Quantity"
                name="quantity"
                type="number"
                min="1"
                defaultValue="1"
                required
              />
              <Field
                label="Reason / transfer note"
                name="note"
                required
                maxLength={500}
                placeholder="Replenish the sales floor"
              />
              {formFooter("Confirm transfer")}
            </form>
          )}
          {modal.type === "count" && (
            <form
              className="modal-body"
              onSubmit={(e) =>
                submitForm(
                  e,
                  "/counts",
                  (x) => ({
                    ...x,
                    version: modal.data.lots.find((l) => l.id === Number(x.lot))
                      .version,
                  }),
                  "Count submitted for manager review.",
                )
              }
            >
              <p className="muted">
                Count the selected lot physically. A manager reviews the
                difference before it changes inventory.
              </p>
              <Field
                label="Lot to count"
                name="lot"
                options={lots.map((l) => ({
                  value: l.id,
                  label: `${product(l.product).name} · ${loc(l.location).name} · ${l.code}`,
                }))}
                required
              />
              <Field
                label="Physical quantity counted"
                name="counted"
                type="number"
                min="0"
                required
              />
              <Field
                label="Count note"
                name="note"
                required
                placeholder="Shelf count at opening"
              />
              {formFooter("Submit for review")}
            </form>
          )}
          {modal.type === "count-review" && (
            <div className="modal-body">
              <p>
                Count #{modal.data.id}:{" "}
                <strong>
                  {modal.data.expected} expected → {modal.data.counted} counted
                </strong>
              </p>
              <p>{modal.data.note}</p>
              <div className="notice warning">
                {modal.data.action === "approve"
                  ? "Approving sets this lot to the physical count. The system checks that no stock has moved since the count."
                  : "Rejecting leaves stock unchanged. A new physical count can then be submitted."}
              </div>
              {formError && <div className="notice error">{formError}</div>}
              <div className="modal-actions">
                <Button variant="secondary" onClick={() => setModal(null)}>
                  Cancel
                </Button>
                <Button
                  disabled={busy || !online}
                  onClick={() =>
                    act(
                      `/counts/${modal.data.id}/review`,
                      { action: modal.data.action },
                      "Count reviewed. Audit trail updated.",
                    )
                  }
                >
                  {modal.data.action === "approve"
                    ? "Approve adjustment"
                    : "Reject count"}
                </Button>
              </div>
            </div>
          )}
          {modal.type === "waste" && (
            <form
              className="modal-body"
              onSubmit={(e) =>
                submitForm(
                  e,
                  "/waste",
                  (x) => ({ ...x, lot: modal.data.id }),
                  "Waste recorded and stock deducted.",
                )
              }
            >
              <p>
                <strong>{product(modal.data.product).name}</strong> ·{" "}
                {modal.data.code} · {modal.data.quantity} available
              </p>
              <Field
                label="Units to write off"
                name="quantity"
                type="number"
                min="1"
                max={modal.data.quantity}
                required
              />
              <Field
                label="Reason"
                name="note"
                type="textarea"
                placeholder="Expired, damaged, or spoiled — include the details"
                required
                maxLength={500}
              />
              {formFooter("Record waste")}
            </form>
          )}
          {modal.type === "order" && (
            <form
              className="modal-body"
              onSubmit={(e) => {
                e.preventDefault();
                const b = Object.fromEntries(new FormData(e.currentTarget));
                act(
                  "/orders",
                  { ...b, items: orderLines },
                  "Purchase order drafted. No email sent.",
                );
              }}
            >
              <div className="form-grid">
                <Field
                  label="Supplier"
                  name="supplier"
                  options={sOptions}
                  value={orderSupplier}
                  onChange={(e) => {
                    setOrderSupplier(e.target.value);
                    setOrderLines([{ product: "", quantity: 12 }]);
                  }}
                />
                <Field
                  label="Expected delivery"
                  name="expected"
                  type="date"
                  defaultValue={day(3)}
                  required
                />
              </div>
              <h3>Order lines</h3>
              {orderLines.map((line, i) => (
                <div className="order-line" key={i}>
                  <Field
                    label={`Product ${i + 1}`}
                    options={[
                      { value: "", label: "Choose product" },
                      ...pOptions.filter(
                        (p) =>
                          product(p.value).supplier === Number(orderSupplier),
                      ),
                    ]}
                    value={line.product}
                    required
                    onChange={(e) =>
                      setOrderLines(
                        orderLines.map((l, j) =>
                          j === i
                            ? { ...l, product: Number(e.target.value) }
                            : l,
                        ),
                      )
                    }
                  />
                  <Field
                    label={`Quantity ${i + 1}`}
                    type="number"
                    min="1"
                    value={line.quantity}
                    required
                    onChange={(e) =>
                      setOrderLines(
                        orderLines.map((l, j) =>
                          j === i ? { ...l, quantity: e.target.value } : l,
                        ),
                      )
                    }
                  />
                  <button
                    type="button"
                    className="icon-button"
                    disabled={orderLines.length === 1}
                    aria-label={`Remove line ${i + 1}`}
                    onClick={() =>
                      setOrderLines(orderLines.filter((_, j) => j !== i))
                    }
                  >
                    <X size={18} />
                  </button>
                </div>
              ))}
              <Button
                type="button"
                variant="secondary"
                icon={Plus}
                onClick={() =>
                  setOrderLines([...orderLines, { product: "", quantity: 12 }])
                }
              >
                Add line
              </Button>
              <Field
                label="Order note (optional)"
                name="note"
                type="textarea"
              />
              <div className="notice subtle">
                Orders start as drafts. Download or print the approved order and
                send it through your normal supplier channel.
              </div>
              {formFooter("Create draft order")}
            </form>
          )}
          {modal.type === "order-detail" && (
            <div className="modal-body">
              <div className="order-heading">
                <div>
                  <h3>{supplier(modal.data.supplier).name}</h3>
                  <p>{supplier(modal.data.supplier).email}</p>
                </div>
                <Tag>{modal.data.status}</Tag>
              </div>
              <p>
                Expected {dateLabel(modal.data.expected)} · {modal.data.note}
              </p>
              <Table
                heads={["PRODUCT", "ORDERED", "RECEIVED", "LINE TOTAL"]}
                rows={orderItems
                  .filter((i) => i.order_id === modal.data.id)
                  .map((i) => [
                    product(i.product).name,
                    i.quantity,
                    i.received,
                    money(i.quantity * i.cost),
                  ])}
              />
              <div className="modal-actions">
                <Button
                  variant="secondary"
                  icon={Download}
                  onClick={() =>
                    downloadCSV(
                      `PO-${modal.data.id}.csv`,
                      [
                        "PO",
                        "Supplier",
                        "SKU",
                        "Product",
                        "Ordered",
                        "Received",
                        "Unit cost cents",
                        "Expected",
                      ],
                      orderItems
                        .filter((i) => i.order_id === modal.data.id)
                        .map((i) => [
                          modal.data.id,
                          supplier(modal.data.supplier).name,
                          product(i.product).sku,
                          product(i.product).name,
                          i.quantity,
                          i.received,
                          i.cost,
                          modal.data.expected,
                        ]),
                    )
                  }
                >
                  Download order
                </Button>
                {canManage && modal.data.status === "draft" && (
                  <Button
                    onClick={() =>
                      act(
                        `/orders/${modal.data.id}/status`,
                        { status: "ordered" },
                        "Order marked ordered. Send the downloaded order to your supplier.",
                      )
                    }
                  >
                    Mark ordered
                  </Button>
                )}
                {canManage &&
                  ["draft", "ordered"].includes(modal.data.status) && (
                    <Button
                      variant="text"
                      onClick={() => open("cancel-order", modal.data)}
                    >
                      Cancel order
                    </Button>
                  )}
                {canOperate &&
                  ["ordered", "partial"].includes(modal.data.status) && (
                    <Button
                      onClick={() => {
                        setSelected(
                          orderItems.find(
                            (i) =>
                              i.order_id === modal.data.id &&
                              i.received < i.quantity,
                          )?.product,
                        );
                        setModal(null);
                        go("receive");
                      }}
                    >
                      Receive delivery
                    </Button>
                  )}
              </div>
            </div>
          )}
          {modal.type === "cancel-order" && (
            <div className="modal-body">
              <h3>Cancel PO-{modal.data.id}?</h3>
              <p>
                This closes the order in Stockroom. Contact your supplier
                separately if the order was already sent.
              </p>
              <Button
                onClick={() =>
                  act(
                    `/orders/${modal.data.id}/status`,
                    { status: "cancelled" },
                    "Order cancelled in Stockroom.",
                  )
                }
              >
                Confirm cancellation
              </Button>
            </div>
          )}
          {modal.type === "location" && (
            <form
              className="modal-body"
              onSubmit={(e) =>
                submitForm(e, "/locations", (x) => x, "Location added.")
              }
            >
              <Field label="Location name" name="name" required />
              <Field label="Site / store" name="site" required />
              <Field
                label="Location type"
                name="type"
                options={[
                  "Sales floor",
                  "Backroom",
                  "Cold storage",
                  "Warehouse",
                  "Receiving",
                ]}
              />
              {formFooter("Add location")}
            </form>
          )}
          {modal.type === "supplier" && (
            <form
              className="modal-body"
              onSubmit={(e) =>
                submitForm(e, "/suppliers", (x) => x, "Supplier added.")
              }
            >
              <Field label="Supplier name" name="name" required />
              <Field label="Order email" name="email" type="email" required />
              <Field
                label="Lead time in days"
                name="lead_days"
                type="number"
                min="0"
                max="365"
                defaultValue="3"
                required
              />
              {formFooter("Add supplier")}
            </form>
          )}
          {modal.type === "sales-preview" && (
            <div className="modal-body">
              <p>
                {modal.data.length} rows ready for validation. Stock is deducted
                only for successfully reconciled sales. Insufficient stock
                becomes an exception.
              </p>
              <Table
                heads={[
                  "REFERENCE",
                  "SKU",
                  "LOCATION",
                  "QUANTITY",
                  "REVENUE CENTS",
                  "DATE",
                ]}
                rows={modal.data
                  .slice(0, 20)
                  .map((r) => [
                    r.external_id,
                    r.sku,
                    r.location,
                    r.quantity,
                    r.revenue,
                    r.date,
                  ])}
              />
              {modal.data.length > 20 && <p>First 20 rows shown.</p>}
              {formError && <div className="notice error">{formError}</div>}
              <div className="modal-actions">
                <Button variant="secondary" onClick={() => setModal(null)}>
                  Cancel
                </Button>
                <Button
                  disabled={busy}
                  onClick={async () => {
                    const r = await act(
                      "/sales/import",
                      { rows: modal.data },
                      "Sales import finished.",
                    );
                    if (r) {
                      setToast(
                        `${r.imported} reconciled · ${r.exceptions} exceptions · ${r.duplicates} duplicates skipped`,
                      );
                      setSaleText("");
                    }
                  }}
                >
                  Import & reconcile
                </Button>
              </div>
            </div>
          )}
          {modal.type === "user" && (
            <form
              className="modal-body"
              onSubmit={async (e) => {
                e.preventDefault();
                setBusy(true);
                setFormError("");
                try {
                  const r = await api(
                    "/users",
                    Object.fromEntries(new FormData(e.currentTarget)),
                  );
                  setSecretResult(r.recovery);
                  await load();
                } catch (e) {
                  setFormError(e.message);
                } finally {
                  setBusy(false);
                }
              }}
            >
              {secretResult ? (
                <>
                  <h3>Team member created.</h3>
                  <p>
                    Share the email, password you entered, and this recovery
                    code using your approved secure channel. No email was sent.
                  </p>
                  <code className="recovery">{secretResult}</code>
                  <Button type="button" onClick={() => setModal(null)}>
                    Done
                  </Button>
                </>
              ) : (
                <>
                  <Field label="Full name" name="name" required />
                  <Field
                    label="Email address"
                    name="email"
                    type="email"
                    required
                  />
                  <Field
                    label="Initial password"
                    name="password"
                    type="password"
                    minLength="12"
                    maxLength="128"
                    required
                    autoComplete="new-password"
                  />
                  <Field
                    label="Role"
                    name="role"
                    options={["operator", "viewer", "manager", "admin"]}
                  />
                  {formFooter("Create account")}
                </>
              )}
            </form>
          )}
          {modal.type === "user-edit" && (
            <form
              className="modal-body"
              onSubmit={(e) => {
                e.preventDefault();
                const b = Object.fromEntries(new FormData(e.currentTarget));
                act(
                  `/users/${modal.data.id}`,
                  { role: b.role, active: b.active === "yes" },
                  "Team access updated. Existing sessions revoked.",
                  "PATCH",
                );
              }}
            >
              <p>{modal.data.email}</p>
              <Field
                label="Role"
                name="role"
                options={["operator", "viewer", "manager", "admin"]}
                defaultValue={modal.data.role}
              />
              <Field
                label="Account access"
                name="active"
                options={[
                  { value: "yes", label: "Active" },
                  { value: "no", label: "Disabled" },
                ]}
                defaultValue={modal.data.active ? "yes" : "no"}
              />
              {formFooter()}
            </form>
          )}
          {modal.type === "password" && (
            <form
              className="modal-body"
              onSubmit={(e) =>
                submitForm(
                  e,
                  "/auth/password",
                  (x) => x,
                  "Password changed. Other sessions signed out.",
                )
              }
            >
              <Field
                label="Current password"
                name="current"
                type="password"
                autoComplete="current-password"
                required
              />
              <Field
                label="New password"
                name="password"
                type="password"
                minLength="12"
                maxLength="128"
                autoComplete="new-password"
                required
              />
              {formFooter("Change password")}
            </form>
          )}
          {modal.type === "recovery" && (
            <form
              className="modal-body"
              onSubmit={async (e) => {
                e.preventDefault();
                try {
                  const r = await api(
                    "/auth/recovery-code",
                    Object.fromEntries(new FormData(e.currentTarget)),
                  );
                  setSecretResult(r.recovery);
                } catch (e) {
                  setFormError(e.message);
                }
              }}
            >
              {secretResult ? (
                <>
                  <p>
                    Save this code securely. The old recovery code no longer
                    works.
                  </p>
                  <code className="recovery">{secretResult}</code>
                  <Button type="button" onClick={() => setModal(null)}>
                    Saved
                  </Button>
                </>
              ) : (
                <>
                  <p>
                    Generating a new code replaces your previous recovery code.
                  </p>
                  <Field
                    label="Current password"
                    name="password"
                    type="password"
                    required
                  />
                  {formFooter("Generate code")}
                </>
              )}
            </form>
          )}
          {modal.type === "alerts" && (
            <div className="modal-body">
              {[
                [low.length, "products need replenishment", "purchasing"],
                [expiring.length, "lots need freshness review", "expiry"],
                [pending.length, "counts await approval", "counts"],
                [exceptions.length, "sales need reconciliation", "sales"],
              ].map(([n, label, target]) => (
                <button
                  className="list-row"
                  key={target}
                  onClick={() => {
                    setModal(null);
                    go(target);
                  }}
                >
                  <span>
                    <strong>
                      {n} {label}
                    </strong>
                    <small>Open {target}</small>
                  </span>
                  <ArrowUpRight size={20} />
                </button>
              ))}
            </div>
          )}
          {modal.type === "discard-draft" && (
            <div className="modal-body">
              <p>
                Discard the unsynced receipt for{" "}
                {product(modal.data.body.product).name}? It has not changed
                inventory.
              </p>
              <Button
                onClick={() => {
                  saveQueue(queue.filter((q) => q.id !== modal.data.id));
                  setModal(null);
                  setToast("Draft discarded.");
                }}
              >
                Discard draft
              </Button>
            </div>
          )}
        </Modal>
      )}
    </div>
  );
}
function Metric({ label, value, icon: Icon, note, accent, onClick }) {
  return (
    <button
      className={`metric ${accent ? "accent" : ""}`}
      onClick={onClick}
      disabled={!onClick}
    >
      <div>
        <span>{label}</span>
        <Icon size={19} />
      </div>
      <strong>{value}</strong>
      <small>{note}</small>
      {onClick && <ArrowUpRight size={15} className="metric-arrow" />}
    </button>
  );
}
function downloadCSV(name, heads, rows) {
  const escape = (v) => {
    let s = String(v ?? "");
    if (/^[=+@\-\t\r]/.test(s)) s = "'" + s;
    return '"' + s.replaceAll('"', '""') + '"';
  };
  const blob = new Blob(
    [
      "\uFEFF" +
        [heads, ...rows].map((r) => r.map(escape).join(",")).join("\r\n"),
    ],
    { type: "text/csv;charset=utf-8" },
  );
  const a = document.createElement("a");
  a.href = URL.createObjectURL(blob);
  a.download = name;
  a.click();
  setTimeout(() => URL.revokeObjectURL(a.href), 1000);
}
function parseCSV(text) {
  const rows = [];
  let row = [],
    field = "",
    quoted = false;
  for (let i = 0; i < text.length; i++) {
    const c = text[i];
    if (c === '"') {
      if (quoted && text[i + 1] === '"') {
        field += '"';
        i++;
      } else quoted = !quoted;
    } else if (c === "," && !quoted) {
      row.push(field);
      field = "";
    } else if ((c === "\n" || c === "\r") && !quoted) {
      if (c === "\r" && text[i + 1] === "\n") i++;
      row.push(field);
      if (row.some((x) => x.trim())) rows.push(row);
      row = [];
      field = "";
    } else field += c;
  }
  if (quoted) throw new Error("CSV has an unclosed quoted field.");
  row.push(field);
  if (row.some((x) => x.trim())) rows.push(row);
  const heads = rows.shift()?.map((s) => s.trim().replace(/^\uFEFF/, ""));
  const required = [
    "external_id",
    "sku",
    "location",
    "quantity",
    "revenue",
    "date",
  ];
  if (!heads || heads.length !== 6 || required.some((h) => !heads.includes(h)))
    throw new Error(
      "Use exactly these headers: external_id, sku, location, quantity, revenue, date.",
    );
  if (!rows.length || rows.length > 500)
    throw new Error("Choose a file with 1–500 sales rows.");
  return rows.map((r, i) => {
    if (r.length !== 6) throw new Error(`Row ${i + 2} needs six columns.`);
    return Object.fromEntries(heads.map((h, j) => [h, r[j].trim()]));
  });
}
async function printLabel(p) {
  const { printBarcode } = await import("./barcode.js");
  printBarcode(p);
}
createRoot(document.getElementById("root")).render(<App />);
