<!-- 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. -->

# 3 · Responsive: from the smallest width up, shaped by content

Most people who open a page open it on a phone. Many of them have larger
text set, a translation turned on, or a name longer than the one in the
design. A layout that holds up is one where the content decides the size and
the screen decides the arrangement. UI design 2.6 sets the widths and limits
(line length, touch targets, no sideways scroll at 320px). This file is how
to build to them.

---

### R1 · Start at 320, then widen
**Rule:** Write the base styles for the smallest screen, then add
`min-width` media queries as the screen grows. Build and look at 320 and 375
first, then 768, then 1280 and wider. Add a breakpoint where the content
breaks (lines too long, items too cramped), not at a device's width. A phone
gets the same content and actions as a desktop, arranged differently: never
hide something people need because it didn't fit.
**Why:** A layout squeezed down from desktop carries desktop assumptions:
side-by-side columns, hover menus, long rows of buttons. On a phone they
overflow or vanish, and the person on the bus can't find the button the
desktop user sees straight away.
**Agent trap:** building the 1440px frame first and patching phones at the
end with `max-width` queries, then hiding what still doesn't fit:
```css
@media (max-width: 768px) { .filters { display: none; } }  /* phone users lose the filters */
```
**Check:** at 320px wide, `document.documentElement.scrollWidth` is not
greater than the viewport width, and `checks/layout.js` reports no overflow.
List anything hidden at small widths and where a phone user finds it
instead.

### R2 · Fluid by default, fixed only on purpose
**Rule:** Let widths come from the space available: `width: 100%` with a
`max-width`, flex with `flex-wrap`, grid with `minmax()` or `auto-fill`,
`gap` for spacing. Fix a size only for things that truly have one (an icon,
an avatar, a border). Wrap text containers in a reading width (about
`max-width: 65ch`). Give flex and grid children that hold text
`min-width: 0`, so they can shrink.
**Why:** People don't use your design's width. A fixed width that fits the
frame is too wide for a phone, which then scrolls sideways and cuts off the
right edge of every line, and too narrow for a wide screen, which leaves
the content in a strip.
**Agent trap:** a fixed width copied from the mock-up, or a flex row whose
items can't shrink below their content:
```css
.sidebar { width: 280px; }  .content { width: 960px; }        /* 1240px, at every width */
.layout { display: grid; gap: var(--space-6); }                 /* one column on a phone */
@media (min-width: 48rem) { .layout { grid-template-columns: minmax(0, 18rem) minmax(0, 1fr); } }
```
**Check:** `checks/layout.js` at 320 and 375 names each element that sticks
out and why (a fixed width, a `min-width`, text that won't wrap, a flex item
that won't shrink). Fix the element; never hide the overflow with
`overflow-x: hidden` on the page (the check flags that too).

### R3 · Content decides height
**Rule:** Never set `height` on anything that contains text or other
content. Use padding for space and `min-height` where a minimum is part of
the design. Place things with flex and grid, not absolute positioning. For
full-screen sections use `min-height: 100dvh`, not `height: 100vh`.
**Why:** Text gets longer: a translation, a larger text setting, a real
product name. In a fixed-height box it's cut off or spills over the next
thing, and the person can't read the end of the sentence or the button
label. On a phone, `100vh` is taller than the visible screen, so the bottom
of the section sits under the browser's toolbar.
**Agent trap:** copying the frame's heights, because the sample text fitted:
```css
.card { height: 296px; overflow: hidden; }   /* the third line of a longer title disappears */
.button { height: 36px; }                     /* a two-line label spills out of the button */
.card { padding: var(--space-5); }            /* the content sets the height */
```
**Check:** `checks/layout.js` flags text cut off or spilling out of its box.
Search your CSS for `height:` with a fixed value on anything that isn't an
icon, image or divider, and for `100vh`.

> **In ihumane Pro** (https://ihumane.ai/#pricing):
> - R4 · Text wraps, and truncates only on purpose
> - R5 · Images and media keep their shape and size
> - R6 · Reserve the space, so nothing jumps

## Summary checklist

- [ ] Base styles for the smallest width; `min-width` queries going up; breakpoints where content breaks.
- [ ] A phone gets the same content and actions, arranged differently.
- [ ] No fixed widths on layout; flex and grid children holding text have `min-width: 0`.
- [ ] No fixed heights on anything with text; `min-height: 100dvh`, not `100vh`.
- [ ] Long strings wrap; truncation only on purpose, with the full text reachable.
- [ ] Images sized with width and height, shape kept, served near their shown size, lazy only below the first screen.
- [ ] Nothing jumps while loading; layout shift under 0.1.
- [ ] `checks/layout.js` clean at 320, 375, 768 and 1280, or every result explained.
