Theme tokens
Colours are CSS variables on :root in src/app/globals.css. No Tailwind plugin remaps them; they are used verbatim via var(--accent) or via Tailwind arbitrary values like text-[var(--text-dim)]. This keeps the design system coherent across server components, client components, and inline style= props.
:root {
/* Backgrounds */
--bg: #0E0D0B;
--bg-card: #181612;
--bg-elevated: #211E1A;
--bg-deep: #0C0A08;
--bg-chat: #1A1714;
--bg-chat-header: #141210;
/* Text */
--text: #F2EDE4;
--text-dim: rgba(242,237,228,0.6);
--text-muted: rgba(242,237,228,0.35);
/* Accent (orange) */
--accent: #E8601C;
--accent-hover: #D4560F;
--accent-light: rgba(232,96,28,0.12);
--accent-glow: rgba(232,96,28,0.15);
/* Semantic */
--green: #4A9960;
--green-dim: rgba(74,153,96,0.15);
--info: #428BFF;
--info-dim: rgba(66,139,255,0.15);
--error: #C13515;
/* Borders */
--border: rgba(242,237,228,0.08);
--border-mid: rgba(242,237,228,0.15);
--border-strong: rgba(242,237,228,0.25);
}Fonts
- Display / body — Geist Sans via
next/font/google, exposed asvar(--font-geist-sans) - Mono— JetBrains Mono, used for eyebrow labels, stat numbers, and code blocks. Exposed as
var(--font-jetbrains)
Motion primitives
Motion constants are the single source of truth for animation timing. Every reveal, hover, and stagger uses these values. Hard-coding a duration or an ease curve is treated as a bug.
// src/lib/motion.ts
export const ease = {
default: [0.25, 0.46, 0.45, 0.94] as const, // smooth deceleration
out: [0.22, 1, 0.36, 1] as const, // springy / snappy
inOut: [0.76, 0, 0.24, 1] as const, // symmetric
};
export const duration = {
fast: 0.2, // press, toggle, hover
normal: 0.4, // standard UI transitions
reveal: 0.6, // section reveals, hero entrances
slow: 0.8, // dramatic reveals
};
export const stagger = {
fast: 0.04,
normal: 0.08,
slow: 0.12,
};
export const hover = {
lift: { y: -4, transition: { duration: 0.25, ease: ease.out } },
liftSm: { y: -2, transition: { duration: 0.2, ease: ease.out } },
};Motion components
Framer-motion is wrapped in three small components under src/components/motion/so callers don't repeat the same variant boilerplate:
<Reveal>— scroll-triggered fade + translate. Props:direction,delay,distance,once.<StaggerGroup>+<StaggerItem>— stagger children with an optional hover lift.<ParallaxLayer>— scroll parallax (auto-disabled on touch devices).<CountUp>— number counter triggered on intersection with a cubic ease-out.<HoverCard>— card with lift + glow micro-interaction.
import { Reveal, StaggerGroup, StaggerItem } from "@/components/motion";
// Simple fade-in on scroll
<Reveal direction="up" delay={0.1}>
<h2>A section heading</h2>
</Reveal>
// Staggered grid with hover lift on each card
<StaggerGroup className="grid grid-cols-3 gap-4">
{items.map(item => (
<StaggerItem key={item.id} hoverLift="lift">
<Card {...item} />
</StaggerItem>
))}
</StaggerGroup>Trust components
The src/components/trust/ directory holds reusable social-proof primitives that any marketing or docs page can drop in:
| Component | Purpose |
|---|---|
<FAQ> | Accordion with AnimatePresence, Plus icon rotation, and keyboard support. Pass items as an array of { q, a }. |
<Testimonials> | Three-card grid with quote, author, role, venue, and initial avatar. Ships with three verified venue owner testimonials. |
<LogoBar> | Scrolling venue logo marquee. Uses Google's favicon service so no assets are shipped. |
<ComparisonMatrix> | Feature comparison table with a featured column (AGNT) highlighted in accent. |
<TranslationDemo> | Animated multi-language reply demo used on the for-businesses page. |
Docs components
This docs site is built from its own small component set under src/components/docs/:
DocsShell— three-column layout: sidebar, main, right-hand TOCDocsSidebar— tree nav driven bynav.tsDocsBreadcrumb— server-rendered breadcrumbDocsPager— prev / next footerDocsTOC— on-page scrollspy driven by IntersectionObserverDocsCallout— note / tip / warning / success / importantDocsCode— code block with language badge + copy buttonDocsProse— article wrapper with baseline typographyDocsPageHeader— consistent eyebrow + H1 + lead
Marketing chrome
MarketingNav, MarketingFooter, and AmbientBackground live in src/components/marketing/. Every public page wraps its content in that chrome. The footer is hand-curated and should not be touched without coordination — the 20 links it holds are the site's navigation contract.