diff --git a/docs/SESSION_LOG.md b/docs/SESSION_LOG.md
index 95451a3..e7975c1 100644
--- a/docs/SESSION_LOG.md
+++ b/docs/SESSION_LOG.md
@@ -4,6 +4,7 @@
с итогами, решениями, открытыми вопросами и инструкцией «как продолжить». Ведётся скиллом
`/session-handoff`.
+- [2026-09-22 20:40 — HEIC, конструктор «Картинки → PDF», белые фоны UI](sessions/2026-09-22-2040.md)
- [2026-09-05 02:31 — ffmpeg/ghostscript в образ, водяной знак PDF, снятие лимитов админа](sessions/2026-09-05-0231.md)
- [2026-07-24 23:48 — Аудит безопасности (19 фиксов) + снятие лимитов /compress, деплой на VPS](sessions/2026-07-24-2348.md)
- [2026-07-24 17:43 — Локальная копия, снятие лимитов /compress, скилл деплоя под VPS](sessions/2026-07-24-1743.md)
diff --git a/docs/sessions/2026-09-22-2040.md b/docs/sessions/2026-09-22-2040.md
new file mode 100644
index 0000000..fdf8c8d
--- /dev/null
+++ b/docs/sessions/2026-09-22-2040.md
@@ -0,0 +1,78 @@
+# 2026-09-22 20:40 — HEIC, конструктор «Картинки → PDF», белые фоны UI
+
+**Сделано:**
+- **HEIC в /compress.** Раньше `.HEIC` проходил фильтр, но падал «Ошибка при сжатии»: prebuilt
+ libvips в sharp декодирует только AV1-HEIF (AVIF), а не HEVC. Добавлен `heic-decode`
+ (libheif на WASM, без нативных зависимостей), общий хелпер `lib/image.js`.
+ В режиме «Оригинал» HEIC/BMP → JPEG с расширением `.jpg`; формат источника берётся из
+ `sharp.metadata()`, а не из MIME браузера.
+- **Конструктор «Картинки → PDF» в /pdf** (старая вкладка была нерабочей: фронт слал поле `files`,
+ бэкенд ждал `images`, и попасть туда можно было только после загрузки PDF):
+ форматы JPG/PNG/WebP/HEIC/AVIF/TIFF/GIF/BMP; drag&drop-порядок, стрелки, сортировка
+ (имя с natural-order/дата/размер), реверс, поворот по одной и всех, повтор страниц, удаление;
+ размер листа (по картинке/A4/A3/A5/Letter), ориентация, поля, качество, имя файла;
+ прогресс загрузки через XHR. Вход — кнопкой на шаге загрузки или броском одних картинок
+ в основную зону. Превью HEIC/TIFF — серверные миниатюры (`POST /pdf/thumb`).
+- **Попутные фиксы /pdf:** потерянная обёртка `
` — из-за лишнего `
`
+ `stepConfig` закрывался рано, «Выполнить» и панели торчали на шаге загрузки; `pdfIcon` был
+ недоступен из inline-`onerror` (вынесен в `window`); SVG больше не принимается.
+- **Белый фон (`--surface-800`)** у зон drag&drop, неактивных табов, кнопок-опций и карточек на
+ страницах compress, pdf, video, converter, formatter, sanitizer, parser. Активные табы —
+ светло-голубая заливка поверх белого (`linear-gradient(...), var(--surface-800)`).
+- **Всё на проде** (VPS 195.140.146.84, контейнер `wadevelop`), прод-файлы байт-в-байт = `HEAD`.
+ `heic-decode@2.1.0` установлен в контейнере (`npm install` в `/app`, node_modules на томе).
+- **Git:** два коммита запушены в Gitea (rpi4): `dabc26d` — незакоммиченная работа сессии
+ 2026-09-05 (owner-реестр, лимиты, crash-guard ffmpeg/gs, водяной знак); `c65b3f5` — эта сессия.
+
+**Изменённые / созданные файлы:**
+- [lib/image.js](../../lib/image.js) — **новый**: `isHeic()` (по ftyp-бренду + расширению), `openImage()`
+ (HEIC через heic-decode → raw в sharp; непрозрачная альфа отбрасывается, иначе всё уходит в PNG)
+- [routes/compress.js](../../routes/compress.js) — `openImage()`, общий `encodeImage()` вместо двух копий
+ if-цепочек, `sourceFormatOf(metadata)`
+- [routes/pdf.js](../../routes/pdf.js) — новый `/fromImages` (опции в JSON-поле `options`, страницы
+ `[{f, r}]`, повторы встраиваются один раз, нетронутые JPEG/PNG — байт-в-байт), `/thumb`
+ (свой лимитер 300/мин, стоит ДО общего `router.use(limiter)`), `saveResult(..., displayName)` +
+ `owner.displayName` в скачивании, сообщение о лимите файлов, фильтр без SVG
+- [public/pdf.html](../../public/pdf.html) — блок `#stepImages` (CSS `.ip-*`, JS `ip*`), панель
+ водяного знака, белые фоны
+- [public/compress.html](../../public/compress.html) — `accept` с `.heic`, превью без битой картинки,
+ белые summary/список
+- [public/video.html](../../public/video.html), [converter](../../public/converter.html),
+ [formatter](../../public/formatter.html), [sanitizer](../../public/sanitizer.html),
+ [parser](../../public/parser.html) — белые фоны
+- [package.json](../../package.json) — `heic-decode`
+
+**Решения:**
+- HEIC декодируем через `heic-decode` (WASM), а не пересобираем sharp/libvips с libde265:
+ не нужен свой libvips в образе, работает на `node:20-slim`.
+- Страницы PDF в режиме «По картинке»: 1 px = 1 pt (как было), длинная сторона ≤ 5080 pt.
+- Миниатюры HEIC/TIFF делает сервер: браузеры, кроме Safari, их не рисуют.
+- Табы `httpclient` (внутри белой панели), `regex` (уже белые), `md` (подчёркнутые) не трогали;
+ редакторы (`svgeditor`, `editor`) — полноэкранные холсты, не трогали.
+
+**Открытые вопросы / следующие шаги:**
+- [ ] Тёмная тема после смены фонов на `--surface-800` визуально не проверена (эмуляция в
+ headless не сработала) — глянуть руками.
+- [ ] В самом браузере под учёткой прод-страницы не открывались (они за авторизацией) —
+ проверено сквозными запросами внутри контейнера и headless-тестом локальной копии.
+- [ ] Серверные бэкапы этой сессии можно удалить, когда всё устоится:
+ `find /opt/sites/www/wadevelop.ru -name '*.bak-20260922-*'`.
+- [ ] Идея: смешанная сборка «PDF + картинки» в одном документе (сейчас конструктор — только картинки).
+
+**Как продолжить (для чистой сессии):**
+- Контекст: [CLAUDE.md](../../CLAUDE.md), скилл `/deploy-wadevelop`. Перед правкой сверяй md5 файла
+ с VPS: `python3 C:/Users/tream/.claude/ssh_cmd.py root@195.140.146.84 "md5sum /opt/sites/www/wadevelop.ru/"`.
+- ⚠️ Грабли Windows: Python в текстовом режиме пишет CRLF — править файлы через `open(p,'rb'/'wb')`
+ или Edit-инструментом, иначе диф раздувается и хэши с продом расходятся (в репо — LF).
+- ⚠️ Заливка через `ssh_cmd.run` + base64 в аргументе упирается в «Argument list too long» на
+ больших файлах (pdf.html ~100 КБ) — лить чанками по ~60 КБ; `ssh_cmd.run` вызывает `sys.exit`,
+ поэтому на несколько файлов — отдельный вызов на каждый (или ловить `SystemExit`).
+- Локальный стенд без MySQL: мини-express с фейковой сессией
+ (`app.use((q,r,n)=>{q.session={user:{id:1}};n()})` + `app.use('/pdf', require('./routes/pdf.js'))`
+ + `express.static('public')`), UI — headless Chrome через `puppeteer-core`
+ (`executablePath: 'C:/Program Files/Google/Chrome/Application/chrome.exe'`).
+- Проверка на проде без логина: временный express-стенд внутри контейнера
+ (`docker exec -w /app wadevelop node -e "..."` на порту 3998).
+
+**Ссылки:** https://wadevelop.ru/compress · https://wadevelop.ru/pdf · Gitea
+`http://192.168.31.200:3002/treamz/wa-dev-tools`