MVP сайта детского лагеря Сокол
- index.html: 9 секций (header, hero, about, shifts, schedule, gallery, signup, payment, contacts, footer) - style.css: оранжево-синяя палитра, шрифт Nunito, мобильная адаптация - script.js: рендер карточек смен из JSON, галерея с лайтбоксом, форма с валидацией - data/shifts.json: 4 mock-смены Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
62621304fa
commit
ca40ebeeb0
114
PRD.md
114
PRD.md
@ -0,0 +1,114 @@
|
||||
# PRD — Сайт детского лагеря «Сокол»
|
||||
|
||||
> Документ написан простым языком — без программистских терминов.
|
||||
> Цель: объяснить, каким должен быть сайт, чтобы передать его разработчику.
|
||||
|
||||
---
|
||||
|
||||
## 1. Что мы хотим создать
|
||||
|
||||
Сайт для детского оздоровительного лагеря **«Сокол»**.
|
||||
Сайт должен быть понятным, красивым и удобным — чтобы родители могли легко записать ребёнка в лагерь, а дети могли узнать, что их ждёт.
|
||||
|
||||
**Инстаграм лагеря:** [https://www.instagram.com/doc.sokol_](https://www.instagram.com/doc.sokol_/)
|
||||
|
||||
---
|
||||
|
||||
## 2. Для кого этот сайт
|
||||
|
||||
### Родители
|
||||
Хотят быстро и без лишних звонков:
|
||||
- записать ребёнка в лагерь
|
||||
- узнать расписание смен и программу
|
||||
- оплатить путёвку онлайн
|
||||
- связаться с администрацией, если есть вопросы
|
||||
|
||||
### Дети
|
||||
Хотят увидеть, что их ждёт:
|
||||
- яркие фото и видео из жизни лагеря
|
||||
- расписание мероприятий и кружков
|
||||
|
||||
---
|
||||
|
||||
## 3. Что должно быть на сайте
|
||||
|
||||
### Главная страница
|
||||
- Красивое фото или видео с территории лагеря
|
||||
- Короткий слоган — одна фраза о том, что такое «Сокол»
|
||||
- Большая кнопка **«Записаться»** и **«Узнать цены»**
|
||||
|
||||
### Запись в лагерь
|
||||
- Простая форма: имя ребёнка, возраст, телефон родителя, выбор смены
|
||||
- После отправки — подтверждение, что заявка принята
|
||||
|
||||
### Онлайн-оплата путёвки
|
||||
- Возможность оплатить картой прямо на сайте
|
||||
- Информация о стоимости каждой смены и что в неё входит
|
||||
|
||||
### Расписание и программа
|
||||
- Даты всех смен на текущий сезон
|
||||
- Описание дня в лагере: подъём, занятия, мероприятия, отбой
|
||||
- Список кружков, секций и конкурсов
|
||||
|
||||
### Фото и видео
|
||||
- Галерея из Инстаграма и дополнительные материалы
|
||||
- Короткие видео — чтобы дети и родители почувствовали атмосферу
|
||||
|
||||
### Контакты и связь с администрацией
|
||||
- Телефон, WhatsApp / Telegram
|
||||
- Адрес лагеря и как добраться
|
||||
- Форма обратной связи для вопросов
|
||||
|
||||
### О лагере
|
||||
- Коротко: история, ценности, команда вожатых
|
||||
- Фото персонала (вызывает доверие у родителей)
|
||||
|
||||
---
|
||||
|
||||
## 4. Что уже есть и можно использовать
|
||||
|
||||
| Материал | Статус |
|
||||
|---|---|
|
||||
| Инстаграм [@doc.sokol_](https://www.instagram.com/doc.sokol_/) | Готов, использовать как основу |
|
||||
| Фото и видео из лагеря | Есть — передать разработчику |
|
||||
| Брошюры / презентации | Есть — передать разработчику |
|
||||
|
||||
---
|
||||
|
||||
## 5. Как должен выглядеть сайт
|
||||
|
||||
- **Яркий и летний** — солнечные цвета, живые фото, радостная атмосфера
|
||||
- **Простой** — родитель любого возраста разбирается за 1–2 минуты
|
||||
- **Удобный на телефоне** — большинство заходят с мобильного
|
||||
- **Без лишнего текста** — больше фото, меньше слов
|
||||
|
||||
---
|
||||
|
||||
## 6. Что НЕ нужно на первом этапе
|
||||
|
||||
- Личный кабинет для родителей
|
||||
- Форум или чат внутри сайта
|
||||
- Сложные фильтры и поиск
|
||||
|
||||
---
|
||||
|
||||
## 7. Главный результат
|
||||
|
||||
Родитель заходит на сайт → за 2–3 минуты понимает, что лагерь классный → записывает ребёнка и оплачивает путёвку онлайн, не выходя из дома.
|
||||
|
||||
---
|
||||
|
||||
## 8. Сроки
|
||||
|
||||
**Приоритет: запустить сайт до начала лета.**
|
||||
|
||||
Рекомендуемый порядок работ:
|
||||
1. Главная страница + форма записи — *в первую очередь*
|
||||
2. Расписание смен и цены — *в первую очередь*
|
||||
3. Галерея фото и видео — *в первую очередь*
|
||||
4. Онлайн-оплата — *после основного запуска*
|
||||
5. Блок «О лагере» и контакты — *вместе с основным запуском*
|
||||
|
||||
---
|
||||
|
||||
*Документ подготовлен сотрудником Казахтелеком для передачи разработчику сайта.*
|
||||
211
TRD.md
211
TRD.md
@ -0,0 +1,211 @@
|
||||
# TRD — Техническое задание. Сайт детского лагеря «Сокол» (MVP)
|
||||
|
||||
> Цель этого документа — дать разработчику чёткие инструкции.
|
||||
> Задача: рабочий MVP за ~1 час. Не идеальный код, а работающий сайт.
|
||||
|
||||
---
|
||||
|
||||
## 1. Выбор технологии
|
||||
|
||||
**Стек: чистый HTML + CSS + JavaScript (без фреймворков)**
|
||||
|
||||
Почему именно это:
|
||||
- Не нужно ничего устанавливать — открыл файл в браузере и готово
|
||||
- Разработчик любого уровня разберётся за минуты
|
||||
- Легко выложить на бесплатный хостинг (GitHub Pages, Netlify, Vercel)
|
||||
- Онлайн-оплата подключается через готовый виджет от Kaspi / CloudPayments — просто вставить код
|
||||
|
||||
---
|
||||
|
||||
## 2. Структура папок проекта
|
||||
|
||||
```
|
||||
sokol-camp/
|
||||
│
|
||||
├── index.html ← единственная страница сайта
|
||||
├── style.css ← все стили (цвета, шрифты, отступы)
|
||||
├── script.js ← логика: форма записи, галерея
|
||||
│
|
||||
├── images/ ← папка с фотографиями
|
||||
│ ├── hero.jpg ← главное фото на обложке
|
||||
│ ├── photo-1.jpg
|
||||
│ ├── photo-2.jpg
|
||||
│ └── ...
|
||||
│
|
||||
├── data/
|
||||
│ └── shifts.json ← данные о сменах (даты, цены, описание)
|
||||
│
|
||||
└── README.md ← как запустить проект (2 строки)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 3. Какие данные нужны
|
||||
|
||||
### Смены лагеря — файл `data/shifts.json`
|
||||
|
||||
Разработчик заполняет этот файл реальными данными от заказчика.
|
||||
|
||||
```json
|
||||
[
|
||||
{
|
||||
"id": 1,
|
||||
"name": "Смена 1 — «Старт лета»",
|
||||
"dates": "1 июня — 21 июня 2025",
|
||||
"price": 120000,
|
||||
"currency": "тенге",
|
||||
"spots_left": 12,
|
||||
"description": "Спорт, творчество, командные игры. Возраст: 7–12 лет.",
|
||||
"includes": ["3-разовое питание", "проживание в корпусе", "все мероприятия"]
|
||||
},
|
||||
{
|
||||
"id": 2,
|
||||
"name": "Смена 2 — «Приключения»",
|
||||
"dates": "25 июня — 15 июля 2025",
|
||||
"price": 135000,
|
||||
"currency": "тенге",
|
||||
"spots_left": 8,
|
||||
"description": "Походы, квесты, природа. Возраст: 10–15 лет.",
|
||||
"includes": ["3-разовое питание", "проживание в корпусе", "все мероприятия", "поход выходного дня"]
|
||||
}
|
||||
]
|
||||
```
|
||||
|
||||
### Форма заявки — данные, которые вводит родитель
|
||||
|
||||
| Поле | Тип | Обязательное |
|
||||
|---|---|---|
|
||||
| Имя ребёнка | Текст | Да |
|
||||
| Возраст ребёнка | Число | Да |
|
||||
| Имя родителя | Текст | Да |
|
||||
| Телефон | Телефон | Да |
|
||||
| Выбор смены | Выпадающий список | Да |
|
||||
| Комментарий | Текст | Нет |
|
||||
|
||||
**Куда отправляется заявка (MVP-вариант):**
|
||||
Использовать бесплатный сервис [Formspree.io](https://formspree.io) — заявка приходит на email администратора. Настройка: 5 минут, регистрация бесплатна.
|
||||
|
||||
---
|
||||
|
||||
## 4. Из чего состоит `index.html` (одна страница, секции сверху вниз)
|
||||
|
||||
```
|
||||
[1] Шапка (header)
|
||||
— Логотип / название «Сокол»
|
||||
— Меню: О лагере | Смены | Галерея | Контакты
|
||||
— Кнопка «Записаться» (ведёт вниз на форму)
|
||||
|
||||
[2] Обложка (hero)
|
||||
— Большое фото лагеря на весь экран
|
||||
— Слоган: «Лето, которое запомнится навсегда»
|
||||
— Две кнопки: «Записаться» и «Узнать цены»
|
||||
|
||||
[3] О лагере
|
||||
— 3–4 предложения + фото команды
|
||||
|
||||
[4] Смены и цены
|
||||
— Карточки смен (данные берутся из shifts.json)
|
||||
— Кнопка «Выбрать смену» → прокрутка к форме
|
||||
|
||||
[5] Расписание дня
|
||||
— Простая таблица: время → активность
|
||||
|
||||
[6] Галерея
|
||||
— Сетка фото (12–16 штук)
|
||||
— При клике — увеличение фото
|
||||
|
||||
[7] Форма записи
|
||||
— Поля (см. раздел 3)
|
||||
— Кнопка «Отправить заявку»
|
||||
— После отправки: сообщение «Заявка принята! Мы позвоним вам в течение часа.»
|
||||
|
||||
[8] Контакты
|
||||
— Телефон (кликабельный — сразу звонит)
|
||||
— WhatsApp и Telegram (кнопки)
|
||||
— Адрес
|
||||
— Ссылка на Инстаграм: instagram.com/doc.sokol_
|
||||
|
||||
[9] Подвал (footer)
|
||||
— Название лагеря, год, ссылки
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 5. Онлайн-оплата (добавить после базового запуска)
|
||||
|
||||
Для MVP достаточно указать реквизиты и кнопку «Оплатить через Kaspi».
|
||||
Kaspi позволяет принимать оплату по номеру телефона или QR-коду — без подключения эквайринга.
|
||||
|
||||
Инструкция для разработчика:
|
||||
1. Добавить кнопку «Оплатить» рядом с каждой сменой
|
||||
2. При нажатии — показать QR-код Kaspi или номер для перевода
|
||||
3. Попросить родителя прислать скриншот оплаты в WhatsApp
|
||||
|
||||
Полноценный эквайринг (CloudPayments, Stripe) — следующий этап, не MVP.
|
||||
|
||||
---
|
||||
|
||||
## 6. Дизайн — минимальные требования
|
||||
|
||||
| Параметр | Значение |
|
||||
|---|---|
|
||||
| Основной цвет | Ярко-оранжевый `#FF6B35` или небесно-синий `#00AAFF` |
|
||||
| Фоновый цвет | Белый `#FFFFFF` |
|
||||
| Шрифт | Google Fonts: «Nunito» (весёлый, читаемый) |
|
||||
| Кнопки | Крупные, яркие, с закруглёнными углами |
|
||||
| Мобильная версия | Обязательно — меню сворачивается в «гамбургер» |
|
||||
|
||||
---
|
||||
|
||||
## 7. Как запустить проект
|
||||
|
||||
### Локально (на компьютере разработчика)
|
||||
```bash
|
||||
# 1. Скачать папку проекта
|
||||
# 2. Открыть index.html в браузере — сайт уже работает
|
||||
```
|
||||
Никаких установок не нужно.
|
||||
|
||||
### Выложить в интернет (бесплатно, за 5 минут)
|
||||
Использовать [Netlify Drop](https://app.netlify.com/drop):
|
||||
1. Зайти на сайт netlify.com/drop
|
||||
2. Перетащить папку `sokol-camp/` в браузер
|
||||
3. Готово — сайт получит адрес вида `sokol-camp.netlify.app`
|
||||
4. Позже можно подключить свой домен (например, `sokol-camp.kz`)
|
||||
|
||||
---
|
||||
|
||||
## 8. Порядок работы (чтобы уложиться в 1 час)
|
||||
|
||||
| Время | Задача |
|
||||
|---|---|
|
||||
| 0–10 мин | Создать структуру папок, вставить фото |
|
||||
| 10–25 мин | Сделать секции: шапка, обложка, о лагере |
|
||||
| 25–40 мин | Добавить смены (из JSON), форму записи |
|
||||
| 40–50 мин | Галерея, контакты, подвал |
|
||||
| 50–60 мин | Проверить на телефоне, выложить на Netlify |
|
||||
|
||||
---
|
||||
|
||||
## 9. Что НЕ делать в MVP
|
||||
|
||||
- Не писать базу данных — заявки идут на email через Formspree
|
||||
- Не делать панель администратора — смены редактируются в файле `shifts.json`
|
||||
- Не подключать сложный эквайринг — только Kaspi QR
|
||||
- Не делать несколько страниц — всё на одной `index.html`
|
||||
|
||||
---
|
||||
|
||||
## 10. Ссылки и ресурсы для разработчика
|
||||
|
||||
| Ресурс | Зачем |
|
||||
|---|---|
|
||||
| [formspree.io](https://formspree.io) | Приём заявок на email бесплатно |
|
||||
| [fonts.google.com](https://fonts.google.com) | Шрифт Nunito |
|
||||
| [netlify.com/drop](https://app.netlify.com/drop) | Быстрая публикация сайта |
|
||||
| [instagram.com/doc.sokol_](https://www.instagram.com/doc.sokol_/) | Фото и видео для галереи |
|
||||
| [squoosh.app](https://squoosh.app) | Сжать фото перед загрузкой |
|
||||
|
||||
---
|
||||
|
||||
*Документ составлен на основе PRD лагеря «Сокол». Версия MVP — первый запуск.*
|
||||
42
data/shifts.json
Normal file
42
data/shifts.json
Normal file
@ -0,0 +1,42 @@
|
||||
[
|
||||
{
|
||||
"id": 1,
|
||||
"name": "Смена 1 — «Старт лета»",
|
||||
"dates": "1 июня — 21 июня 2025",
|
||||
"price": 120000,
|
||||
"currency": "тенге",
|
||||
"spots_left": 12,
|
||||
"description": "Спорт, творчество, командные игры. Возраст: 7–12 лет.",
|
||||
"includes": ["3-разовое питание", "проживание в корпусе", "все мероприятия"]
|
||||
},
|
||||
{
|
||||
"id": 2,
|
||||
"name": "Смена 2 — «Приключения»",
|
||||
"dates": "25 июня — 15 июля 2025",
|
||||
"price": 135000,
|
||||
"currency": "тенге",
|
||||
"spots_left": 8,
|
||||
"description": "Походы, квесты, природа. Возраст: 10–15 лет.",
|
||||
"includes": ["3-разовое питание", "проживание в корпусе", "все мероприятия", "поход выходного дня"]
|
||||
},
|
||||
{
|
||||
"id": 3,
|
||||
"name": "Смена 3 — «Творческая лаборатория»",
|
||||
"dates": "19 июля — 8 августа 2025",
|
||||
"price": 130000,
|
||||
"currency": "тенге",
|
||||
"spots_left": 15,
|
||||
"description": "Музыка, театр, рисование, мультипликация. Возраст: 8–14 лет.",
|
||||
"includes": ["3-разовое питание", "проживание в корпусе", "мастер-классы", "итоговый концерт"]
|
||||
},
|
||||
{
|
||||
"id": 4,
|
||||
"name": "Смена 4 — «Прощание с летом»",
|
||||
"dates": "12 августа — 30 августа 2025",
|
||||
"price": 125000,
|
||||
"currency": "тенге",
|
||||
"spots_left": 20,
|
||||
"description": "Спорт, дискотеки, костры, кино под открытым небом. Возраст: 9–15 лет.",
|
||||
"includes": ["3-разовое питание", "проживание в корпусе", "все мероприятия", "выпускной"]
|
||||
}
|
||||
]
|
||||
246
index.html
Normal file
246
index.html
Normal file
@ -0,0 +1,246 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="ru">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>Детский лагерь «Сокол» — лето 2025</title>
|
||||
<meta name="description" content="Детский лагерь «Сокол»: смены, цены, расписание, запись онлайн." />
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com" />
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
|
||||
<link href="https://fonts.googleapis.com/css2?family=Nunito:wght@400;600;700;800&display=swap" rel="stylesheet" />
|
||||
<link rel="stylesheet" href="style.css" />
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<!-- [1] HEADER -->
|
||||
<header class="header" id="top">
|
||||
<div class="container header__inner">
|
||||
<a href="#top" class="logo">
|
||||
<span class="logo__mark">🦅</span>
|
||||
<span class="logo__text">Сокол</span>
|
||||
</a>
|
||||
<nav class="nav" id="nav">
|
||||
<a href="#about">О лагере</a>
|
||||
<a href="#shifts">Смены</a>
|
||||
<a href="#schedule">Расписание</a>
|
||||
<a href="#gallery">Галерея</a>
|
||||
<a href="#contacts">Контакты</a>
|
||||
</nav>
|
||||
<a href="#signup" class="btn btn--primary btn--small nav__cta">Записаться</a>
|
||||
<button class="burger" id="burger" aria-label="Меню">
|
||||
<span></span><span></span><span></span>
|
||||
</button>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<!-- [2] HERO -->
|
||||
<section class="hero">
|
||||
<div class="hero__bg"></div>
|
||||
<div class="container hero__content">
|
||||
<h1 class="hero__title">Лето, которое запомнится навсегда</h1>
|
||||
<p class="hero__subtitle">Детский лагерь «Сокол» — спорт, друзья, приключения и творчество для детей 7–15 лет.</p>
|
||||
<div class="hero__buttons">
|
||||
<a href="#signup" class="btn btn--primary">Записаться</a>
|
||||
<a href="#shifts" class="btn btn--secondary">Узнать цены</a>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- [3] ABOUT -->
|
||||
<section class="section" id="about">
|
||||
<div class="container about">
|
||||
<div class="about__text">
|
||||
<h2>О лагере</h2>
|
||||
<p>«Сокол» — детский лагерь с 30-летней историей. Корпуса в сосновом лесу, своё озеро, спортивные площадки и опытные вожатые.</p>
|
||||
<p>Каждая смена — отдельная тема: спорт, творчество, природа. Дети возвращаются домой с новыми друзьями и яркими историями.</p>
|
||||
<ul class="about__points">
|
||||
<li>✅ Лицензированные педагоги и медики</li>
|
||||
<li>✅ Соотношение 1 вожатый на 8 детей</li>
|
||||
<li>✅ Питание 3 раза в день + полдник</li>
|
||||
<li>✅ Круглосуточная охрана территории</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="about__photo" aria-label="Команда лагеря"></div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- [4] SHIFTS -->
|
||||
<section class="section section--gray" id="shifts">
|
||||
<div class="container">
|
||||
<h2 class="section__title">Смены и цены</h2>
|
||||
<p class="section__lead">Выбирайте удобные даты. Места ограничены.</p>
|
||||
<div class="shifts" id="shifts-grid">
|
||||
<!-- shift cards rendered by script.js -->
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- [5] SCHEDULE -->
|
||||
<section class="section" id="schedule">
|
||||
<div class="container">
|
||||
<h2 class="section__title">Расписание дня</h2>
|
||||
<p class="section__lead">Чем занят ребёнок с утра до вечера.</p>
|
||||
<table class="schedule">
|
||||
<thead>
|
||||
<tr><th>Время</th><th>Активность</th></tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr><td>08:00</td><td>Подъём, зарядка на свежем воздухе</td></tr>
|
||||
<tr><td>09:00</td><td>Завтрак</td></tr>
|
||||
<tr><td>10:00</td><td>Кружки и мастер-классы</td></tr>
|
||||
<tr><td>12:30</td><td>Спорт и игры на улице</td></tr>
|
||||
<tr><td>14:00</td><td>Обед</td></tr>
|
||||
<tr><td>15:00</td><td>Тихий час</td></tr>
|
||||
<tr><td>16:30</td><td>Полдник</td></tr>
|
||||
<tr><td>17:00</td><td>Командные игры, бассейн</td></tr>
|
||||
<tr><td>19:00</td><td>Ужин</td></tr>
|
||||
<tr><td>20:00</td><td>Вечернее мероприятие, дискотека</td></tr>
|
||||
<tr><td>22:00</td><td>Отбой</td></tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- [6] GALLERY -->
|
||||
<section class="section section--gray" id="gallery">
|
||||
<div class="container">
|
||||
<h2 class="section__title">Галерея</h2>
|
||||
<p class="section__lead">Так выглядит лето в «Соколе».</p>
|
||||
<div class="gallery" id="gallery-grid">
|
||||
<!-- gallery items rendered by script.js -->
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- [7] SIGNUP -->
|
||||
<section class="section" id="signup">
|
||||
<div class="container signup">
|
||||
<div class="signup__info">
|
||||
<h2>Запись в лагерь</h2>
|
||||
<p>Оставьте заявку — администратор перезвонит в течение часа, расскажет о свободных местах и поможет с оплатой.</p>
|
||||
<p class="signup__note">Заявка ни к чему не обязывает. Оплата — только после подтверждения.</p>
|
||||
</div>
|
||||
<form class="form" id="signup-form" novalidate>
|
||||
<label class="form__field">
|
||||
<span>Имя ребёнка *</span>
|
||||
<input type="text" name="child_name" required />
|
||||
</label>
|
||||
<label class="form__field">
|
||||
<span>Возраст ребёнка *</span>
|
||||
<input type="number" name="child_age" min="5" max="17" required />
|
||||
</label>
|
||||
<label class="form__field">
|
||||
<span>Имя родителя *</span>
|
||||
<input type="text" name="parent_name" required />
|
||||
</label>
|
||||
<label class="form__field">
|
||||
<span>Телефон *</span>
|
||||
<input type="tel" name="phone" placeholder="+7 ___ ___ __ __" required />
|
||||
</label>
|
||||
<label class="form__field">
|
||||
<span>Смена *</span>
|
||||
<select name="shift" id="shift-select" required>
|
||||
<option value="">— выберите смену —</option>
|
||||
</select>
|
||||
</label>
|
||||
<label class="form__field form__field--wide">
|
||||
<span>Комментарий</span>
|
||||
<textarea name="comment" rows="3" placeholder="Особенности, аллергии, пожелания..."></textarea>
|
||||
</label>
|
||||
<button type="submit" class="btn btn--primary form__submit">Отправить заявку</button>
|
||||
<p class="form__success" id="form-success" hidden>
|
||||
🎉 Заявка принята! Мы позвоним вам в течение часа.
|
||||
</p>
|
||||
</form>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- [7.5] PAYMENT -->
|
||||
<section class="section section--gray" id="payment">
|
||||
<div class="container">
|
||||
<h2 class="section__title">Оплата</h2>
|
||||
<p class="section__lead">После подтверждения заявки администратором.</p>
|
||||
<div class="payment-simple">
|
||||
<div class="pay-card">
|
||||
<div class="pay-card__icon">💳</div>
|
||||
<h3>Kaspi перевод</h3>
|
||||
<p class="pay-card__big">+7 700 123 45 67</p>
|
||||
<p>Получатель: Сокол ИП</p>
|
||||
<p class="pay-card__hint">В комментарии: имя ребёнка и номер смены</p>
|
||||
</div>
|
||||
<div class="pay-card">
|
||||
<div class="pay-card__icon">🏦</div>
|
||||
<h3>Банковский счёт</h3>
|
||||
<p>АО «Народный Банк»</p>
|
||||
<p>ИИК: KZ123456789012345678</p>
|
||||
<p>БИН: 123456789012</p>
|
||||
</div>
|
||||
<div class="pay-card">
|
||||
<div class="pay-card__icon">📱</div>
|
||||
<h3>Подтверждение</h3>
|
||||
<p>Пришлите скриншот оплаты в WhatsApp:</p>
|
||||
<p class="pay-card__big">
|
||||
<a href="https://wa.me/77001234567" target="_blank" rel="noopener">+7 700 123 45 67</a>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- [8] CONTACTS -->
|
||||
<section class="section section--gray" id="contacts">
|
||||
<div class="container contacts">
|
||||
<h2 class="section__title">Контакты</h2>
|
||||
<div class="contacts__grid">
|
||||
<div class="contact-card">
|
||||
<div class="contact-card__icon">📞</div>
|
||||
<h3>Телефон</h3>
|
||||
<a href="tel:+77001234567">+7 700 123 45 67</a>
|
||||
<p class="contact-card__sub">Ежедневно с 9:00 до 21:00</p>
|
||||
</div>
|
||||
<div class="contact-card">
|
||||
<div class="contact-card__icon">💬</div>
|
||||
<h3>Мессенджеры</h3>
|
||||
<a href="https://wa.me/77001234567" target="_blank" rel="noopener">WhatsApp</a>
|
||||
<a href="https://t.me/sokol_camp" target="_blank" rel="noopener">Telegram</a>
|
||||
</div>
|
||||
<div class="contact-card">
|
||||
<div class="contact-card__icon">📍</div>
|
||||
<h3>Адрес</h3>
|
||||
<p>Алматинская обл., Талгарский район, урочище «Сосновый бор»</p>
|
||||
</div>
|
||||
<div class="contact-card">
|
||||
<div class="contact-card__icon">📷</div>
|
||||
<h3>Инстаграм</h3>
|
||||
<a href="https://www.instagram.com/doc.sokol_/" target="_blank" rel="noopener">@doc.sokol_</a>
|
||||
<p class="contact-card__sub">Фото и видео со смен</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- [9] FOOTER -->
|
||||
<footer class="footer">
|
||||
<div class="container footer__inner">
|
||||
<div>
|
||||
<strong>🦅 Лагерь «Сокол»</strong>
|
||||
<p>© 2025. Все права защищены.</p>
|
||||
</div>
|
||||
<nav class="footer__nav">
|
||||
<a href="#about">О лагере</a>
|
||||
<a href="#shifts">Смены</a>
|
||||
<a href="#signup">Запись</a>
|
||||
<a href="#contacts">Контакты</a>
|
||||
</nav>
|
||||
</div>
|
||||
</footer>
|
||||
|
||||
<!-- Lightbox -->
|
||||
<div class="lightbox" id="lightbox" hidden>
|
||||
<button class="lightbox__close" id="lightbox-close" aria-label="Закрыть">×</button>
|
||||
<div class="lightbox__img" id="lightbox-img"></div>
|
||||
</div>
|
||||
|
||||
<script src="script.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
165
script.js
Normal file
165
script.js
Normal file
@ -0,0 +1,165 @@
|
||||
// ========== DATA ==========
|
||||
// Mock shifts (also available in data/shifts.json — used when fetch works).
|
||||
const MOCK_SHIFTS = [
|
||||
{ id: 1, name: 'Смена 1 — «Старт лета»', dates: '1 июня — 21 июня 2025', price: 120000, currency: 'тенге', spots_left: 12,
|
||||
description: 'Спорт, творчество, командные игры. Возраст: 7–12 лет.',
|
||||
includes: ['3-разовое питание', 'проживание в корпусе', 'все мероприятия'] },
|
||||
{ id: 2, name: 'Смена 2 — «Приключения»', dates: '25 июня — 15 июля 2025', price: 135000, currency: 'тенге', spots_left: 8,
|
||||
description: 'Походы, квесты, природа. Возраст: 10–15 лет.',
|
||||
includes: ['3-разовое питание', 'проживание в корпусе', 'все мероприятия', 'поход выходного дня'] },
|
||||
{ id: 3, name: 'Смена 3 — «Творческая лаборатория»', dates: '19 июля — 8 августа 2025', price: 130000, currency: 'тенге', spots_left: 15,
|
||||
description: 'Музыка, театр, рисование, мультипликация. Возраст: 8–14 лет.',
|
||||
includes: ['3-разовое питание', 'проживание в корпусе', 'мастер-классы', 'итоговый концерт'] },
|
||||
{ id: 4, name: 'Смена 4 — «Прощание с летом»', dates: '12 августа — 30 августа 2025', price: 125000, currency: 'тенге', spots_left: 20,
|
||||
description: 'Спорт, дискотеки, костры, кино под открытым небом. Возраст: 9–15 лет.',
|
||||
includes: ['3-разовое питание', 'проживание в корпусе', 'все мероприятия', 'выпускной'] },
|
||||
];
|
||||
|
||||
// Gallery placeholders (emoji + gradient color pairs).
|
||||
const GALLERY_ITEMS = [
|
||||
{ emoji: '🏕️', from: '#FF6B35', to: '#ffa07a', alt: 'Палатки на поляне' },
|
||||
{ emoji: '🏊', from: '#00AAFF', to: '#7dd3fc', alt: 'Бассейн' },
|
||||
{ emoji: '⚽', from: '#16a34a', to: '#86efac', alt: 'Футбол' },
|
||||
{ emoji: '🎨', from: '#a855f7', to: '#d8b4fe', alt: 'Творчество' },
|
||||
{ emoji: '🔥', from: '#dc2626', to: '#fca5a5', alt: 'Костёр' },
|
||||
{ emoji: '🌲', from: '#15803d', to: '#86efac', alt: 'Сосновый лес' },
|
||||
{ emoji: '🥾', from: '#92400e', to: '#fed7aa', alt: 'Поход' },
|
||||
{ emoji: '🎸', from: '#7c3aed', to: '#c4b5fd', alt: 'Концерт' },
|
||||
{ emoji: '🏹', from: '#ea580c', to: '#fed7aa', alt: 'Стрельба из лука' },
|
||||
{ emoji: '🎭', from: '#be185d', to: '#fbcfe8', alt: 'Театр' },
|
||||
{ emoji: '🚴', from: '#0891b2', to: '#a5f3fc', alt: 'Велопрогулка' },
|
||||
{ emoji: '⭐', from: '#facc15', to: '#fef08a', alt: 'Вечернее небо' },
|
||||
{ emoji: '🏐', from: '#2563eb', to: '#bfdbfe', alt: 'Волейбол' },
|
||||
{ emoji: '🎤', from: '#db2777', to: '#fbcfe8', alt: 'Дискотека' },
|
||||
{ emoji: '🦅', from: '#475569', to: '#cbd5e1', alt: 'Символ лагеря' },
|
||||
{ emoji: '🍉', from: '#dc2626', to: '#86efac', alt: 'Полдник' },
|
||||
];
|
||||
|
||||
// ========== HELPERS ==========
|
||||
const $ = (sel) => document.querySelector(sel);
|
||||
const $$ = (sel) => document.querySelectorAll(sel);
|
||||
const fmtPrice = (n) => n.toLocaleString('ru-RU');
|
||||
|
||||
async function loadShifts() {
|
||||
try {
|
||||
const r = await fetch('data/shifts.json');
|
||||
if (!r.ok) throw new Error('fetch failed');
|
||||
return await r.json();
|
||||
} catch (_) {
|
||||
// file:// or offline — fall back to embedded mock
|
||||
return MOCK_SHIFTS;
|
||||
}
|
||||
}
|
||||
|
||||
// ========== RENDER: SHIFTS ==========
|
||||
function renderShifts(shifts) {
|
||||
const grid = $('#shifts-grid');
|
||||
const select = $('#shift-select');
|
||||
grid.innerHTML = shifts.map((s) => {
|
||||
const lowSpots = s.spots_left <= 10;
|
||||
const includes = s.includes.map((i) => `<li>${i}</li>`).join('');
|
||||
return `
|
||||
<article class="shift" data-id="${s.id}">
|
||||
<h3 class="shift__name">${s.name}</h3>
|
||||
<div class="shift__dates">📅 ${s.dates}</div>
|
||||
<p class="shift__desc">${s.description}</p>
|
||||
<ul class="shift__includes">${includes}</ul>
|
||||
<div class="shift__price-row">
|
||||
<div class="shift__price">${fmtPrice(s.price)} <small>${s.currency}</small></div>
|
||||
<div class="shift__spots ${lowSpots ? 'shift__spots--low' : ''}">
|
||||
Мест: ${s.spots_left}
|
||||
</div>
|
||||
</div>
|
||||
<div class="shift__buttons">
|
||||
<button class="btn btn--primary" data-action="signup" data-shift="${s.id}">Выбрать смену</button>
|
||||
</div>
|
||||
</article>
|
||||
`;
|
||||
}).join('');
|
||||
|
||||
// Populate the select for the form
|
||||
select.innerHTML = '<option value="">— выберите смену —</option>' +
|
||||
shifts.map((s) => `<option value="${s.id}">${s.name} (${s.dates})</option>`).join('');
|
||||
|
||||
// Wire card buttons
|
||||
grid.addEventListener('click', (e) => {
|
||||
const btn = e.target.closest('button[data-action]');
|
||||
if (!btn) return;
|
||||
const shiftId = btn.dataset.shift;
|
||||
if (btn.dataset.action === 'signup') {
|
||||
select.value = shiftId;
|
||||
$('#signup').scrollIntoView({ behavior: 'smooth' });
|
||||
setTimeout(() => $('input[name="child_name"]').focus(), 600);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// ========== RENDER: GALLERY ==========
|
||||
function renderGallery() {
|
||||
const grid = $('#gallery-grid');
|
||||
grid.innerHTML = GALLERY_ITEMS.map((g, i) => `
|
||||
<div class="gallery__item" data-i="${i}"
|
||||
style="background: linear-gradient(135deg, ${g.from}, ${g.to});"
|
||||
aria-label="${g.alt}">
|
||||
${g.emoji}
|
||||
</div>
|
||||
`).join('');
|
||||
|
||||
grid.addEventListener('click', (e) => {
|
||||
const item = e.target.closest('.gallery__item');
|
||||
if (!item) return;
|
||||
const g = GALLERY_ITEMS[Number(item.dataset.i)];
|
||||
const lb = $('#lightbox-img');
|
||||
lb.style.background = `linear-gradient(135deg, ${g.from}, ${g.to})`;
|
||||
lb.textContent = g.emoji;
|
||||
$('#lightbox').hidden = false;
|
||||
});
|
||||
}
|
||||
|
||||
// ========== LIGHTBOX ==========
|
||||
function initLightbox() {
|
||||
const lb = $('#lightbox');
|
||||
$('#lightbox-close').addEventListener('click', () => { lb.hidden = true; });
|
||||
lb.addEventListener('click', (e) => { if (e.target === lb) lb.hidden = true; });
|
||||
document.addEventListener('keydown', (e) => { if (e.key === 'Escape') lb.hidden = true; });
|
||||
}
|
||||
|
||||
// ========== BURGER MENU ==========
|
||||
function initBurger() {
|
||||
const nav = $('#nav');
|
||||
const burger = $('#burger');
|
||||
burger.addEventListener('click', () => nav.classList.toggle('is-open'));
|
||||
nav.addEventListener('click', (e) => {
|
||||
if (e.target.tagName === 'A') nav.classList.remove('is-open');
|
||||
});
|
||||
}
|
||||
|
||||
// ========== FORM ==========
|
||||
function initForm() {
|
||||
const form = $('#signup-form');
|
||||
const success = $('#form-success');
|
||||
form.addEventListener('submit', (e) => {
|
||||
e.preventDefault();
|
||||
if (!form.checkValidity()) {
|
||||
form.reportValidity();
|
||||
return;
|
||||
}
|
||||
const data = Object.fromEntries(new FormData(form).entries());
|
||||
// MVP: log to console (real impl would POST to Formspree).
|
||||
console.log('Заявка:', data);
|
||||
success.hidden = false;
|
||||
form.querySelectorAll('input, select, textarea').forEach((el) => { el.value = ''; });
|
||||
success.scrollIntoView({ behavior: 'smooth', block: 'center' });
|
||||
setTimeout(() => { success.hidden = true; }, 8000);
|
||||
});
|
||||
}
|
||||
|
||||
// ========== INIT ==========
|
||||
(async function init() {
|
||||
const shifts = await loadShifts();
|
||||
renderShifts(shifts);
|
||||
renderGallery();
|
||||
initLightbox();
|
||||
initBurger();
|
||||
initForm();
|
||||
})();
|
||||
306
style.css
Normal file
306
style.css
Normal file
@ -0,0 +1,306 @@
|
||||
/* ========== RESET / BASE ========== */
|
||||
*, *::before, *::after { box-sizing: border-box; }
|
||||
html { scroll-behavior: smooth; }
|
||||
body {
|
||||
margin: 0;
|
||||
font-family: 'Nunito', -apple-system, BlinkMacSystemFont, sans-serif;
|
||||
font-weight: 400;
|
||||
color: #1f2937;
|
||||
background: #fff;
|
||||
line-height: 1.6;
|
||||
}
|
||||
h1, h2, h3 { margin: 0 0 12px; font-weight: 800; color: #0f172a; line-height: 1.2; }
|
||||
h2 { font-size: 2rem; }
|
||||
p { margin: 0 0 12px; }
|
||||
a { color: #FF6B35; text-decoration: none; }
|
||||
a:hover { text-decoration: underline; }
|
||||
img { max-width: 100%; display: block; }
|
||||
|
||||
.container { width: 100%; max-width: 1140px; margin: 0 auto; padding: 0 20px; }
|
||||
|
||||
:root {
|
||||
--orange: #FF6B35;
|
||||
--orange-dark: #e55522;
|
||||
--blue: #00AAFF;
|
||||
--gray-bg: #f8fafc;
|
||||
--border: #e5e7eb;
|
||||
--shadow: 0 4px 12px rgba(0,0,0,0.08);
|
||||
--shadow-hover: 0 8px 24px rgba(0,0,0,0.12);
|
||||
}
|
||||
|
||||
/* ========== BUTTONS ========== */
|
||||
.btn {
|
||||
display: inline-block;
|
||||
padding: 14px 28px;
|
||||
border-radius: 999px;
|
||||
font-weight: 700;
|
||||
font-size: 1rem;
|
||||
cursor: pointer;
|
||||
border: none;
|
||||
transition: transform 0.15s ease, box-shadow 0.15s ease, background 0.15s ease;
|
||||
text-align: center;
|
||||
}
|
||||
.btn:hover { transform: translateY(-2px); text-decoration: none; box-shadow: var(--shadow-hover); }
|
||||
.btn--primary { background: var(--orange); color: #fff; }
|
||||
.btn--primary:hover { background: var(--orange-dark); color: #fff; }
|
||||
.btn--secondary { background: #fff; color: var(--orange); border: 2px solid var(--orange); }
|
||||
.btn--secondary:hover { background: var(--orange); color: #fff; }
|
||||
.btn--small { padding: 10px 20px; font-size: 0.95rem; }
|
||||
.btn--ghost { background: transparent; color: var(--blue); border: 2px solid var(--blue); }
|
||||
.btn--ghost:hover { background: var(--blue); color: #fff; }
|
||||
|
||||
/* ========== HEADER ========== */
|
||||
.header {
|
||||
position: sticky; top: 0; z-index: 50;
|
||||
background: #fff;
|
||||
border-bottom: 1px solid var(--border);
|
||||
}
|
||||
.header__inner {
|
||||
display: flex; align-items: center; justify-content: space-between;
|
||||
height: 70px;
|
||||
}
|
||||
.logo { display: flex; align-items: center; gap: 8px; font-weight: 800; font-size: 1.3rem; color: #0f172a; }
|
||||
.logo:hover { text-decoration: none; }
|
||||
.logo__mark { font-size: 1.6rem; }
|
||||
.nav { display: flex; gap: 24px; }
|
||||
.nav a { color: #334155; font-weight: 600; }
|
||||
.nav a:hover { color: var(--orange); text-decoration: none; }
|
||||
.nav__cta { margin-left: 16px; }
|
||||
.burger { display: none; background: none; border: none; cursor: pointer; padding: 8px; }
|
||||
.burger span { display: block; width: 26px; height: 3px; background: #0f172a; margin: 5px 0; border-radius: 2px; transition: 0.3s; }
|
||||
|
||||
/* ========== HERO ========== */
|
||||
.hero { position: relative; min-height: 80vh; display: flex; align-items: center; color: #fff; overflow: hidden; }
|
||||
.hero__bg {
|
||||
position: absolute; inset: 0;
|
||||
background:
|
||||
linear-gradient(135deg, rgba(255,107,53,0.85) 0%, rgba(0,170,255,0.75) 100%),
|
||||
radial-gradient(circle at 30% 40%, #ffd166 0%, transparent 50%),
|
||||
linear-gradient(180deg, #4a90e2 0%, #2c5282 100%);
|
||||
z-index: -1;
|
||||
}
|
||||
.hero__bg::after {
|
||||
content: ''; position: absolute; inset: 0;
|
||||
background-image:
|
||||
radial-gradient(circle at 20% 80%, rgba(255,255,255,0.1) 0%, transparent 30%),
|
||||
radial-gradient(circle at 80% 20%, rgba(255,255,255,0.15) 0%, transparent 40%);
|
||||
}
|
||||
.hero__content { position: relative; padding: 80px 20px; }
|
||||
.hero__title { font-size: 3rem; color: #fff; max-width: 700px; text-shadow: 0 2px 12px rgba(0,0,0,0.3); }
|
||||
.hero__subtitle { font-size: 1.25rem; max-width: 600px; text-shadow: 0 1px 6px rgba(0,0,0,0.3); }
|
||||
.hero__buttons { display: flex; gap: 16px; flex-wrap: wrap; margin-top: 24px; }
|
||||
|
||||
/* ========== SECTION ========== */
|
||||
.section { padding: 80px 0; }
|
||||
.section--gray { background: var(--gray-bg); }
|
||||
.section__title { text-align: center; }
|
||||
.section__lead { text-align: center; color: #64748b; margin-bottom: 40px; font-size: 1.1rem; }
|
||||
|
||||
/* ========== ABOUT ========== */
|
||||
.about { display: grid; grid-template-columns: 1.2fr 1fr; gap: 48px; align-items: center; }
|
||||
.about__points { list-style: none; padding: 0; margin: 20px 0 0; }
|
||||
.about__points li { padding: 8px 0; font-size: 1.05rem; }
|
||||
.about__photo {
|
||||
height: 360px; border-radius: 20px;
|
||||
background:
|
||||
linear-gradient(135deg, rgba(255,107,53,0.3), rgba(0,170,255,0.3)),
|
||||
repeating-linear-gradient(45deg, #fef3c7, #fef3c7 20px, #fde68a 20px, #fde68a 40px);
|
||||
position: relative;
|
||||
box-shadow: var(--shadow);
|
||||
}
|
||||
.about__photo::before {
|
||||
content: '👨👩👧👦';
|
||||
position: absolute; inset: 0;
|
||||
display: flex; align-items: center; justify-content: center;
|
||||
font-size: 6rem;
|
||||
}
|
||||
|
||||
/* ========== SHIFTS ========== */
|
||||
.shifts {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
|
||||
gap: 24px;
|
||||
}
|
||||
.shift {
|
||||
background: #fff;
|
||||
border-radius: 16px;
|
||||
padding: 28px;
|
||||
box-shadow: var(--shadow);
|
||||
display: flex; flex-direction: column;
|
||||
transition: transform 0.2s ease, box-shadow 0.2s ease;
|
||||
border-top: 4px solid var(--orange);
|
||||
}
|
||||
.shift:nth-child(even) { border-top-color: var(--blue); }
|
||||
.shift:hover { transform: translateY(-4px); box-shadow: var(--shadow-hover); }
|
||||
.shift__name { font-size: 1.25rem; }
|
||||
.shift__dates { color: #64748b; font-weight: 600; margin-bottom: 12px; }
|
||||
.shift__desc { flex-grow: 0; color: #334155; }
|
||||
.shift__includes { list-style: none; padding: 0; margin: 12px 0; font-size: 0.95rem; color: #475569; }
|
||||
.shift__includes li { padding: 3px 0; }
|
||||
.shift__includes li::before { content: '✓ '; color: var(--orange); font-weight: 700; }
|
||||
.shift__price-row {
|
||||
display: flex; align-items: baseline; justify-content: space-between;
|
||||
margin: 16px 0 12px; padding-top: 16px; border-top: 1px solid var(--border);
|
||||
}
|
||||
.shift__price { font-size: 1.6rem; font-weight: 800; color: #0f172a; }
|
||||
.shift__price small { font-size: 0.9rem; color: #64748b; font-weight: 600; }
|
||||
.shift__spots { font-size: 0.9rem; color: #16a34a; font-weight: 700; }
|
||||
.shift__spots--low { color: #dc2626; }
|
||||
.shift__buttons { display: flex; gap: 8px; margin-top: auto; }
|
||||
.shift__buttons .btn { flex: 1; padding: 12px 16px; font-size: 0.95rem; }
|
||||
|
||||
/* ========== SCHEDULE ========== */
|
||||
.schedule {
|
||||
width: 100%; max-width: 700px; margin: 0 auto;
|
||||
border-collapse: collapse;
|
||||
background: #fff; border-radius: 16px; overflow: hidden;
|
||||
box-shadow: var(--shadow);
|
||||
}
|
||||
.schedule th, .schedule td { padding: 14px 20px; text-align: left; border-bottom: 1px solid var(--border); }
|
||||
.schedule th { background: var(--orange); color: #fff; font-weight: 700; }
|
||||
.schedule tbody tr:last-child td { border-bottom: none; }
|
||||
.schedule tbody tr:hover { background: #fff7ed; }
|
||||
.schedule td:first-child { font-weight: 700; color: var(--orange); width: 100px; }
|
||||
|
||||
/* ========== GALLERY ========== */
|
||||
.gallery {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fill, minmax(180px, 1fr));
|
||||
gap: 12px;
|
||||
}
|
||||
.gallery__item {
|
||||
aspect-ratio: 1 / 1;
|
||||
border-radius: 12px;
|
||||
cursor: pointer;
|
||||
overflow: hidden;
|
||||
position: relative;
|
||||
transition: transform 0.2s ease, box-shadow 0.2s ease;
|
||||
display: flex; align-items: center; justify-content: center;
|
||||
font-size: 3rem;
|
||||
}
|
||||
.gallery__item:hover { transform: scale(1.03); box-shadow: var(--shadow-hover); }
|
||||
|
||||
/* ========== SIGNUP / FORM ========== */
|
||||
.signup { display: grid; grid-template-columns: 1fr 1.3fr; gap: 48px; align-items: start; }
|
||||
.signup__info h2 { text-align: left; }
|
||||
.signup__note { color: #64748b; font-size: 0.95rem; font-style: italic; }
|
||||
.form {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1fr;
|
||||
gap: 16px;
|
||||
background: #fff;
|
||||
padding: 32px;
|
||||
border-radius: 16px;
|
||||
box-shadow: var(--shadow);
|
||||
}
|
||||
.form__field { display: flex; flex-direction: column; gap: 6px; font-weight: 600; font-size: 0.95rem; color: #334155; }
|
||||
.form__field--wide { grid-column: 1 / -1; }
|
||||
.form__field input, .form__field select, .form__field textarea {
|
||||
padding: 12px 14px;
|
||||
border: 2px solid var(--border);
|
||||
border-radius: 10px;
|
||||
font-family: inherit;
|
||||
font-size: 1rem;
|
||||
font-weight: 400;
|
||||
transition: border-color 0.15s ease;
|
||||
background: #fff;
|
||||
}
|
||||
.form__field input:focus, .form__field select:focus, .form__field textarea:focus {
|
||||
outline: none; border-color: var(--orange);
|
||||
}
|
||||
.form__field input:invalid:not(:placeholder-shown) { border-color: #dc2626; }
|
||||
.form__submit { grid-column: 1 / -1; }
|
||||
.form__success {
|
||||
grid-column: 1 / -1;
|
||||
background: #dcfce7;
|
||||
color: #166534;
|
||||
padding: 14px 18px;
|
||||
border-radius: 10px;
|
||||
font-weight: 700;
|
||||
text-align: center;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
/* ========== PAYMENT ========== */
|
||||
.payment-simple {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
|
||||
gap: 20px;
|
||||
}
|
||||
.pay-card {
|
||||
background: #fff;
|
||||
padding: 28px 24px;
|
||||
border-radius: 14px;
|
||||
text-align: center;
|
||||
box-shadow: var(--shadow);
|
||||
}
|
||||
.pay-card__icon { font-size: 2.5rem; margin-bottom: 8px; }
|
||||
.pay-card h3 { font-size: 1.15rem; }
|
||||
.pay-card p { margin: 6px 0; color: #334155; }
|
||||
.pay-card__big { font-size: 1.25rem; font-weight: 700; color: #0f172a; }
|
||||
.pay-card__hint { font-size: 0.9rem; color: #64748b; font-style: italic; }
|
||||
.pay-card a { font-weight: 700; }
|
||||
|
||||
/* ========== CONTACTS ========== */
|
||||
.contacts__grid {
|
||||
display: grid; grid-template-columns: repeat(auto-fit, minmax(220px, 1fr)); gap: 20px;
|
||||
margin-top: 32px;
|
||||
}
|
||||
.contact-card {
|
||||
background: #fff;
|
||||
padding: 24px;
|
||||
border-radius: 14px;
|
||||
text-align: center;
|
||||
box-shadow: var(--shadow);
|
||||
}
|
||||
.contact-card__icon { font-size: 2.5rem; margin-bottom: 8px; }
|
||||
.contact-card h3 { font-size: 1.1rem; }
|
||||
.contact-card a { display: block; font-weight: 700; padding: 4px 0; font-size: 1.05rem; }
|
||||
.contact-card__sub { font-size: 0.9rem; color: #64748b; margin-top: 6px; }
|
||||
|
||||
/* ========== FOOTER ========== */
|
||||
.footer { background: #0f172a; color: #cbd5e1; padding: 32px 0; }
|
||||
.footer__inner { display: flex; justify-content: space-between; align-items: center; flex-wrap: wrap; gap: 16px; }
|
||||
.footer strong { color: #fff; font-size: 1.1rem; }
|
||||
.footer p { margin: 4px 0 0; font-size: 0.9rem; }
|
||||
.footer__nav { display: flex; gap: 20px; flex-wrap: wrap; }
|
||||
.footer__nav a { color: #cbd5e1; font-weight: 600; }
|
||||
.footer__nav a:hover { color: var(--orange); }
|
||||
|
||||
/* ========== LIGHTBOX ========== */
|
||||
.lightbox[hidden] { display: none !important; }
|
||||
.lightbox {
|
||||
position: fixed; inset: 0; z-index: 100;
|
||||
background: rgba(0,0,0,0.92);
|
||||
display: flex; align-items: center; justify-content: center;
|
||||
padding: 20px;
|
||||
}
|
||||
.lightbox__img {
|
||||
width: min(80vw, 600px); height: min(80vh, 600px);
|
||||
border-radius: 16px;
|
||||
display: flex; align-items: center; justify-content: center;
|
||||
font-size: 12rem;
|
||||
}
|
||||
.lightbox__close {
|
||||
position: absolute; top: 16px; right: 24px;
|
||||
background: none; border: none; color: #fff; font-size: 3rem; cursor: pointer; line-height: 1;
|
||||
}
|
||||
|
||||
/* ========== MOBILE ========== */
|
||||
@media (max-width: 860px) {
|
||||
.nav, .nav__cta { display: none; }
|
||||
.nav.is-open {
|
||||
display: flex; flex-direction: column;
|
||||
position: absolute; top: 70px; left: 0; right: 0;
|
||||
background: #fff; padding: 20px; gap: 16px;
|
||||
box-shadow: var(--shadow);
|
||||
border-top: 1px solid var(--border);
|
||||
}
|
||||
.burger { display: block; }
|
||||
.hero__title { font-size: 2.2rem; }
|
||||
.hero__subtitle { font-size: 1.1rem; }
|
||||
.about, .signup { grid-template-columns: 1fr; }
|
||||
.form { grid-template-columns: 1fr; padding: 24px; }
|
||||
.section { padding: 56px 0; }
|
||||
h2 { font-size: 1.6rem; }
|
||||
}
|
||||
Reference in New Issue
Block a user