Files
zeekay cb6db9e659 design: every page and component outside the landing and beta paths is at zero lint
Inline style objects became gui props (Box for a div, View or Text rendering the
element for the rest, since Box styles only a div), raw colours and sizes became
the design's tokens, the brand swatches read @hanzo/design's own values, and the
project and creation hues moved to palette.json, which is data. The newsletter's
subscribe button is the standard filled Action. connect-steps.tsx, which nothing
imports, is deleted with the brand constants nobody read.

Pages compared before and after at 1440x900 and 390x844: blockchain, brand,
directory, projects, settings, unsubscribe identical; founder 0.03% of pixels;
buying specialist's title snaps from 28 to the ramp's 26px and the newsletter's
button is now filled.

Claude-Session: https://claude.ai/code/session_017vrVus6PPBgP5YRzKV1iqW
2026-10-26 03:49:42 -07:00

759 lines
32 KiB
TypeScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
'use client'
import { Box, Text, View } from '@hanzo/ui'
import { useEffect, useRef, useState, type FormEvent } from 'react'
import Link from 'next/link'
import { ArrowLeft, ArrowUp, Sparkles, Users } from 'lucide-react'
import { useIam } from '@hanzo/iam/react'
import { useQuery } from '@/lib/auth/query'
interface Message {
id: string
role: 'user' | 'assistant'
content: string
quote?: {
plan: string
seats?: number
standardSeats?: number
premiumSeats?: number
monthlyTotal: number
annualTotal: number
savings: number
checkoutUrl?: string
contactSales?: boolean
}
}
/** Symmetrical neural network tree icon matching the specialist branding. */
function SpecialistIcon({ size = 56 }: { size?: number }) {
return (
<svg width={size} height={size} viewBox="0 0 64 64" fill="none" xmlns="http://www.w3.org/2000/svg" aria-hidden="true">
{/* Central vertical stem */}
<line x1="32" y1="16" x2="32" y2="48" stroke="currentColor" strokeWidth="2" strokeLinecap="round" />
{/* Hexagonal branched network */}
<path d="M 32 20 L 20 27 L 20 41 L 32 47 L 44 41 L 44 27 Z" stroke="currentColor" strokeWidth="2" strokeLinejoin="round" />
<line x1="32" y1="33" x2="20" y2="27" stroke="currentColor" strokeWidth="2" />
<line x1="32" y1="33" x2="44" y2="27" stroke="currentColor" strokeWidth="2" />
<line x1="32" y1="33" x2="20" y2="41" stroke="currentColor" strokeWidth="2" />
<line x1="32" y1="33" x2="44" y2="41" stroke="currentColor" strokeWidth="2" />
{/* Nodes */}
<circle cx="32" cy="14" r="3.5" stroke="currentColor" strokeWidth="2" fill="var(--background, #111113)" />
<circle cx="32" cy="33" r="3" stroke="currentColor" strokeWidth="2" fill="var(--background, #111113)" />
<circle cx="32" cy="50" r="3.5" stroke="currentColor" strokeWidth="2" fill="var(--background, #111113)" />
<circle cx="20" cy="27" r="3" stroke="currentColor" strokeWidth="2" fill="var(--background, #111113)" />
<circle cx="44" cy="27" r="3" stroke="currentColor" strokeWidth="2" fill="var(--background, #111113)" />
<circle cx="20" cy="41" r="3" stroke="currentColor" strokeWidth="2" fill="var(--background, #111113)" />
<circle cx="44" cy="41" r="3" stroke="currentColor" strokeWidth="2" fill="var(--background, #111113)" />
</svg>
)
}
/** Formats simple markdown (bold, lists, links) into clean JSX elements. */
function FormattedText({ text }: { text: string }) {
const paragraphs = text.split('\n\n')
return (
<Box display="flex" flexDirection="column" gap={12}>
{paragraphs.map((p, pIdx) => {
const lines = p.split('\n')
const isList = lines.every((l) => l.trim().startsWith('- ') || l.trim().startsWith('* '))
if (isList) {
return (
<View
key={pIdx}
render="ul"
m={0}
pl={20}
display="flex"
flexDirection="column"
gap={6}
>
{lines.map((l, lIdx) => {
const clean = l.replace(/^[-*]\s+/, '')
return <li key={lIdx} dangerouslySetInnerHTML={{ __html: parseInline(clean) }} />
})}
</View>
)
}
return <View
key={pIdx}
render={<p dangerouslySetInnerHTML={{ __html: parseInline(p) }} />}
display="block"
m={0}
$platform-web={{ lineHeight: "1.6" }}
/>
})}
</Box>
)
}
function parseInline(str: string): string {
return str
.replace(/\*\*(.*?)\*\*/g, '<strong>$1</strong>')
.replace(/\*(.*?)\*/g, '<em>$1</em>')
.replace(/`(.*?)`/g, '<code style="background:var(--white-08);padding:2px 6px;border-radius:4px;font-family:monospace;font-size:0.9em;">$1</code>')
}
export default function BuyingSpecialistPage() {
const query = useQuery()
const { user } = useIam()
// Display name from account, query param, or fallback to Zach (matching the prompt screenshot)
const name = (query.get('name') || user?.name || 'Zach').trim()
const initials = user?.name
? user.name.split(' ').map((n) => n[0]).join('').slice(0, 2).toUpperCase()
: user?.email
? user.email.slice(0, 2).toUpperCase()
: 'ZK'
const [input, setInput] = useState('')
const [messages, setMessages] = useState<Message[]>([])
const [isThinking, setIsThinking] = useState(false)
const messagesEndRef = useRef<HTMLDivElement>(null)
const inputRef = useRef<HTMLInputElement>(null)
const isChatting = messages.length > 0
useEffect(() => {
messagesEndRef.current?.scrollIntoView({ behavior: 'smooth' })
}, [messages, isThinking])
const handleStart = (initialText?: string) => {
const userPrompt = initialText || input.trim() || 'Hi! Can you help me find the right plan for my team?'
setInput('')
const userMessage: Message = {
id: String(Date.now()),
role: 'user',
content: userPrompt,
}
setMessages((prev) => [...prev, userMessage])
setIsThinking(true)
setTimeout(() => {
const response = generateAssistantResponse(userPrompt, name)
setMessages((prev) => [...prev, response])
setIsThinking(false)
}, 700)
}
const handleSubmit = (e: FormEvent) => {
e.preventDefault()
if (!input.trim() && !isChatting) {
handleStart()
return
}
if (!input.trim()) return
const userPrompt = input.trim()
setInput('')
const userMessage: Message = {
id: String(Date.now()),
role: 'user',
content: userPrompt,
}
setMessages((prev) => [...prev, userMessage])
setIsThinking(true)
setTimeout(() => {
const response = generateAssistantResponse(userPrompt, name)
setMessages((prev) => [...prev, response])
setIsThinking(false)
}, 800)
}
return (
<Box
minH="100vh"
bg="var(--surface-card)"
display="flex"
flexDirection="column"
$platform-web={{ fontFamily: "var(--font-body, system-ui, -apple-system, sans-serif)", color: "var(--foreground)" }}
>
{/* Top Navbar */}
<View
render="header"
position="sticky"
t={0}
z="var(--z-dock)"
height={56}
borderBottomWidth={1}
borderBottomColor="var(--white-08)"
display="flex"
items="center"
justify="space-between"
py={0}
px={20}
flexDirection="row"
bg="transparent"
$platform-web={{ backdropFilter: "blur(12px)" }}
>
<Text
render={<Link href="/pricing" onMouseEnter={(e) => (e.currentTarget.style.color = 'var(--foreground)')} onMouseLeave={(e) => (e.currentTarget.style.color = 'var(--muted-foreground)')} />}
items="center"
gap={8}
color="var(--muted-foreground)"
textDecorationLine="none"
fontSize="$3"
fontWeight="500"
$platform-web={{ display: "inline-flex", transition: "color 0.15s ease", flexDirection: "row" }}
>
<ArrowLeft size={16} />
Return to Hanzo
</Text>
<Text fontSize="$3" fontWeight="600" color="var(--foreground)">
Buying specialist
</Text>
<Box
title={name}
width={32}
height={32}
rounded={9999}
bg="var(--art-iris)"
display="flex"
items="center"
justify="center"
flexDirection="row"
$platform-web={{ letterSpacing: "0.5px", color: "var(--foreground)", fontSize: "var(--text-xs)", fontWeight: "700" }}
>
{initials}
</Box>
</View>
{/* Main Body */}
<View
render="main"
flex={1}
display="flex"
flexDirection="column"
items="center"
width="100%"
maxW={680}
my={0}
mx="auto"
pt={isChatting ? 24 : 48}
px={20}
pb={140}
$platform-web={{ boxSizing: "border-box" }}
>
{!isChatting ? (
<Box display="flex" flexDirection="column" items="center" width="100%" gap={24}>
{/* Specialist Icon */}
<Box mt={12} $platform-web={{ color: "var(--neutral-300)" }}>
<SpecialistIcon size={56} />
</Box>
{/* Title & Introduction */}
<Box
display="flex"
flexDirection="column"
gap={12}
$platform-web={{ textAlign: "center" }}
>
<Text
render="h1"
display="block"
fontSize="$8"
fontWeight="600"
color="var(--foreground)"
m={0}
$platform-web={{ lineHeight: "1.25", letterSpacing: "-0.02em" }}
>
Hi {name}, let&apos;s find the right plan for your team.
</Text>
<Text
render="p"
display="block"
fontSize="$4"
color="var(--muted-foreground)"
m={0}
maxW={560}
$platform-web={{ lineHeight: "1.55" }}
>
I&apos;m an AI buying specialist, here to help you figure out which plan fits, what it&apos;ll cost, and how to get your team set up. We can do all of it right here.
</Text>
</Box>
{/* Value Proposition List */}
<View
render="ul"
width="100%"
mt={12}
mx={0}
mb={0}
pt={0}
pr={0}
pb={0}
pl={20}
display="flex"
flexDirection="column"
gap={14}
$platform-web={{ lineHeight: "1.55", color: "var(--neutral-300)", fontSize: "var(--text-base)" }}
>
<li>
<Text render="strong" color="var(--foreground)">The fastest path in.</Text> You&apos;ll have a quote and a plan by the end of this conversation.
</li>
<li>
<Text render="strong" color="var(--foreground)">The best price you&apos;ll get.</Text> I&apos;ll check for our latest pricing.
</li>
<li>
<Text render="strong" color="var(--foreground)">I already know your account.</Text> If you&apos;re using Hanzo, I can see your current plan, seats, and usage.
</li>
<li>
<Text render="strong" color="var(--foreground)">Free to talk.</Text> This conversation doesn&apos;t count toward your usage.
</li>
<li>
<Text render="strong" color="var(--foreground)">A sales rep if you want one.</Text> For complex or large deals, I&apos;ll hand you to a teammate with everything you&apos;ve shared already in context.
</li>
<li>
<Text render="strong" color="var(--foreground)">Nothing sensitive needed.</Text> I can find the right plan with some basic information. Please keep confidential details out of chat.
</li>
</View>
{/* Privacy Box */}
<Box
width="100%"
py={14}
px={18}
rounded={12}
borderWidth={1}
borderColor="var(--white-08)"
bg="var(--white-03)"
mt={8}
$platform-web={{ boxSizing: "border-box", fontSize: "var(--text-sm)", color: "var(--muted-foreground)", textAlign: "left" }}
>
By continuing, you agree to our{' '}
<Text
render={<Link href="/privacy" />}
display="inline"
color="var(--muted-foreground)"
textDecorationLine="underline"
>
Privacy Policy
</Text>
.
</Box>
{/* Starter Suggestions */}
<Box width="100%" display="flex" flexWrap="wrap" gap={8} mt={12} flexDirection="row">
{[
'We have a team of 10 developers',
'Explain Standard vs Premium seats',
'Looking for dedicated VPC & HIPAA',
'Compare Team vs Enterprise',
].map((suggestion) => (
<View
key={suggestion}
render={<button type="button" onClick={() => handleStart(suggestion)} onMouseEnter={(e) => {
e.currentTarget.style.backgroundColor = 'var(--white-08)'
e.currentTarget.style.borderColor = 'var(--white-20)'
e.currentTarget.style.color = 'var(--foreground)'
}} onMouseLeave={(e) => {
e.currentTarget.style.backgroundColor = 'var(--white-03)'
e.currentTarget.style.borderColor = 'var(--white-08)'
e.currentTarget.style.color = 'var(--neutral-300)'
}} />}
bg="var(--white-03)"
borderWidth={1}
borderColor="var(--white-08)"
py={8}
px={14}
rounded={9999}
cursor="pointer"
$platform-web={{ transition: "all 0.15s ease", color: "var(--neutral-300)", fontSize: "var(--text-sm)", display: "inline-block" }}
>
{suggestion} →
</View>
))}
</Box>
</Box>
) : (
/* Conversational Chat View */
<Box width="100%" display="flex" flexDirection="column" gap={20}>
{messages.map((m) => (
<Box
key={m.id}
display="flex"
flexDirection="column"
width="100%"
$platform-web={{ alignItems: m.role === 'user' ? 'flex-end' : 'flex-start' }}
>
{m.role === 'assistant' ? (
<Box display="flex" gap={12} items="flex-start" maxW="100%" flexDirection="row">
<Box
width={32}
height={32}
rounded={9999}
bg="var(--white-08)"
borderWidth={1}
borderColor="var(--white-10)"
display="flex"
items="center"
justify="center"
shrink={0}
mt={2}
flexDirection="row"
$platform-web={{ color: "var(--neutral-300)" }}
>
<Sparkles size={16} />
</Box>
<Box display="flex" flexDirection="column" gap={14} flex={1}>
<Box
bg="var(--white-03)"
borderWidth={1}
borderColor="var(--white-08)"
rounded={16}
py={16}
px={20}
$platform-web={{ lineHeight: "1.6", color: "var(--foreground)", fontSize: "var(--text-lg)" }}
>
<FormattedText text={m.content} />
</Box>
{/* Interactive Quote Card if present */}
{m.quote ? (
<Box
rounded={16}
p={20}
display="flex"
flexDirection="column"
gap={14}
$platform-web={{ borderWidth: "1px", borderStyle: "solid", borderColor: "color-mix(in srgb, var(--art-iris) 35%, transparent)", backgroundColor: "color-mix(in srgb, var(--art-iris) 6%, transparent)" }}
>
<Box
display="flex"
justify="space-between"
items="center"
flexDirection="row"
>
<Box display="flex" items="center" gap={8} flexDirection="row">
<Users size={18} color="var(--art-iris)" />
<Text render="strong" fontSize="$4" color="var(--foreground)">
{m.quote.plan} Configuration
</Text>
</Box>
<Text
fontSize="$1"
fontWeight="700"
py={3}
px={8}
rounded={9999}
color="var(--state-success)"
$platform-web={{ backgroundColor: "color-mix(in srgb, var(--state-success) 20%, transparent)" }}
>
SAVE {m.quote.savings}% ANNUALLY
</Text>
</Box>
<Box
gap={12}
$platform-web={{ display: "grid", gridTemplateColumns: "repeat(auto-fit, minmax(180px, 1fr))" }}
>
<Box
py={12}
px={14}
rounded={12}
bg="var(--white-03)"
borderWidth={1}
borderColor="var(--white-08)"
>
<Box
$platform-web={{ fontSize: "var(--text-xs)", color: "var(--muted-foreground)" }}
>Annual Rate (Recommended)</Box>
<Box
mt={4}
$platform-web={{ fontSize: "var(--text-2xl)", fontWeight: "700", color: "var(--foreground)" }}
>
${m.quote.annualTotal / 12}
<Text
fontSize="$1"
fontWeight="400"
color="var(--muted-foreground)"
>/mo</Text>
</Box>
<Box
mt={2}
$platform-web={{ fontSize: "var(--text-xs)", color: "var(--muted-foreground)" }}
>
Billed ${m.quote.annualTotal} annually upfront
</Box>
</Box>
<Box
py={12}
px={14}
rounded={12}
bg="var(--white-03)"
borderWidth={1}
borderColor="var(--white-06)"
>
<Box
$platform-web={{ fontSize: "var(--text-xs)", color: "var(--muted-foreground)" }}
>Monthly Rate</Box>
<Box
mt={4}
$platform-web={{ fontSize: "var(--text-2xl)", fontWeight: "700", color: "var(--foreground)" }}
>
${m.quote.monthlyTotal}
<Text
fontSize="$1"
fontWeight="400"
color="var(--muted-foreground)"
>/mo</Text>
</Box>
<Box
mt={2}
$platform-web={{ fontSize: "var(--text-xs)", color: "var(--muted-foreground)" }}
>
Cancel anytime
</Box>
</Box>
</Box>
<Box display="flex" gap={10} mt={4} flexWrap="wrap" flexDirection="row">
{m.quote.checkoutUrl ? (
<Text
render={<Link href={m.quote.checkoutUrl} />}
flex={1}
minW={180}
py={10}
px={18}
rounded={9999}
bg="var(--foreground)"
color="var(--background)"
fontWeight="600"
fontSize="$2"
text="center"
textDecorationLine="none"
items="center"
justify="center"
gap={6}
$platform-web={{ display: "inline-flex", flexDirection: "row" }}
>
Continue with {m.quote.plan} →
</Text>
) : null}
<Text
render={<Link href="/contact-sales" />}
py={10}
px={18}
rounded={9999}
borderWidth={1}
borderColor="var(--white-20)"
color="var(--foreground)"
fontWeight="500"
fontSize="$2"
textDecorationLine="none"
items="center"
gap={6}
$platform-web={{ display: "inline-flex", flexDirection: "row" }}
>
Talk to Sales Team
</Text>
</Box>
</Box>
) : null}
</Box>
</Box>
) : (
/* User message */
<Box
maxW="85%"
bg="var(--border)"
rounded={16}
py={12}
px={18}
borderWidth={1}
borderColor="var(--white-08)"
$platform-web={{ lineHeight: "1.5", color: "var(--foreground)", fontSize: "var(--text-lg)" }}
>
{m.content}
</Box>
)}
</Box>
))}
{isThinking ? (
<Box
display="flex"
gap={12}
items="center"
flexDirection="row"
$platform-web={{ color: "var(--muted-foreground)", fontSize: "var(--text-sm)" }}
>
<Box
width={32}
height={32}
rounded={9999}
bg="var(--white-06)"
display="flex"
items="center"
justify="center"
flexDirection="row"
>
<Sparkles size={16} />
</Box>
<span>Finding the best plan for your team...</span>
</Box>
) : null}
<div ref={messagesEndRef} />
</Box>
)}
</View>
{/* Fixed Bottom Input Bar */}
<Box
position="fixed"
b={0}
l={0}
r={0}
z="var(--z-dock)"
pt={16}
px={20}
pb={24}
display="flex"
justify="center"
flexDirection="row"
$platform-web={{ backgroundImage: "linear-gradient(to top, var(--surface-card) 70%, color-mix(in srgb, var(--background) 0%, transparent) 100%)" }}
>
<View
render={<form onSubmit={handleSubmit} />}
width="100%"
maxW={680}
position="relative"
display="flex"
items="center"
flexDirection="row"
>
<View
render={<input ref={inputRef} type="text" value={input} onChange={(e) => setInput(e.target.value)} placeholder={isChatting ? 'Ask the Buying Specialist a question...' : 'Press enter to get started'} onFocus={(e) => {
e.currentTarget.style.borderColor = 'var(--white-30)'
e.currentTarget.style.backgroundColor = 'var(--white-08)'
}} onBlur={(e) => {
e.currentTarget.style.borderColor = 'var(--white-10)'
e.currentTarget.style.backgroundColor = 'var(--white-06)'
}} />}
width="100%"
bg="var(--white-06)"
borderWidth={1}
borderColor="var(--white-10)"
rounded={9999}
pt={16}
pr={54}
pb={16}
pl={22}
$platform-web={{ outline: "none", boxSizing: "border-box", transition: "border-color 0.15s ease, background-color 0.15s ease", fontSize: "var(--text-lg)", color: "var(--foreground)", display: "inline-block" }}
/>
<View
render={<button type="submit" aria-label="Send message" onMouseEnter={(e) => (e.currentTarget.style.opacity = '0.85')} onMouseLeave={(e) => (e.currentTarget.style.opacity = '1')} />}
position="absolute"
r={8}
width={38}
height={38}
rounded={9999}
bg="var(--foreground)"
borderWidth={0}
cursor="pointer"
display="flex"
items="center"
justify="center"
flexDirection="row"
$platform-web={{ transition: "transform 0.15s ease, opacity 0.15s ease", color: "var(--background)" }}
>
<ArrowUp size={18} strokeWidth={2.5} />
</View>
</View>
</Box>
</Box>
)
}
/** Generates specialized domain responses based on user queries and numbers. */
function generateAssistantResponse(prompt: string, userName: string): Message {
const p = prompt.toLowerCase()
const id = String(Date.now())
// Look for team numbers in prompt
const matchNum = p.match(/\b(\d+)\s*(people|developers?|engineers?|members?|seats?|devs?|users?)?\b/)
const num = matchNum ? parseInt(matchNum[1], 10) : null
// 1. Explicit Enterprise or Compliance inquiry
if (p.includes('enterprise') || p.includes('vpc') || p.includes('hipaa') || p.includes('dedicated') || p.includes('cluster') || p.includes('soc 2') || (num && num > 50)) {
return {
id,
role: 'assistant',
content: `For organizations deploying at scale, **Hanzo Enterprise** is the tailored choice.\n\nHere is what is included:\n- **Dedicated Infrastructure**: Private GPU clusters, custom fine-tuned weights, and unlimited concurrency.\n- **Deployment Options**: Host in your own cloud VPC (AWS, GCP, Azure), on-premise servers, or air-gapped offline environments.\n- **Security & Governance**: Centralized SAML SSO, SCIM provisioning, granular RBAC, and immutable audit logs.\n- **Contracted SLAs**: 99.99% uptime guarantees and 24/7 dedicated engineering support.\n\nWould you like me to connect you with our solutions engineering team to review architecture and prepare a custom proposal?`,
quote: {
plan: 'Enterprise',
monthlyTotal: 0,
annualTotal: 0,
savings: 0,
contactSales: true,
},
}
}
// 2. Specific Team seat inquiry or team count detected
if (num && num > 1) {
const standardAnnual = num * 20 * 12
const standardMonthly = num * 25
const mixedStandard = Math.max(1, Math.round(num * 0.7))
const mixedPremium = num - mixedStandard
const mixedAnnual = (mixedStandard * 20 + mixedPremium * 100) * 12
return {
id,
role: 'assistant',
content: `For a team of **${num} members**, the **Hanzo Team** plan provides the best balance of pooled usage, shared workspaces, and team controls.\n\nYou have two seat tiers that you can mix on one single bill:\n- **Standard Seat**: **$20/seat/mo** billed annually ($240 upfront) or $25/mo monthly. Ideal for engineers writing code, using Claude Code / Cursor, and running everyday agentic workflows.\n- **Premium Seat**: **$100/seat/mo** billed annually ($1,200 upfront) or $125/mo monthly. Provides **5× more usage**, higher rate limits, and priority inference across every model.\n\n### Your Pricing Options for ${num} Seats:\n- **All Standard (${num} seats)**: **$${num * 20}/mo** billed annually ($${standardAnnual}/year), saving $${(standardMonthly * 12) - standardAnnual} vs monthly.\n- **Mixed Setup (${mixedStandard} Standard + ${mixedPremium} Premium)**: **$${Math.round(mixedAnnual / 12)}/mo** billed annually ($${mixedAnnual}/year).\n\nBoth setups include unified billing, team workspaces, SSO, and shared automations.`,
quote: {
plan: 'Hanzo Team',
seats: num,
standardSeats: num,
monthlyTotal: standardMonthly,
annualTotal: standardAnnual,
savings: 20,
checkoutUrl: `/pay/cart?plan=team&interval=year&quantity=${num}`,
},
}
}
// 3. Difference between Standard and Premium seats
if (p.includes('standard') || p.includes('premium') || p.includes('difference') || p.includes('seat')) {
return {
id,
role: 'assistant',
content: `Here is the exact breakdown between Hanzo's two seat tiers:\n\n### 1. Standard Seat ($20/mo annual / $25 monthly)\n- **Everything in Hanzo Pro**, plus shared company workspaces.\n- Access to every model (Enso, Zen, Kai, Sonnet, Opus, GPT-5).\n- Hanzo Dev and full CLI tooling (Claude Code, Cursor, Codex acceleration).\n- Pooled limits and unified billing across your team.\n\n### 2. Premium Seat ($100/mo annual / $125 monthly)\n- **5× higher usage allowances** and 5× higher request limits.\n- **Priority inference** during peak frontier model congestion.\n- Early access to unreleased models and experimental agentic harnesses.\n\nOrganizations can **freely mix** Standard and Premium seats on a single team account. For instance, in a 10-person engineering team, you can assign 8 Standard seats and 2 Premium seats for lead researchers.`,
}
}
// 4. Comparison between Team and Enterprise
if (p.includes('compare') || p.includes('vs')) {
return {
id,
role: 'assistant',
content: `Here is a side-by-side comparison between **Team** and **Enterprise**:\n\n- **Hanzo Team** ($20–$100/seat/mo):\n - Self-serve signup starting at 2 seats.\n - Mix Standard ($20) and Premium ($100) seats.\n - Multi-user workspace, shared chat, meetings, and shared storage.\n - Centralized credit card or invoicing.\n\n- **Hanzo Enterprise** (Custom pricing):\n - For organizations with strict compliance, security, or massive scale requirements.\n - Custom VPC deployment (AWS, GCP, Azure, or on-premises).\n - Dedicated GPU clusters with guaranteed inference latency SLAs.\n - Enterprise SAML SSO, SCIM, and contracted 24/7 technical support.\n\nHow many team members are you planning to onboard?`,
}
}
// 5. Default welcoming response
return {
id,
role: 'assistant',
content: `Great to meet you, ${userName}! I can help you configure the right setup for your team.\n\nTo give you the exact numbers and plan recommendation:\n1. **How many people** will be using Hanzo?\n2. **What are your primary use cases** (e.g. coding agents, Claude Code acceleration, model routing, or custom APIs)?\n3. Do you have specific **compliance requirements** like custom VPC or SSO?`,
}
}