wa-dev-tools/public/landing.html
treamz 69ec8f4ede UI: light theme default, remove free mentions, fix scroll animation
- Default theme: light (was dark)
- Removed all бесплатно/free/навсегда mentions across all pages
- Landing: title, hero badge, hero text, CTA button, advantages, footer CTA
- Dashboard: hero text, about section, stats
- Register: subtitle
- Fixed scroll-hint animation (was bouncing infinitely, now static)
- Removed class=dark from all 18 HTML files (theme managed by JS)
2026-03-22 00:10:12 +03:00

962 lines
38 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!DOCTYPE html>
<html lang="ru" >
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>WA Dev Tools — инструменты для веб-разработчика</title>
<meta name="description" content="Сжатие картинок, форматирование кода, HTTP-клиент и ещё 10 инструментов для веб-разработчиков — всё в браузере, " />
<script src="/vendor/tailwind.js"></script>
<script>
tailwind.config = {
darkMode: 'class',
theme: { extend: {
fontFamily: { mono: ['JetBrains Mono', 'monospace'], sans: ['Manrope', 'sans-serif'] },
colors: { surface: { 900: '#060c18', 800: '#091020', 700: '#0d1828', 600: '#162040' }, accent: { DEFAULT: '#0054e6', dim: '#0043b8', bright: '#6b9fff' } }
}}
};
</script>
<link href="/vendor/fonts.css" rel="stylesheet">
<link href="/shared.css" rel="stylesheet">
<style>
/* ── Resets & base ── */
*, *::before, *::after { box-sizing: border-box; }
html { scroll-behavior: smooth; }
/* ── Animations ── */
@keyframes fadeIn {
from { opacity: 0; }
to { opacity: 1; }
}
@keyframes slideUp {
from { opacity: 0; transform: translateY(28px); }
to { opacity: 1; transform: translateY(0); }
}
@keyframes glow-pulse {
0%, 100% { opacity: 0.45; }
50% { opacity: 0.70; }
}
@keyframes float {
0%, 100% { transform: translateY(0px); }
50% { transform: translateY(-8px); }
}
.animate-fade-in { animation: fadeIn 0.7s ease both; }
.animate-slide-up { animation: slideUp 0.7s ease both; }
.delay-100 { animation-delay: 0.10s; }
.delay-200 { animation-delay: 0.20s; }
.delay-300 { animation-delay: 0.30s; }
.delay-400 { animation-delay: 0.40s; }
.delay-500 { animation-delay: 0.50s; }
.delay-600 { animation-delay: 0.60s; }
/* Intersection-observer driven reveal */
.reveal {
opacity: 0;
transform: translateY(24px);
transition: opacity 0.6s ease, transform 0.6s ease;
}
.reveal.visible {
opacity: 1;
transform: translateY(0);
}
.reveal-delay-1 { transition-delay: 0.10s; }
.reveal-delay-2 { transition-delay: 0.20s; }
.reveal-delay-3 { transition-delay: 0.30s; }
.reveal-delay-4 { transition-delay: 0.40s; }
/* ── Hero ── */
.hero {
min-height: 100vh;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
text-align: center;
padding: 80px 20px 60px;
position: relative;
overflow: hidden;
}
/* Glow blobs */
.hero-glow-1 {
position: absolute;
top: -10%;
left: 50%;
transform: translateX(-50%);
width: min(700px, 120vw);
height: min(700px, 120vw);
background: radial-gradient(ellipse at center, rgba(0, 84, 230, 0.18) 0%, transparent 65%);
pointer-events: none;
animation: glow-pulse 5s ease-in-out infinite;
}
.hero-glow-2 {
position: absolute;
bottom: 0;
right: -15%;
width: 420px;
height: 420px;
background: radial-gradient(ellipse at center, rgba(107, 159, 255, 0.08) 0%, transparent 60%);
pointer-events: none;
animation: glow-pulse 7s ease-in-out infinite reverse;
}
.hero-glow-3 {
position: absolute;
bottom: 10%;
left: -10%;
width: 360px;
height: 360px;
background: radial-gradient(ellipse at center, rgba(0, 67, 184, 0.10) 0%, transparent 60%);
pointer-events: none;
animation: glow-pulse 6s ease-in-out infinite 1s;
}
/* Grid lines overlay */
.hero-grid {
position: absolute;
inset: 0;
background-image:
linear-gradient(rgba(0, 84, 230, 0.04) 1px, transparent 1px),
linear-gradient(90deg, rgba(0, 84, 230, 0.04) 1px, transparent 1px);
background-size: 60px 60px;
mask-image: radial-gradient(ellipse at center, black 20%, transparent 75%);
pointer-events: none;
}
.hero-logo {
font-family: 'JetBrains Mono', monospace;
font-size: clamp(11px, 1.5vw, 13px);
font-weight: 700;
letter-spacing: 0.2em;
text-transform: uppercase;
color: var(--text-muted);
margin-bottom: 28px;
}
.hero-logo span {
color: var(--accent-bright);
}
.hero-headline {
font-family: 'Manrope', sans-serif;
font-size: clamp(2rem, 5.5vw, 3.75rem);
font-weight: 800;
line-height: 1.15;
letter-spacing: -0.03em;
color: var(--text-primary);
max-width: 820px;
margin: 0 auto 20px;
}
.hero-headline .accent { color: var(--accent); }
.hero-sub {
font-family: 'Manrope', sans-serif;
font-size: clamp(1rem, 2vw, 1.2rem);
line-height: 1.65;
color: var(--text-secondary);
max-width: 600px;
margin: 0 auto 44px;
}
.hero-cta-group {
display: flex;
flex-direction: column;
align-items: center;
gap: 16px;
}
@media (min-width: 480px) {
.hero-cta-group { flex-direction: row; justify-content: center; }
}
.btn-primary {
display: inline-flex;
align-items: center;
gap: 8px;
padding: 15px 32px;
background: var(--accent);
color: #fff;
border: none;
border-radius: 12px;
font-family: 'Manrope', sans-serif;
font-weight: 700;
font-size: 16px;
text-decoration: none;
cursor: pointer;
transition: background 0.2s, transform 0.2s, box-shadow 0.2s;
box-shadow: 0 0 0 0 rgba(0, 84, 230, 0);
}
.btn-primary:hover {
background: var(--accent-dim);
transform: translateY(-2px);
box-shadow: 0 8px 32px rgba(0, 84, 230, 0.35);
}
.btn-primary:active {
transform: translateY(0);
}
.btn-secondary {
display: inline-flex;
align-items: center;
font-family: 'Manrope', sans-serif;
font-size: 15px;
color: var(--text-secondary);
text-decoration: none;
transition: color 0.2s;
}
.btn-secondary:hover { color: var(--text-primary); }
.btn-secondary .link-text {
border-bottom: 1px solid var(--surface-600);
padding-bottom: 1px;
}
/* Count badge in hero */
.hero-badge {
display: inline-flex;
align-items: center;
gap: 8px;
background: var(--surface-700);
border: 1px solid var(--surface-600);
border-radius: 999px;
padding: 6px 16px 6px 10px;
font-family: 'JetBrains Mono', monospace;
font-size: 12px;
color: var(--text-muted);
margin-bottom: 28px;
}
.hero-badge .dot {
width: 6px;
height: 6px;
border-radius: 50%;
background: var(--accent-bright);
box-shadow: 0 0 6px var(--accent-bright);
animation: glow-pulse 2s ease-in-out infinite;
}
/* ── Scroll hint ── */
.scroll-hint {
position: absolute;
bottom: 28px;
left: 50%;
transform: translateX(-50%);
display: flex;
flex-direction: column;
align-items: center;
gap: 6px;
color: var(--text-muted);
font-family: 'JetBrains Mono', monospace;
font-size: 10px;
letter-spacing: 0.15em;
text-transform: uppercase;
animation: none;
}
/* ── Section common ── */
.section {
padding: 80px 20px;
}
.section-inner {
max-width: 1120px;
margin: 0 auto;
}
.section-label {
font-family: 'JetBrains Mono', monospace;
font-size: 11px;
font-weight: 700;
letter-spacing: 0.2em;
text-transform: uppercase;
color: var(--accent-bright);
margin-bottom: 12px;
}
.section-title {
font-family: 'Manrope', sans-serif;
font-size: clamp(1.6rem, 4vw, 2.4rem);
font-weight: 800;
letter-spacing: -0.025em;
color: var(--text-primary);
margin: 0 0 48px;
line-height: 1.2;
}
/* ── Category cards ── */
.cat-grid {
display: grid;
grid-template-columns: 1fr;
gap: 20px;
}
@media (min-width: 640px) {
.nav-link { display:inline-flex; }
.cat-grid { grid-template-columns: repeat(2, 1fr); }
}
@media (min-width: 1024px) {
.cat-grid { grid-template-columns: repeat(4, 1fr); }
}
.cat-card {
background: var(--surface-700);
border: 1px solid var(--surface-600);
border-radius: 16px;
padding: 28px 24px;
display: flex;
flex-direction: column;
gap: 16px;
transition: border-color 0.25s, transform 0.25s, box-shadow 0.25s;
}
.cat-card:hover {
border-color: rgba(0, 84, 230, 0.5);
transform: translateY(-4px);
box-shadow: 0 16px 48px rgba(0, 0, 0, 0.25), 0 0 0 1px rgba(0, 84, 230, 0.15);
}
.cat-icon-wrap {
width: 48px;
height: 48px;
border-radius: 12px;
background: var(--accent-bg);
display: flex;
align-items: center;
justify-content: center;
color: var(--accent-bright);
flex-shrink: 0;
}
.cat-header {
display: flex;
align-items: center;
justify-content: space-between;
gap: 8px;
}
.cat-title {
font-family: 'Manrope', sans-serif;
font-size: 18px;
font-weight: 700;
color: var(--text-primary);
}
.cat-badge {
font-family: 'JetBrains Mono', monospace;
font-size: 11px;
font-weight: 700;
color: var(--accent-bright);
background: rgba(107, 159, 255, 0.12);
border: 1px solid rgba(107, 159, 255, 0.2);
border-radius: 999px;
padding: 2px 10px;
white-space: nowrap;
}
.cat-desc {
font-family: 'Manrope', sans-serif;
font-size: 14px;
line-height: 1.6;
color: var(--text-secondary);
flex: 1;
}
.cat-tools {
display: flex;
flex-direction: column;
gap: 6px;
padding-top: 4px;
border-top: 1px solid var(--surface-600);
}
.cat-tool-item {
display: flex;
align-items: center;
gap: 8px;
font-family: 'JetBrains Mono', monospace;
font-size: 12px;
color: var(--text-muted);
}
.cat-tool-item::before {
content: '';
width: 4px;
height: 4px;
border-radius: 50%;
background: var(--accent-bright);
opacity: 0.5;
flex-shrink: 0;
}
/* ── Advantages ── */
.adv-section {
background: var(--surface-700);
border-top: 1px solid var(--surface-600);
border-bottom: 1px solid var(--surface-600);
}
.adv-grid {
display: grid;
grid-template-columns: 1fr;
gap: 0;
}
@media (min-width: 640px) {
.adv-grid { grid-template-columns: repeat(2, 1fr); }
}
@media (min-width: 1024px) {
.adv-grid { grid-template-columns: repeat(4, 1fr); }
}
.adv-card {
padding: 36px 28px;
display: flex;
flex-direction: column;
gap: 12px;
border-right: 1px solid var(--surface-600);
border-bottom: 1px solid var(--surface-600);
}
.adv-card:last-child { border-right: none; }
@media (min-width: 640px) {
.adv-card:nth-child(2) { border-right: none; }
.adv-card:nth-child(3) { border-bottom: none; }
.adv-card:nth-child(4) { border-right: none; border-bottom: none; }
}
@media (min-width: 1024px) {
.adv-card:nth-child(2) { border-right: 1px solid var(--surface-600); }
.adv-card:nth-child(3) { border-bottom: 1px solid var(--surface-600); }
.adv-card:last-child { border-right: none; border-bottom: none; }
/* last row has no bottom border */
.adv-card { border-bottom: none; }
}
.adv-icon-wrap {
width: 44px;
height: 44px;
border-radius: 10px;
background: var(--accent-bg);
display: flex;
align-items: center;
justify-content: center;
color: var(--accent-bright);
}
.adv-title {
font-family: 'Manrope', sans-serif;
font-size: 17px;
font-weight: 700;
color: var(--text-primary);
}
.adv-desc {
font-family: 'Manrope', sans-serif;
font-size: 14px;
line-height: 1.65;
color: var(--text-secondary);
}
/* ── Final CTA ── */
.cta-section {
text-align: center;
padding: 100px 20px;
}
.cta-glow {
position: relative;
display: inline-block;
}
.cta-glow::before {
content: '';
position: absolute;
inset: -40px -80px;
background: radial-gradient(ellipse at center, rgba(0, 84, 230, 0.12) 0%, transparent 65%);
pointer-events: none;
}
.cta-headline {
font-family: 'Manrope', sans-serif;
font-size: clamp(1.8rem, 4vw, 2.8rem);
font-weight: 800;
letter-spacing: -0.025em;
color: var(--text-primary);
margin: 0 0 16px;
}
.cta-sub {
font-family: 'Manrope', sans-serif;
font-size: clamp(0.95rem, 1.8vw, 1.1rem);
line-height: 1.65;
color: var(--text-secondary);
margin: 0 auto 40px;
max-width: 480px;
}
/* ── Nav ── */
.landing-nav {
position: fixed;
top: 0;
left: 0;
right: 0;
z-index: 100;
display: flex;
align-items: center;
justify-content: space-between;
padding: 16px 32px;
background: rgba(6, 12, 24, 0.7); backdrop-filter: blur(12px);
border-bottom: 1px solid transparent;
transition: background 0.3s, border-color 0.3s, backdrop-filter 0.3s;
}
.landing-nav.scrolled {
background: rgba(6, 12, 24, 0.85);
border-color: var(--surface-600);
backdrop-filter: blur(12px);
}
.nav-logo {
font-family: 'Manrope', sans-serif;
font-size: 18px;
font-weight: 800;
color: var(--text-primary);
text-decoration: none;
letter-spacing: -0.02em;
}
.nav-logo span { color: var(--accent); }
.nav-actions {
display: flex;
align-items: center;
gap: 12px;
}
.nav-link {
font-family: 'Manrope', sans-serif;
font-size: 14px;
font-weight: 600;
color: var(--text-secondary);
text-decoration: none;
transition: color 0.2s;
padding: 8px 4px;
}
.nav-link:hover { color: var(--text-primary); }
.nav-link.nav-page { display: none; }
@media (min-width: 768px) {
.nav-link.nav-page { display: inline-flex; }
}
.nav-btn {
font-family: 'Manrope', sans-serif;
font-size: 14px;
font-weight: 700;
color: #fff;
background: var(--accent);
text-decoration: none;
padding: 9px 20px;
border-radius: 8px;
transition: background 0.2s;
}
.nav-btn:hover { background: var(--accent-dim); }
/* ── Footer ── */
.landing-footer {
padding: 28px 32px;
border-top: 1px solid var(--surface-600);
display: flex;
align-items: center;
justify-content: space-between;
flex-wrap: wrap;
gap: 12px;
}
.footer-copy {
font-family: 'JetBrains Mono', monospace;
font-size: 12px;
color: var(--text-muted);
}
.footer-links {
display: flex;
gap: 20px;
}
.footer-link {
font-family: 'Manrope', sans-serif;
font-size: 13px;
color: var(--text-muted);
text-decoration: none;
transition: color 0.2s;
}
.footer-link:hover { color: var(--text-secondary); }
/* ── Divider line with accent ── */
.section-divider {
width: 40px;
height: 3px;
background: var(--accent);
border-radius: 2px;
margin-bottom: 16px;
}
@media (prefers-reduced-motion: reduce) {
*, *::before, *::after {
animation-duration: 0.01ms !important;
transition-duration: 0.01ms !important;
}
}
</style>
</head>
<body>
<!-- ════════════════════════════════════════════
NAV
════════════════════════════════════════════ -->
<nav class="landing-nav" id="mainNav">
<a href="/" class="nav-logo">WA Dev <span>Tools</span></a>
<div class="nav-actions">
<a href="#tools" class="nav-link nav-page">Инструменты</a>
<a href="#features" class="nav-link nav-page">Возможности</a>
<a href="/auth/login" class="nav-link">Войти</a>
<a href="/auth/register" class="nav-btn">Регистрация</a>
</div>
</nav>
<!-- ════════════════════════════════════════════
HERO
════════════════════════════════════════════ -->
<section class="hero">
<div class="hero-glow-1"></div>
<div class="hero-glow-2"></div>
<div class="hero-glow-3"></div>
<div class="hero-grid"></div>
<div style="position:relative;z-index:1;width:100%;">
<div class="hero-badge animate-fade-in">
<span class="dot"></span>
<span id="hero-badge-text">14 инструментов для разработчиков</span>
</div>
<div class="hero-logo animate-slide-up delay-100">
WA Dev <span>Tools</span>
</div>
<h1 class="hero-headline animate-slide-up delay-200" id="hero-headline">
Инструменты для<br>
<span class="accent">веб-разработчика</span>
</h1>
<p class="hero-sub animate-slide-up delay-300" id="hero-sub">
Сжатие картинок, форматирование кода, HTTP-клиент и ещё 10 инструментов —
всё в браузере, без установки и регистрации карты.
</p>
<div class="hero-cta-group animate-slide-up delay-400">
<a href="/auth/register" class="btn-primary">
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<path d="M13 5H7a2 2 0 0 0-2 2v10a2 2 0 0 0 2 2h10a2 2 0 0 0 2-2v-6"/>
<path d="M17 3h4v4"/>
<path d="M10 14 21 3"/>
</svg>
Начать работу
</a>
<a href="/auth/login" class="btn-secondary">
<span class="link-text">Уже есть аккаунт? Войти</span>
</a>
</div>
</div>
<a href="#tools" class="scroll-hint" aria-label="Прокрутить вниз">
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<path d="m6 9 6 6 6-6"/>
</svg>
<span>Подробнее</span>
</a>
</section>
<!-- ════════════════════════════════════════════
CATEGORIES
════════════════════════════════════════════ -->
<section class="section" id="tools">
<div class="section-inner">
<div class="reveal">
<p class="section-label">Что внутри</p>
<div class="section-divider"></div>
<h2 class="section-title">Инструменты</h2>
</div>
<div class="cat-grid">
<!-- Изображения -->
<div class="cat-card reveal reveal-delay-1">
<div class="cat-icon-wrap">
<!-- Heroicons: photo -->
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.75" stroke-linecap="round" stroke-linejoin="round">
<rect x="3" y="3" width="18" height="18" rx="3"/>
<path d="M3 9h18"/>
<circle cx="9" cy="6" r="1" fill="currentColor" stroke="none"/>
<path d="M3 15l4-4 4 4 3-3 5 5"/>
</svg>
</div>
<div>
<div class="cat-header">
<span class="cat-title">Изображения</span>
<span class="cat-badge">4 инструмента</span>
</div>
</div>
<p class="cat-desc">Сжатие, редактирование, SVG и placeholder-генератор</p>
<ul class="cat-tools">
<li class="cat-tool-item">Сжатие картинок</li>
<li class="cat-tool-item">Placeholder-генератор</li>
<li class="cat-tool-item">SVG-редактор</li>
<li class="cat-tool-item">Фоторедактор</li>
</ul>
</div>
<!-- Код -->
<div class="cat-card reveal reveal-delay-2">
<div class="cat-icon-wrap">
<!-- Heroicons: code-bracket -->
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.75" stroke-linecap="round" stroke-linejoin="round">
<path d="m8 6-4 6 4 6"/>
<path d="m16 6 4 6-4 6"/>
<path d="m14 4-4 16"/>
</svg>
</div>
<div>
<div class="cat-header">
<span class="cat-title">Код</span>
<span class="cat-badge">3 инструмента</span>
</div>
</div>
<p class="cat-desc">Форматирование, очистка и конвертация кода между форматами</p>
<ul class="cat-tools">
<li class="cat-tool-item">Форматирование кода</li>
<li class="cat-tool-item">HTML Sanitizer</li>
<li class="cat-tool-item">Конвертер форматов</li>
</ul>
</div>
<!-- Веб -->
<div class="cat-card reveal reveal-delay-3">
<div class="cat-icon-wrap">
<!-- Heroicons: globe-alt -->
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.75" stroke-linecap="round" stroke-linejoin="round">
<circle cx="12" cy="12" r="9"/>
<path d="M3.6 9h16.8M3.6 15h16.8"/>
<path d="M12 3a14.4 14.4 0 0 1 0 18M12 3a14.4 14.4 0 0 0 0 18"/>
</svg>
</div>
<div>
<div class="cat-header">
<span class="cat-title">Веб</span>
<span class="cat-badge">3 инструмента</span>
</div>
</div>
<p class="cat-desc">HTTP-клиент, парсер страниц и анализ редиректов</p>
<ul class="cat-tools">
<li class="cat-tool-item">HTTP-клиент</li>
<li class="cat-tool-item">Парсер статей</li>
<li class="cat-tool-item">Redirect-анализатор</li>
</ul>
</div>
<!-- Утилиты -->
<div class="cat-card reveal reveal-delay-4">
<div class="cat-icon-wrap">
<!-- Heroicons: wrench-screwdriver -->
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.75" stroke-linecap="round" stroke-linejoin="round">
<path d="M11.42 15.17 17.25 21A2.652 2.652 0 0 0 21 17.25l-5.877-5.877"/>
<path d="M11.42 15.17l-2.496-2.496a3.5 3.5 0 0 1-4.95-4.95l2.496 2.496"/>
<path d="m6.496 10.22 4.258-4.257a3.5 3.5 0 0 1 4.95 4.95l-4.258 4.257"/>
</svg>
</div>
<div>
<div class="cat-header">
<span class="cat-title">Утилиты</span>
<span class="cat-badge">2 инструмента</span>
</div>
</div>
<p class="cat-desc">Генератор паролей и Markdown-просмотрщик с превью</p>
<ul class="cat-tools">
<li class="cat-tool-item">Генератор паролей</li>
<li class="cat-tool-item">Markdown Viewer</li>
</ul>
</div>
</div>
</div>
</section>
<!-- ════════════════════════════════════════════
ADVANTAGES
════════════════════════════════════════════ -->
<section class="adv-section" id="features">
<div style="max-width:1120px;margin:0 auto;">
<div class="adv-grid">
<div class="adv-card reveal">
<div class="adv-icon-wrap">
<!-- Heroicons: gift -->
<svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.75" stroke-linecap="round" stroke-linejoin="round">
<path d="M20 12v10H4V12"/>
<path d="M22 7H2v5h20V7z"/>
<path d="M12 22V7"/>
<path d="M12 7H7.5a2.5 2.5 0 0 1 0-5C11 2 12 7 12 7z"/>
<path d="M12 7h4.5a2.5 2.5 0 0 0 0-5C13 2 12 7 12 7z"/>
</svg>
</div>
<div class="adv-title">Без ограничений</div>
<p class="adv-desc">Никаких подписок и скрытых платежей. Все 13 инструментов доступны сразу после регистрации.</p>
</div>
<div class="adv-card reveal reveal-delay-1">
<div class="adv-icon-wrap">
<!-- Heroicons: computer-desktop -->
<svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.75" stroke-linecap="round" stroke-linejoin="round">
<rect x="2" y="3" width="20" height="14" rx="2"/>
<path d="M8 21h8M12 17v4"/>
</svg>
</div>
<div class="adv-title">В браузере</div>
<p class="adv-desc">Ничего устанавливать не нужно. Работает на любом устройстве с современным браузером.</p>
</div>
<div class="adv-card reveal reveal-delay-2">
<div class="adv-icon-wrap">
<!-- Heroicons: shield-check -->
<svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.75" stroke-linecap="round" stroke-linejoin="round">
<path d="M12 22s8-4 8-10V5l-8-3-8 3v7c0 6 8 10 8 10z"/>
<path d="m9 12 2 2 4-4"/>
</svg>
</div>
<div class="adv-title">Безопасно</div>
<p class="adv-desc">Ваши файлы обрабатываются локально или транзитно и не сохраняются на нашем сервере.</p>
</div>
<div class="adv-card reveal reveal-delay-3">
<div class="adv-icon-wrap">
<!-- Heroicons: bolt -->
<svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.75" stroke-linecap="round" stroke-linejoin="round">
<path d="M13 2 3 14h9l-1 8 10-12h-9l1-8z"/>
</svg>
</div>
<div class="adv-title">Быстро</div>
<p class="adv-desc">Лёгкий интерфейс, мгновенная обработка без очередей и ожидания серверного ответа.</p>
</div>
</div>
</div>
</section>
<!-- ════════════════════════════════════════════
FINAL CTA
════════════════════════════════════════════ -->
<section class="cta-section">
<div class="cta-glow reveal">
<p class="section-label" style="margin-bottom:16px;">Начните прямо сейчас</p>
<h2 class="cta-headline">Готовы начать?</h2>
<p class="cta-sub">
Зарегистрируйтесь и получите доступ ко всем инструментам.
</p>
<a href="/auth/register" class="btn-primary" style="font-size:17px;padding:17px 40px;">
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<path d="M16 21v-2a4 4 0 0 0-4-4H6a4 4 0 0 0-4 4v2"/>
<circle cx="9" cy="7" r="4"/>
<line x1="19" y1="8" x2="19" y2="14"/>
<line x1="22" y1="11" x2="16" y2="11"/>
</svg>
Создать аккаунт
</a>
</div>
</section>
<!-- ════════════════════════════════════════════
FOOTER
════════════════════════════════════════════ -->
<footer class="landing-footer">
<span class="footer-copy">&copy; 2024&ndash;2026 WA Dev Tools</span>
<nav class="footer-links">
<a href="/auth/login" class="footer-link">Войти</a>
<a href="/auth/register" class="footer-link">Регистрация</a>
</nav>
</footer>
<script>
/* ── Sticky nav ── */
const nav = document.getElementById('mainNav');
const onScroll = () => {
nav.classList.toggle('scrolled', window.scrollY > 40);
};
window.addEventListener('scroll', onScroll, { passive: true });
/* ── Intersection observer for reveal animations ── */
const revealEls = document.querySelectorAll('.reveal');
if ('IntersectionObserver' in window) {
const observer = new IntersectionObserver((entries) => {
entries.forEach((entry) => {
if (entry.isIntersecting) {
entry.target.classList.add('visible');
observer.unobserve(entry.target);
}
});
}, { threshold: 0.12, rootMargin: '0px 0px -40px 0px' });
revealEls.forEach((el) => observer.observe(el));
} else {
// Fallback for old browsers
revealEls.forEach((el) => el.classList.add('visible'));
}
</script>
</body>
</html>
<script>
/* ── Dynamic content from API ── */
(async function() {
try {
const [settingsRes, toolsRes, advRes] = await Promise.all([
fetch('/api/settings'),
fetch('/api/tools'),
fetch('/api/content/advantages'),
]);
if (settingsRes.ok) {
const s = await settingsRes.json();
const headline = document.getElementById('hero-headline');
if (headline && s.hero_headline) {
const parts = s.hero_headline.split(' ');
const last = parts.pop();
headline.innerHTML = parts.join(' ') + '<br><span class="accent">' + last + '</span>';
}
const sub = document.getElementById('hero-sub');
if (sub && s.hero_description) sub.textContent = s.hero_description;
const badge = document.getElementById('hero-badge-text');
if (badge && s.site_tagline) badge.textContent = s.site_tagline;
}
if (toolsRes.ok) {
const cats = await toolsRes.json();
const grid = document.querySelector('.cat-grid');
if (grid && cats.length) {
grid.innerHTML = cats.map((cat, i) => {
const toolsList = cat.tools.map(t => '<li class="cat-tool-item">' + t.title + '</li>').join('');
return '<div class="cat-card reveal visible reveal-delay-' + (i+1) + '">' +
'<div class="cat-icon-wrap" style="color:' + (cat.color || '#0054e6') + '">' +
'<svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.75"><rect x="3" y="3" width="18" height="18" rx="3"/></svg>' +
'</div><div><div class="cat-header"><span class="cat-title">' + cat.title + '</span>' +
'<span class="cat-badge">' + cat.tools.length + ' инстр.</span></div></div>' +
'<p class="cat-desc">' + (cat.description || '') + '</p>' +
'<ul class="cat-tools">' + toolsList + '</ul></div>';
}).join('');
}
}
if (advRes.ok) {
const blocks = await advRes.json();
const advGrid = document.querySelector('.adv-grid');
if (advGrid && blocks.length) {
advGrid.innerHTML = blocks.map((b, i) =>
'<div class="adv-card reveal visible reveal-delay-' + i + '">' +
'<div class="adv-icon-wrap"><svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.75"><path stroke-linecap="round" stroke-linejoin="round" d="M11.48 3.499a.562.562 0 011.04 0l2.125 5.111a.563.563 0 00.475.345l5.518.442c.499.04.701.663.321.988l-4.204 3.602a.563.563 0 00-.182.557l1.285 5.385a.562.562 0 01-.84.61l-4.725-2.885a.563.563 0 00-.586 0L6.982 20.54a.562.562 0 01-.84-.61l1.285-5.386a.562.562 0 00-.182-.557l-4.204-3.602a.563.563 0 01.321-.988l5.518-.442a.563.563 0 00.475-.345L11.48 3.5z"/></svg></div>' +
'<div class="adv-title">' + b.title + '</div>' +
'<p class="adv-desc">' + b.body + '</p></div>'
).join('');
}
}
} catch(e) { /* silent — static content stays as fallback */ }
})();
</script>