diff --git a/README.md b/README.md index adc6736..c12e863 100644 --- a/README.md +++ b/README.md @@ -21,7 +21,7 @@ npm run test:e2e ``` - `npm run check`: production build, проверки контента и ассетов, тесты Sites Worker. -- `npm run test:e2e`: Playwright Chromium, Firefox, WebKit и эмуляция iOS; 14 страниц, навигация, скролл, палитры, работа анимаций и ошибки доступа к буферу обмена. +- `npm run test:e2e`: Playwright Chromium, Firefox, WebKit и эмуляция iOS; 15 страниц, навигация, скролл, палитры, работа анимаций и ошибки доступа к буферу обмена. - `GITHUB_PAGES=true npm run build`: production build с базовым URL /ERDCBB/. - `npm run optimize:video`: отдельная команда обработки видео (не запускается при обычной сборке). diff --git a/krdv-guidelines-prototype/audits/2026-10-14-figma-review.md b/krdv-guidelines-prototype/audits/2026-10-14-figma-review.md new file mode 100644 index 0000000..6a49d4d --- /dev/null +++ b/krdv-guidelines-prototype/audits/2026-10-14-figma-review.md @@ -0,0 +1,38 @@ +# ERDCBB — сверка с замечаниями из Figma «бб крдв» + +Источник: переданные пользователем 14 октября 2026 г. четыре полных снимка полотна Figma; файл: euwFVS5aMubI1z8HQo7fsG, node 0:1. Дополнительно сопоставлено с основным React-исходником проекта. + +## Статусы относительно опубликованной версии до этого PR + +| Раздел | Замечание в Figma | Статус до PR | Исправление в PR | +|---|---|---|---| +| 00 Обзор | Заменить вводный текст | Выполнено | Сохранён утверждённый текст | +| 00 Обзор | Удалить карточку «Руководство» с тегами | Не выполнено полностью | Блок целиком удалён; теперь есть только «Содержание» и «Материалы для скачивания» | +| 00 Обзор | Вместо обрезки описаний и многоточий показать нормальные тексты | Частично | Убрано принудительное обрезание CSS; высота карточек адаптируется к контенту | +| 00 Обзор | В каталоге «Преференциальные режимы» | Выполнено | Сохранено | +| 01 Позиционирование | Убрать лишние четыре карточки принципов и старый текст | Выполнено | Сохранено без повторного добавления | +| 02 Логотип | Русский и английский вертикальный — основной; горизонтальный — дополнительный | Выполнено | Исходники и роли не изменены | +| 02 Логотип | Убрать отдельный логотип-лотос в списке файлов | Выполнено | Не возвращался | +| 06 Типографика | Удалить кнопку и блок скачивания коммерческих шрифтов | Выполнено | Скачивания не возвращались | +| 09 Рекламные материалы | Убрать прессволл | Выполнено | Не возвращался | +| 09 Рекламные материалы | Обновить обложки лифлетов | Выполнено | Сохранены 10 актуальных оригиналов с WebP-превью | +| 09 Рекламные материалы | Дополнительно добавить пример наружной рекламы | Остаётся открытым | В заметке указан внутренний URL Yandex Disk (/client/disk/...). Без доступного внешнего источника и пригодного изображения не вставлен неутверждённый макет | +| 10 Мерч | Обновить иллюстрации, уточнить, что это примеры от ДВК | Выполнено | Сохранены все 41 исходных слайда, пояснения ДВК; ссылка Miro ранее удалена по отдельному указанию | +| 11 Товарный знак | Переименовать раздел вместо «Сделано в ТОР СПВ» | Не выполнено | Название изменено на «Товарный знак», URL /#/made сохранён | +| 11 Товарный знак | Улучшить контраст чёрных знаков; добавить знак ДВ и Арктики | Выполнено | Исходные четыре SVG и стили не тронуты | +| 12 Фотостиль | Удалить неподходящее фото аудитории | Не выполнено | Исключён photostyle-composition-6.webp, сохранён одобренный кадр photostyle-composition-7.webp | +| 12 Фотостиль | Автор и источник как сноска | Частично | Сноска вне галереи уже была; уточнено название источника «Фото-хост-агентство РИА Новости» | +| 13 Дизайн соцсетей | Вместо «Приложение» сделать самостоятельный раздел «Дизайн соцсетей», убрать пример поста | Частично | Переименовано, изображение поста ранее было убрано; контакты перенесены в отдельный раздел | +| 14 Контакты | Отдельная глава, оставить название компании, erdc.ru и дату обновления | Не выполнено как отдельная глава | Создан отдельный маршрут /#/contacts с номером 14 и утверждёнными полями, дата 01.11.2026 | + +## Совместимость + +Старый /#/appendix сохраняет страницу соцсетей под новым названием, прямой маршрут /#/contacts открывает отдельную главу; /#/appendix/contacts по-прежнему разрешается в контакты. Все исходные логотипы, размеры, цвета и скачиваемые файлы сохранены. + +## Тестирование + +Обновлены проверка количества глав, маршруты, тесты редакционных указаний, каталог, сноска и фото, ранее опубликованные загрузки, браузерная навигация. До merge требуются полные тесты Chromium / Firefox / WebKit / мобильных эмуляций и финальный контроль развёртывания GitHub Pages. + +## Открытый внешний ресурс + +**Пример наружной рекламы** остаётся ожидающим предоставления общедоступной ссылки или файла в качестве оригинала. Приватный путь Yandex Disk из аннотации Figma не даёт доступа к подтверждённому визуальному материалу. Без оригинала не следует подменять его случайной картинкой либо копией маленького скриншота. diff --git a/krdv-guidelines-prototype/brandbook-map.md b/krdv-guidelines-prototype/brandbook-map.md index c00b74a..5ee0531 100644 --- a/krdv-guidelines-prototype/brandbook-map.md +++ b/krdv-guidelines-prototype/brandbook-map.md @@ -4,7 +4,7 @@ | № | Раздел | Маршрут | Подразделы | |---|---|---|---| -| 00 | Обзор | `#/overview` | Руководство, Содержание, Материалы для скачивания | +| 00 | Обзор | `#/overview` | Содержание, Материалы для скачивания | | 01 | Позиционирование | `#/positioning` | Бренд-обещание, Основные принципы | | 02 | Логотип | `#/logo` | Полная версия, Версии, Использование, Охранное поле, Фоны и цвет, Запреты | | 03 | Дочерние общества | `#/subsidiaries` | Основная версия, Дополнительная версия, Англоязычная горизонтальная, Англоязычная вертикальная | @@ -14,10 +14,11 @@ | 07 | Оформление текста | `#/text` | Кавычки и тире, Валюты и телефоны, Сокращения и география, Контрольные примеры, Типограф | | 08 | Корпоративные материалы | `#/corporate` | Визитки, Визитки с QR-кодом, Визитки ДО, Бланки ДО | | 09 | Рекламные материалы | `#/advertising` | Лифлеты, Роллап, Навигация кабинетов, Режимник, Наградные документы | -| 10 | Мерч | `#/merch` | Все 41 слайда исходной презентации (02–42) | -| 11 | Сделано в ТОР СПВ | `#/made` | Знак, Сделано на Дальнем Востоке и в Арктике, Применение | +| 10 | Мерч | `#/merch` | 41 слайд исходной презентации (02–42) | +| 11 | Товарный знак | `#/made` | Знак «Сделано в ТОР СПВ», Сделано на Дальнем Востоке и в Арктике, Применение | | 12 | Фотостиль | `#/photostyle` | Принципы съемки, Единый прогресс, Выступления, Природа, Люди | -| 13 | Приложение | `#/appendix` | Социальные сети, Контакты | +| 13 | Дизайн соцсетей | `#/appendix` | Социальные сети | +| 14 | Контакты | `#/contacts` | Контакты и обратная связь | ## Материалы @@ -28,4 +29,4 @@ - `public/fonts` — шрифты, используемые для отображения. Публичные ZIP-архивы и кнопки скачивания шрифтов удалены; правовой статус самих web-файлов требует проверки. - `src/data/resources.js` — все внешние архивы и файлы. -В каталоге раздел `Режимы` подписан **«Преференциальные режимы»**. Вертикальные версии логотипа RU/EN — основные, горизонтальные — дополнительные. Исторические URL сопоставляются текущим страницам через `routeAliases`. +В каталоге раздел `Режимы` подписан **«Преференциальные режимы»**. Вертикальные версии логотипа RU/EN — основные, горизонтальные — дополнительные. Исторические URL сопоставляются текущим страницам через `routeAliases`. Старый адрес `#/appendix/contacts` по-прежнему открывает «Контакты». diff --git a/krdv-guidelines-prototype/public/assets/brandbook/raster/photostyle-composition-6.webp b/krdv-guidelines-prototype/public/assets/brandbook/raster/photostyle-composition-6.webp deleted file mode 100644 index 2bf0339..0000000 Binary files a/krdv-guidelines-prototype/public/assets/brandbook/raster/photostyle-composition-6.webp and /dev/null differ diff --git a/krdv-guidelines-prototype/src/components/GuidelinePage.jsx b/krdv-guidelines-prototype/src/components/GuidelinePage.jsx index d2310cd..8c4c6e6 100644 --- a/krdv-guidelines-prototype/src/components/GuidelinePage.jsx +++ b/krdv-guidelines-prototype/src/components/GuidelinePage.jsx @@ -16,7 +16,7 @@ function GuidelinePage({ page, activePageId, navigate }) { return (
-
+
{page.heroImage ? : null} {page.heroVideo ? : null} {page.heroAnimation === "colorTiles" ? : null} diff --git a/krdv-guidelines-prototype/src/data/pages.js b/krdv-guidelines-prototype/src/data/pages.js index aea7291..1491462 100644 --- a/krdv-guidelines-prototype/src/data/pages.js +++ b/krdv-guidelines-prototype/src/data/pages.js @@ -10,12 +10,6 @@ const pagesData = [ heroLibrary: "overview-panels", intro: "Руководство по визуальной системе АО «КРДВ»: логотип, цвета, типографика, фотостиль, носители и материалы для скачивания.", sections: [ - { - id: "guide", - title: "Руководство", - lead: "Руководство по использованию фирменного стиля АО «КРДВ».", - paragraphs: ["Единые правила помогают сохранять узнаваемость корпорации во внутренних и внешних коммуникациях, печатных материалах, презентациях, рекламных носителях и цифровой среде."], - }, { id: "contents", title: "Содержание", @@ -442,7 +436,7 @@ const pagesData = [ number: "10", title: "Мерч", heroImage: "cover-merch.jpg", - directoryDescription: "Все 41 слайда презентации с примерами брендированной продукции.", + directoryDescription: "41 слайд презентации с примерами брендированной продукции.", intro: "Примеры брендированной продукции КРДВ и дочерних обществ.", sections: [ { @@ -501,7 +495,7 @@ const pagesData = [ { id: "made", number: "11", - title: "Сделано в ТОР СПВ", + title: "Товарный знак", heroImage: "cover-made.jpg", directoryDescription: "Товарные знаки регионального происхождения продукции.", intro: "Фирменные знаки «Сделано в ТОР СПВ» и «Сделано на Дальнем Востоке и в Арктике»: версии, скачивание и примеры использования.", @@ -578,7 +572,7 @@ const pagesData = [ "Неподходящий кадр: участники не вовлечены, людей много и лица не в фокусе, композиция неудачная, на переднем плане затылки или обилие текстур мешает считыванию.", ], assetImages: photostyleImages.events, - photoCredit: { author: "Максим Блинов", source: "Фотохост-агентство РИА Новости" }, + photoCredit: { author: "Максим Блинов", source: "Фото-хост-агентство РИА Новости" }, }, { id: "nature", @@ -608,9 +602,9 @@ const pagesData = [ { id: "appendix", number: "13", - title: "Приложение", + title: "Дизайн соцсетей", heroImage: "cover-appendix.jpg", - directoryDescription: "Гайд по оформлению соцсетей и контакты КРДВ.", + directoryDescription: "Гайд по дизайну публикаций и карточек в социальных сетях КРДВ.", intro: "Гайд по оформлению публикаций в соцсетях.", sections: [ { @@ -619,6 +613,16 @@ const pagesData = [ paragraphs: ["Гайд помогает сохранять узнаваемый визуальный язык в постах, карточках, обложках и регулярных публикациях КРДВ."], resourceLinks: ["socialGuide"], }, + ], + }, + { + id: "contacts", + number: "14", + title: "Контакты", + heroSolid: true, + directoryDescription: "Информация об АО «КРДВ», дата обновления брендбука и обратная связь.", + intro: "Контактная информация и обратная связь по фирменному стилю КРДВ.", + sections: [ { id: "contacts", title: "Контакты", @@ -648,6 +652,7 @@ const routeAliases = { editorial: "text", graphics: "regimes", social: "appendix", + contact: "contacts", gallery: "overview", typography: "typography", color: "color", @@ -660,7 +665,9 @@ const routeAliases = { }; function resolvePageId(hash) { - const route = String(hash || "").replace(/^#\/?/, "").split("/")[0]; + const fragments = String(hash || "").replace(/^#\/?/, "").split("/"); + const route = fragments[0]; + if (route === "appendix" && fragments[1] === "contacts") return "contacts"; const normalized = routeAliases[route] || route; return pagesById[normalized] ? normalized : "overview"; } diff --git a/krdv-guidelines-prototype/src/data/resources.js b/krdv-guidelines-prototype/src/data/resources.js index 7411a87..2ae80c8 100644 --- a/krdv-guidelines-prototype/src/data/resources.js +++ b/krdv-guidelines-prototype/src/data/resources.js @@ -324,7 +324,6 @@ const photostyleImages = { { title: "Инфраструктура города", caption: "Мост, портовый и городской масштаб Дальнего Востока.", file: "photostyle-composition-12.webp" }, ], events: [ - { title: "Деловой стенд", caption: "Коммуникационный кадр с выставки или форума.", file: "photostyle-composition-6.webp" }, { title: "Вовлеченная аудитория", caption: "Событие с участниками, которые включены в процесс.", file: "photostyle-composition-7.webp" }, ], nature: [ diff --git a/krdv-guidelines-prototype/src/styles/hero.css b/krdv-guidelines-prototype/src/styles/hero.css index fee8d70..c59dc86 100644 --- a/krdv-guidelines-prototype/src/styles/hero.css +++ b/krdv-guidelines-prototype/src/styles/hero.css @@ -365,3 +365,9 @@ line-height: 1.05; overflow-wrap: anywhere; } + +/* Contact chapter is intentionally plain, matching the separate navy header in Figma. */ +.hero-band[data-solid-cover="true"] { + height: 280px; + background: #001d37; +} diff --git a/krdv-guidelines-prototype/src/styles/responsive.css b/krdv-guidelines-prototype/src/styles/responsive.css index 6e0c77d..745a18a 100644 --- a/krdv-guidelines-prototype/src/styles/responsive.css +++ b/krdv-guidelines-prototype/src/styles/responsive.css @@ -498,3 +498,9 @@ .page-scroll { scroll-padding-top: 72px; } .content-section { scroll-margin-top: 72px; } } + +@media (max-width: 860px) { + .hero-band[data-solid-cover="true"] { + height: 220px; + } +} diff --git a/krdv-guidelines-prototype/src/styles/sections.css b/krdv-guidelines-prototype/src/styles/sections.css index 1af619e..9d3fbcc 100644 --- a/krdv-guidelines-prototype/src/styles/sections.css +++ b/krdv-guidelines-prototype/src/styles/sections.css @@ -183,7 +183,7 @@ min-width: 0; min-height: 330px; display: grid; - grid-template-rows: 132px 1fr; + grid-template-rows: 132px auto; border: 1px solid var(--line); padding: 0; background: #ffffff; @@ -291,10 +291,6 @@ background: linear-gradient(90deg, #001d37 0 51%, #0056a2 51% 86%, #de2327 86%); } -.directory-visual.has-cover + .directory-copy p { - -webkit-line-clamp: 2; -} - .directory-copy { display: grid; grid-template-columns: 1fr; @@ -317,19 +313,15 @@ } .directory-copy p { - display: -webkit-box; width: 100%; min-width: 0; max-width: 100%; - overflow: hidden; - overflow-wrap: anywhere; + overflow-wrap: break-word; hyphens: auto; white-space: normal; color: var(--muted); font-size: 15px; line-height: 1.4; - -webkit-box-orient: vertical; - -webkit-line-clamp: 3; } .directory-copy small { @@ -565,3 +557,8 @@ object-fit: cover; object-position: center 58%; } + +/* The independent contacts chapter uses its own restrained navy cover. */ +.directory-visual[data-topic="contacts"] .directory-fallback { + background: #001d37; +} diff --git a/krdv-guidelines-prototype/src/styles/workbench.css b/krdv-guidelines-prototype/src/styles/workbench.css index b3f6c0c..ac6fd4d 100644 --- a/krdv-guidelines-prototype/src/styles/workbench.css +++ b/krdv-guidelines-prototype/src/styles/workbench.css @@ -188,7 +188,7 @@ } .directory-copy { - grid-template-rows: auto minmax(0, 1fr) auto; + grid-template-rows: auto auto 1fr; align-content: stretch; } diff --git a/krdv-guidelines-prototype/tests/brandbook.test.mjs b/krdv-guidelines-prototype/tests/brandbook.test.mjs index dea2462..46b0526 100644 --- a/krdv-guidelines-prototype/tests/brandbook.test.mjs +++ b/krdv-guidelines-prototype/tests/brandbook.test.mjs @@ -15,7 +15,7 @@ function asset(relativeFile) { assert.ok(statSync(full).size > 0, "Empty: " + relativeFile); } test("pages and sections have unique stable identities", () => { - assert.equal(pagesData.length, 14); + assert.equal(pagesData.length, 15); assert.equal(new Set(pagesData.map((p) => p.id)).size, pagesData.length); pagesData.forEach((page, index) => { assert.equal(page.number, String(index).padStart(2, "0")); @@ -34,6 +34,7 @@ test("canonical and historic routes resolve to real pages", () => { assert.equal(resolvePageId("#/" + alias), target); } assert.equal(resolvePageId("#/invalid"), "overview"); + assert.equal(resolvePageId("#/appendix/contacts"), "contacts"); }); test("all downloadable logos, marks, fonts, imagery and videos exist", () => { const collections = [ @@ -86,9 +87,15 @@ test("approved editorial changes are represented in the page data", () => { assert.equal(pagesById.positioning.sections.find((s) => s.id === "principles").cards, undefined); assert.equal(pagesById.typography.sections.some((s) => s.id === "font-files"), false); assert.equal(pagesById.advertising.sections.some((s) => s.id === "presswall"), false); - assert.equal(pagesById.appendix.sections.find((s) => s.id === "social").assetImages, undefined); - assert.equal(pagesById.appendix.sections.find((s) => s.id === "contacts").contacts.updatedAt, "2026-11-01"); + assert.equal(pagesById.overview.sections.some((s) => s.id === "guide"), false); + assert.equal(pagesById.made.title, "Товарный знак"); + assert.equal(pagesById.appendix.title, "Дизайн соцсетей"); + assert.equal(pagesById.appendix.sections.length, 1); + assert.equal(pagesById.appendix.sections[0].assetImages, undefined); + assert.equal(pagesById.contacts.title, "Контакты"); + assert.equal(pagesById.contacts.sections[0].contacts.updatedAt, "2026-11-01"); assert.equal(pagesById.photostyle.sections.find((s) => s.id === "events").photoCredit.author, "Максим Блинов"); + assert.deepEqual(pagesById.photostyle.sections.find((s) => s.id === "events").assetImages.map((item) => item.file), ["photostyle-composition-7.webp"]); for (const page of pagesData) { assert.ok(page.directoryDescription?.length > 15 && page.directoryDescription.length < 100); } @@ -134,11 +141,11 @@ test("public download resources are accessible share links, not internal login f assert.equal(businessCard.resourceLinks, undefined); }); -test("all fourteen sections have an intentional cover; nine editorial JPEGs keep original logo assets untouched", () => { +test("all fifteen chapters have intentional covers without changing original logo assets", () => { const illustrated = ["positioning","regimes","typography","text","corporate","advertising","merch","made","appendix"]; assert.deepEqual(pagesData.filter(p => p.heroImage).map(p => p.id), illustrated); for (const page of pagesData) { - assert.ok(page.heroVideo || page.heroImage || page.heroAnimation || page.heroLibrary, "Missing cover: " + page.id); + assert.ok(page.heroVideo || page.heroImage || page.heroAnimation || page.heroLibrary || page.heroSolid, "Missing cover: " + page.id); if (page.heroImage) assert.match(page.heroImage, /^cover-[a-z-]+\.jpg$/); } }); diff --git a/krdv-guidelines-prototype/tests/e2e/brandbook.spec.mjs b/krdv-guidelines-prototype/tests/e2e/brandbook.spec.mjs index 70d8067..3681a91 100644 --- a/krdv-guidelines-prototype/tests/e2e/brandbook.spec.mjs +++ b/krdv-guidelines-prototype/tests/e2e/brandbook.spec.mjs @@ -12,9 +12,10 @@ const titles = [ ["corporate", "Корпоративные материалы"], ["advertising", "Рекламные материалы"], ["merch", "Мерч"], - ["made", "Сделано в ТОР СПВ"], + ["made", "Товарный знак"], ["photostyle", "Фотостиль"], - ["appendix", "Приложение"], + ["appendix", "Дизайн соцсетей"], + ["contacts", "Контакты"], ]; async function ready(page) { @@ -47,7 +48,7 @@ test("all sections load with page titles and without horizontal overflow", async test("navigation and browser history preserve routes", async ({ page, isMobile }) => { await page.goto("/#/"); await ready(page); - await expect(page.locator(".directory-card")).toHaveCount(14); + await expect(page.locator(".directory-card")).toHaveCount(15); if (isMobile) await page.locator(".mobile-menu-button").click(); await page.locator(".nav-parent").filter({ hasText: "Логотип" }).click(); await expect(page).toHaveURL(/#\/logo$/); @@ -129,7 +130,7 @@ test("requested editorial cleanup is reflected on all affected pages", async ({ await page.goto("/#/overview"); await ready(page); await expect(page.locator(".intro-panel")).toContainText("Руководство по визуальной системе"); - await expect(page.locator("#guide .keyword-wall")).toHaveCount(0); + await expect(page.locator("#guide")).toHaveCount(0); await expect(page.locator("#contents .lead-copy")).toContainText("Руководство по использованию фирменного стиля"); await expect(page.locator("#contents .directory-copy h3")).toContainText(["Обзор", "Позиционирование", "Логотип", "Дочерние общества", "Преференциальные режимы"]); // Snapshot all summaries atomically; positional locators can drift during layout transitions. @@ -140,7 +141,7 @@ test("requested editorial cleanup is reflected on all affected pages", async ({ scrollWidth: node.scrollWidth, })) ); - expect(summaries).toHaveLength(14); + expect(summaries).toHaveLength(15); for (const summary of summaries) { expect(summary.text).not.toContain("..."); expect(summary.scrollWidth).toBeLessThanOrEqual(summary.width + 1); @@ -170,18 +171,28 @@ test("requested editorial cleanup is reflected on all affected pages", async ({ await page.goto("/#/photostyle"); await ready(page); - await expect(page.locator("#events .asset-image-card")).toHaveCount(2); + await expect(page.locator("#events .asset-image-card")).toHaveCount(1); await expect(page.locator("#events .photo-credit")).toContainText("Автор фото:"); await expect(page.locator("#events .photo-credit")).toContainText("Максим Блинов"); - await expect(page.locator("#events .photo-credit")).toContainText("Фотохост-агентство РИА Новости"); + await expect(page.locator("#events .photo-credit")).toContainText("Фото-хост-агентство РИА Новости"); await page.goto("/#/appendix"); await ready(page); + await expect(page.locator(".hero-title")).toHaveText("Дизайн соцсетей"); await expect(page.locator(".intro-panel")).toContainText("Гайд по оформлению публикаций в соцсетях"); await expect(page.locator("#social .asset-image-grid")).toHaveCount(0); + await expect(page.locator("#contacts")).toHaveCount(0); + + await page.goto("/#/contacts"); + await ready(page); + await expect(page.locator(".hero-title")).toHaveText("Контакты"); await expect(page.locator("#contacts .contact-block")).toContainText("erdc.ru"); + await expect(page.locator("#contacts .contact-block")).toContainText("Корпорация развития Дальнего Востока и Арктики"); await expect(page.locator("#contacts .contact-block time")).toHaveAttribute("datetime", "2026-11-01"); await expect(page.locator("#contacts .contact-block time")).toHaveText("01.11.2026"); + await page.goto("/#/appendix/contacts"); + await ready(page); + await expect(page.locator(".hero-title")).toHaveText("Контакты"); }); test("clipboard write denial never reports a successful copy", async ({ page }) => { @@ -551,3 +562,37 @@ test("all media assets remain available after scrolling through every section", } expect(errors).toEqual([]); }); + +test("Figma corrections keep directory summaries completely visible", async ({ page }) => { + await page.goto("/#/overview"); + await ready(page); + const descriptions = page.locator("#contents .directory-copy p"); + await expect(descriptions).toHaveCount(15); + for (const description of await descriptions.all()) { + const style = await description.evaluate((node) => ({ + clamp: getComputedStyle(node).webkitLineClamp, + height: node.clientHeight, + scrollHeight: node.scrollHeight, + overflowY: getComputedStyle(node).overflowY, + })); + expect(style.clamp).toBe("none"); + expect(style.scrollHeight).toBeLessThanOrEqual(style.height + 1); + expect(style.overflowY).not.toBe("hidden"); + } +}); + +test("trademark and contact chapters match the annotated design", async ({ page, isMobile }) => { + await page.goto("/#/overview"); + await ready(page); + await expect(page.getByRole("button", { name: "Открыть раздел Товарный знак" })).toHaveCount(1); + await expect(page.getByRole("button", { name: "Открыть раздел Дизайн соцсетей" })).toHaveCount(1); + await expect(page.getByRole("button", { name: "Открыть раздел Контакты" })).toHaveCount(1); + await page.goto("/#/contacts"); + await ready(page); + await expect(page.locator(".hero-title")).toHaveText("Контакты"); + await expect(page.locator("#contacts .contact-block time")).toHaveText("01.11.2026"); + if (isMobile) { + await page.locator(".mobile-menu-button").click(); + await expect(page.locator(".nav-parent[aria-current=page]")).toContainText("Контакты"); + } +});