<!-- Free part of the ihumane Front-end build module, generated from pro/front-end/ by scripts/build-free.js. Edit pro/front-end/, not this file. -->

# 2 · Structure: the right element, one component, styles that hold

The markup is what browsers, keyboards, screen readers, autofill and
translation tools read. The styles are what the next developer reads. A
screenshot shows neither, so a page can look finished while being broken for
both. UI design 2.4 sets the basic rules (buttons for actions, links for
navigation, labels for inputs). This file is about how agents get them wrong
in real code.

---

### M1 · Actions are buttons, places are links
**Rule:** If clicking it does something on this page (opens, saves, sends,
toggles), it's a `<button>`. If it takes the person somewhere with its own
address, it's an `<a href>` with the real URL. A button inside a form that
doesn't submit gets `type="button"`. A clickable card is one real link or
button inside the card, with its hit area stretched over the card, not a
`div` with a click handler around everything.
**Why:** A real button works with Tab, Enter and Space, and a screen reader
announces it as a button. A real link can be opened in a new tab, copied and
bookmarked. A `div` does none of this, so a keyboard user can't reach it and
a screen reader user doesn't know it's there.
**Agent trap:** the screenshot looks the same either way, so you reach for
whatever is quickest to style:
```jsx
<div className="card" onClick={() => router.push(`/projects/${id}`)}>…</div>   // no keyboard, no new tab
<a href="#" onClick={openMenu}>Menu</a>                                       // a link that goes nowhere
<form><button onClick={showHelp}>Help</button></form>                         // submits the form

<article className="card"><h3><a href={`/projects/${id}`} className="card__link">{name}</a></h3>…</article>
<button type="button" aria-expanded={open} onClick={toggleMenu}>Menu</button>
```
For the card, `.card { position: relative }` and
`.card__link::after { content: ""; position: absolute; inset: 0 }` make the
whole card clickable while the link stays the one real target.
**Check:** run `checks/layout.js`: it lists divs and spans with click
handlers or a pointer cursor and no role. Also search the code:
```
grep -nE "<(div|span|li|img)[^>]*onClick|href=\"#\"|href=\"javascript" <ui-files>
```
Each hit becomes a button or a link, or has a reason.

> **In ihumane Pro** (https://ihumane.ai/#pricing):
> - M2 · Headings, lists and landmarks show the shape of the page
> - M3 · One component per thing; variants are props
> - M4 · Styles the next person can follow
> - M5 · Dark mode swaps tokens, not components

## Summary checklist

- [ ] Every action is a `<button>` (with `type="button"` inside forms unless it submits); every place is an `<a href>`.
- [ ] One `h1`, headings in outline order, lists for repeated items, landmarks once each.
- [ ] One definition per part; variants are props, not copies or outside overrides.
- [ ] Styles scoped, flat, from tokens; no `!important`, inline values or ID selectors.
- [ ] Dark mode, if supported, is a token swap with `color-scheme` set, checked on every screen.
