mesh-avatar-studio
Turn one illustration into an animated 2D mesh avatar with a coding agent and a local editor
翻译准备中
尚未检测到更新。GitHub 发布版本后会显示在这里。
个人 GitHub 账号下公开仓库的所有者可以登录并验证所有权,自行管理介绍,无需管理员批准。
登录并生成验证文件,在 30 分钟内将其提交到此仓库的默认分支。其他分支或分叉仓库中的文件无效。然后在下方检查文件,即可无需管理员批准直接管理项目。请保留文件以维持管理权限。
如需登录,将前往登录页面。登录后请回到此处,再次点击所选的验证按钮。
在项目文件夹中运行 /nomorevibe verify,即可验证所有权并自行管理介绍。
一分钟完成验证ASK 设计系列的参考实现 // 分层标记、自托管 OFL 字体、标准 logo-ASK 资产、预览卡片。
AI 翻译
Reference implementation of the ASK design family // tier-demarcated tokens, self-hosted OFL fonts, canonical logo-ASK assets, preview cards
取自仓库 README
正在加载完整 README。 以下为已保存的摘录。
Minimal design foundations for the ASK visual identity. Tokens remain irreducible; the repo may also carry artifact inheritance scaffolds and opt-in semantic primitives that show downstream surfaces how to consume them without redefining them.
order from chaos // beauty in systems
The line above is the ASK master tagline. It is canonically defined in brand-architecture.md (in ASK's context system, not this repo) — displayed here, not defined here. See the Voice section below for the protected-payload rule.查看完整 README ↗Minimal design foundations for the ASK visual identity. Tokens remain irreducible; the repo may also carry artifact inheritance scaffolds and opt-in semantic primitives that show downstream surfaces how to consume them without redefining them.
order from chaos // beauty in systems
The line above is the ASK master tagline. It is canonically defined in brand-architecture.md (in ASK's context system, not this repo) — displayed here, not defined here. See the Voice section below for the protected-payload rule.
This repo, design-system-ASK, is the reference implementation of the ASK design family.
This repo conforms to visual-identity-system.md in ASK's canonical context as the source of truth. The files here are a downstream implementation; when the two disagree, the canonical file wins.
A foundational design system for ASK — a meta-brand expressed through a single wordmark, two diagonal gradients, and a deliberately small set of colors and weights. The system is reductive on purpose. Interface and interaction state is expressed through weight, opacity, and motion — never by introducing a hue outside the named set. The foundation-level opt-in exceptions are the ASK semantic-color primitives for data and architecture visualizations — Spectral State (element state) and Three Functions (structural function), below — not general UI color, and neither expands the palette. A separate pattern-local participant-identity vocabulary exists only inside message-archive; it is not a foundation primitive and does not open the unrestricted general palette.
Scope is the meta-brand. Sub-brand theming (production, builder, artist) layers on top of these tokens elsewhere; it does not live here.
assets/logo-ASK.svg // primary vector wordmark, fill: currentColorassets/logo-ASK-white.png // raster wordmark, white on transparent (light-mode pairing)assets/logo-ASK-lavender-ASK.png // raster wordmark, lavender-ASK on transparent (dark-mode pairing)visual-identity-system.md (in ASK's canonical context, not in this repo)ASK 9 4.ai (Illustrator file, not in this repo by design — production assets only)This repo carries three kinds of material:
surface-shell and diagram-interactive-radial are the instances.The distinction in 2 versus 3 is the lifecycle, and it is load-bearing. An artifact scaffold produces something finished and frozen. A surface pattern produces something that keeps running. Do not apply sealing, freezing, or generation-time inheritance rules to a surface pattern.
The document register (surface-document.css) and the surface treatments (surface-treatments.css) serve both lifecycles: a live surface references or vendors them and re-syncs, and an artifact scaffold may inline them at generation time, after which the sealed copy does not re-sync. The surface treatments extend surface-panel.css, which authors the glass recipe they share, so a surface that uses them loads or inlines that file first.
These are consumption patterns, not components. They are not a generator, not a build pipeline, not an npm package, and not a component library. The catalog holds two artifact classes plus one separate surface-pattern group:
diagram-static-H (horizontal left→right top-aligned cascade), diagram-static-V (vertical top→down centered spine), diagram-static-SEQ (ordered top→down arrowed sequence — succession, not hierarchy), and diagram-static-FLOW (convergence flow — many sources converging into a resolved spec, realized, evaluated, governed, fed back) — structural; state-free. A page of any of the four may opt in to a shared responsive chrome that lays out its caption and legend together and, on a narrow or crowded canvas, closes them behind triggers in one control area with the HUD; an adopting consumer vendors diagrams-chrome.js with the bundle and surface-panel.css then surface-treatments.css for the triggers. diagram-static-peer arranges peers rather than a hierarchy: three or four equal nodes on a triangle or a square, joined by declared directed and neutral relations. It is structural and state-free too, with a relation grammar, engine and exporter of its own, and takes none of the four's shared carriers. Each pattern's README carries the contract.diagram-interactive-spine // a navigable, stateful IA state surface that consumes the Spectral State primitive for node color. The taxonomy encodes static-vs-interactive, not just orientation (the interactive spine is also vertical).Artifact scaffolds — Class A and Class B only — inherit at generation time and freeze for audit. A sealed interactive artifact may retain client-side navigation over embedded content; it introduces no live data dependency. Downstream projects supply their own Tier 3 identity, their own source-truth posture, and their own content and domain structure. Hosting a scaffold here does not make this repo the owner of downstream project content.
The repo may also carry specialized opt-in foundation primitives beyond the core tokens — small, identity-free systems a surface loads only when it needs them. These are the foundation-level bounded exceptions; a pattern-level bounded vocabulary also exists (see below). The first foundation primitive is ASK Spectral State (spectral-state.css), a semantic state-color system for surfaces that encode element state. It is not general UI color, and the static scaffolds above do not use it; the interactive diagram-interactive-spine, the diagram-interactive-radial surface pattern and documents that adopt the Review Semantics composition are the state-bearing members that do.
Bounded color exceptions sit on three distinct axes, and none of them opens the general palette: semantic state — Spectral State and its sanctioned profiles (e.g. Evidence State); structural function — Three Functions; and participant identity — the Class B message-archive participant ramp. The first two are opt-in foundation primitives; the third is pattern-local — it lives inside patterns/message-archive/, is not a foundation token, and authorizes no use outside that pattern. No other values are available as unrestricted general-purpose colors.
A primitive may carry sanctioned profiles for adjacent semantic domains. The first is ASK Evidence State (evidence-state.css), an epistemic evidence-state vocabulary built on Spectral State: it reuses three Spectral State values by reference and adds two evidence-specific roles (weakened, not-yet-testable), leaving Spectral State's own vocabulary unchanged. The second is ASK Review State, the decision facet of ASK Review Semantics (review-semantics.css): five review roles for documents that are reviewed, each reusing an existing value by reference (two Spectral State values, the foundation's emphasis magenta and emphasis cyan, and its --fg-3), with no value of its own. Its annotation composition shows review, evidence and state beside the content they concern.
A second opt-in primitive, ASK Three Functions (three-functions.css), sits alongside Spectral State on a different axis: where Spectral State encodes an element's state, Three Functions encodes its function — legislative / executive / judicial, the three separation-of-powers roles read as color. It is a sibling primitive, not a Spectral State profile, and it expands no palette: the three roles bind to existing ASK values (magenta, the neutral white / lavender-ASK, cyan).
The ASK design system expresses ASK's approved visual identity. Its default design language makes no general claim of accessibility conformance, WCAG conformance, or regulatory compliance. Consuming its tokens or patterns does not establish such conformance for an application.
Accessibility and compliance requirements are application-specific. A documented requirement, or an explicitly authorized claim for a particular pattern, profile, or application, governs that bounded use only. It does not impose a system-wide redesign requirement and does not change the default ASK aesthetic.
The approved palette, typography, materials, and interaction treatments are not provisional choices awaiting a compliance audit. --fg-1 is the default light foreground; --fg-high-contrast is a bounded opt-in for separately registered uses, never the default and never selected automatically by font size. Existing high-contrast registrations and other expressly approved bounded treatments remain valid within their stated scope.
Advisor, executor, and generator conduct is governed by AGENTS.md §Accessibility and compliance scope discipline.
| Path | What it is |
|---|---|
colors_and_type.css | CSS variables — colors, type, spacing, radii, motion |
spectral-state.css + spectral-state.md + spectral-state.html | ASK Spectral State — specialized opt-in state-color primitive (eight --state-* roles — seven neon signals plus neutral, which resolves to the theme foreground — on a 12-hue wheel), with a rendered visual key (spectral-state.html). For surfaces that encode element state; not general UI color. Layers on top of colors_and_type.css. |
evidence-state.css + evidence-state.md + evidence-state.html | ASK Evidence State — a sanctioned profile under Spectral State (epistemic evidence-state). supported / partially-supported / unresolved reuse Spectral State values by reference; weakened (muted 30° brown) and not-yet-testable (lavender-gray, dashed/hollow) are new roles. Rendered key in evidence-state.html. Layers on top of spectral-state.css; Spectral State's own vocabulary is unchanged. |
| + + |
The wordmark uses its own mode-specific brand pairing — it does not inherit the body text color — and it sits on the gradient, not on a fixed lavender-ASK block.
#FFFFFF wordmark on the light gradient (the wordmark's brand pairing — not the #6A637F light-mode text).#D4C6E1 (lavender-ASK) wordmark on the dark gradient (here it coincides with the #D4C6E1 dark-mode text).On a live UI surface, the mark goes on the gradient. The fixed #D4C6E1 lavender-ASK field belongs to standalone exported assets, including social-preview images, and to the browser-icon application below. It is baked into the asset, not used as a live UI background. Do not place the wordmark on a flat lavender-ASK UI block.
logo-ASK.svg is the primary reference: it paints with fill: currentColor, so one vector file can be used for both mode pairings when its container sets the correct wordmark color. The two PNGs are raster pairings/fallbacks.
For the sites and entry points named below, the social-preview image follows the identity ASK assigns to that context. brand-architecture.md, in ASK's canonical context, owns the rule that Tier 3 may differ by presentation context and records project-specific assignments. Where the assignment is the shared ASK card, the ASK site's og-image.png is the source asset, and each site serves a byte-identical copy from its own origin. Matching the visual treatment alone is not sufficient, and a site assigned the shared card adds no project label, recoloring or alternate composition. A project-specific card, including one that carries an ASK-derived mark, is used only where ASK assigns one. That assignment covers the social-preview context alone and does not carry into shell marks, browser icons or content artifacts. Assignments change only on explicit ASK instruction.
Titles, descriptions, site names and canonical URLs remain specific to each page. The shared ASK card is assigned to the ASK, method-ASK, control-surface, design-system-ASK and urban-observatory front doors, their document and diagram entry indexes where present, the design-system style-guide and pattern-gallery entrances, and ASK's practice gateways. The AP-ASK card is assigned to the asset-pipeline-ASK front doors and their entry indexes; asset-pipeline-ASK supplies that card and owns its composition. Neither assignment replaces content-specific images on child pages outside that scope, assigns a mark to another consumer, or follows from consuming Tier 1 + Tier 2.
The prohibition above is about UI surfaces. The browser icon is not one: like the standalone exported deliverable, it is a fixed asset, and it carries the wordmark on the flat #D4C6E1 field by design — fitted to a square. It is the compact square application of the exported-asset treatment, not a third wordmark treatment and not a new logo.
| File | Role |
|---|---|
favicon.svg | 512 × 512, white wordmark on the baked #D4C6E1 square — the primary |
favicon-32.png | 32 × 32 raster fallback |
favicon.ico | root-probe carrier; a container around favicon-32.png, byte-for-byte |
apple-touch-icon.png | 180 × 180, iOS home screen |
These are Tier-3 implementation assets. The visual decision stays with the identity canonical (visual-identity-system.md); this repo owns the reusable package, its verification, and the integration contract. The glyph geometry derives from assets/logo-ASK.svg without redraw — tools/browser-icons.mjs --check fails if any glyph path diverges from the wordmark, if the field or ink colour moves, if a fourth glyph or a wedge-only mark appears, or if the ICO stops matching the 32 px composition. Regenerate the ICO with node tools/browser-icons.mjs; it is byte-deterministic.
Two integration profiles, because ASK browser surfaces are not all origins.
A // deployed origin. The full four-file package at the origin root, root-absolute head paths:
<link rel="icon" type="image/svg+xml" href="/favicon.svg">
<link rel="icon" type="image/png" sizes="32x32" href="/favicon-32.png">
<link rel="apple-touch-icon" href="/apple-touch-icon.png">
/favicon.ico needs no declaration — it answers the browser's automatic root probe and covers pages that declare nothing.
B // package-local browser artifact. A mutable operator package a reader opens directly from its own directory rather than over an origin. Paths are relative to the artifact HTML at the package root, because a leading / there resolves to the filesystem or origin root, not to the package:
<!-- Package-local browser artifact — paths relative to this HTML file -->
<link rel="icon" type="image/svg+xml" href="./favicon.svg">
<link rel="icon" type="image/png" sizes="32x32" href="./favicon-32.png">
Two files only. No apple-touch icon — there is no home-screen role. No root-probe guarantee is claimed under file://, so a package-local .ico is not required unless a concrete local-browser need is demonstrated. The visual bytes are the same canonical owner bytes; only the carrier subset and the path form differ.
A surface uses this package only where it is assigned ASK's own Tier 3. A surface that resolves a different Tier 3 supplies its own browser icon; carrying ASK's icon does not make a project ASK-the-entity, and surface-shell remains Tier-3-neutral — it ships a mark slot and supplies no favicon value. Downstream consumers vendor these exact bytes rather than redrawing or re-extracting a mark.
A web app manifest, PWA 192/512 icons, and mask-icon are not part of the package: none of the consuming surfaces is an installable app, and nothing here needs one.
The README, card labels, and any docs in this repo speak in a calm, declarative, sentence-case voice. Quiet. Restrained. One idea per sentence. Plain present tense. Describe the system rather than narrating a maker.
| Trait | Treatment |
|---|---|
| Person | Impersonal / declarative. Do not invent a studio "we" — ASK is a personal meta-brand, not a collective. Describe the system as a thing that exists, not a thing "we made". |
| Casing | Sentence case in headings and body. UPPERCASE only for small labels (≤14px), tracked by role: Inter Caption at 0.14em, mono operative labels at 0.08em. |
| Length | Short. One idea per sentence. |
| Punctuation | Periods, em-dashes, commas in running prose. Structural joins take // (below). No exclamation marks. No "Introducing:" lead-ins. |
| Numerals | Spell out one through nine in copy; figures in UI labels and prices. |
| Adjective hygiene | No "revolutionary", "leading", "powerful", "next-gen", "AI-powered". Replace with one concrete noun. |
| Verbs | Plain present tense. "The system uses Inter", not "we use Inter". |
| Emoji (scoped) | No emoji in this design system's own surfaces (README, cards, docs). This rule applies to the system, not to ASK universally — ASK's broader personal contexts have a sanctioned exception (a single purple heart used as personal branding) which lives outside this repo. Do not propagate a blanket "ASK never uses emoji" rule. |
Exception to the punctuation rule // protected payloads. The ASK tagline (order from chaos // beauty in systems) and its LinkedIn variant are protected payloads: fixed brand strings rendered verbatim, // intact. They are exempt from the punctuation and voice rules in the table above — the // is part of the string, not prose written in this system's voice. Never normalize it to an em-dash. Canonically defined in brand-architecture.md.
Structural separators. Where one part locates, numbers, names or labels the next, the join is //, with a space on each side: composed headings, numbered headings, label-to-title joins, a name or term followed by its description, and a key followed by its value, as in Question 2 // Should the market square stay in the study?. This is shared ASK-family presentation grammar, not ASK's personal voice. A bullet, middle dot or dash is not chosen as an alternative join for the same role. Peer items and a record's peer fields keep their own separator; a colon or period that introduces a value or numbers a heading stays; a string that is only spoken, such as an accessible name or an announcement, keeps its natural wording, and visual punctuation is not injected into it; and source text, quotations, identifiers, technical syntax, ranges and prose punctuation are preserved. There is no global dash or bullet replacement. The separator selects no font, weight, size, tracking, color or component, and the text keeps its role. It applies to new and revised material.
ASK's personal writing voice, terminalcore, is otherwise a separate convention: slash-slash in place of em dashes in running prose, plus for ampersand, double-angle arrows. That voice belongs to ASK's personal channels, not the design system. The design system speaks the calm sentence-case voice above, and the structural separator is the one element the two share.
Yes
No
Backgrounds // two diagonal gradients. Both 45° (bottom-left → top-right); the lighter end is top-right in light, bottom-left in dark.
linear-gradient(45deg, #D4C6E1 → #E2D3F0). Text is #6A637F (the approved dark-purple foreground).linear-gradient(45deg, #201D26 → #0A090C). Text is #D4C6E1.The gradient is fixed to the viewport (background-attachment: fixed), so scrolling reveals one continuous field.
Browser / under-page edge. A browser paints its own area beyond the document — the
over-scroll pocket above and below the page — and derives it from a solid background
colour, not from a gradient. It reads color-scheme for the same reason, to decide how to
render scrollbars and form controls. Both signals are page-wide, so the foundation owns both
on the root and nowhere else.
--bg-edge is the Tier-1 semantic role that carries the value. It binds existing palette
values and creates none: --ask-lavender-light in light, --ask-ink-dark in dark. The base reset
paints it on html beneath the gradient, so nothing visible on the page changes — the
gradient still covers the viewport, and the solid shows only where the browser reaches past
the document.
Two consequences worth stating, because both are easy to undo by accident:
background-image longhand. The background shorthand resets
background-color to transparent, which is precisely what left the canvas with no solid
layer to derive an edge from..theme-dark, which is right for local subtree theming and wrong here: custom
properties inherit downward, so a .theme-dark on body would resolve dark for that
subtree while html kept the light edge — dark content inside a white browser edge. A
descendant .theme-dark therefore leaves the canvas alone, by design.This is a foundation property, not a pattern feature. A pattern or surface must not declare
background-color or color-scheme on the root to correct its own edge.
Core set // the named values. Everything fundamental is built from these:
| Token | Hex | Use |
|---|---|---|
--ask-fg-light | #6A637F | Default light-mode foreground (body text — the approved dark purple) |
--ask-white | #FFFFFF | Light-mode wordmark (brand mark) — not body text |
--ask-lavender-light | #E2D3F0 | Light gradient, top-right; also the light browser / under-page edge (--bg-edge) |
--ask-lavender-dark | #D4C6E1 | lavender-ASK — light gradient start; dark-mode text |
--ask-ink-light | #201D26 | Dark gradient, bottom-left; also the opt-in high-contrast foreground role (--fg-high-contrast). Approved uses are registered below — see High-contrast foreground — registered uses |
--ask-ink-dark | #0A090C | Dark gradient, top-right; also the dark browser / under-page edge (--bg-edge) |
High-contrast foreground — registered uses. --fg-high-contrast binds --ask-ink-light as an opt-in foreground role, and this list is its registry: a use is approved only if it appears here. The role never rebinds the default gradient-surface foreground ramp — --fg-1 / --fg-2 / --fg-3 stay as approved — it is never the default foreground, and it is never selected by font size. A bounded element or region may opt in where the ordinary roles do not carry enough contrast, and only by registration below. The list order is organizational, not chronological.
message-archive pattern roles // participant ink and search-highlight text on the sanctioned colored fills.--fg-on-card // text on the fixed --surface-solid role, which does not flip with the theme and so takes a foreground that does not either.method-ASK D11 system-ASK hero // in the light theme, the figure-local diagram text roles opt into --fg-high-contrast after measured normal-text failure against the lavender gradient. Dark remains on the ordinary diagram roles. This is a bounded consumer-local use; it does not rebind --fg-1 / --fg-2 / --fg-3, alter the shared diagram patterns, or authorize another surface.A new use requires all three of the following before merge: measured evidence that the ordinary foreground roles are insufficient for the exact bounded element or region; explicit ASK source-of-intent authorization; and registration in this list. Density, legal, tabular, accessibility, or a comparable context may create the pressure that justifies proposing a use — none of them authorizes one on its own.
A canonical inspection specimen may render the role to display and measure it. Inspection is not an additional registered application.
Surface. When a card or container needs a solid fill with more presence than a glass overlay:
| Token | Hex | Use |
|---|---|---|
--ask-surface | #BFB3D4 | Container fill, rest |
--ask-surface-hover | #C9BCDE | Container fill, hover |
UI accents (two, muted, secondary use). For dividers, low-emphasis fills, secondary borders:
| Token | Hex |
|---|---|
--ask-ui-accent-1 | #8B79A2 (muted plum) |
--ask-ui-accent-2 | #AE87C2 (lavender-mid) |
Emphasis accents (three, sparing). Sanctioned for emphasis where the calm field needs a single hot point. Three — full stop. Not an invitation to introduce other hues.
| Token | Hex |
|---|---|
--ask-emphasis-magenta | #FF00FF |
--ask-emphasis-violet | #AA40FF |
--ask-emphasis-cyan | #00BEFF |
Inter is the default interface, display and explanatory family. JetBrains Mono is reserved for explicit technical, structural or operative roles, owned by selectors in their applicable module or pattern. Mono is never a generic body or support-copy substitute, and nothing becomes mono merely for being interface-facing — it enters where structure or precision matters. Family is chosen by the owning selector, never by payload text, HTML element type, capitalization, or the presence of //.
The current live-surface allocation:
| Owner | Selectors | Role |
|---|---|---|
| foundation utility | code · kbd · pre · samp · .mono · [data-mono] · .tabular | code, technical and tabular literals |
surface-action.css | .surface-action | compact operative control |
surface-shell | .surface-title · .surface-badge · .surface-nav-row | structural title, status badge, panel hierarchy row |
surface-document.css | .doc-label · .doc-meta · .doc-quote > footer · .doc-code · .doc-pre · .doc-toc-list · .doc-toc-link · .doc-table-cell · the overflow cue | operative label, metadata, quotation attribution, code, preformatted text, the table-of-contents list and its entries, and dense table cells in the document register |
surface-treatments.css | details.surface-disclosure > summary · .surface-disclosure-trigger · .surface-emphasis-chip | disclosure trigger, controlled disclosure trigger, emphasis chip |
| a consuming surface | its own explicitly named operative control | e.g. the style guide's .surface-theme mode selector |
Everything else on a live surface is Inter unless the owner of a selector says otherwise, and a generic utility class is not a license to make prose mono.
That table is the live-surface allocation, not a repo-wide census. The artifact and diagram patterns own additional pattern-local technical and structural mono selectors — diagram sublabels, stamps, theme tags, archive metadata — under the same principle: an explicit selector in the owning pattern. Those local contracts never make mono a page default, and they do not extend to any surface that has not adopted the pattern. The panel primary label sits between them in the table because it shares the locator's metric exactly, not because it is a third mono role: it is Inter. Both families are loaded locally as variable webfonts in fonts/ (OFL).
Type hierarchy is role-driven. The defined scale steps distinguish semantic roles; do not invent an ad-hoc size merely to add emphasis. Within a role, weight and foreground carry contrast.
Generic H1 and H2 roles use 400. H3 and both primary-label implementations use 300. Body uses 200; Small uses 300; Caption uses 400. The document register assigns weight by its own roles: document and section titles 400; subsection title 300; deep heading 500; lede, document body and quotation text 200; entry titles, preformatted text, table-of-contents entries and dense table cells 300; strong emphasis in document text 500. Light weights are deliberate. No thick typefaces.
Element name does not override the explicit role: an h1 or h2 carrying .surface-title or .surface-panel-title remains a primary label at 300, and conforming it to the generic heading weight is a defect rather than a repair.
Element name does not override a document-register role either. An h1 carrying .doc-title is a document title at 48 / 400. An h2 carrying .doc-section-title is a section title at 36 / 400, and an h3 carrying .doc-subsection-title is a subsection title at 28 / 300. An h4, h5, h6 or [role="heading"] element carrying .doc-deep-title is a deep heading at 24 / 500, at every depth. Each role is a complete text style — family, size, weight, leading, tracking, foreground and margin — so the element's own foundation rule contributes none of those seven. The foundation also sets text-wrap: pretty on h1/.h1, h2/.h2 and p/.body. The document register does not set text-wrap, so wrapping remains subject to the cascade and inheritance rather than being fixed by the text role. The generic H1 and H2 rows govern headings that carry no explicit role. Conforming a document-register heading to the generic heading size or weight is a defect rather than a repair. Uppercase mono is never a content heading, and a heading is never smaller than the prose it governs; depth is carried by the hierarchy rail, not by a smaller, lighter or recolored heading.
The 24px primary label over 18px supporting copy pair is a sanctioned distinction between two defined roles — not ad-hoc sizing, and not a case where a weight difference should be substituted for the size step. Both sit at 300, and the pair separates on role.
| Role | Family | Weight | Size / line-height | Tracking |
|---|---|---|---|---|
| Display | Inter | 200 | 96 / 1.02 | -0.035em |
| H1 | Inter | 400 | 48 / 1.12 | -0.02em |
| H2 | Inter | 400 | 36 / 1.12 | -0.02em |
| H3 | Inter | 300 | 28 / 1.20 | -0.02em |
| Body | Inter | 200 | 24 / 1.45 | 0 |
| Small | Inter | 300 | 18 / 1.40 | 0 |
| Caption | Inter | 400 | 14, UPPERCASE | 0.14em |
| Primary label — structural locator | JetBrains Mono | 300 | 24 / 1.16 | -0.02em |
| Primary label — panel | Inter | 300 | 24 / 1.12 | -0.02em |
| Compact action | JetBrains Mono | 300 | 14 / 1.20 | 0 |
| Code / inline-code | JetBrains Mono | 300 | 0.9× host | 0 |
| Tabular numerals | JetBrains Mono | inherit | inherit | 0 |
| Document title | Inter | 400 | 48 / 1.12 | -0.02em |
| Section title | Inter | 400 | 36 / 1.12 | -0.02em |
| Subsection title | Inter | 300 | 28 / 1.12 | -0.02em |
| Deep heading — h4 and deeper | Inter | 500 | 24 / 1.12 | 0 |
| Lede | Inter | 200 | 24 / 1.45 | 0 |
Inside document compositions, Caption sets 1.30 leading and no margin.
Inline code inside an operative label keeps its source case: the label's capitals never rewrite a code literal, and default-ASK is not DEFAULT-ASK. Plain text in a label, a unit such as mW included, keeps the capitals.
The document-register ladder. Document body is the foundation's Body step — the same 24 / 200 as a plain paragraph — and every document heading sits on a foundation step at or above it: the title on H1, the section title on H2, the subsection title on H3, and the deep heading on Body, where weight (500 against 200) and the space before it carry the distinction. No content heading is smaller than the prose it governs, and a quotation is body-sized at every length. The ladder is the foundation's own; the register adds no size. .doc-quote--display, which set a short quotation larger than its prose while the plain quotation sat smaller, is retired.
Conformance, in two halves. tools/check-type-roles.mjs rule R7 reads surface-document.css against one role matrix and fails when any rule on a role's selector declares another family, size, weight, leading, tracking or foreground, when reading text leaves the Body step, when a heading is declared smaller than body, when any other rule on a quotation sets a type metric, when a quotation or block rail is not declared by exactly one rule or is drawn or recolored anywhere else, when either passage rail leaves .surface-emphasis-rail's geometry (width, style, inset), when the emphasis rail leaves its registered magenta, when the block rail's magenta differs from the emphasis rail's words, when the quotation rail leaves the registered emphasis violet or the violet modifier's words, when the rendered checker pins another quotation color, lets an authorial callout take any color but the emphasis rail's magenta or stops admitting the three sanctioned accents on any other emphasis rail, when the hierarchy rail is not the registered 1px --line-2 rail, or when the rendered-page role matrix or link-state matrix drifts from its source. Geometry parity is enforced; each role's color is pinned, and no role is required to share another's. tools/role-conformance.js checks a rendered page: the foundation tokens, families, accents and theme roles are the owner's wherever governed text renders; every element that carries a role computes to the matrix, and text inside it keeps its family, size and weight (inline emphasis may change the weight) unless a valid profile declares it (and text inside a profile member keeps the member's); each quotation and preformatted block is covered by exactly one rail of the shared geometry — its own, in its role's color, or the nearest railed passage around it, whose role names the passage — each emphasis rail on document text, an authorial callout, draws the geometry in magenta and any other emphasis rail in one of its three accents, and each hierarchy level draws the 1px neutral rail; every table-of-contents link composes .surface-text-link and renders its underline, and every anchor in a contents list is a contents link; the cells of a declared dense table carry their roles and the dense role appears nowhere else; no contents list or dense cell holds document body; no retired class remains; a link inside document text, a label or a heading carries .surface-text-link; each declared peer group in structured text opens on its label, holds no space inside it and sits exactly one line from the next, as measured on its rendered lines; and, where the Review Semantics composition's classes appear, each mark carries the label role, one facet and a value from that facet's vocabulary and draws its outline or marker in its role token, each passage mark carries the shared scope underline in its judgment's value and names its note, and no row, item or list draws a rail. tools/check-role-conformance.mjs runs it headless on any served page, proves each governed link's rest, hover, keyboard-focus and return-to-rest states with real input, and then judges each element of the annotation composition that a closed disclosure kept from being seen on what it presents once open (C12, and C3 for its hierarchy rail); and prove each failure branch fails with its own reason code. Among the limits lists, two bear on what a pass compares. A valid profile exempts its members' own text: it is reported with its computed metrics and compared against no role. And the descendant check (C8) compares family, size and weight only, never letter case; case is compared by the role-metric check (C1), for the four of the fourteen matrix roles that declare one. A page with no governed element is reported , never passing.
Rails: shared geometry, meaning in the color. A quotation, a preformatted block and an authorial callout are all set apart on one geometry — a 2px solid rule and a --space-4 inset — and every one of those outer rails is an emphasis accent, so each reads as a boundary in both themes. A labeled range's scope rail is not one of these rails: it sits in the outer margin, outside the content edge, and marks the extent of a label's scope, never a passage's role. The color says whose passage it is. A quotation is represented voice — words presented as someone's, including an earlier statement by the same author or speech the prose introduces — and its rail is the emphasis violet, declared as .surface-emphasis--violet declares it; it records whose words these are, not verification, evidence, endorsement or approval. The document's own thesis, posed question or analytical contrast within its argument is an authorial callout: .surface-emphasis-rail, magenta, composed onto document body text. An emphasis rail on document text — one that carries document body or lede or a text composition (.doc-group, .doc-prose, .doc-section, .doc-titled, .doc-labeled), or holds any of those, a quotation or a block — is a callout and always magenta; the violet and cyan modifiers stay valid on any other emphasis rail, and the rendered check holds each to that. A preformatted block's line structure is its content: its rail is magenta, declared exactly as .surface-emphasis-rail declares it. Who is speaking is the consuming surface's editorial assignment — never the element, the font, boldness or a pair of quotation marks. Neutral is structure only: the hierarchy rail stays a 1px neutral rule that structures a section, a list or a block, and no set-apart passage takes a neutral outer rail. A passage inside a railed passage draws no second rail, so one logical passage has one outer rail and the outermost role names it; a quoted code excerpt is a .doc-pre inside a .doc-quote and keeps the one violet rail. A section synthesis — the compression that closes a part — is not railed: it is a flat panel (.surface-separate + .surface-material-panel + .surface-attach-free + .surface-elevation-flush + .doc-group) with a .surface-emphasis-chip carrying .surface-emphasis--magenta and its text on .doc-body. A section framing — the statement that frames a whole part before its sections, the part's thesis or the question space it opens — takes the same flat panel and chip, its chip naming the framing. It opens the part, after the part's introduction; it looks forward where a synthesis looks back, and concludes nothing. A thesis or question set apart inside the argument stays an authorial callout. The neutral quotation rail is retired (2026-09-19): it made a set-apart passage look ghosted.
Profiles are declared, not waved through. A consumer's own named role — a count numeral, say — is a profile declaration: { "name", "selector", "owner", "reason", "expected_count" }. The check validates it before it exempts anything: every field present, one selector ending in a class, id or attribute, exactly the declared number of matches, and no match that carries or contains a governed role or passage. A declaration that fails exempts nothing, so a profile cannot hide the defect it was widened over.
Document compositions carry the space between roles. Every document role sets margin: 0. .doc-flow (--space-8), .doc-section and .doc-titled and .doc-group (--space-3), .doc-prose (--space-4) and .doc-labeled (--space-2) set it as a gap; a section nested in a section leads by --space-4 more. .doc-hierarchy is the neutral hierarchy rail: it carries a whole section, one rail per level, to any depth, and a structured preformatted block uses the same rail for indentation that is structure. data-lead-lines records one to three blank source lines. A grouped diagram declares each peer group as a .doc-pre-group, and successive groups sit exactly one line apart (Structured text, below). .doc-quote and .doc-pre draw the passage rail on .surface-emphasis-rail's geometry — a 2px solid rule and a --space-4 inset — each in its own role's color: a quotation is represented voice and takes the emphasis violet; a preformatted block takes the magenta emphasis rail, with no variation; an authorial callout, .surface-emphasis-rail on document text, is magenta too. So a quotation, a block and a callout each read as one set-apart unit — violet represented voice, magenta the document's own, the block's mono its line structure; a passage inside a railed passage draws no second rail. .doc-toc-list is a table of contents (a nested contents list that is also a .doc-hierarchy is one level down) and .doc-toc-link its entry, always composed as class="doc-toc-link surface-text-link": the register owns the entry's type, the text-link module its interaction. A dense table is one the consumer declares: in a table.doc-dense-table, .doc-table-cell is the value and .doc-label the header, and .doc-table-cell appears nowhere else; a table without the marker — a narrative comparison, a prose table — is not the dense role: it is a narrative table, its headers on .doc-label and its cells on .doc-body. A table's geometry stays with the consuming surface unless the table adopts the document table composition (below). .doc-actions arranges a wrapping row with vertically centered items. For a short text lead-in beside a compact action, put .doc-body on the lead-in's own element (for example, <span class="doc-body">) and .surface-action on its sibling control.
Text keeps a clear reading area. A decorative boundary stops at its label (surface-document.html #reading-area-routed). A meaning-bearing connector keeps its ends, direction and path (#reading-area-relation). Both are demonstrations, not module classes.
The primary-label role names a thing the system has — a surface, a route, a panel, a named primitive — rather than setting prose. Its shared core is 24 / 300 / -0.02em, on Body rather than an H-step because a label is a locator and not display type, and its default leading is 1.12 — which the panel implementation takes and the structural locator overrides. It has two implementations, and each owns its family through its selector.
The two implementations differ in family and in leading. They share everything else. The shared core — 24 / 300 / -0.02em — is what makes a primary label read as one object across surfaces, so it is precisely not what separates them. .surface-title is JetBrains Mono on 1.16; .surface-panel-title is Inter on --lh-heading (1.12). The 1.16 is a metric the shell owns for a wrapping, underlined structural locator, and the panel label — a single line, never underlined — has no such condition to earn it.
Both surface-shell title forms take 1.16: the plain title and the breadcrumbed title alike. Those two forms differ in landmark and in linkability — never in leading, and never in family. The breadcrumb's older pattern-local 1.35 was retired: it had been measured against an underline that was a border, and survived the change to a text decoration by inertia. Nothing carries it now.
.surface-title in the surface-shell pattern is the structural locator and is mono. That covers both of the pattern's title forms — the plain <h1> and the breadcrumbed title — because both carry .surface-title. .surface-panel-title in surface-panel.css is the panel primary label and is Inter, and it stays Inter whatever the label says — a panel may name something technical or structural, and may carry // or any other ASK punctuation, without changing family. Those two selectors are the canonical implementations; neither is conformed to the other, and the shared size, weight and tracking are what still make a primary label read as one object across surfaces. No family is ever derived from a payload string.
Supporting copy under either stays on the Small Inter step, so that pair separates on size rather than weight. colors_and_type.css is unchanged by this role: its generic .mono utility remains for code, technical and tabular use, and the mono structural-locator exception is applied only through .surface-title. The compact action (.surface-action) is a separate mono exception, with its own metric and its own canonical selector — it is not an implementation of this role.
The compact-action role is the label on a small control — a chip, a route action, a preview or README button. .surface-action in surface-action.css is its canonical implementation. It is Caption-sized, not the Caption role, and the distinction is load-bearing: Caption is 14px Inter at 400, uppercased, on 0.14em tracking, and it labels things; the compact action is 14px mono at 300, sentence- or lower-cased, on zero tracking, and it is something you click. Conforming a compact action to Caption's uppercase, tracking, or weight — or to Inter — is a defect rather than a repair. This role also does not govern the 18px Inter CTA specimen in the style guide, which is a separate and deliberately different object.
Tracking is assigned by role and never chosen per artifact. Two small uppercase registers exist and never trade values: the Inter Caption at 0.14em and mono operative labels at 0.08em. A label takes its tracking from its role, not from its size — Caption-sized is not the Caption role. Specialized patterns — the Class A diagram scaffolds and the message archive — own pattern-local label metrics that do not extend to any other surface; a diagram scaffold's .caption overlay is one of those, not the Caption role. A new value enters this account only with a named role.
| Tracking | Token | Roles |
|---|---|---|
| -0.02em | --tracking-tight | H1 · H2 · H3 · document title (.doc-title) · section title (.doc-section-title) · subsection title (.doc-subsection-title) · table-of-contents entry (.doc-toc-link) · structural locator (.surface-title) · panel primary label (.surface-panel-title) · panel hierarchy row (.surface-nav-row) |
| 0 | --tracking-normal | Body · Small · supporting copy (.surface-panel-support) · lede (.doc-lede) · document body (.doc-body) · entry title (.doc-entry-title) · quotation text (.doc-quote > p) · deep heading (.doc-deep-title) · preformatted text (.doc-pre) · dense table cell (.doc-table-cell) · compact action (.surface-action) · code and inline code, the document locator included — .doc-code declares no tracking, so a locator stands only where its container sets none · tabular numerals |
| 0.08em | --tracking-wide | mono operative labels and metadata (.doc-label, .doc-meta) · status badge (.surface-badge) · overflow cue (.doc-pre and .doc-table-scroll ::after) · quotation attribution (.doc-quote > footer) · disclosure trigger (.surface-disclosure > summary, .surface-disclosure-trigger) · emphasis chip (.surface-emphasis-chip) |
| 0.14em | --tracking-caption | Caption — Inter, uppercase (.caption) · the pattern gallery's group and card-class labels (.group-label, .card .cls in patterns/index.html) — Inter uppercase labels that share Caption's register and tracking but keep their own weight and foreground, so they are not the Caption role · the style guide's section labels (.sg-h in preview/styleguide.html) — Inter uppercase labels in the same register that keep the 200 weight they inherit, so they are not the Caption role either |
| -0.035em | --tracking-display | Display |
Registered exception. The style guide's .badge component specimen is Inter, uppercase, at --tracking-wide. It is neither the Caption role nor a mono operative label, and it is not a precedent for either register.
--radius-sm (8px), and the attachment axis is corner treatment only. Square corners on hairlines and dividers.rgba(white, 0.45) on light gradient and rgba(lavender-ASK, 0.22) on dark. Always 1px. No passage rail takes the hairline value: a quotation's rail is the emphasis violet, and a neutral outer rail on a set-apart passage is retired.sm (1px), md (24px), lg (60px). No hard drop shadows, no inner shadows, no colored shadows. Zero-blur interaction rings — the focus glow, the attention edge's 0.5px ring, and the inset 1px ring a borderless adopting object draws where a border would sit — are edge paint, not elevation shadows, and this line does not govern them. The content-emphasis bloom (surface-treatments.css) is emphasis paint, not elevation: a persistent, role-assigned accent whose dose is set per theme. This line does not govern it either.--surface-glass fill (white at 14% on light, lavender-ASK at 6% on dark) with a 1px --line-1 hairline, plus a 20px backdrop blur where the material blurs — the page material (.surface-material-page) blurs; the panel material (.surface-material-panel, used by the disclosure) does not. Attachment: corner treatment only — radius-lg (22) on every corner of a free-standing surface (.surface-attach-free); a surface joined at its top or bottom edge rounds only its free corners (.surface-attach-top, .surface-attach-bottom); a surface joined along its full width rounds none (.surface-attach-full-width); a chip takes radius-pill (.surface-attach-chip). Attachment sets no fill, blur, edge or shadow. surface-shell's navigation panel realizes the same corner rule pattern-locally and also drops the border on its joined edge; it does not consume these classes. Elevation: chosen per role — .surface-panel rests on shadow-md; a surface that is not a content panel is flush (.surface-elevation-flush) unless its role raises it (.surface-elevation-raised). surface-panel.css is the complete component selecting page material, free attachment and raised elevation, and it authors that recipe once: the matching axis classes share its declarations by selector grouping, while the linked panel's hover and focus rules and the composed emphasis shadow name again, because a box-shadow list cannot compose across rules. The gradient shows through.Three questions, asked in order; the first two inform the third and do not decide it. Semantic identity — is this a distinct section, quotation, finding or decision? Interaction identity — does it need its own control, focus behavior or navigation target? Presentation requirement — does the reader need a separate visual plane, or only grouping, attribution, indentation, spacing or a local boundary? Only the third selects a treatment, from least to most: ordinary flow (the default) · subordinate grouping (.doc-hierarchy — spacing and one quiet rule; no wash, blur or shadow) · quotation anatomy (.doc-quote — the passage rail, body-sized text and attribution; not a container) · disclosure (details.surface-disclosure — a trigger and an expanded region) · separate surface (.surface-separate with one material, one attachment and one elevation — earned when the object overlays, scrolls independently, arrives from outside the reading flow, or is a whole unit set apart for emphasis or comparison). An addressable subsection stays in ordinary flow; an attributed quotation takes no surface.
Hover // opacity drops 1.0 → 0.92, and/or the border changes; a closed disclosure's trigger changes its foreground only; an open one already rests at the raised foreground. No arbitrary new hue is introduced: where a border changes color, it resolves either to something the element already carries or, for the shaped populations below, to the palette's emphasis magenta. The treatment is role-driven, and the roles genuinely differ — do not conform one to another:
| role | hover treatment |
|---|---|
generic anchors (foundation a) | foreground-bound — the text-edge border resolves to currentColor |
compact actions (.surface-action) and full-panel links (a.surface-panel) | attention edge — the complete border turns pure magenta (--ask-emphasis-magenta) in both themes, with an apparent 1.5px edge in light (the 1px border plus a 0.5px zero-blur ring outside the box) and 1px in dark; no glow and no layout change; a full-panel link's ring composes with its resting --shadow-md. Keyboard-visible focus takes the same edge — see §Focus |
objects that adopt the edge (.surface-attention-edge) — a shaped interactive object that is neither of the above, such as an image card, a media launcher, an overlay control or a linked card in an SVG figure | the attention edge alone, on the anatomy the object has: its own border; on a borderless control (.surface-attention-edge--borderless), an inset 1px ring where a border would sit, with the same 0.5px ring outside in light; in SVG, the stroke of the shape the link marks (.surface-attention-edge-shape), an apparent 1.5px in light and 1px in dark: a figure drawn below its own size declares that scale as --surface-attention-edge-scale, and the stroke widens to hold the edge; at its own size and above, the stroke is 1.5 and 1 units and scales with the figure, for a shape that rests on the diagram box's 1-unit stroke. The class brings no opacity drop, press or motion; the object's own hover stays its own, an anchor's foundation hover included. Keyboard-visible focus takes the same edge |
unboxed textual links (.surface-text-link) and breadcrumb links (.surface-title a) |
cubic-bezier(0.22, 1, 0.36, 1) for entries; cubic-bezier(0.65, 0, 0.35, 1) for cross-fades.opacity and transform. Avoid layout transitions and bouncy easings.Linear.app, Stripe, Apple. Structural elegance, mathematical clarity, refined light typography. Avoid: playful or bloated visuals, thick typefaces, emotional/empathic design tropes.
Each rule file, key, page and pattern in the catalog carries one disposition against the type roles, document compositions and surface treatments above. The attachment axis spans two rule files and has its own row. A disposition describes the item as it is.
| Item | Disposition | Detail |
|---|---|---|
colors_and_type.css | extended | --tracking-caption (0.14em) carries the Caption role's tracking, and .caption uses it |
surface-panel.css | extended | the one authored source of the glass recipe: the page material, panel material, free attachment and raised elevation classes share its declarations by selector grouping; the linked panel's hover and focus rules and the composed emphasis shadow name its raised-elevation token again |
surface-action.css · surface-text-link.css | conforming | the compact-action and textual-link roles, and the attention edge adopted by class, as described above |
surface-document.css · surface-document-overflow.js · surface-treatments.css · surface-document.html | new | the document register, its optional overflow helper, the surface treatments and their rendered key. The key renders every attachment value, labeled pairs (.doc-labeled), long headings from the section title to the eighth level that wrap within their column, grouped structured text at two, five and ten peer groups and under a single label, an ungrouped block keeping a recorded blank line, the section framing beside the synthesis, a repeated collection whose grid, column count, order and words it marks as consumer-owned and whose items of unequal copy end their action rows on one bottom edge, records beside an inspector with a page-local adapter, a source address standing as a field value beside a URL in prose, and narrative, dense and header-bearing tables in the document table composition beside a dense table in its consumer's own geometry |
| the attachment axis | new | five values, corner treatment only: .surface-attach-free in surface-panel.css; .surface-attach-top, .surface-attach-bottom, .surface-attach-full-width and .surface-attach-chip in surface-treatments.css. A surface chooses its attachment independently of its material and its elevation |
spectral-state.* · evidence-state.* · three-functions.* | conforming | the Spectral State, Evidence State and Three Functions primitives. Their rendered keys set the page title and the section titles through .doc-title and , and their page-local labels take the role tracking tokens |
A surface adopts the register by replacing raw sizes with roles. A raw value maps by what the text is, never by the nearest size. These rules are generic; a surface's own selector map stays with that surface.
| Raw pattern | Role |
|---|---|
| a 10–12px mono uppercase label | .doc-label |
| the same label in a thin neutral border, a status word such as DRAFT | .doc-label.surface-bordered-label // the box and edge are the bordered label's; its border stays the tertiary foreground |
| the same label used as an accent flag naming why a unit is emphasized | .surface-emphasis-chip // the bordered label's box, the words in the primary text role, the accent on its border |
| a run of blocks one label governs, with a scope rail in the margin | .surface-labeled-range on the run, its label first, or on one whole list item, which is then the range // the scope rail is the labeled range's, outside the content edge, an item's reached back across its list's indentation; in a document that adopts Review Semantics, .doc-annotation-range.surface-labeled-range, opened by the row naming its one judgment, that judgment first; a document table with a range in its first or only column adds .doc-table-scroll--range-lane to its box |
| the exact words inside a block one label governs, marked by a line under them | .surface-scope-underline on the words // one solid 2px line, the words keeping their color; in a document that adopts Review Semantics, mark.doc-passage-mark.surface-scope-underline with the judgment's data-review, naming its note |
| a label recording a review, evidence or state value, in a document that adopts Review Semantics | span.doc-mark.doc-label with its data-review, data-evidence or data-state value, from review-semantics.css; a review mark also carries .surface-bordered-label, the shared box. Another owner's presentation, such as a consumer's own Evidence State assignment, stays that owner's |
| 10–12px mono metadata, not uppercase | .doc-meta |
| inline code sized in em | .doc-code, inside a sized role |
| a raw 36px or 48px title | .doc-title or .doc-section-title, chosen by its level in the document, not by its old size |
| a code or diagram block at a raw size | .doc-pre — it draws the passage rail |
| a grouped diagram whose peer groups are told apart by typed blank lines |
Structured text. A preformatted passage whose indentation is structure is one scroll box, .doc-pre.doc-pre--structured. Its lines sit in .doc-pre-part elements. The lines beneath a line sit in a .doc-hierarchy, one rail per level of indentation, nested in source order. A level is assigned by what the lines mean to one another; spaces that only align columns are not levels. A block takes .doc-pre on purpose, never through a blanket pre or code selector. Peer groups. A grouped diagram — peer groups, each a label with the lines beneath it — declares each group as a .doc-pre-group: a direct child of the block, opening on its label part, in a block that holds nothing else at its top level. Successive groups sit exactly one line apart, whatever their number; inside a group nothing is set apart, so the label sits on its lines. The consuming surface declares the groups; how it finds them in its own source — a template, a table, a separator its own format defines — is its adapter, never a shared rule. No rule and no check here reads a group from blank lines, capitals, font or line count, an adapter never finds one merely from capitals, font or line count, and verbatim code or a quoted payload keeps its own blank lines. Outside declared groups, data-lead-lines on a part or a rail records one to three blank source lines before it. On a group's first line it adds nothing — the one line between groups stands for it, and before the first group it is dropped; anywhere else inside a group it splits the group, and the rendered check reports it (C11). The whole block sits behind one magenta block rail; its hierarchy rails stay neutral.
Document table. A table takes its geometry from the register only when the consumer adopts the composition by class: table.doc-table as the direct child of a .doc-table-scroll box, with .doc-table-num on a numeric column's header and cells. Both markers are needed: a table marked without its box takes none of it, and a table nested inside a composition cell takes none of its cell rules. The composition draws the fainter rule under every row and the hairline under the header row, and sets the cells' spacing. It aligns a numeric column to the end on tabular figures, keeps a narrative table at a 32rem measure and a dense value on one line, and lets code break only at its own opportunities. A table wider than its column scrolls inside its own box, with its header row in place, and the page never scrolls sideways. A table with a labeled range in its first or only column adds .doc-table-scroll--range-lane to its box: the box reaches the range's 14px lane into the page's margin and pads it back, so the scope rail is drawn inside the box that scrolls and no column moves. Scrolled, the table's content passes through the lane; a consumer that sets the box's inline margin or width itself restates the pair. In any later column a range hangs into the gutter of the column before it. Nothing implies the composition: not table.doc-dense-table, not a text role on a cell, not the table element. The consumer names each scroll box as a region. The composition is not a compact layout and has no stacked narrow-width layout; a surface that needs either keeps its own geometry and does not adopt it. It also carries no print rules and does not address multi-level, spanning or nested headers or interactive header controls; a shared treatment of any of these is deferred to the document register. A surface that prints an adopted table adapts it with print rules of its own, as the output-artifact template does, and a surface that needs a complex or interactive header keeps its own geometry.
Main + inspector. Records in a main region beside an inspector for the one selected are a composition of delivered parts, with no selector of their own. Both regions keep one set of text roles, so a role keeps its treatment wherever it occurs and the inspector's prose stays .doc-body at the Body step however narrow its region. A record's name is an entry title in the main region and the view's heading in the inspector, because there it governs the fields beneath it. Each view composes .doc-titled, .doc-group and .doc-labeled. The inspector is a separate surface chosen on the three axes — .surface-separate, .surface-material-panel, .surface-attach-free and .surface-elevation-flush, the flat panel of the section synthesis. The regions' grid, proportions and breakpoint, the inspector's sticky place and independent scroll, the regions' order at a narrow width, selection, the current-item indication, focus handling and the route back all belong to the consuming surface. surface-action.css's magenta is attention only and never marks the current item. The register's compositions and .surface-action set display, so a consumer that hides a view or control with the hidden attribute supplies its own guard. The key demonstrates the composition with a page-local adapter (surface-document.html #records-inspector); nothing in it is a shared inspector controller.
Document locator. A source address, DOI or path that stands as a field value is inline code on its own: code.doc-code as the value of a .doc-labeled field, inside no other text role. It is an assignment, not a role, and has no class, metric or foreground of its own. Standing alone, .doc-code is mono at the Caption step, 300, in --fg-2, and breaks anywhere, so a long address wraps inside its field. It declares no leading, tracking or case: a locator takes them from where it stands, so it keeps its literal form only where its container sets none. Inside a label it would take the label's tracking and a smaller size, 0.9em of the label's (the register keeps code's source case there); inside a caption or a disclosure trigger, their capitals and tracking; inside a panel title, its tracking. So a locator never sits in any of them, and apart from that one case rule the role enforces none of this in any ancestry. A followed address is a .surface-text-link inside the code element. An address inside running prose stays a body link, an identifier that names a record stays .doc-meta, and which tokens link is the consumer's rule. An address in a page header's chrome is outside this assignment.
Action row at an item's end. In a repeated collection, .doc-actions--end on an item's .doc-actions places the row at the item's end. It works where the item is a flex column that stretches to its grid row's height: a .surface-panel item in a grid that keeps the default align-items. The auto start margin takes whatever block-axis space the item leaves. In grid rows sized to their content, that is only the space a taller neighbor leaves, so the tallest item's row still follows its copy by the item's gap; where the consumer sizes rows otherwise, every item's row may move. The guarantee is precise: the action rows of one grid row share their bottom edge, wherever each item is at least as tall as its content. When neighboring rows wrap to different numbers of lines, their tops do not match; the wrapped row's top sits higher by its extra lines. The grid, its rows and their heights stay the consumer's, and nothing is fixed, filled or offset. A row without the modifier keeps its place after its copy. Where the row has no free block-axis space, in a block container or a column no taller than its content, the modifier moves nothing; in any flex or grid context that leaves it space, it takes that space. It is adopted by class only, never through a bare element or .doc-actions itself. It sets only the row's place; the controls stay surface-action.css's. tests/doc-actions-end-fixture.html guards it.
Overflow helper. surface-document-overflow.js is optional. Without it a wide block, or a document table's box, still scrolls and shows no cue. With it, the helper marks which sides of a wide block or box hold hidden content, and the stylesheet draws the cue.
Sealed use. An artifact scaffold may inline the register at generation time. patterns/output-artifact/ is the owner's scaffold for this use: its template links the modules, and the consuming renderer inlines them at seal time. After the foundation it already carries, it inlines surface-text-link.css, which a table of contents or any governed link requires, and then surface-document.css. An artifact that also uses the surface treatments inlines surface-panel.css, surface-text-link.css, surface-document.css and surface-treatments.css, in that order — the order in which surface-document.html loads them. An artifact that adopts Review Semantics inlines spectral-state.css, evidence-state.css and review-semantics.css after those four, in that order. Each is inlined verbatim: none carries url() or @import. The sealed copy does not re-sync, and the helper stays optional.
Accent. An emphasis accent comes from the consuming surface's information architecture: the role its content plays there selects .surface-emphasis--magenta, .surface-emphasis--violet or .surface-emphasis--cyan. The treatment accepts that accent and never chooses one. In a document, an emphasis rail on document text is the authorial callout and takes magenta (Rails, above).
The default is no icons. The wordmark, the type, and the gradient carry the identity.
When a UI absolutely needs an icon for affordance, treat it as an exception:
currentColor only — never colored, never two-tone, never filled.assets/icons/.Every diagram package generates and retains both theme variants (-light and -dark). The embedding surface selects the default:
This rule selects which existing render is embedded. It does not suppress, rename, or replace the alternate-theme export.
Public downstream repos consume these patterns and tokens by reference. The known public consumers are tracked in CONSUMERS.md.
Consuming a pattern does not fork it. The two material kinds do not share a lifecycle:
Neither route uses a CDN or a runtime hot-link. Ordinary downstream artifact consumers take the foundations through a local pinned _dsa-tokens/ mirror; the ASK front door is the exception recorded in CONSUMERS.md — it vendors the foundations (tokens, fonts, wordmark) directly rather than via a _dsa-tokens/ mirror, and carries ASK's own Tier 3.
.ai vector working source lives operator-side, not in this repo (production assets only). The repo carries the primary vector at assets/logo-ASK.svg (fill: currentColor) and two PNG pairings.patterns/diagram-static-H/, vertical patterns/diagram-static-V/, sequence patterns/diagram-static-SEQ/, convergence-flow patterns/diagram-static-FLOW/, peer-relation patterns/diagram-static-peer/, and interactive patterns/diagram-interactive-spine/) and the Class B project-output scaffold (patterns/output-artifact/) are implemented. Both surface patterns are implemented: patterns/surface-shell/, which this repo's own three public surfaces and its generated reading pages consume, and patterns/diagram-interactive-radial/. Landed public consumers, downstream and first-party alike, are recorded in . No public production Class B output-artifact surface has used this scaffold end-to-end yet. A private operator-internal consumer has exercised the Class B output-artifact flow end-to-end under its v2 contract; contents remain firewalled. has exercised and sealed the v3 document-register path end-to-end through its Class B renderer; that sealed review artifact remains operator-side rather than a public production surface.Copyright 2026 Andrew S Klug // ASK
Licensed under the Apache License 2.0 // see LICENSE
surface-shell (the shared header, control slot, and flush-right footer that make a family of surfaces read as one artifact family with different payloads) and diagram-interactive-radial (a context-agnostic interactive radial map of a containment hierarchy, mounted on a live page). Each runs on a live page and seals nothing, so neither is a sealed output artifact, and the radial pattern is not a Class A scaffold: it is not inherited at generation time. The group is not "Class C" — it is a named group by lifecycle, not a taxonomy.review-semantics.cssASK Review Semantics // Review State, a sanctioned profile under Spectral State for documents that are reviewed, and the opt-in annotation composition that attaches review, evidence, state and basis to the content they concern. proposed / open / accepted / declined / none reuse existing values by reference; it mints none. Rendered key in review-semantics.html. Layers on top of the four register modules, spectral-state.css and evidence-state.css. |
three-functions.css + three-functions.md + three-functions.html | ASK Three Functions — specialized opt-in function-color primitive (three --function-* roles: legislative magenta / executive theme-neutral white·lavender-ASK / judicial cyan), a sibling to Spectral State on the function axis (not a profile). Binds existing ASK values to roles; no palette expansion. Rendered key in three-functions.html. Layers on top of colors_and_type.css. |
surface-panel.css | Opt-in live-surface visual rule — the shared visual contract for live content panels: chrome (.surface-panel), primary label (.surface-panel-title), supporting copy (.surface-panel-support), and the interaction contract for a panel that is itself a link (a.surface-panel). It owns presentation only — no markup, no semantics, no template, no generated preview. Two semantic forms can share this appearance without sharing structure or behavior: a full-panel native link, and an inert panel containing consumer-owned links or actions. It deliberately does not own support-copy foreground, and it assigns no interaction to inert panels. It is also the one source of the glass recipe: the page material, panel material, free attachment and raised elevation classes of surface-treatments.css share its declarations by selector grouping, so an artifact scaffold that inlines the treatments inlines this file with them. Not a component, not a surface pattern, not an artifact scaffold |
surface-action.css | Opt-in live-surface visual rule — the shared visual contract for compact action controls, and the sibling of surface-panel.css on the action axis: the control itself (.surface-action), its foreground-only quieter variant (.surface-action--secondary), and one inherited hover / press / focus contract. It owns presentation and interaction only — never element type, destination, copy, action-row layout, or placement, so the same grammar styles an <a> that navigates and a <button> that acts without changing what either one is. Not for full-panel links, theme selectors, lightbox or gallery-overlay triggers, badges, or non-interactive labels — and not for inline text links, which surface-text-link.css owns. It also carries the attention edge adopted by class (.surface-attention-edge): a shaped interactive object that is not a compact action — an image card, a media launcher, an overlay control, a linked card in an SVG figure — takes the same hover and focus edge on its own anatomy, and nothing else of the compact action. Not a component, not a surface pattern, not an artifact scaffold |
surface-text-link.css | Opt-in live-surface visual rule — the shared visual contract for the unboxed textual traversal affordance (.surface-text-link): a link inside running prose or a structural title, which unlike a panel or a compact action has no geometry announcing that it is operable. It owns presentation only — no markup, no semantics, no destination, no layout, no template, no generated preview — and it deliberately declares no text color, so an ordinary link inherits its context's foreground and a role-colored anchor keeps its own. The resting underline is the emphasis accent at partial opacity — the accent's own hue at a reduced dose, never mixed toward the foreground; hover raises it to full opacity; focus is an independent high-contrast indicator. This is the default-ASK treatment and no strict AA non-text-contrast claim is made for its resting state in either theme — the module's own header carries the measured disposition. Opt-in by class on purpose: the excluded set — panels, actions, cards, gallery launches, marks, linked figures — is open-ended, and a missing class degrades to a visible foundation underline while a too-narrow deny-list would silently give a shaped object the textual grammar. Not a component, not a surface pattern, not an artifact scaffold |
surface-document.css | Opt-in visual rule for both lifecycles — the document register: document text roles on the foundation's own ladder (body on the Body step), the compositions that carry the space between them, the hierarchy rail, the passage rail of a quotation (violet) and a preformatted block (magenta) on the emphasis rail's geometry, the authorial callout composed with .surface-emphasis-rail (magenta), the section framing and the section synthesis composed as the same flat panel, quotation anatomy, preformatted and structured text with its declared peer groups, the entry title of an operable entry in a result list or record index, the document locator (inline code standing alone as a field value), the main + inspector composition of these parts, the action row an item of a repeated collection anchors at its end (.doc-actions--end), the table-of-contents entry (composed with surface-text-link.css, which a table of contents also loads), the dense table a consumer declares with table.doc-dense-table and the narrative table beside it, the document table composition a consumer adopts with table.doc-table directly inside a .doc-table-scroll box, and the overflow cue. It owns presentation only — no markup, no semantics, no template, no generated preview. A live surface references or vendors it and re-syncs; an artifact scaffold may inline it at generation time. Layers on top of colors_and_type.css. Not a component, not a surface pattern, not an artifact scaffold |
surface-document-overflow.js | Optional helper for surface-document.css: reports whether a preformatted block, or a document table's scroll box, is wider than its box, and on which side, so the stylesheet can draw the overflow cue. Without it a block or a table's box still scrolls and shows no cue |
surface-treatments.css | Opt-in visual rule for both lifecycles — separate surfaces composed from three independent axes (material, attachment, elevation), the separate-surface plane (.surface-separate), the disclosure (details.surface-disclosure, or, where the host keeps the region it controls, a controlled trigger: a native button carrying .surface-disclosure-trigger with aria-expanded and aria-controls, which takes the summary's grammar and none of the enclosure's geometry; its specimen sits beside the details specimens in surface-document.html), content emphasis (.surface-emphasis, .surface-emphasis-rail, .surface-emphasis-chip), the bordered label (.surface-bordered-label): one box and edge for every inert bordered label — a neutral label, the emphasis chip and Review Semantics' review mark — whose color only a governed meaning changes; the labeled range (.surface-labeled-range): a scope rail in the outer margin, outside the content edge, beside the exact run of blocks one label governs or one whole list item, neutral by default and colored only by a governed meaning, Review Semantics' annotation range; and the scope underline (.surface-scope-underline): one solid 2px line under the exact words one label governs, apart from a text link's line in weight, place and continuity, neutral by default and colored only by a governed meaning, Review Semantics' passage mark. It owns presentation only — no markup, no semantics, no template, no generated preview. It extends surface-panel.css and loads after it: the page material, panel material, free attachment and raised elevation are that file's own declarations, shared by selector grouping. A live surface references or vendors both and re-syncs; an artifact scaffold may inline both at generation time. Not a component, not a surface pattern, not an artifact scaffold |
surface-document.html | Rendered visual key for the document register and the surface treatments |
fonts/InterVariable.woff2 + italic | Inter variable webfont, OFL |
fonts/JetBrainsMono.woff2 + italic | JetBrains Mono variable webfont, OFL |
assets/logo-ASK.svg | Vector wordmark, primary — fill: currentColor; the consuming surface sets currentColor to the mode-specific wordmark pairing |
assets/logo-ASK-white.png | Raster wordmark in #FFFFFF, on transparent (light-mode pairing / fallback) |
assets/logo-ASK-lavender-ASK.png | Raster wordmark in lavender-ASK (#D4C6E1), on transparent (dark-mode pairing / fallback) |
favicon.svg · favicon-32.png · favicon.ico · apple-touch-icon.png | Browser-icon package — the wordmark on the baked #D4C6E1 square. Tier-3 implementation assets; see Logo placement |
og-image.png | The ASK social card, 1200 × 630 — a byte-identical copy of the A-S-K.studio card, which the ASK site owns. Served at the site root as the link-preview image the generated pages and the authored front doors declare. Not part of the browser-icon package |
tools/browser-icons.mjs | Generates favicon.ico; --check verifies the package against assets/logo-ASK.svg |
tools/check-custom-properties.mjs | Fails when a var(--name) with no fallback cannot resolve — each vendorable stylesheet against its declared dependencies, each page against its own load graph. --check, --self-test; --root, --page and --dep run it against another repository's pages. Static only: it does not prove scope and does not resolve values built at runtime |
tools/check-type-roles.mjs | Fails when typography in its governed set of stylesheets and pages leaves the role system: a font size or tracking value that is neither a token nor a registered literal, a heading set at the Caption size or in uppercase, a heading carrying a label or control class, uppercase mono on a selector that is not registered, or uppercase tracking off its register's token without a registered exception and its reason; and (R7) a document-register role that departs from its role matrix in any rule on its selector, reading text off the Body step, a heading declared smaller than body, any other rule on a quotation that sets a type metric, a passage rail not declared by exactly one rule or set there through a longhand, a rule naming a quotation or block inside :is(), :where(), :not() or :has() that draws or recolors a rail rather than removing it, a rail off .surface-emphasis-rail's geometry, an emphasis rail off its registered magenta accent, a block rail whose magenta differs from the emphasis rail's words, a quotation rail off the registered emphasis violet or a violet modifier that drifts from it, a rendered check that pins another quotation or callout color or stops admitting the three sanctioned accents on an emphasis rail off document text, a hierarchy rail that is not the registered 1px --line-2 rail or is set by a second rule, or a rendered-page role or link-state matrix in tools/role-conformance.js that differs from its source. --check, --self-test. Static only: it does not follow the cascade or inheritance, and reads no file outside the governed set |
tools/role-conformance.js · tools/check-role-conformance.mjs | The rendered half of the document-register check. role-conformance.js runs in a page and fails when a foundation token departs from colors_and_type.css where the check is scoped or wherever a governed role, rail, contents list or bordered label renders — the type steps, weights, leadings and tracking, the rail inset, both families and the three emphasis accents, and the theme roles --fg-1, --fg-3, --line-1 and --line-2, which must hold the owner's light or dark value (C0); an element carrying a role computes to anything but its matrix (C1); reading text leaves the Body step or a heading is smaller than body (C2); a quotation or preformatted block lacks its rail, leaves the shared geometry, takes any color but its role's or draws a second rail, an emphasis rail leaves the geometry, an emphasis rail on document text (an authorial callout) is not magenta, any other emphasis rail takes an accent outside the three sanctioned ones, or a hierarchy level is not the 1px --line-2 rail (C3); a contents link omits .surface-text-link or its resting underline, an anchor anywhere in a contents list omits .doc-toc-link, or a contents list holds body or lede text (C4); a cell or header of a table.doc-dense-table lacks its role or carries or contains body or lede text, or the dense role appears outside a marked table (C5); a retired class remains (C6); a link in document text, a label, a heading or a contents list omits .surface-text-link (C7); text inside a role changes its family, size or weight without a role of its own, or text nested inside a declared profile member leaves the member's metrics (C8); or a profile declaration is incomplete, miscounted, a list, names an element type rather than a class or id, or captures a governed role (C10); or a declared peer group in structured text is malformed, holds space inside it, or does not sit exactly one line from the next group, measured on its rendered lines (C11); a pass covers declared groups only, and the report counts structured blocks that declare none. Where the Review Semantics composition's classes appear, it also fails when a mark, passage mark, annotation note, item, row, list or range departs from that composition's syntax or drawn presentation (C12); an attribute alone opts nothing in. Wherever a bordered label appears — a neutral label, an emphasis chip or a review mark — it fails when its box and size, padding, border, corner, fill, edge reinforcement, inline margin or color departs from the shared bordered label (C13). Wherever a labeled range appears, a whole list item that is its own range included, it fails when its own box, scope rail, lane, label, host, clearance, buffer or color departs from the shared labeled range (C14). Wherever a scope underline appears, it fails when its line, its words or its neutral color departs from the shared scope underline, or when it sits on or inside a link or a control (C15). check-role-conformance.mjs --url URL runs it in headless Chrome (no npm dependency; Node 22+), opens every disclosure in scope, and then drives every governed text link and contents link with a real pointer and real Tab focus, failing when rest, hover, keyboard focus or the return to rest differs from surface-text-link.css, when a governed link carrying the class renders no box, or when a link a script added after the resting check lacks the class (C9). Last, it judges each element of the annotation composition, each bordered label, each labeled range and each scope underline that a closed disclosure kept from being seen on what it presents once open (C12; C13 for a label's box and edge; C14 for a range's scope rail and a neutral range's label; C15 for an underline's line and words; and C3 for a hierarchy rail). --profiles FILE.json supplies profile declarations — name, selector, owner, reason and expected count — which are validated before they exempt anything; --fixture URL runs a fixture page: tests/role-conformance-fixture.html, or tests/review-semantics-fixture.html for C12, and for C13, C14 and C15 where a review mark, an annotation range and a passage mark take the shared treatments. Every finding names a reason code. A page with no governed element is vacuous and fails, and so does a page that throws or fails to load |
tools/gen-peer-font.py | Owner-only generator of diagram-static-peer's two font carriers from fonts/InterVariable.woff2: the labels' measured centering with the key's advance widths, and the embedded Inter subset with its license. --check regenerates both in memory and fails on any difference. Needs fontTools and brotli, which nothing else here uses; a consumer vendors the carriers and never runs it |
preview/styleguide.html | Live token styleguide — the single canonical preview surface |
tools/read/ | The site build: at each deployment it serves the repository, with its three front doors composed, and adds reading pages under /read/, generated from the Markdown of the README, CONSUMERS.md, the semantic primitives, the patterns and the tests, on the document register by same-repo reference. The pages are build output and are never committed |
styleguide-theme-control.js | The style guide's forced-mode selector (auto / light / dark). Style-guide-only; not vendored, and not part of surface-shell. An inspection surface needs to hold a mode fixed; ordinary public surfaces follow the operating system and load nothing. |
SKILL.md | Agent-skill manifest for cross-tool reuse |
CONSUMERS.md | Known public downstream repos that consume these patterns/tokens — transparency record, not a customer list (private consumers tracked operator-side) |
patterns/surface-shell/ | Surface pattern — the shared page shell for a family of surfaces: identity-mark slot, surface identity, lede, optional status badge, optional control slot, and a flush-right footer of terminal compact actions. Header flush left, footer flush right; the shell owns the chrome, never the payload. It also ships an optional responsive-navigation runtime (surface-shell.js): where a surface authors a navigation source, the identity mark becomes the disclosure for a hierarchical panel — a drawer on desktop, a sheet on mobile — and a surface that declines it loads no script and acquires no navigation geometry. Tier-3-neutral, not ASK-neutral — it inherits Tier 1 + Tier 2 and ships the slot rather than a mark, so a consumer supplies only its own Tier 3 |
patterns/output-artifact/ | Class B project-output artifact scaffold — consumption pattern for review packets, reports, dashboards |
patterns/message-archive/ | Class B sealed interactive archive scaffold — one template, two-party/group modes, offline search and year navigation |
patterns/_diagram-shared/ | Canonical shared support for diagram engines — two members, each with its own target set: diagrams-text-layout.js, the text-layout contract consumed by diagram-static-H / -V / -SEQ, and diagrams-pointer.js, the pointer controller consumed by diagram-interactive-radial, diagram-interactive-spine and the static patterns diagram-static-H / -V / -SEQ / -FLOW. The text-layout member owns line breaking (delimiters longest-first, force-break, hard newline), measurement, role metrics — per-role cap, line height and the has-note predicate — and tspan emission; the consuming engines keep no private copy of any of them. A plane, not a mandate: the folder name confers no authority, each member declares its own target set, and diagram-static-FLOW, diagram-static-peer, diagram-interactive-spine and diagram-interactive-radial are explicitly excluded from the text-layout member, and diagram-static-peer from the pointer member too. Members are mirrored into the consuming bundles by tools/sync-diagram-shared.mjs; the mirrors are generated artifacts, never hand-edited, and --check exits non-zero on divergence |
patterns/diagram-static-H/ | Class A system / architecture diagram scaffold — horizontal left→right cascade; for architecture trees, topology maps, source-of-truth maps. Consumes the shared _diagram-shared/diagrams-text-layout.js contract, vendored as a generated byte-identical mirror; the engine keeps its own topology, placement, connector geometry and SVG envelope, because the three differ genuinely there |
patterns/diagram-static-V/ | Class A system / architecture diagram scaffold — vertical top→down centered spine; for inheritance chains and one-axis information-architecture diagrams. Consumes the shared _diagram-shared/diagrams-text-layout.js contract, vendored as a generated byte-identical mirror; the engine keeps its own topology, placement, connector geometry and SVG envelope, because the three differ genuinely there |
patterns/diagram-static-SEQ/ | Class A system / architecture diagram scaffold — ordered top→down sequence joined by arrows, left-aligned; for pipelines, workflows, lifecycles (succession, not hierarchy). Consumes the shared _diagram-shared/diagrams-text-layout.js contract, vendored as a generated byte-identical mirror; the engine keeps its own topology, placement, connector geometry and SVG envelope, because the three differ genuinely there |
patterns/diagram-static-FLOW/ | Class A system / architecture diagram scaffold — convergence flow: many normative sources converging into one resolved spec, realized, evaluated against an evaluation bus, governed, and fed back; for source-resolution / realization-governance topologies |
patterns/diagram-static-peer/ | Class A system / architecture diagram scaffold — peer relations: three or four equal nodes on a triangle or a square, joined by declared directed, neutral or unspecified relations, every pair declared once; for cycles and other relations among equals rather than a hierarchy. A relation grammar of its own, with a validating engine shared by the specimen page and an exporter that writes standalone SVG plates, art plate and keyed, in both themes, with the canonical tokens resolved and a licensed Inter subset embedded, and PNG plates through headless Chrome or Chromium. Its two font carriers are generated from fonts/InterVariable.woff2 |
patterns/diagram-interactive-spine/ | Class A interactive diagram scaffold — navigable, stateful IA state surface (hover/click/inspector; pan, pinch and wheel zoom through the shared pointer controller). Consumes the Spectral State primitive for node color; state-bearing (unlike the static scaffolds) |
patterns/diagram-interactive-radial/ | Surface pattern — a context-agnostic interactive radial map of a containment hierarchy for a live page: a recursive, validated data contract with tested limits (depth 6, 2,500 placed nodes), a radial layout grammar, screen-space names with level of detail, pan / pinch / wheel through the shared pointer controller, Fit through the shared Fit helper, selection, a keyboard path over the hierarchy, a chooser where marks overlap, deep-link arrival, and six optional modules: a legend; a responsive chrome that shows the caption and legend in their corners while they fit and otherwise folds them behind triggers in the shared disclosure grammar beside the HUD, measured rather than set by one width; an inspector that reports a node or an undrawn record in text from the adapter's sections; search, facets and the membership they set, in a drawer; a PNG page plate and diagram plate; and a theme control for the instance that owns the document theme. Consumes Spectral State for state color. A consumer vendors the owner files byte-identical (and the foundation files its modules take) and supplies its data, its adapter (its domain words, fields, facets, plate words, and any override of the owner's generic control and announcement defaults) and its page; it seals nothing. It has two public expressions, each with a gallery preview: a reference specimen, the public content of the Consciousness + Free Will research map captured on 2026-10-02, and a synthetic parks composition, which also serves development and tests. Each supplies its own data and adapter; both run the same owner modules |
| Document body |
| Inter |
| 200 |
| 24 / 1.45 |
| 0 |
| Quotation text | Inter | 200 | 24 / 1.45 | 0 |
| Entry title — the primary text of an operable entry | Inter | 300 | 24 / 1.45 | 0 |
| Preformatted text | JetBrains Mono | 300 | 18 / 1.45 | 0 |
| Table-of-contents entry | JetBrains Mono | 300 | 18 / 1.20 | -0.02em |
Dense table cell — table.doc-dense-table only | JetBrains Mono | 300 | 18 / 1.45, tabular numerals | 0 |
| Operative label | JetBrains Mono | 300 | 14 / 1.20, UPPERCASE | 0.08em |
| Metadata · quotation attribution | JetBrains Mono | 300 | 14 / 1.40 | 0.08em |
tests/role-conformance-fixture.htmltests/review-semantics-fixture.htmltools/role-conformance.jsshadow-md| the magenta text decoration rises from partial to full opacity; element opacity held at 1 so the 0.92 drop reads as press |
disclosure triggers (details.surface-disclosure > summary, .surface-disclosure-trigger) | foreground-only — on a closed disclosure the trigger and its indicator rise from --fg-2 to --fg-1; an open disclosure's trigger already rests at --fg-1, so hover changes nothing; no border, no opacity drop, no press |
the identity mark (a.surface-mark) | declared opacity only; nothing else changes |
| shell footer destinations | none of their own — they are compact actions and take the compact-action row |
Two border treatments, split by role. A generic anchor's hover belongs to running text, so its text-edge border stays with its own inherited color. A compact action and a full-panel link are shaped objects a reader targets; in their hover, magenta carries attention, and each keeps its own anatomy — the complete pill border, or the complete panel border with its ring composed on the resting shadow. The magenta lasts only while the object is hovered or focused. It is never a selected, current, filtered, error or other persistent state; the same palette value carries persistent, context-governed meanings elsewhere, and a persistent semantic border — a diagram mark's state, a status encoding — keeps its own paint and does not acquire this treatment; a linked card in a figure takes the edge only while its link is hovered or focused. A persistent emphasis carried by a compact action, a full-panel link or an adopting object is overwritten while the object is hovered or focused, and needs its own consumer composition; surface-treatments.css's content emphasis is not composed onto either.
The reason is scale. A --line-2 rest border is the faintest line the system has, so brightening it to --line-1 reads as almost no response on the light gradient. The magenta border gives a shaped object one attention response in both themes. No non-text contrast claim is made for the edge.
Hover and focus share this paint and nothing else. They remain independent states answering different questions, so a shaped object that is hovered and focused shows one edge rather than two competing indicators, and the 0.92 opacity drop stays hover's alone. Two objects, one hovered and one focused, show the same edge; only hover's opacity drop tells them apart. An adopting object takes no drop from this rule, so its own hover, where it has one, is what tells its states apart.
The list is closed. Compact actions, full-panel links and objects that adopt the edge share the attention treatment — one contract: compact actions and adopting objects share one set of declarations in surface-action.css, and the full-panel link keeps its own in surface-panel.css, composed with its resting shadow — and generic anchors alone keep the foreground-bound one; a future bordered control inherits neither by being interactive, and joins only by being named here or by adopting .surface-attention-edge. The class is opt-in and never inferred. It gives the edge alone, so an adopting object without a hover behavior of its own looks the same hovered as focused. It removes the browser's focus ring, so an object adopts it only with an anatomy that paints: its own border, the borderless ring, or a marked shape. The borderless ring paints beneath the object's content, so it suits a control whose content stays clear of its edge. A consumer rule that sets the object's border color, or its marked shape's stroke, on hover or focus, later in source or at a higher specificity, overrides the edge and is retired on adoption. --surface-attention-edge-scale is a geometric input, not a token: the effective uniform scale from the marked shape's own units to CSS pixels on the page, a plain positive number, 1 where nothing declares it, supplied by whatever scales the figure. Only the SVG attention stroke reads it. An adopting object with a resting or hover shadow restates it with the ring in its own rules, as the full-panel link composes with its own. The edge reaches only the page's own document: a control inside an embedded document from another origin, such as a video player's own buttons, keeps that document's focus indicator. Inert panels do not hover. A disclosure trigger joins neither shared treatment; its rows in the hover and focus tables are its own.
Press // transform: scale(0.97), 120ms ease-out. No darker fill. Exception: inline text that wraps. A scale press needs a transformable box, and giving one to a wrapping link changes how its text breaks — a segment wider than its column stops fragmenting and swells to the full column. The fragmenting population is exactly .surface-text-link and breadcrumb links (.surface-title a); they press without geometry, hover raising the underline to full opacity and holding element opacity at 1, so on them the 0.92 drop reads as press rather than as hover. The identity mark is a box and keeps the scale; so do footer destinations, through surface-action.css rather than through a rule of the shell's. patterns/surface-shell/README.md carries the state model. Reduced motion. Under prefers-reduced-motion: reduce, compact actions and full-panel links drop their transitions and their press scale; their hover and focus paint still applies, instantly. The shell's own reduced-motion rules stay the shell's.
Focus // never the browser default. Across the live-surface modules and the shell there are four anatomies by role, which are not interchangeable; artifact patterns such as message-archive own pattern-local indicators:
| role | focus indicator |
|---|---|
compact actions (.surface-action), full-panel links (a.surface-panel) and objects that adopt the edge (.surface-attention-edge) | the same attention edge as hover — magenta border, apparent 1.5px light / 1px dark, composed with the module's resting shadow (--shadow-md on a full-panel link; a compact action has none; an adopting object with a shadow of its own restates it). An adopting object takes the edge on its own anatomy, as in the hover table. No glow. No non-text contrast claim is made for this edge |
the identity mark (.surface-mark — the anchor, or the runtime <button> trigger) and the shell's navigation rows (a.surface-nav-row) | the 0 0 0 1px white, 0 0 0 4px rgba(white, 0.25) glow |
unboxed textual links (.surface-text-link) and breadcrumb links (.surface-title a) | a fragment-native indicator — their own decoration recolored to --fg-1 at 2px thickness and 2px offset, so one underline renders in every state |
disclosure triggers (details.surface-disclosure > summary, .surface-disclosure-trigger) | a --fg-1 outline around the trigger, 2px wide and --space-1 out, with the trigger at --fg-1 and its indicator turned --ask-emphasis-magenta; the outline shows in every case: open or closed, and when the trigger leads with a mark; no edge, no glow |
Why a shaped object shares hover's edge. Hover and focus are independent states — focus persists when the pointer leaves, hover goes with it — but nothing in this contract requires a shaped control's focus to look different from its hover — unlike the textual links below, where focus is a separate safety channel — and giving a shaped control two competing indicators means deciding which one wins every time both are live. Sharing the paint removes that question without merging the states: the 0.92 opacity drop still belongs to hover alone, and the edge composes with resting elevation rather than replacing it, so a focused panel does not lose its shadow. The composition is with the module's own resting shadow: a consumer that sets a different one restates it in its own hover and focus rules.
Why wrapping text cannot take either. Anything drawn around the box fails on fragmented inline text — sliced it opens at the cuts, cloned it becomes one ring per line rather than a single typographic indicator, and a rectangular outline is one shape only where the fragments happen to overlap horizontally. The identity mark has no border to recolor, so it keeps the glow. Footer destinations are compact actions and take the shaped-control edge through surface-action.css's shared hover and focus rule; so does the navigation panel's close control, whose edge the shell suppresses after a pointer-opened entry exactly as it suppresses a row's glow. patterns/surface-shell/README.md records the measurements.
.doc-section-titlereview-semantics.* | new | the Review State profile and the document annotation composition, a source of the register's review, evidence and state marks. The marks' words take .doc-label, and the rendered key is drawn on the document register |
patterns/surface-shell/ | specialized | its navigation panel keeps its own material for navigation composed over another surface: the --surface-glass-2 fill with a 14px blur. It realizes the attachment corner rule pattern-locally — the desktop drawer rounds its bottom corners, and the mobile sheet its top corners. It also drops the border on its joined edge. It does not consume the attachment classes |
patterns/_diagram-shared/ | conforming | the one canonical text-layout source for the H, V and SEQ static diagram engines, and the pointer controller of the radial and spine patterns, which carries no type. tools/sync-diagram-shared.mjs generates its mirrors, and --check verifies them. The caps and line heights it owns serve those diagrams' own register; fonts and letter-spacing stay with each engine's stylesheet |
patterns/diagram-static-H/ · patterns/diagram-static-V/ · patterns/diagram-static-SEQ/ · patterns/diagram-static-FLOW/ | specialized | a compact register of their own in diagrams.css: 9–15px text, tracking from -0.01em to 0.18em, and a 10px caption overlay at 0.06em that is not the Caption role. The four diagrams.css copies are byte-identical and shared by convention; no tool keeps them in step |
patterns/diagram-static-peer/ | specialized | its plate is drawn in units of its own: the letters at 150 of a 1000-unit plate in --fw-extralight, the key's words at 34 in --fw-regular, both in the foundation family and ink, and connector geometry its engine owns. Its specimen's text takes the document register, and the rendered check passes on its generated preview; its two mode selectors are pattern-local, in the style guide's selector grammar: they repeat the .surface-theme rules, adding one for reduced motion, and no tool keeps the two in step. It stands outside tools/check-type-roles.mjs by declared disposition, as the other diagram patterns do |
patterns/diagram-interactive-spine/ | specialized | a compact register for its top bar, nodes, inspector, legend and controls: 8.5–15px text, and glass panels with a 14px radius and a --surface-glass-2 edge. Its caption band keeps --tracking-wide (0.08em) rather than Caption's tracking, and its mono uppercase labels (node groups, inspector and legend headings, field labels) keep 0.14–0.16em |
patterns/diagram-interactive-radial/ | specialized | a compact register for its bar, its screen-space names, HUD, legend, caption, chooser, inspector and facets drawer: 8–23px text (the root's name 23px, depth-1 names 16px, deeper names 13px, leaf names 11px at 200, count lines 9px and identifiers 8px in mono at 0.1em), and glass panels with the 14px radius and a --surface-glass-2 edge. Its caption band keeps --tracking-wide (0.08em), and its mono uppercase labels (the legend and chooser headings at 0.16em, the tier readout at 0.1em, the chooser's zoom action at 0.08em) are pattern-local. It stands outside tools/check-type-roles.mjs by declared disposition, as the other diagram patterns do |
patterns/message-archive/ | specialized | its participant-identity ramp, its focus outlines and its chrome metrics are pattern-local. Its sticky control bar blurs at 20px, the shared material value; its day-heading chips keep 8px |
patterns/output-artifact/ | conforming | the Class B document scaffold on the document register. Its title, lede, section titles, body and list text, labels, metadata, code, quotation, preformatted block, dense and narrative tables and disclosure take the register's roles and treatments, loaded as the four modules in the sealed-use order below; its tables adopt the document table composition; and the rendered check passes on its generated preview. Its own CSS sets no type metric, no text foreground and no screen geometry on an adopted table. One named print adaptation of its own relaxes, in print only, the composition rules that rely on scrolling, so that an adopted table can fit the printed column; it writes every other geometry rule on an element the register may also style at zero specificity. It draws only the geometry the register leaves to a consumer — the column, the metadata strip's and provenance footer's layout, list geometry, the geometry of a table that does not adopt the composition, and rules — in the Class B line-intensity token --artifact-line, stronger than the foundation hairline in light. That token never reaches a table the composition draws, a text foreground, a passage rail or the disclosure's panel; it lies outside the type roles, compositions and treatments a disposition measures, and it is no variant for another surface. tools/check-type-roles.mjs governs its template's typography declarations |
patterns/_preview/ | generated | tools/gen-pattern-previews.mjs writes it from the canonical templates, and --check verifies it |
read/ (the built site only) | generated | tools/read/read_gen.py writes the reading pages from the repository's Markdown at deployment. They load the owner's own stylesheets and scripts by same-repo reference, and are never committed |
index.html · patterns/index.html · preview/styleguide.html | conforming | tools/check-type-roles.mjs governs all three. The tracking account above records the gallery's and the style guide's page-local Inter labels, and the style guide's registered .badge exception |
one .doc-pre-group per peer group in a .doc-pre--structured block, declared by the surface from its own source |
| a quotation set larger or smaller than its prose | .doc-quote — body-sized; .doc-quote--display is retired |
| a set-apart passage on a faint neutral rail | its role's accent: .doc-quote violet for represented voice; .surface-emphasis-rail magenta for the document's own callout |
| a section synthesis on a rail, or in supporting-copy size inside a card | the flat synthesis panel with a magenta-bordered chip and .doc-body text |
| a part's opening thesis or question, set as a callout or as a synthesis | the section framing: the same flat panel and chip, after the part's introduction, its chip naming the framing |
| a bare anchor in a table of contents | .doc-toc-link.surface-text-link inside .doc-toc-list |
| a result's or record index entry's primary text set as body prose or as a panel label | .doc-entry-title — its identifier and supporting fields take .doc-meta; the entry's element, interaction and row geometry stay the consumer's |
| a detail panel beside a record list, with smaller type of its own | main + inspector: the same roles in both regions, the inspector's prose on .doc-body, and the inspector a separate flat surface on the three axes; the regions, selection and the route back stay the consumer's |
| a source address, DOI or path set as a field value in a hand-made mono style | code.doc-code standing alone as the value of a .doc-labeled field — the document locator; a followed address is a .surface-text-link inside it, an identifier stays .doc-meta, and a URL in running prose stays a body link |
| action rows lined up across a grid's items by fixed heights, spacers or per-item offsets | .doc-actions--end on each item's .doc-actions, in items that stretch to their grid row; the grid and the items' heights stay the consumer's |
| a dense technical table set as body prose | table.doc-dense-table, with .doc-table-cell for values and .doc-label for headers; a narrative table is not dense and stays unmarked |
| a prose table at raw sizes | a narrative table: .doc-label headers and .doc-body cells, unmarked |
| a table's hand-set rules, padding and sideways scroll | the document table composition, adopted by class: table.doc-table directly inside a .doc-table-scroll box, .doc-table-num on a numeric column; a surface that must not scroll a table sideways keeps its own geometry |
| a disclosure summary used as a label | details.surface-disclosure > summary |
| control sizes inside an interactive application, and glyph sizes set in em | not text roles |
CONSUMERS.md