Files
zeekayandHanzo Dev d1a39698ee Give the ramp every hue and boot it dark
Yellow and orange were dropped for failing 3:1 against the light ground at
one uniform rung, which was a fact about the rung. Each stop now names the
rung that shows it on each scheme, and every dot carries an ink hairline —
the edge that draws white on white, black on black, and the yellow that no
rung can both darken and keep yellow. White, grey and black join as stops;
grey still clears the accent, and none of the three washes the page, since
an absolute palette under the other scheme's ink is a page with its text
turned off.

Dark is the default a reader who has named neither scheme gets: the meta
hands the UA dark rather than the machine's own answer, and the setting
that meant "ask the machine" is dropped, since the pre-paint script and the
app resolved it differently and the page turned light a frame after booting.

Co-authored-by: Hanzo Dev <[email protected]>
2026-09-07 23:35:59 -07:00

125 lines
5.6 KiB
TypeScript

import '@hanzogui/core/reset.css'
import '@hanzo/design/styles.css'
import '~/app.css'
import '~/hanzogui.generated.css'
import { bootScript } from '@hanzo/appearance/state'
import { LoadProgressBar, Slot } from 'one'
import { setupPopper } from '@hanzo/gui'
import { Providers } from '../components/Providers'
setupPopper({
// prevents a reflow on mount
disableRTL: true,
})
// Inlined @font-face, so the faces cost no render-blocking stylesheet. The
// files come from @hanzo/font — one variable file per family instead of a
// weight per request — and are copied into public/fonts because a self-hosted
// site has to serve them from its own origin.
//
// font-display:swap paints a fallback immediately rather than holding text
// invisible; the three files are preloaded below so that window is short.
const fontFaceCss = `
@font-face{font-family:'Zen';src:url('/fonts/Zen-Variable.woff2') format('woff2-variations');font-weight:100 900;font-style:normal;font-display:swap}
@font-face{font-family:'Zen Mono';src:url('/fonts/ZenMono-Variable.woff2') format('woff2-variations');font-weight:100 900;font-style:normal;font-display:swap}
@font-face{font-family:'Zen Pixel Square';src:url('/fonts/ZenPixel-Square.woff2') format('woff2');font-weight:500;font-style:normal;font-display:swap}`
export default function Layout() {
return (
// Dark is the default every Hanzo surface shares. The class is here so the
// first paint already carries gui's dark scope; SchemeProvider's own script
// corrects it before paint for a reader who chose light.
<html lang="en-US" className="t_dark" suppressHydrationWarning>
<head>
<meta charSet="utf-8" />
<meta httpEquiv="X-UA-Compatible" content="IE=edge" />
<meta
name="viewport"
content="width=device-width, initial-scale=1, maximum-scale=5"
/>
{/* The ground before any stylesheet lands, so no frame paints white. */}
<style>{`html{background:#0a0a0a;color-scheme:dark}html.t_light{background:#f7f7f7;color-scheme:light}`}</style>
{/* The site's scheme is dark or light and nothing else. A value stored
when there was a third answer is dropped before anything reads it,
so the pre-paint script and the app cannot disagree over what it
meant; the provider's own default is what fills the gap. */}
<script
dangerouslySetInnerHTML={{
__html: `try{if(localStorage.getItem('vxrn-scheme')==='system')localStorage.removeItem('vxrn-scheme')}catch(e){}`,
}}
/>
{/* The reader's own type scale, density, face, measure and accent, back
on the document before first paint. @hanzo/appearance writes them to
storage; this is the half that reads them. */}
<script dangerouslySetInnerHTML={{ __html: bootScript() }} />
{/* @hanzo/design scopes its light tokens to `html.light` and gui to
`t_light`. One theme, two vocabularies: the second is derived from
the first, and the observer carries a switch across. */}
<script
dangerouslySetInnerHTML={{
__html: `(function(){var e=document.documentElement,was;function s(){var l=e.classList.contains('t_light');if(l===was)return;was=l;e.classList.toggle('light',l)}s();new MutationObserver(s).observe(e,{attributes:true,attributeFilter:['class']})})()`,
}}
/>
{/* Copied from @hanzo/logo/dist at prebuild — the mark has one home. */}
<link rel="icon" href="/favicon.ico" sizes="any" />
<link rel="icon" href="/favicon.svg" type="image/svg+xml" />
<meta name="docsearch:language" content="en" />
<meta name="docsearch:version" content="1.0.0,latest" />
<meta id="theme-color" name="theme-color" />
{/* Dark, not "dark light": the second form hands the choice back to the
OS for the blank frame the browser paints before this document does,
which is a white flash on a light machine. `html.t_light` above puts
it back for a reader who asked for light. */}
<meta name="color-scheme" content="dark" />
<meta name="twitter:card" content="summary_large_image" />
<meta name="twitter:site" content="@hanzogui_js" />
<meta name="twitter:creator" content="@natebirdman" />
<meta name="robots" content="index,follow" />
<link
rel="preload"
href="/fonts/ZenMono-Variable.woff2"
as="font"
crossOrigin="anonymous"
type="font/woff2"
/>
<link
rel="preload"
href="/fonts/Zen-Variable.woff2"
as="font"
crossOrigin="anonymous"
type="font/woff2"
/>
<link
rel="preload"
href="/fonts/ZenPixel-Square.woff2"
as="font"
crossOrigin="anonymous"
type="font/woff2"
/>
{/* inline @font-face instead of 4 render-blocking <link> stylesheets (each
cost a round-trip ~500ms on slow connections and blocked first paint).
font-display: swap (was block) lets text paint immediately with a
fallback instead of staying invisible until the font loads (FOIT) —
this was the LCP bottleneck (3.1s element render delay). fonts are
preloaded above so the swap window is short. */}
<style>{fontFaceCss}</style>
</head>
<body>
<LoadProgressBar />
{/* warm cherry-bomb on first interaction so it's ready when navigating
to the pages that use it, no eager preload */}
<Providers>
<Slot />
</Providers>
</body>
</html>
)
}