# Кастомизация лейаута: стили контролов, «плавающий остров», скрытие кнопок

Помимо темы (цвета/типографика/радиусы) компания настраивает **расположение и
состав элементов управления** — от классической нижней панели до популярного
«плавающего острова» с кнопками. Всё задаётся в `TenantConfig.layout`, работает
через API, редактор, MCP и дашборд, применяется в рантайме (`updateConfig`).

## 1. Поля конфига

```jsonc
{
  "layout": {
    "mode": "grid",                 // grid | spotlight | sidebar
    "selfView": "corner",           // corner | pip | hidden
    "controlsStyle": "island",      // bar | island | minimal
    "controlsAnchor": "bottom-center", // bottom-center | bottom-left | bottom-right | top-center | top-right
    "hiddenControls": ["blur", "recording", "transcript"],
    "controlOrder": ["mic", "camera", "screen", "chat", "leave"],
    "autoHideControls": true,
    "autoHideDelaySec": 5,
    "chatPosition": "right",
    "chatDefaultOpen": false,
    "chrome": "none",               // full | compact | none
    "minimized": { "enabled": true, "mode": "bubble", "position": "bottom-right" },
    "showRoomName": true,
    "showParticipantCount": true,
    "showQualityIndicator": true,
    "showTimer": true,
    "tileAspectRatio": "16:9",
    "gridMaxTiles": 9,
    "spotlightFollowSpeaker": true,
    "persistAcrossPages": false,
    "inheritHostStyles": false
  }
}
```

### Идентификаторы контролов (`controlIds`)

`mic`, `camera`, `screen`, `blur`, `chat`, `hand`, `reactions`, `participants`,
`notes`, `transcript`, `assistant`, `recording`, `fullscreen`, `newtab`,
`minimize`, `settings`, `leave`.

`hiddenControls` — полностью скрыть у тенанта (API-методы и горячие клавиши
остаются, если фича разрешена правами). `controlOrder` — явный порядок; элементы
вне списка идут после в дефолтном порядке.

## 2. Стили контролов

| `controlsStyle` | Вид |
|---|---|
| `bar` | классическая нижняя панель (по умолчанию), все кнопки в ряд |
| `island` | **плавающий остров**: компактная пилюля с ключевыми кнопками (mic, camera, screen, chat, leave) + меню «⋯» для остальных; полупрозрачный фон, blur, тень, скругление; позиция из `controlsAnchor` |
| `minimal` | только mic/camera/leave + «⋯» (для встраивания в чужой UI и мобильных) |

- `controlsAnchor` задаёт позицию острова/панели внутри виджета.
- `autoHideControls` — плавное скрытие по простою (`autoHideDelaySec`), появление
  на движение мыши/тап/фокус; не влияет на доступность (Tab/скринридер).
- На мобильных `island` автоматически сжимается; меню «⋯» — popover.
- В режиме `chrome:'none'` контролы остаются, но без шапки/фона виджета.

## 3. API и инструменты

- REST: `PATCH /v1/tenants/:id/config` `{layout:{...}}`; виджет подхватывает при
  следующем `welcome`/`config` broadcast (или `instance.updateConfig({layout})`).
- Widget API: `updateConfig({layout})`, `getState().config.layout`;
  data-атрибуты для e2e: `data-agil-controls-style`, `data-agil-controls-anchor`,
  `data-agil-control="mic|camera|..."`, `[data-agil-more]`.
- MCP: `agil_update_config`/`agil_apply_theme_to_config` (layout — часть конфига),
  `agil_explain_feature` по layout; в редакторе — секция «Лейаут».
- Дашборд: настройки лейаута в «Настройках/Встраивании»; превью через редактор.

## 4. Демо-страницы (сравнение)

| Страница | Что показывает |
|---|---|
| `/` (default) | «из коробки»: фирменный стиль AGIL Calls, светлая/тёмная тема, классический bar/остров по переключателю |
| `/guardify.html` | **пример интеграции в стиле guardify.ru**: тёмный фон, Inter, фиолетовый акцент `#8576ff`, поверхности `#0e1522/#121b2c`, моно-логотип `GUARDIFY`, встроенный звонок без собственной шапки (`chrome:'none'`), остров контролов, внутренний чат скрыт (чат остаётся в мессенджере компании), мини-окно/bubble |

Обе страницы используют один и тот же SDK/виджет и различаются только
конфигом тенанта/`options`: тема, `layout`, скрытые контролы, брендинг. Это
демонстрирует «тот же продукт — другой дизайн» без форка кода.

### Палитра Guardify (используется в демо)

| Токен | Значение |
|---|---|
| background | `#05080f` |
| surface / elevated | `#0e1522` / `#121b2c` |
| primary/accent | `#8576ff` |
| onPrimary | `#ffffff` |
| text / muted | `#f4f7fb` / `#99aac0` |
| border | `#1e2a3f` |
| radius | 12–18px |
| font | Inter (headings −0.02em, weight 700–800) |
| brand | моноширинный uppercase, letter-spacing 0.12em |

## 5. Правила

- Скрывать контролы, но не ломать клавиатурные сокращения и API — доступность
  проверяется правами (`resolveAccess`), лейаут — только визуальный слой.
- `hiddenControls` не отключает функцию: mic/camera можно переключить API-методом
  или горячей клавишей; если нужно полностью выключить — используйте
  `features.*`/`accessPolicy`.
- После смены лейаута виджет перерисовывает контролы без перезагрузки; состояние
  звонка сохраняется.
- Для iframe-встраивания `chrome:'none'` + `island` дают «нативный» вид в UI
  компании; мини-окно (`minimized.mode:'bubble'`) — поверх страниц.

## 6. Ограничения

- Позиции задаются внутри виджета; глобальное «перетаскивание» острова
  пользователем (drag-and-drop) — roadmap.
- Свободное размещение произвольных кнопок (не из `controlIds`) — roadmap
  (кастомные действия через API).
- В режиме broadcast у зрителя набор контролов ограничен правами (см.
  `docs/scaling.md` §6).
