Files
zooqueenandHanzo Dev 387de25417 The Enterprise share card says what the plan holds, and the sales form waits for its page, sizes its select in Safari and counts its trap
The /enterprise card claimed SOC 2 Type II, HIPAA, ISO 27001 and a 99.99%
uptime SLA; it now names the deployments, unlimited members, dedicated
compute and 24/7 engineering support, and /contact-sales shares it.
`generate-og.mjs <name>` redraws the named cards alone.

/contact-sales keeps its submit off until the page runs, so the export's
form never sends answers as an address, and takes any it finds out of the
address. The team size select draws its own chevron at 56px in WebKit, the
hidden field is read off the form and counted as sales_trapped, and an
invalid field keeps its error edge in focus.

/enterprise qualifies the database claim with Hanzo Base, records the audit
status as /trust does, links the Privacy Policy for data use, and the site's
sales contact point is [email protected] at /contact-sales.



Co-authored-by: Hanzo Dev <[email protected]>
2026-10-16 11:23:51 -07:00

96 lines
4.4 KiB
TypeScript

'use client'
/**
* Where Enterprise runs, as one picture: four stops on one track, from the
* fastest start (Hanzo's cloud) to the most control (air-gapped). The stops
* are the Enterprise plan's own list (GET /v1/billing/plans, `enterprise`:
* "Run Hanzo in your cloud, on your servers or fully offline"); the line under
* each comes from /trust (one database file per organization) and lib/data/solutions
* `INSIDE` (models served on machines you control).
*
* Below `$lg` the track runs down the left edge and the stops stack beside it;
* from `$lg` it runs across the top and the four stand side by side.
*/
import type { LucideIcon } from 'lucide-react'
import { Cloud, Network, Server, ShieldCheck } from 'lucide-react'
import { Text, View, XStack, YStack } from '@hanzo/ui'
import { CARD } from './kit'
type Stop = { icon: LucideIcon; name: string; where: string; line: string }
export const STOPS: readonly Stop[] = [
{ icon: Cloud, name: 'Hanzo Cloud', where: 'We run it for you', line: "Start today. On Hanzo Base, your organization's data is its own database." },
{ icon: Network, name: 'Your cloud', where: 'Inside your VPC', line: 'Hanzo runs in your own cloud account, on your network.' },
{ icon: Server, name: 'Your servers', where: 'On premises', line: 'On hardware in your data center, beside the systems you already run.' },
{ icon: ShieldCheck, name: 'Air-gapped', where: 'Fully offline', line: 'Sealed inside your network, with models served on machines you control.' },
]
/** The track's own ink: the hairline one rung up, so it reads on either ground. */
const RAIL = 'var(--border-strong)'
export default function Deploy() {
return (
<YStack {...CARD} p={24} $sm={{ p: 32 }} gap={28} data-slot="deploy">
{/* The legend reads across, so it stands only where the track does. */}
<XStack display="none" $lg={{ display: 'flex' }} items="center" gap={12} aria-hidden>
<Text fontSize="$2" color="var(--muted-foreground)" shrink={0}>
Fastest start
</Text>
<View
grow={1}
height={2}
rounded="var(--radius-full)"
backgroundImage="linear-gradient(to right, var(--border), var(--foreground))"
/>
<Text fontSize="$2" color="$ink" shrink={0}>
Most control
</Text>
</XStack>
<View render="ol" display="grid" gridTemplateColumns="minmax(0, 1fr)" m={0} p={0} $lg={{ gridTemplateColumns: 'repeat(4, minmax(0, 1fr))' }} $platform-web={{ listStyle: 'none' }}>
{STOPS.map((s, i) => (
<Stop key={s.name} stop={s} first={i === 0} last={i === STOPS.length - 1} />
))}
</View>
</YStack>
)
}
function Stop({ stop: { icon: Icon, name, where, line }, first, last }: { stop: Stop; first: boolean; last: boolean }) {
return (
<XStack render="li" gap={16} minW={0} $lg={{ flexDirection: 'column', items: 'center', gap: 20 }}>
{/* The track: down the left edge on a phone, across the top from $lg. */}
<YStack items="center" width={44} shrink={0} $lg={{ flexDirection: 'row', width: '100%' }}>
<View display="none" $lg={{ display: 'flex', grow: 1, height: 1, bg: first ? 'transparent' : RAIL }} />
<Text
display="inline-flex"
items="center"
justify="center"
width={44}
height={44}
shrink={0}
rounded="var(--radius-full)"
borderWidth={1}
borderColor={last ? 'var(--foreground)' : 'var(--border-strong)'}
bg={last ? 'var(--foreground)' : 'var(--background)'}
color={last ? 'var(--background)' : 'var(--foreground)'}
>
<Icon width={20} height={20} aria-hidden />
</Text>
<View grow={1} width={1} minH={24} bg={last ? 'transparent' : RAIL} $lg={{ height: 1, width: 'auto', minH: 0, bg: last ? 'transparent' : RAIL }} />
</YStack>
<YStack gap={6} minW={0} grow={1} shrink={1} pb={last ? 0 : 28} $lg={{ pb: 0, px: 12, items: 'center' }}>
<Text render="h3" fontSize="$5" lineHeight="1.75rem" fontWeight="600" color="$ink" $lg={{ text: 'center' }}>
{name}
</Text>
<Text fontSize="$2" color="var(--muted-foreground)" $lg={{ text: 'center' }}>
{where}
</Text>
<Text render="p" fontSize="$3" lineHeight="1.5rem" color="$ink" mt={4} $lg={{ text: 'center' }}>
{line}
</Text>
</YStack>
</XStack>
)
}