From 94d125a50345a347eed8a055ff8f4c5679f62e8f Mon Sep 17 00:00:00 2001 From: neo Date: Thu, 25 Jun 2026 19:37:57 +0500 Subject: [PATCH] Premium polish: counters anim, data flow, live clock, gradient h1, 3D tilt, FAQ spring --- index_ibm.html | 318 ++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 265 insertions(+), 53 deletions(-) diff --git a/index_ibm.html b/index_ibm.html index 5cc06e7..ad7213a 100644 --- a/index_ibm.html +++ b/index_ibm.html @@ -84,6 +84,7 @@ body { --mono: 'IBM Plex Mono', 'SF Mono', monospace; --grid: 8px; --ease-out: cubic-bezier(0.22, 1, 0.36, 1); + --ease-spring: cubic-bezier(0.34, 1.56, 0.64, 1); } /* ── BACKGROUND — grid + ambient gradient ── */ @@ -264,8 +265,10 @@ section { padding: 120px 0; position: relative; z-index: 1; } h1 { font-size: clamp(3rem, 6vw, 5rem); font-weight: 700; letter-spacing: -0.04em; line-height: 0.95; margin-bottom: 24px; + background: linear-gradient(135deg, var(--text) 45%, var(--accent) 100%); + -webkit-background-clip: text; -webkit-text-fill-color: transparent; + background-clip: text; } -h1 .accent { color: var(--accent); } .hero-sub { font-size: 1.125rem; color: var(--text-sec); @@ -298,13 +301,25 @@ h1 .accent { color: var(--accent); } position: relative; animation: dashFloat 6s ease-in-out infinite; box-shadow: var(--dash-shadow); - transition: background 0.5s var(--ease-out), box-shadow 0.5s var(--ease-out); + transition: background 0.5s var(--ease-out), box-shadow 0.5s var(--ease-out), transform 0.1s; + transform-style: preserve-3d; + perspective: 1000px; } @keyframes dashFloat { 0%, 100% { transform: translateY(0); } 50% { transform: translateY(-6px); } } +/* ── 3D TILT (Feature #7) ── */ +.hero-right.tilt-active { + animation: none; + transition: transform 0.15s var(--ease-out), box-shadow 0.3s var(--ease-out); + box-shadow: 0 20px 60px rgba(34,197,94,0.08), 0 0 1px var(--border); +} +.hero-right.tilt-active .dash-glow { + opacity: calc(var(--dash-glow-opacity) * 1.8); +} + .dash-glow { position: absolute; top: -40%; left: -20%; width: 140%; height: 140%; background: radial-gradient(circle, var(--accent), transparent 50%); @@ -337,6 +352,13 @@ h1 .accent { color: var(--accent); } 50% { opacity:0.3; box-shadow: 0 0 0 4px transparent; } } +/* ── LIVE CLOCK (Feature #5) ── */ +.dash-clock { + font-size: 0.625rem; color: var(--text-dim); font-family: 'IBM Plex Mono', 'SF Mono', monospace; + letter-spacing: 0.05em; +} +.dash-clock .clock-time { color: var(--text-sec); } + .dash-body { display: grid; position: relative; z-index: 1; } .dash-big { @@ -351,12 +373,13 @@ h1 .accent { color: var(--accent); } .dash-big-value { font-size: clamp(3rem, 5vw, 5rem); font-weight: 700; font-family: 'IBM Plex Mono', 'SF Mono', monospace; - line-height: 1; + line-height: 1; display: flex; align-items: center; justify-content: flex-end; gap: 12px; } .dash-big-value .accent { color: var(--accent); } +.dash-big-value .count-up { display: inline-block; } .dash-big-trend { display: inline-flex; align-items: center; gap: 6px; - margin-left: 16px; font-size: 0.875rem; color: var(--accent); + font-size: 0.875rem; color: var(--accent); font-weight: 600; } .trend-icon { width: 14px; height: 14px; } @@ -427,6 +450,64 @@ h1 .accent { color: var(--accent); } transform: scaleX(1); } +/* ── DATA FLOW (Feature #3) ── */ +.data-flow { + border-bottom: 1px solid var(--border); + padding: 64px 0; + overflow: hidden; + position: relative; +} +.flow-inner { + display: flex; align-items: center; justify-content: center; gap: 0; + max-width: 900px; margin: 0 auto; +} +.flow-node { + display: flex; flex-direction: column; align-items: center; gap: 12px; + padding: 20px; position: relative; z-index: 1; +} +.flow-icon { + width: 56px; height: 56px; border-radius: 12px; + border: 1px solid var(--border); + display: flex; align-items: center; justify-content: center; + background: var(--surface); + font-family: 'IBM Plex Mono', 'SF Mono', monospace; + font-size: 0.6875rem; font-weight: 700; color: var(--accent); + transition: all 0.4s var(--ease-out); +} +.flow-node:hover .flow-icon { + border-color: var(--accent); + box-shadow: 0 0 0 4px var(--accent-dim); + transform: translateY(-2px); +} +.flow-icon svg { width: 24px; height: 24px; stroke: var(--text-sec); fill: none; stroke-width: 1.5; } +.flow-node:hover .flow-icon svg { stroke: var(--accent); } +.flow-name { + font-size: 0.75rem; color: var(--text-sec); text-align: center; + font-family: 'IBM Plex Mono', 'SF Mono', monospace; +} +.flow-arrow { + display: flex; align-items: center; padding: 0 8px; + opacity: 0.3; +} +.flow-arrow svg { width: 40px; height: 12px; stroke: var(--accent); fill: none; stroke-width: 2; } +.flow-arrow .arrow-dash { + stroke-dasharray: 6 4; + animation: flowDash 1s linear infinite; +} +@keyframes flowDash { + to { stroke-dashoffset: -10; } +} +.flow-pulse { + width: 8px; height: 8px; border-radius: 50%; + background: var(--accent); + animation: flowPulse 2s ease-in-out infinite; + box-shadow: 0 0 8px var(--accent-glow); +} +@keyframes flowPulse { + 0%, 100% { transform: scale(1); opacity: 0.4; } + 50% { transform: scale(1.5); opacity: 1; } +} + /* ── MANIFESTO ── */ .manifesto { padding: 160px 0; border-bottom: 1px solid var(--border); } .manifesto-inner { @@ -621,26 +702,40 @@ h1 .accent { color: var(--accent); } font-style: italic; } -/* ── FAQ ── */ +/* ── FAQ — Enhanced (Feature #8) ── */ .faq-list { max-width: 800px; margin: 0 auto; } .faq-item { border-bottom: 1px solid var(--border); } .faq-q { display: flex; align-items: center; justify-content: space-between; padding: 24px 0; cursor: pointer; font-size: 1rem; font-weight: 600; letter-spacing: -0.01em; transition: color 0.2s; + user-select: none; } .faq-q:hover { color: var(--accent); } .faq-q::after { - content: '+'; font-family: 'IBM Plex Mono', 'SF Mono', monospace; font-size: 1.25rem; - color: var(--text-dim); transition: transform 0.3s var(--ease-out); - flex-shrink: 0; margin-left: 16px; + content: '+'; font-family: 'IBM Plex Mono', 'SF Mono', monospace; font-size: 1.5rem; + color: var(--text-dim); transition: all 0.4s var(--ease-spring); + flex-shrink: 0; margin-left: 16px; width: 24px; height: 24px; + display: flex; align-items: center; justify-content: center; + border-radius: 4px; border: 1px solid var(--border); +} +.faq-item.open .faq-q::after { + transform: rotate(45deg); + color: var(--accent); + border-color: var(--accent); } -.faq-item.open .faq-q::after { transform: rotate(45deg); } .faq-a { max-height: 0; overflow: hidden; transition: max-height 0.5s var(--ease-out); } -.faq-item.open .faq-a { max-height: 400px; } +.faq-item.open .faq-a { max-height: 500px; } .faq-a-inner { padding: 0 0 24px; font-size: 0.875rem; color: var(--text-sec); line-height: 1.7; + opacity: 0; + transform: translateY(-8px); + transition: opacity 0.4s var(--ease-out) 0.1s, transform 0.4s var(--ease-out) 0.1s; +} +.faq-item.open .faq-a-inner { + opacity: 1; + transform: translateY(0); } /* ── FOOTER ── */ @@ -711,6 +806,8 @@ h1 .accent { color: var(--accent); } .step:nth-child(2) { border-right: none; } .step:nth-child(n+3) { border-top: 1px solid var(--border); } .footer-inner { grid-template-columns: 1fr 1fr; } + .flow-inner { flex-wrap: wrap; gap: 16px; } + .flow-arrow { transform: rotate(90deg); } } @media (max-width: 640px) { .wrap { padding: 0 16px; } @@ -728,6 +825,7 @@ h1 .accent { color: var(--accent); } .nav { display: none; } .price-card { padding: 40px 24px; } .price-amount { font-size: 3rem; } + .flow-arrow { display: none; } } @@ -768,7 +866,7 @@ h1 .accent { color: var(--accent); }
ДАННЫЕ. БЕЗ ШУМА.
-

Вы теряете
деньги, не зная
почему

+

Вы теряете
деньги, не зная
почему

Один дашборд с 10 ключевыми метриками вашего бизнеса. Обновляется автоматически из 1С, CRM и банков. @@ -810,13 +908,16 @@ h1 .accent { color: var(--accent); } ROI24 / DASHBOARD - LIVE +

+ --:--:-- + LIVE +
Выручка за 30 дней
- 12.4М ₽ + 12.4М ₽ @@ -827,28 +928,28 @@ h1 .accent { color: var(--accent); }
Маржа
-
23.4%
+
23.4%
↑ 2.1% к прошлому месяцу
Касса
-
4.8М ₽
+
4.8М ₽
Дебиторка: 1.2М
Конверсия
-
2.8%
+
2.8%
CAC
-
890₽
+
890₽
ROI рекл.
-
91%
+
91%
@@ -863,6 +964,47 @@ h1 .accent { color: var(--accent); }
+ +
+
+
+
+
+ +
+ 1С / CRM +
+
+ +
+
+
+ +
+ Агрегатор +
+
+ +
+
+
+ +
+ Реклама +
+
+ +
+
+
+ +
+ ROI24 +
+
+
+
+
@@ -1128,7 +1270,6 @@ h1 .accent { color: var(--accent); } const html = document.documentElement; const themeToggle = document.getElementById('themeToggle'); -// Check saved preference const savedTheme = localStorage.getItem('roi24-theme'); if (savedTheme) { html.setAttribute('data-theme', savedTheme); @@ -1154,7 +1295,7 @@ window.addEventListener('load', () => { setTimeout(() => { document.querySelectorAll('.dash-mini-fill').forEach(bar => { - const target = bar.style.width || '0'; + const target = bar.dataset.targetWidth || bar.style.width; bar.style.width = '0'; requestAnimationFrame(() => { requestAnimationFrame(() => { @@ -1163,8 +1304,68 @@ window.addEventListener('load', () => { }); }); }, 800); + + // ── Feature #2: Counter Animation ── + animateCounters(); }); +/* ── Feature #2: Animated Counters ── */ +function animateCounters() { + document.querySelectorAll('.count-up').forEach(el => { + if (el.dataset.animated) return; + el.dataset.animated = 'true'; + + const text = el.textContent; + const match = text.match(/^(\d+\.?\d*)/); + if (!match) return; + + const target = parseFloat(match[1]); + const prefix = text.substring(0, text.indexOf(match[1])); + const suffix = text.substring(text.indexOf(match[1]) + match[1].length); + const duration = 1500; + const startTime = performance.now(); + const startVal = 0; + + function easeOutQuart(t) { return 1 - Math.pow(1 - t, 4); } + + function update(now) { + const elapsed = now - startTime; + const progress = Math.min(elapsed / duration, 1); + const easedProgress = easeOutQuart(progress); + const currentVal = startVal + (target - startVal) * easedProgress; + + let display; + if (text.includes('.')) { + display = prefix + currentVal.toFixed(1) + suffix; + } else { + display = prefix + Math.round(currentVal) + suffix; + } + + el.textContent = display; + + if (progress < 1) { + requestAnimationFrame(update); + } else { + el.textContent = text; + } + } + + requestAnimationFrame(update); + }); +} + +/* ── Feature #5: Live Clock ── */ +function updateClock() { + const now = new Date(); + const timeStr = now.toLocaleTimeString('ru-RU', { hour: '2-digit', minute: '2-digit', second: '2-digit' }); + const clockEl = document.getElementById('dashClock'); + if (clockEl) { + clockEl.querySelector('.clock-time').textContent = timeStr; + } +} +setInterval(updateClock, 1000); +updateClock(); + /* ── SCROLL REVEAL ── */ const revealObserver = new IntersectionObserver((entries) => { entries.forEach(entry => { @@ -1180,34 +1381,37 @@ document.querySelectorAll('.reveal').forEach(el => revealObserver.observe(el)); /* ── DASHBOARD SEGMENT TOGGLE ── */ const SEGMENTS = { ecom: { - revenue: '12.4М', revenueTrend: '+12%', - margin: '23.4%', marginNote: '↑ 2.1% к прошлому месяцу', - cash: '4.8М ₽', cashNote: 'Дебиторка: 1.2М', + revenue: '12.4', revenueTrend: '+12%', + margin: '23.4', marginNote: '↑ 2.1% к прошлому месяцу', + cash: '4.8', cashNote: 'Дебиторка: 1.2М', mini: [ - { label: 'Конверсия', value: '2.8%', pct: 28, color: 'var(--blue)' }, - { label: 'CAC', value: '890₽', pct: 45, color: 'var(--amber)' }, - { label: 'ROI рекл.', value: '91%', pct: 91, color: 'var(--accent)' } - ] + { label: 'Конверсия', value: '2.8', pct: 28, color: 'var(--blue)' }, + { label: 'CAC', value: '890', pct: 45, color: 'var(--amber)' }, + { label: 'ROI рекл.', value: '91', pct: 91, color: 'var(--accent)' } + ], + suffixes: ['М ₽', '%', 'М ₽', '%', '', '%'] }, services: { - revenue: '3.8М', revenueTrend: '+8%', - margin: '31.2%', marginNote: '↑ 1.4%', - cash: '2.1М ₽', cashNote: 'Пайплайн: 8.5М', + revenue: '3.8', revenueTrend: '+8%', + margin: '31.2', marginNote: '↑ 1.4%', + cash: '2.1', cashNote: 'Пайплайн: 8.5М', mini: [ - { label: 'Загрузка', value: '78%', pct: 78, color: 'var(--blue)' }, - { label: 'Марж. проект', value: '34%', pct: 68, color: 'var(--amber)' }, - { label: 'LTV', value: '185К', pct: 82, color: 'var(--accent)' } - ] + { label: 'Загрузка', value: '78', pct: 78, color: 'var(--blue)' }, + { label: 'Марж. проект', value: '34', pct: 68, color: 'var(--amber)' }, + { label: 'LTV', value: '185', pct: 82, color: 'var(--accent)' } + ], + suffixes: ['М ₽', '%', 'М ₽', '%', '', 'К'] }, production: { - revenue: '28.7М', revenueTrend: '+5%', - margin: '18.7%', marginNote: '↓ 0.8%', - cash: '6.2М ₽', cashNote: 'OEE: 72%', + revenue: '28.7', revenueTrend: '+5%', + margin: '18.7', marginNote: '↓ 0.8%', + cash: '6.2', cashNote: 'OEE: 72%', mini: [ - { label: 'План/факт', value: '94%', pct: 94, color: 'var(--blue)' }, - { label: 'OEE', value: '72%', pct: 72, color: 'var(--amber)' }, - { label: 'Качество', value: '99.1%', pct: 99, color: 'var(--accent)' } - ] + { label: 'План/факт', value: '94', pct: 94, color: 'var(--blue)' }, + { label: 'OEE', value: '72', pct: 72, color: 'var(--amber)' }, + { label: 'Качество', value: '99.1', pct: 99, color: 'var(--accent)' } + ], + suffixes: ['М ₽', '%', 'М ₽', '%', '', '%'] } }; @@ -1227,9 +1431,10 @@ toggleBtns.forEach(btn => { bigValue.style.transition = 'opacity 0.3s, transform 0.3s'; setTimeout(() => { - bigValue.innerHTML = `${seg.revenue} ₽${seg.revenueTrend}`; + bigValue.innerHTML = `${seg.revenue}${seg.suffixes[0]}${seg.revenueTrend}`; bigValue.style.opacity = '1'; bigValue.style.transform = 'translateY(0)'; + animateCounters(); }, 300); const marginValue = document.getElementById('marginValue'); @@ -1243,11 +1448,12 @@ toggleBtns.forEach(btn => { }); setTimeout(() => { - marginValue.textContent = seg.margin; + marginValue.innerHTML = `${seg.margin}%`; marginNote.textContent = seg.marginNote; - cashValue.textContent = seg.cash; + cashValue.innerHTML = `${seg.cash}${seg.suffixes[2]}`; cashNote.textContent = seg.cashNote; [marginValue, marginNote, cashValue, cashNote].forEach(el => { el.style.opacity = '1'; }); + animateCounters(); }, 280); seg.mini.forEach((m, i) => { @@ -1257,7 +1463,7 @@ toggleBtns.forEach(btn => { miniVal.style.transform = 'translateY(-4px)'; setTimeout(() => { - miniVal.textContent = m.value; + miniVal.innerHTML = `${m.value}${seg.suffixes[4 + i] || ''}`; miniVal.style.color = m.color; miniVal.style.opacity = '1'; miniVal.style.transform = 'translateY(0)'; @@ -1269,7 +1475,7 @@ toggleBtns.forEach(btn => { }); }); -/* ── FAQ ACCORDION ── */ +/* ── Feature #8: Enhanced FAQ Accordion ── */ document.querySelectorAll('.faq-q').forEach(q => { q.addEventListener('click', () => { const item = q.parentElement; @@ -1279,25 +1485,31 @@ document.querySelectorAll('.faq-q').forEach(q => { }); }); -/* ── HERO PARALLAX ── */ +/* ── Feature #7: 3D Tilt on Dashboard ── */ const hero = document.getElementById('hero'); const heroRight = document.getElementById('heroRight'); hero.addEventListener('mousemove', (e) => { + heroRight.classList.add('tilt-active'); const rect = hero.getBoundingClientRect(); const x = (e.clientX - rect.left) / rect.width - 0.5; const y = (e.clientY - rect.top) / rect.height - 0.5; - heroRight.style.transform = `translateY(${-6 + y * -4}px) perspective(800px) rotateY(${x * 1.5}deg) rotateX(${y * 1.5}deg)`; + heroRight.style.transform = `perspective(1200px) rotateX(${y * -8}deg) rotateY(${x * 8}deg) translateY(0)`; + heroRight.style.boxShadow = `${x * -30}px ${y * -30 + 20}px 80px rgba(34,197,94,0.06), 0 0 1px var(--border)`; }); hero.addEventListener('mouseleave', () => { - heroRight.style.transform = 'translateY(0) perspective(800px) rotateY(0) rotateX(0)'; - heroRight.style.transition = 'transform 0.6s var(--ease-out)'; + heroRight.classList.remove('tilt-active'); + heroRight.style.transform = ''; + heroRight.style.boxShadow = ''; setTimeout(() => { - heroRight.style.transition = 'transform 0.1s, opacity 0.8s var(--ease-out) 0.3s, box-shadow 0.5s var(--ease-out), background 0.5s var(--ease-out)'; - }, 600); + heroRight.style.transition = 'transform 0.6s var(--ease-out), box-shadow 0.6s var(--ease-out)'; + setTimeout(() => { + heroRight.style.transition = ''; + }, 600); + }, 100); }); - \ No newline at end of file +