Files
hanzo.ai/app/(marketing)/startups/page.tsx
zeekay 6c65e3e941 @hanzo/app 0.2.0: the app SDK, renamed from @hanzo/rooms
Every import, the catalog pin and the docs name @hanzo/app and
github.com/hanzoai/app. lib/rooms.ts is lib/app.ts and
components/rooms.tsx is components/app.tsx.
2026-10-22 19:07:20 -07:00

955 lines
33 KiB
TypeScript

'use client'
/**
* /startups — the credits programme, and the form that applies to it.
*
* NO TAILWIND AND NO STYLE OBJECTS. @hanzo/ui's marketing components carry the
* type and the controls (`Display`, `Lede`, `Title`, `Chip`, `Action`), `Grid`
* wraps on the width a column actually has, and everything left is gui props
* over @hanzo/design's tokens: `Label` is the line over a field, `Card` a
* pillar, `Check` the box a choice ticks.
*
* NOT `Band`. This page's sections carry no rule, its gutter steps 16/32/48
* where every band on the site steps 16/24/32, and its rhythm (112/40, 32,
* 56, 96) is not on the band's ladder. A form page is not a product page, and
* borrowing the product band would restate all three.
*
* - `Field`/`Note` are gui's `Input`, because a placeholder's colour lives on
* `::placeholder` and `placeholderTextColor` is the prop that reaches it;
* without it the ink falls to @hanzo/design's `--text-disabled` (white at
* 30%) instead of gui's `$placeholderColor`, design's `--text-tertiary`.
* The two selects are @hanzo/ui's `Picker` in the same box.
* - `Cell` on `Toggle` — the site's surface whose ground answers a pointer.
* It adds no geometry, so an option in a multi-select wears it exactly as a
* grid tile does, and both grounds are its properties.
* - the privacy link says NOTHING. @hanzo/design's base already underlines a
* link inside a paragraph on approach, which is what every prose link on
* this site does; `More` is the wrong shape for one inside a sentence, since
* it is `inline-flex` at `text-sm` and stretching a link inside a line tears
* it.
*/
import React, { useState, type ReactNode } from 'react'
import { motion } from '@/components/motion'
import Link from 'next/link'
import {
Rocket,
ArrowRight,
CheckCircle2,
Coins,
Cpu,
Gift,
Building2,
Globe,
User,
Mail,
Briefcase,
Users,
Banknote,
Boxes,
Send,
type LucideIcon,
} from 'lucide-react'
import { Box, Picker, Text, View, XStack, YStack } from '@hanzo/ui'
import { Input, type GetProps } from '@hanzo/gui'
import { Grid } from '@hanzo/ui/grid'
import { Action, Chip, Display, Lede, Title, Cell, Line } from '@hanzo/ui/marketing'
import { mix } from '@hanzo/app/lib/mix'
import { api } from '@hanzo/app/lib/api'
// Canonical cloud intake endpoint (public startup-program application), on the
// gateway of the host this page is open on.
const apply = () => `${api()}/v1/crm/applications`
/** How narrow a column may get before the grid drops one. */
const TRIO = { min: 280, max: 3 } as const
const DUO = { min: 260, max: 2 } as const
const MUTED = 'var(--muted-foreground)'
/** The two small rungs, each on the leading its utility paired it with: a ratio,
* so it follows the reader's type scale. `Line` takes it as written. */
const XS = { fontSize: '$1', lineHeight: '1.3333' } as const
const SM = { fontSize: '$2', lineHeight: '1.4286' } as const
/** The line over a field: its mark and its words, `htmlFor` where it names one control. */
const Label = ({ htmlFor, icon: Icon, children }: { htmlFor?: string; icon: LucideIcon; children: ReactNode }) => (
<Line
render="label"
htmlFor={htmlFor}
display="flex"
items="center"
gap={8}
mb={8}
{...SM}
fontWeight="500"
color="var(--foreground)"
>
<View render={<Icon width={14} height={14} color={MUTED} />} shrink={0} />
{children}
</Line>
)
/** The quiet half of a label — "(optional)", "(funds, angels)". */
const Aside = ({ children }: { children: ReactNode }) => (
<Text fontWeight="400" color={MUTED}>
{children}
</Text>
)
/** A pillar: its mark on a disc in the page's one accent at 10%, a title and a line. */
const Card = ({ icon: Icon, title, children }: { icon: LucideIcon; title: string; children: ReactNode }) => (
<Box minW={0} p={24} rounded="var(--radius-xl)" borderWidth={1} borderColor="var(--border)" bg={mix('var(--secondary)', 20)}>
<XStack items="center" justify="center" width={40} height={40} mb={16} rounded="var(--radius-lg)" bg={mix('var(--primary)', 10)}>
<Icon width={20} height={20} color={mix('var(--foreground)', 80)} />
</XStack>
<Line render="h3" display="block" mb={8} fontSize="$4" fontWeight="600" color="var(--text-primary)" lineHeight="1.5556">
{title}
</Line>
<Line render="p" display="block" fontSize="$2" color={MUTED} lineHeight="var(--leading-relaxed)">
{children}
</Line>
</Box>
)
/** The tick itself, drawn in the ground's ink. */
const Tick = ({ size }: { size: number }) => (
<svg width={size} height={size} fill="none" viewBox="0 0 24 24" stroke="var(--background)" strokeWidth={3}>
<path strokeLinecap="round" strokeLinejoin="round" d="M5 13l4 4L19 7" />
</svg>
)
/** The box a choice ticks, at the two sizes this page ticks one: filled in the ink when on. */
const Check = ({ on, size, mt }: { on: boolean; size: 16 | 20; mt?: number }) => (
<View
render="span"
display="inline-flex"
width={size}
height={size}
shrink={0}
items="center"
justify="center"
mt={mt}
rounded="var(--radius)"
borderWidth={1}
borderStyle="solid"
transition="quickest"
bg={on ? 'var(--foreground)' : undefined}
borderColor={on ? 'var(--foreground)' : mix('var(--muted-foreground)', 40)}
>
{on && <Tick size={size === 16 ? 10 : 12} />}
</View>
)
/**
* One option in a multi-select, ticked or not.
*
* ONE ground on approach, for both the fund list and the use-case list — they
* were the same eleven utilities written twice, differing only in how far the
* tick sits from the top and how much room the row has.
*/
const Toggle = ({
on,
onClick,
align,
pad,
children,
}: {
on: boolean
onClick: () => void
align: 'center' | 'flex-start'
pad: number
children: React.ReactNode
}) => (
<Cell
render="button"
type="button"
onClick={onClick}
display="flex"
items={align}
gap={12}
p={pad}
rounded="var(--radius-lg)"
borderWidth={1}
borderStyle="solid"
text="left"
{...(on ? CHOSEN : CHOICE)}
>
<Check on={on} size={16} mt={align === 'flex-start' ? 2 : undefined} />
{children}
</Cell>
)
/** A choice in the form: its edge and its ground at rest and on approach. The
* chosen one holds its ground under the pointer. */
const CHOICE = {
borderColor: 'var(--border)',
bg: mix('var(--secondary)', 30),
hoverStyle: { bg: mix('var(--secondary)', 60) },
} as const
const CHOSEN = {
borderColor: mix('var(--pure-white)', 40),
bg: mix('var(--primary)', 10),
hoverStyle: { bg: mix('var(--primary)', 10) },
} as const
/** The box every field here is drawn in. `unstyled` zeroes the outline, so
* the focus ring @hanzo/design draws on every control is given its width back. */
const ENTRY = {
unstyled: true,
width: '100%',
px: 16,
py: 12,
rounded: 'var(--radius-lg)',
borderWidth: 1,
borderColor: 'var(--border)',
bg: 'var(--secondary)',
fontSize: '$2',
lineHeight: '$2',
color: 'var(--foreground)',
placeholderTextColor: '$placeholderColor',
focusVisibleStyle: { outlineWidth: 2 },
} as const
/** The two controls a form is made of: a line, and the same field `rows` tall. */
const Field = (props: GetProps<typeof Input>) => <Input {...ENTRY} {...props} />
const Note = (props: GetProps<typeof Input>) => <Input render="textarea" {...ENTRY} {...props} />
/** The platform's own select in the fields' box. */
const Choose = (props: React.ComponentProps<typeof Picker>) => (
<Picker
pl={16}
pr={16}
py={12}
minH={0}
rounded="var(--radius-lg)"
borderWidth={1}
borderColor="var(--border)"
bg="var(--secondary)"
fontSize="$2"
$platform-web={{ lineHeight: '1.4286' }}
color="var(--foreground)"
{...props}
/>
)
const STAGES = [
{ id: 'idea', label: 'Idea' },
{ id: 'pre-seed', label: 'Pre-seed' },
{ id: 'seed', label: 'Seed' },
{ id: 'series-a', label: 'Series A' },
{ id: 'series-b-plus', label: 'Series B+' },
]
// Tier-1 funds recognized for the credits program. Free-text field captures any others.
const TIER1_FUNDS = [
'Andreessen Horowitz (a16z)',
'Sequoia',
'Benchmark',
'Greylock',
'Accel',
'Founders Fund',
'Lightspeed',
'Index Ventures',
'Bessemer',
'Khosla Ventures',
'GV (Google Ventures)',
'Techstars',
]
const USE_CASES = [
{ id: 'ai', label: 'AI & inference', description: 'Models, agents, RAG, one API for every model' },
{ id: 'deploy', label: 'Deploy', description: 'Apps, functions, edge, machines' },
{ id: 'data', label: 'Data', description: 'Vector, SQL, KV, object storage' },
{ id: 'compute', label: 'Compute', description: 'GPUs, training, batch jobs' },
]
const HEARD_OPTIONS = [
'Search',
'X / Twitter',
'LinkedIn',
'A friend or colleague',
'A Techstars connection',
'An investor',
'An event or conference',
'Hanzo docs or GitHub',
'Other',
]
const PILLARS = [
{
icon: Coins,
title: 'Start in minutes',
body: <>Creating an account is free. Add funds when you are ready and pay only for what you use &mdash; no subscription, no minimums.</>,
},
{
icon: Cpu,
title: 'Bring your own compute',
body: <>Connect your own GPUs and machines. Run cheap on hardware you already have &mdash; we meter the platform, not your iron.</>,
},
{
icon: Gift,
title: 'Up to $150,000 in credits',
body: <>For venture-backed startups. Application required, and tier-1 VC backing is required for the credits program.</>,
},
] as const
interface FormData {
company: string
website: string
contactName: string
email: string
role: string
stage: string
investors: string
tier1Investors: string[]
amountRaised: string
teamSize: string
building: string
useCases: string[]
infraSpend: string
byoCompute: boolean
byoHardware: string
techstarsBatch: string
heardVia: string
// Honeypot: must stay empty. Real users never see or fill this.
hp: string
}
const INITIAL_FORM: FormData = {
company: '',
website: '',
contactName: '',
email: '',
role: '',
stage: '',
investors: '',
tier1Investors: [],
amountRaised: '',
teamSize: '',
building: '',
useCases: [],
infraSpend: '',
byoCompute: false,
byoHardware: '',
techstarsBatch: '',
heardVia: '',
hp: '',
}
export default function StartupsPage() {
const [formData, setFormData] = useState<FormData>(INITIAL_FORM)
const [isSubmitting, setIsSubmitting] = useState(false)
const [submitted, setSubmitted] = useState(false)
const [error, setError] = useState<string | null>(null)
const handleChange = (
e: React.ChangeEvent<HTMLInputElement | HTMLTextAreaElement | HTMLSelectElement>
) => {
setFormData({ ...formData, [e.target.name]: e.target.value })
}
const toggleInArray = (key: 'tier1Investors' | 'useCases', value: string) => {
setFormData((prev) => ({
...prev,
[key]: prev[key].includes(value)
? prev[key].filter((v) => v !== value)
: [...prev[key], value],
}))
}
const validate = (): string | null => {
if (!formData.company.trim()) return 'Company name is required.'
if (!formData.contactName.trim()) return 'Your name is required.'
if (!/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(formData.email)) return 'A valid email is required.'
if (!formData.stage) return 'Please select your company stage.'
if (!formData.building.trim()) return 'Tell us what you are building.'
return null
}
const handleSubmit = async (e: React.FormEvent) => {
e.preventDefault()
const validationError = validate()
if (validationError) {
setError(validationError)
return
}
setIsSubmitting(true)
setError(null)
try {
const res = await fetch(apply(), {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ ...formData, submittedAt: new Date().toISOString() }),
})
if (!res.ok) {
throw new Error(`Request failed (${res.status})`)
}
setSubmitted(true)
} catch (err) {
setError(
err instanceof Error ? err.message : 'Something went wrong. Please try again.'
)
} finally {
setIsSubmitting(false)
}
}
return (
<Box minH="100vh" $platform-web={{ color: 'var(--foreground)' }}>
<Box render="main">
{/* Hero */}
<Box render="section" position="relative" pt={112} pb={40} px={16} $md={{ px: 32 }} $lg={{ px: 48 }}>
<Box width="100%" maxW={768} mx="auto" $platform-web={{ textAlign: 'center' }}>
<Box
render={<motion.div initial={{ opacity: 0, y: 16 }} animate={{ opacity: 1, y: 0 }} transition={{ duration: 0.4 }} />}
mb={24}
>
<Chip px={12} py={4} fontSize="$1" lineHeight="1.3333" fontWeight="500" borderColor="var(--border)" bg={mix('var(--primary)', 10)} color="var(--foreground)">
<Rocket width={12} height={12} />
Techstars &rsquo;17 &mdash; built for founders
</Chip>
</Box>
<Display
render={<motion.h1 initial={{ opacity: 0, y: 16 }} animate={{ opacity: 1, y: 0 }} transition={{ duration: 0.4, delay: 0.05 }} />}
mb={20}
>
The Hanzo Startup Program
</Display>
<Lede
render={<motion.p initial={{ opacity: 0, y: 16 }} animate={{ opacity: 1, y: 0 }} transition={{ duration: 0.4, delay: 0.1 }} />}
width="100%"
maxW={672}
mx="auto"
>
Build frontier AI on the same infrastructure we run in production.
Everyone starts free. Venture-backed teams get up to $150,000 in
credits. Bring your own compute and we meter the platform, not your
iron.
</Lede>
<Box
render={<motion.div initial={{ opacity: 0, y: 16 }} animate={{ opacity: 1, y: 0 }} transition={{ duration: 0.4, delay: 0.15 }} />}
mt={32}
>
<XStack flexWrap="wrap" items="center" justify="center" gap={12}>
<Action href="#apply" fill>
Apply for credits
<ArrowRight width={16} height={16} />
</Action>
<Action href="https://platform.hanzo.ai" borderColor="var(--border)">
Start building free
</Action>
</XStack>
</Box>
</Box>
</Box>
{/* Pillars */}
<Box render="section" pb={32} px={16} $md={{ px: 32 }} $lg={{ px: 48 }}>
<Box width="100%" maxW={1024} mx="auto">
<Grid columns={TRIO} gap={16}>
{PILLARS.map(({ icon, title, body }) => (
<Card key={title} icon={icon} title={title}>
{body}
</Card>
))}
</Grid>
</Box>
{/* Techstars note */}
<Box width="100%" maxW={1024} mx="auto" mt={16}>
<XStack
items="flex-start"
gap={12}
p={20}
rounded="var(--radius-xl)"
borderWidth={1}
borderColor="var(--border)"
bg="$hover"
>
<View render={<Rocket width={16} height={16} color={mix('var(--foreground)', 70)} />} mt={2} shrink={0} />
<Line render="p" display="block" fontSize="$2" color={MUTED} lineHeight="var(--leading-relaxed)">
<Text color="var(--foreground)" fontWeight="500">Techstars founders:</Text>{' '}
Hanzo is a Techstars company. We offer perks tailored to each
portfolio brand &mdash; mention your batch when you apply and we
will match it.
</Line>
</XStack>
</Box>
</Box>
{/* Application form */}
<Box render="section" id="apply" py={56} px={16} $md={{ px: 32 }} $lg={{ px: 48 }} $platform-web={{ scrollMarginTop: '96px' }}>
<Box width="100%" maxW={672} mx="auto">
<Box mb={40} $platform-web={{ textAlign: 'center' }}>
<Title quiet mb={12}>
Apply to the program
</Title>
<Text render="p" display="block" color={MUTED}>
We review applications weekly. The more you share, the faster we
can match you to the right tier.
</Text>
</Box>
{submitted ? (
<Box
render={<motion.div initial={{ opacity: 0, scale: 0.95 }} animate={{ opacity: 1, scale: 1 }} transition={{ duration: 0.4 }} />}
p={40}
rounded="var(--radius-xl)"
borderWidth={1}
borderColor="var(--border)"
bg={mix('var(--primary)', 5)}
$platform-web={{ textAlign: 'center' }}
>
<XStack
items="center"
justify="center"
width={56}
height={56}
mx="auto"
mb={20}
rounded="var(--radius-full)"
bg="$raised"
>
<CheckCircle2 width={28} height={28} color={mix('var(--foreground)', 70)} />
</XStack>
<Title quiet mb={12}>
Application received
</Title>
<Text render="p" display="block" mb={8} color={MUTED}>
Thanks &mdash; we review applications weekly and will be in touch
by email.
</Text>
<Line render="p" display="block" mb={32} {...SM} color={MUTED}>
Want to start building today? Create an account and pay only
for what you use &mdash; no subscription required.
</Line>
<XStack flexWrap="wrap" justify="center" gap={16}>
<Action href="https://platform.hanzo.ai" fill>
Start free
<ArrowRight width={16} height={16} />
</Action>
<Action href="/" borderColor="var(--border)">
Back to Home
</Action>
</XStack>
</Box>
) : (
<YStack
render={<motion.form onSubmit={handleSubmit} initial={{ opacity: 0, y: 20 }} animate={{ opacity: 1, y: 0 }} transition={{ duration: 0.5, delay: 0.1 }} />}
gap={24}
>
{/* Company + website */}
<Grid columns={DUO} gap={16}>
<Box>
<Label htmlFor="company" icon={Building2}>
Company name
</Label>
<Field
type="text"
id="company"
name="company"
value={formData.company}
onChange={handleChange}
required
placeholder="Acme AI"
/>
</Box>
<Box>
<Label htmlFor="website" icon={Globe}>
Website
</Label>
<Field
type="text"
id="website"
name="website"
value={formData.website}
onChange={handleChange}
placeholder="https://acme.ai"
/>
</Box>
</Grid>
{/* Contact name + email */}
<Grid columns={DUO} gap={16}>
<Box>
<Label htmlFor="contactName" icon={User}>
Your name
</Label>
<Field
type="text"
id="contactName"
name="contactName"
value={formData.contactName}
onChange={handleChange}
required
placeholder="Jane Smith"
/>
</Box>
<Box>
<Label htmlFor="email" icon={Mail}>
Work email
</Label>
<Field
type="email"
id="email"
name="email"
value={formData.email}
onChange={handleChange}
required
placeholder="[email protected]"
/>
</Box>
</Grid>
{/* Role + stage */}
<Grid columns={DUO} gap={16}>
<Box>
<Label htmlFor="role" icon={Briefcase}>
Your role
</Label>
<Field
type="text"
id="role"
name="role"
value={formData.role}
onChange={handleChange}
placeholder="Co-founder & CEO"
/>
</Box>
<Box>
<Label htmlFor="stage" icon={Rocket}>
Company stage
</Label>
<Choose
id="stage"
name="stage"
value={formData.stage}
onChange={handleChange}
required
>
<option value="" disabled>
Select stage
</option>
{STAGES.map((s) => (
<option key={s.id} value={s.id}>
{s.label}
</option>
))}
</Choose>
</Box>
</Grid>
{/* Investors free text */}
<Box>
<Label htmlFor="investors" icon={Banknote}>
Who are your investors?{' '}
<Aside>(funds, angels)</Aside>
</Label>
<Field
type="text"
id="investors"
name="investors"
value={formData.investors}
onChange={handleChange}
placeholder="e.g. Sequoia, plus a few angels"
/>
</Box>
{/* Tier-1 checkboxes */}
<Box>
<Label icon={CheckCircle2}>
Backed by any of these?{' '}
<Aside>
(tier-1 backing qualifies you for the credits program)
</Aside>
</Label>
<Grid columns={DUO} gap={8}>
{TIER1_FUNDS.map((fund) => (
<Toggle
key={fund}
on={formData.tier1Investors.includes(fund)}
onClick={() => toggleInArray('tier1Investors', fund)}
align="center"
pad={10}
>
<Line {...SM} color="var(--foreground)">{fund}</Line>
</Toggle>
))}
</Grid>
</Box>
{/* Raised + team size */}
<Grid columns={DUO} gap={16}>
<Box>
<Label htmlFor="amountRaised" icon={Banknote}>
Amount raised{' '}
<Aside>(optional)</Aside>
</Label>
<Field
type="text"
id="amountRaised"
name="amountRaised"
value={formData.amountRaised}
onChange={handleChange}
placeholder="$2M"
/>
</Box>
<Box>
<Label htmlFor="teamSize" icon={Users}>
Team size
</Label>
<Field
type="text"
id="teamSize"
name="teamSize"
value={formData.teamSize}
onChange={handleChange}
placeholder="5"
/>
</Box>
</Grid>
{/* Building */}
<Box>
<Label htmlFor="building" icon={Boxes}>
What are you building?
</Label>
<Note
id="building"
name="building"
value={formData.building}
onChange={handleChange}
required
rows={4}
placeholder="Describe your product, who it is for, and where you are today..."
/>
</Box>
{/* Use cases */}
<Box>
<Label icon={Cpu}>
How will you use Hanzo?
</Label>
<Grid columns={DUO} gap={8}>
{USE_CASES.map((uc) => (
<Toggle
key={uc.id}
on={formData.useCases.includes(uc.id)}
onClick={() => toggleInArray('useCases', uc.id)}
align="flex-start"
pad={12}
>
<span>
<Line {...SM} fontWeight="500" color="var(--foreground)">{uc.label}</Line>
<Line render="p" display="block" mt={2} {...XS} color={MUTED}>{uc.description}</Line>
</span>
</Toggle>
))}
</Grid>
</Box>
{/* Infra spend */}
<Box>
<Label htmlFor="infraSpend" icon={Banknote}>
Current infra / compute spend per month{' '}
<Aside>(optional)</Aside>
</Label>
<Field
type="text"
id="infraSpend"
name="infraSpend"
value={formData.infraSpend}
onChange={handleChange}
placeholder="$3,000 / mo"
/>
</Box>
{/* BYO compute */}
<YStack
gap={16}
p={20}
rounded="var(--radius-xl)"
borderWidth={1}
borderColor="var(--border)"
bg="$panel"
>
<XStack
render={<button type="button" onClick={() => setFormData((p) => ({ ...p, byoCompute: !p.byoCompute }))} />}
items="flex-start"
gap={12}
width="100%"
$platform-web={{ textAlign: 'left' }}
>
<Check on={formData.byoCompute} size={20} mt={2} />
<span>
<Line display="flex" items="center" gap={8} {...SM} fontWeight="500" color="var(--foreground)">
<Cpu width={14} height={14} color={MUTED} />
I want to bring my own compute
</Line>
<Line display="block" mt={4} {...XS} color={MUTED}>
Connect your own GPUs or machines and run on hardware you
already own.
</Line>
</span>
</XStack>
{formData.byoCompute && (
<Box>
<Line render="label" htmlFor="byoHardware" display="block" mb={8} {...XS} fontWeight="500" color={MUTED}>
What hardware do you have?
</Line>
<Field
type="text"
id="byoHardware"
name="byoHardware"
value={formData.byoHardware}
onChange={handleChange}
placeholder="e.g. 8x H100, a few Mac Studios, on-prem cluster"
/>
</Box>
)}
</YStack>
{/* Techstars + heard */}
<Grid columns={DUO} gap={16}>
<Box>
<Label htmlFor="techstarsBatch" icon={Rocket}>
Techstars affiliation{' '}
<Aside>(optional)</Aside>
</Label>
<Field
type="text"
id="techstarsBatch"
name="techstarsBatch"
value={formData.techstarsBatch}
onChange={handleChange}
placeholder="Batch / program, e.g. NYC W17"
/>
</Box>
<Box>
<Label htmlFor="heardVia" icon={Globe}>
How did you hear about us?
</Label>
<Choose
id="heardVia"
name="heardVia"
value={formData.heardVia}
onChange={handleChange}
>
<option value="">Select one</option>
{HEARD_OPTIONS.map((h) => (
<option key={h} value={h}>
{h}
</option>
))}
</Choose>
</Box>
</Grid>
{/* Honeypot: visually hidden, off-screen, not tab-reachable. */}
<Box aria-hidden="true" position="absolute" l={-9999} t={-9999} width={0} height={0} overflow="hidden">
<label htmlFor="hp">Do not fill this in</label>
<input
type="text"
id="hp"
name="hp"
value={formData.hp}
onChange={handleChange}
tabIndex={-1}
autoComplete="off"
/>
</Box>
{/* Error */}
{error && (
<Line
render="div"
display="block"
p={16}
rounded="var(--radius-lg)"
borderWidth={1}
fontSize="$2"
color="var(--state-error-text)"
lineHeight="1.4286" borderColor={mix('var(--state-error)', 30)}
bg={mix('var(--state-error)', 10)}
>
{error}
</Line>
)}
{/* Submit.
`alignItems` is what `w-full sm:w-auto` was asking for: the
control stretches on a phone and shrinks to its words from
640, which is a property of the COLUMN and not of the button. */}
<YStack pt={8} items="stretch" $sm={{ items: 'flex-start' }}>
<Action
render="button"
type="submit"
disabled={isSubmitting}
fill
justify="center"
opacity={isSubmitting ? 0.5 : undefined}
>
{isSubmitting ? (
'Submitting...'
) : (
<>
<Send width={16} height={16} />
Submit application
</>
)}
</Action>
</YStack>
<Line render="p" display="block" fontSize="$1" lineHeight="1.3333" color={mix('var(--muted-foreground)', 60)}>
By submitting, you agree to Hanzo&rsquo;s{' '}
{/* Nothing of its own: @hanzo/design's base underlines a link
inside a paragraph on approach, which is this site's whole
treatment for a link in a sentence. */}
<Link href="/legal/privacy">
Privacy Policy
</Link>
. We use your information only to review this application.
</Line>
</YStack>
)}
</Box>
</Box>
{/* Fallback CTA for everyone */}
<Box render="section" pb={96} px={16} $md={{ px: 32 }} $lg={{ px: 48 }}>
<Box
width="100%"
maxW={768}
mx="auto"
p={32}
$sm={{ p: 40 }}
rounded="var(--radius-2xl)"
borderWidth={1}
borderColor="var(--border)"
bg="$panel"
$platform-web={{ textAlign: 'center' }}
>
<Title quiet mb={12}>
Not venture-backed yet?
</Title>
<Text render="p" display="block" mb={24} width="100%" maxW={576} mx="auto" color={MUTED}>
You do not need to qualify to build. Create an account, pay only for
what you use, and apply for credits when you raise.
</Text>
<Action href="https://platform.hanzo.ai" fill>
Start free
<ArrowRight width={16} height={16} />
</Action>
</Box>
</Box>
</Box>
</Box>
)
}