mirror of
https://github.com/hanzoai/rfc.git
synced 2026-10-30 18:23:14 +00:00
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.
867 lines
21 KiB
CSS
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. */
|