Plain+ Design Specification v1.0

Plain+

A design system for interfaces that don't look AI-generated. Premium through restraint, not decoration. The HTML is the design.

Contents

  1. Philosophy
  2. Decision Tree
  3. Design Tokens
  4. Typography
  5. Color
  6. Spacing & Rhythm
  7. Components
  8. Layout Archetypes
  9. The Rules
  10. React / JSX Usage
  11. Pre-Ship Checklist

1. Philosophy

LLM-generated UIs have developed a recognizable aesthetic: rounded corners, soft gradients, purple-to-blue color ramps, geometric sans-serif fonts, centered card layouts, decorative shadows. These are individually fine choices. Collectively, they're a fingerprint.

Plain+ is a deliberate counter-aesthetic. It starts from the premise that unformatted HTML — a browser's default rendering of semantic markup — already communicates structure clearly. The job of the stylesheet is not to add decoration but to refine what's already there: tune the type, control the measure, establish rhythm, and get out of the way.

The "plus" is the gap between a raw index.html and one that feels like it was set by someone who knows typography. That gap is crossed with:

Nothing else. No motion. No texture. No visual effects. The premium is in what you don't see.

Core test: If someone screenshots the artifact and posts it, could a viewer confidently say "an AI made this"? If yes, something needs to be removed.

2. Decision Tree

Use this to decide whether an artifact should use Plain+, the default bold aesthetic, or something custom.

Is the artifact content-forward?

Content-forward = the user came for information, data, or a tool. The interface is a vehicle, not the experience. Examples: documentation, dashboards, settings panels, reference tables, forms, CLIs with web frontends, admin UIs.

Experience-forward = the interface itself is the point. The user came to be engaged, persuaded, or entertained. Examples: landing pages, marketing sites, games, creative showcases, portfolios.

Content-forward → Does it need to feel "designed"?

Yes, visually rich: Use the default frontend-design skill. Dashboards with data visualization, consumer-facing tools where visual polish is a feature.

No, it should feel transparent: Use Plain+. The user should focus on content, not chrome. Docs, admin panels, dev tools, internal tools, reference pages.

Experience-forward → What kind?

Marketing / persuasion / portfolio: Use the default frontend-design skill with a bold direction.

Game / interactive art / experiment: Custom aesthetic, designed from scratch for the concept.

Still unsure?

Ask: "Would serif body text feel wrong here?" If serif would feel stuffy or out of place (e.g., a music app, a social feed), Plain+ probably isn't the right fit. If serif would feel authoritative and natural (e.g., a settings page, a data table, a writing tool), Plain+ is the move.

3. Design Tokens

Every value in Plain+ is defined as a CSS custom property. These are the atomic units — nothing else is used.

3.1 Type Scale

Minor third ratio (1.2), fluid between viewport sizes using clamp().

TokenRoleMinMax
--step--1Captions, labels, hints0.80rem0.89rem
--step-0Body text (base)1.00rem1.06rem
--step-1Lede, h31.20rem1.35rem
--step-2h21.44rem1.69rem
--step-3Large display (rare)1.73rem2.11rem
--step-4h1, page title2.07rem2.64rem

3.2 Color

TokenValue (Light)Value (Dark)Usage
--ink#1a1a1a#e8e6e3Primary text, headings
--ink-light#555#aaaSecondary text, lede
--ink-faint#999#777Labels, captions, markers
--surface#fdfdfc#1a1a19Page background
--rule#d4d0cb#333Borders, dividers
--accent#b44#d66Flourish, interactive states
--code-bg#f4f3f1#242422Code blocks, disabled inputs
--highlight-bg#fef9f0#2a2520Accent notices

3.3 Color Swatches

ink
ink-light
ink-faint
surface
rule
accent
code-bg

Alternate accents

The accent can be swapped per-artifact. Always muted, always singular.

#b44
default
#4a7
success
#b80
caution
#67a
technical

3.4 Spacing

TokenValueUsage
--space1.6remBase unit; paragraph margin, padding
--space × 0.250.4remTight: below h3, between label and input
--space × 0.50.8remBelow h2
--space × 23.2remSection breaks, above h3, page padding
--space × 34.8remAbove h2 (major sections)

3.5 Measure

ContextValue≈ Characters
Default (reading)38em~65 chars
Spec / documentation42em~72 chars
Wide (dashboards)60emContent blocks still 38em
Full (data tables)72emProse still capped at 38em

3.6 Font Stacks

TokenStackUsage
--font-bodyCharter → Bitstream Charter → Iowan Old Style → Palatino Linotype → Palatino → Georgia → Cambria → serifBody text, blockquotes, input values
--font-heading-apple-system → Helvetica Neue → Segoe UI → sans-serifHeadings, labels, buttons, UI chrome
--font-monoSF Mono → Cascadia Code → JetBrains Mono → Consolas → monospaceCode, token values

4. Typography

4.1 The serif/sans pairing

This is the single most important design decision in Plain+. Body text is set in a serif (Charter by preference) and headings in the system sans-serif. The contrast between the two creates visual hierarchy without any decoration — no size tricks, no color changes, no weight extremes. Just two different voices.

Why this matters as an anti-tell: virtually every LLM-generated UI uses a geometric or grotesque sans for body text (Inter, Roboto, system-ui). Choosing a serif immediately places the output in a different visual category. It reads as editorial, considered, human.

4.2 Heading hierarchy

LevelSizeWeightSpacingDecoration
h1--step-4600letter-spacing: -0.025emNone
h2--step-2600letter-spacing: -0.01em1px bottom rule
h3--step-1600letter-spacing: -0.01emNone
h4--step-0600DefaultNone

Note: only h2 gets a bottom rule. This is deliberate — it marks major section boundaries without cluttering sub-sections.

4.3 Special text roles

Lede — the first paragraph after h1. Larger, lighter color. Sets the tone.

This is a lede paragraph. It introduces the page at a larger size and in a softer ink, creating a gentle ramp from the title into the body text.

Caption / label — small, uppercase, tracked. Uses the heading font.

This is a caption or label

Inline emphasis — italic for aside, bold for stress, code for values.

5. Color

5.1 The warmth principle

Plain+ uses warm neutrals throughout. The ink is not pure black (#000) but a very dark warm gray (#1a1a1a). The surface is not pure white (#fff) but a barely perceptible warm off-white (#fdfdfc). The rules are not cool gray but a warm stone tone (#d4d0cb).

This warmth is subtle — most people won't consciously notice it — but it's the difference between "screen" and "paper." It contributes to the sense that a human set this type.

5.2 Accent discipline

The accent color appears in exactly three places maximum:

  1. The flourish — the thin colored bar at the top of the page (body::before)
  2. Interactive hover states — link underlines, button borders on hover
  3. One inline emphasis — optional, for a single word or status that needs to pop

If you find the accent in a fourth place, remove it from somewhere.

5.3 Forbidden colors

ColorWhy it's banned
Purple (#7c3aed, #8b5cf6, etc.)The #1 Claude/AI-UI color. Instantly recognizable.
Teal (#14b8a6, #06b6d4, etc.)The #2 AI-UI color. Common in ChatGPT-adjacent design.
Blue-to-purple gradientsThe gradient direction itself is a tell.
Startup blue (#2563eb, #3b82f6)Reads as generic SaaS / landing page.
Pure black (#000)Too harsh. Use --ink instead.
Pure white (#fff)Only for input backgrounds. Use --surface for page background.

6. Spacing & Rhythm

All vertical spacing is a multiple of --space (1.6rem). This creates a consistent visual rhythm down the page. The key spacings:

BetweenSpaceValue
Paragraphs1×1.6rem
h3 → content0.25×0.4rem
h2 → content0.5×0.8rem
Content → h32×3.2rem
Content → h23×4.8rem
Section break (hr)2× above and below3.2rem
Page top/bottom padding2×3.2rem

The asymmetry matters: more space above a heading than below it. This binds the heading to its content rather than floating equidistant between sections.

7. Components

7.1 Button

Square, bordered, uppercase small text. The anti-pill.

Variants

Primary action
Key action
Secondary
Inline / tight
Inactive

State matrix

StateBorderBackgroundTextCursor
Default1.5px --inktransparent--inkpointer
Hover1.5px --ink--ink--surfacepointer
Focus-visible1.5px --inktransparent--ink— (2px --accent outline, 2px offset)
Active1.5px --ink--ink--surfacepointer (opacity 0.85)
Disabled1.5px --ruletransparent--ink-faintnot-allowed (opacity 0.5)

7.2 Text Input

Hint text appears here in --ink-faint.
Error messages use --accent color.

State matrix

StateBorderBackgroundText
Default1px --rulewhite / #222 (dark)--ink
Focus1px --inkwhite / #222 (dark)--ink
Error1px --accentwhite / #222 (dark)--ink
Disabled1px --rule--code-bg--ink-faint

7.3 Table

No zebra striping. No cell backgrounds. Structure comes from the header weight and thin row rules.

FeatureTreatment
Header rowUppercase, tracked, 2px bottom border in --ink
Body rows1px bottom border in --rule
Row hoverNone (optional: subtle --code-bg background on interactive tables)
AlignmentLeft by default. Right-align numbers. Top-align multi-line cells.
Cell padding0.5em vertical, 0.75em horizontal

7.4 Notice / Callout

Default notice. Uses --code-bg background with a 2px left border in --ink-faint. For neutral information.

Accent notice. Uses --highlight-bg with a 2px left border in --accent. For warnings, important notes, or key callouts. Use sparingly — one per section maximum.

7.5 Tag / Badge

Default Inactive / informational
Active Selected / current

7.6 Link

Links are same-color as body text with a light underline that shifts to the accent on hover. This is intentional — colored links (especially blue ones) would introduce a second color into the palette and break the single-accent rule. The underline alone signals interactivity.

7.7 Code

Inline code has a border and tinted background. Code blocks have the same treatment at block scale:

function greet(name) {
  return `Hello, ${name}.`;
}

// Plain+ code blocks: no syntax highlighting by default.
// If highlighting is needed, use a muted, warm palette —
// not the typical saturated VS Code colors.

7.8 Blockquote

A blockquote is indented with a 2px left rule and set in italic at a lighter ink weight. It's for attributions, asides, and quoted material — not for callouts (use the notice component for those).

8. Layout Archetypes

These are pre-solved layout patterns. When building a Plain+ artifact, pick the closest archetype and adapt it. Don't invent new layout approaches — the system works because it's consistent.

8.1 Document

Single column, centered, --measure width. For articles, specs, documentation, READMEs. This page is an example.

Document
Content at --measure (38em), centered

8.2 Sidebar + Content

For settings panels, navigation + detail views, admin layouts. Fixed sidebar width, fluid content.

Sidebar + Content
Sidebar
(14em fixed)
Content area (fluid, border-left rule)

8.3 Two-Column

For comparisons, side-by-side data, split views. Equal columns.

Two-Column
Column 1
Column 2

8.4 Data Table with Controls

Full-width table with filter/search controls above it. Controls are left-aligned, inline.

Data Table with Controls
Full-width data table

8.5 Dashboard Grid

For metrics, KPIs, monitoring. Three columns of equal width. No card containers — use thin rules or whitespace to separate cells.

Dashboard Grid
Metric 1
Metric 2
Metric 3
Chart / detail area (full width below)

8.6 Form

Single column, narrow (24em max). Labels above inputs. Stacked vertically with --space between fields. Submit button left-aligned below.

Form
Optional hint text

9. The Rules

These are non-negotiable. If any of them are broken, the artifact is not Plain+.

#RuleWhy
1No border-radiusThe #1 AI-generated UI tell. Square = intentional.
2No gradientsFlat or nothing. Gradients signal "design effort" in the wrong direction.
3No box-shadowDepth from hierarchy, not effects.
4No purple, teal, or startup blueThese are AI-UI signature colors.
5Serif body textBreaks the sans-serif monoculture of AI output.
6System sans for headings onlyThe contrast is the design system.
7Whitespace over containersSpace separates; boxes decorate.
8Thin rules over thick borders1px communicates; 3px decorates.
9One accent, ≤ 3 usesDiscipline, not decoration.
10Warm neutrals"Paper" not "screen."

10. React / JSX Usage

When building a React artifact with Plain+, inject the design tokens and font stacks via a <style> block inside the component. Then use Tailwind utilities that reference them.

Setup pattern

export default function App() {
  return (
    <>
      <style>{`
        :root {
          --ink: #1a1a1a;
          --ink-light: #555;
          --ink-faint: #999;
          --surface: #fdfdfc;
          --rule: #d4d0cb;
          --accent: #b44;
          --code-bg: #f4f3f1;
          --font-body: "Charter", "Bitstream Charter",
            "Iowan Old Style", "Palatino Linotype",
            "Georgia", serif;
          --font-heading: -apple-system,
            "Helvetica Neue", "Segoe UI", sans-serif;
        }
        @media (prefers-color-scheme: dark) {
          :root {
            --ink: #e8e6e3;
            --ink-light: #aaa;
            --ink-faint: #777;
            --surface: #1a1a19;
            --rule: #333;
            --accent: #d66;
            --code-bg: #242422;
          }
        }
      `}</style>
      <div style={{
        fontFamily: 'var(--font-body)',
        color: 'var(--ink)',
        background: 'var(--surface)',
      }}>
        {/* Content */}
      </div>
    </>
  );
}

Tailwind mapping

Plain+ conceptTailwind approach
No border-radiusDon't add rounded-* classes. Tailwind's default is square.
Serif bodystyle={{ fontFamily: 'var(--font-body)' }} on the root div
Sans headingsstyle={{ fontFamily: 'var(--font-heading)' }} on h-tags
Ink colorstyle={{ color: 'var(--ink)' }} or text-[color:var(--ink)]
Thin rulesborder-b with style={{ borderColor: 'var(--rule)' }}
Spacingmb-6 ≈ --space, mb-3 ≈ half, mb-12 ≈ double
No shadowsDon't add shadow-* classes.

11. Pre-Ship Checklist

Before finalizing any Plain+ artifact, verify every item. This is a grep-able list — literally search the CSS/JSX for violations.

CheckSearch forExpected
No border-radiusborder-radius, rounded0 results
No box-shadowbox-shadow, shadow-0 results
No gradientslinear-gradient, radial-gradient, bg-gradient0 results
No forbidden colors#7c3aed, #8b5cf6, #14b8a6, purple, teal0 results
Serif body fontfont-family on body / rootCharter / Georgia stack
Sans heading fontfont-family on h1–h4System sans stack
Accent usage--accent, #b44, #d66≤ 3 locations
Dark modeprefers-color-scheme: darkPresent and complete
Measure setmax-width on body / root≤ 72em; prose ≤ 42em
Warm neutrals#000, #fff as backgrounds/text0 results (use --ink, --surface)

Plain+ Design Specification v1.0 — This document is self-demonstrating: every element uses the system it describes.
The source is the specification.