Files
zeekayandHanzo Dev 0a3ebececd Ship the real Hanzo mark, and stop the chat button sitting on it
The favicon was hand-made. `6c17299` replaced the generated scaffold icon with a
drawn "Hanzo H mark" whose blob is byte-identical to what production still
serves: three layers, fully opaque, polarity inverted, and offset about half a
cell so two of the four corner squares fall off the canvas. At its real 16px
tab size it is a pale smear. Take the mark from `@hanzo/logo` instead — already
a dependency here, already the source of the header logo — and ship the whole
set it publishes: favicon.ico (6 layers, 16→256), favicon.svg, apple-touch-icon.
`<head>` now declares all three; it previously declared one 696px opaque PNG and
nothing else, which also suppressed `app/icon.svg` (deleted — the mark has one
home now).

The header mark was invisible, and the fix on main only moved which theme it was
invisible in. `variant="mono"` does not inherit `currentColor` as Logo.tsx
claimed — it is hardcoded #000000, so main rendered black on the black page.
It is one ink on transparency, exactly like every mark in `partner-logos.ts`, so
it is carried the same way: `hz-ink-black`, none on light and invert(1) on dark.
The inversion lands on #ffffff/#DDDDDD, which is the `white` variant byte for
byte.

The chat launcher was covering the logo. `hz-fixed` sets `position: fixed` and
nothing else, so a fixed element with no offsets stays where it was: top-left,
48px square, directly over the mark, on every page and both themes. Nothing
could catch it — every class on the button had a rule, the missing one was never
written. Added `hz-dock` as that one rule, and sized the panel against the
viewport so it cannot grow past the screen it is docked to. The panel also took
`hz-bg` from `hz-bg-surface`, whose dark value is rgba(38,38,38,.5): right for a
card on the page, wrong for one floating over it.

A fabricated trademark is gone. `lux-network.svg` was hand-coded rects and
polygons spelling "LUX", nothing like the real mark, duplicated under three
filenames. Lux and Zoo Labs are sibling orgs in this estate, not our clients —
their marks and their entries in `clients` are both removed. A Hanzo surface
carries Hanzo branding.

Every share card 404'd: og:image pointed at `/opengraph-image`, a file-convention
route this app does not have, while the real `/og-image.png` sat declared and
unused. og:site_name was carrying the tagline and twitter:title disagreed with
og:title; both now say what they are.

The repo count contradicted itself in one viewport — "727+" in the hero, "2,500+"
in a tile 200px below it, 3.4x apart, and both in `<head>`. Neither survives
measurement: 535 non-archived public repos across the six orgs the site names.
Stated once now, as a floor, with the query that produced it.

"All systems operational" was a hardcoded string on every page with no health
check behind it — it would have said that straight through an outage. It links
to /status as "System status" instead.

Verified in a real browser at 390 and 1280, light and dark: the mark matches an
isolated render of the same SVG (mean abs diff 0.05/255) and dark is its exact
inverse; `elementFromPoint` at the mark's centre returns its own path; the
served .ico is 2b734c3b, six layers. Routes 60/60, no overflow, no console
errors.

Co-authored-by: Hanzo Dev <[email protected]>
2026-08-05 16:27:35 -07:00

63 lines
1.9 KiB
TypeScript

import type { Metadata, Viewport } from 'next'
import site from '@/site.config'
import { Providers } from './providers'
import './globals.css'
// Geist Sans and Geist Mono arrive self-hosted with @hanzo/design (globals.css),
// so there is no build-time fetch from fonts.googleapis.com and no second place
// the site's typeface is named.
export const metadata: Metadata = {
metadataBase: new URL(site.brand.url),
title: {
template: site.seo.titleTemplate,
default: site.seo.defaultTitle,
},
description: site.brand.description,
openGraph: {
// `/opengraph-image` is Next's file-convention route and this app has no
// such file — it 404'd, so every share card was blank. The real asset is
// `site.seo.ogImage`, which was declared and never used. 2400x1258.
images: [{ url: site.seo.ogImage, width: 2400, height: 1258, alt: site.seo.defaultTitle }],
siteName: site.brand.name,
title: site.seo.defaultTitle,
type: 'website',
url: site.brand.url,
},
twitter: {
card: 'summary_large_image',
title: site.seo.defaultTitle,
description: site.brand.description,
images: [site.seo.ogImage],
},
// Declared explicitly, so `app/icon.svg`'s file convention is not silently
// overridden by a partial `icons` block — that is how this site ended up
// announcing a 696px opaque PNG as its only icon while serving a broken .ico.
icons: {
icon: [
{ url: site.seo.icons.ico, sizes: '16x16 32x32 48x48 64x64 128x128 256x256' },
{ url: site.seo.icons.svg, type: 'image/svg+xml' },
],
apple: site.seo.icons.appleTouch,
shortcut: site.seo.icons.ico,
},
}
export const viewport: Viewport = {
themeColor: site.seo.themeColor,
}
export default function RootLayout({
children,
}: {
children: React.ReactNode
}) {
return (
<html lang="en" suppressHydrationWarning>
<body>
<Providers>{children}</Providers>
</body>
</html>
)
}