// Shared icons (inline SVG, currentColor)
const Icon = ({ name, size = 20, ...rest }) => {
const paths = {
check: ,
arrow: ,
play: ,
spark: ,
users: ,
map: ,
coin: ,
chart: ,
shield: ,
clock: ,
pin: ,
zap: ,
doc: ,
cal: ,
bolt: ,
plug: ,
lock: ,
wave: ,
target: ,
layers: ,
heart: ,
globe: ,
};
return (
);
};
// Reveal-on-scroll
const Reveal = ({ children, delay = 0, as = 'div', className = '', style = {} }) => {
const ref = React.useRef(null);
React.useEffect(() => {
const el = ref.current;
if (!el) return;
const io = new IntersectionObserver(es => es.forEach(e => {
if (e.isIntersecting) { setTimeout(() => el.classList.add('is-in'), delay); io.unobserve(el); }
}), { threshold: 0.12 });
io.observe(el);
return () => io.disconnect();
}, [delay]);
const T = as;
return {children};
};
// CountUp number
const CountUp = ({ to, prefix = '', suffix = '', duration = 1600, decimals = 0 }) => {
const ref = React.useRef(null);
const [v, setV] = React.useState(0);
React.useEffect(() => {
const el = ref.current;
if (!el) return;
let started = false;
const io = new IntersectionObserver(es => es.forEach(e => {
if (e.isIntersecting && !started) {
started = true;
const start = performance.now();
const tick = (now) => {
const t = Math.min(1, (now - start) / duration);
const eased = 1 - Math.pow(1 - t, 3);
setV(to * eased);
if (t < 1) requestAnimationFrame(tick);
};
requestAnimationFrame(tick);
}
}), { threshold: 0.4 });
io.observe(el);
return () => io.disconnect();
}, [to, duration]);
const fmt = decimals > 0 ? v.toFixed(decimals) : Math.round(v).toLocaleString('en-IN');
return {prefix}{fmt}{suffix};
};
// Brand logo mark
const Logo = ({ size = 20 }) => (
);
// Top nav
const NavBar = ({ active = '' }) => {
const [scrolled, setScrolled] = React.useState(false);
React.useEffect(() => {
const onScroll = () => setScrolled(window.scrollY > 8);
window.addEventListener('scroll', onScroll);
return () => window.removeEventListener('scroll', onScroll);
}, []);
const [megaOpen, setMegaOpen] = React.useState(false);
const closeTimer = React.useRef(null);
const openMega = () => { clearTimeout(closeTimer.current); setMegaOpen(true); };
const closeMega = () => { closeTimer.current = setTimeout(() => setMegaOpen(false), 120); };
const [mobileOpen, setMobileOpen] = React.useState(false);
const closeMobile = () => setMobileOpen(false);
// Close mobile nav on resize to desktop
React.useEffect(() => {
const onResize = () => { if (window.innerWidth > 900) setMobileOpen(false); };
window.addEventListener('resize', onResize);
return () => window.removeEventListener('resize', onResize);
}, []);
return (
<>
{/* Mobile nav drawer */}
>
);
};
// Footer
const Footer = () => (
);
// Page hero (for inner pages)
const PageHero = ({ crumbs, eyebrow, title, sub, ctas, children }) => (
{crumbs.map((c, i) => (
{i > 0 && /}
{c.href ? {c.label} : {c.label}}
))}
{eyebrow &&
{eyebrow}}
{title}
{sub}
{ctas &&
{ctas}
}
{children &&
{children}
}
);
// CTA banner
const CTABanner = ({ title = "Ready to consolidate your stack?", sub = "Start a 30-day free trial. No credit card. Tally migration assistance included.", primary = "Start free trial", secondary = "Book a demo" }) => (
get started
{title}
{sub}
{/* decorative dots */}
);
// Logo strip
const LogoStrip = ({ label = "Trusted by 1,200+ teams" }) => (
{label}
ACME · Logistics
Surya Pharma
BlueWave
Nimbus Fin
Patel & Co.
Kavya Foods
);
// Mega-dropdown for Solutions
const SOLUTIONS = {
hrms: {
label: 'HCM',
items: [
{ slug: 'payroll', icon: 'coin', t: 'Payroll', d: 'Auto salary, statutory, payslips' },
{ slug: 'attendance', icon: 'cal', t: 'Attendance', d: 'Geo-fenced clock-ins, shifts' },
{ slug: 'leave', icon: 'wave', t: 'Leave management', d: 'Policies, balances, approvals' },
{ slug: 'reimbursement', icon: 'doc', t: 'Reimbursement', d: 'Claims, receipts, approvals' },
{ slug: 'assets', icon: 'layers', t: 'Assets management', d: 'Laptops, devices, allocations' },
{ slug: 'tasks', icon: 'target', t: 'Task — todos', d: 'Daily tasks, SLAs, reminders' },
{ slug: 'letters', icon: 'doc', t: 'Letter generation', d: 'Offer, appraisal, experience' },
]
},
finance: {
label: 'Finance & Accounting',
items: [
{ slug: 'invoice', icon: 'doc', t: 'Invoice', d: 'GST, multi-currency, e-invoice' },
{ slug: 'bank-statement', icon: 'chart', t: 'Bank statement upload', d: 'Auto-parse PDF/CSV/XLSX' },
{ slug: 'expense-payment', icon: 'coin', t: 'Expense & Payment', d: 'Bills, vendor payouts, UPI' },
{ slug: 'reconciliation', icon: 'plug', t: 'Reconciliation', d: 'Bank ↔ ledger auto-match' },
]
},
ffa: {
label: 'Field Force',
items: [
{ slug: 'routes', icon: 'pin', t: 'Track routes', d: 'GPS breadcrumb trail' },
{ slug: 'ffa-reimburse', icon: 'coin', t: 'Reimbursement', d: 'Travel, food, fuel claims' },
{ slug: 'ffa-attendance', icon: 'cal', t: 'Attendance', d: 'Geo-tagged start/end day' },
{ slug: 'visits', icon: 'check', t: 'Visits', d: 'Photo + GPS proof' },
{ slug: 'collection', icon: 'coin', t: 'Collection', d: 'Cash & cheque tracking' },
{ slug: 'party-master', icon: 'users', t: 'Party master', d: 'Customer & vendor database' },
{ slug: 'route-plan', icon: 'map', t: 'Routes plan', d: 'Auto-optimized beat plans' },
{ slug: 'mis', icon: 'chart', t: 'MIS report', d: 'Daily/weekly snapshots' },
{ slug: 'complaint', icon: 'bolt', t: 'Complaint', d: 'Ticket Kanban with SLA' },
]
},
soon: {
label: 'Coming soon',
items: [
{ slug: 'performance', icon: 'target', t: 'Performance', d: 'KRA/KPI, 1:1, appraisals', soon: true },
{ slug: 'ats', icon: 'users', t: 'ATS', d: 'AI screening, interviews', soon: true },
{ slug: 'time-tracking', icon: 'clock', t: 'Time tracking', d: 'Timesheets, billable hrs', soon: true },
]
},
};
const SolutionsMega = ({ open }) => (
{['hrms', 'finance', 'ffa'].map(g => (
{SOLUTIONS[g].label}
{SOLUTIONS[g].items.map(it => (
))}
))}
{SOLUTIONS.soon.label}
{SOLUTIONS.soon.items.map(it => (
))}
All modules. One price.
Per-employee billing, no add-on fees, free Tally migration.
See pricing →
);
Object.assign(window, { Icon, Reveal, CountUp, Logo, NavBar, Footer, PageHero, CTABanner, LogoStrip, SOLUTIONS, SolutionsMega });