1. Контекст: ваш App — гость в доме ChatGPT
Прежде чем рисовать кнопки и подбирать шрифты, важно принять реальность: пользователь не открывает «ваш сайт», он сидит в ChatGPT. У ChatGPT уже есть свои:
- цветовая схема,
- шрифты и размеры,
- отступы и компоновка элементов.
Ваш виджет показывается внутри этого окружения, чаще всего в iframe. Отсюда важный вывод: визуально App должен выглядеть как естественное продолжение интерфейса ChatGPT, а не как баннер, привезённый с 2008 года.
Официальные гайдлайны OpenAI как раз об этом: не ломать системные цвета и шрифты, добавлять лишь умеренные брендовые акценты и следовать базовой типографике и сетке площадки.
В практическом смысле это означает три вещи.
Во‑первых, фон, базовый цвет текста, стандартная типографика — всё это должно наследоваться от ChatGPT или от системных переменных, а не «я художник, а так вижу».
Во‑вторых, если вы хотите «свой стиль», он должен быть сконцентрирован в акцентах: основные кнопки, бейджи, выделенные состояния. Но не радужный фон и не кастомный шрифт Comic Sans — даже если в душе вы очень хотите.
В‑третьих, inline и fullscreen‑режимы одного и того же App должны визуально быть частью одного мира: одинаковые цвета CTA, одинаковые радиусы и отступы карточек, одинаковая типографика. Пользователь не должен ощущать, что при переходе из inline в fullscreen попал на другой продукт.
Дальше разберёмся по слоям: цвета и темы, типографика, отступы и сетка, затем — как Tailwind и shadcn/ui помогают всё это собрать.
Insight
ChatGPT sandbox не только ограничивает функциональность вашего виджета, но и добавляет ему свои стили.
Во-первых — это заголовок HTML
Оригинал с сайта:
<html lang="ru">
В песочнице:
<html lang="en-US" data-theme="light" class="light" style="--safe-area-inset-top: 0px; --safe-area-inset-bottom: 0px; --safe-area-inset-left: 0px; --safe-area-inset-right: 0px;">
Во-вторых — это родные CSS стили, чтобы ваш виджет больше походит на ChatGPT:
<style>
html,body,#root{-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;margin:0;padding:0}
html,body{font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen,Ubuntu,Cantarell,Helvetica Neue,Arial,sans-serif!important}
button,input,textarea,select{font-family:inherit}
html{background-color:#fff}
html.dark{background-color:#212121}
html.mobileSkybridge.dark{background-color:#000}
@supports (font: -apple-system-body){html.mobileSkybridge{font:-apple-system-body}}
</style>
Лучше вам об этом помнить — будет меньше сюрпризов.
2. Темы и цвета: живём в светлой и тёмной вселенных
Светлая и тёмная темы
Интерфейс ChatGPT уже поддерживает светлую и тёмную темы. Ваш виджет показывается внутри одной из них, и пользователь может переключаться между ними когда угодно. Значит, любые жёстко зашитые белые или чёрные фоны — потенциальная мина.
Представьте виджет, который рисует белый фон и чёрный текст. В светлой теме он выглядит терпимо. В тёмной теме — как прожектор в глаза. Обратная ситуация с чёрным фоном в светлой теме выглядит не лучше. Именно поэтому официальные рекомендации советуют не хардкодить цвета, а опираться на тему/переменные хоста.
В Apps SDK окружение обычно даёт вам API или CSS‑переменные для текущей темы. В документации фигурируют варианты вроде window.openai.theme и использование стандартных CSS‑переменных ChatGPT. Плюс никто не отменял prefers-color-scheme и утилиты dark: в Tailwind.
Идея примерно такая: ваш виджет должен автоматически подстраивать под тему хоста такие вещи, как:
- фон карточек (слегка светлее/темнее базового фона),
- цвет текста (достаточный контраст),
- границы, тени и hover‑состояния.
Пример простейшей обёртки для темы с Tailwind:
// components/AppShell.tsx
export function AppShell({ children }: { children: React.ReactNode }) {
return (
<div className="bg-background text-foreground">
{/* bg-background/text-foreground переопределяются темой */}
{children}
</div>
);
}
Где bg-background и text-foreground — это не стандартные Tailwind‑классы, а алиасы к CSS‑переменным вашей дизайн‑системы (например, из shadcn/ui), которые в свою очередь привязаны к светлой/тёмной теме ChatGPT.
Системные цвета против брендовых акцентов
OpenAI довольно прямо говорит: системные цвета ChatGPT менять нельзя. Базовый текст, стандартные панели чата, фон — всё это должно оставаться в общих цветах платформы. Ваше поле — акценты внутри виджета: CTA‑кнопки (call to action — основное действие), бейджи, малые элементы.
В практике GiftGenius это означает, что:
- фон карточки подарка близок к системному,
- текст — обычного цвета, как и текст в чате,
- фирменный цвет GiftGenius используется для основной кнопки «Выбрать подарок» и, возможно, для бейджа скидки.
Можно представить таблицу:
| Элемент | Что делать | Чего избегать |
|---|---|---|
| Фон виджета | Наследовать от ChatGPT | Ставить яркий брендовый градиент |
| Основной текст | Наследовать системный цвет | Делать цветным/серым до нечитаемости |
| Основная CTA‑кнопка | Использовать брендовый акцентный цвет | Рисовать на ней «радугу» и 5 цветов |
| Вторичные кнопки/ссылки | Близки к системным ссылкам | Делать их такими же яркими, как CTA |
| Тени/рамки | Нежные, минималистичные | Толстые неоновые обводки |
Мини‑пример с Tailwind для основного цвета:
// styles/globals.css (фрагмент)
:root {
--gift-accent: 222 84% 56%; /* hsl */
}
.dark {
--gift-accent: 222 84% 64%; /* чуть светлее для dark */
}
// components/GiftButton.tsx
export function GiftButton({ children }: { children: React.ReactNode }) {
return (
<button className="rounded-md bg-[hsl(var(--gift-accent))] px-4 py-2 text-sm font-medium text-white hover:opacity-90">
{children}
</button>
);
}
Вы не трогаете фон всего виджета, но аккуратно применяете свой цвет к основной CTA‑кнопке.
Контраст и WCAG без фанатизма
Даже если вы не готовитесь сдавать экзамен по WCAG, есть простой ориентир: текст должен быть читаемым. Чем меньше шрифт, тем выше должен быть контраст. В курсах по доступности советуют держать контраст текста по отношению к фону не ниже ~4.5:1 для основного текста. Подробно в стандарты доступности мы здесь не углубляемся: нам нужен один практический ориентир — достаточный контраст текста и фона.
На практике:
- не используйте светло‑серый текст на светло‑сером фоне ради «элегантности»;
- избегайте тёмно‑серого текста на почти чёрном фоне в тёмной теме;
- проверяйте хотя бы на глаз: если вы щуритесь — пользователю тоже будет больно.
Можно договориться с самим собой: любой второстепенный текст (подписи, подсказки) всё равно читаем, просто чуть менее акцентный по цвету и размеру, но не «полностью призрачный».
3. Типографика: системные шрифты, иерархия и немного здравого смысла
Системные шрифты вместо «своей» гарнитуры
Официальные гайдлайны призывают использовать системные шрифты платформы, вроде SF Pro, Roboto и их аналоги, и не подсовывать свой webfont. И причина не только в производительности, но и в том, что ваш App должен выглядеть родным элементом интерфейса.
В Next.js‑приложении проще всего сделать так, чтобы всё внутри виджета наследовало базовый системный стек. В Tailwind это обычно уже настроено как font-sans. Если вы хотите быть более явными:
// app/layout.tsx (фрагмент)
export default function RootLayout({ children }: { children: React.ReactNode }) {
return (
<html lang="en">
<body className="font-sans antialiased">
{children}
</body>
</html>
);
}
Не нужно подключать 3 семейства через Google Fonts. Для учебного GiftGenius строгий системный шрифт будет выглядет аккуратнее, чем условный Lobster.
Иерархия размеров
Нам достаточно нескольких уровней типографики: заголовок блока, подзаголовок/ключевой параметр, основной текст и подпись.
Для inline‑карточки GiftGenius, например, удобно договориться о таких уровнях:
| Роль | Tailwind‑класс | Пример |
|---|---|---|
| Заголовок карточки | |
Название подарка |
| Ключевой параметр | |
Цена или категория |
| Описание | |
Краткое описание |
| Подпись/мелочи | |
Доставка, магазин |
Мини‑компонент карточки:
// components/GiftCard.tsx
type GiftCardProps = {
title: string;
price: string;
description: string;
};
export function GiftCard({ title, price, description }: GiftCardProps) {
return (
<div className="rounded-lg border bg-card p-4">
<h3 className="text-base font-semibold">{title}</h3>
<p className="mt-1 text-sm font-medium text-emerald-600">{price}</p>
<p className="mt-2 text-sm text-muted-foreground">{description}</p>
</div>
);
}
Здесь:
- нет огромного H1;
- вся информация компактна;
- иерархия считывается по размеру и насыщенности шрифта.
Выравнивание и длина строк
Чат‑интерфейс обычно узкий, особенно в inline. Поэтому можно не перегревать мозг сложной типографикой: обычное выравнивание по левому краю и длина строки в 40–60 символов вполне комфортны.
Полезные привычки:
- не центрировать длинные тексты в карточке — их сложнее читать;
- не писать ВСЁ ЗАГЛАВНЫМИ БУКВАМИ;
- не делать базовый текст меньше 14 px (в Tailwind это text-sm) без очень серьёзной причины.
При сомнениях помните: читать будет уставший человек на телефоне в метро, а не вы с идеальным 27‑дюймовым монитором.
4. Отступы, плотность и сетка
Если цвета и шрифты — это «краски», то отступы — это воздух. Без них даже самые аккуратные карточки превращаются в кашу.
OpenAI в своих рекомендациях подчёркивает: элементы не должны быть «склеены», отступы и радиусы лучше брать из дизайн‑системы или UI‑фреймворка (Tailwind, shadcn/ui и т.д.), а горизонтальный скролл следует минимизировать.
Принцип «дышать»
Самый простой паттерн: использовать единую шкалу отступов (например, шаг 4 px или 8 px) и не придумывать каждый раз «свой» размер. В Tailwind это уже встроено: p-2, p-3, p-4, gap-3 и т.п.
Пример небольшой сетки для списка подарков в inline:
// components/GiftListInline.tsx
export function GiftListInline({ children }: { children: React.ReactNode }) {
return (
<div className="flex flex-col gap-3">
{children}
</div>
);
}
Каждая карточка отделена gap-3, имеет свои внутренние p-4, и уже этого хватает, чтобы список не выглядел как «простыня».
Колонки: inline против fullscreen
В документах по UX для Apps SDK рекомендуется для inline‑виджета держаться 1–2 колонок карточек, а для fullscreen можно позволить себе 2–3 при достаточной ширине.
Причина проста: в чате ширина ограничена, особенно на мобильном, и две колонки — это уже на грани по читаемости. В fullscreen же вы получаете экран почти целиком и можете расположить контент плотнее.
Ориентировочная схема:
flowchart LR
subgraph Inline
A[1 колонка
узкий экран]
B[2 колонки
на десктопе]
end
subgraph Fullscreen
C[2 колонки
основной сценарий]
D[3 колонки
для сеток/каталогов]
end
Реализация в Tailwind для GiftGenius:
// components/GiftGrid.tsx
export function GiftGrid({ fullscreen, children }: { fullscreen?: boolean; children: React.ReactNode }) {
const base = fullscreen ? "grid-cols-2 md:grid-cols-3" : "grid-cols-1 sm:grid-cols-2";
return (
<div className={`grid gap-4 ${base}`}>
{children}
</div>
);
}
В inline‑режиме вы даёте одну колонку на мобильном и две на более широких экранах. В fullscreen сразу делаете 2–3 колонки в зависимости от ширины.
Избегаем горизонтального скролла
Чат по природе вертикальный. Пользователь привык листать вниз, а не вбок. Поэтому:
- старайтесь, чтобы таблицы и карточки укладывались в ширину контейнера;
- не задавайте фиксированные ширины вроде width: 600px; для элемента, который живёт в гибком контейнере;
- используйте max-w-full, overflow-x-auto только как «последний шанс», а не как дефолт.
Для карточек GiftGenius удобно задавать w-full и позволять сетке решать, сколько поместится в ряд.
5. Адаптивность внутри контейнера ChatGPT
В обычном фронтенде у вас есть полный контроль над viewport. В ChatGPT этот контроль ограничен: ваш виджет помещён в контейнер чата, у которого свои размеры и правила. Apps SDK даёт несколько полезных мостиков: максимальная высота, safe area для вырезов экрана, тип устройства и т.п.
maxHeight и вертикальные ограничения
В inline‑режиме ChatGPT может ограничивать высоту виджета, чтобы он не «съедал» весь экран. Хуки вроде useMaxHeight() позволяют вам узнать, сколько места сейчас можно честно занять, и вешать внутренние скроллы там, где нужно.
Псевдокод:
// Псевдокод, не реальный API:
const maxHeight = useMaxHeight();
return (
<div style={{ maxHeight, overflowY: "auto" }}>
<GiftGrid>{/* ... */}</GiftGrid>
</div>
);
Так вы избегаете ситуации, когда виджет упирается в нижний край экрана, а чат‑сообщения «съезжают» куда‑то в прошлую жизнь.
safeArea и мобильные устройства
На мобильных устройствах сверху и снизу могут быть вырезы, статус‑бар, системные панели. Apps SDK позволяет получить safeArea и подстроить отступы так, чтобы ничего не уехало под «чёлку» телефона.
На уровне CSS можно добавить дополнительные паддинги:
// Псевдокод
const { top, bottom } = useSafeArea(); // допустим, вернёт { top: 8, bottom: 16 }
return (
<div style={{ paddingTop: top, paddingBottom: bottom }}>
{/* контент */}
</div>
);
В рамках лекции нам важнее понять сам принцип: виджет должен уважать ограничитель высоты и безопасную область, иначе UX мгновенно превращается в «проскролль ещё три раза, чтобы увидеть кнопку».
6. Tailwind и shadcn/ui: не изобретать кнопки заново
Писать весь UI руками на чистом CSS сейчас уже почти хардкор‑спорт. В контексте ChatGPT Apps гораздо проще взять проверенную библиотеку и настроить её под требования платформы. В курсе мы опираемся на Tailwind и shadcn/ui как базовый стек.
Tailwind как словарь отступов и цветов
Tailwind даёт удобный набор утилит:
- отступы (p-4, gap-3),
- размеры (text-sm, text-base),
- цвета (text-muted-foreground, bg-card), которые в shadcn/ui и подобных системах уже привязаны к CSS‑переменным темы.
Это идеально ложится на требования ChatGPT:
- вы не придумываете произвольные отступы,
- консистентно задаёте размеры текста,
- не ломаете системные цвета, а используете заранее согласованные токены.
shadcn/ui как набор аккуратных компонентов
shadcn/ui (и похожие библиотеки) предоставляют готовые Card, Button, Input, Tabs и т.п., настроенные на Tailwind‑тему. Это значительно ускоряет сборку аккуратного, минималистичного интерфейса, особенно для карточек GiftGenius.
Пример GiftCard с использованием shadcn/ui:
// components/GiftCardShadcn.tsx
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
import { Button } from "@/components/ui/button";
type GiftCardProps = {
title: string;
price: string;
description: string;
};
export function GiftCardShadcn(props: GiftCardProps) {
return (
<Card>
<CardHeader>
<CardTitle className="text-base">{props.title}</CardTitle>
</CardHeader>
<CardContent className="space-y-2">
<p className="text-sm font-medium text-emerald-600">{props.price}</p>
<p className="text-sm text-muted-foreground">{props.description}</p>
<Button className="mt-2">Выбрать подарок</Button>
</CardContent>
</Card>
);
}
Главное здесь не сам shadcn, а принципы:
- заголовок не гигантский;
- описание читаемо;
- кнопка оформлена по общей дизайн‑системе, а не «своим путём».
Настройка под ChatGPT
В реальном проекте вы можете подстроить палитру под минималистичный стиль ChatGPT: светлый фон, мягкие тени, аккуратные радиусы. План модуля прямо предлагает опираться на существующую дизайн‑систему, а не создавать свою вселенную.
Простой подход:
- взять базу shadcn/ui;
- оставить системный шрифт;
- настроить один‑два брендовых цвета в токенах primary / accent;
- убедиться, что и inline, и fullscreen используют те же токены.
Так вы получаете цельное визуальное ядро без лишних усилий.
7. Визуальный язык GiftGenius: собираем всё вместе
Давайте систематизируем, что для нашего условного GiftGenius уже можно считать «визуальным языком».
Во‑первых, цветовая схема. Фон и текст наследуются от ChatGPT; акцентный цвет — неброский, но заметный, применяется к CTA‑кнопкам и, возможно, бейджам скидок. В тёмной теме этот акцент чуть светлее, чтобы сохранять контраст.
Во‑вторых, типографика. Базовый системный шрифт, размеры text-sm для основного текста и text-base для заголовков карточек. Курсив и капс используются редко, исключительно по делу. Заголовки в fullscreen‑мастере на шаг выше, но всё ещё без кричащих text-4xl.
В‑третьих, отступы и сетка. В inline‑режиме список подарков — одна или две колонки с gap-3/gap-4, каждая карточка с p-4. В fullscreen‑режиме — 2–3 колонки, шаги мастера с достаточными промежутками между формами и кнопками. Никакого горизонтального скролла для основных сценариев.
Небольшая схема для экранов GiftGenius:
graph TD A[Inline: список подарков] --> B[GiftCard
цвета/типографика/CTA] A --> C[GiftGrid 1-2 колонки] D[Fullscreen: мастер подбора] --> E[Шаг 1
форма] D --> F[Шаг 2
фильтры/диапазоны] D --> G[Шаг 3
подтверждение] B --> H[GiftButton
брендовый акцент]
Во‑четвёртых, совместимость с host‑контекстом. Все элементы ведут себя прилично при переключении светлой/тёмной темы, уважают maxHeight и не прячутся под safe‑area. Цвета не спорят с ChatGPT, а CTA‑кнопки везде выглядят одинаково, чтобы пользователь на уровне мышечной памяти знал, куда жать.
Такой набор решений уже делает ваше приложение пригодным к демонстрации не только программистам, но и живым пользователям или продукт‑менеджерам: будет что обсудить, кроме «тут у нас MCP, а тут Agents SDK».
8. Доступность (Accessibility Guidelines, WCAG AA)
Мы уже мельком упоминали WCAG, когда говорили про контраст текста и фона в разделе 2.3. Там нас интересовал один практический ориентир — не убивать читаемость. Теперь посмотрим на доступность чуть шире: как тот же интерфейс выглядит для тех, кто не видит его глазами, и для самой ChatGPT в голосовом режиме.
WCAG AA — это уровень стандарта доступности из международного набора правил WCAG (Web Content Accessibility Guidelines), которые описывают, как делать сайты и интерфейсы доступными для людей с разными ограничениями по зрению, моторике, когнитивным особенностям и т.д.
Главная идея WCAG AA — превратить интерфейс из просто «теоретически доступного» в по‑настоящему используемый. Этот уровень включает десятки требований, которые напрямую влияют на качество взаимодействия. Среди них — тот самый порог контраста текста и фона около 4.5:1, о котором мы уже говорили, а также требования к размерам кликабельных областей, состояниям фокуса, ошибкам в формах и т.д.
Отдельный слой — поддержка технологий доступности, включая screen reader’ы. Уровень AA требует корректной семантики: заголовки должны быть заголовками, списки — списками, кнопки — кнопками, а интерактивные элементы должны иметь правильно назначенные роли и текстовые альтернативы. Это позволяет пользователям, которые работают с программами VoiceOver, TalkBack или NVDA, полноценно понимать структуру и смысл интерфейса.
Screen reader (экранный чтец)
Screen reader (экранный чтец) — это программа, которая озвучивает и/или структурирует содержимое экрана, позволяя людям с нарушениями зрения пользоваться компьютером, смартфоном или веб‑приложениями.
Но screen reader — это не просто «программа, которая читает текст вслух». Это полноценная система взаимодействия с интерфейсом, которая превращает визуальное представление сайта или приложения в доступную для восприятия звуковую и структурированную навигацию.
ChatGPT, screen reader и WCAG AA
Если ваш виджет размечен по принципам WCAG AA (правильные роли, заголовки, подписи к кнопкам), он становится понятным не только для screen reader’ов, но и для ChatGPT в голосовом режиме. Пользователь говорит с ChatGPT голосом, а модель, опираясь на ту же семантическую структуру, может «виртуально» делать то же самое, что и человек: находить нужные элементы интерфейса, нажимать кнопки, переходить по ссылкам и т.п.
Согласно требованиям ChatGPT Store, поддержка стандарта WCAG AA является обязательной для каждого приложения. Каждый виджет и каждый tool должны иметь максимально качественные и детальные описания, а вёрстка — быть выполненной в соответствии со стандартами WCAG AA: корректная семантика, читаемые подписи, предсказуемые состояния.
Поэтому требование WCAG AA — это не отдельная «фича для людей с особыми потребностями», а базовый дизайн‑принцип для того, чтобы ChatGPT Apps могла полноценно работать с вашим приложением, в том числе когда пользователь общается с ней в голосовом режиме.
К сценариям voice‑UX, отличиях голосового диалога от текстового и требованиям ChatGPT Store мы ещё вернёмся отдельно — в других уроках этого модуля и в модуле про публикацию App. Но всё это стоит на фундаменте, который вы сейчас увидели: голосовой режим = мультимодальность + доступность (WCAG AA + screen reader’ы).
9. Типичные ошибки визуального дизайна ChatGPT App
Ошибка №1: Жёстко зашитые белый/чёрный фон и цвета текста.
Разработчик рисует белый фон и чёрный текст, не задумываясь о тёмной теме. В светлой теме ещё как‑то живёт, в тёмной — превращается в прожектор и портит весь UX. Правильнее использовать системные цвета и тему хоста (CSS‑переменные, prefers-color-scheme или API Apps SDK), а свои цвета держать только для акцентов.
Ошибка №2: Слишком агрессивный брендинг.
Появляется яркий градиентный фон, кастомный шрифт, пёстрые рамки. Виджет начинает выглядеть как промо‑баннер, а не часть интерфейса ChatGPT. Гайдлайны требуют наоборот: минималистичный, «родной» вид, с аккуратным использованием брендового цвета только в ключевых элементах, например в основных кнопках.
Ошибка №3: Отсутствие иерархии в типографике.
Все тексты одного размера и веса, или наоборот — три уровня заголовков на маленькой карточке, да ещё в капсе. Пользователь не понимает, что главное: название, цена или описание. Лучше заранее договориться о 3–4 уровнях и везде их придерживаться: заголовок, ключевой параметр, основной текст, подпись.
Ошибка №4: Слипшиеся элементы без отступов.
Карточки прижаты друг к другу, текст впритык к краю, кнопки вплотную к тексту. На десктопе это ещё терпимо, на мобильном превращается в визуальный шум. Рекомендуется использовать единую шкалу отступов (например, Tailwind‑классы p-4, gap-3) и не экономить на воздухе.
Ошибка №5: Попытка впихнуть 4–5 колонок в inline‑режиме.
Разработчик мысленно всё ещё на странице интернет‑магазина и делает в чате плитку из четырёх узеньких карточек. На широком экране это выглядит спорно, на мобильном — вообще нечитабельно, добавляется горизонтальный скролл. В inline‑виджете обычно хватает одной‑двух колонок; третий столбец оставьте fullscreen‑режиму.
Ошибка №6: Игнорирование ограничений высоты и safe‑area.
Виджет рисует гигантский список без внутреннего скролла и без учёта maxHeight, так что кнопки оказываются «ниже дна экрана». Или элементы прячутся под вырез экрана на мобильном. Стоит использовать данные о максимальной высоте и безопасной области, чтобы корректно распределять высоту и отступы внутри.
Ошибка №7: Непоследовательный вид кнопок и карточек между inline и fullscreen.
В inline‑режиме кнопка зелёная и закруглённая, а в fullscreen — синяя и квадратная. Пользователь теряет ощущение единого продукта. Нужно вынести базовые стили кнопок и карточек в общий компонент/тему и использовать их во всех режимах.
Ошибка №8: «Авторский» шрифт и декоративные выкрутасы.
Подключение тяжёлого webfont «чтобы было красиво» ломает визуальную консистентность с ChatGPT и иногда портит производительность. Рекомендации платформы говорят использовать системные шрифты и аккуратную типографику. Если очень хочется выразиться как дизайнер — лучше поработать над иконками и microcopy, а не шрифтовой революцией.
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ