# design/llms.txt — правила вёрстки opopa.top
Этот файл читается перед любой работой с `src/`. Если правила нет здесь — его нет.
Источник значений: `design/design.md`. Механический перенос: `src/styles/tokens.css`.
## Жёсткие запреты
1. **Ни одного литерального цвета** в `src/components`, `src/layouts`, `src/pages`.
Запрещено: `#0b0c0e`, `rgb(...)`, `hsl(...)`, `white`, `black`, `slate-800`, `blue-500`.
Разрешено: утилиты по нашим токенам (`bg-canvas`, `text-text-muted`, `border-border`).
2. **Ни одного магического размера.** Запрещено: `p-[13px]`, `mt-[37px]`, `text-[19px]`,
`w-[420px]`, любые произвольные значения в квадратных скобках для отступов, кеглей и радиусов.
Разрешено: `p-5`, `mt-7`, `text-body`, `rounded-card` — только шаги нашей шкалы.
3. **Никаких inline-стилей** (`style="..."`) кроме одного исключения: динамическая ширина
полосы прогресса чтения.
4. **Никаких новых цветов.** Палитра закрыта: 4 поверхности, 3 уровня текста, iris, ember,
2 границы. Нужен новый цвет — сначала правка `design.md`, потом `tokens.css`, потом код.
5. **Никакой светлой темы и никакого переключателя тем.** Система dark-only.
6. **Белый текст на заливке-акценте запрещён.** На `iris-deep` и `ember` текст только
`text-canvas`. Контраст белого там 3.71 и 2.33 — это провал WCAG AA.
7. **`font-display` ниже 28px запрещён.** Тело, навигация, подписи, кнопки — только `font-body`.
8. **`outline: none` без замены запрещён.** Фокус всегда виден: `shadow-focus`.
9. **Тени для разделения карточек запрещены.** Разделяем поверхностью и границей.
10. **Аврорная полоса** — только на главной, горизонтальной полосой 3px под навигацией,
один раз на страницу. Не как заливка фона, не на странице поста.
11. **Третий акцентный цвет запрещён.** Пара iris/ember — весь словарь.
12. **Текст тише `--color-text-subtle` (`#8d929b`) запрещён.**
13. **Ссылка на `/en/` без реального перевода запрещена.** Переключатель языка и `hreflang`
появляются только там, где перевод существует, иначе читатель попадает в 404.
## Как писать значения
Токены объявлены один раз в `@theme static` внутри `src/styles/tokens.css`.
**Принятый способ вёрстки — scoped `
```
Tailwind-утилиты не запрещены, но в проекте не используются. Если берёте их —
только по нашим токенам (`bg-card`, `text-body`), никогда чужую палитру.
Единственное место с `!important` — `Prose.astro`, перекрытие фона Shiki.
## Карта: что нужно → какой токен
| Нужно | Токен |
|---|---|
| фон страницы | `var(--color-canvas)` |
| фон секции, шапки, подвала | `var(--color-surface)` |
| фон карточки, врезки | `var(--color-card)` |
| фон блока кода | `var(--color-code)` |
| основной текст | `var(--color-text)` |
| вторичный текст, лид | `var(--color-text-muted)` |
| дата, метаданные, подпись | `var(--color-text-subtle)` |
| ссылка, активный пункт | `var(--color-iris)` |
| заливка primary-кнопки | `var(--color-iris-deep)` + текст `var(--color-canvas)` |
| «Артефакт», цифры, наш вывод | `var(--color-ember)` |
| подложка пилюли-тега | `var(--color-iris-wash)` / `var(--color-ember-wash)` |
| декоративная граница | `var(--color-border)` |
| граница кликабельного | `var(--color-border-strong)` |
| скругление кнопки/тега | `var(--radius-pill)` |
| скругление карточки | `var(--radius-card)` |
| скругление кода/инпута | `var(--radius-code)` |
| кегль текста | `var(--text-body)` + `var(--text-body--line-height)` |
| кегль лида | `var(--text-lead)` |
| заголовки | `var(--text-h1)`…`var(--text-h4)`, `var(--text-display)` |
| шаг отступа | `var(--spacing-1)`…`var(--spacing-10)` (4/8/12/16/24/32/48/64/96/144px) |
| ширина колонки текста | `var(--max-prose)` (68ch) |
| ширина страницы | `var(--max-page)` (1200px) |
Каждый кегль идёт в паре со своим `--text-*--line-height` и `--text-*--letter-spacing`.
## Компоненты
Список закрыт. Нужен новый — сначала описать в `design.md` → Components, потом верстать.
`Primary Button` · `Ghost Button` · `Post Row` · `Prose` · `Code Block` · `Artifact Block` ·
`Callout` · `Tag Pill` · `Header` · `Footer` · `Aurora Strip` · `Reading Progress` ·
`Table of Contents` · `Subscribe` · `Intent Nav` · `Month Group` · `Search` · `Feed Filter` · `Related` · `FileStat`
## Хорошо / плохо
**Плохо**
```astro
{title}
{description}
```
Почему плохо: литеральные цвета, inline-стиль, магические размеры, чужая палитра Tailwind,
белый текст вместо токена, кегль мимо шкалы.
## Самопроверка перед коммитом
```bash
# 1. Литеральные цвета и магические px в компонентах — должно быть пусто
grep -rnE '#[0-9a-fA-F]{3,8}|rgb\(|hsl\(|\[[0-9]+px\]' src/components src/layouts src/pages
# 2. Inline-стили — должно быть пусто (кроме Reading Progress)
grep -rn 'style="' src/components src/layouts src/pages
# 3. Классы чужой палитры Tailwind — должно быть пусто
grep -rnE '(bg|text|border)-(slate|gray|zinc|neutral|stone|blue|indigo|red|green)-[0-9]' src/
# 4. Сборка
npm run build
```
## Приложения
- `design/design.md` — источник правды по токенам и компонентам.
- `design/donors/huly-DESIGN.md` — стиль-донор (палитра, ритм, pill-геометрия).
- `design/references/intercom-onboarding/` — структурный референс (композиция, микрокопирайт).
Палитру оттуда НЕ брать: он light-first.
- shadcn/ui llms.txt: https://ui.shadcn.com/llms.txt — берём паттерны примитивов
(composition, `data-*` состояния, слоты), ставим только те React-примитивы, которые
реально нужны; стили всегда переопределяются нашими токенами.