Files
zeekay dc053ec955 the face is Zen, and it ships from @hanzo/font
One family. Font stacks name Zen and fall back to the native faces, tokens
name the role rather than a face, and the packages that used to supply a
face now point at @hanzo/font.

Self-hosted @font-face blocks are removed rather than renamed: rewriting the
family in one would leave a src pointing at a file this repo no longer ships.
@hanzo/font carries the binaries and declares the faces, so the local copies
go with the declaration that used them.

Comments naming a face we no longer use are deleted, not reworded.
2026-09-01 13:58:32 -07:00

867 lines
21 KiB
CSS

/**
* The one stylesheet.
*
* Design tokens come from @hanzo/ui — the canonical Hanzo identity, plain CSS
* custom properties, no build step. Everything below is a small SEMANTIC
* vocabulary (`rfc-card`, `rfc-badge`, `rfc-row`…) named for what a thing IS,
* not for what it looks like. There is exactly one definition per concept and
* markup never encodes presentation.
*
* No Tailwind, no utility strings, no `!important` — nothing is fighting a
* framework for the cascade any more.
*/
@import '@hanzo/ui/theme.css';
/* Zen, the one family. @hanzo/design ships the faces and declares them, so this
import is the whole of it — nothing is vendored here and a face update arrives
with the package.
It follows the identity, and that ORDER is the rule, not tidiness: theme.css
defines --font-sans and --font-mono as Geist itself, at bare :root. Two equal
declarations of one property, so the later file wins and Zen is only the later
file while this line stays below. Swap the two imports and every surface silently
goes back to asking for a face nothing loads. */
@import '@hanzo/design/tokens/fonts.css';
/* ── Tokens this site adds on top of the identity ─────────────────────────── */
:root {
/* @hanzo/ui still spells the identity's families --font-sans*, and its own
body/code rules read those names. Point them at Zen so nothing downstream
resolves a second family. */
--font-sans: Zen, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
--font-mono: Zen Mono, ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", monospace;
/* Semantic hues. The proposal lifecycle and the category accents are the only
places this site uses colour, and every one of them resolves here. */
--hue-green: oklch(0.72 0.17 152);
--hue-emerald: oklch(0.72 0.15 162);
--hue-amber: oklch(0.78 0.16 76);
--hue-orange: oklch(0.72 0.17 52);
--hue-blue: oklch(0.66 0.18 253);
--hue-cyan: oklch(0.72 0.13 210);
--hue-indigo: oklch(0.61 0.2 275);
--hue-violet: oklch(0.63 0.22 296);
--hue-purple: oklch(0.63 0.23 305);
--hue-pink: oklch(0.68 0.21 350);
--hue-rose: oklch(0.67 0.21 15);
--hue-red: oklch(0.64 0.22 27);
/* Lifecycle → hue. One table; badges and dots both read it. */
--status-final: var(--hue-emerald);
--status-review: var(--hue-amber);
--status-last-call: var(--hue-blue);
--status-draft: var(--muted-foreground);
--status-withdrawn: var(--hue-red);
--shell-max: 72rem;
--prose-max: 50rem;
--sidebar-width: 16.25rem;
--toc-width: 14rem;
--header-height: 3.5rem;
--tint: 12%;
--code-bg: oklch(0.16 0 0);
--code-fg: oklch(0.92 0 0);
}
/* gui names its face through ONE property, --f-family, which it sets on each
`.font_<token>` class it injects at runtime and every component reads. It wraps
the app in `.font_body`, so whatever that resolves to is the whole page. Point
them at Zen. The doubled `:root` is the specificity: gui injects after this
sheet, so an equal-weight rule would lose on source order.
Three of gui's four font tokens resolve here. The fourth, `silkscreen`, is a
pixel face with no counterpart in the token layer, and nothing on this site
asks for it — Zen Pixel exists but @hanzo/design declares no variable for it,
and vendoring the binary to invent one is the thing this import avoids. */
:root:root .font_body,
:root:root .font_heading {
--f-family: var(--font-sans);
}
:root:root .font_mono {
--f-family: var(--font-mono);
}
/* Category accent. A component sets `data-accent="blue"` and everything inside
reads `--hue` — no per-colour class table duplicated across pages. */
[data-accent] { --hue: var(--hue-blue); }
[data-accent='green'] { --hue: var(--hue-green); }
[data-accent='emerald'] { --hue: var(--hue-emerald); }
[data-accent='amber'] { --hue: var(--hue-amber); }
[data-accent='orange'] { --hue: var(--hue-orange); }
[data-accent='blue'] { --hue: var(--hue-blue); }
[data-accent='cyan'] { --hue: var(--hue-cyan); }
[data-accent='indigo'] { --hue: var(--hue-indigo); }
[data-accent='violet'] { --hue: var(--hue-violet); }
[data-accent='purple'] { --hue: var(--hue-purple); }
[data-accent='pink'] { --hue: var(--hue-pink); }
[data-accent='rose'] { --hue: var(--hue-rose); }
[data-accent='red'] { --hue: var(--hue-red); }
/* ── Element defaults ─────────────────────────────────────────────────────── */
*,
*::before,
*::after {
box-sizing: border-box;
}
html {
scroll-behavior: smooth;
-webkit-text-size-adjust: 100%;
}
body {
margin: 0;
min-height: 100svh;
background: var(--background);
color: var(--foreground);
font-synthesis-weight: none;
text-rendering: optimizeLegibility;
-webkit-font-smoothing: antialiased;
}
a {
color: inherit;
text-decoration: none;
}
button {
font: inherit;
color: inherit;
background: none;
border: 0;
padding: 0;
cursor: pointer;
}
svg {
display: block;
flex: none;
}
::selection {
background: color-mix(in oklch, var(--foreground) 20%, transparent);
}
/* ── Layout primitives ────────────────────────────────────────────────────── */
.rfc-shell {
width: 100%;
max-width: var(--shell-max);
margin-inline: auto;
padding-inline: 1rem;
}
@media (min-width: 40rem) {
.rfc-shell { padding-inline: 1.5rem; }
}
@media (min-width: 64rem) {
.rfc-shell { padding-inline: 2rem; }
}
/* Vertical flow with one gap knob. */
.rfc-stack {
display: flex;
flex-direction: column;
gap: var(--gap, 0.75rem);
}
/* Horizontal run that wraps. */
.rfc-cluster {
display: flex;
flex-wrap: wrap;
align-items: center;
gap: var(--gap, 0.75rem);
}
.rfc-cluster[data-between] {
justify-content: space-between;
}
.rfc-cluster[data-center] {
justify-content: center;
}
.rfc-grid {
display: grid;
gap: 1rem;
grid-template-columns: 1fr;
}
@media (min-width: 40rem) {
.rfc-grid[data-cols='2'],
.rfc-grid[data-cols='3'],
.rfc-grid[data-cols='4'] { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
@media (min-width: 64rem) {
.rfc-grid[data-cols='3'] { grid-template-columns: repeat(3, minmax(0, 1fr)); }
.rfc-grid[data-cols='4'] { grid-template-columns: repeat(4, minmax(0, 1fr)); }
}
.rfc-section {
padding-block: 4rem;
}
@media (min-width: 40rem) {
.rfc-section { padding-block: 5rem; }
}
.rfc-section[data-tinted] {
background: color-mix(in oklch, var(--muted) 35%, transparent);
border-block: 1px solid var(--border);
}
/* ── Type ─────────────────────────────────────────────────────────────────── */
.rfc-title {
font-size: clamp(2.25rem, 1.5rem + 3vw, 3.75rem);
font-weight: 700;
letter-spacing: -0.03em;
line-height: 1.1;
margin: 0;
}
.rfc-heading {
font-size: 1.5rem;
font-weight: 700;
letter-spacing: -0.02em;
margin: 0;
}
.rfc-subheading {
font-size: 1.125rem;
font-weight: 600;
letter-spacing: -0.015em;
margin: 0;
}
.rfc-lead {
font-size: 1.125rem;
line-height: 1.6;
color: var(--muted-foreground);
margin: 0;
}
.rfc-muted {
color: var(--muted-foreground);
}
.rfc-mono {
font-family: Zen Mono, ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", monospace;
font-variant-numeric: tabular-nums;
}
.rfc-small {
font-size: 0.875rem;
}
.rfc-fine {
font-size: 0.75rem;
}
.rfc-truncate {
min-width: 0;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.rfc-clamp {
display: -webkit-box;
-webkit-box-orient: vertical;
-webkit-line-clamp: var(--lines, 2);
line-clamp: var(--lines, 2);
overflow: hidden;
}
.rfc-link {
color: var(--muted-foreground);
transition: color 0.15s ease;
}
.rfc-link:hover {
color: var(--foreground);
}
.rfc-link[data-underline] {
text-decoration: underline;
text-underline-offset: 4px;
}
/* ── Controls ─────────────────────────────────────────────────────────────── */
/* No button rule lives here. A button is `<Button>` from @hanzo/ui — one
definition, already carrying the variant, size, hover, focus ring and 44px
touch floor, and the same component on web, native and desktop. A local
`.rfc-btn` would be a second answer to a question already answered. */
.rfc-card:focus-visible,
.rfc-row:focus-visible {
outline: 2px solid var(--ring);
outline-offset: 2px;
}
.rfc-kbd {
display: inline-flex;
align-items: center;
gap: 0.125rem;
padding: 0.125rem 0.375rem;
border: 1px solid var(--border);
border-radius: 0.25rem;
background: var(--muted);
font-family: Zen Mono, ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", monospace;
font-size: 0.6875rem;
color: var(--muted-foreground);
}
/* ── Surfaces ─────────────────────────────────────────────────────────────── */
.rfc-card {
display: flex;
flex-direction: column;
gap: 0.5rem;
padding: 1.5rem;
border: 1px solid var(--border);
border-radius: calc(var(--radius) * 1.5);
background: var(--card);
color: var(--card-foreground);
transition: border-color 0.15s ease, background-color 0.15s ease;
}
.rfc-card[data-accent] {
border-color: color-mix(in oklch, var(--hue) 25%, transparent);
}
a.rfc-card:hover,
a.rfc-card:focus-visible {
border-color: color-mix(in oklch, var(--foreground) 25%, var(--border));
}
.rfc-row {
display: flex;
align-items: center;
gap: 1rem;
padding: 0.75rem;
border: 1px solid var(--border);
border-radius: var(--radius);
transition: border-color 0.15s ease, background-color 0.15s ease;
}
a.rfc-row:hover {
border-color: color-mix(in oklch, var(--foreground) 25%, var(--border));
background: color-mix(in oklch, var(--accent) 50%, transparent);
}
.rfc-panel {
padding: 1rem;
border: 1px solid var(--border);
border-radius: var(--radius);
background: var(--card);
}
/* ── Badges, dots, tiles ──────────────────────────────────────────────────── */
.rfc-badge {
--hue: var(--status-draft);
display: inline-flex;
align-items: center;
gap: 0.375rem;
flex: none;
padding: 0.125rem 0.5rem;
border-radius: 999px;
border: 1px solid color-mix(in oklch, var(--hue) 30%, transparent);
background: color-mix(in oklch, var(--hue) var(--tint), transparent);
color: var(--hue);
font-size: 0.75rem;
font-weight: 500;
white-space: nowrap;
}
.rfc-badge[data-status='Final'] { --hue: var(--status-final); }
.rfc-badge[data-status='Review'] { --hue: var(--status-review); }
.rfc-badge[data-status='Last Call'] { --hue: var(--status-last-call); }
.rfc-badge[data-status='Withdrawn'] { --hue: var(--status-withdrawn); }
/* Neutral pill: counts, ranges, tags. */
.rfc-pill {
display: inline-flex;
align-items: center;
flex: none;
padding: 0.125rem 0.5rem;
border-radius: 999px;
background: var(--muted);
color: var(--muted-foreground);
font-size: 0.75rem;
transition: background-color 0.15s ease, color 0.15s ease;
}
a.rfc-pill:hover {
background: color-mix(in oklch, var(--primary) var(--tint), transparent);
color: var(--foreground);
}
.rfc-dot {
width: 0.5rem;
height: 0.5rem;
border-radius: 999px;
background: var(--hue, var(--muted-foreground));
flex: none;
}
.rfc-tile {
display: inline-flex;
align-items: center;
justify-content: center;
flex: none;
width: 3rem;
height: 3rem;
border-radius: calc(var(--radius) * 1.5);
background: color-mix(in oklch, var(--hue, var(--muted-foreground)) var(--tint), transparent);
color: var(--hue, var(--foreground));
}
.rfc-tile[data-size='sm'] {
width: 2rem;
height: 2rem;
border-radius: var(--radius);
background: var(--muted);
color: var(--muted-foreground);
}
/* ── Stats strip ──────────────────────────────────────────────────────────── */
.rfc-stats {
display: grid;
grid-template-columns: repeat(2, minmax(0, 1fr));
}
@media (min-width: 40rem) {
.rfc-stats { grid-template-columns: repeat(4, minmax(0, 1fr)); }
}
.rfc-stat {
padding: 2rem 1rem;
text-align: center;
border-inline-start: 1px solid var(--border);
}
.rfc-stat:first-child,
.rfc-stat:nth-child(3) {
border-inline-start: 0;
}
@media (min-width: 40rem) {
.rfc-stat:nth-child(3) { border-inline-start: 1px solid var(--border); }
}
.rfc-stat-value {
font-size: 2rem;
font-weight: 700;
font-variant-numeric: tabular-nums;
line-height: 1.1;
}
/* ── Site chrome ──────────────────────────────────────────────────────────── */
.rfc-header {
position: sticky;
top: 0;
z-index: 40;
border-bottom: 1px solid var(--border);
background: color-mix(in oklch, var(--background) 85%, transparent);
backdrop-filter: blur(16px);
}
.rfc-header > .rfc-shell {
display: flex;
align-items: center;
justify-content: space-between;
height: var(--header-height);
}
.rfc-footer {
border-top: 1px solid var(--border);
padding-block: 3rem;
}
.rfc-cta {
border-radius: calc(var(--radius) * 3);
background: var(--foreground);
color: var(--background);
padding: 2rem;
}
@media (min-width: 40rem) {
.rfc-cta { padding: 3rem; }
}
/* The CTA inverts the page, so the gui components on it need the inverted gui
theme — <Inverted> in components/inverted.tsx, not a per-control override
here. One inversion covers every control the panel ever holds. */
/* ── Logo lockup ──────────────────────────────────────────────────────────── */
.rfc-logo {
display: inline-flex;
align-items: center;
justify-content: center;
border-radius: var(--radius);
background: var(--foreground);
color: var(--background);
flex: none;
}
.rfc-lockup {
display: inline-flex;
align-items: center;
gap: 0.5rem;
font-weight: 700;
font-size: 1.125rem;
}
.rfc-lockup .rfc-logo {
transition: transform 0.2s ease;
}
.rfc-lockup:hover .rfc-logo {
transform: scale(1.1);
}
/* The short name swaps for the full name on hover — one cell, two layers. */
.rfc-swap {
display: grid;
overflow: hidden;
height: 1.5rem;
align-items: center;
}
.rfc-swap > * {
grid-area: 1 / 1;
white-space: nowrap;
transition: opacity 0.25s ease, transform 0.25s ease;
}
.rfc-swap > :last-child {
opacity: 0;
transform: translateY(100%);
}
.rfc-lockup:hover .rfc-swap > :first-child {
opacity: 0;
transform: translateY(-100%);
}
.rfc-lockup:hover .rfc-swap > :last-child {
opacity: 1;
transform: translateY(0);
}
/* ── Docs shell ───────────────────────────────────────────────────────────── */
.rfc-docs {
display: flex;
align-items: flex-start;
max-width: 87.5rem;
margin-inline: auto;
}
.rfc-sidebar {
position: sticky;
top: 0;
flex: none;
width: var(--sidebar-width);
height: 100svh;
overflow-y: auto;
overscroll-behavior: contain;
border-inline-end: 1px solid var(--border);
padding: 1rem;
display: flex;
flex-direction: column;
gap: 1rem;
}
@media (max-width: 63.99rem) {
.rfc-sidebar { display: none; }
}
.rfc-sidebar-group > summary {
display: flex;
align-items: center;
gap: 0.5rem;
padding: 0.375rem 0.5rem;
border-radius: var(--radius);
font-size: 0.8125rem;
font-weight: 600;
cursor: pointer;
list-style: none;
}
.rfc-sidebar-group > summary::-webkit-details-marker {
display: none;
}
.rfc-sidebar-group > summary::before {
content: '';
width: 0.35rem;
height: 0.35rem;
border-inline-end: 1.5px solid currentColor;
border-block-end: 1.5px solid currentColor;
transform: rotate(-45deg);
transition: transform 0.15s ease;
}
.rfc-sidebar-group[open] > summary::before {
transform: rotate(45deg);
}
.rfc-sidebar-group > summary:hover {
background: var(--muted);
}
.rfc-sidebar-link {
display: block;
padding: 0.3125rem 0.5rem;
border-radius: var(--radius);
font-size: 0.8125rem;
color: var(--muted-foreground);
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
transition: background-color 0.15s ease, color 0.15s ease;
}
.rfc-sidebar-link:hover {
background: var(--muted);
color: var(--foreground);
}
.rfc-sidebar-nest {
padding-inline-start: 0.75rem;
border-inline-start: 1px solid var(--border);
margin-inline-start: 0.5rem;
}
.rfc-content {
flex: 1;
min-width: 0;
padding: 2.5rem 1.5rem 4rem;
}
.rfc-article {
display: flex;
gap: 2rem;
align-items: flex-start;
}
.rfc-article > article {
flex: 1;
min-width: 0;
max-width: var(--prose-max);
}
.rfc-toc {
position: sticky;
top: 1.5rem;
flex: none;
width: var(--toc-width);
max-height: calc(100svh - 3rem);
overflow-y: auto;
border-inline-start: 1px solid var(--border);
padding-inline-start: 1.25rem;
font-size: 0.8125rem;
}
@media (max-width: 79.99rem) {
.rfc-toc { display: none; }
}
.rfc-toc a {
display: block;
padding: 0.25rem 0;
padding-inline-start: 0.75rem;
border-inline-start: 2px solid transparent;
color: var(--muted-foreground);
transition: color 0.15s ease, border-color 0.15s ease;
}
.rfc-toc a:hover,
.rfc-toc a[data-active] {
color: var(--foreground);
border-inline-start-color: var(--foreground);
}
/* ── Prose (rendered markdown) ────────────────────────────────────────────── */
.rfc-prose {
line-height: 1.75;
}
.rfc-prose > :first-child {
margin-top: 0;
}
.rfc-prose h1 {
font-size: 2.25rem;
font-weight: 700;
letter-spacing: -0.03em;
line-height: 1.15;
margin: 0 0 1.25rem;
}
.rfc-prose h2 {
font-size: 1.625rem;
font-weight: 600;
letter-spacing: -0.025em;
line-height: 1.25;
margin: 3rem 0 1rem;
padding-bottom: 0.75rem;
border-bottom: 1px solid var(--border);
}
.rfc-prose h3 {
font-size: 1.25rem;
font-weight: 600;
letter-spacing: -0.02em;
margin: 2.25rem 0 0.75rem;
}
.rfc-prose h4 {
font-size: 1.0625rem;
font-weight: 600;
margin: 1.75rem 0 0.5rem;
}
.rfc-prose p {
margin: 0 0 1.5rem;
}
.rfc-prose ul,
.rfc-prose ol {
margin: 0 0 1.5rem;
padding-inline-start: 1.75rem;
}
.rfc-prose li {
margin-bottom: 0.5rem;
}
.rfc-prose li > ul,
.rfc-prose li > ol {
margin-block: 0.5rem;
}
.rfc-prose a {
color: var(--primary);
text-decoration: underline;
text-underline-offset: 3px;
}
.rfc-prose a:hover {
opacity: 0.85;
}
.rfc-prose blockquote {
margin: 1.75rem 0;
padding: 0.75rem 1.5rem;
border-inline-start: 3px solid color-mix(in oklch, var(--primary) 30%, transparent);
border-radius: 0 var(--radius) var(--radius) 0;
background: color-mix(in oklch, var(--muted) 40%, transparent);
color: var(--muted-foreground);
}
.rfc-prose blockquote p:last-child {
margin-bottom: 0;
}
.rfc-prose table {
width: 100%;
margin: 2rem 0;
border-collapse: collapse;
font-size: 0.9rem;
}
.rfc-prose th,
.rfc-prose td {
padding: 0.875rem 1.125rem;
border: 1px solid var(--border);
text-align: start;
}
.rfc-prose th {
background: color-mix(in oklch, var(--muted) 50%, transparent);
font-weight: 600;
}
.rfc-prose img {
max-width: 100%;
height: auto;
}
.rfc-prose :not(pre) > code {
padding: 0.2em 0.45em;
border-radius: 0.375rem;
background: var(--muted);
font-size: 0.875em;
font-weight: 500;
}
/*
* Code blocks carry ASCII diagrams in a lot of proposals: line-height must be
* exactly 1 and ligatures off, or the box-drawing characters stop connecting.
*/
.rfc-prose pre {
margin: 2rem 0;
padding: 1.5rem 1.75rem;
border: 1px solid var(--border);
border-radius: calc(var(--radius) * 1.25);
background: var(--code-bg);
color: var(--code-fg);
font-size: 0.875rem;
line-height: 1;
overflow-x: auto;
white-space: pre;
tab-size: 4;
font-variant-ligatures: none;
font-feature-settings: 'liga' 0, 'calt' 0;
letter-spacing: 0;
}
.rfc-prose pre code {
display: block;
padding: 0;
background: none;
font: inherit;
color: inherit;
}
/* ── Search ───────────────────────────────────────────────────────────────── */
.rfc-search-trigger {
display: flex;
align-items: center;
gap: 0.5rem;
width: 100%;
padding: 0.5rem 0.75rem;
border: 1px solid var(--border);
border-radius: var(--radius);
background: color-mix(in oklch, var(--muted) 50%, transparent);
color: var(--muted-foreground);
font-size: 0.875rem;
text-align: start;
transition: background-color 0.15s ease, color 0.15s ease;
}
.rfc-search-trigger:hover {
background: var(--muted);
color: var(--foreground);
}
/* No dialog, palette rows, palette footer or keyframes here. Search IS
`Command` from @hanzo/ui — modal, cursor, arrow keys, empty state, one
implementation shared with every other Hanzo surface. */