# Gautier UI — a design context file for humans and AI agents *v0.1 · July 2026* > One accent. Two typefaces. Six greys. Everything else must earn its place. **What this is.** A complete, opinionated UI charte in one markdown file. Drop it into a project and point your AI coding agent at it (reference it from `CLAUDE.md`, `AGENTS.md`, or your system prompt: *"Follow `Gautier-ui.md` for all UI work."*). The agent gets rules it can actually apply; you get interfaces that don't look generated. **The living reference.** `Gautier-ui-preview.html` (same folder) demonstrates every rule in this file — self-contained, zero dependencies, opens from `file://`. When both are present and disagree, **the preview wins**. This file is nonetheless **complete on its own**: an agent holding only this markdown has everything it needs. **Provenance.** Generalized from the working charte of [Jérôme Gautier](https://jeromegautier.info)'s pen-plotter atelier (Geneva, Switzerland) — Swiss typographic style, born on paper, every value validated by eye. The atelier's own charte, with its signature red, remains the original; this file is the transferable method. **The mark.** The kit's emblem is the **Gautier family armoirie** — five lozenges in cross, inlined in the preview in `currentColor` so it follows the ink in both modes. On a dashboard it appears once, as the brand tile on the chrome. Replace it with your own mark the same way: a small inline SVG, single color, `currentColor` or white-on-accent. **The sample data is real.** The preview's demo content is the Gautier family's own record — citizens of Geneva since **1508** (Louis, notary), Jean-Antoine's *Histoire de Genève* (9 volumes, kept sealed by the Council until 1896), Raoul's 42 years directing the Geneva Observatory (1889–1931), Hélène Gautier-Pictet's suffrage fight (CLAFG 1937, referendum lost 1953, vote won 1960). Provenance runs through the examples too: no lorem ipsum, no fake metrics — replace them with your own true data. **Customize — the entire surface is two typefaces, one color, one mode.** 1. `--accent` — your brand color. Pick it in the preview's **Accent picker**: the whole page re-renders live, a contrast guard checks it **against the current paper** (≥ 3:1 required for UI marks, ≥ 4.5:1 if the accent ever carries text), and the token block updates for copy-paste. 2. `--font` — your grotesque, for the UI (system stack only; never ship font files). 3. `--font-mono` — your monospace, for **data literals only**: file names, IDs, hex values, code. Numbers in the UI stay tabular grotesque. 4. **Mode** — light (default) or dark, via `data-theme="dark"` on ``. Dark is a **designed inverse** with its own ramp (§1) — never a CSS filter, never an ad-hoc inversion. The preview's Mode button toggles and persists it. Everything else — greys, scales, regimes, rules — **is the method, not a preference**. Changing it silently breaks the guarantees below (contrast budget, grayscale test). Both files mark the boundary: *"everything below is the method — do not edit."* --- ## 0. Prime directive — function first Spacing, typography, colors and grey levels exist **only to serve a function**. Every value must prove its job; when in doubt, it goes. Never add a color, a shadow, a border or a size "for looks" — if you cannot name the function, do not add the mark. ## 1. Tokens Declare once, at `:root`. These are the **only** values allowed — no free values anywhere. ```css :root{ /* THE accent — the single brand decision. Set it once; used pure, never tinted. */ --accent:#e2231a; /* replace with your brand accent (one color, everywhere) */ /* surfaces */ --paper:#ffffff; /* all surfaces, cards, canvases */ --desk:#e6e6e6; /* "desk" background behind paper previews */ /* ink ramp — grey is the ONLY value channel (see §3) */ --ink-900:#141414; /* primary text, full ink (the black — softer than #000) */ --ink-700:#3d3d3d; /* strong secondary text */ --ink-500:#727272; /* tertiary / muted text, units, quiet labels */ --ink-300:#b0b0b0; /* faint marks: axis ticks, background series — never running text */ --ink-200:#dcdcdc; /* hairlines, borders */ --ink-100:#eeeeee; /* faint grid fills */ /* type scale — six steps, nothing in between */ --type-100:10px; /* axis labels, graduations */ --type-200:11px; /* UI labels, buttons, notes */ --type-300:12px; /* body text, tables */ --type-400:13px; /* subheadings */ --type-500:15px; /* window / page titles */ --type-900:26px; /* large figures (KPIs) */ /* spacing scale — base 4px, six steps */ --sp-100:4px; /* micro: chip gaps */ --sp-200:8px; /* within a component */ --sp-300:12px; /* between control rows */ --sp-400:16px; /* card / panel padding */ --sp-500:24px; /* between modules */ --sp-600:32px; /* page breathing room */ /* DASHBOARD regime only (see §6) */ --r-dash:8px; --shadow-dash:0 1px 2px rgba(0,0,0,.06), 0 8px 24px rgba(0,0,0,.10); /* type — system stacks only; no webfonts, no font files shipped */ --font:"Helvetica Neue",Helvetica,Arial,system-ui,sans-serif; --font-mono:ui-monospace,"SF Mono",Menlo,Consolas,monospace; /* data literals only */ } /* dark — a designed inverse (its own ramp), not a filter */ :root[data-theme="dark"]{ --paper:#242424; /* night paper — clearly lighter than the desk */ --desk:#121212; --ink-900:#f2f2f2; --ink-700:#d6d6d6; --ink-500:#9a9a9a; --ink-300:#616161; --ink-200:#3f3f3f; --ink-100:#2f2f2f; --shadow-dash:0 1px 2px rgba(0,0,0,.5), 0 8px 24px rgba(0,0,0,.6); } ``` **Bi-mode constants** (never themed): slider thumbs and toggle knobs stay **white** in both modes; code/terminal blocks keep their own fixed dark ground; inline SVG line-work uses `currentColor` so it follows the ink automatically. **Rule: every size and every gap in the UI is one of these steps.** If a value fits no step, either it proves its function or it snaps to the nearest step. ## 2. The accent — doctrine of the one color The accent is a **rare pre-attentive attribute**: *one* salient point per view — a section number, the active value, the anomaly in a chart, the alert on a dashboard. - **Never a flood.** No accent-colored fills, panels, or large areas — saturation on a large surface crushes everything else. - **Never a second encoding.** The accent means "look here", nothing else. It never encodes a category or a quantity. - **One per view — and "one" is arbitrated by layer:** - **Chrome** (section numbers, the app tile, required marks `*`): exempt — these are wayfinding and may repeat. - **Controls** (the active value beside a slider, the active chip's edge): live state, may repeat — a tool with five sliders legitimately shows five accent values. - **Data** (charts, KPIs, messages): **at most one accent mark per view.** In a tool that mark is the **error**; on a dashboard it is the **alert/anomaly** (a threshold breach qualifies; a normal delta does not). - The accent **underlines, it does not paint**: active states get ink-colored text with a 2px accent underline — not accent-colored text on a tinted pill. ## 3. Grey is the only value channel The palette has one hue. Everything data-viz normally does with color, do with **grey (value) and position**: - A sequential "degree" gradient = the **ink ramp** (`--ink-100…900`), never a second hue. - **Grayscale test (hard acceptance criterion):** converting the screen to grayscale must change nothing about its readability. If meaning is lost, color was carrying it — rebuild. - **Contrast rule:** `--ink-300` (~2.3:1 on white) is **never used for words that must be read** — only faint marks (axis ticks, upcoming steps, background series). ## 4. Typography - **System grotesque** (`--font`) for all UI. No webfonts, no shipped font files. - **Monospace** (`--font-mono`) for **data literals only** — file names, IDs, hex values, code. Never for UI labels; never for numbers in tables or KPIs (those stay tabular grotesque). Two families total; there is no third. - **Tabular numerals everywhere** (`font-variant-numeric: tabular-nums`) — columns of figures align. Exact values belong in a **table**, not in a chart. - **Spaced uppercase** (letter-spacing ≥ .06em) is a signal for **short labels only** — never for long titles or sentences (readability wins). - Weight 700 for titles and emphasis; no intermediate weights. - Text hierarchy is built from **position, size step, and ink level** — never from color. ## 5. Layout & structure - **Numbered sections**: `01 / 02 / 03…` (CSS counter), number in accent, title in ink. Frank alignments, generous white. - **Hairlines** (1px, `--ink-200`) are **always a background layer** — under the data, under the content, never in front. - **Tables**: header in caps (`--type-100`, `--ink-500`) · one hairline under each row (`--ink-200`), no verticals, no zebra · text left, numbers right (tabular) · cell padding `--sp-200` · the one featured value may be accent (§2). - **Stepper** for stepwise flows (`1 · Draw → 4 · Export`), in the top bar: active step = **ink text and ink number + 2px accent underline, no fill**; completed steps ink; upcoming steps `--ink-500`/`--ink-300`. - A dashboard header may carry one **app tile** (accent square, the mark in white) — the brand lives on the chrome, never in the data. ## 6. Two regimes — never mixed | | TOOL (default) | DASHBOARD | |---|---|---| | Use | working instruments: editors, generators, forms | reading surfaces: KPIs, monitoring | | Corners | `border-radius:0` — sharp, always | cards `border-radius:var(--r-dash)` | | Shadows | none (flat) | `var(--shadow-dash)` on cards | | Unit | the panel/hairline grid | **the card** is the unit of reading | One screen commits to **one** regime. The other regime may appear only as a **framed object** inside it (e.g. a tool window shown inside a dashboard, like paper on a desk). Exception in TOOL regime: a paper/canvas preview may carry a soft shadow — that is the shadow of the depicted *object*, not of the chrome. **The regime governs surfaces, not controls.** Inputs, buttons, chips and sliders keep their sharp TOOL anatomy (§7) everywhere — including inside dashboard cards. Only the containing surface rounds. **KPI card anatomy** (dashboard): caps label on top (`--type-100`/`200`, `--ink-500`) · figure in `--type-900`, `--ink-900`, tabular · one context line below (`--type-200`, `--ink-500`). Deltas speak in words and glyphs (▲ ▼), not in color — except *the* alert (§2). **App tile**: snap to a spacing step (24–32px); page title `--type-400`/`500` beside it. ## 7. Controls - **Slider**: 3px hairline track (`--ink-200`), round **white** thumb (15px, hairline border, soft shadow), **dark fill** (`--ink-900`) up to the thumb. For symmetric ranges (`min < 0 < max`), the fill grows **from the center** — at zero the bar is empty; it never lies. Fill requires ~6 lines of JS (see the preview's `fillRange`). - **Editable value field** to the right of each slider: accent-colored figure, hairline border, two-way binding. - **Toggle**: same family as the slider thumb — round white knob with shadow; track `--ink-200` (off) → `--ink-900` (on). Replaces the native checkbox for settings. - **Buttons**: hairline ink border, paper background, uppercase `--type-200` label; hover inverts (ink background, paper text). Disabled = `--ink-300` text + `--ink-200` border, no interaction, no hover. - **Format/choice chips**: compact bordered items; the active chip gets a 2px accent **left border** and a faint accent tint. - **Focus is always visible**: `:focus-visible { outline:2px solid var(--ink-900); outline-offset:2px; }`. Minimal style never deletes the outline. - Notes/help live **in the UI, next to the control they explain** (small `--ink-500` text) — not in tooltips. - **Form fields**: caps label (`--type-200`, ink-700) + required mark in accent · hairline input, focus = ink border · help text below in `--ink-500`. **Error state**: accent border + bold inline accent message, directly **under the field it concerns** — never a summary box far away, never a toast. - **Dialogs** (TOOL regime): sharp ink frame over a dimmed desk; primary action inverted (ink background), cancel plain. For destructive actions **the sentence does the warning, not the button color** — state the consequence in words ("this cannot be undone"); buttons stay ink. The accent never colors a button. - **Navigation**: linear flows get the **stepper**; multi-section tools get the **numbered sidebar rail** (the sections *are* the navigation). No tab bars, no hamburger. ## 8. States & feedback - **Working**: thin dark progress bar (`--ink-900` on `--ink-100`) + tabular percentage. Black, not accent — computing is normal, not an alarm. - **Success**: plain ink text ("Exported ✓ …"). Succeeding is a tool's normal state; it is not celebrated. - **Error**: **the only accent-colored state.** An error is an anomaly — exactly the accent's job. Bold, `--type-200`. - **Empty**: plain `--ink-500` text stating what will appear and how to make it appear ("No data yet — the record continues."). No illustrations, no mascots, no oversized icons. - **No green, no orange, no state colors.** Ever. - **Motion**: transitions exist only as **state feedback** (a toggle sliding, ≤ 150 ms) — never decorative, never on page load, nothing moves on its own. - **Icons**: none. Typographic glyphs only (▶ ✓ ✕ ⬇ →) — the vocabulary is words. - **Two modes, one method**: light is paper, dark is **night paper** — a designed inverse with its own ramp (§1), toggled via `data-theme="dark"`, persisted (localStorage in a try/catch — it may be unavailable on `file://`). Never a CSS filter, never an ad-hoc inversion; every rule in this file must hold **in both modes** (run the self-check twice). **Accent text on dark** (default accent = 3.3:1): permitted for short bold error/alert lines only, always paired with a glyph or weight so the meaning survives without the hue. - **Responsive**: modules stack on narrow screens; the type and spacing steps **do not change**. No mobile-specific sizes. ## 9. Charts - Encode quantity by **position** (height, place on a common scale) — never by hue. - Bars start at **zero**. No pie charts, no 3D, no decorative gradients. - **Labels sit on the data** (names at line ends, under bars) — no separate legend. The **value figure** may accompany **the one featured mark** (the accent point); the full series' exact values belong in a table, not stacked on every bar. - Sort by **the effect you are showing**, not alphabetically. - ≤ 4 series per chart; more → **small multiples** (identical scale, identical framing). - One accent mark per chart maximum: *the* point of the chart. Context series use `--ink-500`/`--ink-300`; the featured series uses `--ink-900`. - Grid lines: `--ink-100`/`--ink-200`, behind the data. Axis labels `--type-100`, `--ink-300`. - Exact values go in a **table** (tabular numerals), not on the chart. ## 10. Accessibility budget — measured, not promised Contrast on white (`--paper`), WCAG relative luminance: | Token | Ratio | Verdict | |---|---|---| | `--ink-900` #141414 | 18.4:1 | AAA — body text, titles | | `--ink-700` #3d3d3d | 10.9:1 | AAA — secondary text | | `--ink-500` #727272 | 4.8:1 | AA — smallest readable text allowed | | `--ink-300` #b0b0b0 | 2.2:1 | **fails for text** — faint marks only, enforced by rule §3 | | `--accent` #e2231a (default) | 4.7:1 | AA — may carry short text (error messages) | Dark mode mirrors the budget on `#242424` (ink-900 → 13.9:1, ink-500 → 5.5:1 AA, ink-300 faint marks only). The default accent reads **3.3:1 on night paper**: fine for marks, **below the 4.5:1 text bar** — on dark, error messages lean on weight and position, not on the hue alone. Plus: keyboard focus visible on every control (§7) · no meaning carried by color alone (grayscale test, §3) · custom accents are gated by the preview's contrast guard, which re-checks **against the current paper** in both modes (≥ 3:1 marks, ≥ 4.5:1 text). If you swap the accent, **this table is now yours to honor — twice.** ## 11. Self-check — run before you ship Acceptance criteria. Every "no" is a defect: - [ ] Is there **at most one accent-colored data mark** per view? - [ ] **Grayscale test**: does the screen lose nothing when desaturated? - [ ] Is every size and gap **on a scale step** (`--type-*`, `--sp-*`)? - [ ] Is `--ink-300` used **only** for faint marks, never for readable words? - [ ] Does the screen commit to **one regime** (sharp/flat vs. cards/shadow)? - [ ] Are bars zero-based, labels on the data, legends absent? - [ ] Is keyboard **focus visible** on every interactive element? - [ ] Do sliders show a dark fill (center-origin when symmetric)? Do toggles use the white-knob family? - [ ] Are errors the only accent-colored state — no green, no orange anywhere? - [ ] Do form errors sit **inline under their field**, with accent border + message? - [ ] Are empty states plain text — no illustration, no oversized icon? - [ ] Is all motion state-feedback only (≤ 150 ms) — nothing moves on its own? - [ ] Does the screen hold in **both modes** (toggle dark, then re-run the grayscale test)? - [ ] Are data literals (file names, IDs, hex) in `--font-mono` — and nothing else? - [ ] Can you name the **function** of every mark on the screen? ## License MIT. Attribution appreciated, not required: *"UI charte: [Gautier UI](https://jeromegautier.info) — Jérôme Gautier, Swiss pen-plotter atelier."* Note: the font stack references system fonts only — no font files are (or may be) distributed with this charte.