Files
hanzo.ai/components/analytics/Security.tsx
zeekayandHanzo Dev f11062f432 fix(analytics): theme-aware hero ground and surfaces to fix light-mode contrast
The /analytics landing page hardcoded theme-independent colors
(var(--pure-black), var(--pure-white), --neutral-*) into the hero ground,
dashboard mock, code windows and section washes. In light mode that meant
near-black ink on a pure-black hero and white chart lines on light
surfaces — unreadable and harsh.

Swap them for @hanzo/design's theme-aware tokens (--background, --muted,
--secondary, --primary, --muted-foreground). Dark rendering is unchanged;
light mode now resolves correctly.

Verified with headless Chromium (hero bg/ink before vs after) and clean
tsc --noEmit / design lint.


Co-authored-by: Hanzo Dev <[email protected]>
2026-10-25 09:02:26 -07:00

156 lines
6.9 KiB
TypeScript

'use client'
import React from "react";
import { motion } from "@/components/motion";
import { ShieldCheck, Lock, CheckCircle } from "lucide-react";
import { Band, Head, INK } from '@/components/marketing/band'
import { More } from '@hanzo/ui/marketing'
import { Body, Disc, Sub, Title, ink } from './kit'
import { Box, Text, XStack, YStack } from '@hanzo/ui'
import { Grid } from '@hanzo/ui/grid'
import { phrase } from '@hanzo/i18n'
import { useI18n } from '@hanzo/i18n/react'
// A framework name under a heading reading "Certifications" IS a claim to
// hold one, whatever the line beneath it says -- and the qualifier here sat in
// `details`, a second line nobody reads before they read the name. That is the
// exact shape the /security badge row had. What each of these is instead: a
// control we run, named by the control.
const assurances = [
{ name: phrase("Continual internal audits"), details: phrase("Report on request.") },
{ name: phrase("Data protection"), details: phrase("EU data handling, deletion, and export on request.") },
{ name: phrase("Privacy by design"), details: phrase("Collected because it is used, not because it can be.") }
];
const SecurityFeatures = [
phrase("End-to-end encryption"),
phrase("Data residency controls"),
phrase("Custom data retention policies"),
phrase("Role-based access control"),
phrase("Regular security audits"),
phrase("Privacy-focused data collection"),
phrase("Automated compliance monitoring")
];
/** The two panels' shared ground — neutral falling to half of itself. */
const PANEL = { background: 'linear-gradient(to bottom right, var(--muted), color-mix(in oklab, var(--muted) 50%, transparent))' } as const
/** One of the two panels. */
function Panel({ children }: { children: React.ReactNode }) {
return (
<Box height="100%" rounded="var(--radius-xl)" borderWidth={1} borderColor="var(--neutral-800)" p="$5" $platform-web={PANEL}>
{children}
</Box>
)
}
const Security = () => {
const { t } = useI18n()
return (
<Band rule={false} pad="$14" measure={1152} ground={INK}>
<Box position="relative" z="var(--z-raised)">
<XStack mb="$4" justify="center">
<ShieldCheck size={40} color="var(--foreground)" />
</XStack>
<Head
loud
title={t('Enterprise-Grade Security & Compliance')}
lede={t('Secure by design, ensuring your data meets stringent compliance standards.')}
/>
{/* One column on a phone, three from `$lg` — a fixed `columns={3}` never
collapses and pushes the wide panel off the side. */}
<Box display="grid" gridTemplateColumns="minmax(0,1fr)" gap="$6" mb="$10" $lg={{ gridTemplateColumns: 'repeat(3, minmax(0,1fr))' }}>
<motion.div initial={{ opacity: 0, y: 20 }} whileInView={{ opacity: 1, y: 0 }} viewport={{ once: true }} transition={{ duration: 0.5 }}>
<Panel>
<XStack justify="center" mb="$5">
<Disc pct={20}>
<Lock size={32} />
</Disc>
</XStack>
<Title mb={24} text="center">
{t('Security Features')}
</Title>
<YStack render="ul" gap="$3">
{SecurityFeatures.map((feature, index) => (
<XStack key={feature} render="li">
<motion.div initial={{ opacity: 0, x: -10 }} whileInView={{ opacity: 1, x: 0 }} viewport={{ once: true }} transition={{ duration: 0.3, delay: 0.1 * index }}>
<XStack items="center">
<XStack mr={12} shrink={0}>
<CheckCircle size={20} color="var(--foreground)" />
</XStack>
<Text fontSize="$3" lineHeight="1.25rem" $platform-web={{ color: ink(80) }}>
{t(feature)}
</Text>
</XStack>
</motion.div>
</XStack>
))}
</YStack>
</Panel>
</motion.div>
{/* A one-cell grid, so the panel inside stretches to the row the
narrow panel beside it sets. */}
<Box display="grid" $lg={{ gridColumn: 'span 2' }} minW={0}>
<motion.div initial={{ opacity: 0, y: 20 }} whileInView={{ opacity: 1, y: 0 }} viewport={{ once: true }} transition={{ duration: 0.5, delay: 0.2 }}>
<Panel>
<Title mb={24}>{t('Security and assurance')}</Title>
<Grid columns={{ min: 260, max: 2 }} gap={24}>
{assurances.map((cert, index) => (
<motion.div
key={cert.name}
initial={{ opacity: 0, y: 20 }}
whileInView={{ opacity: 1, y: 0 }}
viewport={{ once: true }}
transition={{ duration: 0.5, delay: 0.1 * index }}
>
<Box height="100%" rounded="var(--radius-lg)" borderWidth={1} borderColor="var(--neutral-700)" bg="$panel" p={20}>
<XStack items="center">
<Box mr={12}>
<Disc pct={30} pad={8} edge="none">
<ShieldCheck size={24} />
</Disc>
</Box>
<Sub>{t(cert.name)}</Sub>
</XStack>
<Body mt={12}>{t(cert.details)}</Body>
</Box>
</motion.div>
))}
</Grid>
<Box mt="$6" rounded="var(--radius-lg)" borderWidth={1} borderColor="$edge" bg="$raised" p={20}>
<XStack>
<Box mr={16} self="flex-start">
<Disc pct={20} pad={8} edge="none">
<svg width={24} height={24} fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M13 16h-1v-4h-1m1-4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z" />
</svg>
</Disc>
</Box>
<Box>
<Sub mb={8}>{t('Data Privacy Commitment')}</Sub>
<Body>
{t('Hanzo Analytics collects what a report uses and nothing else. You choose where the data lives, how long it is kept, and who on your team can read it, and you can export or delete it on request.')}
</Body>
<More href="/legal/privacy" mt={12} color="var(--foreground)">
{t('Read our privacy policy →')}
</More>
</Box>
</XStack>
</Box>
</Panel>
</motion.div>
</Box>
</Box>
</Box>
</Band>
);
};
export default Security;