Components
Ten primitives, and the markup to paste
These are the web reference implementation: plain CSS classes, no framework, no runtime, no build step. On a phone or desktop app, take the same proportions, tokens and refusals and build the native equivalent. Every snippet below is complete and correct, including its ARIA.
Actions
Button
A quiet CTA in wide-tracked uppercase small caps. Press shrinks by 3% and
never bounces. The feedback is :active rather than a pointerdown
handler, so sliding your finger off still cancels the action — which matters
to anyone whose aim is not precise.
Variants
--ghost is an outlined pill, not gray text. Gray text beside a filled pill reads as a caption, and a caption is not a choice. --danger is warm earth, never red: removing something is not an emergency.
<button class="ah-btn" type="button">Continue</button>
<button class="ah-btn ah-btn--ghost" type="button">Not now</button>
<button class="ah-btn ah-btn--sm ah-hit" type="button">Small</button>
<button class="ah-btn ah-btn--danger" type="button">Remove it</button>
On a gradient
Glass needs something behind it. On flat cream it reads as nothing — keep it for surfaces sitting on a gradient.
<div class="ah-surface--dawn">
<button class="ah-btn ah-btn--glass" type="button">Glass</button>
</div>
Actions
Pill
The workhorse: tags, switchers, filters, quiet actions. Always wrap small
pills in .ah-hit — the painted control is under the 44px target
floor, and that class grows what the finger hits without moving a pixel of
what the eye sees.
Variants and states
The dot is never the only carrier of its meaning — the pill's own text says the same thing, because color is not a channel everyone has.
<button class="ah-pill ah-hit" type="button">Default</button>
<button class="ah-pill is-active ah-hit" type="button" aria-pressed="true">Active</button>
<span class="ah-pill ah-pill--static">
<span class="ah-pill__dot"></span>With a dot
</span>
Actions
Link
The rule under a link draws itself in rather than the text changing color and jumping. Taken from the reference this aesthetic was tuned against, and it fills a gap: the system previously had no link treatment at all.
Two registers
A standing link keeps a faint rule at rest. A quiet link draws its rule only when you reach for it — for running prose, where a permanent underline on every reference would be noise.
<a class="ah-link" href="/somewhere">A standing link</a>
<a class="ah-link ah-link--quiet" href="/somewhere">A quiet link</a>
Forms
Field
No box. A single bottom rule that strengthens on focus does the whole job: a full border around a text field is a container, and a container implies something being collected.
Utility and essence
Inputs are 1rem, not the 0.8125rem the rest of the UI uses. Safari on iOS zooms the viewport when a field under 16px takes focus, and a zoomed fixed-position app cannot be scrolled — which reads as the app breaking the moment you try to type.
<label class="ah-field">
<span class="ah-field__label">Their name</span>
<input type="text" placeholder="Someone you are thinking of">
</label>
<label class="ah-field ah-field--essence">
<span class="ah-field__label">What is alive in you</span>
<textarea rows="2" placeholder="Say it however it comes"></textarea>
</label>
Forms
ToggleChip
Multi-select in the emotional voice. Nothing is pre-selected and nothing is required.
Selected and not
<button class="ah-chip" type="button" role="checkbox" aria-checked="false">seen</button>
<button class="ah-chip is-selected" type="button" role="checkbox" aria-checked="true">held</button>
Surfaces
Card
Three surface levels plus one glass level, expressed as background first and shadow second. A sunk surface gets no shadow at all — the color is the elevation.
Variants
elevated
The default. Warm paper shadow with an inner highlight.
list
A lighter shadow, for rows that repeat.
sunk
Recessed. No shadow at all.
gradient
One featured moment per screen.
No colored-left-border cards and no hard outlines. Two gradient cards side by side is the rule this system breaks least gladly.
<div class="ah-card">…</div>
<div class="ah-card ah-card--list">…</div>
<div class="ah-card ah-card--sunk">…</div>
<!-- a gradient card carries its own measured ink -->
<div class="ah-card ah-surface--cream">…</div>
Surfaces
Sheet
The bottom sheet, and the only modal this system has. Three ways out, always: the scrim, the grab handle, and a visible Close at equal weight. Never a trap. Putting the Close in the shared chrome is what makes omitting it structurally impossible rather than something to remember.
Structure
Wire Escape to close as well. A sheet you can only leave by dragging is not leaveable by everyone.
<div class="ah-scrim" role="presentation">
<div class="ah-sheet" role="dialog" aria-modal="true" aria-labeledby="t">
<div class="ah-sheet__grab"></div>
<div class="ah-sheet__head">
<h2 class="ah-sheet__title" id="t">Share this card</h2>
<button class="ah-sheet__close" type="button" aria-label="Close">×</button>
</div>
…
</div>
</div>
Display
Small caps, pull quote, monogram, dots
This system is deliberately icon-light, and its most distinctive "icon" is the absence of one: there is no notification badge component, by design. Updates surface through the rhythm of use, never a red dot.
SmallCapsLabel
<span class="ah-caps">Last together</span>
<span class="ah-caps ah-caps--rule">With a rule</span>
<span class="ah-caps ah-caps--micro">Quietest metadata</span>
PullQuote
Nothing here is designed to grab you.
In NVC, every no is a yes to something else.
Never quotation marks. The setting is already the quotation; the marks would only shout.
<p class="ah-quote">Nothing here is designed to grab you.</p>
<p class="ah-quote ah-quote--bordered">Every no is a yes to something else.</p>
Monogram — an initial, never a photograph
Mark it aria-hidden when the person's name is already beside it — otherwise a screen reader reads the initial twice.
<span class="ah-mono" aria-hidden="true">R</span>
<span class="ah-mono ah-mono--s84 ah-mono--sunk" aria-hidden="true">M</span>
ProgressDots — where you are, with no count
Each dot is a real button. Pagination you can only reach by dragging is not reachable at all for some people (WCAG 2.5.7), and the 44px target is added invisibly.
<div class="ah-dots">
<button type="button" class="is-on" aria-label="Page 1 of 4" aria-current="true"></button>
<button type="button" aria-label="Page 2 of 4"></button>
</div>
SectionRule
This week
<p class="ah-rule-row ah-caps">This week</p>
Feedback
Toast and Notice
This is where the attention principle is load-bearing. Nothing in an Ahimsa interface appears on its own. The test is not "is it dismissible" but did the person cause this, here, now?
Toast — the acknowledgement of an action just taken
Always role="status" with aria-live="polite". Never role="alert" or aria-live="assertive": an assertive region interrupts a screen-reader user mid-sentence, which is the same harm in a different channel.
<div class="ah-toast" role="status" aria-live="polite">
<div class="ah-caption">Saved to this device. You can undo this.</div>
</div>
Notice — what replaces every banner this system refuses
Version
You are running 1.4.0.
That did not go through
The file could not be read. Nothing was changed, and your cards are as they were.
A notice sits in the document flow, where the person already is. It does not float, does not cover anything, and does not take focus. There is deliberately no UpdateBar, no InstallBar, no banner and no modal in this system.
<div class="ah-notice">
<p class="ah-notice__title">Version</p>
<div class="ah-notice__row">
<p class="ah-body">You are running 1.4.0.</p>
<button class="ah-btn ah-btn--sm ah-btn--ghost ah-hit">Check for a new one</button>
</div>
</div>