---
version: alpha
name: Umbra
description: "Umbra by Aid Beisembin, единая дизайн-система продуктов Aid Beisembin: бенто из плиток, цвет только с ролью, APCA, стекло только поверх. Сгенерировано из tokens/ (DTCG 2025.10) скриптом pnpm design-md."
colors:
  window: "#ECEEEB"
  tile: "#FFFFFF"
  nested: "#F3F3F1"
  popover: "#FFFFFF"
  text: "#111111"
  text-muted: "#4D4D4D"
  border: "#E4E4E2"
  nav-active: "#333333"
  nav-active-foreground: "#FFFFFF"
  loader: "#666666"
  skeleton: "#EEEEEC"
  indigo: "#B49DF8"
  indigo-ink: "#6C4BD7"
  indigo-soft: "#D1C5FD"
  giants: "#EA6E38"
  giants-soft: "#FBC0A9"
  giants-ink: "#A64217"
  record: "#D92D20"
  record-foreground: "#FFFFFF"
  destructive: "#B6251B"
  destructive-foreground: "#FFFFFF"
  on-role: "#111111"
  primary: "#E4FB77"
  primary-foreground: "#111111"
  primary-ink: "#576E00"
  primary-edge: "#98B620"
  ring: "#576E00"
  window-dark: "#1C1C1C"
  tile-dark: "#0A0A0A"
  nested-dark: "#1A1A1A"
  popover-dark: "#212121"
  text-dark: "#FFFFFF"
  text-muted-dark: "#CFCFCF"
  border-dark: "#242424"
  nav-active-dark: "#383838"
  loader-dark: "#A3A3A3"
  skeleton-dark: "#1F1F1F"
  indigo-ink-dark: "#C3B1F9"
  giants-ink-dark: "#F1A17E"
  destructive-dark: "#D92D20"
  primary-ink-dark: "#E4FB77"
  primary-edge-dark: "#E4FB77"
  ring-dark: "#E4FB77"
  portfolio-primary: "#3044D8"
  portfolio-primary-foreground: "#FFFFFF"
  portfolio-primary-ink: "#3044D8"
  portfolio-primary-ink-dark: "#C4CBFF"
  portfolio-primary-edge: "#3044D8"
  portfolio-primary-edge-dark: "#C4CBFF"
typography:
  display:
    fontFamily: -apple-system, BlinkMacSystemFont, 'SF Pro Display', 'SF Pro Text', Inter, 'Helvetica Neue', system-ui, sans-serif
    fontSize: 36px
    fontWeight: 700
    lineHeight: 40px
    letterSpacing: -0.02em
  title:
    fontFamily: -apple-system, BlinkMacSystemFont, 'SF Pro Display', 'SF Pro Text', Inter, 'Helvetica Neue', system-ui, sans-serif
    fontSize: 22px
    fontWeight: 700
    lineHeight: 28px
    letterSpacing: -0.01em
  heading:
    fontFamily: -apple-system, BlinkMacSystemFont, 'SF Pro Display', 'SF Pro Text', Inter, 'Helvetica Neue', system-ui, sans-serif
    fontSize: 20px
    fontWeight: 600
    lineHeight: 28px
    letterSpacing: -0.01em
  timer:
    fontFamily: -apple-system, BlinkMacSystemFont, 'SF Pro Display', 'SF Pro Text', Inter, 'Helvetica Neue', system-ui, sans-serif
    fontSize: 32px
    fontWeight: 700
    lineHeight: 36px
    fontFeature: '"tnum" 1'
  body:
    fontFamily: -apple-system, BlinkMacSystemFont, 'SF Pro Display', 'SF Pro Text', Inter, 'Helvetica Neue', system-ui, sans-serif
    fontSize: 15px
    fontWeight: 400
    lineHeight: 22px
  body-web:
    fontFamily: -apple-system, BlinkMacSystemFont, 'SF Pro Display', 'SF Pro Text', Inter, 'Helvetica Neue', system-ui, sans-serif
    fontSize: 16px
    fontWeight: 400
    lineHeight: 24px
  label:
    fontFamily: -apple-system, BlinkMacSystemFont, 'SF Pro Display', 'SF Pro Text', Inter, 'Helvetica Neue', system-ui, sans-serif
    fontSize: 14px
    fontWeight: 500
    lineHeight: 20px
  caption:
    fontFamily: -apple-system, BlinkMacSystemFont, 'SF Pro Display', 'SF Pro Text', Inter, 'Helvetica Neue', system-ui, sans-serif
    fontSize: 13px
    fontWeight: 400
    lineHeight: 18px
  mono:
    fontFamily: "'SF Mono', ui-monospace, Menlo, 'IBM Plex Mono', monospace"
    fontSize: 12px
    fontWeight: 400
    lineHeight: 16px
    letterSpacing: 0.02em
rounded:
  frame: 56px
  panel: 40px
  tile: 24px
  nested: 16px
  chip: 8px
  pill: 9999px
  window: 17px
spacing:
  "4": 4px
  "8": 8px
  "12": 12px
  "16": 16px
  "20": 20px
  "24": 24px
  "32": 32px
  tile-gap: 8px
  tile-pad: 20px
  inner-gap: 8px
components:
  tile:
    backgroundColor: "{colors.tile}"
    textColor: "{colors.text}"
    rounded: "{rounded.tile}"
    padding: "{spacing.tile-pad}"
  tile-nested:
    backgroundColor: "{colors.nested}"
    textColor: "{colors.text}"
    rounded: "{rounded.nested}"
    padding: "{spacing.16}"
  tile-primary:
    backgroundColor: "{colors.primary}"
    textColor: "{colors.primary-foreground}"
    rounded: "{rounded.tile}"
    padding: "{spacing.tile-pad}"
  tile-giants-soft:
    backgroundColor: "{colors.giants-soft}"
    textColor: "{colors.on-role}"
    rounded: "{rounded.tile}"
    padding: "{spacing.tile-pad}"
  tile-indigo-soft:
    backgroundColor: "{colors.indigo-soft}"
    textColor: "{colors.on-role}"
    rounded: "{rounded.tile}"
    padding: "{spacing.tile-pad}"
  button-primary:
    backgroundColor: "{colors.primary}"
    textColor: "{colors.primary-foreground}"
    typography: "{typography.label}"
    rounded: "{rounded.pill}"
    height: 48px
  button-secondary:
    backgroundColor: "{colors.nested}"
    textColor: "{colors.text}"
    typography: "{typography.label}"
    rounded: "{rounded.pill}"
    height: 48px
  button-ghost:
    textColor: "{colors.text}"
    typography: "{typography.label}"
    rounded: "{rounded.pill}"
    height: 48px
  button-destructive:
    backgroundColor: "{colors.destructive}"
    textColor: "{colors.destructive-foreground}"
    typography: "{typography.label}"
    rounded: "{rounded.pill}"
    height: 48px
  button-icon:
    rounded: "{rounded.pill}"
    size: 56px
  button-hero:
    backgroundColor: "{colors.record}"
    rounded: "{rounded.pill}"
    size: 88px
  chip:
    backgroundColor: "{colors.nested}"
    textColor: "{colors.text}"
    typography: "{typography.label}"
    rounded: "{rounded.pill}"
    height: 40px
  list-row:
    textColor: "{colors.text}"
    typography: "{typography.label}"
  list-row-meta:
    textColor: "{colors.text-muted}"
    typography: "{typography.caption}"
  sidebar:
    backgroundColor: "{colors.tile}"
    rounded: "{rounded.tile}"
    width: 72px
  sidebar-item-active:
    backgroundColor: "{colors.nav-active}"
    textColor: "{colors.nav-active-foreground}"
    rounded: "{rounded.pill}"
    size: 56px
  notice-card:
    backgroundColor: "{colors.popover}"
    textColor: "{colors.text}"
    rounded: "{rounded.tile}"
  toast:
    backgroundColor: "{colors.popover}"
    textColor: "{colors.text}"
    rounded: "{rounded.tile}"
    width: 380px
  field:
    backgroundColor: "{colors.nested}"
    textColor: "{colors.text}"
    typography: "{typography.body}"
    rounded: "{rounded.pill}"
    height: 48px
  skeleton:
    backgroundColor: "{colors.skeleton}"
    rounded: "{rounded.nested}"
  spinner:
    textColor: "{colors.loader}"
  mono-label:
    textColor: "{colors.text-muted}"
    typography: "{typography.mono}"
    rounded: "{rounded.chip}"
---

# Umbra by Aid Beisembin: ДНК и правила

## Overview

Единая визуальная система для всех продуктов Aid Beisembin: приложений (ShadeNotes), сайта-портфолио и всего, что будет дальше. Собрана из фактических решений ShadeNotes (ветка `aid`, `CLAUDE.md`, `globals.css`, `docs/case/decisions.md`) и портфолио (PR #6 на Vercel, `globals.css`, `page.tsx`) на 7 ноября 2026. Ничего в самих продуктах этим документом не меняется: он фиксирует, что уже решено, и предлагает единую основу для нового

Как читать. Файл в формате DESIGN.md (спецификация Google Stitch): YAML-шапка с токенами для агентов и инструментов, затем стандартные разделы Overview, Colors, Typography, Layout, Elevation & Depth, Shapes, Components, Do's and Don'ts. Это правила, которым следует любой новый продукт. После них дополнительные разделы: «ДНК: восемь принципов», «Движение», «Иконки», «Стекло и движение», «Слой продукта» (что продукт меняет, а что нет), «Расхождения портфолио и ShadeNotes» (с предложением, как их свести) и «Источники». Слово «Предложение» помечает то, что ещё не принято

YAML-шапка генерируется из `tokens/` (W3C Design Tokens 2025.10) скриптом `pnpm design-md` и проверяется в CI; руками её не править. В шапке светлая тема и акцент ShadeNotes под основными именами, тёмная тема с суффиксом `-dark`, акцент портфолио с префиксом `portfolio-`. Тело файла правится руками и содержит принятые решения

---

## Colors

Имена даны в CSS. В Tailwind они доступны через `@theme` (Tailwind 4) или `theme.extend` (Tailwind 3.4), см. `tokens.css`

### Нейтрали: две темы

Тёмная тема это светлая наоборот: светлая держит белые плитки на сером окне, тёмная чёрные плитки на сером окне. Плитка всегда контрастнее окна, вложенная поверхность ближе к окну

| Токен | Роль | Светлая | Тёмная |
|---|---|---|---|
| `--window` | фон окна (рамка вокруг плиток) | `#ECEEEB` | `#1C1C1C` |
| `--tile` | плитка | `#FFFFFF` | `#0A0A0A` |
| `--nested` | вложенная поверхность внутри плитки, чипы, поля | `#F3F3F1` | `#1A1A1A` |
| `--popover` | меню, подсказки, сплошной вариант стекла | `#FFFFFF` | `#212121` |
| `--text` | текст | `#111111` | `#FFFFFF` |
| `--text-muted` | подписи, второстепенное (по APCA не ниже Lc 75 на окне, плитке, вложенном и поповере) | `#4D4D4D` | `#CFCFCF` |
| `--border` | только для полей ввода и редких разделителей | `#E4E4E2` | `#242424` |
| `--nav-active` | выбранный пункт сайдбара (таблетка, белая иконка); на витрине сайта Umbra вместо таблетки стеклянная капля (см. «Стекло и движение») | `#333333` | `#383838` |
| `--loader` | дуга спиннера | `#666666` | `#A3A3A3` |
| `--skeleton` | скелетоны | `#EEEEEC` | `#1F1F1F` |

Портфолио сейчас только тёмное и живёт на `#2A2A2A` (рамка) / `#0A0A0A` (основная поверхность) / `#1E1E1E` (карточки) / `#404040` (приподнятое) / текст `#9B9B9B`. Это та же трёхслойная модель окно, плитка, вложенное; в единой системе значения берутся из таблицы

### Роли цвета (общие для всех продуктов)

| Роль | Токен | Цвет | Чернила (`-ink`: иконки и текст роли на нейтральной плитке, мелкий текст только если пара проходит Lc 75) | Что значит |
|---|---|---|---|---|
| ИИ | `--indigo` | `#B49DF8` | светлая `#6C4BD7`, тёмная `#C3B1F9` | итоги, всё, что делает модель |
| Предупреждение | `--giants` | `#EA6E38` | светлая `#A64217`, тёмная `#F1A17E` | «не распознано», внимание |
| Запись | `--record` | `#D92D20` | тот же | кнопка «Остановить», точка записи; знак и текст на нём `--record-foreground` (белый в обеих темах) |
| Опасное | `--destructive` | светлая `#B6251B`, тёмная `#D92D20` (красный записи) | тот же | удаление |
| Текст на роли | `--on-role` | `#111111` | | текст на акценте, Indigo и Giants |

На красном текст белый: на `--record` и на `--destructive` (в тёмной теме опасное тот же красный `#D92D20`, Lc 77). На насыщенных Indigo и Giants текста нет, только иконки и знаки (белый на Giants даёт 3,09:1, `#111` на Indigo Lc 58). Текст роли стоит на мягком тоне: `--indigo-soft` это Indigo 60 % с белым (Lc 76 с `#111`), `--giants-soft` это Giants 45 % с белым (Lc 76,5): абзацы и списки итогов и предупреждений стоят на них. Чернила `-ink` на нейтральной плитке: иконки (не ниже Lc 45) и крупный полужирный текст от 18 px 600 (не ниже Lc 60). Мелкий текст чернилами разрешён, если пара проходит Lc 75 в `scripts/apca.ts`: решает скрипт, а не цвет. Сейчас проходят `--primary-ink` во всех продуктах и темах и `--indigo-ink`, `--giants-ink` в светлой теме; в тёмной Indigo и Giants `-ink` только крупный полужирный и иконки

Зелёного в системе нет: успех показывается галочкой цветом акцента и формой (плитка «загорается»), а не отдельным цветом. Статусные зелёные портфолио (`#22C55E`, `#DCE95E`) в единую систему не входят (см. «Расхождения портфолио и ShadeNotes», Р6)

### Акцент продукта

Единственное, что продукт задаёт сам. Три токена, остальное выводится:

| Токен | Что это | ShadeNotes |
|---|---|---|
| `--primary` | цвет акцента: главное действие, выбор, фокус | лайм `#E4FB77` |
| `--primary-foreground` | текст на акценте, по APCA не ниже Lc 75 | `#111111` |
| `--primary-ink` | акцент как текст и иконка на нейтральной плитке | светлая `#576E00`, тёмная `#E4FB77` |
| `--primary-edge` | рамка выбранного чипа на белом, где сам акцент не виден | светлая `#98B620`, тёмная `#E4FB77` |

Правило вывода: если акцент светлый (лайм, жёлтый, мятный), текст на нём `#111`, а `-ink` в светлой теме это тот же оттенок, затемнённый до Lc 75 на белом. Если акцент тёмный (кобальт, бордо), текст на нём белый, `-ink` в светлой теме сам акцент, в тёмной акцент осветляется до Lc 75 на `#0A0A0A`

Пример для кобальта портфолио `#3044D8`: `--primary-foreground: #FFFFFF` (Lc 89), `--primary-ink` светлая `#3044D8` (Lc 84 на белом), тёмная `#C4CBFF` (Lc 77 на `#0A0A0A`)

---

## Typography

Шрифт: SF Pro через системный стек `-apple-system, BlinkMacSystemFont, 'SF Pro Display', 'SF Pro Text'`, запасной Inter (latin + cyrillic) для Windows, Linux и веба в не-Apple браузерах. SF Pro в продукт не встраивается (лицензия Apple). Моноширинный для коротких системных подписей: `SF Mono, ui-monospace, Menlo`, запасной IBM Plex Mono. Вес через `font-weight`, не через разные семейства

| Роль | Размер / интерлиньяж | Вес | Трекинг | Где |
|---|---|---|---|---|
| Display | 36 / 40 | 700 | −0.02em | заголовок экрана («Встречи», название встречи) |
| Hero (`--type-hero`) | `clamp(28px, 5.6 % ширины плитки, 76px)` / 1.06, одна строка | 600 | −0.028em | только первый экран витрины сайта Umbra; в продуктах запрещён (см. ниже) |
| Title | 22 / 28 | 700 | −0.01em | заголовок раздела, шаг онбординга |
| Heading | 20 / 28 | 600 | −0.01em | заголовки в вебе и длинных текстах |
| Timer | 32 / 36 | 700 | tabular | таймер записи, крупные числа |
| Body | 15 / 22 | 400 | 0 | основной текст приложений |
| Body web | 16 / 24 | 400 | 0 | чтение на сайте |
| Label | 14 / 20 | 500 | 0 | подписи кнопок, строк, чипы |
| Caption | 13 / 18 | 400 | 0 | мета, второстепенное |
| Mono | 12 / 16 | 400 | +0.02em | системные метки (дата, место, статус), всегда `--text-muted` |

Display 36/40 это потолок для всех экранов продуктов и сайта. Единственное исключение `--type-hero`: SF Pro 600, `clamp(28px, 5.6cqi, 76px)`, интерлиньяж 1.06, трекинг −0.028em, по центру, цвет `--text`. Каждая фраза в одну строку без переноса: кегль подобран так, чтобы самая длинная фраза влезала в колонку; место под одну строку (`min-height: 1.06em`), ниже ничего не прыгает при печати. Он только на первом экране витрины сайта Umbra (интро главной с печатью фраз по кругу), в продуктах запрещён. Причина: первый экран витрины работает как обложка, у него нет рабочего содержимого, и заголовок 36 на целой пустой высоте плитки теряется. Размер считается от ширины плитки (`cqi`), а не окна: у сайта есть сайдбар, и 5.6vw окна давали лишний перенос. Токен задан в CSS сайта, а не в `tokens/`: в продукт он не попадает, классов Tailwind у него нет

Колонка текста до 760 px. Заголовки, подсказки и короткие статусы с `text-wrap: balance` (колонка около 30 символов для заголовков), абзацы с `text-wrap: pretty` (до 52 символов в плитках). Имя продукта и предлоги не отрываются: неразрывный пробел. Текст на цветном фоне не приглушается (ни `muted`, ни прозрачность) и не тоньше 500

---

## Layout

### Сетка и отступы

Сетка 8 px. Внутри группы «заголовок плюс описание» 8–12, между группами 24–32

| Токен | Значение | Что это |
|---|---|---|
| `--tile-gap` | 8 | между плитками и от края окна |
| `--tile-pad` | 20 | внутренний отступ плитки (во всём продукте один) |
| `--inner-gap` | 8 | между плиткой и вложенным |

Контролы: обычные 48 px, главные действия 56 px (иконка 24 px без подложки), мелкие 40 px (вкладки, чипы). Главная круглая кнопка продукта 88 px (запись в ShadeNotes), иконка 32. Круглые кнопки-иконки 56 px. Миниатюры состояния в списке 48 px. Сайдбар 72 px, логотип в нём 48 px с радиусом 12 (концентрично), пункты 48 px с иконкой 24. Миниатюры состояния круглые

**Внутреннее меньше внешнего** (правило 13, по М. Ильяхову). Расстояние между связанными элементами меньше, чем от них до соседней группы и до края контейнера. Группы задаёт пустота, а не рамки и линии

| Ступень | Что | Отступ |
|---|---|---|
| Пара | подпись и поле, заголовок и описание, иконка и текст | 4–12 |
| Пункты одной группы | поля формы, строки, карточки с подписью | 8–16 |
| Группы | разделы страницы, блоки плитки | 24–32 |
| Край плитки | от содержимого до края | 20 (`--tile-pad`) |

Каждая ступень заметно больше предыдущей, соседние ступени не равны: если подпись стоит в 8 от поля, следующее поле не ближе 16

Исключение: залитые контейнеры (плитки бенто, чипы, кнопки, строки на `--nested`). Их край сам отделяет группу, поэтому зазор между ними может быть меньше их внутреннего отступа: плитки с отступом 20 стоят через 8. Правило тогда действует внутри контейнера: содержимое ближе друг к другу, чем к краю

Частые ошибки:

| Плохо | Хорошо |
|---|---|
| Подпись поля ближе к предыдущему полю, чем к своему (поля через 8, подпись в 8 от поля) | Подпись в 8 от своего поля, поля через 16–24 |
| Заголовок раздела на равном расстоянии от текста сверху и снизу | Заголовок в 8–12 от своего текста, от предыдущего раздела 32 |
| Описание карточки дальше от её заголовка, чем от соседней карточки (подпись в 12, карточки через 8) | Подпись в 8–12, незалитые карточки с подписью через 24 |
| Иконка в кнопке дальше от текста, чем от края | Иконка в 8 от текста, от края 16–24 |

Проверяет `scripts/check-spacing.ts` в `pnpm check`: в собранном сайте подпись ближе к своему полю, заголовок раздела к своему тексту, подпись карточки к своей карточке, чем к соседнему блоку. Живые примеры на странице сайта «Отступы и сетка» (`/layout`)

Оптические поправки: у карточки с кнопкой-таблеткой справа правый отступ на 4 px меньше; обложка-иллюстрация заполнена на 60–70 % и стоит чуть выше геометрического центра

**Композиция без дыр.** Одна ширина колонки на странице: карточки, код, таблицы и примеры одной ширины, ни один блок не шире соседей, справа не остаётся пустой полосы; абзацы внутри колонки до 760 px. Ряды сетки полные: карточки по 2 в ряд (по 1 на узком окне), в ряду одной высоты; нечётный последний элемент на всю ширину широкой плиткой, а не обрубком (`.umbra-fill` в `base.css`). Пустая колонка допустима только как намеренный отступ по шкале

**Выравнивание подписей.** Подпись поля, подсказка и ошибка выравниваются по левому краю поля; текст внутри поля начинается с отступа 20. Так же у селектов, переключателей и карточек: подпись и контрол на одной левой линии, одинаково на всех экранах

### Каркас экрана

- **Рамка.** Приложение: окно `--window`, плитки от края через `--tile-gap`. Сайт: на десктопе внешняя рамка `--window` с отступом 8 px и основная поверхность с радиусом 56; на телефоне рамки нет, отступ 16
- **Сайдбар** 72 px отдельной плиткой слева: логотип сверху, служебное внизу (настройки, приватность, тема таблеткой). На macOS над сайдбаром подложка кнопок окна 72 × 26
- **Страница** одной плиткой: липкая шапка (Display, подпись, действия круглыми кнопками 56, чипы-фильтры), при прокрутке шапка становится стеклом, край растворяется. Прокрутка обрезана по радиусу плитки, полоса прокрутки 4 px цветом `--text` 22 %, видна при движении и скрывается через 0,7 с после остановки
- **Док действия** внизу по центру поверх контента (запись в ShadeNotes). Снизу у контента запас под него, только если контент до него доходит
- **Сетка сайта:** одна колонка до 1024, две от 1024 (320 px сайдбар плюс лента), три от 1280 (сайдбар, лента, виджет 320)

---

## Elevation & Depth

Глубина задаётся тремя плоскими слоями, а не тенями: окно `--window`, плитка `--tile`, вложенное `--nested` (см. Colors). Плитка всегда контрастнее окна, вложенная поверхность ближе к окну. Приподнятого слоя в бенто нет (Р9). Над контентом поднимается только стекло: липкая шапка, капсула записи, меню, подсказки, диалоги (принцип 5 в «ДНК»); параметры стекла и его тень в разделе «Стекло и движение». Карточки при наведении на витрине сайта поднимаются на 2 px с мягкой тенью `--glass-shadow`, но остаются плотными. Градиентов и свечений на поверхностях нет

---

## Shapes

| Токен | Значение | Что это |
|---|---|---|
| `--radius-frame` | 56 | внешняя рамка сайта на десктопе (портфолио) |
| `--radius-panel` | 40 | крупная панель внутри рамки (чат-виджет портфолио) |
| `--radius-tile` | 24 | плитка |
| `--radius-nested` | 16 | вложенное = плитка минус `--inner-gap` (концентрично) |
| `--radius-chip` | 8 | мелкие моно-метки, миниатюры 40 px |
| `--radius-pill` | 9999 | кнопки, поля, чипы, таблетки |
| `--window-radius` | 17 | скругление окна macOS (обрезка контента по углу) |

---

## Components

Каталог для реестра. У каждого: что это, состояния, из чего собран. Все уже есть в коде ShadeNotes или портфолио, кит их обобщает

| Компонент | Описание | Состояния |
|---|---|---|
| `Tile` | плитка: `--tile`, радиус 24, отступ 20; вариант `nested` (радиус 16, отступ 16, `--nested`), `role` (indigo / giants / primary, мягкие indigo-soft / giants-soft; в коде проп `tone`) | обычная, цветная роли, интерактивная (hover: плитка тон `--nested`, вложенное тон `--border`, primary и indigo 90 % непрозрачности) |
| `Page` | колонка страницы: липкая шапка, стекло при прокрутке, edge-fade, запас под док, обрезка по радиусу | шапка плоская / стекло |
| `Sidebar` | 72 px, логотип 48, пункты 48 круглые с иконкой 24, активный `--nav-active` (вариант витрины сайта: стеклянная капля `MorphIndicator`, перетекает между пунктами) | |
| `WindowBar` | подложка кнопок macOS 72 × 26 | только macOS |
| `Button` | таблетка; `primary` (акцент, текст `--primary-foreground`), `secondary` (`--nested`), `ghost` (текст), `destructive`; размеры 40 / 48 / 56; `icon` круглая | hover (primary и destructive 90 % непрозрачности, secondary тон `--border`, ghost подложка `--nested`), active (`translateY(1px)`), disabled нейтральный серый (никогда приглушённый акцент), focus-visible кольцо `--primary-ink` внутри |
| `Chip` | фильтр и вкладка, 40 px таблетка на `--nested`; выбранный: рамка 2 px `--primary-edge`, лёгкое стекло `.glass-soft`, `font-medium` | on / off, со счётчиком |
| `SearchToggle` | круглая кнопка 56 с лупой, поле выезжает влево до 280 px, лупа поворотом становится крестиком | закрыт, открыт, с текстом |
| `ListRow` | строка списка без вложенной карточки: круглая миниатюра состояния 48, заголовок Label 500, мета Caption, шеврон; две колонки от 1100 px | hover, выбрана |
| `NoticeCard` | карточка-уведомление у дока: плотное стекло, радиус 24, знак в круге 44 слева, заголовок одной строкой, одно главное действие, тихие второстепенные; появляется из размытия, уходит за `--t-exit` (0.28 с) по `--ease-in`; знак info нейтральный на `--nested`, Indigo только для того, что делает ИИ | info, warning (Giants), с иллюстрацией-подсказкой |
| `Dock` | капсула состояния поверх контента (запись): стекло, таймер tabular, полосы уровней 0–1 (источник задаёт продукт; в ShadeNotes это сегменты детектора речи), пауза 56, стоп красный со знаком `--record-foreground` | покой (кнопка 88, иконка 32), активна, пауза |
| `Glass` | материал стекла `@umbra/glass`: `.umbra-glass`, плотное `-dense`, `-soft`, индикатор `-select`, преломление `-refract` (Chromium), нажатие `.umbra-press`; обёртка `Glass` с `dense`, `soft`, `pop`, `refract`, `press` | |
| `MorphIndicator` | `@umbra/motion`: капля выбора перетекает к выбранной вкладке, чипу, пункту, бегунку; вытягивается по направлению и садится пружиной | покой, движение |
| `Spinner`, `Skeleton` | дуга без подложки; скелетоны `--skeleton` | |
| `Toast` | уведомление Sonner в стекле, радиус 24, ширина 380 | success, error (знак без красного), warning (Giants) |
| `Toggle`, `Select`, `Field` | по shadcn на Radix, таблетки, фокус внутри | |
| `Onboarding` | плитка до 600 px по центру окна, точки шага (текущая `--primary-edge`), обложка 8:3 с живым показом, шаги размытием и сдвигом; до трёх шагов, каждый в 1100 × 700 | шаг появляется, уходит; уход экрана в приложение |
| `Showcase` | показ работы продукта на первом экране (шаг знакомства): обложка 8:3, сцены по очереди, итоговый кадр держится 1,7 с и гаснет перед повтором (`useDemoScenes`), 60–70 % заполнения, оптический центр; повтор разрешён только здесь | по сценам |
| `ProcessScreen` | экран процесса (обработка, импорт, загрузка): сверху текущий шаг 22/28 со спиннером по реальному статусу, ниже настоящее содержимое процесса, факты одной строкой подписью; финал «Готово» с галочкой и явными действиями; автопереход не раньше 3 с без действия человека; без иллюстраций и выдуманного прогресса | идёт, готово, сбой |
| `Counter` | число считается вверх 0.5 с ease-out при появлении | |
| `Composer` | поле ввода ИИ-чата с живой аурой и кнопкой отправки (портфолио) | idle, busy (дыхание) |
| `Mascot` | персонаж продукта: статичный знак в приложениях, живой (настроения, взгляды, жесты) только в портфолио; у каждого продукта свой персонаж | см. «Слой продукта», «Персонажи» |

---

## Do's and Don'ts

### Правила, которые проверяются

1. **APCA.** Текст до 16 px на цвете не ниже Lc 75, крупный полужирный (от 18 px 600) не ниже Lc 60, иконки и знаки не ниже Lc 45. Лайм с `#111` даёт Lc ≈ 96. На насыщенных Indigo и Giants текста нет, только иконки; текст роли на мягких тонах `--indigo-soft` и `--giants-soft`. Мелкий текст чернилами `-ink` только там, где пара проходит Lc 75 в скрипте (в тёмной теме Indigo и Giants `-ink` только крупный полужирный). Проверяет `pnpm apca` на всех парах обеих тем и всех продуктов, исключений нет
2. **Две плитки.** Не больше двух цветных плиток на экране. Indigo вложен в показ, и это не считается третьей
3. **Отступ плитки один** во всём продукте. Шкала 8 / 12 / 16 / 20 / 24 / 32, других значений нет
4. **Без рамок и подложек.** Границы задаёт поверхность. Рамка только у выбранного чипа (2 px акцентом) и у полей ввода
5. **Текст.** Заголовок одна строка или две ровные; одиночных слов нет; текст на цвете не приглушается; неактивная кнопка серая, а не блёклый акцент
6. **Движение.** Одна кривая на появление, одна на уход; у слоя управления (индикатор выбора, бегунок, нажатие, перетекание стекла) пружины `--spring-snappy` и `--spring-smooth`, других кривых нет; суммарная искусственная задержка до 3 с; `reduced-motion` даёт статичный итог; живых элементов на экране не больше одного
7. **Окно.** Каждый экран приложения помещается в 1100 × 700 без прокрутки, если это экран-шаг (онбординг, обработка)
8. **Честность.** Нарисованный показ системного окна стилизован и уменьшен, никогда не стоит рядом с настоящим. Статус в интерфейсе только из реального источника
9. **Копирайт.** Короткие фразы: что случилось и что сделать. Кавычки «ёлочки», короткие тире, без длинных тире. Термин поясняется при первом упоминании. Абзацы, подписи, описания карточек, тосты, подсказки и пункты списков заканчиваются без точки; точки между предложениями внутри остаются. Исключения: код, цитаты, сокращения («т. д.»). Проверяет `scripts/check-periods.ts` в `pnpm check` по собранному сайту и `llms.txt`
10. **Экран процесса показывает реальное содержимое, а не иллюстрацию.** Статус сверху по реальному источнику, ниже то, что процесс производит (транскрипт, файлы), финал «Готово» с явными действиями
11. **Композиция без дыр:** одна ширина колонки на странице; ряды сетки полные; нечётный последний элемент на всю ширину. Карточки в ряду одной высоты, пустая колонка только как намеренный отступ по шкале
12. **Подпись по левому краю поля** (а не по тексту внутри): одинаково у полей, селектов, переключателей и карточек
13. **Внутреннее меньше внешнего:** связанные элементы ближе друг к другу, чем к соседней группе и к краю контейнера; ступени пара 4–12, пункты 8–16, группы 24–32, край плитки 20, соседние ступени не равны. Залитые контейнеры (плитки, чипы, кнопки) могут стоять ближе своего внутреннего отступа (Layout, «Сетка и отступы»)

### Запреты

- Градиенты и свечения на поверхностях, у кнопок, у плиток. (Исключение: одно живое существо продукта, см. «Слой продукта», «Одно живое существо».)
- Приглушённый акцент как неактивное состояние («грязная олива»)
- Иконки с подложкой, второй набор иконок, спиннеры из иконок
- Любой текст на насыщенных Indigo и Giants: на них только иконки и знаки. Мелкий текст чернилами `-ink` там, где пара не проходит Lc 75
- Декоративный цвет без роли, зелёный «для статуса»
- Красный для ошибки: ошибка показывается знаком Giants, красный только запись и удаление
- Ролик по кругу, фальшивый прогресс, задержка ради анимации. Повтор показа только на шаге знакомства (`Showcase`). На первом экране витрины сайта Umbra допустимы печать фраз по кругу (пауза вне вида и на скрытой вкладке, при `reduced-motion` первая фраза целиком) и подсказка прокрутки (шеврон, покачивание на 4 px с периодом `--t-loop`)
- Треугольник вместо шеврона (`Caret*` в заливке)
- Стрелки `Arrow*` запрещены, направление только шевроном `Caret*` bold
- Текст крупнее Display 36/40. Единственное исключение `--type-hero` на первом экране витрины сайта Umbra; в продуктах запрещено
- Стекло на стекле, стекло без контента под ним, `backdrop-filter` у плитки и карточки (предупреждение `umbra/glass-layer`); преломление у больших панелей
- Внутреннее не меньше внешнего: подпись ближе к чужому полю, чем к своему; заголовок посередине между разделами; описание карточки ближе к соседней карточке; иконка в кнопке дальше от текста, чем от края
- Пустая правая треть, блоки разной ширины на одной странице, неполные ряды разной ширины (ряды по 4, потом 3 растянутых); карточки разной высоты в одном ряду
- Иллюстрация вместо содержимого на экране процесса: там настоящий статус и настоящее содержимое (`ProcessScreen`)
- Название из первой фразы транскрипта и любые данные пользователя в интерфейсе до того, как они проверены
- Реальные встречи, записи, ключи и личные данные в фикстурах и репозиториях

---

## ДНК: восемь принципов

1. **Бенто.** Экран состоит из плиток на фоне окна. Плитка это единица смысла: одна плитка, одна задача. Между плитками воздух, а не линии. Рамок и разделителей нет: границы задают цвет поверхности и расстояние
2. **Цвет только с ролью.** Нейтральная основа, и каждый цвет на экране что-то значит: акцент продукта это главное действие и выбор, Indigo это ИИ, Giants это предупреждение, красный это запись и удаление. Декоративного цвета нет. На экране не больше двух цветных плиток одновременно
3. **Контраст по восприятию.** Читаемость текста на цвете проверяется по APCA (Lc, модель контраста по восприятию; WCAG 2 переоценивает тёмный текст на средне-светлом цвете), а не на глаз и не по WCAG 2
4. **Текст кирпичиком.** Заголовки и подсказки переносятся ровными строками, без лесенки и висящих слов. Текст короткий: что случилось и что сделать. Объяснять показом, а не абзацем
5. **Стекло только поверх.** Полупрозрачное стекло в духе Liquid Glass macOS 26 бывает только у слоя управления, который лежит над контентом: шапка при прокрутке, индикатор выбора, переключатели, капсула записи, меню, подсказки, тосты, диалоги. Поверхности плоские. Градиентов и свечений на поверхностях нет (раздел «Стекло и движение»)
6. **Движение объясняет.** Появление из размытия, сдвиг на 8 px, одна кривая ease-out. Длительности 0,2–0,35 с. Анимация показывает, что произошло, и никогда не держит человека ради красоты: нет роликов по кругу и выдуманных процентов. `prefers-reduced-motion` уважается всегда: статичный итоговый кадр
7. **Одно живое существо.** У продукта может быть один живой элемент, который дышит, двигается и реагирует: маскот в портфолио, показ работы на первом экране ShadeNotes. Всё остальное спокойно. Два живых элемента на экране спорят друг с другом
8. **Честность состояний.** Интерфейс показывает только настоящий статус. Неуверенность не трактуется как успех: «Проверим при первой записи», а не «Доступ есть». Нарисованный показ системного окна не должен быть похож на настоящее

---

## Движение

| Токен | Значение | Где |
|---|---|---|
| `--ease-out` | `cubic-bezier(0.22, 1, 0.36, 1)` | всё появление и сдвиги |
| `--ease-in` | `cubic-bezier(0.4, 0, 1, 1)` | уход |
| `--t-fast` | 0.14–0.2 с | уход, крестики, смена состояния |
| `--t-base` | 0.22–0.32 с | появление, смена экрана (0.24), карточка у кнопки (0.32) |
| `--t-exit` | 0.28 с | уход карточки-уведомления (NoticeCard), с `--ease-in` |
| `--t-slow` | 0.4–0.6 с | крупные панели, счётчики чисел (0.5), логотип |
| `--t-stagger` | 120–180 мс | шаг между элементами списка |
| `--spring-snappy` | `linear()`, перелёт 2 % | индикатор выбора, бегунок, нажатие (`--t-spring-snappy` 0.35 с) |
| `--spring-smooth` | `linear()`, перелёт 0.2 % | перетекание крупного: плавающая панель, шапка, смена темы (`--t-spring-smooth` 0.5 с) |

Появление: `opacity 0 → 1`, `scale 0.96 → 1`, `blur 6–8px → 0`, иногда `translateY(8px)`. Циклы живых элементов 1.4–2.6 с, `ease-in-out`. Итоговый кадр показа держится 1.5–2 с, перед повтором затухание, без резкого сброса. Искусственная задержка на весь путь не больше 3 с; когда результат готов, его можно открыть сразу (клик, Enter). При `prefers-reduced-motion`: 0 анимаций, показы стоят на итоговом кадре

---

## Иконки

Только `@phosphor-icons/react`, вес `fill` везде. Исключения с весом `bold`: все шевроны `Caret*` (`CaretRight`, `CaretLeft`, `CaretDown`, `CaretUp`), галочка `Check`, крестик `X`, лупа `MagnifyingGlass` (в заливке они рисуются плашкой или диском). Стрелки `Arrow*` запрещены, направление только шевроном `Caret*` bold: ни `ArrowDown`, `ArrowRight`, `ArrowUpRight`, `ArrowLeft`, ни иконок со стрелкой внутри (`CloudArrowUp`, `ArrowsClockwise`); это проверяет правило `umbra/no-arrow-icons`. Шеврон только линией `bold` (2–3 px), 20 px в поле: треугольник (`Caret*` в заливке) запрещён везде, в том числе у `Select`; это проверяет `@umbra/eslint`. Нельзя: варианты `*Circle` и `*Square`, всё, что в заливке становится сплошной плашкой (`Subtitles`, `QuestionMark`). Размеры: 24 в кнопках с текстом, главных действиях, круглых кнопках-иконках 56 px и пунктах сайдбара 48 px; 32 в главной круглой кнопке 88; 16 и 20 в мелких местах. Иконки без подложек. Индикатор ожидания только дуга-спиннер без подложки, цвет `--loader`

---

## Стекло и движение

Стекло и движение в духе Liquid Glass macOS 26 и iOS 26. Живые примеры каждого пункта на странице сайта «Стекло и анимация» (`/glass-motion`), код в реестре: `@umbra/glass` (материал, `styles/umbra/glass.css`) и `@umbra/motion` (утилиты и `MorphIndicator`, `styles/umbra/motion.css`). Эталон материала: `.aid-glass` в ShadeNotes

### Два слоя

Контент плотный: плитки, карточки, текст, образцы. Стекло только у слоя управления, который плавает поверх: шапка при прокрутке, индикатор выбора, переключатели, меню, подсказки, тосты, диалоги, плавающие панели. Стекло на стекло не кладётся: внутри стеклянной капсулы бегунок и кнопки плотные. Стекло без контента под ним не ставится: капсула над пустой плиткой это просто серая таблетка. Проверяет `umbra/glass-layer` (предупреждение): `backdrop-filter` у плитки и стекло внутри стекла по классам

### Материал

`.umbra-glass`: тон `--glass-tint` с `--glass-alpha`, `backdrop-filter: blur(var(--glass-blur)) saturate(180%)`, блик по верхней кромке `inset 0 1px 0 rgb(255 255 255 / var(--glass-rim))`, тонкая кромка `--glass-edge`, мягкая тень `0 12px 32px -12px var(--glass-shadow)`

| | Светлая | Тёмная |
|---|---|---|
| `--glass-tint` / `--glass-alpha` | `#FFFFFF` / 0.70 | `#141414` / 0.72 |
| `--glass-alpha-dense` | 0.97 | 0.97 |
| `--glass-rim` | 0.85 | 0.16 |
| `--glass-edge` | `rgba(0,0,0,.06)` | `rgba(255,255,255,.08)` |
| `--glass-shadow` | `rgba(0,0,0,.14)` | `rgba(0,0,0,.5)` |

Варианты: обычное `.umbra-glass` и плотное `.umbra-glass-dense` (для текста поверх пёстрого). Лёгкое `.umbra-glass-soft` без тени и края. Индикатор выбора `.umbra-glass-select`: тон `--text` 8 % вместо `--glass-tint`, чтобы капля читалась на однотонной плитке. Базовые `.glass`, `.glass-soft`, `.glass-dense` из `theme-base` это тот же материал без преломления и нажатия. Нижний край шапки растворяется полосой 28 px (`.edge-fade`, scroll edge effect), линии нет. Снизу так же: где прокрутка уходит под плавающее управление (капсула темы внизу сайдбара, док), её нижний край закрыт полосой размытия и затемнения тоном плитки (`backdrop-filter` и `--tile` 72 %), растворённой вверх; линии нет, растворение маской у самой прокрутки там не нужно. При `prefers-reduced-transparency` полоса сплошная `--tile`. Широкие полосы на всю ширину плитки (шапка при прокрутке) берут половину `--glass-blur`: полное размытие поверх маски прокрутки заметно дороже, а на тексте под шапкой разницы не видно

### Преломление

Лупа по краю: SVG `feDisplacementMap` в `backdrop-filter` (фильтр `#umbra-refract`, ставит `<GlassRefraction />`), класс `.umbra-glass-refract`. Только Chromium, проверка `@supports`; в Safari и Firefox только blur и saturate. Только у мелких элементов: индикатор выбора, бегунок, тост. У больших панелей нет: дорого

### Концентричность

Радиус внутреннего равен внешнему минус отступ: плитка 24, отступ 8, вложенное 16. У управления таблетки: внутренняя таблетка с отступом 4 повторяет внешнюю

### Доступность

- `prefers-reduced-transparency` (и `data-transparency="reduce"` на `<html>`): сплошной фон темы без размытия (`--popover`, индикатор выбора `--nested`)
- `prefers-reduced-motion`: без перетекания и пружин, только смена прозрачности (длительности токенов 0)
- Контраст текста на стекле по APCA проверяется на самом пёстром фоне под ним; `pnpm apca` считает худший случай, когда под стеклом сплошной цвет (текст, акцент, Indigo, Giants, красный записи, поверхности). Итог: мелкий текст (до 16 px) и подписи `--text-muted` только на плотном стекле; на обычном крупный полужирный от 18 px 600 и иконки; мелкий `--text` на обычном стекле только в тёмной теме (светлое обычное стекло над `#111` даёт Lc 65)

### Движение

Пружины только у слоя управления; появление контента в потоке остаётся на `--ease-out`

| Токен | Значение | Где |
|---|---|---|
| `--spring-snappy` | `linear()`, перелёт 2 %, `--t-spring-snappy` 0.35 с | индикатор выбора, бегунок, нажатие |
| `--spring-smooth` | `linear()`, перелёт 0.2 %, `--t-spring-smooth` 0.5 с | плавающая панель, шапка, появление поверх, смена темы |

Перелёт любой пружины не больше 4 %. В `tokens/` у пружин есть `$value` cubic-bezier для инструментов без `linear()`, в CSS точная кривая

- **Перетекание (morph).** Индикатор выбора не появляется на новом месте, а перетекает каплей (`MorphIndicator`): во время движения вытягивается по направлению (scale по оси около 1.08), садится пружиной `--spring-snappy`
- **Появление поверх.** Из `blur(8px)`, `scale 0.96` и прозрачности (`.umbra-pop-in`); уход быстрее появления, за `--t-exit` по `--ease-in` (`.umbra-pop-out`)
- **Нажатие.** `scale 0.97` и усиленный блик кромки на время нажатия (`.umbra-press`)
- **Смена страниц.** View Transitions: контент проявляется из `blur(6px)` за `--t-page`, заголовок страницы (`.umbra-vt-title`) перетекает, если он есть на обеих. Только если новая страница готова сразу (данные уже на клиенте): переход замораживает экран до отрисовки, и при загрузке по сети он ощущается долгим. Если страница грузится, выбор в навигации меняется сразу по клику, а контент появляется следом быстрым проявлением из прозрачности и сдвига 4 px за `--t-fast`, без размытия (так на сайте Umbra)
- **Смена темы.** View Transition круговым раскрытием от кнопки (`umbraThemeTransition`); при `reduced-motion` мгновенно

### Витрина сайта Umbra

На сайте правила применены так: выбранный пункт сайдбара стеклянная капля, которая перетекает между пунктами (в продуктах выбранный пункт остаётся таблеткой `--nav-active`); вкладки и чипы продуктов со стеклянным индикатором; тема стеклянной капсулой с перетекающим бегунком; капля совпадает с пунктом (тот же отступ, что у наведения, текст с отступом 12), наведение только `--nested` без стекла, на выбранном пункте наведение не рисуется; при прокрутке верхний край плитки контента уходит под полосу стекла с размытием и затемнением тоном плитки (`--tile` 80 %): она проявляется постепенно по первым 96 px и растворяется книзу длинным переходом; когда заголовок страницы уходит под край, его текст проявляется на полосе; пока полоса видна, нижнее растворение плитки снято; в интро тег автора и круглые кнопки на плотном стекле; фон интро: плывущий шум точечным дизерингом Байера 8 × 8 (пиксель 2, 4 уровня, точки `--text` 70 % на `--tile`), курсор вдавливает шум вокруг себя; показывается сразу, пауза вне вида и на скрытой вкладке, при `reduced-motion` неподвижный кадр. Вместе с печатью это одно живое существо витрины: в продуктах так нельзя; тост «Скопировано» стеклянный и появляется из размытия; карточки и образцы плотные, при наведении подъём на 2 px и мягкая тень; блоки ниже первого экрана проявляются `umbra-rise` с шагом 60 мс

---

## Слой продукта

Продукт меняет только то, что перечислено здесь. Всё остальное берётся из базы без правок

### Что задаёт продукт (`product.css`)

```css
:root {
  --product-name: "ShadeNotes";
  --primary: #E4FB77;
  --primary-foreground: #111111;
  --primary-ink: #576E00;
  --primary-edge: #98B620;
}
.dark {
  --primary-ink: #E4FB77;
  --primary-edge: #E4FB77;
}
```

Портфолио задаёт `--product-name: "Aidyn Beisembin"` и кобальт `#3044D8` (Colors, «Акцент продукта»)

Плюс логотип (SVG, плитка цвета акцента, знак на ней) и иконка приложения. Радиус плитки логотипа 52/256 (macOS сетка 824/1024)

### Одно живое существо

У продукта один живой элемент. В ShadeNotes это показ работы на первом экране (экран обработки показывает настоящий статус и содержимое, без живого показа). В портфолио это персонаж-ассистент в чате: настроения, взгляды, жесты, ответ на действия, и его аура в композере. Аура это единственное место, где разрешён мягкий градиент, потому что это не поверхность, а свет от живого существа. Второй живой элемент в тот же продукт не добавляется

### Персонажи

Семья персонажей Umbra: у каждого продукта свой персонаж, а не один на все. Персонажи разные, их объединяет общая ДНК. Исходные файлы в `brand/` (перенесены из продуктов без изменений), показ на странице сайта «Знаки продуктов» (`/characters`, раздел «Персонажи и логотипы»)

**Общая ДНК:**
- чёрный силуэт (`#0A0A0A` в знаке);
- белые глаза;
- акцент продукта: плитка под знаком или свечение у живого персонажа;
- свои детали у каждого продукта, по ним персонажа узнают

**Персонажи продуктов:**

| Продукт | Персонаж | Свои детали | Вид |
|---|---|---|---|
| ShadeNotes | знак `brand/shadenotes/mark.svg` | острый силуэт, глаза-полумесяцы, искра цветом акцента | статичный знак на лаймовой плитке, радиус 52/256; без эмоций, анимации и градиентов (решено в ShadeNotes 6 ноября 2026) |
| Портфолио | живой маскот `brand/portfolio/mascot.svg` | круглая голова с ушами, вертикальные глаза-эллипсы `#FFFEF5`, без искры | живой: это «одно живое существо» портфолио, он и есть продукт |

Искра есть только у ShadeNotes; в портфолио её не добавлять

**Живой или знак.** Правило «одно живое существо» остаётся: живой персонаж только там, где он и есть продукт (портфолио). В приложениях персонаж статичный знак (логотип, иконка, заставка, сайдбар): анимированный персонаж в инструменте отвлекает. Живой компонент живёт в продукте (`assistant-avatar` портфолио) и в реестр не идёт

**Живой персонаж портфолио:**
- Рисунок: тело тёмное с радиальными градиентами (`#050507` к `#1A132B`), снизу фиолетовый свет (`#5930AF`), мягкий край. Градиенты и свечение ауры разрешены только у живого персонажа: это свет существа, а не поверхность интерфейса. Цвета персонажа не роли интерфейса и в токены не входят
- Настроения (8), по приоритету сверху вниз:

| Настроение | Когда | Как выглядит |
|---|---|---|
| `error` | ошибка | наклон, короткая дрожь, капля пота |
| `thinking` | запрос ушёл, ответа ещё нет | наклон и покачивание, глаза разного размера, три точки загораются по очереди |
| `speaking` | идёт ответ | сжатие и растяжение с маленьким прыжком, пульсируют звуковые дуги |
| `happy` | ответ готов, «спасибо» | прыжок с растяжением, искры, румянец |
| `wink` | приветствие | подмигивание, кивок, звёздочка у глаза |
| `curious` | человек печатает или задержался на приветствии | наклон, взгляд ищет, глаза к полю ввода, «?» |
| `sleepy` | 40 с без действий | голова опущена, глубокое дыхание, поднимается «z»; любое действие будит с любопытством |
| `idle` | покой | моргание, дыхание, редкие взгляды |

- Движения (7), одной фигурой от нижнего центра: `turn`, `lean`, `hop`, `stretch`, `shake`, `settle`, `twitch`. Одно событие за раз; между событиями только моргание, дыхание и взгляды
- Взгляд: моргание (иногда двойное), микросаккады, осмотр в восьми направлениях
- Размеры: 24 и 40 (глаза и брови крупнее, без аксессуаров и циклов), 64 и 120 (аксессуары настроений, сцены только в 120)
- `prefers-reduced-motion`: событий и циклов нет, персонаж стоит
- Возможно позже: взгляд за курсором. Сейчас в коде портфолио слежение выключено, глаза двигаются только с настроениями, осмотром и взглядами

**Знак для мелких размеров.** У живого персонажа есть плоский знак для 16–24 px: силуэт без градиентов, белые глаза, на плитке акцента продукта с тем же радиусом 52/256. Для портфолио это предложение `brand/portfolio/mark-proposal.svg` (кобальтовая плитка), в продукт пока не поставлен

**Как сделать персонажа новому продукту (чек-лист по ДНК):**
- [ ] свой силуэт, чёрный, узнаётся по контуру без глаз и деталей;
- [ ] белые глаза, читаются в 16 px (в мелких размерах глаза крупнее, как у живого персонажа портфолио);
- [ ] одна своя деталь, по которой персонажа отличают от остальных; чужие детали (искра ShadeNotes, уши портфолио) не брать;
- [ ] знак на плитке акцента продукта, радиус 52/256 (сетка иконок macOS 824/1024);
- [ ] в знаке без градиентов, теней, обводок и эмоций;
- [ ] читается в 16, 24, 28 и 48 px на окне и на плитке в обеих темах;
- [ ] живой вариант только если персонаж и есть продукт; тогда градиенты ауры как свет существа и `prefers-reduced-motion` останавливает его

### Компоненты продукта

Специфичные компоненты (капсула записи, обложка кейса, виджет чата) живут в продукте, но собираются из базовых: плитка, таблетка, стекло, роли цвета, токены движения. Новый компонент продукта не вводит новых цветов, радиусов и кривых

---

## Расхождения портфолио и ShadeNotes

Что сейчас разное и как свести. Портфолио и ShadeNotes не трогаем; при следующей крупной правке портфолио подтягивается к базе

| # | Тема | ShadeNotes | Портфолио | Предложение |
|---|---|---|---|---|
| Р1 | Шрифт | SF Pro, запасной Inter | IBM Plex Sans и Mono | **Решено:** SF Pro везде, Inter запасной; моно SF Mono, запасной Plex Mono |
| Р2 | Акцент | лайм, текст `#111` | кобальт `#3044D8`, текст белый | У каждого продукта свой. Портфолио остаётся на кобальте, если это осознанный выбор; тогда `-ink` в тёмной теме осветлить до Lc 75: кобальт на `#0A0A0A` даёт Lc 18, как текст и иконка он не читается, годится только как заливка кнопки с белым текстом |
| Р3 | Иконки | Phosphor fill | lucide | Phosphor fill; lucide в портфолио заменить при следующей правке |
| Р4 | Рамки | нет, границы поверхностью | `rgba(255,255,255,.1)` на чипах и карточках | Убрать рамки, оставить поверхность `--nested`; рамка только у полей |
| Р5 | Радиусы | 24 / 16 / таблетки | 56 / 40 / 12 / 8 / 6 | Одна шкала (Shapes): 56 рамка, 40 панель, 24 плитка, 16 вложенное, 8 моно-метка, таблетки. 6 и 12 уходят |
| Р6 | Статусные цвета | роли: Indigo, Giants, red | `#22C55E` зелёный, `#DCE95E` «позитив», `#EC4362` негатив | Роли из «Роли цвета». Зелёный убрать: успех галочкой акцента. `#EC4362` заменить на `--destructive` |
| Р7 | Градиенты | запрещены | аура композера, стеклянная сфера кнопки отправки, свечение внутри панели чата | Аура остаётся как свет живого существа («Слой продукта», «Одно живое существо»). Стеклянная сфера и внутреннее свечение панели: убрать, кнопка отправки обычная таблетка акцента |
| Р8 | Темы | светлая и тёмная | только тёмная | Сайт может быть только тёмным, но токены берёт из таблицы «Нейтрали: две темы», чтобы светлую можно было включить без перекраски |
| Р9 | Поверхности | `#1C1C1C` / `#0A0A0A` / `#1A1A1A` | `#2A2A2A` / `#0A0A0A` / `#1E1E1E` / `#404040` | Значения из «Нейтрали: две темы»; `#404040` как «приподнятое» не нужно: приподнятого слоя в бенто нет |
| Р10 | Типографика | 36/40, 22/28, 15 | 30/36 600, 20/28 600, 16/24 | Одна шкала Typography: заголовок экрана 36/40 700 и на сайте тоже; 30/36 уходит. Единственное исключение: `--type-hero` (600, до 76 px, `clamp` от 34) на первом экране витрины сайта Umbra (Typography), в продуктах запрещено |
| Р11 | Моно-метки | нет | дата, место, статус моно 12/16 | Принять в базу как роль Mono (Typography): полезно для системных меток и в приложениях (таймер, даты) |
| Р12 | Кнопка shadcn | таблетки 40/48/56 | shadcn base-nova: 24–36 px, радиус `lg` | Размеры и форма из Layout и Shapes; shadcn-варианты пересобираются под них в ките |
| Р13 | Контраст тёмной темы | `--text-muted` `#B3B3B3`, `--indigo-ink` `#B49DF8`, `--giants-ink` `#EA6E38`, `--destructive` `#F97167` с чёрным текстом | текст `#9B9B9B` | **Решено** (APCA, aid-design PR #1): `--text-muted` `#CFCFCF`, `--indigo-ink` `#C3B1F9`, `--giants-ink` `#F1A17E`, `--destructive` `#D92D20` с белым, добавлен `--giants-soft`. ShadeNotes пока на `#B3B3B3` и старых `-ink`, переходит при следующей правке |
| Р14 | Персонажи | знак: острый силуэт, глаза-полумесяцы, искра | живой маскот: круглая голова с ушами, вертикальные глаза | **Решено:** у каждого продукта свой персонаж, общая ДНК (чёрный силуэт, белые глаза, акцент продукта). Знак ShadeNotes не упрощение маскота портфолио. Логотипы и иконка приложения не меняются |
| Р15 | Взгляд персонажа | статичный знак (решено 6 ноября 2026); `DESIGN.md` в репозитории ShadeNotes устарел: там маскот в сайдбаре живой | глаза за курсором не следят (выключено) | **Решено:** DESIGN.md приведён к коду, взгляд за курсором записан как «возможно позже» |

---

## Источники

- ShadeNotes: `frontend/CLAUDE.md` (разделы «Стек интерфейса»), `frontend/src/aid/styles/globals.css`, `docs/case/decisions.md`, PR #17, #18, #19 (ветка `aid`, 7 ноября 2026)
- Портфолио: PR #6 `claude/responsive-layout` (включает #4 и `main`), `src/app/globals.css` (токены Paper, 43 штуки), `src/app/page.tsx`, `src/components/ui/button.tsx`, `src/app/layout.tsx`
