// ── Nav registry — the ONE list the icon rail renders from. Adding a view
//    means adding a row here; nothing else defines the app's navigation.
//    `badge` names a key in railBadges (computed per render) — badges show
//    things needing action, never raw totals.
const NAV_ITEMS = [
    { id: 'dashboard', icon: 'fa-tachometer-alt',      label: 'Dashboard' },
    { id: 'accounts',  icon: 'fa-building',            label: 'Accounts'  },
    { id: 'tasks',     icon: 'fa-tasks',               label: 'Tasks',  badge: 'tasks' },
    { id: 'leads',     icon: 'fa-inbox',               label: 'Leads',  badge: 'leads' },
    { id: 'billing',   icon: 'fa-file-invoice-dollar', label: 'Billing'   },
    { id: 'inventory', icon: 'fa-boxes',               label: 'Inventory' },
];

const MainApp = ({ currentUser, onLogout, appVersion }) => {
    const [showGlobalSearch, setShowGlobalSearch] = React.useState(false);
    const [searchTerm, setSearchTerm]             = React.useState('');
    const [selectedAccount, setSelectedAccount]   = React.useState(null);
    const [data, setData]                 = React.useState({ accounts: [], followUpTasks: [], followups: [], users: [], tags: [] });
    const [loadingData, setLoadingData]   = React.useState(true);
    const [showNewAccount, setShowNewAccount] = React.useState(false);
    // Workspace identity — name/letterhead/branding from GET /api/tenant.
    // Loaded once; Settings edits flow back through handleTenantChange so the
    // nav logo and custom CSS update live without a refresh.
    const [tenant, setTenant]                 = React.useState(null);
    // Land on Settings → Email automatically when returning from the OAuth
    // redirect (/api/email/callback bounces back to /?email=connected|declined|error).
    // Keep the flag's *value* too — the Email section uses it to tell the user
    // whether the connect actually worked (a silent bounce back to "Connect"
    // reads as success-then-amnesia when the server side actually failed).
    const [emailOAuthResult] = React.useState(() => {
        const flag = new URLSearchParams(window.location.search).get('email');
        if (flag) window.history.replaceState({}, '', '/'); // clean the URL so refresh doesn't re-trigger
        return flag; // 'connected' | 'declined' | 'error' | null
    });
    // accounts | dashboard | tasks | leads | billing | inventory | settings
    // Deep links: the URL is parsed once at boot (src/router.js) and seeds the
    // initial state; the sync effect below writes state → URL from then on.
    const initialRoute = React.useMemo(() => parseRoute(), []);
    const [currentView, setCurrentView] = React.useState(initialRoute.view || (emailOAuthResult ? 'settings' : 'tasks'));
    // Billing groups the old Quotes/Invoices nav tabs behind one button.
    const [billingTab, setBillingTabState] = React.useState(initialRoute.billingTab === 'invoices' ? 'invoices' : 'quotes');
    // Doc open in the global Billing view (modal). ref = human number (Q-…/INV-…).
    const [billingDoc, setBillingDoc] = React.useState(initialRoute.view === 'billing' ? initialRoute.doc : null);
    const setBillingTab = (tab) => { setBillingTabState(tab); setBillingDoc(null); };
    // The docked quote/invoice pane. Lives here (not in AccountDetailView)
    // so deep links can set account + doc together at boot.
    const [openDoc, setOpenDoc] = React.useState(null); // { kind: 'quote'|'invoice', id } | null — id is the human number when we have it

    // A doc pane belongs to the account it was opened from — switching (or
    // clearing) the account closes it. The ref suppresses exactly one clear:
    // a deep link / popstate that sets account + doc together.
    const keepDocOnNextAccountChange = React.useRef(false);
    React.useEffect(() => {
        if (keepDocOnNextAccountChange.current) { keepDocOnNextAccountChange.current = false; return; }
        setOpenDoc(null);
    }, [selectedAccount?.id]);

    // ── Deep links: boot + back/forward ───────────────────────────
    // Apply the account/doc part of a route (view/tab are plain setters).
    const applyAccountRoute = (route) => {
        if (route.view === 'accounts' && route.accountRef) {
            api.getAccount(route.accountRef).then(full => {
                keepDocOnNextAccountChange.current = true;
                setSelectedAccount(full);
                setOpenDoc(route.doc ? { kind: route.doc.kind, id: route.doc.ref } : null);
            }).catch(err => console.error('Deep-linked account load failed:', err));
        } else if (route.view === 'accounts') {
            setSelectedAccount(null);
        }
    };
    React.useEffect(() => { applyAccountRoute(initialRoute); }, []);
    React.useEffect(() => {
        const onPop = () => {
            const r = parseRoute();
            setCurrentView(r.view || 'tasks');
            setBillingTabState(r.billingTab === 'invoices' ? 'invoices' : 'quotes');
            setBillingDoc(r.view === 'billing' ? r.doc : null);
            applyAccountRoute(r);
        };
        window.addEventListener('popstate', onPop);
        return () => window.removeEventListener('popstate', onPop);
    }, []);

    // ── URL sync: state → address bar ─────────────────────────────
    // First run replaces (boot must not grow the back stack); later changes
    // push, so browser Back walks through views/accounts/docs naturally.
    const firstUrlSync = React.useRef(true);
    React.useEffect(() => {
        if (initialRoute.focus) return; // popout window: URL is fixed to its doc
        syncRoute({
            view: currentView,
            billingTab,
            accountRef: currentView === 'accounts' && selectedAccount
                ? (selectedAccount.customer_number || String(selectedAccount.id)) : null,
            doc: currentView === 'accounts'
                ? (openDoc ? { kind: openDoc.kind, ref: String(openDoc.id) } : null)
                : (currentView === 'billing' ? billingDoc : null),
        }, firstUrlSync.current);
        firstUrlSync.current = false;
    }, [currentView, billingTab, selectedAccount?.id, openDoc, billingDoc]);
    const [myAccountsOnly, setMyAccountsOnly] = React.useState(false);
    const [tagFilter, setTagFilter]           = React.useState([]); // selected tag ids — OR-match (account shows if it has ANY selected tag)
    const [isFullscreen, setIsFullscreen]     = React.useState(Boolean(document.fullscreenElement));

    // ── Theme: the account's saved theme wins over the local cache ───
    // (localStorage is just a pre-paint hint; the DB value is the truth,
    // so signing in on a new machine brings your theme with you.)
    React.useEffect(() => {
        if (currentUser.settings?.theme) applyTheme(currentUser.settings.theme);
    }, []);

    // ── Workspace branding ────────────────────────────────────────
    React.useEffect(() => {
        api.getTenant()
            .then(t => { setTenant(t); applyBranding(t.branding); })
            .catch(err => console.error('Tenant load failed:', err));
    }, []);

    const handleTenantChange = (t) => { setTenant(t); applyBranding(t.branding); };

    // ── Fullscreen ────────────────────────────────────────────────
    // Track via the browser event, not our own flag — Esc exits fullscreen
    // without ever touching our button, and the icon must follow reality.
    React.useEffect(() => {
        const handler = () => setIsFullscreen(Boolean(document.fullscreenElement));
        document.addEventListener('fullscreenchange', handler);
        return () => document.removeEventListener('fullscreenchange', handler);
    }, []);

    const toggleFullscreen = () => {
        if (document.fullscreenElement) document.exitFullscreen();
        else document.documentElement.requestFullscreen().catch(err => console.error('Fullscreen refused:', err));
    };

    React.useEffect(() => {
        const handler = (e) => { if ((e.ctrlKey || e.metaKey) && e.key === 'k') { e.preventDefault(); setShowGlobalSearch(s => !s); } };
        document.addEventListener('keydown', handler);
        return () => document.removeEventListener('keydown', handler);
    }, []);

    const [accountTotal, setAccountTotal] = React.useState(0);

    // Rail badge: leads awaiting review. Refetched on every view change —
    // promote/dismiss happen inside LeadsView, which this component can't
    // see, and one small GET per nav click is cheap enough to stay fresh.
    const [newLeadsCount, setNewLeadsCount] = React.useState(0);
    React.useEffect(() => {
        api.getLeads({ status: 'new' }).then(rows => setNewLeadsCount(rows.length)).catch(() => {});
    }, [currentView]);

    React.useEffect(() => { loadAll(); }, []);

    // Search-first account list: the server filters and pages; the browser
    // never holds the whole account table. Debounced so typing doesn't fire
    // a request per keystroke.
    const accountParams = () => {
        const params = { paged: 'true', limit: 100 };
        if (myAccountsOnly) params.mine = 'true';
        if (searchTerm.trim()) params.search = searchTerm.trim();
        if (tagFilter.length) params.tag_ids = tagFilter.join(',');
        return params;
    };

    // A failed accounts/tasks load must not render as "no accounts" — the
    // landing view is exactly where a rep would believe it (swallowed-error rule).
    const [dataLoadError, setDataLoadError] = React.useState(false);

    const loadAccounts = async () => {
        const { rows, total } = await api.getAccounts(accountParams());
        setData(p => ({ ...p, accounts: rows }));
        setAccountTotal(total);
        setDataLoadError(false);
    };

    React.useEffect(() => {
        if (loadingData) return;
        const t = setTimeout(() => { loadAccounts().catch(() => setDataLoadError(true)); }, 250);
        return () => clearTimeout(t);
    }, [myAccountsOnly, searchTerm, tagFilter]);

    // Refetch on view entry (owner's call 2026-08-10): the self-fetching views
    // (Dashboard/Billing/Inventory/Leads) remount and refetch on every nav
    // click already — Accounts and Tasks are MainApp-fed and went stale in a
    // long-lived tab. One GET per entry, same budget as the leads rail badge.
    // loadingData guard skips the mount firing (loadAll covers first load).
    React.useEffect(() => {
        if (loadingData) return;
        if (currentView === 'accounts') loadAccounts().catch(() => setDataLoadError(true));
        if (currentView === 'tasks') {
            Promise.all([api.getTasks({ completed: false }), api.getFollowups()])
                .then(([tasks, followups]) => { setData(p => ({ ...p, followUpTasks: tasks, followups })); setDataLoadError(false); })
                .catch(() => setDataLoadError(true));
        }
    }, [currentView]);

    const loadAll = async () => {
        setLoadingData(true);
        try {
            const isManager = currentUser.role === 'admin' || currentUser.role === 'manager';
            const [accountsPage, tasks, followups, users, tags] = await Promise.all([
                api.getAccounts(accountParams()),
                api.getTasks({ completed: false }),
                api.getFollowups(),
                isManager ? api.getUsers() : Promise.resolve([]),
                api.getTags(),
            ]);
            setData(p => ({ ...p, accounts: accountsPage.rows, followUpTasks: tasks, followups, users, tags }));
            setAccountTotal(accountsPage.total);
            setDataLoadError(false);
        } catch (err) {
            console.error('Failed to load data:', err);
            if (err.message.includes('token') || err.message.includes('401')) onLogout();
            else setDataLoadError(true);
        } finally {
            setLoadingData(false);
        }
    };

    const handleCreateAccount = async (formData) => {
        const account = await api.createAccount(formData);
        setData(p => ({ ...p, accounts: [...p.accounts, account] }));
        setShowNewAccount(false);
    };

    // signoff is present when the task requires it (TasksView collects it);
    // the server enforces the rule either way.
    const handleCompleteTask = async (taskId, signoff) => {
        await api.completeTask(taskId, signoff);
        setData(p => ({ ...p, followUpTasks: p.followUpTasks.filter(t => t.id !== taskId) }));
    };

    // Log-or-clear completion for a DERIVED follow-up (no task row exists):
    // optionally log the contact as a comm, then clear/advance the account's
    // callback_date — the date is the record, this just edits it.
    const handleCompleteFollowup = async ({ accountId, comm, nextDate }) => {
        if (comm) await api.createComm(comm);
        await api.updateAccount(accountId, { callback_date: nextDate || null });
        const followups = await api.getFollowups();
        setData(p => ({ ...p, followups }));
    };

    const handleUpdateTask = async (taskId, fd) => {
        await api.updateTask(taskId, fd);
        // Refetch rather than merge: the PATCH returns a bare row without the
        // joined account_name, and the edit may have moved the task.
        const tasks = await api.getTasks({ completed: false });
        setData(p => ({ ...p, followUpTasks: tasks }));
    };

    const handleDeleteTask = async (taskId) => {
        if (!window.confirm('Delete this task?')) return;
        await api.deleteTask(taskId);
        setData(p => ({ ...p, followUpTasks: p.followUpTasks.filter(t => t.id !== taskId) }));
    };

    const handleMergeAccount = async (sourceId, targetId) => {
        await api.mergeAccounts(sourceId, targetId);
        setSelectedAccount(null);
        await loadAll();
    };

    const handleSelectAccountFromSearch = async (accountStub) => {
        setCurrentView('accounts');
        setShowGlobalSearch(false);
        try {
            const full = await api.getAccount(accountStub.id);
            setSelectedAccount(full);
        } catch(e) { console.error(e); }
    };

    // Filtering happens server-side now (search + tags + mine, paged) —
    // data.accounts IS the filtered page.
    const filteredAccounts = data.accounts;

    // Rail badges — action counts only (owner's call 2026-08-09): tasks =
    // overdue + due today, leads = awaiting review. Never raw totals — a
    // badge that's always lit is noise.
    // Derived follow-ups count too (owner's call 2026-08-10): a due callback
    // is exactly the "action needed" signal the badge exists for.
    const tasksDueCount =
        data.followUpTasks.filter(t => ['overdue', 'today'].includes(getTaskStatusClass(t.due_date))).length
        + data.followups.filter(f => ['overdue', 'today'].includes(getTaskStatusClass(f.callback_date))).length;
    const railBadges = { tasks: tasksDueCount, leads: newLeadsCount };
    const viewTitle = currentView === 'settings' ? 'Settings'
        : (NAV_ITEMS.find(v => v.id === currentView)?.label || '');

    // ── Popout window mode (?focus=1 on a doc URL) ────────────────
    // Just the document, no app chrome — the compact floating window.
    // Placed after every hook so the hooks order never changes between modes.
    if (initialRoute.focus && initialRoute.doc) {
        document.title = `${initialRoute.doc.ref} — CRM`;
        return (
            <div className="focus-shell">
                <DocDetailModal
                    inline
                    allowPopout={false}
                    kind={initialRoute.doc.kind}
                    docId={initialRoute.doc.ref}
                    currentUser={currentUser}
                    onClose={() => window.close()}
                    onChanged={() => {}}
                />
            </div>
        );
    }

    return (
        <div className="crm-container">

            {/* ── Icon rail — the app's only nav (rail UI, 2026-08-09). Renders
                NAV_ITEMS so navigation can't drift from the registry. Real <a>
                links so cmd/middle-click opens a view in its own tab; plain
                click stays SPA (navClick, src/router.js). Settings/fullscreen/
                logout pin to the bottom — the old top-nav icon cluster. ── */}
            <nav className="rail">
                <div className="rail-logo" title={tenant?.name || 'CRM'}>
                    <img src={resolveTenantLogo(tenant?.branding, 'app') || '/assets/logo.svg'} alt={tenant?.name || 'CRM'} />
                </div>
                {NAV_ITEMS.map(v => {
                    const badge = v.badge ? railBadges[v.badge] : 0;
                    return (
                        <a key={v.id} href={routeUrl({ view: v.id, billingTab })}
                           className={`rail-btn ${currentView === v.id ? 'active' : ''}`}
                           data-tip={v.label} aria-label={v.label}
                           onClick={(e) => navClick(e, () => setCurrentView(v.id))}>
                            <i className={`fas ${v.icon}`}></i>
                            {badge > 0 && <span className="rail-badge">{badge > 99 ? '99+' : badge}</span>}
                        </a>
                    );
                })}
            </nav>

            <div className="main-col">

            <div className="topbar">
                <h1 className="topbar-title">{viewTitle}</h1>
                {currentView === 'accounts' && selectedAccount && (
                    <span className="topbar-crumb">/ {selectedAccount.name}</span>
                )}
                <button className="topbar-search" onClick={() => setShowGlobalSearch(true)} title="Search (Ctrl+K / ⌘K)">
                    <i className="fas fa-search"></i>
                    <span className="topbar-search-label">Search everything…</span>
                    <kbd className="topbar-search-kbd">⌘K</kbd>
                </button>
                {tenant?.name && <span className="nav-workspace-name">{tenant.name}</span>}
                {appVersion && <span className="nav-version" title="CRM version">v{appVersion}</span>}
                <div className="nav-user-chip" title={`${currentUser.first_name} ${currentUser.last_name} (${currentUser.role})`}>
                    <span className="nav-avatar">{currentUser.first_name[0]}{currentUser.last_name?.[0] || ''}</span>
                    <span className="nav-user-name">{currentUser.first_name}</span>
                    <span className="nav-role-tag">{currentUser.role}</span>
                </div>
                <button className="topbar-icon-btn" onClick={toggleFullscreen} title={isFullscreen ? 'Exit fullscreen' : 'Fullscreen'}>
                    <i className={`fas ${isFullscreen ? 'fa-compress' : 'fa-expand'}`}></i>
                </button>
                {/* One settings door for everyone — the role filter inside
                    SettingsView decides what each user sees. */}
                <button className={`topbar-icon-btn ${currentView === 'settings' ? 'active' : ''}`}
                        onClick={() => setCurrentView('settings')} title="Settings">
                    <i className="fas fa-cog"></i>
                </button>
                <button className="topbar-icon-btn" onClick={onLogout} title="Sign out">
                    <i className="fas fa-sign-out-alt"></i>
                </button>
            </div>

            {currentView === 'dashboard' && <DashboardView onSelectAccount={handleSelectAccountFromSearch} />}
            {/* No accounts prop on TasksView: data.accounts is the server-paged
                Accounts view page, not a lookup table — tasks carry
                account_name from their own API. */}
            {currentView === 'tasks'     && (
                <TasksView
                    tasks={data.followUpTasks}
                    followups={data.followups}
                    onCompleteFollowup={handleCompleteFollowup}
                    loadError={dataLoadError}
                    onRetryLoad={loadAll}
                    onSelectAccount={handleSelectAccountFromSearch}
                    onComplete={handleCompleteTask}
                    onDelete={handleDeleteTask}
                    onUpdateTask={handleUpdateTask}
                    onCreateTask={async (fd) => {
                        const task = await api.createTask(fd);
                        setData(p => ({ ...p, followUpTasks: [...p.followUpTasks, task] }));
                    }}
                />
            )}
            {currentView === 'inventory' && <ProductsView  currentUser={currentUser} />}
            {currentView === 'leads'     && <LeadsView     onSelectAccount={handleSelectAccountFromSearch} />}
            {currentView === 'billing'   && (
                <div className="billing-view">
                    <div className="billing-toggle">
                        <button className={`toggle-btn ${billingTab === 'quotes' ? 'active' : ''}`} onClick={() => setBillingTab('quotes')}>
                            <i className="fas fa-file-alt" style={{ marginRight: '0.25rem' }}></i>Quotes
                        </button>
                        <button className={`toggle-btn ${billingTab === 'invoices' ? 'active' : ''}`} onClick={() => setBillingTab('invoices')}>
                            <i className="fas fa-file-invoice-dollar" style={{ marginRight: '0.25rem' }}></i>Invoices
                        </button>
                    </div>
                    {billingTab === 'quotes'
                        ? <QuotesView   currentUser={currentUser}
                                        initialDetailId={billingDoc?.kind === 'quote' ? billingDoc.ref : null}
                                        onDetailChange={(ref) => setBillingDoc(ref ? { kind: 'quote', ref: String(ref) } : null)} />
                        : <InvoicesView currentUser={currentUser}
                                        initialDetailId={billingDoc?.kind === 'invoice' ? billingDoc.ref : null}
                                        onDetailChange={(ref) => setBillingDoc(ref ? { kind: 'invoice', ref: String(ref) } : null)} />}
                </div>
            )}
            {currentView === 'settings'  && (
                <SettingsView
                    currentUser={currentUser}
                    allTags={data.tags}
                    onTagsChange={() => api.getTags().then(tags => setData(p => ({ ...p, tags })))}
                    tenant={tenant}
                    onTenantChange={handleTenantChange}
                    initialSection={emailOAuthResult ? 'email' : null}
                    emailOAuthResult={emailOAuthResult}
                />
            )}

            {/* ── Accounts: the list IS the view (rail UI) — a full-width table
                landing; picking a row swaps to the full-width detail with Back.
                No side list pane anywhere (owner's call, 2026-08-09). ── */}
            {currentView === 'accounts' && (selectedAccount ? (
                <AccountDetailView
                    account={selectedAccount}
                    currentUser={currentUser}
                    openDoc={openDoc}
                    onOpenDoc={setOpenDoc}
                    allTags={data.tags}
                    allUsers={data.users}
                    onBack={() => setSelectedAccount(null)}
                    onOpenAccount={async (id) => {
                        try { setSelectedAccount(await api.getAccount(id)); }
                        catch (e) { console.error(e); }
                    }}
                    onAccountUpdate={(updated) => {
                        setData(p => ({ ...p, accounts: p.accounts.map(a => a.id === updated.id ? updated : a) }));
                        setSelectedAccount(updated);
                    }}
                    onAccountDelete={(id) => {
                        setData(p => ({ ...p, accounts: p.accounts.filter(a => a.id !== id) }));
                        setSelectedAccount(null);
                    }}
                    onMerge={handleMergeAccount}
                />
            ) : (
                <div className="accounts-landing">
                    <div className="accounts-toolbar">
                        <input
                            type="text"
                            className="search-box accounts-search"
                            placeholder="Search accounts…"
                            value={searchTerm}
                            onChange={(e) => setSearchTerm(e.target.value)}
                        />
                        {data.tags.map(t => {
                            const active = tagFilter.includes(t.id);
                            return (
                                <button
                                    key={t.id}
                                    className={`tag-pill tag-filter-chip ${active ? 'active' : ''}`}
                                    style={active
                                        ? { background: t.color, color: '#fff', border: `1px solid ${t.color}` }
                                        : { background: t.color + '22', color: t.color, border: `1px solid ${t.color}44` }}
                                    onClick={() => setTagFilter(p => active ? p.filter(id => id !== t.id) : [...p, t.id])}
                                    title={active ? `Stop filtering by ${t.name}` : `Show ${t.name} accounts`}
                                >
                                    {t.name}
                                </button>
                            );
                        })}
                        {tagFilter.length > 0 && (
                            <button className="tag-filter-clear" onClick={() => setTagFilter([])}>clear</button>
                        )}
                        {currentUser.role !== 'rep' && (
                            <div className="my-accounts-toggle accounts-toolbar-seg">
                                <button className={`toggle-btn ${myAccountsOnly ? 'active' : ''}`} onClick={() => setMyAccountsOnly(true)}>
                                    <i className="fas fa-user" style={{ marginRight: '0.25rem' }}></i>My
                                </button>
                                <button className={`toggle-btn ${!myAccountsOnly ? 'active' : ''}`} onClick={() => setMyAccountsOnly(false)}>
                                    <i className="fas fa-users" style={{ marginRight: '0.25rem' }}></i>All
                                </button>
                            </div>
                        )}
                        <button className="btn btn-primary" onClick={() => setShowNewAccount(true)}>
                            <i className="fas fa-plus"></i> New Account
                        </button>
                    </div>

                    {dataLoadError && !loadingData && (
                        <LoadErrorBanner what="accounts" hasData={filteredAccounts.length > 0} onRetry={loadAll} />
                    )}

                    {loadingData ? (
                        <div className="loading-state"><i className="fas fa-spinner fa-spin"></i> Loading…</div>
                    ) : filteredAccounts.length === 0 ? (
                        <div className="empty-state" style={{ marginTop: '3rem' }}>
                            <i className="fas fa-building empty-state-icon"></i>
                            <p className="empty-state-message">{searchTerm ? `No results for "${searchTerm}"` : tagFilter.length > 0 ? 'No accounts match the selected tags.' : 'No accounts yet.'}</p>
                        </div>
                    ) : (<>
                        {accountTotal > filteredAccounts.length && (
                            <div className="accounts-count-note">
                                Showing {filteredAccounts.length} of {accountTotal.toLocaleString()} — search to narrow
                            </div>
                        )}
                        <table className="data-table accounts-table">
                            <thead>
                                <tr>
                                    <th>Name</th>
                                    <th>Type</th>
                                    <th>Contact</th>
                                    <th>Status</th>
                                    <th>Rep</th>
                                </tr>
                            </thead>
                            <tbody>
                                {filteredAccounts.map(account => (
                                    <tr key={account.id} className="row-clickable" onClick={() => setSelectedAccount(account)}>
                                        <td>
                                            {/* Real link so cmd/middle-click opens the account
                                                in its own tab; plain click selects in-app. */}
                                            <a
                                                href={'/accounts/' + encodeURIComponent(account.customer_number || account.id)}
                                                className="doc-link accounts-table-name"
                                                onClick={(e) => { e.stopPropagation(); navClick(e, () => setSelectedAccount(account)); }}
                                            >
                                                {account.name}
                                            </a>
                                            {account.customer_number && (
                                                /* List view shows the bare number — the CUS- prefix
                                                   is noise at a glance; full number stays on the
                                                   detail view and pickers. */
                                                <span className="customer-number-badge" style={{ marginLeft: '0.5rem' }}>{account.customer_number.replace(/^CUS-/, '')}</span>
                                            )}
                                        </td>
                                        <td className="accounts-table-type">{account.type}</td>
                                        <td className="accounts-table-contact">
                                            {account.main_email || account.main_phone || '—'}
                                        </td>
                                        <td>
                                            <div className="accounts-table-status">
                                                {/* Stage is derived, never hand-set. */}
                                                {billingStage(account.billing_stage) && (
                                                    <span className={`badge stage-badge ${billingStage(account.billing_stage).cls}`}
                                                          title={billingStage(account.billing_stage).title}>
                                                        {billingStage(account.billing_stage).label}
                                                    </span>
                                                )}
                                                {account.urgent_task_count > 0 && (
                                                    <span className="badge urgent-flare"
                                                          title={`${account.urgent_task_count} urgent open task(s)`}>
                                                        <i className="fas fa-exclamation-circle"></i> {account.urgent_task_count}
                                                    </span>
                                                )}
                                                {/* Pipeline service pills only — manual tags show inside
                                                    the record. Muted tag treatment (owner's call): tinted
                                                    text + thin border, no solid fill. */}
                                                {pipelineTags(account.tags).map(t => (
                                                    <span key={t.id} className="badge service-pill"
                                                          style={{ color: t.color, borderColor: t.color + '55', background: t.color + '14' }}>
                                                        {pipelinePill(t).text}
                                                    </span>
                                                ))}
                                            </div>
                                        </td>
                                        <td className="accounts-table-rep">{account.assigned_to_name || '—'}</td>
                                    </tr>
                                ))}
                            </tbody>
                        </table>
                    </>)}
                </div>
            ))}

            </div>{/* /main-col */}

            <Modal isOpen={showNewAccount} onClose={() => setShowNewAccount(false)} title="Create New Account">
                <AccountForm onSubmit={handleCreateAccount} onCancel={() => setShowNewAccount(false)} />
            </Modal>

            {showGlobalSearch && (
                <GlobalSearch onClose={() => setShowGlobalSearch(false)} onSelectAccount={handleSelectAccountFromSearch} />
            )}

            <WhatsNewModal currentUser={currentUser} />
        </div>
    );
};
