---
name: quiet-interface
title: quiet interface
kind: skill
version: 1.0.0
description: >
  a complete method for designing and building calm, coherent interfaces — one
  colour source, no boxes, motion that settles rather than pops — together with
  the craft floor a competent designer never skips: accessibility, responsiveness,
  every state, honest copy, performance, and a verification loop. load before
  writing or editing any ui, choosing a visual direction, or judging whether a
  screen is finished.
when_to_load: >
  before the first line of any ui work — a new screen, a component, a redesign, a
  stylesheet, a landing page. also whenever someone asks for something on-brand,
  cleaner, or "less ai-looking", or asks whether a design is done.
authored_by: innernet
author_url: https://innernet.live
license: CC BY 4.0
updated: 2026-07-26
tags: [design, ui, frontend, css, accessibility, motion, design-system]
---

# quiet interface

> one product, one language. the screen is mostly ground and whitespace; content
> floats; a single living colour tints everything. if an element isn't carrying
> meaning, it isn't on the screen.

This is a method, not a theme. The laws below describe *how a coherent interface
holds together* — you supply the colour, the type, the personality. Follow the
method and two screens built a month apart by two different hands still read as
one product.

Read it in three passes:

- **the look** — the ten laws that decide whether a screen belongs.
- **the floor** — accessibility, responsiveness, states, performance. Not
  polish. A screen that misses the floor is unfinished, however pretty.
- **the work** — how to go from a brief to a shipped screen without producing
  something that reads as machine-made.

---

## I. the look — ten laws

### 1. no boxes

Content floats on the ground, separated by **whitespace, hairline rules, and
type** — not by bordered rectangles. The reflex to reach for a card (fill +
1px border + radius + padding) is the single loudest source of visual noise in
modern UI, because cards nest: a card inside a panel inside a section is three
outlines saying nothing.

Where containment genuinely helps — a document lifted for reading, a modal —
use the faintest surface tint or a soft-cornered frosted panel, never a hard
outline. **Boxes-on-boxes is the smell to design against.** If you need to show
that two things are different, change the space between them before you draw a
line around them.

### 2. one source of colour

Every visible colour — the whole ink ladder, structure, accents, gradients,
glows — derives from **one** hue variable. Set it once; everything downstream is
a `color-mix` / `oklch` derivation of it. Then the entire interface can shift
tone as one breath, and a new component inherits the relationship for free.

Never introduce a raw, disconnected colour. An accent is your colour at a
different lightness, not a stray green borrowed from a chart library. The one
sanctioned exception is **semantic signal** — error, warning, success — and even
then, tune it toward your hue rather than pasting a stock red.

Corollary: exactly **one** gradient in the system. Compose it once, then have
every surface that wants it paint that same gradient full-viewport and *mask it
back* to its own shape. Re-mixing a tint per element is what makes a frosted bar
read as a slightly-wrong colour floating over the page, and makes it visibly lag
when the theme changes.

### 3. one weight, one case, one scale

One font weight everywhere (a regular). Weight contrast is the cheapest and
loudest hierarchy tool; hierarchy from **size, colour, and space** is quieter
and ages better. Bold is for a word inside a sentence, not for a heading.

Pick a case convention and hold it. Lowercase throughout reads calm and modern;
sentence case reads neutral; title case reads institutional. Any of the three is
fine — mixing them is not. Never `text-transform: uppercase` for eyebrows and
labels: caps are shouting, and shouting is what a templated dashboard does.
Proper nouns keep their own casing whatever the convention.

One fluid type scale, defined with `clamp()` so sizes interpolate with the
viewport instead of jumping at breakpoints. Tighten tracking optically as size
grows (large display type wants negative letter-spacing; small text wants none).

### 4. one component per job

There is **one** button, **one** text field, **one** list row, **one** small
toggle, **one** colour control, **one** menu. Variants, never second styles.

The moment a screen needs "a slightly different button", the answer is a variant
of the one button or a rethink of the hierarchy — not a new component. Two
button languages in one product is the most common way a design system dies, and
it always starts as a reasonable exception.

Practical shape of the rule:

- **the button** — a capsule, label left, a small round badge right carrying a
  chevron (forward), a check (a toggle that's on), or a mark. Primary and quiet
  variants of the same component. Never a gradient fill, never a stem arrow.
- **the field** — a soft rounded field: faint fill at rest, brighter fill when
  active, a highlight ring on focus. Textareas begin at one line and grow to a
  handful before scrolling inside themselves — a field never reflows the page.
- **the list** — one dense-row language: name + meta, a faint separator,
  whitespace for the rest. No decorative leading icon; the exception is a row
  whose identity *is* a logo.
- **the quiet action** — anything that isn't primary is an underlined text link,
  not a second-tier button.

### 5. hierarchy is space, then ink, then size

In that order. Before you make something bigger or add a colour, try giving it
more room. Before you add a colour, try moving it up the ink ladder. Keep at
least four steps of ink (primary → secondary → tertiary → faint) and use them
deliberately: metadata is two steps down from its subject, never one.

Prose is bounded to a readable measure (~60–75 characters). A label/value ledger
stays at that measure too, so a value never drifts to the far edge of a wide
column with an ocean of nothing between it and its label.

Vertical rhythm comes from one spacing scale. Pick a base and stay on it; a
one-off `padding: 13px` is a defect, not a detail.

### 6. soft corners, consistently

Nothing that lifts off the ground has a sharp corner, and nothing invents its
own radius. Three steps and a pill is enough for any product:

- a **card / panel / code block / image** radius,
- a larger **sheet / modal / drawer** radius,
- a smaller **popover / menu** radius,
- plus a **field** radius and a full **pill**.

Reach for the step, never a number. A sheet seated on the bottom edge of a
phone rounds its top two corners only.

### 7. motion settles, never pops

One easing family. Entrances **decelerate** (fade + rise + de-blur, staggered by
index); exits **accelerate**. Cap a staggered list reveal at roughly 0.6–0.8s
total — beyond that the user is waiting for your animation, which is the
definition of decoration.

Animate compositor properties only: `opacity`, `transform`, `clip-path`, masks,
fixed-radius blurs. Never animate layout. Never run per-frame JavaScript on a
scroll handler — write a CSS variable from a `requestAnimationFrame` and let CSS
do the rest.

Everything degrades cleanly under `prefers-reduced-motion: reduce` — and
"degrades" means the state change still reads, just without travel. Removing the
animation must never remove the information.

### 8. everything was always there

New surfaces are **uncovered**, not entered. Before animating an entrance, ask:
*how would this look if it had been here the whole time and my attention was
simply elsewhere?*

Two moves cover almost every case:

- **reveal** — a clip-path or mask wipe behind a progressive blur edge (a feather
  grading into a frost), with the content itself never translating.
- **attention shift** — the element existed all along, and something the user
  already trusts carries their gaze to it at the right moment.

A panel that slides in from off-screen announces machinery. A panel that was
always there, unblurring, announces nothing — which is the point.

### 9. reading beats atmosphere

Any page with a living, animated, or image background must resolve the conflict
between atmosphere and legibility in favour of legibility, **the moment the user
starts reading**.

The reading ramp: at the top of the page the background is fully present and
sharp. As the user scrolls, a fixed scrim fades in over it — ground tint plus
backdrop blur — so the words sit in full contrast. Scroll back to the top and it
clears. Drive it from one `0 → 1` variable written on scroll.

Two hard-won corollaries:

- **the blur radius rides the ramp too.** `blur(calc(var(--ramp) * 18px))`, not a
  constant 18px behind an animated opacity. A full-viewport gaussian is the most
  expensive thing on a page, and cost grows with the square of the radius — so
  browsing should pay zero, and only real reading should pay full.
- **frost and tint are two layers.** Keep the `backdrop-filter` on a small,
  correctly-shaped box; only the *tint* needs to be full-viewport. Never put a
  backdrop-filter on a full-viewport tint layer.

The exception: a view where watching the background change *is* the effect. Opt
that one out explicitly, and say why in a comment.

### 10. text is wrapped, not left to chance

Set `text-wrap: pretty` on body prose (no widows, no orphans) and
`text-wrap: balance` on **every** short display line — headings, eyebrows, hero
lines, closing lines. Add it in the same pass that adds the heading class, not in
a later cleanup, or a two-word ragged last line will survive at some width you
never tested.

Text must never clip. If your reset zeroes padding, every element owns its own:
give descenders room with a line-height of at least ~1.3 on tight chrome, and put
a min-height plus vertical padding on rows. Any element beside text aligns to the
**text baseline**, not the box centre — a mark vertically centred against a label
is the classic mismatched-bases smell.

---

## II. the token contract

Never hard-code what a token owns. The names below are a portable skeleton — use
your own, but keep the *shape*: one hue at the root, an ink ladder, hairlines,
faint surfaces, a radius ladder, a fluid type scale, and one motion family.

```css
:root {
  /* the one hue — everything below derives from it */
  --hue: 217;

  /* ground + ink ladder */
  --bg:      oklch(98.5% 0.012 var(--hue));
  --ink:     oklch(22%   0.03  var(--hue));
  --ink-2:   color-mix(in oklab, var(--ink) 72%, transparent);
  --ink-3:   color-mix(in oklab, var(--ink) 48%, transparent);
  --ink-4:   color-mix(in oklab, var(--ink) 28%, transparent);

  /* structure — hairlines and the faintest fills, never grey panels */
  --hair:      color-mix(in oklab, var(--ink) 12%, transparent);
  --hair-soft: color-mix(in oklab, var(--ink) 7%,  transparent);
  --surface:   color-mix(in oklab, var(--ink) 3%,  transparent);
  --glass:     color-mix(in oklab, var(--ink) 7%,  transparent);

  /* accent = your own colour at another lightness, never a stray hue */
  --accent:     oklch(62% 0.14 var(--hue));
  --accent-ink: oklch(46% 0.12 var(--hue));
  --on-accent:  oklch(99% 0.01 var(--hue));

  /* semantic signal — the one sanctioned departure, tuned toward the hue */
  --danger: oklch(56% 0.17 25);

  /* radius ladder — reach for a step, never a number */
  --radius-field: 12px;
  --radius-card:  16px;
  --radius-menu:  16px;
  --radius-modal: 26px;
  --radius-pill:  999px;

  /* one fluid type scale */
  --t-display: clamp(2.4rem, 1.6rem + 3.6vw, 4.4rem);
  --t-h1:      clamp(1.9rem, 1.4rem + 2.4vw, 3rem);
  --t-h2:      clamp(1.4rem, 1.15rem + 1.1vw, 2rem);
  --t-body:    clamp(0.95rem, 0.92rem + 0.15vw, 1.05rem);
  --t-label:   0.82rem;

  /* one motion family */
  --ease-soft:  cubic-bezier(0.22, 1, 0.36, 1);
  --ease-drift: cubic-bezier(0.4, 0, 0.2, 1);
  --dur-fast: 140ms;
  --dur:      260ms;
  --dur-slow: 520ms;

  /* shadows: soft, ground-coloured, never a black drop */
  --shadow-soft: 0 1px 2px color-mix(in oklab, var(--ink) 6%, transparent),
                 0 8px 24px color-mix(in oklab, var(--ink) 5%, transparent);
}
```

Two rules about the contract itself:

- **JS motion mirrors CSS motion.** If you animate in JavaScript, import the same
  easing and duration values. A tween must read identically whichever side of
  the fence it lives on.
- **a token has exactly one writer.** Decide which module owns `--hue` and let
  nothing else set it. Two writers is how a theme starts flickering.

---

## III. the floor

Everything above is taste. Everything here is not. A screen that misses the
floor is unfinished, and no amount of visual quality substitutes.

### accessibility

- **contrast.** Body text ≥ 4.5:1 against its actual background — including
  against a blurred backdrop, which is where "it looked fine" fails. Large text
  and UI borders ≥ 3:1. Check the real rendered pair, not the token's intent.
- **never colour alone.** A state carried only by hue is invisible to a large
  minority of users. Pair it with shape, position, weight, or text.
- **focus is visible, always.** A keyboard user must be able to see where they
  are on every interactive element. `:focus-visible` with a ring that clears the
  element (offset), never `outline: none` without a replacement.
- **every interactive thing is reachable and operable by keyboard**, in a tab
  order that matches the visual order. Custom controls get real roles and
  states; a `div` with an onClick is a defect.
- **targets are ≥ 44×44px** on touch, including icon buttons — pad the hit area
  even when the mark is small.
- **semantic HTML first.** One `h1`, headings that descend without skipping,
  `button` for actions, `a` for navigation, `label` bound to every input, lists
  as lists. ARIA is a patch for what HTML can't say, not a substitute for it.
- **images carry alt text**; decorative ones carry `alt=""` and `aria-hidden`.
- **live regions** announce anything that changes without a navigation — a toast,
  a validation result, an async success.
- **motion and transparency preferences are honoured** (`prefers-reduced-motion`,
  `prefers-contrast`), and honouring them never removes meaning.
- **it works zoomed to 200%** and at a 320px viewport width without horizontal
  scroll.

### responsiveness

Design the narrow case first — it forces the hierarchy question early. Then let
the layout grow: fluid type, `minmax()` grids, `clamp()` spacing, container
queries where a component must adapt to its slot rather than the viewport.

Verify at three widths at minimum: **375px** (phone), **768px** (tablet),
**1280px+** (desktop). Check both orientations if the product is used on phones.
Check that nothing overflows horizontally — wide content (tables, code blocks,
diagrams) scrolls inside its own container, never the page body.

Respect the safe areas on notched devices, and remember that `100vh` on mobile
lies; use `100svh` / `100dvh` deliberately.

### every state, not just the happy one

For each surface you build, decide and design all of these before you call it
done:

- **empty** — the first-run state. An empty screen is an invitation, not an
  apology. Say what will be here and offer the one action that starts it.
- **loading** — a skeleton in the shape of the content that's coming, so nothing
  jumps when it lands. Never a spinner where a shape would do.
- **partial** — some of it loaded, some still coming. Very common; almost never
  designed.
- **error** — explain what happened and what to do, in the user's terms. Don't
  apologise, don't blame, don't show a stack trace.
- **success / confirmation** — a state change is visible or it didn't happen.
- **disabled** — and it says *why*, on hover or beside the control. A disabled
  button with no explanation is a dead end.
- **too much** — long names, 500 rows, a 40-character word with no spaces. Decide
  where it truncates and whether the full value stays reachable.
- **too little** — one item, no metadata, a missing avatar.
- **offline / stale**, if the product can be either.

### performance is a design property

- Nothing on the page shifts after first paint (reserve space for images, fonts,
  and async content). Layout shift is a *visual* defect.
- Fonts load without a flash of invisible text; prefer variable fonts and
  `font-display: swap` with a metric-matched fallback.
- Images are sized, lazy below the fold, and served in a modern format.
- One full-viewport `backdrop-filter` is a budget. Two is a bug. Gate them behind
  a ramp (see law 9) and drop the radius on low-power devices.
- Don't animate what isn't visible; pause offscreen work.

---

## IV. words

Copy is design. A perfect layout with technical copy is off-brand; a plain
layout with exact copy is not.

- **write from the user's side.** Name what they see and do, not what the system
  does internally. "couldn't reach the server" is honest; "500 internal server
  error" is a log line.
- **active voice, plain verbs, no filler.** Cut "please", "simply", "just",
  "oops". They add length and remove authority.
- **actions keep their name through a flow.** If the button says "send", the
  confirmation says "sent" — not "your message has been submitted".
- **errors say what happened, why if it's useful, and what to do next** — in that
  order, in one or two sentences. Never a bare "something went wrong" if you know
  more, and never an apology in place of information.
- **empty states point forward.** One sentence of what belongs here, one action.
- **numbers get units and context**; timestamps get a human form and a precise
  one on hover.
- **no emoji as UI.** Named services get their real logo, never an emoji, a
  coloured dot, or plain text.

---

## V. how to work

Do not open a stylesheet first. The order below is what separates a designed
screen from a generated one.

### 1. ground it in the subject

Establish, in a sentence each: **who** this is for, **what** the page's single
purpose is, and **what world** the subject lives in. Draw the visual vocabulary
from that world — its instruments, its materials, its language — not from
whatever the last dashboard you saw looked like.

Use real content throughout. Lorem ipsum hides every hierarchy problem you have.
If you don't have the copy, write the copy — it's faster than redesigning around
it later.

If you're working inside an existing product, read its actual tokens and
components before designing. Designing from memory and then reconciling is
twice the work and produces a second language.

### 2. declare the system before placing anything

Write it down — five lines is enough:

- **colour**: the hue, plus the four to six derived values you'll actually use.
- **type**: the faces, the scale, the weight, the tracking rule.
- **space**: the base unit and the measure.
- **motion**: the easing, the two durations, what enters and how.
- **the signature**: the *one* memorable thing this design does that nothing
  generic would. One. Everything else stays quiet so it can land.

Consistency comes from a declared system, not from restraint applied later.

### 3. two passes, always

**Pass one — the plan.** Sketch the layout in words or ASCII. Choose the
structure. Name the sections. Don't write CSS yet.

**Pass two — the critique.** Before building, read the plan back against the
brief and strike anything that reads as a default. Ask: *would this be
recognisable with the logo removed?* If not, the signature isn't doing its job —
and if the answer is "I'd add another accent colour", that's the wrong fix.

Then build. Then critique the built thing once more, on screen, at three widths.

### 4. spend boldness in one place

Restraint is not blandness. Pick the one element that carries the personality —
a typographic move, a single piece of motion, a structural device — and let
everything around it go quiet. Two bold elements halve each other; three read as
noise.

### 5. verify, don't assume

Never report a UI change as working without having looked at it. Load the page,
and check, in this order:

1. **console and network clean** — no errors, no failed requests.
2. **structure** — read the rendered DOM or accessibility tree; confirm the
   headings, labels, and roles are what you intended.
3. **the three widths**, plus dark mode if the product has one.
4. **keyboard** — tab through it; every stop is visible and in order.
5. **the states** — force the empty, loading, and error paths and look at them.
6. **motion** — watch it in a real browser at real speed. Headless screenshots
   freeze transitions and will tell you an entrance works when it doesn't.

Then show the evidence: a screenshot of the actual change, not a description of
it.

---

## VI. what makes work read as machine-made

Any one of these is enough to give a design away. They are not banned forever —
they're banned as *defaults*, and each needs a reason.

- gradient text on a heading, and gradient-filled buttons
- a left-border accent stripe on a callout box
- three feature cards in a row, each with an icon in a tinted rounded square
- emoji standing in for icons
- glassmorphism applied to everything rather than to one layer that needs it
- a hero with a big number and a coloured accent underneath it
- purple-to-blue on near-black, or acid green on charcoal
- warm cream + a serif display + terracotta (the "tasteful" default)
- shadows in black rather than in the ground's own colour
- decoration that carries no information: divider dots, meaningless flourishes,
  icons that repeat the word next to them
- an animation on every element, arriving all at once
- copy written in marketing register when the user is trying to do a task
- borders drawn to separate things that whitespace already separated

The tell they share: each is a decision made by reflex rather than for this
subject. Replace them with something the subject actually justifies, or delete
them.

---

## VII. before you ship — the checklist

**the look**

- [ ] no bordered box added; containment is whitespace, hairline, faint surface,
      or one soft-cornered panel
- [ ] every colour traces to the one hue, the ink ladder, or a semantic signal
- [ ] one weight, one case convention, one fluid scale
- [ ] one button, one field, one row language — no second style introduced
- [ ] radii come from the ladder; no invented corner
- [ ] motion uses the shared easing and durations, decelerates in, and survives
      `prefers-reduced-motion`
- [ ] new surfaces are uncovered, not entered
- [ ] any living background frosts as the user reads, and the blur radius rides
      the same ramp as the opacity
- [ ] every display line carries `text-wrap: balance`; prose carries `pretty`
- [ ] nothing clips: descender room on tight chrome, min-height on rows
- [ ] anything beside text sits on the text baseline

**the floor**

- [ ] contrast checked against the real rendered background
- [ ] no state carried by colour alone
- [ ] visible focus on every interactive element; full keyboard path
- [ ] touch targets ≥ 44px
- [ ] semantic HTML; one h1; labels bound; alt text present
- [ ] 375 / 768 / 1280 verified; no horizontal page scroll; works at 200% zoom
- [ ] empty, loading, partial, error, disabled, overflow states all designed
- [ ] no layout shift after first paint; at most one full-viewport blur
- [ ] copy is plain, active, and written from the user's side
- [ ] verified in a real browser, with a screenshot to show for it

---

## VIII. making it yours

The laws are portable; the values are not. To adapt this skill to another brand:

1. Replace the token block with your own values — keep the *structure* (one hue,
   an ink ladder, a radius ladder, one motion family).
2. Rewrite law 3 to your own case and weight convention, and law 6 to your own
   radius steps.
3. Name your one component per job, and record their real names, so the next
   person reaches for them instead of inventing.
4. Choose your signature — the one bold thing — and write it down. If it isn't
   written down, it will be diluted by the third screen.
5. Leave the floor (section III) exactly as it is. It isn't brand-specific.

## IX. keeping the skill alive

A design system dies as a document and lives as a ledger. Whenever a design
decision is made, queried, or approved — a shape, a component, a motion, an
interaction rule — record it back here in the same pass: as a law, a token, or a
line in the component vocabulary. Never let the code drift ahead of the skill;
the next build reads this to stay coherent.

Evolve it. Don't fork it. A second document describing the same system is how you
end up with two systems.

---

*kept by [innernet](https://innernet.live) — memory your AI tools can read.
Free to use and adapt under CC BY 4.0.*
