# AMMO design system — agent instructions

You are building an interface for an AMMO project. This file is normative: the
words **must**, **never** and **always** are requirements, not preferences.

- Machine-readable tokens: https://styles.ammo.tools/tokens.json
- Full reference: https://styles.ammo.tools/
- Page index: https://styles.ammo.tools/llms.txt

The design language is **quiet, compact and dark-first**: neutral grey surfaces,
restrained accent colour, dense but calm controls.

---

## 1. Start from the tokens

Load the stylesheet and use its custom properties:

```html
<link rel="stylesheet" href="https://styles.ammo.tools/static/app.css">
```

**Never hard-code a hex value that exists as a token.** `#3097ef` is wrong;
`var(--primary-fill)` is right. Fetch `tokens.json` for the complete list — it
is generated from the stylesheet, so it always matches what the site renders.

Dark is the default appearance. `data-theme="light"` on `<html>` switches to
the paired light set. **Every role is defined for both** — never define a colour
for one appearance only.

---

## 2. Required metrics

These are fixed, not fluid.

| Element | Value |
| --- | --- |
| Button | 32px minimum height, `6px 10px` padding, 12px text |
| Button radius | 12px (`--button-radius`) |
| Field | 360px maximum width, 34px height, 13px text |
| Field gap | 16px between fields |
| Control radius | 8px (`--control-radius`) |
| Compact radius | 4px (`--compact-control-radius`) |
| Touch target | 44px minimum, even though pointer controls run at 32–34px |
| Baseline grid | 8px |
| Border weight | 1px |
| Sidebar | 242px fixed (272px above 851px) |
| Content column | 1300px maximum |
| Body text | 15px / 1.55, system sans |

**Never enlarge a control beyond these values.** Compact is the point.

---

## 3. Colour rules

- **One accent per screen.** `#3097ef` blue, `#6434b9` purple and `#ef3340`
  red are signals. General interface surfaces stay grey.
- **Purple appears in exactly one place:** the 3px tri-colour rule under the
  header, split into equal thirds — blue, purple, red, left to right.
- **Green means saved.** Reserve the success tone for success.
- **Status colour never travels alone.** Every state pairs its colour with
  text beside it. Colour is never the only signal.
- **Never add a second accent hue**, a gradient wash, or a drop shadow to a
  flat surface.

---

## 4. Typography

- **Rockwell is display-only.** Headings, quotes and statements. **Never set
  body copy or interface text in Rockwell.**
- Everything else is system sans at 15px / 1.55.
- Mono is `ui-monospace, SFMono-Regular, Consolas, monospace`.
- Icons are **Heroicons outline**: `fill:none`, `stroke:currentColor`,
  `stroke-width:1.5`, `aria-hidden="true"`, rendered at exactly **16×16px**
  inside controls.
- Use leading icons on buttons. Use plus, pencil and trash **alone**, unlabelled
  visually, for CRUD — with `aria-label` and `title`.

---

## 5. Behaviour is part of the brand

These interactions are specified, not optional:

- **Autosave.** Changes save after a short pause (~900ms). Feedback appears
  directly beneath the field it belongs to, never in a global banner.
- **Search.** Enter searches immediately. Three characters start a two-second
  timer. Clearing the field resets the results.
- **Refresh.** Explicit intervals only — 5 seconds, 30 seconds, 1 minute, or
  Paused. **Never a silent poll.**
- **Destructive confirmation.** One control arms the action; a **separate**
  click performs it. Switching on must never delete anything.
- **Errors stay next to the action** that failed.

---

## 6. Accessibility

- Keep headings hierarchical. Keep controls as real `button`, `a`, `input`
  and `select` elements.
- **Never remove a focus ring.** Focus is always visible, 2px, using
  `--focus`.
- Use `role="alert"` only for failures; success and progress use
  `role="status"`.
- Tabs follow the WAI-ARIA pattern: roving `tabindex`, Arrow keys move between
  tabs, `aria-controls` links each tab to its panel.
- Progress bars carry the percentage as text beside them — a bar alone cannot
  be read precisely.

---

## 7. Do not

- Do not invent a component the guide already documents. Check the routes below.
- Do not add decorative status badges, filler copy or redundant labels.
- Do not add a hover underline that competes with a selected tab state.
- Do not lower contrast on hover.
- Do not use stock photography, hand-drawn illustration, or multi-colour icon
  sets.
- Do not add OpenDesign chrome, preview labels or design-process annotations to
  product UI.

---

## 8. Where to look

| Need | Read |
| --- | --- |
| Complete token list | `tokens.json` |
| Palette, states, focus | `/color/` |
| Type scale and field metrics | `/typography/` |
| Buttons, fields, tabs, confirmation | `/components/` |
| Breadcrumbs, pagination, steps | `/navigation/` |
| Tables, stats, avatars, accordion | `/data/` |
| Status labels | `/tags/` |
| Alerts and progress | `/alerts/` |
| Radii, spacing, app shell | `/layout/` |
| Testimonials, pricing, cards | `/marketing/` |
| Landing, deck, poster, email, form | `/artifacts/` |
| Logo rules and imagery | `/brand-assets/` |

---

## 9. Portable widgets

If you are working outside this repository, these files carry the behaviour
with no build step:

- `/widgets/ammo-widgets.css`
- `/widgets/ammo-widgets.js`
- `/widgets/confirmation.html`

Override the `--ammo-*` variables to match the host theme. Tabs opt in with
`data-ammo-tabs` on a `role="tablist"`; panels are matched by `aria-controls`.
Search forms use `role="search"`. **The destructive control requires a
server-side action and CSRF token of your own** — the widget does not submit
anything by itself.

---

## 10. Before you finish

1. Does every colour come from a token?
2. Are the metrics exactly as specified in §2?
3. Does the result work in **both** appearances?
4. Is every state's colour paired with text?
5. Does it survive keyboard-only use, with visible focus throughout?
