Загрузка...

Интерактивные карточки с ценами и анимированными уровнями. Драг-н-дроп, тайпрайтер-заголовки, WebGL-фон. Идеально для SaaS.
<div
class="antialiased bg-gray-50 text-gray-900 min-h-screen flex flex-col items-center justify-center overflow-x-hidden relative font-['Inter',sans-serif] font-light selection:bg-cyan-500/20 py-20 md:py-0">
<script src="https://cdn.tailwindcss.com"></script>
<script src="https://code.iconify.design/iconify-icon/1.0.7/iconify-icon.min.js"></script>
<style>
@import url('https://fonts.googleapis.com/css2?family=Inter:wght@300;400&display=swap');
.perspective-1200 {
perspective: 1200px;
}
</style>
<!-- Background Layers -->
<div class="fixed inset-0 z-0 flex items-center justify-center pointer-events-none overflow-hidden">
<div
class="absolute w-[70vw] h-[70vw] max-w-[900px] max-h-[900px] rounded-full blur-[120px] opacity-30 animate-[pulse_6s_ease-in-out_infinite]"
style="background: radial-gradient(circle, rgba(34,211,238,0.2) 0%, transparent 70%); left: 5%; top: 10%;"></div>
<div
class="absolute w-[70vw] h-[70vw] max-w-[900px] max-h-[900px] rounded-full blur-[120px] opacity-30 animate-[pulse_8s_ease-in-out_infinite]"
style="background: radial-gradient(circle, rgba(251,146,60,0.2) 0%, transparent 70%); right: 5%; bottom: 10%;">
</div>
</div>
<canvas id="noiseCanvas"
class="fixed inset-0 pointer-events-none z-50 opacity-[0.03] w-full h-full mix-blend-multiply"></canvas>
<!-- Header Section -->
<div class="relative z-10 text-center mb-10 md:mb-16 px-6 flex flex-col items-center w-full max-w-3xl mx-auto">
<div
class="inline-flex items-center gap-2 px-3 py-1.5 rounded-full bg-white/80 border border-gray-200/50 mb-6 backdrop-blur-md"
style="box-shadow: 0 4px 12px rgba(0,0,0,0.03), 0 1px 3px rgba(0,0,0,0.02), inset 0 1px 0 rgba(255,255,255,1);">
<div class="w-1.5 h-1.5 rounded-full bg-cyan-500 animate-pulse"></div>
<span class="text-xs text-gray-500 tracking-widest uppercase font-medium">Service Levels</span>
</div>
<h1 class="text-4xl md:text-5xl tracking-tight text-gray-900 mb-4 font-normal">Choose Your Configuration</h1>
<p class="text-sm text-gray-500 max-w-md typewriter-text h-10 md:h-auto"
data-text="Select the bandwidth and security parameters for your environment."></p>
</div>
<!-- Main Container -->
<div
class="relative w-full max-w-5xl mx-auto px-6 flex flex-col md:flex-row items-center justify-center gap-10 md:gap-8 z-10 perspective-1200">
<!-- Tier 1: Standard Node -->
<div class="draggable-card cursor-grab select-none relative w-full max-w-sm md:w-[22rem] h-[32rem] z-10">
<div
class="relative w-full h-full rounded-3xl p-8 flex flex-col group transition-all duration-700 ease-out hover:-translate-y-4 hover:rotate-0 md:-rotate-6 md:translate-x-12"
style="background: linear-gradient(145deg, #ffffff 0%, #f0f9ff 100%); box-shadow: 2px 4px 8px rgba(0,0,0,0.02), 8px 16px 24px rgba(0,0,0,0.03), 64px 96px 128px rgba(0,0,0,0.12), 80px 120px 160px rgba(6, 182, 212, 0.15), inset 0 1px 1px rgba(255,255,255,1), 0 0 0 1px rgba(0,0,0,0.04);">
<div class="flex justify-between items-start relative z-10 mb-8">
<div class="w-16 h-16 rounded-xl p-2.5 flex items-end justify-between gap-0.5 bg-white shadow-sm">
<div class="w-full bg-cyan-500/90 rounded-t-sm animate-pulse"
style="height: 40%; animation-duration: 0.7s;"></div>
<div class="w-full bg-cyan-500/90 rounded-t-sm animate-pulse"
style="height: 85%; animation-duration: 1.2s; animation-delay: 0.2s;"></div>
<div class="w-full bg-cyan-500/90 rounded-t-sm animate-pulse"
style="height: 100%; animation-duration: 1.5s; animation-delay: 0.1s;"></div>
<div class="w-full bg-cyan-500/90 rounded-t-sm animate-pulse"
style="height: 30%; animation-duration: 0.8s; animation-delay: 0.7s;"></div>
</div>
<div class="flex flex-col items-end">
<div class="flex items-center gap-1.5 text-cyan-600 font-normal">
<iconify-icon icon="solar:box-linear" class="text-lg"></iconify-icon>
<span class="tracking-tight">INIT</span>
</div>
<div class="text-[10px] text-cyan-600/70 mt-1 uppercase tracking-widest">Base Node</div>
</div>
</div>
<div class="relative z-10 mb-6">
<div class="flex items-end gap-2 mb-2">
<span class="text-5xl tracking-tight text-cyan-500 font-normal">0</span>
<span class="text-sm text-cyan-600/70 mb-1 tracking-widest uppercase">/ Mo</span>
</div>
<h2 class="text-xl tracking-tight text-gray-900 mb-2 font-normal">Standard Node</h2>
<p class="text-xs text-gray-500 leading-relaxed typewriter-text min-h-[2.5rem]"
data-text="Essential telemetry and foundational security layers."></p>
</div>
<div class="relative z-10 flex flex-col gap-3 mb-8 flex-grow">
<div class="w-full h-px mb-1 bg-black/5"></div>
<div class="flex items-center gap-3 text-xs text-gray-600">
<iconify-icon icon="solar:shield-check-linear" class="text-cyan-500 text-base"></iconify-icon>
<span>Standard Encryption</span>
</div>
<div class="flex items-center gap-3 text-xs text-gray-600">
<iconify-icon icon="solar:database-linear" class="text-cyan-500 text-base"></iconify-icon>
<span>Metered Bandwidth</span>
</div>
</div>
<button class="relative z-10 w-full py-3.5 px-5 rounded-xl flex items-center justify-between group/btn transition-all duration-300 hover:bg-gray-50 bg-white border border-black/5 shadow-sm">
<span class="text-xs text-cyan-600 tracking-widest uppercase font-medium">Deploy</span>
<iconify-icon icon="solar:alt-arrow-right-linear" class="text-cyan-500 text-lg group-hover/btn:translate-x-1 transition-transform"></iconify-icon>
</button>
</div>
</div>
<!-- Tier 2: Premium Relay -->
<div class="draggable-card cursor-grab select-none relative w-full max-w-sm md:w-[22rem] h-[32rem] z-0">
<div
class="relative w-full h-full rounded-3xl p-8 flex flex-col group transition-all duration-700 ease-out hover:-translate-y-4 hover:rotate-0 md:rotate-6 md:-translate-x-12"
style="background: linear-gradient(145deg, #ffffff 0%, #fff7ed 100%); box-shadow: 2px 4px 8px rgba(0,0,0,0.02), 8px 16px 24px rgba(0,0,0,0.03), 64px 96px 128px rgba(0,0,0,0.12), 80px 120px 160px rgba(249, 115, 22, 0.15), inset 0 1px 1px rgba(255,255,255,1), 0 0 0 1px rgba(0,0,0,0.04);">
<div class="flex justify-between items-start relative z-10 mb-8">
<div class="w-16 h-16 rounded-xl p-2.5 flex items-end justify-between gap-0.5 bg-white shadow-sm">
<div class="w-full bg-orange-500/90 rounded-t-sm animate-pulse"
style="height: 60%; animation-duration: 0.9s;"></div>
<div class="w-full bg-orange-500/90 rounded-t-sm animate-pulse"
style="height: 90%; animation-duration: 1.1s; animation-delay: 0.1s;"></div>
<div class="w-full bg-orange-500/90 rounded-t-sm animate-pulse"
style="height: 50%; animation-duration: 0.8s; animation-delay: 0.6s;"></div>
<div class="w-full bg-orange-500/90 rounded-t-sm animate-pulse"
style="height: 75%; animation-duration: 1.3s; animation-delay: 0.3s;"></div>
</div>
<div class="flex flex-col items-end">
<div class="flex items-center gap-1.5 text-orange-600 font-normal">
<iconify-icon icon="solar:layers-linear" class="text-lg"></iconify-icon>
<span class="tracking-tight">PLUS</span>
</div>
<div class="text-[10px] text-orange-600/70 mt-1 uppercase tracking-widest">Ultra Relay</div>
</div>
</div>
<div class="relative z-10 mb-6">
<div class="flex items-end gap-2 mb-2">
<span class="text-5xl tracking-tight text-orange-500 font-normal">50</span>
<span class="text-sm text-orange-600/70 mb-1 tracking-widest uppercase">/ Mo</span>
</div>
<h2 class="text-xl tracking-tight text-gray-900 mb-2 font-normal">Premium Relay</h2>
<p class="text-xs text-gray-500 leading-relaxed typewriter-text min-h-[2.5rem]"
data-text="High-speed pathways featuring intelligent failover."></p>
</div>
<div class="relative z-10 flex flex-col gap-3 mb-8 flex-grow">
<div class="w-full h-px mb-1 bg-black/5"></div>
<div class="flex items-center gap-3 text-xs text-gray-600">
<iconify-icon icon="solar:shield-keyhole-linear" class="text-orange-500 text-base"></iconify-icon>
<span>Advanced Cryptography</span>
</div>
<div class="flex items-center gap-3 text-xs text-gray-600">
<iconify-icon icon="solar:infinity-linear" class="text-orange-500 text-base"></iconify-icon>
<span>Unlimited Transfer</span>
</div>
</div>
<button class="relative z-10 w-full py-3.5 px-5 rounded-xl flex items-center justify-between group/btn transition-all duration-300 hover:bg-[#fffcf9] bg-white border border-black/5 shadow-sm">
<span class="text-xs text-orange-600 tracking-widest uppercase font-medium">Deploy</span>
<iconify-icon icon="solar:alt-arrow-right-linear" class="text-orange-500 text-lg group-hover/btn:translate-x-1 transition-transform"></iconify-icon>
</button>
</div>
</div>
</div>
<!-- Logic Layer -->
<script>
// WebGL Noise Background Logic
(function() {
const c = document.getElementById('noiseCanvas');
const gl = c.getContext('webgl', { alpha: true });
if (!gl) return;
const pid = gl.createProgram();
const shader = (type, src) => {
const s = gl.createShader(type);
gl.shaderSource(s, src);
gl.compileShader(s);
gl.attachShader(pid, s);
};
shader(gl.VERTEX_SHADER, 'attribute vec2 p;void main(){gl_Position=vec4(p,0,1);}');
shader(gl.FRAGMENT_SHADER, 'precision lowp float;uniform float t;float rand(vec2 n){return fract(sin(dot(n,vec2(12.9898,4.1414)))*43758.5453);}void main(){vec2 uv=gl_FragCoord.xy;float n=rand(uv+vec2(t,-t));gl_FragColor=vec4(vec3(n),1.0);}');
gl.linkProgram(pid); gl.useProgram(pid);
gl.bindBuffer(gl.ARRAY_BUFFER, gl.createBuffer());
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([-1,-1, 1,-1, -1,1, 1,1]), gl.STATIC_DRAW);
const p = gl.getAttribLocation(pid, 'p');
gl.enableVertexAttribArray(p); gl.vertexAttribPointer(p, 2, gl.FLOAT, false, 0, 0);
const tLoc = gl.getUniformLocation(pid, 't');
const resize = () => { c.width = window.innerWidth; c.height = window.innerHeight; gl.viewport(0,0,c.width,c.height); };
window.addEventListener('resize', resize); resize();
let time = 0;
const draw = () => { time += 0.05; gl.uniform1f(tLoc, time); gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4); requestAnimationFrame(draw); };
draw();
})();
// Typewriter Effect Logic
document.querySelectorAll('.typewriter-text').forEach(el => {
const text = el.getAttribute('data-text');
let i = 0;
const type = () => {
if (i < text.length) { el.innerHTML += text.charAt(i); i++; setTimeout(type, 35); }
};
setTimeout(type, 800 + Math.random() * 500);
});
// Draggable Cards Logic
document.querySelectorAll('.draggable-card').forEach(wrapper => {
let isDragging = false, startX, startY, currentX = 0, currentY = 0;
const originalZ = window.getComputedStyle(wrapper).zIndex;
const start = (e) => {
if (e.target.closest('button')) return;
isDragging = true; wrapper.style.transition = 'none'; wrapper.style.zIndex = '50';
const clientX = e.touches ? e.touches[0].clientX : e.clientX;
const clientY = e.touches ? e.touches[0].clientY : e.clientY;
startX = clientX - currentX; startY = clientY - currentY;
wrapper.classList.replace('cursor-grab', 'cursor-grabbing');
};
const move = (e) => {
if (!isDragging) return;
const clientX = e.touches ? e.touches[0].clientX : e.clientX;
const clientY = e.touches ? e.touches[0].clientY : e.clientY;
currentX = clientX - startX; currentY = clientY - startY;
wrapper.style.transform = `translate(${currentX}px, ${currentY}px)`;
};
const end = () => {
if (!isDragging) return;
isDragging = false; wrapper.style.zIndex = originalZ;
wrapper.style.transition = 'transform 0.6s cubic-bezier(0.34, 1.56, 0.64, 1)';
currentX = 0; currentY = 0; wrapper.style.transform = `translate(0px, 0px)`;
wrapper.classList.replace('cursor-grabbing', 'cursor-grab');
};
wrapper.addEventListener('mousedown', start);
window.addEventListener('mousemove', move);
window.addEventListener('mouseup', end);
wrapper.addEventListener('touchstart', start, {passive: true});
window.addEventListener('touchmove', (e) => { if(isDragging) e.preventDefault(); move(e); }, {passive: false});
window.addEventListener('touchend', end);
});
</script>
</div>