This document records the visual system actually in use on the GTMC website. It is descriptive, not prescriptive: when reality and this doc disagree, the code wins. Source-of-truth examples live in app/globals.css, components/ui/*, components/layout/*, and the homepage and article-reader compositions.
The site uses a "Print Edition" aesthetic: an academic monograph series (think Springer Graduate Texts in Mathematics) re-set for the web, layered over the original technical-drafting bones.
The conceit: GTMC is a textbook series, so the site looks like one. Archival paper, navy-black ink, a single unmistakable blueprint-azure signal band, serif display titles, and mono "apparatus" text (folios, running heads, colophons) where a book would have typographic furniture. The signal is cold on purpose: a printed monograph annotated in technical blue, so the original drafting-table bones read through the paper rather than being painted over.
- Warm paper surfaces (
tech-bgis cream, not blue-white) with flat, near-square geometry. No rounded corners. - Serif display type (
display-title/ STIX Two Text + Noto Serif SC) for page titles, section titles, and article headings. Ink-dark, tight tracking, sentence case — never uppercase serif. - Monospace remains the "apparatus" voice: nav links, labels, status readouts, folios, build stamps. Uppercase + wide tracking belongs to mono only.
tech-signal(blueprint azure / cyanotype blue) is the one loud color. Used in hairline accents (the 3px nav band, header rules, active-state underlines, the logo mark) — never as a large fill except the hero book band. It is a cold signal: a sun-printed blue mark layered over the warm page, not a glow.- Drafting motifs survive in supporting roles: dimension marks, guide lines, corner brackets on technical panels, dot-grid backdrop.
- Motion still reads like instrumentation: fade, clip-path slide, pop-in, sweep, scan confirm.
Avoid generic SaaS gradients, pill cards, emoji-as-icons, heavy drop shadows,
purple-on-white "AI default" palettes, and ad-hoc hex colors when a tech-*
token will do. Avoid uppercase serif and letter-spaced serif: the serif voice
is calm; the mono voice is technical.
The visual system serves a reading experience. These principles govern how users move through the site and how affordances are surfaced.
GTMC is a community textbook. Every surface should reinforce the book metaphor, not fight it.
- The homepage is the book opening. A cover (hero) scrolls into a real printed Table of Contents built from the live article tree — chapter numbers, dotted leaders, section counts, appendix separator. The TOC is the primary navigation, not a secondary index page.
- Reading progress is a bookmark, not a progress bar. Articles record a localStorage bookmark (slug, title, scroll position). The homepage shows a bookmark ribbon — title, blueprint-azure progress bar, one-click return — like a physical bookmark tucked into the book.
- The reader has a running head. Articles inside a chapter show a
blueprint-azure
CH 01chip and linked chapter title above the article metadata, so a reader arriving from search always knows where they are in the book. - Glossary is the index. The command palette (
⌘K) returns anINDEX — GLOSSARYsection alongside article results. Cross-linking between articles and glossary terms is a first-class concern.
The site has three audiences: readers, contributors, and admins. The nav must not lie about what's available.
- Anonymous visitors see reader-only nav: Articles, Glossary, Feedback. No dead-end links to pages that require login.
- MY DRAFTS appears only for authenticated users — after Glossary, before Feedback. It's a contributor affordance, not a reader one.
- REVIEW HUB appears only for admins, injected by
AuthAwareNavafter a session check. - FEEDBACK (formerly FEATURES) describes what the page actually is: bug reports and feature requests. The old label "FEATURES" implied a feature list, not an issue tracker.
Labels on reading surfaces use textbook vocabulary, not drafting jargon.
- Chapter tree panel: Table of Contents (not
SYS.DIR_TREE). - Search modal header: Search the Text (not
SYS.QUERY_ENGINE). - Outline rail: On This Page (not
Paragraph Outline). - All reader-surface labels are localized — no hardcoded English on Chinese pages, no hardcoded Chinese on English pages.
The footer is organized by audience intent: READ (Preface, Articles, Glossary), COMMUNITY (Contribute, Team, Issues), SOURCE (Errata & Feedback, Repository, License), DOWNLOAD (Offline PDF). Section headers are localized.
Tokens and global styles
app/globals.css— theme (@theme), animations, body backdrop, utility classes.app/[locale]/layout.tsx— root locale shell, font injection, footer wrapper.
Layout and navigation
components/layout/site-shell.tsx,desktop-nav.tsx,mobile-nav.tsx,auth-aware-nav.tsx,auth-island.tsx,language-switcher.tsx,footer.tsx,footer-wrapper.tsx,footer-context.tsx.
Core primitives
components/ui/tech-card.tsx,tech-button.tsx,input-box.tsx,textarea-box.tsx,corner-brackets.tsx,selectable-card.tsx,segmented-control.tsx.
Headings, status, metadata
components/ui/page-header.tsx,section-title.tsx,status-badge.tsx,status-dot.tsx,tag-list.tsx,metadata-row.tsx,empty-state.tsx,loading-indicator.tsx.
Loading and progress
components/ui/loading-shell-primitives.tsx,operation-progress.tsx.
Editor and review subsystems
components/editor/editor-surface.tsx,editor-toolbar-shell.tsx,editor-tab-strip.tsx,editor-textarea.tsx,editor-preview-frame.tsx.components/review/review-editor.tsx,conflict-block.tsx,rebase-progress.tsx.
Article reader
app/[locale]/(public)/articles/articles-layout-client.tsx,chapter-nav-panel.tsx,chapter-nav/tree.tsx,mobile-chapter-nav-card.tsx.components/articles/article-metadata-layout.tsx,article-metadata-full.tsx,article-navigation.tsx,outline-rail.tsx,mobile-outline-bar.tsx.lib/markdown/components/*— custom markdown rendering (noproseplugin).
Homepage
app/[locale]/_homepage/use-homepage-motion.ts,background-layer.tsx,midground-layer.tsx,foreground-layer.tsx,hero-card.tsx,decor-element.tsx.
The Tailwind v4 theme is defined in app/globals.css (@theme). There is no tailwind.config.*. Use these tokens; avoid raw hex values.
| Token | Hex | Role |
|---|---|---|
tech-bg |
#f5f4ef |
Warm archival-paper page background |
tech-main |
#4a5468 |
Ink-gray for body text, borders, controls, labels |
tech-main-dark |
#20283c |
Navy-black ink: headings and high-emphasis text |
tech-accent |
#c9cfdd |
Hover fills, subtle highlights, selected states |
tech-line |
#d6d3c8 |
Border-only token: dot grid and quiet dividers |
tech-signal |
#1d6a96 |
Blueprint azure: hairline accents, active states, the mark |
tech-signal-ink |
#f5f4ef |
Text color guaranteed legible on a tech-signal fill |
Usage rules
- Default text:
text-tech-main. High-emphasis titles:text-tech-main-dark. - Common borders:
border-tech-main/40. Quiet guide lines:guide-lineorborder-tech-main/20. Strong structural rules (page header, footer top, nav band) useborder-tech-main-darkwith a shortbg-tech-signaltick overlapping them. - Surfaces:
bg-surface/70–/95plusbackdrop-blur-sm(orbackdrop-blur-mdon hero/modal panels). Pale fills usebg-tech-bg/50–/80. Never rawbg-white. tech-signalbudget: at most one band + a few hairline ticks per screen. It marks "you are here" (active nav, current chapter, focus rules) and brand moments (logo mark, hero band). It is never body text on light backgrounds and never a large fill outside the hero. As a cold signal it reads as a blueprint annotation, not a highlighter — keep it sparing so the warm page stays dominant.- Filled controls invert to ink:
bg-tech-main-dark text-tech-bg(e.g. primary buttons, active language tab). Primary button hover flips tobg-tech-signal text-tech-signal-ink. - Hover/selection stay muted:
bg-tech-accent/10,bg-tech-main/5–/10,hover:border-tech-main/60. - Semantic colors are translucent and bracketed: yellow/blue/green/red at
/10fills with/40borders. Neutral states (loading, secondary metadata) may use gray/slate/zinc at low opacity. tech-lineis for borders only; it has no fill or text utility in practice.
Map every background, border, and text color to a semantic Tailwind token so both themes resolve through CSS variables.
| Tailwind class | Light | Dark |
|---|---|---|
bg-tech-bg |
#f5f4ef | #101826 |
bg-surface |
#fcfbf8 | #162031 |
bg-surface-overlay |
#fcfbf8 | #1a2536 |
bg-surface-input |
#fffefb | #0c121d |
bg-surface-modal |
#fcfbf8 | #18222f |
text-tech-main |
#4a5468 | #9aa7bd |
text-tech-main-dark |
#20283c | #e7ecf4 |
border-tech-line |
#d6d3c8 | #243248 |
text-tech-advanced |
#8c2f39 | #c25664 |
bg-tech-accent |
#c9cfdd | #2a3852 |
bg-tech-signal |
#1d6a96 | #5fb0d4 |
text-tech-signal-ink |
#f5f4ef | #0e1521 |
Dark mode is "Blueprint": the book re-set as a drafting print — a cool blue-slate ground, cool slate ink, and a luminous cyan signal that glows against the dark. Where the light theme is warm paper annotated in blueprint blue, the dark theme is the blueprint itself: the cold drafting-table bones brought fully forward. Surfaces stay near-neutral blue-slate, never saturated navy, so long-form reading stays comfortable.
- Use
dark:Tailwind variant, scoped via[data-theme="dark"]. - Never use
@media (prefers-color-scheme: dark)in application code — the runtimedata-themeattribute is the single source of truth. - Replace hardcoded
bg-whitewithbg-surfaceorbg-surface-overlay. - Replace
text-slate-700withtext-tech-main,text-slate-800/900withtext-tech-main-dark.
Schematic viewer passes theme-aware background color to Three.js renderer.setClearColor(). Light: #f5f4ef, dark: #101826.
Icons use currentColor or text-tech-main. When contained in a dark: block that changes text color, icons follow automatically.
color-scheme: light is set on :root; color-scheme: dark is set on [data-theme="dark"]. This controls native browser elements (scrollbars, form controls, system dialogs).
Fonts are declared in app/globals.css and loaded via app/[locale]/layout.tsx.
Families
- Sans (body):
var(--font-geist-sans),Noto Sans SC,PingFang SC,Microsoft YaHei,sans-serif. - Serif (display):
var(--font-stix-two-text),Noto Serif SC,Songti SC,Georgia,serif— exposed as--font-serifand thedisplay-titleutility. - Mono (apparatus):
var(--font-geist-mono),SF Mono,Consolas,Noto Sans Mono SC,monospace.
Three voices
- Serif speaks as the book: page titles, section titles, article headings, the logo wordmark, the hero.
display-title= serif, semibold,-0.015emtracking, sentence case. - Sans speaks as the text block: body copy, descriptions, UI prose.
- Mono speaks as the apparatus: nav, labels, badges, folios, status strips. Mono owns uppercase and wide tracking.
Scale
- Root font size scales by viewport:
16pxon small screens, stepping up to18pxon large screens via media queries inhtml. - Page titles:
display-title text-3xl md:text-5xl tracking-tight text-tech-main-dark, with a mono kicker label above (text-[0.625rem] tracking-[0.25em] uppercase text-tech-main/60). - Section titles:
display-title text-xl md:text-2xlwith a leadingsize-2 bg-tech-signalsquare and a bottom guide line (seeSectionTitle). - HUD and metadata labels:
font-mono text-xs tracking-widest uppercase text-tech-main/50. - Body copy:
text-sm/relaxedtotext-base/relaxed. - Article paragraphs:
font-sans text-base/relaxed text-tech-main-dark. - Article headings (H1–H3):
markdown-title, regular capitalization, semibold.--font-markdown-titleresolves to the serif stack; H1 carries a heavy ink bottom rule, H3 atech-signalleft rule.
Tracking
- House default:
tracking-widest(broadly used on labels, badges, nav). - Custom step:
tracking-tech-wide(0.2em) for slightly tighter HUD text.
Mobile-first, modest spacing, predictable container rhythm.
- Page container:
page-container=mx-auto max-w-6xl space-y-8. The-pbvariant addspb-12. - Site chrome max-width inside the nav strip:
max-w-450(a custom Tailwind v4 spacing alias). - Common gutters:
p-4 sm:p-6,px-4 sm:px-6 lg:px-8. Editor and reader pages may go wider (max-w-[1400px],lg:px-24). - Common grids:
grid grid-cols-1 gap-6 md:grid-cols-2 lg:grid-cols-3. - Page headers commonly stack on mobile and align on desktop:
flex flex-col gap-* md:flex-row md:items-end. - Touch targets meet
touch-target(≥44px) on buttons and primary controls.
12-column grid (asymmetric layouts)
Use this grid only when the page has asymmetric column allocations (sidebars, rails). Single-column pages use page-container instead.
- Container:
flex flex-col md:grid md:grid-cols-12 md:gap-6 md:max-w-360 md:mx-auto. Mobile stacks vertically; grid activates atmd(≥768px). - Column allocation (default 3 | 7 | 2 split):
- Left sidebar / nav:
md:col-span-3 - Main content:
md:col-span-7, further capped atmax-w-3xl - Right rail (TOC, related):
md:col-span-2
- Left sidebar / nav:
- Variant: the footer uses a 4 | 8 split (
md:col-span-4/md:col-span-8) withmd:gap-10instead ofmd:gap-6. - Current usages: article reader (
articles-layout-client.tsx) and footer (footer.tsx).
Path: components/layout/{site-shell,desktop-nav,mobile-nav,auth-aware-nav,auth-island,language-switcher}.tsx.
Site shell
SiteShellis the canonical frame: a sticky translucent top nav (sticky top-0 z-50 border-b bg-white/60 backdrop-blur-sm) over a full-widthmain.- The footer is global but suppressed on
/and on routes that callHideFooter().
Desktop
- Hidden below
md. Links are mono uppercase:font-mono text-xs tracking-[0.15em] border-b-2 pb-1. - Active:
border-tech-signal text-tech-main. Inactive: transparent border +text-tech-main-dark, hover swaps both totech-main. - Base nav is reader-only: Articles, Glossary, Feedback. MY DRAFTS is
injected by
AuthAwareNavfor authenticated users (after Glossary). REVIEW HUB is injected for admins (before Feedback).
Mobile
- Hamburger button uses three
h-0.5 w-5 bg-tech-mainbars with animated transform states; touch targetmin-h-11 min-w-11. - Drawer is portal-mounted under the top nav:
border-b border-tech-main/40 bg-white/95 backdrop-blur-md,duration-300max-height transition. - Drawer links are square bordered blocks with mono tracking and a hover fill.
Auth island and language switcher
- Unauthenticated users see a square
INlogin button. Authenticated users see an avatar with a hover dropdown to profile and sign-out. - Language switcher is a 2-button segmented control (
Eng/中文), square, monospace, locale-aware article-slug fallback.
There is no single universal card. Several surface systems coexist; each is internally consistent.
TechCard (components/ui/tech-card.tsx)
- The default framed panel for feature, draft, review, and dashboard surfaces.
- Real props include:
tone,borderOpacity,background,padding,hover,brackets,bracketVariant,pattern(gridonly —dotsis defined but unused). - Conventions: thin
border-tech-main/40borders, near-square geometry, optionalCornerBrackets, hover changes border/fill opacity rather than adding elevation.
Editor surfaces (components/editor/editor-surface.tsx)
- A separate frame system used by the draft editor.
- Two visible variants:
default(white/80 panel) andgrid(grid-paper texture with inset shadow and corner ticks). - Pairs with
EditorToolbarShell,EditorTabStrip,EditorTextarea(CodeMirror), andEditorPreviewFrame.
Article reader shell
- A bordered translucent sheet around the entire reader:
border border-tech-main/40 bg-transparent p-6 sm:p-8with corner brackets. This is its own surface, not aTechCard.
Profile and admin panels
- Custom panels with
border-tech-main/40 bg-white/60 backdrop-blur-mdand corner ticks. Used in profile and admin whereTechCard’s API is too tight.
Selectable cards and segmented controls
SelectableCardandSegmentedControlprovide consistent radio-group / tab-group behavior with the same square, bordered, mono-label language.
Geometry guidance
- Default to square (
rounded-none). Small radii are acceptable on dense indicators and skeletons (rounded-sm,rounded-xs,rounded-[2px]) and on circular dots (rounded-full). Reach for radii consciously, not by default.
TechButton is the primary control.
- Square geometry, border, bold mono uppercase text, wide tracking,
duration-300transitions. - Variants:
primary,secondary,danger,ghost. Sizes:sm,md,lg(md/lg meet touch minimums). - Non-ghost buttons include a small accent corner mark.
- Two hover rhythms exist on the site:
- Color/fill change (default):
hover:bg-tech-main hover:text-white transition-colors. - Scale transform (heroes, error pages, key CTAs):
hover:scale-[1.02] active:scale-95 transition-transform duration-300.
- Color/fill change (default):
- Avoid pill or fully-rounded CTAs unless a future design decision changes the system.
InputBox and TextAreaBox are the canonical fields.
- Base:
border border-tech-main/30 bg-white/50 font-mono text-tech-main-dark, square geometry, comfortable padding (px-3 py-2.5 sm:px-4 sm:py-3), min height44px. - Focus is a deliberate border-color change (
focus:border-tech-main) — fields do not use ring/outline. - Error: red border and helper text, same square geometry.
- Provide visible labels and helper text near fields; placeholder-only labeling is not enough.
- Composition: form labels often live in a
FormFieldwith a left border accent and mono uppercase label.
Bracketed and translucent. Examples: [Pending], [Resolved], [Closed].
- Base:
border px-2 py-0.5 font-mono text-xs tracking-wider. - Pending: yellow border/text on yellow
/10fill. - In progress / review: blue border/text on blue
/10fill. - Resolved / success: green border/text on green
/10fill. - Rejected / closed / destructive: red border/text on red
/10fill. - Neutral / loading: gray or slate at low opacity.
- Tags use
guide-line,bg-tech-main/5, mono uppercase text, square borders. - Pulsing status dots:
size-1.5 animate-pulse rounded-full bg-tech-mainfor live indicators; reserve for state that actually updates.
Decoration should read as drafting overlay or instrumentation, not ornament.
Cross-verified motifs
CornerBrackets(components/ui/corner-brackets.tsx) atsize-2–size-3. Common variants: static frame, hover reveal, hover-only onTechCard, hover-expand onTechCard, diagonal pairs, top-bottom pairs.- Thin guide lines:
guide-line,border-tech-main/20,section-divider. - Small square markers:
size-3 border border-tech-main/40 bg-tech-main/20. - Dot-grid backdrop on the body via a radial gradient using
tech-line(mobile fixes grid size to40px 40px). - Grid-paper texture on
EditorSurface variant="grid"andTechCard pattern="grid". - Watermark + HUD label families on full-screen routes (auth, errors, homepage layers). Use them as a family, not as literal strings.
- Code/HUD readouts, hex dumps, isometric or radar diagrams, dimension marks (
|< ---- 640px ---- >|).
Use decor-desktop-only to hide complex decoration on small screens.
Avoid
- One-off vignettes or radial glows unless they belong to a recurring surface system.
- Heavy drop shadows, conic gradients, or dense decorative SVG that does not appear elsewhere.
- Ornamental hover effects on elements that are not interactive.
Motion lives in two distinct places.
CSS animation tokens (defined in app/globals.css, used across the site)
| Class | Use |
|---|---|
animate-fade-in |
Simple appearance |
animate-slide-up-fade |
Section/CTA entrance |
animate-tech-pop-in |
Primary panel entrance with scale + blur |
animate-tech-slide-in |
Heading or line reveal with clip-path |
animate-tree-drop-in |
Tree/sidebar/outline reveal |
animate-blueprint-sweep / shimmer |
Scan/sweep highlight on loading or CTAs |
animate-target-blink |
Anchor-target confirmation |
animate-scan-confirm |
Loading → content handoff |
animate-skeleton-exit |
Skeleton → content fade with translate |
Homepage parallax (app/[locale]/_homepage/*)
- The only place that imports
motion/react. Drives a single bespoke parallax/tilt/blur system built onuseMotionValue,useSpring, anduseTransform. - Spring physics only (
damping,stiffness); no shared duration/easing tokens. - Honors reduced motion and mobile gating inside
use-homepage-motion.ts.
Rules
- Prefer
transform,opacity, andclip-path; avoid layout-shifting animation. - Stagger entrances with
[animation-delay:*]for hero and lists. - Decorative motion must be optional: pair
animate-*withmotion-reduce:animate-none(ormotion-reduce:animate-fade-out) wherever the animation is nontrivial. The loading and skeleton primitives incomponents/ui/loading-shell-primitives.tsxare the working reference. - Pulsing dots are reserved for live or status indicators.
- Body background is a radial dot grid using
tech-line, with responsive grid sizing. - Panels use
bg-white/60–/95plusbackdrop-blur-smorbackdrop-blur-md. - Mobile drawers and full-screen overlays use a translucent dark scrim:
bg-tech-main-dark/20 backdrop-blur-xs(or similar). - Empty states may layer dashed borders over a low-opacity diagonal stripe background.
- Localized scanline / striped overlays exist (empty states, chapter nav panel, draft editor backdrop). Implementation is intentionally ad hoc; treat them as a vocabulary, not a single utility.
The reader is its own layout, separate from the rest of the site chrome.
- Outer frame: bordered translucent sheet with corner brackets, large gutters.
- Desktop layout (3 columns):
- Left chapter nav (
w-64 lg:w-80), sticky, internally scrollable. - Center column:
md:max-w-2xl(ormd:max-w-3xlwhen nav hidden),1920:max-w-4xlon very wide screens. - Right outline rail: hidden until
sm,sticky,w-16expanding tow-52on hover.
- Left chapter nav (
- Mobile layout: chapter nav becomes a top toggle + collapsible sheet, the outline rail becomes a bottom progress bar (
MobileOutlineBar). - Markdown is rendered with custom components in
lib/markdown/components/*. The Tailwind typography plugin is not used; do not introduceprose-*classes. - Code blocks use a custom chrome (language strip, line counts, wrap toggle, copy button) and a bordered light frame.
- Prev/next article navigation is a 2-column grid on
md+, withmin-h-[44px]touch targets.
The text block is typeset like a printed monograph, not a blog post.
- Series imprint, not a stream readout. The metadata head strip opens with the series name (
Graduate Texts in Minecraft) behind a blueprint-azure signal tick, in mono small-caps — it reads as a running imprint.PATH:stays as honest apparatus on the right. - The opening paragraph starts plainly. The article H1 already carries the book voice, so the first body paragraph stays in the normal sans body face without a versal, drop cap, or small-caps incipit. A small gap sits between the title rule and the opening paragraph so the text block has breathing room without adding a competing typographic device.
- Body paragraphs are justified at reading width. At
md+, top-level article paragraphs justify withhyphens: auto; mobile stays ragged-right where a narrow measure justifies poorly. Lists, blockquotes, and callouts are not justified. - Thematic breaks are asterisms. A
---in source renders as a centered hairline-rule + ink diamond device, not a full-width line. - Each article closes with a chapter-end mark. A centered colophon device (three diamonds, the middle one in the article's accent — blueprint azure, or burgundy when Advanced) sits between the body and the prev/next navigation, the way a printed chapter ends before the next begins.
A coherent loading language exists; reach for it before inventing new spinners.
LoadingIndicator: a pulsingsize-2square dot with a mono uppercase label. The canonical inline loading treatment.loading-shell-primitives.tsxexposesSegmentedBar,SweepOverlay,ScanConfirmOverlay, andSkeletonExitWrapper. Route-level loading states useSkeletonExitWrapperwitharia-busy="true"and anaria-label.OperationProgressprovides a longer-running shell withrole="status" aria-live="polite"and arole="progressbar"track.- Mark async action buttons with
aria-busywhile pending; the system relies on this consistently.
The system has clear conventions; apply them when writing or reviewing UI.
Focus
- Canonical:
focus-visible:outline-tech-main focus-visible:outline-2 focus-visible:outline-offset-2. Use this for buttons, cards, segmented options, and nav links. - Inputs are a deliberate exception: focus is a border-color change to
border-tech-main, no outline or ring. - Never set
focus:outline-nonewithout supplying a visible replacement.
Hover
- Default rhythm: color/fill change with
transition-colorsandduration-200–duration-300. - CTA rhythm: scale transform —
hover:scale-[1.02] active:scale-95 transition-transform duration-300. Reserve this for hero and primary call-to-action surfaces.
Active and disabled
active:scale-95(or[0.98]) is the system pressed-state for the scale rhythm.- Disabled controls dim with
opacity-50–opacity-60andcursor-not-allowed(the latter is also handled globally inapp/globals.css). Usearia-busyfor in-flight async,disabled/aria-disabledfor actually-blocked controls.
The system reliably provides
aria-labelon icon-only controls (hamburger, search, language, close).aria-busyon async action buttons.aria-live="polite"on loading and status regions.aria-expandedon toggles (mobile nav, chapter tree, license, popovers).role="status"androle="progressbar"onOperationProgress.motion-reduce:fallbacks on the loading and skeleton primitives.- A canonical focus-visible outline (see above).
Open gaps to be careful with when adding new UI
- Dialog/sheet focus trap and
aria-modalare not provided centrally; supply them per-component. aria-describedbyandaria-labelledbyon dialogs/popovers are not consistent — set them when introducing a new overlay.- Decorative
motion-*animations outside the loading system do not havemotion-reduce:fallbacks; add them when you reach for a new animation.
General rules
- Never disable zoom; preserve
viewport-fit=coverandinitial-scale=1from the root layout. - Maintain ≥
44pxtouch targets on buttons, nav controls, and important links. - Do not rely on hover-only affordances. Hover brackets and decorative reveals are decoration; clickable elements still need visible borders, labels, or icons.
- Mark purely decorative elements
pointer-events-noneand, where appropriate,aria-hidden. - Hide dense technical decoration on mobile if it competes with content.
- Maintain readable contrast against translucent surfaces; body copy should not depend on full opacity.
Before adding or changing UI, check:
- Uses
tech-*tokens instead of raw hex. - Defaults to square geometry; reaches for radius consciously.
- Uses existing primitives (
TechCard,TechButton,InputBox,TextAreaBox,SelectableCard,SegmentedControl,CornerBrackets,PageHeader,SectionTitle,StatusBadge,StatusDot) before inventing new ones. - Picks the right surface system:
TechCardfor general panels,EditorSurfacefor editor work, the article shell for reader work, custom panels only when none of the above fit. - Respects mobile-first layout and
44pxtouch targets. - Uses mono labels and HUD text intentionally, not for long prose.
- Keeps decorative HUD/grid/scan motifs subordinate to content.
- Uses motion from the existing
animate-*catalog and avoids layout shift. - Supplies a visible focus state — outline for controls, border-color for inputs.
- Pairs nontrivial decorative motion with a
motion-reduce:fallback. - Avoids emoji as structural icons; uses text, CSS geometry, or SVG instead.