Initial commit

This commit is contained in:
2026-02-05 18:09:28 +03:00
commit d6ee21c9d7
24 changed files with 2645 additions and 0 deletions

19
.gitignore vendored Normal file
View File

@@ -0,0 +1,19 @@
!**/glob-import/dir/node_modules
.DS_Store
.idea
.pnpm-store
*.cpuprofile
*.local
*.log
/.vscode/
/docs/.vitepress/cache
/docs/.vitepress/.temp
/packages/vite/LICENSE
dist
dist-ssr
explorations
node_modules
playground-temp
temp
TODOs.md
.eslintcache

55
CLAUDE.md Normal file
View File

@@ -0,0 +1,55 @@
# CLAUDE.md
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
## Project Overview
A brutalist editorial landing page for Alina Mamut, a brand strategy and creative consulting professional. The site is a premium magazine-style single-page website showcasing four service offerings, with content primarily in Russian.
**Status**: Pre-development — only `PLANNING.md` (content + design specs) and `design-spec.jpg` (visual spec) exist. No framework or build tooling has been chosen yet.
## Design System
Strict visual identity — do not deviate from these values.
**Typography**:
- Headlines: **Druk Wide Bold** (tight line-height ~0.9)
- Body: **Inter Regular** only — no medium/bold weights for body text
- Desktop: H1 48px/40px, H2 31px/30px, H3 24px/20px, Body 16px/18px, Caption 16px/44px
- Mobile: H1 32px/40px, H2 34px/30px, H3 20px/80px, Body 16px/14px, Caption 14px/12px
**Color palette** (flat only — no gradients, shadows, or cards):
| Name | Hex |
|------|-----|
| Blue | `#007DDA` |
| Warm White | `#E7F2EA` |
| Stone Grey | `#FCC3C3` |
| Ink Black | `#BD5E24` |
| Oxide Red | `#FB9322` |
**Grid**:
- Desktop: 12 columns, 1200px container, 1424px max-width, 32px gutters
- Mobile: 4 columns, 20px margins
- Vertical spacing between sections: 160220px
**Design don'ts**: No phone mockups, no SaaS/startup patterns, no subscription-style UI, no shadowed text, no icons, pills, or card components.
## Page Structure (5 Screens)
1. **Hero** — Massive left-aligned headline (~7 cols), smartphone mockup center-right (~4 cols), small editorial annotations with thin hairline connectors, primary CTA
2. **Manifest** — Asymmetric layout, large text block (5 cols), opposite side mostly empty with small caption
3. **Journal Preview** — Large image breaking grid (~7 cols), offset text block (~4 cols), oversized faded number in background
4. **Selected Cases** — Dark background, 2×2 editorial image tiles (6 cols each), overlapping titles
5. **Access/FAQ** — Editorial accordion (8 cols centered), numbered thin rows, one-at-a-time expand behavior
**Header**: Minimal sticky nav — wordmark left, text anchors right. Buttons: rectangular, 24px border-radius.
## Content
All service descriptions and UI copy are in Russian (see `PLANNING.md` for full text). Four service sections expand via accordion:
1. Creative & strategy consultations
2. Brand platform development
3. Communication strategies
4. Special projects & creative concepts
CTA directs to Telegram: @alinamamut

43
IMPLEMENTATION.md Normal file
View File

@@ -0,0 +1,43 @@
# Implementation Summary
## Tech Stack
- **Vite 6** + Vanilla HTML/CSS/JS (no framework)
- **Archivo** (Google Fonts, expanded width, weight 900) for headlines
- **Inter** (Google Fonts, weight 400) for body text
## Project Structure
```
├── index.html # Single page with all 5 screens
├── package.json
├── vite.config.js
├── public/
├── src/
│ ├── main.js # Scroll reveal, smooth scroll, header scroll
│ ├── style.css # Master @import file
│ ├── css/
│ │ ├── reset.css # Modern CSS reset
│ │ ├── tokens.css # Design tokens (colors, type, spacing, grid)
│ │ ├── base.css # Typography classes (.h1, .h2, .h3)
│ │ ├── grid.css # 12-col grid + utilities
│ │ ├── components.css # Buttons, annotations, hairlines
│ │ ├── header.css # Sticky header
│ │ ├── hero.css # Screen 1
│ │ ├── manifest.css # Screen 2
│ │ ├── journal.css # Screen 3
│ │ ├── cases.css # Screen 4
│ │ ├── services.css # Screen 5 (accordion)
│ │ ├── footer.css
│ │ └── animations.css # Scroll-driven + IntersectionObserver fallback
│ └── assets/
```
## Running
- `npm run dev` — development server with HMR
- `npm run build` — production build to `dist/`
- `npm run preview` — preview production build
## Design Decisions
- Native `<details name="accordion">` for one-at-a-time accordion (zero JS)
- CSS `animation-timeline: view()` with IntersectionObserver fallback
- Colored placeholder blocks instead of images (swap with `<img>` later)
- BEM-lite class naming

142
PLANNING.md Normal file
View File

@@ -0,0 +1,142 @@
Here is the plan, that needs to be done, combining several inputs and tasks.
# Initial goal, reasoning and explanation of pages (in Russian):
Раздел 1:
1. Консультации по креативу и стратегии
Выпадающий текст:
Когда это нужно
• Бренд чувствует, что коммуникации устарели;
• Идеи есть, но они не складываются в систему и, главное, не приносят результат;
• Команда не понимает, куда двигаться дальше;
• Нужно свежее, независимое видение.
Что вы получаете
• Разбор текущей коммуникации бренда;
• Анализ визуального языка и смыслов;
• Точки роста и возможности для отстройки;
• Направления для креатива и спецпроектов.
Как происходит работа:
1. Оперативный созвон-знакомство, вы заполняете бриф, по которому я готовлюсь к консультации;
2. 2-часовая консультация;
3. Презентация с рекомендациями и планом работ.
Раздел 2:
2. Бренд-платформа
Выпадающий текст:
Когда это нужно
• Проект не растет, нет клиентов;
• Коммуникации выглядят разрозненно;
• Нет четкого позиционирования и голоса;
• Нет понимания, кто аудитория проекта;
• Сложно масштабировать маркетинг.
Что вы получаете
• Ядро бренда: аудитория, конкуренты, миссия, ценности, характер;
• Чёткое позиционирование и big idea;
• Tone of voice и визуальные принципы;
• Основу для всех коммуникаций.
Как происходит работа:
1. Оперативный созвон-знакомство, вы заполняете бриф;
2. 2-4 недели разработки бренд-платформы анализ аудитории и конкурентов, интервью с основателем (при необходимости с командой и клиентами/потенциальными клиентами);
3. Презентация с готовой бренд-платформой.
Раздел 3:
3. Коммуникационные стратегии
Выпадающий текст:
Когда это нужно
• Бренд хочет выйти за рамки стандартной рекламы;
• Нужно привлечь новую аудиторию;
• Конкуренты выглядят ярче и смелее;
• Нет ясного сценария развития коммуникаций.
Что вы получаете
• Стратегию коммуникаций на основе трендов и инсайтов;
• Ключевые смыслы и сообщения бренда;
• Идеи форматов, контента и спецпроектов;
• Дорожную карту для кого, в каком канале, что необходимо сделать.
Как происходит работа:
1. Оперативный созвон-знакомство, вы заполняете бриф;
2. 2-4 недели разработки коммуникационной стратегии анализ аудитории и коммуникации конкурентов, анализ лучших релевантных зарубежных и локальных практик;
3. Презентация с готовой коммуникационной стратегией.
Раздел 4:
4. Идеи спецпроектов и креативные концепции
Выпадающий текст:
Когда это нужно
• Бренд хочет вау-эффект без банальных решений;
• Нужна идея, которую будут обсуждать;
• Важно выйти за рамки стандартных форматов.
Что вы получаете
• Концепции спецпроектов;
• Сценарии интеграций и коллабораций;
• Решения, которые можно масштабировать.
Как происходит работа:
1. Оперативный созвон-знакомство, вы заполняете бриф;
2. 2-3 недели разработки идеи сбор референс, анализ лучших практик, подготовка идеи;
3. Презентация с готовой коммуникационной стратегией.
Далее колл-ту-экшен:
Я могу как разработать идею, так и взять на себя всю реализацию при помощи мой команды профессионалов.
Чтобы ознакомиться с моим портфолио и реализованными кейсами, пожалуйста, напишите мне: @alinamamut
Внизу подвал с политикой конфиденциальности и тд
***
По арт-дирекшену:
1. Шрифт заголовков Druk Wide Bold
2. Шрифт основного текста Inter Regular
3. Сверстать необходимо по референту в том же стиле, что и в файле
# WebPage coding prompt that was generated by some LLM:
Create a premium editorial landing page for a cultural trend journal. The design must feel like a high-end magazine, not a startup. Style: brutal typography, strong grid, oversized type, large negative space, minimal color, zero friendly marketing patterns.
Grid: desktop 12 columns, container 1280px, max-width 1560px, gutter 32px, outer margins 96px. Vertical spacing 160220px. Mobile: 4 columns, 20px margins.
Typography: Headlines similar to Druk Wide Bold. Body Inter Regular only. No medium weights. Massive scale contrast. Tight line-height for headers (~0.9). Large readable body (~2022px desktop).
Color palette: warm white (#F7F7F5), ink black (#0A0A0A), oxide red (#B3342B), dusty blue (#6F8FA6), stone grey (#D9D9D6). Flat colors only. No gradients.
Screen 1 — Hero
Massive left-aligned headline spanning ~7 columns. Center-right smartphone mockup (~4 columns). 34 small editorial annotations with thin hairline connector lines. Primary button below headline. Leave 3040% empty space.
Screen 2 — Manifest
Asymmetric layout. Large intellectual text block (5 columns). Opposite side mostly empty with a small caption in the top corner.
Screen 3 — Journal Preview
Large issue image breaking grid (~7 columns). Text block offset vertically (~4 columns). Oversized faded issue number in background. Two buttons: primary + outline.
Screen 4 — Selected Cases
Dark background. 2×2 editorial tiles (6 columns each). No cards, no shadows. Image-led with overlapping titles.
Screen 5 — Access
Editorial accordion centered in grid (8 columns). Closed: thin rows with numbers. Open: split text + button. One item open at a time.
Header: minimal sticky nav with wordmark left, text anchors right.
Buttons: rectangular, 24px radius.
Avoid icons, cards, gradients, pills, and SaaS visuals. Make it intellectual, cultural, and expensive.
# Additional DESIGN specification
Local file called design-spec.jpg

BIN
design-spec.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 101 KiB

307
index.html Normal file
View File

@@ -0,0 +1,307 @@
<!DOCTYPE html>
<html lang="ru">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Alina Mamut — Бренд-стратегия и креативный консалтинг</title>
<meta name="description" content="Бренд-стратегия, креативный консалтинг и коммуникационные стратегии от Алины Мамут." />
<!-- Fonts -->
<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=Archivo:ital,wdth,wght@0,62..150,100..900;1,62..150,100..900&family=Inter:wght@400&display=swap" rel="stylesheet" />
<link rel="stylesheet" href="/src/style.css" />
</head>
<body>
<!-- ============ HEADER ============ -->
<header class="header" id="header">
<div class="header__inner container">
<a href="#" class="header__wordmark">ALINA MAMUT</a>
<nav class="header__nav">
<a href="#manifest" class="header__link">О подходе</a>
<a href="#journal" class="header__link">Журнал</a>
<a href="#cases" class="header__link">Кейсы</a>
<a href="#services" class="header__link">Услуги</a>
</nav>
</div>
</header>
<!-- ============ SCREEN 1: HERO ============ -->
<section class="hero" id="hero">
<div class="hero__inner container grid">
<div class="hero__headline-block col-span-7" data-reveal>
<h1 class="h1 hero__title">Бренд-стратегия<br />и креативный<br />консалтинг</h1>
<p class="body-text hero__subtitle">Помогаю брендам находить свой голос, формировать стратегию и создавать коммуникации, которые работают.</p>
<a href="https://t.me/alinamamut" class="btn btn--primary hero__cta" target="_blank" rel="noopener">Написать в Telegram</a>
</div>
<div class="hero__editorial col-start-8 col-span-5" data-reveal>
<div class="hero__image-placeholder"></div>
</div>
<div class="hero__annotations col-span-7" data-reveal>
<div class="annotation">
<div class="annotation__label">Опыт</div>
<div class="annotation__text">10+ лет в брендинге и стратегии</div>
</div>
<div class="annotation">
<div class="annotation__label">Подход</div>
<div class="annotation__text">Исследования, аналитика, креатив</div>
</div>
<div class="annotation">
<div class="annotation__label">Результат</div>
<div class="annotation__text">Система, а не разовые решения</div>
</div>
</div>
</div>
</section>
<!-- ============ SCREEN 2: MANIFEST ============ -->
<section class="manifest" id="manifest">
<div class="manifest__inner container grid">
<div class="manifest__text col-span-5" data-reveal>
<h2 class="h2 manifest__heading">Я верю, что сильный бренд — это не логотип и не визуал. Это стратегия, смыслы и последовательность.</h2>
<p class="body-text manifest__body">Каждый проект начинается с глубокого понимания: кто вы, для кого вы и зачем вы существуете. Я нахожу ответы, которые становятся основой для всех ваших коммуникаций — от позиционирования до рекламных кампаний.</p>
</div>
<div class="manifest__caption col-start-9 col-span-4" data-reveal>
<span class="caption">О подходе</span>
</div>
</div>
</section>
<!-- ============ SCREEN 3: JOURNAL PREVIEW ============ -->
<section class="journal" id="journal" data-number="01">
<div class="journal__inner container grid">
<div class="journal__image-block col-span-7" data-reveal>
<div class="journal__image-placeholder"></div>
</div>
<div class="journal__text-block col-start-9 col-span-4" data-reveal>
<h2 class="h2 journal__heading">Стратегия — это не документ. Это способ думать о бренде каждый день.</h2>
<p class="body-text journal__body">Результат моей работы — не просто презентация на 50 слайдов. Это живой инструмент, который помогает принимать решения, формировать контент и развивать бренд осознанно.</p>
<div class="journal__buttons">
<a href="https://t.me/alinamamut" class="btn btn--primary" target="_blank" rel="noopener">Обсудить проект</a>
<a href="#services" class="btn btn--outline">Подробнее об услугах</a>
</div>
</div>
</div>
</section>
<!-- ============ SCREEN 4: SELECTED CASES ============ -->
<section class="cases" id="cases">
<div class="cases__inner container">
<h2 class="h2 cases__heading" data-reveal>Избранные кейсы</h2>
<div class="cases__grid grid">
<div class="cases__tile col-span-6" data-reveal>
<div class="cases__tile-image" style="background-color: var(--color-primary);"></div>
<h3 class="h3 cases__tile-title">Ребрендинг и стратегия коммуникаций</h3>
</div>
<div class="cases__tile col-span-6" data-reveal>
<div class="cases__tile-image" style="background-color: var(--color-surface);"></div>
<h3 class="h3 cases__tile-title">Бренд-платформа с нуля</h3>
</div>
<div class="cases__tile col-span-6" data-reveal>
<div class="cases__tile-image" style="background-color: var(--color-ink);"></div>
<h3 class="h3 cases__tile-title">Креативная концепция спецпроекта</h3>
</div>
<div class="cases__tile col-span-6" data-reveal>
<div class="cases__tile-image" style="background-color: var(--color-accent);"></div>
<h3 class="h3 cases__tile-title">Коммуникационная стратегия</h3>
</div>
</div>
</div>
</section>
<!-- ============ SCREEN 5: SERVICES / ACCORDION ============ -->
<section class="services" id="services">
<div class="services__inner container grid">
<div class="services__block col-start-3 col-span-8">
<h2 class="h2 services__heading" data-reveal>Услуги</h2>
<!-- Service 1 -->
<details class="services__item" name="accordion" data-reveal>
<summary class="services__summary">
<span class="services__number">01</span>
<span class="services__title">Консультации по креативу и стратегии</span>
<span class="services__icon">+</span>
</summary>
<div class="services__content">
<div class="services__content-left">
<div class="services__section">
<h4 class="services__section-title">Когда это нужно</h4>
<ul class="services__list">
<li>Бренд чувствует, что коммуникации устарели;</li>
<li>Идеи есть, но они не складываются в систему и, главное, не приносят результат;</li>
<li>Команда не понимает, куда двигаться дальше;</li>
<li>Нужно свежее, независимое видение.</li>
</ul>
</div>
<div class="services__section">
<h4 class="services__section-title">Что вы получаете</h4>
<ul class="services__list">
<li>Разбор текущей коммуникации бренда;</li>
<li>Анализ визуального языка и смыслов;</li>
<li>Точки роста и возможности для отстройки;</li>
<li>Направления для креатива и спецпроектов.</li>
</ul>
</div>
</div>
<div class="services__content-right">
<div class="services__section">
<h4 class="services__section-title">Как происходит работа</h4>
<ol class="services__steps">
<li>Оперативный созвон-знакомство, вы заполняете бриф, по которому я готовлюсь к консультации;</li>
<li>2-часовая консультация;</li>
<li>Презентация с рекомендациями и планом работ.</li>
</ol>
</div>
<a href="https://t.me/alinamamut" class="btn btn--primary services__cta" target="_blank" rel="noopener">Записаться</a>
</div>
</div>
</details>
<!-- Service 2 -->
<details class="services__item" name="accordion" data-reveal>
<summary class="services__summary">
<span class="services__number">02</span>
<span class="services__title">Бренд-платформа</span>
<span class="services__icon">+</span>
</summary>
<div class="services__content">
<div class="services__content-left">
<div class="services__section">
<h4 class="services__section-title">Когда это нужно</h4>
<ul class="services__list">
<li>Проект не растет, нет клиентов;</li>
<li>Коммуникации выглядят разрозненно;</li>
<li>Нет четкого позиционирования и голоса;</li>
<li>Нет понимания, кто аудитория проекта;</li>
<li>Сложно масштабировать маркетинг.</li>
</ul>
</div>
<div class="services__section">
<h4 class="services__section-title">Что вы получаете</h4>
<ul class="services__list">
<li>Ядро бренда: аудитория, конкуренты, миссия, ценности, характер;</li>
<li>Чёткое позиционирование и big idea;</li>
<li>Tone of voice и визуальные принципы;</li>
<li>Основу для всех коммуникаций.</li>
</ul>
</div>
</div>
<div class="services__content-right">
<div class="services__section">
<h4 class="services__section-title">Как происходит работа</h4>
<ol class="services__steps">
<li>Оперативный созвон-знакомство, вы заполняете бриф;</li>
<li>2-4 недели разработки бренд-платформы — анализ аудитории и конкурентов, интервью с основателем (при необходимости с командой и клиентами/потенциальными клиентами);</li>
<li>Презентация с готовой бренд-платформой.</li>
</ol>
</div>
<a href="https://t.me/alinamamut" class="btn btn--primary services__cta" target="_blank" rel="noopener">Записаться</a>
</div>
</div>
</details>
<!-- Service 3 -->
<details class="services__item" name="accordion" data-reveal>
<summary class="services__summary">
<span class="services__number">03</span>
<span class="services__title">Коммуникационные стратегии</span>
<span class="services__icon">+</span>
</summary>
<div class="services__content">
<div class="services__content-left">
<div class="services__section">
<h4 class="services__section-title">Когда это нужно</h4>
<ul class="services__list">
<li>Бренд хочет выйти за рамки стандартной рекламы;</li>
<li>Нужно привлечь новую аудиторию;</li>
<li>Конкуренты выглядят ярче и смелее;</li>
<li>Нет ясного сценария развития коммуникаций.</li>
</ul>
</div>
<div class="services__section">
<h4 class="services__section-title">Что вы получаете</h4>
<ul class="services__list">
<li>Стратегию коммуникаций на основе трендов и инсайтов;</li>
<li>Ключевые смыслы и сообщения бренда;</li>
<li>Идеи форматов, контента и спецпроектов;</li>
<li>Дорожную карту — для кого, в каком канале, что необходимо сделать.</li>
</ul>
</div>
</div>
<div class="services__content-right">
<div class="services__section">
<h4 class="services__section-title">Как происходит работа</h4>
<ol class="services__steps">
<li>Оперативный созвон-знакомство, вы заполняете бриф;</li>
<li>2-4 недели разработки коммуникационной стратегии — анализ аудитории и коммуникации конкурентов, анализ лучших релевантных зарубежных и локальных практик;</li>
<li>Презентация с готовой коммуникационной стратегией.</li>
</ol>
</div>
<a href="https://t.me/alinamamut" class="btn btn--primary services__cta" target="_blank" rel="noopener">Записаться</a>
</div>
</div>
</details>
<!-- Service 4 -->
<details class="services__item" name="accordion" data-reveal>
<summary class="services__summary">
<span class="services__number">04</span>
<span class="services__title">Идеи спецпроектов и креативные концепции</span>
<span class="services__icon">+</span>
</summary>
<div class="services__content">
<div class="services__content-left">
<div class="services__section">
<h4 class="services__section-title">Когда это нужно</h4>
<ul class="services__list">
<li>Бренд хочет вау-эффект без банальных решений;</li>
<li>Нужна идея, которую будут обсуждать;</li>
<li>Важно выйти за рамки стандартных форматов.</li>
</ul>
</div>
<div class="services__section">
<h4 class="services__section-title">Что вы получаете</h4>
<ul class="services__list">
<li>Концепции спецпроектов;</li>
<li>Сценарии интеграций и коллабораций;</li>
<li>Решения, которые можно масштабировать.</li>
</ul>
</div>
</div>
<div class="services__content-right">
<div class="services__section">
<h4 class="services__section-title">Как происходит работа</h4>
<ol class="services__steps">
<li>Оперативный созвон-знакомство, вы заполняете бриф;</li>
<li>2-3 недели разработки идеи — сбор референс, анализ лучших практик, подготовка идеи;</li>
<li>Презентация с готовой креативной концепцией.</li>
</ol>
</div>
<a href="https://t.me/alinamamut" class="btn btn--primary services__cta" target="_blank" rel="noopener">Записаться</a>
</div>
</div>
</details>
<div class="services__footer" data-reveal>
<p class="body-text services__footer-text">Я могу как разработать идею, так и взять на себя всю реализацию при помощи моей команды профессионалов.</p>
<p class="body-text services__footer-text">Чтобы ознакомиться с моим портфолио и реализованными кейсами, пожалуйста, напишите мне:</p>
<a href="https://t.me/alinamamut" class="btn btn--primary" target="_blank" rel="noopener">@alinamamut</a>
</div>
</div>
</div>
</section>
<!-- ============ FOOTER ============ -->
<footer class="footer">
<div class="footer__inner container">
<span class="footer__copy">&copy; 2026 Alina Mamut</span>
<a href="https://t.me/alinamamut" class="footer__telegram" target="_blank" rel="noopener">@alinamamut</a>
<a href="#" class="footer__privacy">Политика конфиденциальности</a>
</div>
</footer>
<script type="module" src="/src/main.js"></script>
</body>
</html>

1104
package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

14
package.json Normal file
View File

@@ -0,0 +1,14 @@
{
"name": "alina-design-website",
"private": true,
"version": "1.0.0",
"type": "module",
"scripts": {
"dev": "vite",
"build": "vite build",
"preview": "vite preview"
},
"devDependencies": {
"vite": "^6.0.0"
}
}

49
src/css/animations.css Normal file
View File

@@ -0,0 +1,49 @@
/* ===== IntersectionObserver fallback ===== */
[data-reveal] {
opacity: 0;
transform: translateY(24px);
transition: opacity 0.6s ease, transform 0.6s ease;
}
[data-reveal].is-visible {
opacity: 1;
transform: translateY(0);
}
/* ===== Scroll-driven animations (progressive enhancement) ===== */
.has-scroll-driven [data-reveal] {
opacity: 1;
transform: none;
transition: none;
animation: reveal-in linear both;
animation-timeline: view();
animation-range: entry 0% entry 30%;
}
@keyframes reveal-in {
from {
opacity: 0;
transform: translateY(24px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
/* Details open/close transition */
.services__content {
animation: accordion-open 0.25s ease;
}
@keyframes accordion-open {
from {
opacity: 0;
transform: translateY(-8px);
}
to {
opacity: 1;
transform: translateY(0);
}
}

53
src/css/base.css Normal file
View File

@@ -0,0 +1,53 @@
body {
font-family: var(--font-body);
font-size: var(--body-size);
line-height: var(--body-lh);
color: var(--color-dark);
background-color: var(--color-bg);
font-weight: 400;
}
.h1 {
font-family: var(--font-headline);
font-size: var(--h1-size);
line-height: var(--h1-lh);
font-weight: 900;
font-stretch: 125%;
text-transform: uppercase;
letter-spacing: -0.02em;
}
.h2 {
font-family: var(--font-headline);
font-size: var(--h2-size);
line-height: var(--h2-lh);
font-weight: 900;
font-stretch: 125%;
text-transform: uppercase;
letter-spacing: -0.01em;
}
.h3 {
font-family: var(--font-headline);
font-size: var(--h3-size);
line-height: var(--h3-lh);
font-weight: 900;
font-stretch: 125%;
text-transform: uppercase;
}
.body-text {
font-family: var(--font-body);
font-size: var(--body-size);
line-height: calc(var(--body-lh) + 6px);
font-weight: 400;
}
.caption {
font-family: var(--font-body);
font-size: var(--caption-size);
line-height: var(--caption-lh);
font-weight: 400;
text-transform: uppercase;
letter-spacing: 0.05em;
}

52
src/css/cases.css Normal file
View File

@@ -0,0 +1,52 @@
.cases {
padding: var(--section-gap) 0;
background-color: var(--color-dark);
color: var(--color-white);
}
.cases__heading {
margin-bottom: 60px;
}
.cases__grid {
row-gap: var(--grid-gutter);
}
.cases__tile {
display: grid;
grid-template: 1fr / 1fr;
overflow: hidden;
cursor: pointer;
}
.cases__tile-image {
grid-area: 1 / 1;
width: 100%;
aspect-ratio: 4 / 3;
transition: transform 0.4s ease;
}
.cases__tile:hover .cases__tile-image {
transform: scale(1.03);
}
.cases__tile-title {
grid-area: 1 / 1;
align-self: end;
padding: 24px;
color: var(--color-white);
mix-blend-mode: difference;
z-index: 1;
line-height: 1.2;
}
@media (max-width: 768px) {
.cases__heading {
margin-bottom: 32px;
}
.cases__tile-title {
padding: 16px;
font-size: 16px;
}
}

89
src/css/components.css Normal file
View File

@@ -0,0 +1,89 @@
.btn {
display: inline-block;
font-family: var(--font-body);
font-size: 14px;
font-weight: 400;
letter-spacing: 0.05em;
text-transform: uppercase;
padding: 14px 32px;
border-radius: var(--btn-radius);
border: 1.5px solid transparent;
cursor: pointer;
transition: background-color 0.2s, color 0.2s, border-color 0.2s;
text-align: center;
}
.btn--primary {
background-color: var(--color-dark);
color: var(--color-white);
border-color: var(--color-dark);
}
.btn--primary:hover {
background-color: transparent;
color: var(--color-dark);
}
.btn--outline {
background-color: transparent;
color: var(--color-dark);
border-color: var(--color-dark);
}
.btn--outline:hover {
background-color: var(--color-dark);
color: var(--color-white);
}
.btn--light {
background-color: var(--color-white);
color: var(--color-dark);
border-color: var(--color-white);
}
.btn--light:hover {
background-color: transparent;
color: var(--color-white);
}
.hairline {
width: 1px;
background-color: var(--color-dark);
opacity: 0.3;
}
.hairline--h {
width: 100%;
height: 1px;
}
.annotation {
position: relative;
padding-left: 16px;
}
.annotation::before {
content: '';
position: absolute;
left: 0;
top: 0;
bottom: 0;
width: 1px;
background-color: var(--color-dark);
opacity: 0.3;
}
.annotation__label {
font-family: var(--font-body);
font-size: 11px;
text-transform: uppercase;
letter-spacing: 0.1em;
opacity: 0.5;
margin-bottom: 4px;
}
.annotation__text {
font-family: var(--font-body);
font-size: 13px;
line-height: 1.4;
}

31
src/css/footer.css Normal file
View File

@@ -0,0 +1,31 @@
.footer {
padding: 40px 0;
border-top: 1px solid rgba(26, 26, 26, 0.15);
}
.footer__inner {
display: flex;
align-items: center;
justify-content: space-between;
}
.footer__copy,
.footer__telegram,
.footer__privacy {
font-family: var(--font-body);
font-size: 13px;
opacity: 0.5;
}
.footer__telegram:hover,
.footer__privacy:hover {
opacity: 0.8;
}
@media (max-width: 768px) {
.footer__inner {
flex-direction: column;
gap: 12px;
text-align: center;
}
}

76
src/css/grid.css Normal file
View File

@@ -0,0 +1,76 @@
.container {
width: 100%;
max-width: var(--grid-max);
margin: 0 auto;
padding: 0 var(--grid-margin);
}
.grid {
display: grid;
grid-template-columns: repeat(var(--grid-columns), 1fr);
gap: var(--grid-gutter);
}
/* Column span utilities */
.col-span-1 { grid-column: span 1; }
.col-span-2 { grid-column: span 2; }
.col-span-3 { grid-column: span 3; }
.col-span-4 { grid-column: span 4; }
.col-span-5 { grid-column: span 5; }
.col-span-6 { grid-column: span 6; }
.col-span-7 { grid-column: span 7; }
.col-span-8 { grid-column: span 8; }
.col-span-9 { grid-column: span 9; }
.col-span-10 { grid-column: span 10; }
.col-span-11 { grid-column: span 11; }
.col-span-12 { grid-column: span 12; }
/* Column start utilities */
.col-start-1 { grid-column-start: 1; }
.col-start-2 { grid-column-start: 2; }
.col-start-3 { grid-column-start: 3; }
.col-start-4 { grid-column-start: 4; }
.col-start-5 { grid-column-start: 5; }
.col-start-6 { grid-column-start: 6; }
.col-start-7 { grid-column-start: 7; }
.col-start-8 { grid-column-start: 8; }
.col-start-9 { grid-column-start: 9; }
.col-start-10 { grid-column-start: 10; }
.col-start-11 { grid-column-start: 11; }
.col-start-12 { grid-column-start: 12; }
@media (max-width: 768px) {
.container {
padding: 0 var(--grid-margin);
}
.col-span-1,
.col-span-2,
.col-span-3,
.col-span-4,
.col-span-5,
.col-span-6,
.col-span-7,
.col-span-8,
.col-span-9,
.col-span-10,
.col-span-11,
.col-span-12 {
grid-column: span 4;
}
.col-start-1,
.col-start-2,
.col-start-3,
.col-start-4,
.col-start-5,
.col-start-6,
.col-start-7,
.col-start-8,
.col-start-9,
.col-start-10,
.col-start-11,
.col-start-12 {
grid-column-start: 1;
}
}

59
src/css/header.css Normal file
View File

@@ -0,0 +1,59 @@
.header {
position: fixed;
top: 0;
left: 0;
right: 0;
z-index: 100;
height: var(--header-height);
background-color: rgba(231, 242, 234, 0.85);
border-bottom: 1px solid rgba(26, 26, 26, 0.1);
transition: backdrop-filter 0.3s;
}
.header--scrolled {
backdrop-filter: blur(8px);
-webkit-backdrop-filter: blur(8px);
}
.header__inner {
display: flex;
align-items: center;
justify-content: space-between;
height: 100%;
}
.header__wordmark {
font-family: var(--font-headline);
font-weight: 900;
font-stretch: 125%;
font-size: 14px;
letter-spacing: 0.05em;
text-transform: uppercase;
}
.header__nav {
display: flex;
gap: 32px;
}
.header__link {
font-family: var(--font-body);
font-size: 13px;
letter-spacing: 0.03em;
opacity: 0.7;
transition: opacity 0.2s;
}
.header__link:hover {
opacity: 1;
}
@media (max-width: 768px) {
.header__nav {
gap: 16px;
}
.header__link {
font-size: 12px;
}
}

72
src/css/hero.css Normal file
View File

@@ -0,0 +1,72 @@
.hero {
min-height: 100vh;
display: flex;
align-items: center;
padding-top: var(--header-height);
padding-bottom: 80px;
}
.hero__inner {
align-items: start;
row-gap: 60px;
}
.hero__headline-block {
display: flex;
flex-direction: column;
gap: 32px;
padding-top: 80px;
}
.hero__title {
max-width: 600px;
}
.hero__subtitle {
max-width: 420px;
opacity: 0.7;
}
.hero__editorial {
display: flex;
align-items: center;
justify-content: center;
padding-top: 80px;
}
.hero__image-placeholder {
width: 100%;
aspect-ratio: 3 / 4;
background-color: var(--color-primary);
max-height: 500px;
}
.hero__annotations {
display: flex;
gap: 40px;
}
@media (max-width: 768px) {
.hero {
min-height: auto;
padding-top: calc(var(--header-height) + 40px);
padding-bottom: 60px;
}
.hero__headline-block {
padding-top: 40px;
}
.hero__editorial {
padding-top: 0;
}
.hero__image-placeholder {
max-height: 300px;
}
.hero__annotations {
flex-direction: column;
gap: 24px;
}
}

73
src/css/journal.css Normal file
View File

@@ -0,0 +1,73 @@
.journal {
padding: var(--section-gap) 0;
position: relative;
overflow: hidden;
}
.journal::after {
content: attr(data-number);
position: absolute;
top: -40px;
right: 5%;
font-family: var(--font-headline);
font-weight: 900;
font-stretch: 125%;
font-size: clamp(200px, 30vw, 400px);
line-height: 1;
color: var(--color-dark);
opacity: 0.04;
pointer-events: none;
z-index: 0;
}
.journal__inner {
position: relative;
z-index: 1;
align-items: end;
}
.journal__image-block {
overflow: hidden;
}
.journal__image-placeholder {
width: 100%;
height: 500px;
background-color: var(--color-surface);
object-fit: cover;
}
.journal__text-block {
display: flex;
flex-direction: column;
gap: 20px;
align-self: end;
}
.journal__body {
opacity: 0.7;
}
.journal__buttons {
display: flex;
gap: 16px;
margin-top: 12px;
}
@media (max-width: 768px) {
.journal__image-placeholder {
height: 300px;
}
.journal__text-block {
align-self: start;
}
.journal__buttons {
flex-direction: column;
}
.journal__buttons .btn {
text-align: center;
}
}

39
src/css/manifest.css Normal file
View File

@@ -0,0 +1,39 @@
.manifest {
padding: var(--section-gap) 0;
}
.manifest__inner {
align-items: start;
}
.manifest__text {
display: flex;
flex-direction: column;
gap: 28px;
}
.manifest__heading {
color: var(--color-dark);
}
.manifest__body {
opacity: 0.7;
max-width: 400px;
}
.manifest__caption {
text-align: right;
padding-top: 8px;
}
.manifest__caption .caption {
opacity: 0.5;
}
@media (max-width: 768px) {
.manifest__caption {
text-align: left;
order: -1;
margin-bottom: 16px;
}
}

61
src/css/reset.css Normal file
View File

@@ -0,0 +1,61 @@
*,
*::before,
*::after {
box-sizing: border-box;
margin: 0;
padding: 0;
}
html {
-moz-text-size-adjust: none;
-webkit-text-size-adjust: none;
text-size-adjust: none;
scroll-behavior: smooth;
}
body {
min-height: 100vh;
line-height: 1.5;
-webkit-font-smoothing: antialiased;
}
img,
picture,
video,
svg {
display: block;
max-width: 100%;
}
input,
button,
textarea,
select {
font: inherit;
}
h1, h2, h3, h4, h5, h6 {
overflow-wrap: break-word;
font-weight: normal;
}
a {
color: inherit;
text-decoration: none;
}
ul, ol {
list-style: none;
}
details summary {
cursor: pointer;
}
details summary::-webkit-details-marker {
display: none;
}
details summary::marker {
content: '';
}

150
src/css/services.css Normal file
View File

@@ -0,0 +1,150 @@
.services {
padding: var(--section-gap) 0;
}
.services__heading {
margin-bottom: 48px;
}
.services__item {
border-top: 1px solid rgba(26, 26, 26, 0.2);
}
.services__item:last-of-type {
border-bottom: 1px solid rgba(26, 26, 26, 0.2);
}
.services__summary {
display: flex;
align-items: center;
gap: 24px;
padding: 24px 0;
list-style: none;
user-select: none;
}
.services__number {
font-family: var(--font-body);
font-size: 13px;
opacity: 0.4;
min-width: 28px;
}
.services__title {
font-family: var(--font-headline);
font-size: clamp(16px, 1.5vw, 20px);
font-weight: 900;
font-stretch: 125%;
text-transform: uppercase;
flex: 1;
}
.services__icon {
font-size: 24px;
font-weight: 300;
opacity: 0.5;
transition: transform 0.3s;
}
.services__item[open] .services__icon {
transform: rotate(45deg);
}
.services__content {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 40px;
padding: 8px 0 40px 52px;
}
.services__section {
margin-bottom: 24px;
}
.services__section-title {
font-family: var(--font-body);
font-size: 12px;
text-transform: uppercase;
letter-spacing: 0.1em;
opacity: 0.5;
margin-bottom: 12px;
}
.services__list {
display: flex;
flex-direction: column;
gap: 6px;
}
.services__list li {
font-family: var(--font-body);
font-size: 14px;
line-height: 1.5;
padding-left: 12px;
position: relative;
}
.services__list li::before {
content: '\2022';
position: absolute;
left: 0;
opacity: 0.4;
}
.services__steps {
display: flex;
flex-direction: column;
gap: 8px;
counter-reset: step;
}
.services__steps li {
font-family: var(--font-body);
font-size: 14px;
line-height: 1.5;
padding-left: 20px;
position: relative;
counter-increment: step;
}
.services__steps li::before {
content: counter(step) '.';
position: absolute;
left: 0;
opacity: 0.5;
}
.services__cta {
margin-top: 8px;
}
.services__footer {
margin-top: 60px;
display: flex;
flex-direction: column;
gap: 16px;
align-items: flex-start;
}
.services__footer-text {
opacity: 0.7;
max-width: 500px;
}
@media (max-width: 768px) {
.services__block {
grid-column: span 4;
grid-column-start: 1;
}
.services__content {
grid-template-columns: 1fr;
gap: 24px;
padding-left: 0;
}
.services__summary {
gap: 12px;
padding: 20px 0;
}
}

60
src/css/tokens.css Normal file
View File

@@ -0,0 +1,60 @@
:root {
/* Colors */
--color-primary: #007DDA;
--color-bg: #E7F2EA;
--color-surface: #FCC3C3;
--color-ink: #BD5E24;
--color-accent: #FB9322;
--color-dark: #1A1A1A;
--color-white: #FFFFFF;
/* Typography — Families */
--font-headline: 'Archivo', sans-serif;
--font-body: 'Inter', sans-serif;
/* Typography — Sizes (Desktop) */
--h1-size: clamp(32px, 4vw, 48px);
--h1-lh: 40px;
--h2-size: clamp(24px, 2.5vw, 31px);
--h2-lh: 30px;
--h3-size: clamp(18px, 2vw, 24px);
--h3-lh: 20px;
--body-size: 16px;
--body-lh: 18px;
--caption-size: 16px;
--caption-lh: 44px;
/* Grid */
--grid-columns: 12;
--grid-container: 1200px;
--grid-max: 1424px;
--grid-gutter: 32px;
--grid-margin: 96px;
/* Spacing */
--section-gap: clamp(120px, 15vw, 220px);
--headline-spacing: 160px;
/* Misc */
--btn-radius: 3px;
--header-height: 64px;
}
@media (max-width: 768px) {
:root {
--h1-size: 32px;
--h1-lh: 40px;
--h2-size: 34px;
--h2-lh: 30px;
--h3-size: 20px;
--h3-lh: 80px;
--body-size: 16px;
--body-lh: 14px;
--caption-size: 14px;
--caption-lh: 12px;
--grid-columns: 4;
--grid-gutter: 16px;
--grid-margin: 20px;
}
}

75
src/main.js Normal file
View File

@@ -0,0 +1,75 @@
import './style.css'
function initScrollReveal() {
const supportsScrollDriven = CSS.supports('animation-timeline', 'view()')
if (supportsScrollDriven) {
document.documentElement.classList.add('has-scroll-driven')
return
}
const reveals = document.querySelectorAll('[data-reveal]')
if (!reveals.length) return
const observer = new IntersectionObserver(
(entries) => {
entries.forEach((entry) => {
if (entry.isIntersecting) {
entry.target.classList.add('is-visible')
observer.unobserve(entry.target)
}
})
},
{ threshold: 0.15 }
)
reveals.forEach((el) => observer.observe(el))
}
function initSmoothScroll() {
document.querySelectorAll('a[href^="#"]').forEach((anchor) => {
anchor.addEventListener('click', (e) => {
const targetId = anchor.getAttribute('href')
if (targetId === '#') return
const target = document.querySelector(targetId)
if (!target) return
e.preventDefault()
const headerOffset = parseInt(
getComputedStyle(document.documentElement)
.getPropertyValue('--header-height'),
10
)
const top = target.getBoundingClientRect().top + window.scrollY - headerOffset - 20
window.scrollTo({ top, behavior: 'smooth' })
})
})
}
function initHeaderScroll() {
const header = document.getElementById('header')
if (!header) return
let ticking = false
window.addEventListener(
'scroll',
() => {
if (!ticking) {
requestAnimationFrame(() => {
header.classList.toggle('header--scrolled', window.scrollY > 100)
ticking = false
})
ticking = true
}
},
{ passive: true }
)
}
document.addEventListener('DOMContentLoaded', () => {
initScrollReveal()
initSmoothScroll()
initHeaderScroll()
})

13
src/style.css Normal file
View File

@@ -0,0 +1,13 @@
@import './css/reset.css';
@import './css/tokens.css';
@import './css/base.css';
@import './css/grid.css';
@import './css/components.css';
@import './css/header.css';
@import './css/hero.css';
@import './css/manifest.css';
@import './css/journal.css';
@import './css/cases.css';
@import './css/services.css';
@import './css/footer.css';
@import './css/animations.css';

9
vite.config.js Normal file
View File

@@ -0,0 +1,9 @@
import { defineConfig } from 'vite'
export default defineConfig({
root: '.',
publicDir: 'public',
build: {
outDir: 'dist',
},
})