Files
roi24/hero-v2.html
T
neo d1fd87d9ee hero-v2: boost sweep opacity 2.5x, add glow pulse animation
- Sweep peak: 0.06 → 0.15 (green), 0.025 → 0.04 (white)
- Glow now pulses via CSS @keyframes (opacity 0.7 ↔ 1, scale 1 ↔ 1.05)
- Hover: glow jumps to opacity 1.3 + scale 1.08 + sweep accelerates
2026-06-21 21:15:08 +05:00

413 lines
14 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>ROI24 — Hero Preview</title>
<link rel="preconnect" href="https://fonts.cdnfonts.com">
<link href="https://fonts.cdnfonts.com/css/inter" rel="stylesheet">
<link href="https://fonts.cdnfonts.com/css/jetbrains-mono" rel="stylesheet">
<style>
/* ============================================================
DESIGN TOKENS
============================================================ */
:root {
--bg: #0a0a0a;
--surface: #111111;
--card: #161618;
--border: rgba(255,255,255,0.06);
--border-hover: rgba(255,255,255,0.12);
--text: #f5f5f5;
--text-sec: #a1a1aa;
--text-dim: #52525b;
--accent: #22c55e;
--accent-dim: rgba(34,197,94,0.12);
--accent-glow: rgba(34,197,94,0.18);
--blue: #3b82f6;
--blue-dim: rgba(59,130,246,0.12);
--amber: #f59e0b;
--red: #ef4444;
--red-dim: rgba(239,68,68,0.12);
--font: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
--mono: 'JetBrains Mono', 'SF Mono', monospace;
}
/* ============================================================
RESET
============================================================ */
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
body {
background: var(--bg); color: var(--text); font-family: var(--font);
line-height: 1.6; overflow-x: hidden; min-height: 100vh;
-webkit-font-smoothing: antialiased;
}
/* ============================================================
ANIMATED HERO BACKGROUND (composio.dev style)
============================================================ */
.hero-bg {
position: fixed; inset: 0; z-index: 0; pointer-events: none;
overflow: hidden;
}
/* Layer 1: Noise texture */
.hero-bg::before {
content: ''; position: absolute; inset: 0;
background-image: url("data:image/svg+xml,%3Csvg viewBox='0 0 256 256' xmlns='http://www.w3.org/2000/svg'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='4' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)' opacity='0.025'/%3E%3C/svg%3E");
opacity: 0.5; z-index: 2;
}
/* Layer 2: Big radial gradient blob — статичное brand-glow */
.hero-glow {
position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%);
width: 900px; height: 900px; border-radius: 50%;
background: radial-gradient(
circle at 50% 50%,
var(--accent-glow) 0%,
var(--accent-dim) 25%,
rgba(34,197,94,0.02) 55%,
transparent 70%
);
z-index: 1;
pointer-events: none;
animation: glowPulse 4s ease-in-out infinite;
}
@keyframes glowPulse {
0%, 100% { opacity: 0.7; transform: translate(-50%, -50%) scale(1); }
50% { opacity: 1; transform: translate(-50%, -50%) scale(1.05); }
}
/* Layer 3: Animated gradient sweep */
.hero-sweep {
position: absolute; inset: 0; z-index: 1;
background: linear-gradient(
90deg,
transparent 0%,
transparent 28%,
rgba(255,255,255,0.04) 40%,
rgba(34,197,94,0.15) 50%,
rgba(255,255,255,0.03) 60%,
transparent 72%,
transparent 100%
);
background-size: 200% 100%;
/* position driven by JS requestAnimationFrame */
pointer-events: none;
will-change: background-position;
}
/* ============================================================
HERO CONTAINER
============================================================ */
.hero {
position: relative; z-index: 10;
min-height: 100vh; display: flex; flex-direction: column;
align-items: center; justify-content: center;
padding: 120px 24px 80px;
overflow: hidden;
}
/* ============================================================
KPI CARDS — floating on sides
============================================================ */
.kpi-cards {
position: absolute; top: 0; left: 0; right: 0; bottom: 0;
z-index: 20; pointer-events: none;
}
.kpi-card {
position: absolute;
pointer-events: auto;
background: rgba(22,22,24,0.85);
backdrop-filter: blur(12px);
border: 1px solid rgba(255,255,255,0.08);
border-radius: 14px;
padding: 16px 18px;
width: 180px;
transform: translateY(-50%);
transition: all 0.4s cubic-bezier(0.4, 0, 0.2, 1);
}
.kpi-card:hover {
border-color: rgba(255,255,255,0.18);
transform: translateY(-50%) translateY(-3px);
box-shadow: 0 12px 40px rgba(0,0,0,0.4);
}
.kpi-card.left { left: calc(50% - 440px); }
.kpi-card.right { left: calc(50% + 260px); }
.kpi-card.l1 { top: 28%; }
.kpi-card.l2 { top: 72%; }
.kpi-card.r1 { top: 28%; }
.kpi-card.r2 { top: 72%; }
.kpi-card-label {
font-size: 10px; text-transform: uppercase; letter-spacing: 0.08em;
color: var(--text-dim); font-weight: 600; margin-bottom: 6px;
}
.kpi-card-value {
font-family: var(--mono); font-size: 22px; font-weight: 700;
line-height: 1.15; margin-bottom: 4px;
}
.kpi-card-value.green { color: var(--accent); }
.kpi-card-value.blue { color: var(--blue); }
.kpi-card-value.amber { color: var(--amber); }
.kpi-card-trend {
display: inline-flex; align-items: center; gap: 3px;
padding: 2px 6px; border-radius: 5px;
font-family: var(--mono); font-weight: 600; font-size: 10px;
}
.kpi-card-trend.up { color: var(--accent); background: var(--accent-dim); }
.kpi-card-trend.down { color: var(--red); background: var(--red-dim); }
.kpi-card-chart {
margin-top: 10px; width: 100%; height: 36px;
border-radius: 6px; overflow: hidden;
background: rgba(255,255,255,0.02);
position: relative;
}
/* Mini sparkline bars */
.spark-bars {
display: flex; align-items: flex-end; gap: 3px;
height: 100%; padding: 4px 4px 0;
}
.spark-bar {
flex: 1; background: var(--accent-dim);
border-radius: 2px 2px 0 0;
transition: height 0.6s ease;
}
/* ============================================================
CENTER CONTENT (composio.dev style — clean, minimal bg)
============================================================ */
.hero-center {
position: relative; z-index: 30;
text-align: center; max-width: 640px;
}
.hero-badge {
display: inline-flex; align-items: center; gap: 8px;
padding: 6px 16px; border: 1px solid rgba(255,255,255,0.1);
border-radius: 100px; margin-bottom: 24px;
font-size: 12px; color: var(--text-sec); font-family: var(--mono);
background: rgba(255,255,255,0.02);
}
.hero-badge-dot {
width: 6px; height: 6px; background: var(--accent);
border-radius: 50%;
animation: livePulse 1.5s ease-in-out infinite;
}
@keyframes livePulse {
0%, 100% { box-shadow: 0 0 4px var(--accent); }
50% { box-shadow: 0 0 12px var(--accent); }
}
.hero-center h1 {
font-size: clamp(2rem, 6vw, 4.5rem);
font-weight: 800;
letter-spacing: -0.04em;
line-height: 1.08;
margin-bottom: 20px;
}
.hero-center h1 .accent { color: var(--accent); }
.hero-center .hero-sub {
font-size: 1.125rem; color: rgba(255,255,255,0.45);
line-height: 1.65; margin-bottom: 36px; max-width: 520px;
margin-left: auto; margin-right: auto;
}
.hero-center .hero-sub .dim { color: rgba(255,255,255,0.25); }
.hero-actions {
display: flex; gap: 12px; justify-content: center;
flex-wrap: wrap;
}
.btn {
display: inline-flex; align-items: center; justify-content: center; gap: 8px;
padding: 16px 32px; border-radius: 100px; font-weight: 600; font-size: 0.9375rem;
cursor: pointer; border: none; transition: all 0.25s ease;
white-space: nowrap; text-decoration: none;
}
.btn-accent {
background: var(--accent); color: #000;
}
.btn-accent:hover {
background: #16a34a; color: #000;
transform: translateY(-1px);
box-shadow: 0 12px 40px rgba(34,197,94,0.25);
}
.btn-outline {
background: transparent; border: 1px solid rgba(255,255,255,0.2);
color: var(--text);
}
.btn-outline:hover {
border-color: rgba(255,255,255,0.4);
background: rgba(255,255,255,0.03);
}
/* ============================================================
RESPONSIVE
============================================================ */
@media (max-width: 1024px) {
.kpi-cards {
position: relative; top: auto; left: auto; right: auto; bottom: auto;
display: grid; grid-template-columns: 1fr 1fr;
gap: 12px; width: 100%; max-width: 660px;
margin: 0 auto 32px;
pointer-events: auto;
}
.kpi-card {
position: static; transform: none;
width: 100%;
}
.kpi-card.left, .kpi-card.right { left: auto; }
.hero { padding-top: 160px; }
.hero-glow { width: 500px; height: 500px; }
}
@media (max-width: 640px) {
.kpi-cards { grid-template-columns: 1fr; max-width: 320px; }
.hero-center h1 { font-size: clamp(1.75rem, 8vw, 2.5rem); }
.hero { padding: 140px 16px 60px; }
.btn { padding: 14px 24px; font-size: 0.875rem; }
}
</style>
</head>
<body>
<div class="hero-bg">
<div class="hero-glow"></div>
<div class="hero-sweep" id="heroSweep"></div>
</div>
<section class="hero">
<!-- KPI cards on sides -->
<div class="kpi-cards" id="kpiCards">
<div class="kpi-card left l1">
<div class="kpi-card-label">Выручка за 30 дней</div>
<div class="kpi-card-value green">2 051 857 ₽</div>
<span class="kpi-card-trend up">↑ +15%</span>
<div class="kpi-card-chart">
<div class="spark-bars" id="spark1"></div>
</div>
</div>
<div class="kpi-card left l2">
<div class="kpi-card-label">CPA средний</div>
<div class="kpi-card-value blue">890 ₽</div>
<span class="kpi-card-trend down">↓ −5%</span>
<div class="kpi-card-chart">
<div class="spark-bars" id="spark2"></div>
</div>
</div>
<div class="kpi-card right r1">
<div class="kpi-card-label">Прибыль</div>
<div class="kpi-card-value green">981 857 ₽</div>
<span class="kpi-card-trend up">↑ +12%</span>
<div class="kpi-card-chart">
<div class="spark-bars" id="spark3"></div>
</div>
</div>
<div class="kpi-card right r2">
<div class="kpi-card-label">ROI рекламы</div>
<div class="kpi-card-value amber">91.8%</div>
<span class="kpi-card-trend up">↑ +5%</span>
<div class="kpi-card-chart">
<div class="spark-bars" id="spark4"></div>
</div>
</div>
</div>
<!-- Center content -->
<div class="hero-center">
<div class="hero-badge">
<span class="hero-badge-dot"></span>
АНАЛИТИКА ДЛЯ СОБСТВЕННИКОВ
</div>
<h1>
Живые цифры<br>вашего <span class="accent">бизнеса</span>
</h1>
<p class="hero-sub">
10 ключевых метрик из 1С, CRM и банков —<br>
автоматически, без обучения, каждое утро<br>
<span class="dim">в вашем телефоне.</span>
</p>
<div class="hero-actions">
<a href="#cta" class="btn btn-accent" id="ctaBtn"
onmouseenter="accelerateBg(true)"
onmouseleave="accelerateBg(false)">
Получить демо за 3 дня
</a>
<a href="#demo" class="btn btn-outline"
onmouseenter="accelerateBg(true)"
onmouseleave="accelerateBg(false)">
Посмотреть пример
</a>
</div>
</div>
</section>
<script>
/* ============================================================
BACKGROUND ACCELERATION — JS-driven, smooth speed transition
============================================================ */
const sweepEl = document.getElementById('heroSweep');
let bgOffset = 100;
let bgTargetSpeed = 8; // seconds per full sweep
let bgCurrentSpeed = 8; // lerped toward target
function accelerateBg(active) {
bgTargetSpeed = active ? 1.2 : 8;
const glow = document.querySelector('.hero-glow');
if (active) {
glow.style.animation = 'none';
glow.style.opacity = '1.3';
glow.style.transform = 'translate(-50%, -50%) scale(1.08)';
glow.style.transition = 'opacity 0.4s ease, transform 0.4s ease';
} else {
glow.style.opacity = '';
glow.style.transform = '';
glow.style.animation = '';
}
}
(function bgLoop() {
// Smooth interpolation toward target speed
bgCurrentSpeed += (bgTargetSpeed - bgCurrentSpeed) * 0.04;
// Frame advance: 100% range over (speed * 60fps) frames
bgOffset += (100 / (bgCurrentSpeed * 60)) * 1.5;
if (bgOffset > 200) bgOffset -= 200;
if (bgOffset < 0) bgOffset += 200;
sweepEl.style.backgroundPosition = bgOffset.toFixed(2) + '% 50%';
requestAnimationFrame(bgLoop);
})();
/* ============================================================
SPARKLINES — tiny bars inside KPI cards
============================================================ */
function renderSpark(elId, values, color) {
const el = document.getElementById(elId);
const max = Math.max(...values);
el.innerHTML = values.map(v => {
const h = (v / max) * 100;
return `<div class="spark-bar" style="height:${h}%;background:${color}"></div>`;
}).join('');
}
// Revenue trend (up)
renderSpark('spark1', [80,85,82,90,88,95,92,98], 'var(--accent-dim)');
// CPA trend (down = good, so bars going down)
renderSpark('spark2', [95,88,85,78,72,68,62,58], 'var(--blue-dim)');
// Profit trend (up)
renderSpark('spark3', [60,65,68,75,78,82,88,90], 'var(--accent-dim)');
// ROI trend (up)
renderSpark('spark4', [70,72,75,78,82,85,88,92], 'rgba(245,158,11,0.15)');
</script>
</body>
</html>