/* =============================================================
   CoreIQ Office — App shell, sign-in, state
   ============================================================= */
const { useState: oUseState, useEffect: oUseEffect, useMemo: oUseMemo, useCallback: oUseCallback, useRef: oUseRef, createContext: oCC, useContext: oUC } = React;

const OD = window.OFFICE_DATA;
const oMoney = window.officeMoney;
const findP = window.findOfficeProduct;
const findS = window.findOfficeStore;
const findSup = window.findOfficeSupplier;
const findU = window.findOfficeUser;

// -----------------------------------------------------------------
// Office context — shared state
// -----------------------------------------------------------------
const OfficeContext = oCC(null);
window.useOffice = () => oUC(OfficeContext);

function OfficeProvider({ children }) {
  // Sign-in — persisted so switching store (which reloads the page) doesn't log you out.
  // In Cognito mode the session is only valid while the stored ID token is unexpired;
  // an expired/missing token forces a fresh sign-in.
  const [signedIn, setSignedIn] = oUseState(() => {
    try {
      if (window.OFFICE_COGNITO) {
        const t = sessionStorage.getItem("coreiq-office-idtoken");
        if (!t) return false;
        const body = JSON.parse(atob(t.split(".")[1].replace(/-/g, "+").replace(/_/g, "/")));
        if (!body.exp || body.exp * 1000 < Date.now() + 60000) return false;
        window.OfficeAPI.setToken(t);
        return true;
      }
      return localStorage.getItem("coreiq-office-signedin") === "1";
    } catch (_) { return false; }
  });
  oUseEffect(() => {
    try { localStorage.setItem("coreiq-office-signedin", signedIn ? "1" : "0"); } catch (_) {}
  }, [signedIn]);
  const [activeUser, setActiveUser] = oUseState(OD.USERS[0]);

  // Multi-store (group) switcher: every store the owner controls ACROSS their orgs,
  // loaded LIVE from /stores. Each store is one (org, site). The active store sets
  // which org/site all screens query (sent as headers; persisted across the reload
  // we do on switch). Empty until loaded.
  const [stores, setStores] = oUseState([]);
  const [storesLoading, setStoresLoading] = oUseState(true);
  const [orgError, setOrgError] = oUseState(null);
  const [activeStoreId, setActiveStoreId] = oUseState(null); // the active store's site id
  oUseEffect(() => {
    let alive = true;
    window.OfficeAPI.listStores()
      .then(res => {
        if (!alive) return;
        const list = (res.stores || []).map(s => ({ id: s.siteId, orgId: s.orgId, code: s.code, name: s.siteName, orgName: s.orgName }));
        setStores(list);
        // Reconcile the persisted store against the LIVE list. The saved org can go
        // stale (e.g. a re-migration moved a site under a different org), and since
        // every request is scoped by that org, a stale org silently returns ZEROS
        // across the whole dashboard. Match by site (authoritative), else the org the
        // API resolved to, else the first store — then re-persist the CURRENT org so
        // the headers hit the right tenant.
        const active = window.OfficeAPI.getActiveStore();
        const chosen =
          list.find(s => s.id === active.siteId) ||
          list.find(s => s.orgId === res.defaultOrgId) ||
          list[0] || null;
        if (chosen && (active.orgId !== chosen.orgId || active.siteId !== chosen.id)) {
          window.OfficeAPI.setActiveStore(chosen.orgId, chosen.id);
          // Reload once so every screen re-queries the corrected org (same mechanism
          // as switchStore). Guard against a reload loop if it can't converge.
          if (!sessionStorage.getItem("coreiq-store-reconciled")) {
            sessionStorage.setItem("coreiq-store-reconciled", "1");
            window.location.reload();
            return;
          }
        }
        setActiveStoreId(chosen ? chosen.id : null);
        setStoresLoading(false);
      })
      .catch(err => { if (alive) { setOrgError(String(err && err.message || err)); setStoresLoading(false); } });
    return () => { alive = false; };
  }, []);

  // Switch the active store → persist + reload so every screen re-queries that org.
  const switchStore = oUseCallback((store) => {
    if (!store || store.id === activeStoreId) return;
    window.OfficeAPI.setActiveStore(store.orgId, store.id);
    window.location.reload();
  }, [activeStoreId]);

  // Active store as the "scope" the rest of the shell already understands.
  const scope = activeStoreId || "all";
  const setScope = () => {}; // legacy no-op; switching goes through switchStore
  const scopedStores = stores.filter(s => s.id === activeStoreId);
  const scopedStoreIds = scopedStores.map(s => s.id);

  // Navigation
  const [screen, setScreen] = oUseState("dashboard");
  const [screenState, setScreenState] = oUseState({});

  // Toasts
  const [toasts, setToasts] = oUseState([]);
  const pushToast = oUseCallback((t) => {
    const id = "t" + Date.now() + Math.random();
    setToasts(ts => [...ts, { ...t, id }]);
    setTimeout(() => setToasts(ts => ts.filter(x => x.id !== id)), 4200);
  }, []);
  const dismissToast = (id) => setToasts(ts => ts.filter(t => t.id !== id));

  // Right-side drawer (used by store-switcher etc)
  const [drawer, setDrawer] = oUseState(null); // null | "stores"

  const value = {
    signedIn, setSignedIn,
    activeUser, setActiveUser,
    scope, setScope, scopedStores, scopedStoreIds,
    activeStoreId, switchStore,
    stores, storesLoading, orgError,
    screen, setScreen, screenState, setScreenState,
    toasts, pushToast, dismissToast,
    drawer, setDrawer,
  };

  return <OfficeContext.Provider value={value}>{children}</OfficeContext.Provider>;
}

// -----------------------------------------------------------------
// Icon helper — defaults 16×16
// -----------------------------------------------------------------
function OIcon({ name, width = 16, height = 16, ...rest }) {
  return <svg aria-hidden="true" width={width} height={height} {...rest}><use href={"#i-" + name}/></svg>;
}
window.OIcon = OIcon;

// -----------------------------------------------------------------
// Nav definitions
// -----------------------------------------------------------------
// MVP menu — only the features wired to the live Office API are shown. The rest
// of the back-office (Stores, Buying, Customer, Clinical, Government, Staff,
// Finance, Reports, Operations, and the Admin extras) is built in the prototype
// but NOT yet wired to the API, so it is hidden until each vertical is wired.
// The complete menu is preserved as OFF_NAV_FUTURE below for phased re-enable.
const OFF_NAV = [
  { section: "Overview", items: [
    { key: "dashboard", label: "Dashboard", icon: "dashboard" },
    { key: "customers", label: "Customers", icon: "users" },
  ]},
  { section: "Catalogue & stock", items: [
    { key: "catalogue",     label: "Product catalogue", icon: "pill" },
    { key: "stockOverview", label: "Stock overview", icon: "stock" },
    { key: "manageStock",   label: "Manage stock",   icon: "list" },
    { key: "newStock",      label: "New stock line", icon: "plus" },
    { key: "suppliers",     label: "Suppliers",      icon: "truck" },
  ]},
  { section: "History", items: [
    { key: "salesHistory", label: "Sales history",      icon: "doc" },
    { key: "invoices",     label: "Wholesaler invoices", icon: "doc" },
    { key: "accounts",     label: "Account statements", icon: "card" },
    { key: "stockHistory", label: "Stock movements",    icon: "transfer" },
  ]},
  { section: "Analytics", items: [
    { key: "salesAnalytics",     label: "Sales analytics",        icon: "chart" },
    { key: "inventoryAnalytics", label: "Inventory intelligence", icon: "stock" },
    { key: "financialAnalytics", label: "Financial analytics",    icon: "card" },
    { key: "pricePosition",      label: "Price position",         icon: "tag" },
    { key: "shortageRadar",      label: "Supply & shortages",     icon: "truck" },
  ]},

  { section: "Administration", items: [
    { key: "storeSetup", label: "Store setup", icon: "settings" },
  ]},
];

// Full back-office menu — future work, re-enable per vertical once wired.
const OFF_NAV_FUTURE = [
  { section: "Overview", items: [
    { key: "dashboard", label: "Dashboard", icon: "dashboard" },
  ]},
  { section: "Stock", items: [
    { key: "stockOverview", label: "Stock overview", icon: "stock" },
    { key: "manageStock",   label: "Manage stock",   icon: "list" },
    { key: "newStock",      label: "New stock line", icon: "plus" },
    { key: "labels",        label: "Print labels",   icon: "printer" },
    { key: "esls",          label: "Electronic shelf labels", icon: "tag" },
    { key: "stocktake",     label: "Stocktake",      icon: "clipboard" },
    { key: "planner",       label: "Floor & shelf planner", icon: "shelf" },
    { key: "shelfMarket",   label: "Shelf marketplace", icon: "tag" },
  ]},
  { section: "Stores", items: [
    { key: "stores",        label: "Stores",         icon: "store" },
    { key: "transfers",     label: "Stock transfers", icon: "transfer" },
  ]},
  { section: "Buying", items: [
    { key: "purchaseOrders", label: "Purchase orders", icon: "doc" },
    { key: "receiving",      label: "Receiving", icon: "download" },
    { key: "ordering",       label: "Ordering channels", icon: "truck" },
    { key: "priceLists",     label: "Price lists",     icon: "list" },
    { key: "backorders",     label: "Backorders",      icon: "clock" },
    { key: "buyingGroups",   label: "Groups & formulary", icon: "users" },
    { key: "ediStatus",      label: "EDI status",      icon: "transfer" },
    { key: "invoices",       label: "Wholesaler invoices", icon: "doc" },
  ]},
  { section: "Customer", items: [
    { key: "customerProfiles", label: "Customer profiles", icon: "users" },
    { key: "scriptsOnFile",   label: "Scripts on file", icon: "rx" },
    { key: "commsPrefs",      label: "Consent & comms", icon: "phone" },
    { key: "accounts",        label: "Payment accounts", icon: "card" },
    { key: "promotions",      label: "Promotions",      icon: "tag" },
    { key: "loyalty",         label: "Loyalty",         icon: "loyalty" },
    { key: "vouchers",        label: "Corporate vouchers", icon: "loyalty" },
  ]},
  { section: "Clinical", items: [
    { key: "ironbark",     label: "Ironbark · AI",     icon: "pill" },
    { key: "vaccinations", label: "Vaccinations · AIR", icon: "check-circle" },
    { key: "servicesLog",  label: "MedsCheck & services", icon: "doc" },
    { key: "medProfiles",  label: "Patient med profiles", icon: "user" },
  ]},
  { section: "Government programs", items: [
    { key: "govPrograms", label: "Federal · State · PPA", icon: "doc" },
  ]},
  { section: "Staff", items: [
    { key: "staff", label: "Profiles, roster, training", icon: "users" },
  ]},
  { section: "Finance", items: [
    { key: "payments",       label: "Payments · Adyen", icon: "card" },
    { key: "pbsClaims",      label: "PBS claims",       icon: "doc" },
    { key: "eodRecon",       label: "End of day",       icon: "clock" },
    { key: "invoiceMatching",label: "Invoice matching", icon: "transfer" },
    { key: "pnl",            label: "P&L by store",     icon: "chart" },
    { key: "tax",            label: "Tax & BAS",        icon: "doc" },
  ]},
  { section: "Reports", items: [
    { key: "reports",       label: "Reports",        icon: "chart" },
    { key: "schemas",       label: "Report columns", icon: "columns" },
  ]},
  { section: "Operations", items: [
    { key: "operations", label: "Incidents & SLA", icon: "alert" },
  ]},
  { section: "Admin", items: [
    { key: "users",         label: "Users & roles",  icon: "users" },
    { key: "suppliers",     label: "Suppliers",      icon: "truck" },
    { key: "auditLogs",     label: "Audit logs",     icon: "doc" },
    { key: "integrations",  label: "Integrations",   icon: "transfer" },
    { key: "settings",      label: "Settings",       icon: "settings" },
  ]},
];

// -----------------------------------------------------------------
// Sign-in
// -----------------------------------------------------------------
function SignIn() {
  const { setSignedIn, setActiveUser } = window.useOffice();
  const [email, setEmail] = oUseState(window.OFFICE_COGNITO ? "" : "suni.k@coreiq.au");
  const [password, setPassword] = oUseState(window.OFFICE_COGNITO ? "" : "•••••••••");
  const [error, setError] = oUseState(null);
  const [loading, setLoading] = oUseState(false);

  // Real Cognito sign-in when the page carries pool config (production);
  // the demo-user path remains for local dev where no pool is configured.
  async function cognitoAuth() {
    const cfg = window.OFFICE_COGNITO;
    const res = await fetch(`https://cognito-idp.${cfg.region}.amazonaws.com/`, {
      method: "POST",
      headers: {
        "Content-Type": "application/x-amz-json-1.1",
        "X-Amz-Target": "AWSCognitoIdentityProviderService.InitiateAuth",
      },
      body: JSON.stringify({
        ClientId: cfg.clientId,
        AuthFlow: "USER_PASSWORD_AUTH",
        AuthParameters: { USERNAME: email, PASSWORD: password },
      }),
    });
    const data = await res.json();
    if (!res.ok || !data.AuthenticationResult || !data.AuthenticationResult.IdToken) {
      throw new Error(data.message || "Sign-in failed — check your email and password.");
    }
    const idToken = data.AuthenticationResult.IdToken;
    window.OfficeAPI.setToken(idToken);
    try { sessionStorage.setItem("coreiq-office-idtoken", idToken); } catch (_) {}
    const first = (email.split("@")[0].split(/[._-]/)[0] || "User");
    return {
      id: "cognito", email,
      first: first[0].toUpperCase() + first.slice(1), last: "",
      role: "Owner", status: "active",
    };
  }

  function tryAuth(e) {
    e.preventDefault();
    setError(null);
    if (window.OFFICE_COGNITO) {
      setLoading(true);
      cognitoAuth()
        .then((user) => { setActiveUser(user); setSignedIn(true); setLoading(false); })
        .catch((err) => { setError(String(err.message || err)); setLoading(false); });
      return;
    }
    const user = OD.USERS.find(u => u.email === email && u.status === "active");
    if (!user) {
      setError("No account matches that email — or it's been suspended.");
      return;
    }
    setLoading(true);
    setTimeout(() => {
      setActiveUser(user);
      setSignedIn(true);
      setLoading(false);
    }, 350);
  }

  function pickDemoUser(u) {
    setEmail(u.email);
    setError(null);
  }

  return (
    <div className="signin-stage">
      <div className="signin-card">
        <div className="signin-brand">
          <div className="signin-brand-mark">C</div>
          <div className="signin-brand-text">
            <span className="signin-brand-name">CoreIQ</span>
            <span className="signin-brand-sub">Office · Admin web</span>
          </div>
        </div>

        <h1 className="signin-title">Sign in to Office</h1>
        <p className="signin-sub">Multi-store admin, stock and reporting.</p>

        <form className="signin-form" onSubmit={tryAuth}>
          <div className="field">
            <label className="field-label">Email</label>
            <input className="input" type="email" value={email} onChange={e => setEmail(e.target.value)} autoFocus/>
          </div>
          <div className="field">
            <label className="field-label">Password</label>
            <input className="input" type="password" value={password} onChange={e => setPassword(e.target.value)}/>
          </div>
          {error && <div className="signin-error">{error}</div>}
          <button type="submit" className="btn btn--primary signin-cta" disabled={loading}>
            {loading ? <span className="spinner" style={{borderColor:'rgba(255,255,255,0.4)', borderTopColor:'#fff'}}/> : <OIcon name="lock"/>}
            <span>{loading ? "Signing in…" : "Sign in"}</span>
          </button>

          {window.OFFICE_COGNITO ? null : <div style={{fontSize:'var(--fs-11)', color:'rgba(255,255,255,0.45)', textTransform:'uppercase', letterSpacing:'0.06em', fontWeight:500, marginTop:14, paddingTop:14, borderTop:'1px solid rgba(255,255,255,0.08)'}}>
            Demo · try a user
          </div>}
          <div style={{display:'flex', flexWrap:'wrap', gap:6}}>
            {window.OFFICE_COGNITO ? null : <React.Fragment>
            {OD.USERS.filter(u => u.status === "active").slice(0, 4).map(u => (
              <button
                key={u.id}
                type="button"
                onClick={() => pickDemoUser(u)}
                style={{
                  background:'rgba(255,255,255,0.05)',
                  border:'1px solid rgba(255,255,255,0.10)',
                  color:'#fff',
                  borderRadius:8,
                  padding:'7px 10px',
                  fontSize:'var(--fs-11)',
                  cursor:'pointer',
                  display:'inline-flex',
                  alignItems:'center',
                  gap:6,
                  fontFamily:'inherit',
                }}
              >
                <span style={{width:18, height:18, borderRadius:99, background:'var(--teal-700)', display:'inline-grid', placeItems:'center', fontSize:9, fontWeight:600}}>{(u.first[0]+u.last[0]).toUpperCase()}</span>
                {u.first} {u.last[0]}.
                <span style={{color:'rgba(255,255,255,0.45)'}}>· {u.role.split(" ")[0]}</span>
              </button>
            ))}
            </React.Fragment>}
          </div>
        </form>

        <div className="signin-foot">
          <a href="#">Forgot password?</a>
          <span>v0.2 · 26 May 2026</span>
        </div>
      </div>
    </div>
  );
}

// -----------------------------------------------------------------
// Sidebar
// -----------------------------------------------------------------
function OffSidebar() {
  const { screen, setScreen, activeUser, setSignedIn, setDrawer } = window.useOffice();

  const badgeFor = (key) => {
    switch (key) {
      case "labels":     return OD.LABEL_QUEUE.filter(l => l.status === "queued").length;
      case "stocktake":  return OD.STOCKTAKES.filter(s => s.status === "in-progress").length;
      case "transfers":  return OD.TRANSFERS.filter(t => t.status === "pending" || t.status === "in-transit").length;
      case "accounts":   return null;
      case "promotions": return null;
      case "users":      return OD.USERS.filter(u => u.status === "pending").length;
      default: return null;
    }
  };

  return (
    <aside className="off-side">
      <div className="off-side-brand">
        <div className="off-side-brand-mark">C</div>
        <div className="off-side-brand-meta">
          <span className="off-side-brand-name">CoreIQ</span>
          <span className="off-side-brand-store">Office · Admin</span>
        </div>
      </div>

      {OFF_NAV.map(sec => (
        <div key={sec.section}>
          <div className="off-side-section">{sec.section}</div>
          <div className="off-nav">
            {sec.items.map(it => {
              const b = badgeFor(it.key);
              const active = screen === it.key || (it.key === "shelfMarket" && screen === "shelfMarketListing") || (it.key === "suppliers" && screen === "supplierDetail") || (it.key === "receiving" && (screen === "receiveOrder" || screen === "productHistory"));
              return (
                <button
                  key={it.key}
                  className={"off-nav-item" + (active ? " off-nav-item--active" : "")}
                  onClick={() => setScreen(it.key)}
                >
                  <OIcon name={it.icon}/>
                  <span>{it.label}</span>
                  {b ? <span className="off-nav-badge">{b}</span> : null}
                </button>
              );
            })}
          </div>
        </div>
      ))}

      <div className="off-side-foot">
        <div className="off-side-user" onClick={() => setDrawer("user")}>
          <div className="off-side-user-av">{(activeUser.first[0]+activeUser.last[0]).toUpperCase()}</div>
          <div className="off-side-user-meta">
            <span className="off-side-user-name">{activeUser.first} {activeUser.last}</span>
            <span className="off-side-user-role">{activeUser.role}</span>
          </div>
          <button
            className="off-topbar-btn"
            style={{width:24,height:24, border:'none', background:'transparent'}}
            onClick={(e) => { e.stopPropagation(); setSignedIn(false); }}
            title="Sign out"
          >
            <OIcon name="logout" width={12} height={12}/>
          </button>
        </div>
      </div>
    </aside>
  );
}

// -----------------------------------------------------------------
// Data-source badge — tells you, per screen, whether what you're looking at is
// REAL (this org's live Aurora data), real-but-shared (the national reference
// catalogue), or still mock prototype data. Keyed by screen so it can never
// drift from the truth: a screen is only "live" once it's listed here.
// -----------------------------------------------------------------
const SCREEN_SOURCE = {
  dashboard: "live-org",       // real org KPIs from /overview
  stockOverview: "live-org",   // real org inventory from /stock + /overview
  manageStock: "live-org",     // real products; edits PATCH to Aurora → POS
  suppliers: "live-org",       // real suppliers from /suppliers
  supplierDetail: "live-org",  // real supplier profile + its products
  productDetail: "live-org",   // full real product page; edits PATCH to Aurora → POS
  catalogue: "live-ref",       // real, but the NATIONAL shared reference catalogue (not this org's products)
  // This pharmacy's own real data — to the user it's a seamless continuation, not an "archive".
  salesHistory: "live-org",
  invoices: "live-org",
  accounts: "live-org",
  stockHistory: "live-org",
  salesAnalytics: "live-org",
  inventoryAnalytics: "live-org",
  financialAnalytics: "live-org",
  pricePosition: "live-org",
  shortageRadar: "live-org",
};
const DATA_BADGE = {
  "live-org": { text: "LIVE · this pharmacy", bg: "var(--paid-bg)", fg: "var(--paid-text)", dot: "var(--paid)",
    title: "Real data for the signed-in organisation, queried live from Aurora." },
  "live-ref": { text: "LIVE · national reference", bg: "var(--navy-100)", fg: "var(--navy-800)", dot: "var(--navy-600)",
    title: "Real data, but the shared national ARTG/PBS reference catalogue — not this organisation's own products." },
  "live-archive": { text: "LIVE · legacy archive", bg: "var(--hold-bg)", fg: "var(--hold-text)", dot: "var(--hold)",
    title: "Real retained data from the legacy Z system (7-year retention archive), queried live from Aurora. Read-only history." },
  "demo": { text: "DEMO DATA", bg: "var(--hold-bg)", fg: "var(--hold-text)", dot: "var(--hold)",
    title: "Mock prototype data. NOT real — this screen is not wired to the database yet." },
};
function DataBadge({ screen }) {
  const cfg = DATA_BADGE[SCREEN_SOURCE[screen] || "demo"];
  return (
    <span title={cfg.title} style={{display:'inline-flex',alignItems:'center',gap:6,background:cfg.bg,color:cfg.fg,borderRadius:99,padding:'5px 11px',fontSize:'var(--fs-11)',fontWeight:700,letterSpacing:'0.03em',whiteSpace:'nowrap'}}>
      <span style={{width:7,height:7,borderRadius:99,background:cfg.dot,boxShadow:'0 0 0 3px '+cfg.bg}}/>
      {cfg.text}
    </span>
  );
}

// -----------------------------------------------------------------
// Topbar
// -----------------------------------------------------------------
function OffTopbar() {
  const { scope, stores, storesLoading, screen, setDrawer, drawer } = window.useOffice();
  const cur = stores.find(s => s.id === scope);
  const label = storesLoading ? "Loading stores…" : (cur ? cur.name : "Select store");
  const avLabel = cur?.code || "··";

  return (
    <div className="off-topbar">
      <button className="off-topbar-store" onClick={() => setDrawer(drawer === "stores" ? null : "stores")}>
        <div className="off-topbar-store-av">{avLabel}</div>
        <div className="off-topbar-store-meta">
          <span className="off-topbar-store-name">{label}</span>
          <span className="off-topbar-store-sub">{stores.length > 1 ? `${stores.length} stores · click to switch` : "Store · click to switch"}</span>
        </div>
        <OIcon name="chevron-down" width={14} height={14} style={{marginLeft:6, color:'var(--text-subtle)'}}/>
      </button>

      <div className="off-topbar-divider"/>

      <div className="off-topbar-search">
        <OIcon name="search" className="off-topbar-search-ic"/>
        <input className="input" placeholder="Search products, suppliers, users, reports…"/>
        <span className="kbd">⌘ K</span>
      </div>

      <div className="off-topbar-meta">
        <DataBadge screen={screen}/>
        <button className="off-topbar-btn" title="Notifications">
          <OIcon name="bell"/>
        </button>
        <button className="off-topbar-btn" title="Help">
          <OIcon name="info"/>
        </button>
      </div>
    </div>
  );
}

// -----------------------------------------------------------------
// Store switcher drawer
// -----------------------------------------------------------------
function StoreDrawer() {
  const { scope, switchStore, setDrawer, stores, storesLoading, orgError } = window.useOffice();
  return (
    <div className="off-drawer">
      <div className="off-drawer-head">
        <div>
          <div style={{fontSize:'var(--fs-11)', color:'var(--text-subtle)', textTransform:'uppercase', letterSpacing:'0.06em', fontWeight:500}}>Your stores · live from Aurora</div>
          <div style={{fontSize:'var(--fs-16)', fontWeight:600, letterSpacing:'-0.01em'}}>Switch store</div>
        </div>
        <button className="off-topbar-btn" onClick={() => setDrawer(null)}>
          <OIcon name="x"/>
        </button>
      </div>
      <div className="off-drawer-body">
        {storesLoading && <div style={{padding:'14px 16px', fontSize:'var(--fs-13)', color:'var(--text-subtle)'}}>Loading stores…</div>}
        {orgError && <div style={{padding:'14px 16px', fontSize:'var(--fs-13)', color:'var(--void-text)'}}>Couldn't load stores: {orgError}</div>}
        {!storesLoading && !orgError && stores.length === 0 && <div style={{padding:'14px 16px', fontSize:'var(--fs-13)', color:'var(--text-subtle)'}}>No stores found.</div>}
        {stores.map(s => (
          <div
            key={s.id}
            className={"off-drawer-row" + (scope === s.id ? " off-drawer-row--active" : "")}
            onClick={() => { setDrawer(null); switchStore(s); }}
          >
            <div className="off-topbar-store-av" style={{width:34, height:34, borderRadius:8}}>{s.code || "··"}</div>
            <div style={{flex:1}}>
              <div style={{fontWeight:500, fontSize:'var(--fs-14)'}}>{s.name}</div>
              <div style={{fontSize:'var(--fs-12)', color:'var(--text-subtle)'}}>{s.orgName} · live</div>
            </div>
            {scope === s.id && <OIcon name="check" style={{color:'var(--brand)'}}/>}
          </div>
        ))}
      </div>
    </div>
  );
}

// -----------------------------------------------------------------
// Toast stack
// -----------------------------------------------------------------
function OffToastStack() {
  const { toasts, dismissToast } = window.useOffice();
  return (
    <div className="toast-stack">
      {toasts.map(t => (
        <div key={t.id} className={"toast toast--" + (t.kind || "paid")}>
          <OIcon name={t.icon || "check-circle"} className="toast-icon"/>
          <div className="toast-body">
            <h4 className="toast-title">{t.title}</h4>
            {t.meta ? <p className="toast-meta">{t.meta}</p> : null}
          </div>
          <button className="toast-dismiss" onClick={() => dismissToast(t.id)} aria-label="Dismiss">
            <OIcon name="x" width={14} height={14}/>
          </button>
        </div>
      ))}
    </div>
  );
}

// -----------------------------------------------------------------
// Screen host
// -----------------------------------------------------------------
function OffScreenHost() {
  const { screen } = window.useOffice();
  const Comp = (window.OFFICE_SCREENS || {})[screen];
  if (!Comp) {
    return (
      <div className="off-screen">
        <header className="off-screen-header">
          <div className="off-screen-header-meta">
            <span className="off-screen-eyebrow">Loading</span>
            <h2 className="off-screen-title">{screen}</h2>
          </div>
        </header>
        <div className="off-screen-body">
          <div className="off-empty">
            <div className="empty-icon"><OIcon name="info" width={20} height={20}/></div>
            <div className="empty-title">Screen not registered yet</div>
          </div>
        </div>
      </div>
    );
  }
  return <Comp/>;
}

// -----------------------------------------------------------------
// App entry
// -----------------------------------------------------------------
function OfficeApp() {
  const [theme, setTheme] = oUseState(() => {
    try { return localStorage.getItem("coreiq-office-theme") || "light"; } catch (_) { return "light"; }
  });
  oUseEffect(() => {
    document.documentElement.setAttribute("data-theme", theme);
    try { localStorage.setItem("coreiq-office-theme", theme); } catch (_) {}
  }, [theme]);

  return (
    <OfficeProvider>
      <OfficeAppInner theme={theme} setTheme={setTheme}/>
    </OfficeProvider>
  );
}

function OfficeAppInner({ theme, setTheme }) {
  const { signedIn, drawer } = window.useOffice();
  if (!signedIn) return <SignIn/>;

  return (
    <>
      <div className="office-shell">
        <OffSidebar/>
        <main className="off-main">
          <OffTopbar/>
          <OffScreenHost/>
        </main>
        {drawer === "stores" && <StoreDrawer/>}
      </div>
      <OffToastStack/>
    </>
  );
}

// Mount
(function mount() {
  const node = document.getElementById("office-root");
  if (!node) { window.addEventListener("DOMContentLoaded", mount); return; }
  const root = ReactDOM.createRoot(node);
  root.render(<OfficeApp/>);
})();
