Системные правила интерфейсов
Дизайн-гайдлайн и эталонный код
Официальное руководство по визуальной стилистике и чистый эталонный HTML/CSS код страниц «Игровой стол» для разработчиков и ИИ-агентов.
1. Палитра дизайн-токенов
Background
#FFFFFF
Основной фон всех страниц
--ink
#121317
Текст, заголовки, Primary-кнопки
--ink-muted
#5F6368
Пояснения, субтитры, вторичный текст
--card-bg
#F8F9FB
Фон карточек, полей ввода кода
--border
rgba(18, 19, 23, 0.08)
Тонкие разделители и рамки
--accent-green
#137333
Успех, подтверждение статуса
2. Строгие правила для ИИ при создании страниц
1
Всегда чистый белый фон: Тело страницы (`body`) обязано иметь цвет `#ffffff`. Никаких темных «геймерских» фонов, черных градиентов или неоновых рамок.
2
Фирменная типографика: Основной шрифт — строго
'Google Sans', sans-serif. Для кодов авторизации, цифр и ID использовать моноширинный 'JetBrains Mono', monospace.
3
Стандартная шапка и логотип: В шапке использовать строго SVG
assets/image/logo.svg с CSS-свойством filter: invert(1) для чистого черного цвета логотипа на белом фоне. Ссылка всегда ведёт на корень /.
4
Pill-кнопки (скругление 999px): Все интерактивные кнопки имеют полное скругление
border-radius: 999px, высоту 48–52px и плавную микро-анимацию при наведении.
5
Обязательный деплой: При любых изменениях файлов в папке
public/ необходимо запускать деплой Firebase: npx firebase-tools deploy --only hosting:main-site.
3. Эталонный код главной страницы (index.html)
Минималистичный лейаут с центрированным заголовком, субтитром и кнопками перехода:
index.html (Core Layout)
<!DOCTYPE html>
<html lang="ru">
<head>
<meta charset="utf-8">
<title>Игровой стол</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="icon" type="image/x-icon" href="/fav.ico?v=4">
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Google+Sans:wght@400;500;700&display=swap">
<style>
:root {
--ink: #121317;
--ink-muted: #5f6368;
--border: rgba(18, 19, 23, 0.08);
--card-bg: #f8f9fb;
}
body {
margin: 0; min-height: 100svh; display: flex; flex-direction: column;
background: #ffffff; color: var(--ink); font-family: 'Google Sans', sans-serif;
}
.site-header { width: 100%; padding: 24px 48px; display: flex; align-items: center; }
.brand-logo { height: 26px; filter: invert(1); display: block; }
.hero { flex: 1; display: flex; flex-direction: column; align-items: center; justify-content: center; padding: 48px 24px; text-align: center; }
.hero-title { font-size: clamp(2.5rem, 6vw, 5rem); font-weight: 500; letter-spacing: -0.025em; line-height: 1.08; margin-bottom: 24px; }
.hero-subtitle { font-size: 18px; color: var(--ink-muted); max-width: 560px; margin-bottom: 40px; line-height: 1.6; }
.btn {
display: inline-flex; align-items: center; justify-content: center; gap: 10px;
height: 52px; padding: 0 30px; border-radius: 999px; font-size: 16px; font-weight: 500;
text-decoration: none; border: 1px solid transparent; cursor: pointer; transition: all 0.2s ease;
}
.btn-primary { background: var(--ink); color: #fff; box-shadow: 0 8px 24px rgba(18, 19, 23, 0.12); }
.btn-primary:hover { background: #2b2d33; transform: translateY(-2px); }
.btn-secondary { background: var(--card-bg); color: var(--ink); border-color: rgba(18, 19, 23, 0.1); }
.btn-secondary:hover { background: #f0f2f6; transform: translateY(-2px); }
.site-footer { width: 100%; padding: 32px 24px; border-top: 1px solid var(--border); }
.footer-inner { max-width: 1120px; margin: 0 auto; display: flex; justify-content: space-between; align-items: center; }
</style>
</head>
<body>
<header class="site-header">
<a href="/"><img src="assets/image/logo.svg" class="brand-logo" alt="Игровой стол"></a>
</header>
<main class="hero">
<h1 class="hero-title">Один сервер. Единая экосистема.</h1>
<p class="hero-subtitle">Цифровая инфраструктура сообщества «Игровой стол» и система Karczerbot.</p>
<div style="display:flex; gap:14px; flex-wrap:wrap; justify-content:center;">
<a href="https://discord.gg/xY9Gtp6GVR" class="btn btn-primary">Discord сервер</a>
<a href="/kbadmin" class="btn btn-secondary">Karczerbot</a>
</div>
</main>
<footer class="site-footer">
<div class="footer-inner">
<span style="color:var(--ink-muted); font-size:14px;">© 2026 Игровой стол</span>
<div style="display:flex; gap:20px;">
<a href="/design.html" style="color:var(--ink-muted); text-decoration:none;">Брендбук</a>
<a href="/guideline.html" style="color:var(--ink); text-decoration:none; font-weight:500;">Гайдлайн</a>
</div>
</div>
</footer>
</body>
</html>
4. Эталонный код карточки авторизации (callback.html)
Шаблон карточки с одноразовым кодом, кнопкой копирования в буфер и кнопками Discord:
callback.html (Card & Code Box)
<!-- Карточка центрального экрана callback.html -->
<main class="hero">
<div class="card">
<div class="status-badge" id="statusBadge">
<svg width="16" height="16" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2.4" d="M9 12.75L11.25 15 15 9.75M21 12a9 9 0 11-18 0 9 9 0 0118 0z" />
</svg>
<span>Авторизация подтверждена</span>
</div>
<h1 class="hero-title">Одноразовый код</h1>
<p class="hero-subtitle">
Скопируйте код и отправьте его боту на сервере с помощью команды <code class="code-pill">/code</code>
</p>
<div class="code-box">
<span class="code-text" id="codeDisplay">Загрузка...</span>
<button type="button" class="btn-copy" id="copyBtn" onclick="copyCode()">
<span id="copyText">Копировать</span>
</button>
</div>
<div class="actions">
<a href="https://discord.com/channels/1301478636880400405" target="_blank" class="btn btn-primary">
Перейти в Discord
</a>
<a href="/" class="btn btn-secondary">
На главную страницу
</a>
</div>
</div>
</main>
<script>
const urlParams = new URLSearchParams(window.location.search);
const code = urlParams.get('code');
const codeDisplay = document.getElementById('codeDisplay');
const copyBtn = document.getElementById('copyBtn');
const copyText = document.getElementById('copyText');
if (code && code.trim() !== '') {
codeDisplay.textContent = code;
} else {
codeDisplay.textContent = 'Код не найден';
codeDisplay.classList.add('error');
copyBtn.style.display = 'none';
}
function copyCode() {
if (!code) return;
navigator.clipboard.writeText(code).then(() => {
copyBtn.classList.add('copied');
copyText.textContent = 'Скопировано!';
setTimeout(() => {
copyBtn.classList.remove('copied');
copyText.textContent = 'Копировать';
}, 2000);
});
}
</script>