Доработка VK-бота ИКП: контент, новые функции, защита и визуал
Контент и брендинг: - Реальные данные ИКP (infocyber.pro): услуги CS2/Dota 2/WoT, цены, FAQ, контакты, площадки - Приветствие и тексты приведены к бренду ИКП Новые функции: - Раздельные согласия (152-ФЗ): маркетинговая рассылка — отдельный необязательный шаг - Шаг «удобное время звонка» в форме заявки - Раздел «Карьера в ИКП»: набор игроков и сотрудников (таблица applications) - Админ-команды: статистика (стата) и рассылка по подписчикам с троттлингом и отпиской - Журнал заявок leads, «бот помнит клиента», международные телефоны, валидация имени - Email-уведомления о заявках и откликах (mailer.py); HR-адрес через HR_MAIL_TO Защита: - Анти-флуд по пользователю и кулдаун уведомлений оператору (анти-DDoS) - Веб-форма: серверная валидация, honeypot, рейт-лимит, CORS по ALLOWED_ORIGIN, SQLite-first Визуал: - Убрана Markdown-разметка (VK её не рендерит) - Логотип в приветствии, карусели услуг и «Карьеры» (фото 13:8), предзагрузка медиа - Кнопки-ссылки на соцсети - Веб-форма: анимации, конфетти на успехе Промокоды добавлены, но пока ВЫКЛЮЧЕНЫ флагом PROMO_ENABLED (по умолчанию false). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
+159
@@ -483,3 +483,162 @@ main {
|
||||
font-size: 0.95rem;
|
||||
}
|
||||
}
|
||||
|
||||
/* ----------------------------------------------------
|
||||
11. VISUAL POLISH (анимации и «живой» неон)
|
||||
---------------------------------------------------- */
|
||||
|
||||
/* Плавное появление карточки при загрузке */
|
||||
@keyframes cardIn {
|
||||
from { opacity: 0; transform: translateY(24px) scale(0.98); }
|
||||
to { opacity: 1; transform: translateY(0) scale(1); }
|
||||
}
|
||||
.card {
|
||||
animation: cardIn 0.55s cubic-bezier(0.22, 1, 0.36, 1) both;
|
||||
}
|
||||
|
||||
/* Бегущий градиент в верхней акцент-линии */
|
||||
@keyframes accentFlow {
|
||||
0% { background-position: 0% 50%; }
|
||||
100% { background-position: 200% 50%; }
|
||||
}
|
||||
.card::before {
|
||||
background: linear-gradient(90deg,
|
||||
var(--cyan-accent) 0%, var(--primary-orange) 50%, var(--cyan-accent) 100%);
|
||||
background-size: 200% 100%;
|
||||
animation: accentFlow 4s linear infinite;
|
||||
}
|
||||
|
||||
/* Каскадное появление полей формы */
|
||||
@keyframes fadeUp {
|
||||
from { opacity: 0; transform: translateY(12px); }
|
||||
to { opacity: 1; transform: translateY(0); }
|
||||
}
|
||||
#formContainer .form-group,
|
||||
#formContainer .checkbox-group,
|
||||
#formContainer .submit-btn {
|
||||
animation: fadeUp 0.5s ease both;
|
||||
}
|
||||
#formContainer .form-group:nth-of-type(1) { animation-delay: 0.10s; }
|
||||
#formContainer .form-group:nth-of-type(2) { animation-delay: 0.16s; }
|
||||
#formContainer .form-group:nth-of-type(3) { animation-delay: 0.22s; }
|
||||
#formContainer .form-group:nth-of-type(4) { animation-delay: 0.28s; }
|
||||
#formContainer .checkbox-group { animation-delay: 0.34s; }
|
||||
#formContainer .submit-btn { animation-delay: 0.42s; }
|
||||
|
||||
/* Мягкое пульсирующее свечение логотипа */
|
||||
@keyframes logoGlow {
|
||||
0%, 100% { box-shadow: 0 8px 24px rgba(0, 0, 0, 0.5); }
|
||||
50% { box-shadow: 0 8px 30px rgba(255, 122, 0, 0.35); }
|
||||
}
|
||||
.logo-img {
|
||||
animation: logoGlow 3.5s ease-in-out infinite;
|
||||
}
|
||||
|
||||
/* Световой блик, пробегающий по кнопке при наведении */
|
||||
.submit-btn {
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
}
|
||||
.submit-btn::after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: -120%;
|
||||
width: 60%;
|
||||
height: 100%;
|
||||
background: linear-gradient(120deg, transparent, rgba(255, 255, 255, 0.45), transparent);
|
||||
transform: skewX(-20deg);
|
||||
transition: left 0.6s ease;
|
||||
}
|
||||
.submit-btn:hover::after {
|
||||
left: 130%;
|
||||
}
|
||||
|
||||
/* Спиннер в кнопке во время отправки (класс .loading добавляется из script.js) */
|
||||
@keyframes spin { to { transform: rotate(360deg); } }
|
||||
.submit-btn.loading {
|
||||
pointer-events: none;
|
||||
opacity: 0.85;
|
||||
}
|
||||
.submit-btn.loading::before {
|
||||
content: '';
|
||||
width: 18px;
|
||||
height: 18px;
|
||||
margin-right: 10px;
|
||||
border: 2.5px solid rgba(10, 15, 31, 0.35);
|
||||
border-top-color: var(--text-dark);
|
||||
border-radius: 50%;
|
||||
animation: spin 0.7s linear infinite;
|
||||
}
|
||||
|
||||
/* Уважаем системную настройку «уменьшить движение» */
|
||||
@media (prefers-reduced-motion: reduce) {
|
||||
.card,
|
||||
.card::before,
|
||||
#formContainer .form-group,
|
||||
#formContainer .checkbox-group,
|
||||
#formContainer .submit-btn,
|
||||
.logo-img {
|
||||
animation: none !important;
|
||||
}
|
||||
.submit-btn::after { display: none; }
|
||||
}
|
||||
|
||||
/* ----------------------------------------------------
|
||||
12. ПРОМОКОД НА ЭКРАНЕ УСПЕХА
|
||||
---------------------------------------------------- */
|
||||
.promo-box {
|
||||
display: none;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
gap: 4px;
|
||||
width: 100%;
|
||||
background: rgba(255, 122, 0, 0.08);
|
||||
border: 1.5px dashed var(--primary-orange);
|
||||
border-radius: 14px;
|
||||
padding: 16px 20px;
|
||||
margin: 0 0 24px;
|
||||
animation: scaleIn 0.4s cubic-bezier(0.34, 1.56, 0.64, 1) both;
|
||||
}
|
||||
.promo-label {
|
||||
font-size: 0.78rem;
|
||||
color: var(--text-gray);
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 1px;
|
||||
text-align: center;
|
||||
}
|
||||
.promo-code {
|
||||
font-family: var(--font-headings);
|
||||
font-size: 1.55rem;
|
||||
font-weight: 800;
|
||||
color: var(--primary-orange);
|
||||
letter-spacing: 1.5px;
|
||||
}
|
||||
.promo-hint {
|
||||
font-size: 0.76rem;
|
||||
color: var(--text-gray);
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
/* ----------------------------------------------------
|
||||
13. КОНФЕТТИ (салют при успешной отправке)
|
||||
---------------------------------------------------- */
|
||||
.confetti-piece {
|
||||
position: fixed;
|
||||
top: -14px;
|
||||
z-index: 9999;
|
||||
border-radius: 2px;
|
||||
pointer-events: none;
|
||||
animation-name: confetti-fall;
|
||||
animation-timing-function: cubic-bezier(0.2, 0.6, 0.4, 1);
|
||||
animation-fill-mode: forwards;
|
||||
}
|
||||
@keyframes confetti-fall {
|
||||
0% { transform: translateY(-10px) rotate(0deg); opacity: 1; }
|
||||
100% { transform: translateY(105vh) rotate(720deg); opacity: 0.9; }
|
||||
}
|
||||
@media (prefers-reduced-motion: reduce) {
|
||||
.confetti-piece { display: none; }
|
||||
.promo-box { animation: none; }
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user