'use client';
import { useState } from 'react';
import { usePathname } from 'next/navigation';
/**
* VYNDR 2.0 mobile tab bar (§6, Session 37). The PWA's primary navigation —
* 5 tabs: Slate · Explore · Scan · Ledger · More. Scan is prominent (raised,
* grade-green) because it's the core action. More opens a bottom sheet with
* every secondary route. Hidden ≥768px via globals.css (.mobile-tab-bar).
*
* Session 57 (Phase 0): the Terminal tab is gone — that surface was fabricated
* and now redirects to /dashboard. Explore (real graded-props browser) takes
* its slot so the bar keeps 5 tabs.
*
* Shown for everyone (anon included): Slate/Explore/Scan are open routes and
* this is the only mobile nav. Gated routes (Ledger, Account…) bounce through
* the client AuthGate when an anon user taps them.
*/
type TabDef = {
id: string;
label: string;
icon: React.ComponentType<{ color: string }>;
href?: string;
primary?: boolean;
isSheet?: boolean;
};
const TABS: TabDef[] = [
{ id: 'slate', label: 'Slate', href: '/dashboard', icon: SlateIcon },
{ id: 'explore', label: 'Explore', href: '/explore', icon: ExploreIcon },
{ id: 'scan', label: 'Scan', href: '/scan', icon: ScanIcon, primary: true },
{ id: 'ledger', label: 'Ledger', href: '/ledger', icon: LedgerIcon },
{ id: 'more', label: 'More', icon: MoreIcon, isSheet: true },
];
const MORE_ITEMS = [
{ label: 'Compare', href: '/compare' },
{ label: 'Tracker', href: '/tracker' },
{ label: 'The Report', href: '/blog' },
{ label: 'Invite Friends', href: '/invite' },
{ label: 'Pricing', href: '/pricing' },
{ label: 'Account', href: '/account' },
{ label: 'Settings', href: '/settings/security' },
{ label: 'Help & FAQ', href: '/help' },
{ label: 'About', href: '/about' },
{ label: 'Responsible Play', href: '/responsible-gambling' },
];
// Auth flows own the full screen — no app chrome.
// Session 59 (work-order 3.1) — '/' REMOVED from this set. Hiding the bar on
// the landing left anonymous phones with ZERO navigation (the desktop links
// hide <768px and the hamburger was retired in S37) — the audit's vanished-
// nav-at-390px finding. The tab bar is the only mobile nav; it shows
// everywhere except true auth flows.
const HIDE_ON = new Set(['/login', '/signup', '/auth/callback']);
function isActive(pathname: string, href?: string) {
if (!href) return false;
return pathname === href || pathname.startsWith(`${href}/`);
}
export default function BottomTabBar() {
const pathname = usePathname() || '/';
const [moreOpen, setMoreOpen] = useState(false);
if (HIDE_ON.has(pathname)) return null;
return (
<>
{/* More bottom sheet */}
{moreOpen && (
setMoreOpen(false)}
style={{ position: 'fixed', inset: 0, zIndex: 60, background: 'rgba(6,6,11,.6)', backdropFilter: 'blur(3px)', WebkitBackdropFilter: 'blur(3px)', display: 'flex', flexDirection: 'column', justifyContent: 'flex-end' }}
>
e.stopPropagation()}
className="sheet-up scanlines"
style={{ background: 'var(--bg-1)', borderTop: '1px solid var(--border-hi)', borderRadius: '18px 18px 0 0', maxHeight: '82%', overflowY: 'auto', paddingBottom: 'calc(16px + env(safe-area-inset-bottom, 0px))' }}
>
MORE
{/* S6 (A1 board) — global search, first item in the sheet.
Same modal as ⌘K / the Nav icon (window.__search). */}
{MORE_ITEMS.map((it) => (
setMoreOpen(false)}
className="mono"
style={{
display: 'flex',
alignItems: 'center',
justifyContent: 'space-between',
minHeight: 48,
padding: '0 18px',
color: isActive(pathname, it.href) ? 'var(--g-a)' : 'var(--text-0)',
textDecoration: 'none',
fontSize: 13,
fontWeight: 700,
letterSpacing: '0.06em',
textTransform: 'uppercase',
borderBottom: '1px solid var(--border)',
}}
>
{it.label}
›
))}
)}
>
);
}
/* ── inline SVG icons (slim, no icon lib) ── */
function SlateIcon({ color }: { color: string }) {
return (
);
}
function ExploreIcon({ color }: { color: string }) {
return (
);
}
function ScanIcon({ color }: { color: string }) {
return (
);
}
function LedgerIcon({ color }: { color: string }) {
return (
);
}
function MoreIcon({ color }: { color: string }) {
return (
);
}