# Fluid Theme — CSS Conventions

When writing or modifying CSS for a site built with The Fluid Theme, follow these rules.

## Layer Order (never violate)

```css
@layer reset, tokens, base, layouts, components, themes, utilities;
```

## Required Patterns

- **All values from tokens**: `var(--space-4)` not `16px`, `var(--color-text)` not `#333`
- **Logical properties only**: `margin-block-start` not `margin-top`, `inline-size` not `width`
- **Data attributes for variants**: `data-variant="danger"` not `.btn--danger`
- **Component-scoped private properties**: prefix with underscore `--_card-padding`
- **All components** wrapped in `@layer components { }`

## Token Quick Reference

| Category | Examples |
|----------|---------|
| Knobs | ~20 per-site values on `:root`: `--accent`, `--accent-ink`, `--on-accent`, `--neutral-tint`, fonts, radii, `--shadow-style`, … (list: `_docs/STATUS.md`) |
| Spacing | `--space-0-5` through `--space-24` (4px base) |
| Typography | `--font-size-xs` through `--font-size-5xl`, `--hero-headline-size` (a knob) |
| Colors | `--color-text`, `--color-surface`, `--accent` (fills), `--accent-ink` (text), `--on-accent` (text on fills), `--color-success/warning/error/info` (text) with `-fill`, `-on`, `-subtle` |
| Borders | `--radius-card`, `--radius-control`, `--radius-pill` (knobs), `--radius-sm`…`--radius-xl`, `--radius-full` (circles), `--border-width` |
| Shadows | `--shadow-xs` through `--shadow-xl` |
| Motion | `--duration-fast`, `-normal`, `-slow`, `-slower`, all from `--motion-base` |
| Macro dials | `--space-section`, `--space-gutter`, `--container-content` (knobs) |

## Attribute Quick Reference

Theme axes (on `<html>`): `data-theme` (`light`/`dark`; absent = follow the OS) and `data-motion` (any element). `data-preset`, `data-palette`, `data-accent` and `data-contrast` were removed in Pass 0. Never use `var(--accent)` as a text colour: use `--accent-ink`.

| Attribute | Values | Used on | Notes |
|-----------|--------|---------|-------|
| `data-text-overflow` | `hyphenate`, `break`, `clip`, `normal` | Any element | Text overflow (`@layer utilities`). Headings already default to hyphenate; `normal` opts out. Needs `lang` on `<html>` for hyphens |
| `data-overflow` | `hidden`, `auto`, `scroll` | Any element | Box overflow (`@layer layouts`) — same attribute, different value set; one value per element |
| `data-fit-text` | (presence) | Any element | Shrink-to-fit display text; needs `assets/js/fit-text.js`. Down only, 55% floor. `window.fluidFitText()` after injecting content |
| `data-show-if` | one or more of `advertise`, `partner`, `buy-site`, `buy-domain`, `hire`, `other` | A field's wrapper in a form with `select[name="reason"]` | Shown only for those reasons (`@layer utilities`, `form.css`); never required, no constraint a hidden value can fail. `_docs/reference/components.md` |
| `.hp` (class) | — | The honeypot's wrapper, with `aria-hidden="true"` | Clipped to 1px in place (`@layer utilities`); last in the form |
| `data-arrange` | `auto` | `.hero` | Centered grid for flat hero markup (`hero__headline`/`hero__subheadline`/`hero__actions`/`hero__media` as direct children); a `hero__content` wrapper opts out. Beats `data-layout` |

**Fit text with no script.** On a page whose CSP allows no script (`default-src 'none'`), `fit-text.js` never runs, and `style-src 'self'` refuses a `style=""` the server writes instead. Size the text on the server: estimate its width from a table of glyph widths, err wide, and name a step in a `data-*` attribute that the stylesheet maps to a size. Give the text a safe break (`<wbr>`) for fonts the table did not measure. Do not measure text in CSS with scroll-driven animations: Firefox does not run them, so it gets a different size. Example: domain-landing `nameLength()` in `src/domains.js`, `data-name-length` on `<main>` (2026-10-27).

## Component File Pattern

Every component CSS file should include:
1. Header comment with usage examples
2. Base styles
3. Variants via `data-*` attributes
4. Responsive behavior (container queries preferred over media queries)
5. Reduced motion: `@media (prefers-reduced-motion: reduce) { }`

## File Locations

- Components: `src/components/[name].css`
- Sections: `src/sections/[name].css`
- After creating a new component, add `@import` to `src/fluid.css`

## Never Do

- `padding: 16px` — use a token
- `margin-top: 1rem` — use logical property (`margin-block-start`)
- `.card--elevated` — use `data-variant="elevated"`
- `:focus { outline: none }` — never remove focus outlines
- Vendor prefixes — modern browsers only
