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

519 lines
22 KiB
TypeScript

'use client'
/**
* /brand — the design system, shown rather than described.
*
* NO TAILWIND. The seven section frames are `components/marketing/band`'s
* `Band` and `Head`; @hanzo/ui's marketing components carry the type and the
* controls (`Display`, `Lede`, `Title`, `Chip`, `Action`, `Leaf`, `Line`);
* everything left is gui props over @hanzo/design's tokens. A `color-mix()`
* ink is not a value gui's colour props type, so a frame's tint rides
* `$platform-web`, which gui still writes as a class.
*
* THE THREE LOCAL COMPONENTS TOOK A `className` AND IT WAS THE PAYLOAD, which
* is the one shape a de-Tailwind pass cannot leave alone: `ColorSwatch` was
* handed `bg-[#171717]`, and `TypographyExample` a whole type ramp, so the
* utility string WAS the thing being demonstrated. Each now takes the VALUE it
* was demonstrating — a `fill` for the swatch, the `type` props for the
* specimen — and every call site passes one. A page about a design system may
* not be the last place still writing utilities to describe it.
*
* Two things the swap moves, both deliberate:
*
* - the section headings take `Title quiet`, so `text-2xl md:text-3xl`
* becomes the site's own section rung and steps at 640 rather than 768.
* - `Action` is the one button shape, so the four `Button` variants in the
* Components showcase render as the site's two weights plus `More` — which
* is what those four have BEEN on every other page since the roles landed.
*
* `rounded-3xl` on the CTA glows had no design token (`--radius-3xl` is
* Tailwind's alone) and neither did they need one: they are circles, so they
* take `--radius-full`, which is what `rounded-full` already said.
*/
import { colors } from '@hanzo/design'
import React from "react";
import { motion } from "@/components/motion";
import {
Palette,
Download,
Type,
Grid3X3,
Sparkles,
ArrowRight,
} from "lucide-react";
import { Box, XStack, YStack } from '@hanzo/ui'
import { phrase } from '@hanzo/i18n'
import { useI18n } from '@hanzo/i18n/react'
import { Grid } from '@hanzo/ui/grid'
import { Band, Head } from '@/components/marketing/band'
import { Action, Chip, Display, Lede, More, Title, Leaf, Lift, Line, type LineProps } from '@hanzo/ui/marketing'
/** How narrow a column may get before a grid drops one, per shape. */
const TRIO = { min: 280, max: 3 } as const
const RAMP = { min: 140, max: 6 } as const
const PAIR_UP = { min: 140, max: 4 } as const
/** The wash a mark's plate is drawn on, at the two strengths this page uses. */
const PLATE = 'color-mix(in srgb, var(--primary) 10%, transparent)'
const BADGE = 'color-mix(in srgb, var(--primary) 15%, transparent)'
const TILE = '$hover'
const CAPTION = { fontSize: '$1', lineHeight: '1.3333', color: 'var(--muted-foreground)' } as const
const LABEL = { fontSize: '$2', lineHeight: '1.4286', fontWeight: '500', color: 'var(--foreground)' } as const
/** A heading inside a section or a card, at the rung and weight it states. */
const Heading = (p: LineProps) => <Line render="h3" display="block" color="var(--foreground)" {...p} />
/** The card whose edge lifts on approach — a `Leaf`, at this page's one wash. */
const LEAF = { p: 24, borderColor: "var(--border)", bg: TILE, hoverStyle: { borderColor: "color-mix(in oklab, var(--pure-white) 30%, transparent)" } } as const
/** A mark's plate, in the page's one accent at 10%. */
const MARK = {
items: 'center',
justify: 'center',
width: 48,
height: 48,
mb: 16,
rounded: 'var(--radius-lg)',
'$platform-web': { backgroundColor: PLATE },
} as const
/**
* A colour, drawn as itself. `fill` is any CSS `background` — a hex, a token,
* or a gradient — because that is the thing the swatch exists to show, and a
* class name was only ever a way of naming it indirectly.
*/
const ColorSwatch = ({ name, hex, fill }: { name: string; hex: string; fill: string }) => {
const { t } = useI18n()
return (
<YStack gap={8}>
<Box width="100%" aspectRatio={1} rounded="var(--radius-lg)" borderWidth={1} borderColor="var(--border)" background={fill} />
<Line render="div" display="block" {...LABEL}>
{t(name)}
</Line>
<Line render="div" display="block" {...CAPTION}>
{t(hex)}
</Line>
</YStack>
)
};
/**
* One rung of the ramp, set in itself. `type` is the style the specimen is
* demonstrating, so the rung and its description travel together and neither
* can be a utility string.
*/
const TypographyExample = ({ name, type, description }: { name: string; type: LineProps; description: string }) => {
const { t } = useI18n()
return (
<YStack gap={8} mb={40}>
<Line render="div" display="block" {...type}>
{t(name)}
</Line>
<Line render="div" display="block" {...CAPTION}>
{t(description)}
</Line>
</YStack>
)
};
const ComponentShowcase = ({ title, children }: { title: string; children: React.ReactNode }) => (
<Box overflow="hidden" rounded="var(--radius-xl)" borderWidth={1} borderColor="$edge">
<Box p={16} borderBottomWidth={1} borderColor="$edge" bg={TILE}>
<Heading {...LABEL}>{title}</Heading>
</Box>
<XStack
flexWrap="wrap"
items="center"
justify="center"
gap={16}
p={32}
bg="$panel"
>
{children}
</XStack>
</Box>
);
const PRINCIPLES = [
{
icon: Sparkles,
title: phrase("Minimal & Focused"),
description: phrase("Reduce visual noise and focus on essential elements. Each design decision should have purpose and enhance the user experience.")
},
{
icon: Type,
title: phrase("Elegant & Refined"),
description: phrase("Use subtle gradients, appropriate spacing, and thoughtful typography to create elegant and sophisticated interfaces.")
},
{
icon: Grid3X3,
title: phrase("Consistent & Cohesive"),
description: phrase("Maintain consistency in design patterns, spacing, and visual hierarchy to create a unified experience across all touchpoints.")
}
] as const
/** A swatch of the design's own palette: the label is the token's value, the fill is the token. */
const swatch = (name: string, token: keyof typeof colors) => ({ name, hex: colors[token], fill: `var(--${token})` })
const BRAND_COLORS = [swatch(phrase("Hanzo Black"), "hanzo-black"), swatch(phrase("Hanzo White"), "hanzo-white")] as const
const GRAY_SCALE = [
swatch(phrase("Gray 900"), "neutral-900"),
swatch(phrase("Gray 800"), "neutral-800"),
swatch(phrase("Gray 700"), "neutral-700"),
swatch(phrase("Gray 600"), "neutral-600"),
swatch(phrase("Gray 500"), "neutral-500"),
swatch(phrase("Gray 400"), "neutral-400"),
] as const
const GRADIENTS = [
{ name: phrase("Brand Glow"), hex: phrase("Radial"), fill: "linear-gradient(to bottom right in oklab, color-mix(in oklab, var(--pure-white) 30%, transparent), transparent)" },
{ name: phrase("White Fade"), hex: phrase("Linear"), fill: "linear-gradient(to bottom in oklab, color-mix(in oklab, var(--pure-white) 10%, transparent), transparent)" },
{ name: phrase("Gray Fade"), hex: phrase("Linear"), fill: "linear-gradient(to right in oklab, color-mix(in oklab, var(--neutral-800) 50%, transparent), transparent)" },
] as const
/** The ramp, each rung set in itself. `--text-*` rather than a frozen pixel,
* so the reader's own type size still moves the specimen it describes. */
const RAMP_ROWS = [
{ name: phrase("Heading 1"), description: phrase("Large page titles, hero sections"), type: { fontSize: '$10', lineHeight: '1.1111', fontWeight: '700', letterSpacing: 'var(--tracking-tight)', color: 'var(--foreground)' } },
{ name: phrase("Heading 2"), description: phrase("Section titles, major divisions"), type: { fontSize: '$8', lineHeight: '1.2', fontWeight: '700', letterSpacing: 'var(--tracking-tight)', color: 'var(--foreground)' } },
{ name: phrase("Heading 3"), description: phrase("Subsection headings, feature headings"), type: { fontSize: '$7', lineHeight: '1.3333', fontWeight: '600', color: 'var(--foreground)' } },
{ name: phrase("Heading 4"), description: phrase("Card titles, minor section headings"), type: { fontSize: '$6', lineHeight: '1.4', fontWeight: '500', color: 'var(--foreground)' } },
{ name: phrase("Body Large"), description: phrase("Featured paragraphs, pull quotes"), type: { fontSize: '$4', lineHeight: 'var(--leading-relaxed)', color: 'color-mix(in oklab, var(--foreground) 80%, transparent)' } },
{ name: phrase("Body"), description: phrase("Primary body text"), type: { fontSize: '$3', lineHeight: 'var(--leading-relaxed)', color: 'var(--muted-foreground)' } },
{ name: phrase("Caption"), description: phrase("Supporting text, metadata, labels"), type: { fontSize: '$2', lineHeight: '1.4286', color: 'var(--muted-foreground)' } },
] as const
/**
* The two heading rungs the ramp above states at `md:` — 6xl for Heading 1 and
* 4xl for Heading 2 — stay OFF the specimen. The row is a demonstration of
* one rung at every width, not the page's own
* heading; the ladder itself lives in `Display` and `Title`, which is where
* this page's real headings take it.
*/
const Brand = () => {
const { t } = useI18n()
return (
<Box minH="100vh" $platform-web={{ color: 'var(--foreground)' }}>
<Box render="main">
{/* Hero Section */}
<Box render="section" position="relative" overflow="hidden" pt={96} pb={64} px={16} $md={{ px: 32 }} $lg={{ px: 48 }}>
<Box position="relative" z="var(--z-raised)" width="100%" maxW={1024} mx="auto">
<Box $platform-web={{ textAlign: 'center' }}>
<Chip
render={<motion.div initial={{ opacity: 0, y: 16 }} animate={{ opacity: 1, y: 0 }} transition={{ duration: 0.4 }} />}
mb={24}
px={12}
py={4}
fontSize="$1"
lineHeight="1.3333"
fontWeight="500"
bg={BADGE}
color="var(--primary)"
>
<Palette width={14} height={14} />
{t('Design System')}
</Chip>
<Display
render={<motion.h1 initial={{ opacity: 0, y: 16 }} animate={{ opacity: 1, y: 0 }} transition={{ duration: 0.4, delay: 0.05 }} />}
mb={24}
>
{t('Hanzo Brand{br}Guidelines.', { br: <br /> })}
</Display>
<Lede
render={<motion.p initial={{ opacity: 0, y: 16 }} animate={{ opacity: 1, y: 0 }} transition={{ duration: 0.4, delay: 0.1 }} />}
mb={40}
width="100%"
maxW={768}
mx="auto"
>
{t('How to build interfaces that look like the rest of Hanzo across our platform and products.')}
</Lede>
<motion.div
initial={{ opacity: 0, y: 16 }}
animate={{ opacity: 1, y: 0 }}
transition={{ duration: 0.4, delay: 0.15 }}
>
<XStack flexWrap="wrap" items="center" justify="center" gap={16}>
<Action href="#assets" fill px={24}>
<Download width={16} height={16} />
{t('Download Assets')}
</Action>
<Action href="/press" px={24} borderColor="var(--border)">
{t('Press Kit')}
</Action>
</XStack>
</motion.div>
</Box>
</Box>
</Box>
{/* Design Principles */}
<Band
rule={false}
pad="$10"
measure={1152}
ground="linear-gradient(to bottom in oklab, var(--background), color-mix(in oklab, var(--neutral-900) 30%, transparent))"
>
<Head title={t('Design Principles')} lede={t('Our core principles guide every design decision we make.')} />
<Grid columns={TRIO} gap={24}>
{PRINCIPLES.map(({ icon: Icon, title, description }, index) => (
<Leaf
render={<motion.div initial={{ opacity: 0, y: 20 }} whileInView={{ opacity: 1, y: 0 }} viewport={{ once: true }} transition={{ delay: index * 0.1 }} />}
key={title}
{...LEAF}
hoverStyle={{ borderColor: "color-mix(in oklab, var(--pure-white) 30%, transparent)" }}
>
<XStack {...MARK}>
<Icon width={24} height={24} />
</XStack>
<Heading mb={8} fontSize="$4" lineHeight="1.5556" fontWeight="600">
{t(title)}
</Heading>
<Line render="p" display="block" fontSize="$2" lineHeight="1.4286" color="var(--muted-foreground)">
{t(description)}
</Line>
</Leaf>
))}
</Grid>
</Band>
{/* Color Palette */}
<Band rule={false} pad="$10" measure={1152}>
<Head title={t('Color Palette')} lede={t('Our colors are carefully selected to create a bold, modern aesthetic.')} />
<YStack gap={48}>
<motion.div
initial={{ opacity: 0, y: 20 }}
whileInView={{ opacity: 1, y: 0 }}
viewport={{ once: true }}
>
<Heading mb={24} fontSize="$6" lineHeight="1.4" fontWeight="500">
{t('Brand Colors')}
</Heading>
<Grid columns={PAIR_UP} gap={24}>
{BRAND_COLORS.map((c) => (
<ColorSwatch key={c.name} name={c.name} hex={c.hex} fill={c.fill} />
))}
</Grid>
</motion.div>
<motion.div
initial={{ opacity: 0, y: 20 }}
whileInView={{ opacity: 1, y: 0 }}
viewport={{ once: true }}
>
<Heading mb={24} fontSize="$6" lineHeight="1.4" fontWeight="500">
{t('Gray Scale')}
</Heading>
<Grid columns={RAMP} gap={24}>
{GRAY_SCALE.map((c) => (
<ColorSwatch key={c.name} name={c.name} hex={c.hex} fill={c.fill} />
))}
</Grid>
</motion.div>
<motion.div
initial={{ opacity: 0, y: 20 }}
whileInView={{ opacity: 1, y: 0 }}
viewport={{ once: true }}
>
<Heading mb={24} fontSize="$6" lineHeight="1.4" fontWeight="500">
{t('Gradients')}
</Heading>
<Grid columns={TRIO} gap={24}>
{GRADIENTS.map((c) => (
<ColorSwatch key={c.name} name={c.name} hex={c.hex} fill={c.fill} />
))}
</Grid>
</motion.div>
</YStack>
</Band>
{/* Typography */}
<Band rule={false} pad="$10" measure={1152} ground="color-mix(in oklab, var(--secondary) 30%, transparent)">
<Head title={t('Typography')} lede={t('Clean, readable typography is essential to our design language.')} />
<Box
render={<motion.div initial={{ opacity: 0, y: 20 }} whileInView={{ opacity: 1, y: 0 }} viewport={{ once: true }} />}
width="100%"
maxW={768}
mx="auto"
p={32}
rounded="var(--radius-xl)"
borderWidth={1}
borderColor="var(--border)"
bg={TILE}
>
{RAMP_ROWS.map((row) => (
<TypographyExample key={row.name} name={row.name} type={row.type} description={row.description} />
))}
</Box>
</Band>
{/* Components */}
<Band rule={false} pad="$10" measure={1152}>
<Head title={t('Components')} lede={t('Reusable UI components that maintain consistency across our products.')} />
<YStack gap={32}>
<motion.div
initial={{ opacity: 0, y: 20 }}
whileInView={{ opacity: 1, y: 0 }}
viewport={{ once: true }}
>
<ComponentShowcase title={t('Buttons')}>
<Action render="span" fill>
{t('Primary Button')}
</Action>
<Action render="span" borderColor="var(--border)">
{t('Secondary Button')}
</Action>
<Action render="span" borderWidth={0}>
{t('Ghost Button')}
</Action>
<More render="span">
{t('Link Button')}
</More>
</ComponentShowcase>
</motion.div>
<motion.div
initial={{ opacity: 0, y: 20 }}
whileInView={{ opacity: 1, y: 0 }}
viewport={{ once: true }}
>
<ComponentShowcase title={t('Cards')}>
<Leaf width="100%" maxW={448} {...LEAF}>
<Heading mb={8} fontSize="$6" lineHeight="1.4" fontWeight="500">
{t('Card Title')}
</Heading>
<Line render="p" display="block" mb={16} color="var(--muted-foreground)">
{t('This is a standard card component with hover states and consistent styling.')}
</Line>
<Action render="span" minH={36} px={16} borderColor="var(--border)">
{t('Learn More')}
</Action>
</Leaf>
</ComponentShowcase>
</motion.div>
<motion.div
initial={{ opacity: 0, y: 20 }}
whileInView={{ opacity: 1, y: 0 }}
viewport={{ once: true }}
>
<ComponentShowcase title={t('Badges')}>
<Chip px={12} py={4} borderWidth={0} fontWeight="500" bg={BADGE} color="var(--primary)">
{t('Brand Badge')}
</Chip>
<Chip px={12} py={4} borderColor="var(--border)" fontWeight="500" bg="var(--secondary)" color="color-mix(in oklab, var(--foreground) 80%, transparent)">
{t('Default Badge')}
</Chip>
<Chip px={12} py={4} borderColor="var(--border)" fontWeight="500" bg={PLATE} color="color-mix(in oklab, var(--foreground) 70%, transparent)">
{t('Success Badge')}
</Chip>
</ComponentShowcase>
</motion.div>
</YStack>
</Band>
{/* Download Assets */}
<Band id="assets" rule={false} pad="$10" measure={1152} ground="color-mix(in oklab, var(--secondary) 30%, transparent)">
<Head title={t('Download Assets')} lede={t('Get our brand assets for your projects and presentations.')} />
<Box width="100%" maxW={448} mx="auto">
<Leaf
render={<motion.a initial={{ opacity: 0, y: 20 }} whileInView={{ opacity: 1, y: 0 }} viewport={{ once: true }} />}
href="/press/hanzo-press-kit.zip"
{...LEAF}
hoverStyle={{ borderColor: "color-mix(in oklab, var(--pure-white) 30%, transparent)" }}
>
<XStack {...MARK}>
<Download width={24} height={24} />
</XStack>
{/* The card decides the lift; the content says who takes part. */}
<Lift render="h3" display="block" mb={4} fontSize="$4" lineHeight="1.5556" fontWeight="600" color="var(--foreground)">
{t('Press Kit')}
</Lift>
<Line render="p" display="block" mb={8} fontSize="$2" lineHeight="1.4286" color="var(--muted-foreground)">
{t('Logos and brand assets (ZIP)')}
</Line>
</Leaf>
</Box>
</Band>
{/*
CTA Section — NOT a `Band`, and the reason is the two glows. They are
direct children of the section and are placed from ITS corners; inside
a Band they would fall to the inner measure box and step ~270px in from
each edge. A decorative element positioned against the frame keeps the
frame it was positioned against.
*/}
<Box
render="section"
position="relative"
overflow="hidden"
py={96}
px={16}
$md={{ px: 32 }}
background="linear-gradient(to bottom in oklab, color-mix(in oklab, var(--neutral-900) 30%, transparent), var(--background))"
>
<Box position="absolute" t={-160} r={-160} width={320} height={320} rounded="var(--radius-full)" pointerEvents="none" filter="blur(64px)" $platform-web={{ backgroundColor: 'color-mix(in oklab, var(--primary) 10%, transparent)' }} />
<Box position="absolute" b={-160} l={-160} width={320} height={320} rounded="var(--radius-full)" pointerEvents="none" filter="blur(64px)" $platform-web={{ backgroundColor: 'color-mix(in oklab, var(--primary) 5%, transparent)' }} />
<Box position="relative" z="var(--z-raised)" width="100%" maxW={896} mx="auto" $platform-web={{ textAlign: 'center' }}>
<Title
render={<motion.h2 initial={{ opacity: 0, y: 20 }} whileInView={{ opacity: 1, y: 0 }} viewport={{ once: true }} />}
quiet
mb={16}
>
{t('Need brand assistance?')}
</Title>
<Lede
render={<motion.p initial={{ opacity: 0, y: 20 }} whileInView={{ opacity: 1, y: 0 }} viewport={{ once: true }} transition={{ delay: 0.1 }} />}
mb={40}
width="100%"
maxW={672}
mx="auto"
mt="$3.5"
>
{t('Our team can help with custom assets, co-branding requests, and other brand-related inquiries.')}
</Lede>
<motion.div
initial={{ opacity: 0, y: 20 }}
whileInView={{ opacity: 1, y: 0 }}
viewport={{ once: true }}
transition={{ delay: 0.2 }}
>
<XStack flexWrap="wrap" items="center" justify="center" gap={16}>
<Action href="/contact" fill px={32}>
{t('Contact Us')}
<ArrowRight width={20} height={20} data-i18n-mirror />
</Action>
<Action href="mailto:[email protected]" px={32} borderColor="var(--border)">
brand@hanzo.ai
</Action>
</XStack>
</motion.div>
</Box>
</Box>
</Box>
</Box>
);
};
export default Brand;