一、④段整套同步(用户选候选 A)
- 新增 `references/stage-proto-doc/assets/产品文档模板.html`(16 KB/247 行,从备份拷、转 LF)。
- ④段 SKILL.md 换成备份 15:28 那版,并按模板口径改齐:
· 「产品文档框架」从「四块+一附录」改成**六节** —— 页面结构/功能清单/使用场景/操作流程/
跨页与界面状态/待确认与偏离;与模板同构,⛔ 不从空白页重写结构。
· 编号从 R/S/F 改成 **P 页面/S 场景/F 功能/J 二级功能**,各自唯一、按展示顺序通排。
· 保留旧版有价值的要求:每项功能补齐 做什么/入口在哪/输入边界/异常与恢复;重点功能三处标红;
横向流程图每步写清页面/功能/操作/完成判据。
· 完成标准「七节」→「六节」,自查清单同步换掉「需求」那批条目,补模板与配图两条。
· 路径 `designs/<项目>/` → `docs/pm/<项目>/ui/`(2 处)。
· 补回本机那条「每份产出文档开头都要有一张图」的引用(指向主 skill,段内不复述)。
- 主 skill 同步:四段结构表④行、④段沿革、画图小节(④段画页面结构图 + 用户路径)。
二、open-design 移到技能根(用户选候选 A)
- `git mv product-planning/references/stage-delivery/assets/open-design → open-design/`(4178 文件)。
- `.gitignore` 白名单加 `!/open-design/` —— 否则移出去就不再纳入版本控制。
- 引用改 11 处:路径形态 `assets/open-design/...` → `<技能根>/open-design/...`;
「随段携带的自带件」改称「同根技能」;「路径怎么找」那条改成自带件(段内相对路径)与
同根技能(`<技能根>/<技能名>/`)两类分开写。
- open-design 自己的 ATTRIBUTION.md 两处同步(它现在与 oil-ui-pro 同层)。
- 副作用(有益):命名闸门读数由 2063 降到 225 —— 此前它把 open-design 里 919 个第三方 md
当成规则一起扫了;现在只扫本包 23 个 md。已确认④段的 H1 与 4a/4b/4c 子步仍在检查范围内。
三、验收
- check_naming.py --ws E:/ProgramData/AIProject/contentm_agent = 通过 225 / 失败 0 / 提示 27。
- 活文件里 `assets/open-design` 残留 0;工作区 CRLF 文件 0。
840 lines
33 KiB
HTML
840 lines
33 KiB
HTML
<!doctype html>
|
||
<html lang="en">
|
||
<head>
|
||
<meta charset="utf-8" />
|
||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||
<title>Resend — reference components</title>
|
||
<meta
|
||
name="description"
|
||
content="Reference fixture for design-systems/resend. Every visible
|
||
value comes from tokens.css; the page itself follows Resend's
|
||
rules — void-black canvas, near-white text, frost-blue borders
|
||
instead of gray, one accent at a time (Resend Orange), ABC
|
||
Favorit with -0.05em display tracking, Inter for body, Commit
|
||
Mono for code."
|
||
/>
|
||
|
||
<style>
|
||
/* :root paste — sourced verbatim from design-systems/resend/tokens.css. */
|
||
:root {
|
||
--bg: #000000;
|
||
--surface: #000000;
|
||
--surface-warm: var(--surface);
|
||
|
||
--fg: #f0f0f0;
|
||
--fg-2: #a1a4a5;
|
||
--muted: #5c5c5c;
|
||
--meta: #464a4d;
|
||
|
||
--border: rgba(214, 235, 253, 0.19);
|
||
--border-soft: rgba(217, 237, 254, 0.145);
|
||
|
||
--accent: #ff801f;
|
||
--accent-on: #000000;
|
||
--accent-hover: color-mix(in oklab, var(--accent), white 10%);
|
||
--accent-active: color-mix(in oklab, var(--accent), black 12%);
|
||
|
||
--success: #11ff99;
|
||
--warn: #ffc53d;
|
||
--danger: #ff2047;
|
||
|
||
--font-display: "ABC Favorit", "Inter", -apple-system, system-ui, "Segoe UI", "Helvetica Neue", Arial, sans-serif;
|
||
--font-body: "Inter", -apple-system, system-ui, "Segoe UI", "Helvetica Neue", Arial, sans-serif;
|
||
--font-mono: "Commit Mono", "JetBrains Mono", ui-monospace, "SF Mono", Menlo, Monaco, Consolas, monospace;
|
||
|
||
--text-xs: 12px;
|
||
--text-sm: 14px;
|
||
--text-base: 16px;
|
||
--text-lg: 20px;
|
||
--text-xl: 24px;
|
||
--text-2xl: 36px;
|
||
--text-3xl: 56px;
|
||
--text-4xl: 96px;
|
||
|
||
--leading-body: 1.5;
|
||
--leading-tight: 1.0;
|
||
--tracking-display: -0.05em;
|
||
|
||
--space-1: 4px;
|
||
--space-2: 8px;
|
||
--space-3: 12px;
|
||
--space-4: 16px;
|
||
--space-5: 20px;
|
||
--space-6: 24px;
|
||
--space-8: 32px;
|
||
--space-12: 48px;
|
||
|
||
--section-y-desktop: 120px;
|
||
--section-y-tablet: 80px;
|
||
--section-y-phone: 48px;
|
||
|
||
--radius-sm: 4px;
|
||
--radius-md: 8px;
|
||
--radius-lg: 16px;
|
||
--radius-pill: 9999px;
|
||
|
||
--elev-flat: none;
|
||
--elev-ring: 0 0 0 1px var(--border);
|
||
--elev-raised:
|
||
0 0 0 1px rgba(176, 199, 217, 0.145),
|
||
0 1px 3px rgba(0, 0, 0, 0.4),
|
||
0 1px 2px -1px rgba(0, 0, 0, 0.4);
|
||
|
||
--focus-ring: 0 0 0 2px var(--accent);
|
||
|
||
--motion-fast: 150ms;
|
||
--motion-base: 200ms;
|
||
--ease-standard: cubic-bezier(0.2, 0, 0, 1);
|
||
|
||
--container-max: 1200px;
|
||
--container-gutter-desktop: 32px;
|
||
--container-gutter-tablet: 24px;
|
||
--container-gutter-phone: 16px;
|
||
}
|
||
|
||
/* ─── Reset (minimal) ─────────────────────────────────────── */
|
||
*, *::before, *::after { box-sizing: border-box; }
|
||
html, body { margin: 0; padding: 0; }
|
||
body {
|
||
background: var(--bg);
|
||
color: var(--fg);
|
||
font-family: var(--font-body);
|
||
font-size: var(--text-base);
|
||
line-height: var(--leading-body);
|
||
font-weight: 400;
|
||
/* OpenType ligatures + ABC Favorit / Domaine stylistic sets per
|
||
DESIGN.md §3: ss01 / ss03 / ss04 / ss11 are part of the
|
||
typographic identity. Browsers without those faces simply
|
||
ignore the directives — no fallback ugliness. */
|
||
font-feature-settings: "liga" 1, "ss01" 1, "ss04" 1, "ss11" 1;
|
||
-webkit-font-smoothing: antialiased;
|
||
text-rendering: optimizeLegibility;
|
||
}
|
||
|
||
/* ─── Layout primitives ─────────────────────────────────── */
|
||
.container {
|
||
max-width: var(--container-max);
|
||
margin-inline: auto;
|
||
padding-inline: var(--container-gutter-desktop);
|
||
}
|
||
section {
|
||
padding-block: var(--section-y-desktop);
|
||
}
|
||
section + section {
|
||
/* Single frost hairline between major sections — DESIGN.md §4
|
||
"Sticky dark header with frost border bottom"; we extend
|
||
the same idea to inter-section dividers so the page reads
|
||
as a stack of gallery rooms rather than a continuous wash. */
|
||
border-top: 1px solid var(--border);
|
||
}
|
||
@media (max-width: 1023px) {
|
||
.container { padding-inline: var(--container-gutter-tablet); }
|
||
section { padding-block: var(--section-y-tablet); }
|
||
}
|
||
@media (max-width: 639px) {
|
||
.container { padding-inline: var(--container-gutter-phone); }
|
||
section { padding-block: var(--section-y-phone); }
|
||
}
|
||
|
||
/* ─── Typography ────────────────────────────────────────────
|
||
* Three-font hierarchy: display uses ABC Favorit via the display
|
||
* font token with aggressive negative tracking; body uses Inter
|
||
* via the body font token; code uses Commit Mono via the mono
|
||
* font token. Hierarchy comes from size + tracking, not weight —
|
||
* DESIGN.md §3 keeps weight at 400 / 500 / 600 only. */
|
||
h1, h2, h3, h4 {
|
||
font-family: var(--font-display);
|
||
line-height: var(--leading-tight);
|
||
margin: 0;
|
||
color: var(--fg);
|
||
}
|
||
h1 {
|
||
font-size: var(--text-4xl);
|
||
font-weight: 400;
|
||
letter-spacing: var(--tracking-display);
|
||
}
|
||
h2 {
|
||
font-size: var(--text-3xl);
|
||
font-weight: 400;
|
||
/* DESIGN.md §3 Section Heading line-height 1.20 — overrides
|
||
the shared --leading-tight (1.0) used by the 96px hero. */
|
||
line-height: 1.20;
|
||
letter-spacing: var(--tracking-display);
|
||
}
|
||
h3 {
|
||
font-size: var(--text-xl);
|
||
font-weight: 500;
|
||
/* DESIGN.md §3 Feature Title (24px Inter weight 500, line-
|
||
height 1.50). Feature titles use Inter, not the display
|
||
face — opt out of var(--font-display) inline. */
|
||
font-family: var(--font-body);
|
||
line-height: 1.5;
|
||
letter-spacing: normal;
|
||
}
|
||
h4 {
|
||
font-size: var(--text-lg);
|
||
font-weight: 400;
|
||
line-height: 1.3;
|
||
}
|
||
p { margin: 0; }
|
||
|
||
.lede {
|
||
font-family: var(--font-display);
|
||
font-size: var(--text-lg);
|
||
line-height: 1.3;
|
||
color: var(--fg-2);
|
||
letter-spacing: normal;
|
||
}
|
||
.body-muted { color: var(--fg-2); }
|
||
.body-meta { color: var(--muted); font-size: var(--text-sm); }
|
||
.body-sm { font-size: var(--text-sm); }
|
||
|
||
/* Eyebrow uses Commit Mono uppercase with positive tracking —
|
||
the documented nav-link pattern from DESIGN.md §3:
|
||
"ABC Favorit nav links use +0.35px letter-spacing — the only
|
||
positive tracking in the system." We extend the same airy
|
||
tracking to mono eyebrows so they read as a technical label
|
||
rather than a heading. */
|
||
.eyebrow {
|
||
font-family: var(--font-mono);
|
||
font-size: var(--text-xs);
|
||
font-weight: 500;
|
||
line-height: 1;
|
||
color: var(--muted);
|
||
text-transform: uppercase;
|
||
letter-spacing: 0.08em;
|
||
}
|
||
|
||
.stack-3 > * + * { margin-block-start: var(--space-3); }
|
||
.stack-4 > * + * { margin-block-start: var(--space-4); }
|
||
.stack-6 > * + * { margin-block-start: var(--space-6); }
|
||
|
||
/* ─── Buttons ───────────────────────────────────────────────
|
||
* DESIGN.md §4 documents three primary patterns:
|
||
* .btn-pill transparent fill + frost border + pill radius
|
||
* .btn-pill-white white solid fill + black label + pill radius
|
||
* .btn-ghost transparent, no border, sharp 4px radius
|
||
* The hero CTA pair below pairs a white-pill (max contrast)
|
||
* with a frost-pill (subtle) — Resend's signature CTA shape. */
|
||
.btn {
|
||
display: inline-flex;
|
||
align-items: center;
|
||
gap: var(--space-2);
|
||
padding: 8px 18px;
|
||
border: none;
|
||
border-radius: var(--radius-sm);
|
||
font-family: var(--font-body);
|
||
font-size: var(--text-sm);
|
||
font-weight: 500;
|
||
line-height: 1.43;
|
||
cursor: pointer;
|
||
text-decoration: none;
|
||
background: transparent;
|
||
color: inherit;
|
||
transition:
|
||
background-color var(--motion-fast) var(--ease-standard),
|
||
color var(--motion-fast) var(--ease-standard),
|
||
box-shadow var(--motion-fast) var(--ease-standard);
|
||
}
|
||
.btn:focus-visible {
|
||
outline: none;
|
||
box-shadow: var(--focus-ring);
|
||
}
|
||
.btn-pill {
|
||
border-radius: var(--radius-pill);
|
||
padding: 8px 18px;
|
||
background: transparent;
|
||
color: var(--fg);
|
||
box-shadow: 0 0 0 1px var(--border);
|
||
}
|
||
.btn-pill:hover {
|
||
/* White-glass hover from DESIGN.md §4: rgba(255,255,255,0.28).
|
||
Expressed via color-mix so it stays token-clean. */
|
||
background: color-mix(in oklab, var(--fg), transparent 72%);
|
||
box-shadow: 0 0 0 1px color-mix(in oklab, var(--fg), transparent 60%);
|
||
}
|
||
.btn-pill-white {
|
||
border-radius: var(--radius-pill);
|
||
padding: 8px 18px;
|
||
background: #ffffff;
|
||
color: #000000;
|
||
}
|
||
.btn-pill-white:hover {
|
||
background: color-mix(in oklab, #ffffff, var(--accent) 6%);
|
||
}
|
||
.btn-ghost {
|
||
background: transparent;
|
||
color: var(--fg-2);
|
||
padding-inline: var(--space-3);
|
||
}
|
||
.btn-ghost:hover {
|
||
color: var(--fg);
|
||
background: color-mix(in oklab, var(--fg), transparent 92%);
|
||
}
|
||
|
||
/* ─── Inputs ────────────────────────────────────────────────
|
||
* DESIGN.md §4: "Radius: 4px. Focus: shadow-based ring."
|
||
* Inputs use the frost-border via box-shadow so the focus
|
||
* state can swap the shadow to the accent ring without a
|
||
* layout shift. */
|
||
.field {
|
||
display: flex;
|
||
flex-direction: column;
|
||
gap: var(--space-2);
|
||
}
|
||
.field label {
|
||
font-size: var(--text-sm);
|
||
font-weight: 500;
|
||
color: var(--fg);
|
||
font-family: var(--font-body);
|
||
}
|
||
.field input {
|
||
padding: 10px 14px;
|
||
border: none;
|
||
border-radius: var(--radius-sm);
|
||
background: var(--surface);
|
||
color: var(--fg);
|
||
font-family: inherit;
|
||
font-size: var(--text-sm);
|
||
line-height: 1.43;
|
||
outline: none;
|
||
box-shadow: 0 0 0 1px var(--border);
|
||
transition: box-shadow var(--motion-fast) var(--ease-standard);
|
||
}
|
||
.field input::placeholder { color: var(--muted); }
|
||
.field input:hover {
|
||
box-shadow: 0 0 0 1px color-mix(in oklab, var(--border), white 30%);
|
||
}
|
||
.field input:focus-visible {
|
||
box-shadow: var(--focus-ring);
|
||
}
|
||
.field-help {
|
||
font-size: var(--text-xs);
|
||
color: var(--muted);
|
||
}
|
||
|
||
/* ─── Cards ─────────────────────────────────────────────────
|
||
* DESIGN.md §4: "Background: transparent or very subtle dark
|
||
* tint. Border: 1px solid rgba(214, 235, 253, 0.19)." Radius
|
||
* 16px (--radius-lg) for feature cards. Depth comes from the
|
||
* frost border alone — no opaque blur shadow, which would
|
||
* vanish into the void. */
|
||
.card {
|
||
background: var(--surface);
|
||
border: 1px solid var(--border);
|
||
border-radius: var(--radius-lg);
|
||
padding: var(--space-6);
|
||
display: flex;
|
||
flex-direction: column;
|
||
gap: var(--space-3);
|
||
transition:
|
||
border-color var(--motion-base) var(--ease-standard),
|
||
background-color var(--motion-base) var(--ease-standard);
|
||
}
|
||
.card:hover {
|
||
/* Intensify the frost edge on hover — luminance step, not
|
||
a shadow drop. Faintly tint the background with the same
|
||
cool blue at near-zero opacity so the card warms up. */
|
||
border-color: color-mix(in oklab, var(--border), white 30%);
|
||
background: color-mix(in oklab, var(--bg), white 2%);
|
||
}
|
||
|
||
/* ─── Badges ────────────────────────────────────────────────
|
||
* DESIGN.md §4 "Multi-color Accent Badges": background at
|
||
* 12–42% opacity of the accent, text at full opacity.
|
||
* `.badge-accent` uses the orange accent; `.badge-success` /
|
||
* `.badge-danger` reach the semantic tokens. Pill radius
|
||
* (9999px) is the brand-default badge shape. */
|
||
.badge {
|
||
display: inline-flex;
|
||
align-items: center;
|
||
gap: var(--space-1);
|
||
padding: 4px 12px;
|
||
border-radius: var(--radius-pill);
|
||
font-size: var(--text-xs);
|
||
font-weight: 500;
|
||
line-height: 1.5;
|
||
font-family: var(--font-body);
|
||
}
|
||
.badge-accent {
|
||
color: var(--accent);
|
||
background: color-mix(in oklab, var(--accent), transparent 80%);
|
||
}
|
||
.badge-muted {
|
||
color: var(--fg-2);
|
||
background: transparent;
|
||
box-shadow: 0 0 0 1px var(--border);
|
||
}
|
||
.badge-success {
|
||
color: var(--success);
|
||
background: color-mix(in oklab, var(--success), transparent 85%);
|
||
}
|
||
.badge-dot {
|
||
width: 6px;
|
||
height: 6px;
|
||
border-radius: 50%;
|
||
background: currentColor;
|
||
}
|
||
|
||
/* ─── Links ─────────────────────────────────────────────────
|
||
* Resend's link voice from DESIGN.md §2: link highlights are
|
||
* the pure-white moment. We pair an underline that thickens
|
||
* on hover with `--fg` (near-white) for body links — leaving
|
||
* the orange accent for explicit CTA badges only, so the ≤2
|
||
* accent uses per screen rule holds even in copy-dense
|
||
* sections. */
|
||
a {
|
||
color: var(--fg);
|
||
text-decoration: underline;
|
||
text-decoration-color: var(--border);
|
||
text-underline-offset: 3px;
|
||
text-decoration-thickness: 1px;
|
||
transition: text-decoration-color var(--motion-fast) var(--ease-standard);
|
||
}
|
||
a:hover {
|
||
text-decoration-color: var(--fg);
|
||
}
|
||
a.link-accent {
|
||
color: var(--accent);
|
||
text-decoration-color: color-mix(in oklab, var(--accent), transparent 50%);
|
||
}
|
||
a.link-accent:hover { text-decoration-color: var(--accent); }
|
||
a:focus-visible {
|
||
outline: none;
|
||
border-radius: 2px;
|
||
box-shadow: var(--focus-ring);
|
||
}
|
||
|
||
/* ─── Kbd ───────────────────────────────────────────────────
|
||
* Commit Mono, frost shadow-border edge. The mono face is
|
||
* the "developer console voice" connecting marketing copy
|
||
* to the product surface. */
|
||
kbd {
|
||
font-family: var(--font-mono);
|
||
font-size: var(--text-xs);
|
||
padding: 2px 8px;
|
||
border-radius: var(--radius-sm);
|
||
background: var(--surface);
|
||
color: var(--fg-2);
|
||
box-shadow: 0 0 0 1px var(--border);
|
||
}
|
||
|
||
/* ─── Distinctive: Code preview panel ───────────────────────
|
||
* DESIGN.md §4 "Code Preview Panels": dark code blocks using
|
||
* Commit Mono, frost borders, syntax-highlighted with multi-
|
||
* color accent tokens. The 24px radius is the brand "Section"
|
||
* radius (panel tier); reached inline because the schema's
|
||
* --radius-lg caps at 16px and adding a fifth radius slot
|
||
* would require a C-extension. */
|
||
.code-panel {
|
||
border: 1px solid var(--border);
|
||
border-radius: 24px;
|
||
background: var(--surface);
|
||
overflow: hidden;
|
||
box-shadow: var(--elev-raised);
|
||
}
|
||
.code-panel-head {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: var(--space-2);
|
||
padding: var(--space-3) var(--space-4);
|
||
border-bottom: 1px solid var(--border-soft);
|
||
font-family: var(--font-mono);
|
||
font-size: var(--text-xs);
|
||
color: var(--muted);
|
||
}
|
||
.code-panel-dot {
|
||
width: 8px;
|
||
height: 8px;
|
||
border-radius: 50%;
|
||
background: color-mix(in oklab, var(--fg), transparent 80%);
|
||
}
|
||
.code-panel-title { margin-inline-start: auto; }
|
||
.code-panel pre {
|
||
margin: 0;
|
||
padding: var(--space-5) var(--space-6);
|
||
font-family: var(--font-mono);
|
||
font-size: var(--text-sm);
|
||
line-height: 1.6;
|
||
color: var(--fg);
|
||
overflow-x: auto;
|
||
}
|
||
.code-panel .tok-key { color: var(--accent); }
|
||
.code-panel .tok-str { color: var(--success); }
|
||
.code-panel .tok-fn { color: var(--warn); }
|
||
.code-panel .tok-com { color: var(--meta); font-style: italic; }
|
||
|
||
/* ─── Section-specific layout ─────────────────────────────── */
|
||
.hero {
|
||
text-align: left;
|
||
position: relative;
|
||
overflow: hidden;
|
||
}
|
||
/* Atmospheric warm gradient glow behind the hero — DESIGN.md
|
||
§6 "Decorative Depth: subtle warm gradient glows behind hero
|
||
content (orange/amber tints)". A radial wash of the accent
|
||
at very low opacity, blurred heavily — token-clean because
|
||
it mixes var(--accent) over var(--bg) rather than
|
||
introducing a raw hex. */
|
||
.hero::before {
|
||
content: "";
|
||
position: absolute;
|
||
inset: -20% -10% auto -10%;
|
||
height: 80%;
|
||
background: radial-gradient(
|
||
ellipse at 20% 30%,
|
||
color-mix(in oklab, var(--accent), var(--bg) 70%) 0%,
|
||
color-mix(in oklab, var(--accent), var(--bg) 90%) 35%,
|
||
var(--bg) 70%
|
||
);
|
||
filter: blur(80px);
|
||
opacity: 0.5;
|
||
z-index: 0;
|
||
pointer-events: none;
|
||
}
|
||
.hero > * { position: relative; z-index: 1; }
|
||
.hero .eyebrow { margin-block-end: var(--space-6); }
|
||
.hero h1 { max-width: 16ch; }
|
||
.hero .lede {
|
||
max-width: 52ch;
|
||
margin-block-start: var(--space-6);
|
||
}
|
||
.hero-actions {
|
||
display: flex;
|
||
gap: var(--space-3);
|
||
margin-block-start: var(--space-8);
|
||
align-items: center;
|
||
flex-wrap: wrap;
|
||
}
|
||
.hero-meta {
|
||
display: inline-flex;
|
||
align-items: center;
|
||
gap: var(--space-3);
|
||
margin-block-start: var(--space-6);
|
||
color: var(--muted);
|
||
font-size: var(--text-sm);
|
||
flex-wrap: wrap;
|
||
}
|
||
|
||
.features-grid {
|
||
display: grid;
|
||
grid-template-columns: repeat(3, 1fr);
|
||
gap: var(--space-5);
|
||
margin-block-start: var(--space-12);
|
||
}
|
||
@media (max-width: 1023px) {
|
||
.features-grid { grid-template-columns: 1fr 1fr; }
|
||
}
|
||
@media (max-width: 639px) {
|
||
.features-grid { grid-template-columns: 1fr; }
|
||
}
|
||
.feature-card .feature-icon {
|
||
width: 32px;
|
||
height: 32px;
|
||
border-radius: var(--radius-md);
|
||
background: color-mix(in oklab, var(--accent), transparent 85%);
|
||
color: var(--accent);
|
||
display: inline-flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
}
|
||
|
||
.form-row {
|
||
display: grid;
|
||
grid-template-columns: 1.1fr 1fr;
|
||
gap: var(--space-12);
|
||
align-items: start;
|
||
margin-block-start: var(--space-8);
|
||
}
|
||
@media (max-width: 1023px) {
|
||
.form-row { grid-template-columns: 1fr; gap: var(--space-8); }
|
||
}
|
||
.form {
|
||
display: flex;
|
||
flex-direction: column;
|
||
gap: var(--space-4);
|
||
max-width: 460px;
|
||
padding: var(--space-6);
|
||
background: var(--surface);
|
||
border: 1px solid var(--border);
|
||
border-radius: var(--radius-lg);
|
||
}
|
||
.form-actions {
|
||
display: flex;
|
||
gap: var(--space-3);
|
||
margin-block-start: var(--space-2);
|
||
align-items: center;
|
||
}
|
||
|
||
.row-between {
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: space-between;
|
||
gap: var(--space-3);
|
||
}
|
||
.icon { width: 16px; height: 16px; flex-shrink: 0; }
|
||
</style>
|
||
</head>
|
||
<body>
|
||
<main class="container">
|
||
<!-- ════════════════════════════════════════════════════════════
|
||
HERO — exercises: atmospheric warm gradient (DESIGN.md §6
|
||
"subtle warm gradient glows behind hero content"), h1 at
|
||
96px ABC Favorit with -0.05em tracking, .lede in --fg-2,
|
||
white-pill CTA (max contrast), frost-pill CTA (subtle),
|
||
kbd shortcut, muted-pill status badge. Single-column
|
||
layout — Resend heroes float a tight content island in
|
||
vast dark space.
|
||
═══════════════════════════════════════════════════════════════ -->
|
||
<section class="hero" data-od-id="hero">
|
||
<p class="eyebrow">Reference fixture · Resend</p>
|
||
<h1>Email for developers, not marketing teams.</h1>
|
||
<p class="lede">
|
||
A token block distilled from Resend's published design
|
||
system — ABC Favorit with -0.05em display tracking, frost
|
||
borders instead of gray hairlines, one accent at a time.
|
||
The fixture you are reading paints from the same
|
||
<code style="font-family: var(--font-mono); font-size: 0.95em">:root</code>
|
||
block agents inline into every Resend artifact.
|
||
</p>
|
||
<div class="hero-actions">
|
||
<a href="./tokens.css" class="btn btn-pill-white">
|
||
Send your first email
|
||
<svg
|
||
class="icon"
|
||
viewBox="0 0 24 24"
|
||
fill="none"
|
||
stroke="currentColor"
|
||
stroke-width="1.75"
|
||
stroke-linecap="round"
|
||
stroke-linejoin="round"
|
||
aria-hidden="true"
|
||
>
|
||
<path d="M5 12h14M13 6l6 6-6 6" />
|
||
</svg>
|
||
</a>
|
||
<a href="./DESIGN.md" class="btn btn-pill">Read the spec</a>
|
||
<a href="#code" class="btn btn-ghost">See the SDK</a>
|
||
</div>
|
||
<p class="hero-meta">
|
||
<span class="badge badge-success">
|
||
<span class="badge-dot" aria-hidden="true"></span>
|
||
v0.1 · stable
|
||
</span>
|
||
<span>Press <kbd>⌘</kbd> <kbd>K</kbd> to search the docs.</span>
|
||
</p>
|
||
</section>
|
||
|
||
<!-- ════════════════════════════════════════════════════════════
|
||
FEATURES — exercises: .card with frost border (no opaque
|
||
shadow on void), h3 at 24px Inter weight 500, .body-muted,
|
||
.badge-accent at 20% accent tint, .feature-icon glyph
|
||
tile, .features-grid three-up collapsing to one. Three
|
||
cards demonstrate the three product surfaces: SDK / API
|
||
/ Domain — each gets exactly one accent tint per card so
|
||
the ≤2 accent uses per screen rule still reads at scale.
|
||
═══════════════════════════════════════════════════════════════ -->
|
||
<section data-od-id="features">
|
||
<div class="stack-3">
|
||
<p class="eyebrow">What this fixture exercises</p>
|
||
<h2 style="max-width: 18ch">
|
||
Built for the way you actually ship.
|
||
</h2>
|
||
<p class="body-muted" style="margin-block-start: var(--space-4); max-width: 56ch">
|
||
Every component below pulls from
|
||
<code style="font-family: var(--font-mono); font-size: 0.95em">var(--*)</code>
|
||
— no raw hex outside the documented brand palette, no
|
||
off-token type. Frost borders carry every container edge;
|
||
the orange accent appears at most twice per viewport.
|
||
</p>
|
||
</div>
|
||
|
||
<div class="features-grid">
|
||
<article class="card feature-card">
|
||
<span class="feature-icon" aria-hidden="true">
|
||
<svg
|
||
class="icon"
|
||
viewBox="0 0 24 24"
|
||
fill="none"
|
||
stroke="currentColor"
|
||
stroke-width="1.75"
|
||
stroke-linecap="round"
|
||
stroke-linejoin="round"
|
||
>
|
||
<path d="M4 6h16v12H4z" />
|
||
<path d="M4 6l8 7 8-7" />
|
||
</svg>
|
||
</span>
|
||
<h3>One SDK, every runtime.</h3>
|
||
<p class="body-muted body-sm">
|
||
Node, Python, Ruby, Go, PHP, Rust, Java — same surface,
|
||
same idempotent send. Drop the SDK into an edge worker
|
||
and the API contract doesn't shift.
|
||
</p>
|
||
<a href="./tokens.css" class="link-accent body-sm">Inspect tokens →</a>
|
||
</article>
|
||
|
||
<article class="card feature-card">
|
||
<span class="feature-icon" aria-hidden="true">
|
||
<svg
|
||
class="icon"
|
||
viewBox="0 0 24 24"
|
||
fill="none"
|
||
stroke="currentColor"
|
||
stroke-width="1.75"
|
||
stroke-linecap="round"
|
||
stroke-linejoin="round"
|
||
>
|
||
<path d="M3 12h4l3-7 4 14 3-7h4" />
|
||
</svg>
|
||
</span>
|
||
<h3>Frost borders, no shadows.</h3>
|
||
<p class="body-muted body-sm">
|
||
<code style="font-family: var(--font-mono); font-size: 0.95em">border: 1px solid rgba(214,235,253,.19)</code>
|
||
replaces every gray hairline. On pure black, blur
|
||
shadows vanish — the icy line catches what little
|
||
light there is and reads as a crystalline edge.
|
||
</p>
|
||
<a href="./DESIGN.md" class="link-accent body-sm">Read the rule →</a>
|
||
</article>
|
||
|
||
<article class="card feature-card">
|
||
<span class="feature-icon" aria-hidden="true">
|
||
<svg
|
||
class="icon"
|
||
viewBox="0 0 24 24"
|
||
fill="none"
|
||
stroke="currentColor"
|
||
stroke-width="1.75"
|
||
stroke-linecap="round"
|
||
stroke-linejoin="round"
|
||
>
|
||
<path d="M4 7h16M4 12h10M4 17h16" />
|
||
</svg>
|
||
</span>
|
||
<h3>Three fonts, three roles.</h3>
|
||
<p class="body-muted body-sm">
|
||
ABC Favorit announces, Inter reads, Commit Mono
|
||
instructs. Display tracking compresses to
|
||
<code style="font-family: var(--font-mono); font-size: 0.95em">-0.05em</code>
|
||
so headlines feel engineered, never decorative.
|
||
</p>
|
||
<a href="./tokens.css" class="link-accent body-sm">Inspect typography →</a>
|
||
</article>
|
||
</div>
|
||
</section>
|
||
|
||
<!-- ════════════════════════════════════════════════════════════
|
||
CODE PANEL — Resend's distinctive surface: a Commit Mono
|
||
code block inside a frost-bordered 24px-radius panel.
|
||
Syntax highlighting reaches the multi-color accent tokens
|
||
(orange for keys, green for strings, yellow for fn names,
|
||
dark gray for comments) — this is the ONE place per
|
||
viewport where multiple accent colors are sanctioned by
|
||
DESIGN.md §4 "Code Preview Panels".
|
||
═══════════════════════════════════════════════════════════════ -->
|
||
<section data-od-id="code" id="code">
|
||
<p class="eyebrow">The SDK in two lines</p>
|
||
<h2 style="margin-block-start: var(--space-3); max-width: 22ch">
|
||
<code style="font-family: var(--font-mono); font-size: 0.78em">resend.emails.send</code>, and you're done.
|
||
</h2>
|
||
<p class="body-muted" style="margin-block-start: var(--space-4); max-width: 56ch">
|
||
The code panel is the one surface where Resend's multi-
|
||
color accent scale is sanctioned: orange for keys, green
|
||
for strings, yellow for function names, dark gray for
|
||
comments. Everywhere else, the orange accent holds the
|
||
chromatic moment alone.
|
||
</p>
|
||
|
||
<div class="code-panel" style="margin-block-start: var(--space-8); max-width: 760px">
|
||
<div class="code-panel-head">
|
||
<span class="code-panel-dot" aria-hidden="true"></span>
|
||
<span class="code-panel-dot" aria-hidden="true"></span>
|
||
<span class="code-panel-dot" aria-hidden="true"></span>
|
||
<span class="code-panel-title">send.ts</span>
|
||
</div>
|
||
<pre><span class="tok-com">// send your first transactional email</span>
|
||
<span class="tok-key">import</span> { Resend } <span class="tok-key">from</span> <span class="tok-str">"resend"</span>;
|
||
|
||
<span class="tok-key">const</span> resend = <span class="tok-key">new</span> <span class="tok-fn">Resend</span>(<span class="tok-str">"re_xxxxx"</span>);
|
||
|
||
<span class="tok-key">await</span> resend.emails.<span class="tok-fn">send</span>({
|
||
from: <span class="tok-str">"[email protected]"</span>,
|
||
to: <span class="tok-str">"[email protected]"</span>,
|
||
subject: <span class="tok-str">"Hello from Resend"</span>,
|
||
html: <span class="tok-str">"<p>Shipped.</p>"</span>,
|
||
});</pre>
|
||
</div>
|
||
</section>
|
||
|
||
<!-- ════════════════════════════════════════════════════════════
|
||
FORM — exercises: .field with frost shadow-border inputs,
|
||
focus-visible swap to the 2px accent ring, .btn-pill-white
|
||
and .btn-pill reuse. Form sits inside its own frost-
|
||
bordered card so the input edges read as recessed within
|
||
the form surface.
|
||
═══════════════════════════════════════════════════════════════ -->
|
||
<section data-od-id="form">
|
||
<p class="eyebrow">Form components</p>
|
||
<h2 style="margin-block-start: var(--space-3); max-width: 28ch">
|
||
Inputs inherit the same tokens.
|
||
</h2>
|
||
|
||
<div class="form-row">
|
||
<div class="stack-4">
|
||
<p class="body-muted" style="max-width: 48ch">
|
||
Focus rings, edges, placeholder color — all derive from
|
||
<code style="font-family: var(--font-mono); font-size: 0.95em">--accent</code>
|
||
and <code style="font-family: var(--font-mono); font-size: 0.95em">--border</code>.
|
||
The submit button reuses
|
||
<code style="font-family: var(--font-mono); font-size: 0.95em">.btn-pill-white</code>
|
||
unchanged — white fill, black label, 9999px radius.
|
||
</p>
|
||
<p class="body-muted body-sm">
|
||
No new token is introduced for this section. The form
|
||
card uses the standard frost border + 16px radius;
|
||
input shadow-borders read as recessed beneath the
|
||
card's outer frost line.
|
||
</p>
|
||
<p class="body-meta">
|
||
Full reference at <a href="./tokens.css">tokens.css</a> ·
|
||
spec at <a href="./DESIGN.md">DESIGN.md</a>.
|
||
</p>
|
||
</div>
|
||
|
||
<form class="form" onsubmit="event.preventDefault();">
|
||
<div class="row-between">
|
||
<p class="eyebrow">Join the beta</p>
|
||
<span class="badge badge-muted">
|
||
<span class="badge-dot" aria-hidden="true" style="color: var(--success)"></span>
|
||
Open
|
||
</span>
|
||
</div>
|
||
<div class="field">
|
||
<label for="email">Work email</label>
|
||
<input
|
||
id="email"
|
||
type="email"
|
||
placeholder="[email protected]"
|
||
autocomplete="email"
|
||
required
|
||
/>
|
||
<p class="field-help">
|
||
We'll send the API key and nothing else.
|
||
</p>
|
||
</div>
|
||
<div class="form-actions">
|
||
<button type="submit" class="btn btn-pill-white">
|
||
Get the API key
|
||
</button>
|
||
<button type="button" class="btn btn-pill">
|
||
Read the docs
|
||
</button>
|
||
</div>
|
||
</form>
|
||
</div>
|
||
</section>
|
||
</main>
|
||
</body>
|
||
</html>
|