Files
zeekay 9b37f2017f sign-in: the way in is one page, and a known address gets its link
"Create your account" lost the wordmark because the panel's terms step was
portalled to <body> at the modals' layer: it covered the bar, and outside
the font scope its title fell to 14px. It is drawn in place now, under the
bar, as the next page of the same flow.

components/shell/focus is that page, once: the light from the top of the
window (painted on the bar too, so they are one ground, in both themes),
one column at the sign-in card's measure centred under the bar, pay's
32/26px title, and Hanzo's mark at the foot. /login, /signup, /forget,
/join, /login/mfa, /auth/callback, /auth/initiate, /auth/logout and
/onboarding draw it; /beta draws the same light. /forget, /join and
/login/mfa lose the CLI demo and the closing call.

A known address is sent its link at once, its password a press away.
With no sign-in in the tab five seconds on, the page turns to the code
form. Only an application that makes no accounts asks for the password
first.

e2e/gates/focus.spec.ts holds the page; login.spec the link-first steps,
the five seconds on a fake clock, and the one exception.

Claude-Session: https://claude.ai/code/session_01BLLMyBFSvAfCt7ZGqYuiEz
2026-10-22 11:12:15 -07:00

73 lines
2.3 KiB
TypeScript

'use client'
/**
* The pieces /enterprise, /contact-sales and /contact share, drawn as the
* sign-up and the checkout are drawn (components/auth): a black page, cards on
* the `--muted` ground (#171717) whose hairline reads #2e2e2e over it, and one
* 56px white pill for the call to action.
*/
import type { ComponentProps, ReactNode } from 'react'
import { ArrowRight } from 'lucide-react'
import { Text, YStack } from '@hanzo/ui'
import { Action } from '@hanzo/ui/marketing'
/** Where every "Talk to sales" goes. */
export const SALES = '/contact-sales'
/** The sales mailbox /contact-sales shows (e2e/gates/cta.spec.ts holds every control to it). */
export const MAILBOX = '[email protected]'
/** The funnel's control (components/shell/focus `LARGE`): 56px on 1rem type, with room beside the words. */
export const PILL = { minH: 56, px: 28, fontSize: '1rem' } as const
/**
* A card on the funnel's ground: `--muted` under the hairline, lit from above by
* `--edge-highlight` (transparent on the light ground, where the edge does the work).
*/
export const CARD = {
bg: 'var(--muted)',
borderWidth: 1,
borderColor: 'var(--border)',
rounded: 'var(--radius-2xl)',
boxShadow: 'var(--edge-highlight)',
} as const
/** The one loud control on these pages: "Talk to sales", to /contact-sales. */
export function Talk({ children = 'Talk to sales', ...rest }: { children?: ReactNode } & Omit<ComponentProps<typeof Action>, 'children'>) {
return (
<Action href={SALES} fill {...PILL} {...rest}>
{children}
<ArrowRight width={18} height={18} aria-hidden />
</Action>
)
}
/** A card: the `CARD` ground and edge at 24px of padding, 28px from `$sm`. */
export function Tile(props: ComponentProps<typeof YStack>) {
return <YStack {...CARD} p={24} $sm={{ p: 28 }} gap={10} minW={0} {...props} />
}
/** A card's mark: the icon on a 40px disc of the page ground, inked by the disc. */
export function Mark({ children }: { children: ReactNode }) {
return (
<Text
display="inline-flex"
self="flex-start"
items="center"
justify="center"
width={40}
height={40}
shrink={0}
mb={6}
rounded="var(--radius-lg)"
bg="var(--background)"
borderWidth={1}
borderColor="var(--border)"
color="$ink"
>
{children}
</Text>
)
}