Dynamic Gradient Cookie Consent Banner
A stunning cookie consent banner featuring dynamic gradient backgrounds, smooth animations, and modern interactive design
Responsive Design
Yes
Dark Mode Support
No
lines
997
Browser Compatibility
No
Live Preview
Interact with the component without leaving the page.
Dynamic Gradient Cookie Consent Banner
A visually stunning cookie consent banner that features dynamic gradient backgrounds, smooth color transitions, and modern interactive elements. Perfect for websites that want to make a bold visual statement while maintaining GDPR compliance.
Features
- Dynamic Gradients: Animated gradient backgrounds that shift colors smoothly
- Modern Design: Contemporary UI with vibrant colors and smooth transitions
- Interactive Elements: Hover effects and micro-animations enhance user engagement
- Responsive Layout: Adapts beautifully to all screen sizes and orientations
- GDPR Compliant: Complete consent management with granular controls
- Accessibility First: Full keyboard navigation and screen reader support
- Customizable Colors: Easy gradient and color scheme customization
- Smooth Animations: Fluid transitions and entrance/exit animations
Preview
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Dynamic Gradient Cookie Banner</title>
<style>
:root {
--primary-gradient: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
--secondary-gradient: linear-gradient(135deg, #f093fb 0%, #f5576c 100%);
--accent-gradient: linear-gradient(135deg, #4facfe 0%, #00f2fe 100%);
--success-gradient: linear-gradient(135deg, #43e97b 0%, #38f9d7 100%);
--warning-gradient: linear-gradient(135deg, #fa709a 0%, #fee140 100%);
--text-light: #ffffff;
--text-dark: #2d3748;
--text-muted: rgba(255, 255, 255, 0.8);
--backdrop: rgba(0, 0, 0, 0.3);
--border-radius: 16px;
--shadow: 0 20px 40px rgba(0, 0, 0, 0.1);
--transition: all 0.4s cubic-bezier(0.4, 0, 0.2, 1);
}
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
background: linear-gradient(135deg, #667eea 0%, #764ba2 50%, #f093fb 100%);
background-size: 400% 400%;
animation: gradientShift 15s ease infinite;
min-height: 100vh;
color: var(--text-light);
line-height: 1.6;
}
@keyframes gradientShift {
0% { background-position: 0% 50%; }
50% { background-position: 100% 50%; }
100% { background-position: 0% 50%; }
}
.demo-content {
padding: 3rem 2rem;
text-align: center;
max-width: 800px;
margin: 0 auto;
}
.demo-content h1 {
font-size: 3rem;
font-weight: 800;
margin-bottom: 1rem;
background: linear-gradient(135deg, #ffffff 0%, #f0f0f0 100%);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
background-clip: text;
text-shadow: 0 4px 8px rgba(0, 0, 0, 0.2);
}
.demo-content p {
font-size: 1.2rem;
color: var(--text-muted);
margin-bottom: 2rem;
}
/* Dynamic Gradient Cookie Banner */
.gradient-cookie-banner {
position: fixed;
bottom: 2rem;
left: 2rem;
right: 2rem;
background: linear-gradient(135deg, rgba(102, 126, 234, 0.95) 0%, rgba(118, 75, 162, 0.95) 100%);
backdrop-filter: blur(20px);
border: 1px solid rgba(255, 255, 255, 0.2);
border-radius: var(--border-radius);
padding: 2rem;
box-shadow: var(--shadow);
transform: translateY(120%);
transition: var(--transition);
z-index: 10000;
max-width: 1200px;
margin: 0 auto;
overflow: hidden;
position: relative;
}
.gradient-cookie-banner::before {
content: '';
position: absolute;
top: 0;
left: -100%;
width: 100%;
height: 100%;
background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.1), transparent);
animation: shimmer 3s infinite;
}
@keyframes shimmer {
0% { left: -100%; }
100% { left: 100%; }
}
.gradient-cookie-banner.show {
transform: translateY(0);
}
.cookie-container {
display: grid;
grid-template-columns: auto 1fr auto;
gap: 2rem;
align-items: center;
position: relative;
z-index: 1;
}
.cookie-icon {
width: 60px;
height: 60px;
background: var(--accent-gradient);
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
font-size: 2rem;
box-shadow: 0 8px 16px rgba(79, 172, 254, 0.3);
animation: pulse 2s infinite;
}
@keyframes pulse {
0%, 100% { transform: scale(1); }
50% { transform: scale(1.05); }
}
.cookie-content {
flex: 1;
}
.cookie-title {
font-size: 1.5rem;
font-weight: 700;
margin-bottom: 0.5rem;
color: var(--text-light);
background: linear-gradient(135deg, #ffffff 0%, #e2e8f0 100%);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
background-clip: text;
}
.cookie-description {
color: var(--text-muted);
font-size: 1rem;
line-height: 1.6;
}
.cookie-link {
color: #4facfe;
text-decoration: none;
font-weight: 600;
transition: var(--transition);
position: relative;
}
.cookie-link::after {
content: '';
position: absolute;
bottom: -2px;
left: 0;
width: 0;
height: 2px;
background: var(--accent-gradient);
transition: width 0.3s ease;
}
.cookie-link:hover::after {
width: 100%;
}
.cookie-actions {
display: flex;
gap: 1rem;
flex-wrap: wrap;
}
/* Gradient Buttons */
.gradient-btn {
padding: 0.875rem 1.75rem;
border: none;
border-radius: 12px;
font-family: inherit;
font-size: 0.95rem;
font-weight: 600;
cursor: pointer;
transition: var(--transition);
position: relative;
overflow: hidden;
min-width: 130px;
color: var(--text-light);
text-transform: uppercase;
letter-spacing: 0.5px;
}
.gradient-btn::before {
content: '';
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: linear-gradient(45deg, rgba(255, 255, 255, 0.1), transparent);
transform: translateX(-100%);
transition: transform 0.6s ease;
}
.gradient-btn:hover::before {
transform: translateX(100%);
}
.btn-accept {
background: var(--success-gradient);
box-shadow: 0 8px 16px rgba(67, 233, 123, 0.3);
}
.btn-accept:hover {
transform: translateY(-3px);
box-shadow: 0 12px 24px rgba(67, 233, 123, 0.4);
}
.btn-decline {
background: var(--warning-gradient);
box-shadow: 0 8px 16px rgba(250, 112, 154, 0.3);
}
.btn-decline:hover {
transform: translateY(-3px);
box-shadow: 0 12px 24px rgba(250, 112, 154, 0.4);
}
.btn-settings {
background: var(--accent-gradient);
box-shadow: 0 8px 16px rgba(79, 172, 254, 0.3);
}
.btn-settings:hover {
transform: translateY(-3px);
box-shadow: 0 12px 24px rgba(79, 172, 254, 0.4);
}
.gradient-btn:active {
transform: translateY(-1px);
}
/* Settings Modal */
.cookie-settings-modal {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: var(--backdrop);
backdrop-filter: blur(10px);
display: flex;
align-items: center;
justify-content: center;
z-index: 10001;
opacity: 0;
visibility: hidden;
transition: var(--transition);
}
.cookie-settings-modal.show {
opacity: 1;
visibility: visible;
}
.settings-content {
background: linear-gradient(135deg, rgba(102, 126, 234, 0.95) 0%, rgba(118, 75, 162, 0.95) 100%);
backdrop-filter: blur(20px);
border: 1px solid rgba(255, 255, 255, 0.2);
border-radius: var(--border-radius);
padding: 2.5rem;
max-width: 600px;
width: 90%;
max-height: 80vh;
overflow-y: auto;
box-shadow: 0 25px 50px rgba(0, 0, 0, 0.2);
transform: scale(0.9) translateY(20px);
transition: var(--transition);
position: relative;
}
.cookie-settings-modal.show .settings-content {
transform: scale(1) translateY(0);
}
.settings-content::before {
content: '';
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: linear-gradient(135deg, rgba(255, 255, 255, 0.1) 0%, transparent 50%, rgba(255, 255, 255, 0.05) 100%);
border-radius: var(--border-radius);
pointer-events: none;
}
.settings-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 2rem;
padding-bottom: 1rem;
border-bottom: 1px solid rgba(255, 255, 255, 0.2);
position: relative;
z-index: 1;
}
.settings-title {
font-size: 1.75rem;
font-weight: 700;
color: var(--text-light);
background: linear-gradient(135deg, #ffffff 0%, #e2e8f0 100%);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
background-clip: text;
}
.close-btn {
width: 44px;
height: 44px;
border: none;
border-radius: 50%;
background: var(--warning-gradient);
color: var(--text-light);
font-size: 1.5rem;
cursor: pointer;
transition: var(--transition);
display: flex;
align-items: center;
justify-content: center;
box-shadow: 0 4px 8px rgba(250, 112, 154, 0.3);
}
.close-btn:hover {
transform: scale(1.1) rotate(90deg);
box-shadow: 0 6px 12px rgba(250, 112, 154, 0.4);
}
.cookie-category {
margin-bottom: 2rem;
padding: 1.5rem;
background: rgba(255, 255, 255, 0.1);
border: 1px solid rgba(255, 255, 255, 0.2);
border-radius: 12px;
backdrop-filter: blur(10px);
position: relative;
z-index: 1;
}
.category-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 1rem;
}
.category-title {
font-weight: 700;
font-size: 1.2rem;
color: var(--text-light);
}
.category-description {
font-size: 0.95rem;
color: var(--text-muted);
line-height: 1.6;
}
/* Gradient Toggle Switch */
.gradient-toggle {
position: relative;
width: 64px;
height: 32px;
background: rgba(255, 255, 255, 0.2);
border-radius: 16px;
cursor: pointer;
transition: var(--transition);
border: 1px solid rgba(255, 255, 255, 0.3);
}
.gradient-toggle.active {
background: var(--success-gradient);
box-shadow: 0 4px 8px rgba(67, 233, 123, 0.3);
}
.gradient-toggle::before {
content: '';
position: absolute;
top: 2px;
left: 2px;
width: 28px;
height: 28px;
background: linear-gradient(135deg, #ffffff 0%, #f7fafc 100%);
border-radius: 50%;
transition: var(--transition);
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2);
}
.gradient-toggle.active::before {
transform: translateX(32px);
background: linear-gradient(135deg, #ffffff 0%, #e2e8f0 100%);
}
.settings-actions {
display: flex;
gap: 1rem;
justify-content: flex-end;
margin-top: 2rem;
padding-top: 1rem;
border-top: 1px solid rgba(255, 255, 255, 0.2);
position: relative;
z-index: 1;
}
/* Responsive Design */
@media (max-width: 768px) {
.gradient-cookie-banner {
bottom: 1rem;
left: 1rem;
right: 1rem;
padding: 1.5rem;
}
.cookie-container {
grid-template-columns: 1fr;
gap: 1.5rem;
text-align: center;
}
.cookie-actions {
justify-content: center;
}
.gradient-btn {
flex: 1;
min-width: auto;
}
.settings-content {
padding: 2rem;
margin: 1rem;
}
.demo-content h1 {
font-size: 2rem;
}
}
@media (max-width: 480px) {
.cookie-actions {
flex-direction: column;
}
.gradient-btn {
width: 100%;
}
.cookie-container {
grid-template-columns: 1fr;
}
}
/* Demo Button */
.demo-btn {
padding: 1rem 2rem;
border: none;
border-radius: 12px;
background: var(--primary-gradient);
color: var(--text-light);
font-family: inherit;
font-size: 1.1rem;
font-weight: 600;
cursor: pointer;
transition: var(--transition);
box-shadow: 0 8px 16px rgba(102, 126, 234, 0.3);
text-transform: uppercase;
letter-spacing: 0.5px;
}
.demo-btn:hover {
transform: translateY(-3px);
box-shadow: 0 12px 24px rgba(102, 126, 234, 0.4);
}
/* Floating Particles */
.particle {
position: absolute;
width: 4px;
height: 4px;
background: rgba(255, 255, 255, 0.6);
border-radius: 50%;
animation: float 6s infinite linear;
}
@keyframes float {
0% {
transform: translateY(100vh) rotate(0deg);
opacity: 0;
}
10% {
opacity: 1;
}
90% {
opacity: 1;
}
100% {
transform: translateY(-100px) rotate(360deg);
opacity: 0;
}
}
</style>
</head>
<body>
<div class="demo-content">
<h1>Dynamic Gradient Banner</h1>
<p>Experience the beauty of dynamic gradients with smooth animations and modern interactions</p>
<button class="demo-btn" onclick="showCookieBanner()">Show Cookie Banner</button>
</div>
<!-- Cookie Banner -->
<div id="gradientCookieBanner" class="gradient-cookie-banner">
<div class="cookie-container">
<div class="cookie-icon">🍪</div>
<div class="cookie-content">
<div class="cookie-title">Cookie Preferences</div>
<div class="cookie-description">
We use cookies to enhance your browsing experience and provide personalized content.
<a href="#" class="cookie-link">Privacy Policy</a> |
<a href="#" class="cookie-link">Cookie Policy</a>
</div>
</div>
<div class="cookie-actions">
<button class="gradient-btn btn-accept" onclick="acceptCookies()">Accept All</button>
<button class="gradient-btn btn-decline" onclick="declineCookies()">Decline</button>
<button class="gradient-btn btn-settings" onclick="openSettings()">Customize</button>
</div>
</div>
</div>
<!-- Settings Modal -->
<div id="cookieSettingsModal" class="cookie-settings-modal">
<div class="settings-content">
<div class="settings-header">
<h3 class="settings-title">Cookie Settings</h3>
<button class="close-btn" onclick="closeSettings()">×</button>
</div>
<div class="cookie-category">
<div class="category-header">
<span class="category-title">Essential Cookies</span>
<div class="gradient-toggle active" data-category="essential">
</div>
</div>
<div class="category-description">
These cookies are necessary for the website to function and cannot be switched off. They are usually only set in response to actions made by you.
</div>
</div>
<div class="cookie-category">
<div class="category-header">
<span class="category-title">Analytics Cookies</span>
<div class="gradient-toggle" data-category="analytics">
</div>
</div>
<div class="category-description">
These cookies help us understand how visitors interact with our website by collecting and reporting information anonymously.
</div>
</div>
<div class="cookie-category">
<div class="category-header">
<span class="category-title">Marketing Cookies</span>
<div class="gradient-toggle" data-category="marketing">
</div>
</div>
<div class="category-description">
These cookies are used to deliver advertisements more relevant to you and your interests based on your browsing behavior.
</div>
</div>
<div class="cookie-category">
<div class="category-header">
<span class="category-title">Functional Cookies</span>
<div class="gradient-toggle" data-category="functional">
</div>
</div>
<div class="category-description">
These cookies enable enhanced functionality and personalization, such as remembering your preferences and settings.
</div>
</div>
<div class="settings-actions">
<button class="gradient-btn btn-decline" onclick="saveSettings(false)">Save Preferences</button>
<button class="gradient-btn btn-accept" onclick="saveSettings(true)">Accept All</button>
</div>
</div>
</div>
<script>
class DynamicGradientCookieBanner {
constructor(options = {}) {
this.options = {
autoShow: true,
showDelay: 1000,
storageKey: 'gradient_cookie_consent',
expiryDays: 365,
enableParticles: true,
particleCount: 20,
onAccept: null,
onDecline: null,
onSettingsSave: null,
...options
};
this.banner = document.getElementById('gradientCookieBanner');
this.modal = document.getElementById('cookieSettingsModal');
this.consent = this.getStoredConsent();
this.init();
}
init() {
if (this.options.autoShow && !this.consent) {
setTimeout(() => this.show(), this.options.showDelay);
}
this.setupEventListeners();
this.loadSettings();
if (this.options.enableParticles) {
this.createParticles();
}
}
setupEventListeners() {
// Toggle switches
document.querySelectorAll('.gradient-toggle').forEach(toggle => {
toggle.addEventListener('click', () => {
if (toggle.dataset.category !== 'essential') {
toggle.classList.toggle('active');
this.animateToggle(toggle);
}
});
});
// Modal backdrop click
this.modal.addEventListener('click', (e) => {
if (e.target === this.modal) {
this.closeSettings();
}
});
// Keyboard navigation
document.addEventListener('keydown', (e) => {
if (e.key === 'Escape') {
this.closeSettings();
}
});
// Button hover effects
document.querySelectorAll('.gradient-btn').forEach(btn => {
btn.addEventListener('mouseenter', () => {
this.createRipple(btn);
});
});
}
animateToggle(toggle) {
toggle.style.transform = 'scale(0.95)';
setTimeout(() => {
toggle.style.transform = 'scale(1)';
}, 150);
}
createRipple(button) {
const ripple = document.createElement('span');
const rect = button.getBoundingClientRect();
const size = Math.max(rect.width, rect.height);
ripple.style.width = ripple.style.height = size + 'px';
ripple.style.left = '50%';
ripple.style.top = '50%';
ripple.style.transform = 'translate(-50%, -50%) scale(0)';
ripple.style.position = 'absolute';
ripple.style.borderRadius = '50%';
ripple.style.background = 'rgba(255, 255, 255, 0.3)';
ripple.style.pointerEvents = 'none';
ripple.style.animation = 'ripple 0.6s ease-out';
button.style.position = 'relative';
button.style.overflow = 'hidden';
button.appendChild(ripple);
setTimeout(() => {
ripple.remove();
}, 600);
}
createParticles() {
for (let i = 0; i < this.options.particleCount; i++) {
setTimeout(() => {
this.createParticle();
}, i * 300);
}
setInterval(() => {
this.createParticle();
}, 2000);
}
createParticle() {
const particle = document.createElement('div');
particle.className = 'particle';
particle.style.left = Math.random() * 100 + '%';
particle.style.animationDelay = Math.random() * 2 + 's';
particle.style.animationDuration = (Math.random() * 3 + 3) + 's';
document.body.appendChild(particle);
setTimeout(() => {
particle.remove();
}, 6000);
}
show() {
this.banner.classList.add('show');
this.animateEntrance();
}
hide() {
this.banner.classList.remove('show');
}
animateEntrance() {
const elements = this.banner.querySelectorAll('.cookie-icon, .cookie-content, .cookie-actions');
elements.forEach((el, index) => {
el.style.opacity = '0';
el.style.transform = 'translateY(20px)';
setTimeout(() => {
el.style.transition = 'all 0.6s cubic-bezier(0.4, 0, 0.2, 1)';
el.style.opacity = '1';
el.style.transform = 'translateY(0)';
}, index * 150);
});
}
accept() {
const consent = {
essential: true,
analytics: true,
marketing: true,
functional: true,
timestamp: Date.now()
};
this.saveConsent(consent);
this.hide();
if (this.options.onAccept) {
this.options.onAccept(consent);
}
}
decline() {
const consent = {
essential: true,
analytics: false,
marketing: false,
functional: false,
timestamp: Date.now()
};
this.saveConsent(consent);
this.hide();
if (this.options.onDecline) {
this.options.onDecline(consent);
}
}
openSettings() {
this.modal.classList.add('show');
document.body.style.overflow = 'hidden';
this.animateModalEntrance();
}
closeSettings() {
this.modal.classList.remove('show');
document.body.style.overflow = '';
}
animateModalEntrance() {
const categories = this.modal.querySelectorAll('.cookie-category');
categories.forEach((category, index) => {
category.style.opacity = '0';
category.style.transform = 'translateX(-20px)';
setTimeout(() => {
category.style.transition = 'all 0.4s cubic-bezier(0.4, 0, 0.2, 1)';
category.style.opacity = '1';
category.style.transform = 'translateX(0)';
}, index * 100);
});
}
saveSettings(acceptAll = false) {
const toggles = document.querySelectorAll('.gradient-toggle');
const consent = { timestamp: Date.now() };
toggles.forEach(toggle => {
const category = toggle.dataset.category;
if (acceptAll) {
consent[category] = true;
toggle.classList.add('active');
} else {
consent[category] = toggle.classList.contains('active');
}
});
this.saveConsent(consent);
this.closeSettings();
this.hide();
if (this.options.onSettingsSave) {
this.options.onSettingsSave(consent);
}
}
loadSettings() {
if (this.consent) {
document.querySelectorAll('.gradient-toggle').forEach(toggle => {
const category = toggle.dataset.category;
if (this.consent[category]) {
toggle.classList.add('active');
} else {
toggle.classList.remove('active');
}
});
}
}
saveConsent(consent) {
const expiryDate = new Date();
expiryDate.setDate(expiryDate.getDate() + this.options.expiryDays);
const consentData = {
...consent,
expiry: expiryDate.getTime()
};
localStorage.setItem(this.options.storageKey, JSON.stringify(consentData));
this.consent = consent;
}
getStoredConsent() {
try {
const stored = localStorage.getItem(this.options.storageKey);
if (stored) {
const data = JSON.parse(stored);
if (data.expiry && Date.now() < data.expiry) {
return data;
} else {
localStorage.removeItem(this.options.storageKey);
}
}
} catch (e) {
console.error('Error reading cookie consent:', e);
}
return null;
}
reset() {
localStorage.removeItem(this.options.storageKey);
this.consent = null;
this.show();
}
getConsent() {
return this.consent;
}
updateGradient(gradient) {
const root = document.documentElement;
root.style.setProperty('--primary-gradient', gradient);
}
setParticles(enabled) {
this.options.enableParticles = enabled;
if (enabled) {
this.createParticles();
} else {
document.querySelectorAll('.particle').forEach(p => p.remove());
}
}
}
// Add ripple animation CSS
const style = document.createElement('style');
style.textContent = `
@keyframes ripple {
to {
transform: translate(-50%, -50%) scale(2);
opacity: 0;
}
}
`;
document.head.appendChild(style);
// Initialize the banner
const cookieBanner = new DynamicGradientCookieBanner({
onAccept: (consent) => {
console.log('Cookies accepted:', consent);
// Initialize analytics, marketing scripts, etc.
},
onDecline: (consent) => {
console.log('Cookies declined:', consent);
// Load only essential scripts
},
onSettingsSave: (consent) => {
console.log('Settings saved:', consent);
// Load scripts based on user preferences
}
});
// Global functions for demo
function showCookieBanner() {
cookieBanner.reset();
}
function acceptCookies() {
cookieBanner.accept();
}
function declineCookies() {
cookieBanner.decline();
}
function openSettings() {
cookieBanner.openSettings();
}
function closeSettings() {
cookieBanner.closeSettings();
}
function saveSettings(acceptAll) {
cookieBanner.saveSettings(acceptAll);
}
</script>
</body>
</html>Usage
Basic Implementation
// Initialize with default settings
const cookieBanner = new DynamicGradientCookieBanner();
// Initialize with custom options
const cookieBanner = new DynamicGradientCookieBanner({
autoShow: true,
showDelay: 2000,
storageKey: 'my_cookie_consent',
expiryDays: 180,
enableParticles: true,
particleCount: 30,
onAccept: (consent) => {
console.log('User accepted cookies:', consent);
// Load analytics scripts
if (consent.analytics) {
loadGoogleAnalytics();
}
// Load marketing scripts
if (consent.marketing) {
loadMarketingPixels();
}
},
onDecline: (consent) => {
console.log('User declined cookies:', consent);
// Load only essential functionality
},
onSettingsSave: (consent) => {
console.log('User saved custom settings:', consent);
// Load scripts based on specific preferences
}
});Advanced Configuration
// Advanced styling and behavior
const advancedBanner = new DynamicGradientCookieBanner({
autoShow: false, // Manual control
showDelay: 0,
storageKey: 'advanced_consent',
expiryDays: 90,
enableParticles: true,
particleCount: 50,
// Custom callbacks
onAccept: (consent) => {
// Advanced analytics setup
initializeAdvancedTracking(consent);
},
onDecline: (consent) => {
// Minimal tracking setup
initializeEssentialOnly();
},
onSettingsSave: (consent) => {
// Granular script loading
loadScriptsBasedOnConsent(consent);
}
});
// Custom gradient themes
function setCustomGradient(gradient) {
advancedBanner.updateGradient(gradient);
}
// Particle control
function toggleParticles(enabled) {
advancedBanner.setParticles(enabled);
}
// Manual control
function showConsentBanner() {
advancedBanner.show();
}
// Check current consent status
function checkConsentStatus() {
const consent = advancedBanner.getConsent();
if (consent) {
console.log('Current consent:', consent);
} else {
console.log('No consent given yet');
}
}API Methods
Core Methods
show()- Display the cookie bannerhide()- Hide the cookie banneraccept()- Accept all cookies and hide bannerdecline()- Decline optional cookies and hide bannerreset()- Clear stored consent and show banner again
Settings Management
openSettings()- Open the settings modalcloseSettings()- Close the settings modalsaveSettings(acceptAll)- Save current settingsloadSettings()- Load and apply stored settings
Data Management
getConsent()- Get current consent objectsaveConsent(consent)- Save consent to storagegetStoredConsent()- Retrieve consent from storage
Visual Customization
updateGradient(gradient)- Change the primary gradientsetParticles(enabled)- Enable/disable floating particlesanimateEntrance()- Trigger entrance animationscreateRipple(button)- Create button ripple effects
Customization Options
Visual Customization
- Gradient Schemes: Modify CSS custom properties for different color themes
- Animation Speed: Adjust transition durations and animation timings
- Particle Effects: Control particle count, speed, and appearance
- Typography: Change font families, sizes, and weights
Functional Configuration
- Auto Display: Control automatic banner appearance
- Storage Duration: Set cookie consent expiration period
- Delay Settings: Configure show/hide timing
- Callback Functions: Custom handlers for user actions
Accessibility Features
- Keyboard Navigation: Full keyboard support with focus indicators
- Screen Reader Support: Proper ARIA labels and descriptions
- High Contrast: Enhanced visibility for accessibility
- Focus Management: Proper focus trapping in modal
Browser Compatibility
- Chrome 60+
- Firefox 55+
- Safari 12+
- Edge 79+
- Mobile browsers (iOS Safari 12+, Chrome Mobile 60+)
License
MIT License - free to use in personal and commercial projects.
HTML
965
lines
CSS
1
lines
JavaScript
31
lines
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Dynamic Gradient Cookie Banner</title>
<style>
:root {
--primary-gradient: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
--secondary-gradient: linear-gradient(135deg, #f093fb 0%, #f5576c 100%);
--accent-gradient: linear-gradient(135deg, #4facfe 0%, #00f2fe 100%);
--success-gradient: linear-gradient(135deg, #43e97b 0%, #38f9d7 100%);
--warning-gradient: linear-gradient(135deg, #fa709a 0%, #fee140 100%);
--text-light: #ffffff;
--text-dark: #2d3748;
--text-muted: rgba(255, 255, 255, 0.8);
--backdrop: rgba(0, 0, 0, 0.3);
--border-radius: 16px;
--shadow: 0 20px 40px rgba(0, 0, 0, 0.1);
--transition: all 0.4s cubic-bezier(0.4, 0, 0.2, 1);
}
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
background: linear-gradient(135deg, #667eea 0%, #764ba2 50%, #f093fb 100%);
background-size: 400% 400%;
animation: gradientShift 15s ease infinite;
min-height: 100vh;
color: var(--text-light);
line-height: 1.6;
}
@keyframes gradientShift {
0% { background-position: 0% 50%; }
50% { background-position: 100% 50%; }
100% { background-position: 0% 50%; }
}
.demo-content {
padding: 3rem 2rem;
text-align: center;
max-width: 800px;
margin: 0 auto;
}
.demo-content h1 {
font-size: 3rem;
font-weight: 800;
margin-bottom: 1rem;
background: linear-gradient(135deg, #ffffff 0%, #f0f0f0 100%);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
background-clip: text;
text-shadow: 0 4px 8px rgba(0, 0, 0, 0.2);
}
.demo-content p {
font-size: 1.2rem;
color: var(--text-muted);
margin-bottom: 2rem;
}
/* Dynamic Gradient Cookie Banner */
.gradient-cookie-banner {
position: fixed;
bottom: 2rem;
left: 2rem;
right: 2rem;
background: linear-gradient(135deg, rgba(102, 126, 234, 0.95) 0%, rgba(118, 75, 162, 0.95) 100%);
backdrop-filter: blur(20px);
border: 1px solid rgba(255, 255, 255, 0.2);
border-radius: var(--border-radius);
padding: 2rem;
box-shadow: var(--shadow);
transform: translateY(120%);
transition: var(--transition);
z-index: 10000;
max-width: 1200px;
margin: 0 auto;
overflow: hidden;
position: relative;
}
.gradient-cookie-banner::before {
content: '';
position: absolute;
top: 0;
left: -100%;
width: 100%;
height: 100%;
background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.1), transparent);
animation: shimmer 3s infinite;
}
@keyframes shimmer {
0% { left: -100%; }
100% { left: 100%; }
}
.gradient-cookie-banner.show {
transform: translateY(0);
}
.cookie-container {
display: grid;
grid-template-columns: auto 1fr auto;
gap: 2rem;
align-items: center;
position: relative;
z-index: 1;
}
.cookie-icon {
width: 60px;
height: 60px;
background: var(--accent-gradient);
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
font-size: 2rem;
box-shadow: 0 8px 16px rgba(79, 172, 254, 0.3);
animation: pulse 2s infinite;
}
@keyframes pulse {
0%, 100% { transform: scale(1); }
50% { transform: scale(1.05); }
}
.cookie-content {
flex: 1;
}
.cookie-title {
font-size: 1.5rem;
font-weight: 700;
margin-bottom: 0.5rem;
color: var(--text-light);
background: linear-gradient(135deg, #ffffff 0%, #e2e8f0 100%);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
background-clip: text;
}
.cookie-description {
color: var(--text-muted);
font-size: 1rem;
line-height: 1.6;
}
.cookie-link {
color: #4facfe;
text-decoration: none;
font-weight: 600;
transition: var(--transition);
position: relative;
}
.cookie-link::after {
content: '';
position: absolute;
bottom: -2px;
left: 0;
width: 0;
height: 2px;
background: var(--accent-gradient);
transition: width 0.3s ease;
}
.cookie-link:hover::after {
width: 100%;
}
.cookie-actions {
display: flex;
gap: 1rem;
flex-wrap: wrap;
}
/* Gradient Buttons */
.gradient-btn {
padding: 0.875rem 1.75rem;
border: none;
border-radius: 12px;
font-family: inherit;
font-size: 0.95rem;
font-weight: 600;
cursor: pointer;
transition: var(--transition);
position: relative;
overflow: hidden;
min-width: 130px;
color: var(--text-light);
text-transform: uppercase;
letter-spacing: 0.5px;
}
.gradient-btn::before {
content: '';
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: linear-gradient(45deg, rgba(255, 255, 255, 0.1), transparent);
transform: translateX(-100%);
transition: transform 0.6s ease;
}
.gradient-btn:hover::before {
transform: translateX(100%);
}
.btn-accept {
background: var(--success-gradient);
box-shadow: 0 8px 16px rgba(67, 233, 123, 0.3);
}
.btn-accept:hover {
transform: translateY(-3px);
box-shadow: 0 12px 24px rgba(67, 233, 123, 0.4);
}
.btn-decline {
background: var(--warning-gradient);
box-shadow: 0 8px 16px rgba(250, 112, 154, 0.3);
}
.btn-decline:hover {
transform: translateY(-3px);
box-shadow: 0 12px 24px rgba(250, 112, 154, 0.4);
}
.btn-settings {
background: var(--accent-gradient);
box-shadow: 0 8px 16px rgba(79, 172, 254, 0.3);
}
.btn-settings:hover {
transform: translateY(-3px);
box-shadow: 0 12px 24px rgba(79, 172, 254, 0.4);
}
.gradient-btn:active {
transform: translateY(-1px);
}
/* Settings Modal */
.cookie-settings-modal {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: var(--backdrop);
backdrop-filter: blur(10px);
display: flex;
align-items: center;
justify-content: center;
z-index: 10001;
opacity: 0;
visibility: hidden;
transition: var(--transition);
}
.cookie-settings-modal.show {
opacity: 1;
visibility: visible;
}
.settings-content {
background: linear-gradient(135deg, rgba(102, 126, 234, 0.95) 0%, rgba(118, 75, 162, 0.95) 100%);
backdrop-filter: blur(20px);
border: 1px solid rgba(255, 255, 255, 0.2);
border-radius: var(--border-radius);
padding: 2.5rem;
max-width: 600px;
width: 90%;
max-height: 80vh;
overflow-y: auto;
box-shadow: 0 25px 50px rgba(0, 0, 0, 0.2);
transform: scale(0.9) translateY(20px);
transition: var(--transition);
position: relative;
}
.cookie-settings-modal.show .settings-content {
transform: scale(1) translateY(0);
}
.settings-content::before {
content: '';
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: linear-gradient(135deg, rgba(255, 255, 255, 0.1) 0%, transparent 50%, rgba(255, 255, 255, 0.05) 100%);
border-radius: var(--border-radius);
pointer-events: none;
}
.settings-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 2rem;
padding-bottom: 1rem;
border-bottom: 1px solid rgba(255, 255, 255, 0.2);
position: relative;
z-index: 1;
}
.settings-title {
font-size: 1.75rem;
font-weight: 700;
color: var(--text-light);
background: linear-gradient(135deg, #ffffff 0%, #e2e8f0 100%);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
background-clip: text;
}
.close-btn {
width: 44px;
height: 44px;
border: none;
border-radius: 50%;
background: var(--warning-gradient);
color: var(--text-light);
font-size: 1.5rem;
cursor: pointer;
transition: var(--transition);
display: flex;
align-items: center;
justify-content: center;
box-shadow: 0 4px 8px rgba(250, 112, 154, 0.3);
}
.close-btn:hover {
transform: scale(1.1) rotate(90deg);
box-shadow: 0 6px 12px rgba(250, 112, 154, 0.4);
}
.cookie-category {
margin-bottom: 2rem;
padding: 1.5rem;
background: rgba(255, 255, 255, 0.1);
border: 1px solid rgba(255, 255, 255, 0.2);
border-radius: 12px;
backdrop-filter: blur(10px);
position: relative;
z-index: 1;
}
.category-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 1rem;
}
.category-title {
font-weight: 700;
font-size: 1.2rem;
color: var(--text-light);
}
.category-description {
font-size: 0.95rem;
color: var(--text-muted);
line-height: 1.6;
}
/* Gradient Toggle Switch */
.gradient-toggle {
position: relative;
width: 64px;
height: 32px;
background: rgba(255, 255, 255, 0.2);
border-radius: 16px;
cursor: pointer;
transition: var(--transition);
border: 1px solid rgba(255, 255, 255, 0.3);
}
.gradient-toggle.active {
background: var(--success-gradient);
box-shadow: 0 4px 8px rgba(67, 233, 123, 0.3);
}
.gradient-toggle::before {
content: '';
position: absolute;
top: 2px;
left: 2px;
width: 28px;
height: 28px;
background: linear-gradient(135deg, #ffffff 0%, #f7fafc 100%);
border-radius: 50%;
transition: var(--transition);
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2);
}
.gradient-toggle.active::before {
transform: translateX(32px);
background: linear-gradient(135deg, #ffffff 0%, #e2e8f0 100%);
}
.settings-actions {
display: flex;
gap: 1rem;
justify-content: flex-end;
margin-top: 2rem;
padding-top: 1rem;
border-top: 1px solid rgba(255, 255, 255, 0.2);
position: relative;
z-index: 1;
}
/* Responsive Design */
@media (max-width: 768px) {
.gradient-cookie-banner {
bottom: 1rem;
left: 1rem;
right: 1rem;
padding: 1.5rem;
}
.cookie-container {
grid-template-columns: 1fr;
gap: 1.5rem;
text-align: center;
}
.cookie-actions {
justify-content: center;
}
.gradient-btn {
flex: 1;
min-width: auto;
}
.settings-content {
padding: 2rem;
margin: 1rem;
}
.demo-content h1 {
font-size: 2rem;
}
}
@media (max-width: 480px) {
.cookie-actions {
flex-direction: column;
}
.gradient-btn {
width: 100%;
}
.cookie-container {
grid-template-columns: 1fr;
}
}
/* Demo Button */
.demo-btn {
padding: 1rem 2rem;
border: none;
border-radius: 12px;
background: var(--primary-gradient);
color: var(--text-light);
font-family: inherit;
font-size: 1.1rem;
font-weight: 600;
cursor: pointer;
transition: var(--transition);
box-shadow: 0 8px 16px rgba(102, 126, 234, 0.3);
text-transform: uppercase;
letter-spacing: 0.5px;
}
.demo-btn:hover {
transform: translateY(-3px);
box-shadow: 0 12px 24px rgba(102, 126, 234, 0.4);
}
/* Floating Particles */
.particle {
position: absolute;
width: 4px;
height: 4px;
background: rgba(255, 255, 255, 0.6);
border-radius: 50%;
animation: float 6s infinite linear;
}
@keyframes float {
0% {
transform: translateY(100vh) rotate(0deg);
opacity: 0;
}
10% {
opacity: 1;
}
90% {
opacity: 1;
}
100% {
transform: translateY(-100px) rotate(360deg);
opacity: 0;
}
}
</style>
</head>
<body>
<div class="demo-content">
<h1>Dynamic Gradient Banner</h1>
<p>Experience the beauty of dynamic gradients with smooth animations and modern interactions</p>
<button class="demo-btn" onclick="showCookieBanner()">Show Cookie Banner</button>
</div>
<!-- Cookie Banner -->
<div id="gradientCookieBanner" class="gradient-cookie-banner">
<div class="cookie-container">
<div class="cookie-icon">🍪</div>
<div class="cookie-content">
<div class="cookie-title">Cookie Preferences</div>
<div class="cookie-description">
We use cookies to enhance your browsing experience and provide personalized content.
<a href="#" class="cookie-link">Privacy Policy</a> |
<a href="#" class="cookie-link">Cookie Policy</a>
</div>
</div>
<div class="cookie-actions">
<button class="gradient-btn btn-accept" onclick="acceptCookies()">Accept All</button>
<button class="gradient-btn btn-decline" onclick="declineCookies()">Decline</button>
<button class="gradient-btn btn-settings" onclick="openSettings()">Customize</button>
</div>
</div>
</div>
<!-- Settings Modal -->
<div id="cookieSettingsModal" class="cookie-settings-modal">
<div class="settings-content">
<div class="settings-header">
<h3 class="settings-title">Cookie Settings</h3>
<button class="close-btn" onclick="closeSettings()">×</button>
</div>
<div class="cookie-category">
<div class="category-header">
<span class="category-title">Essential Cookies</span>
<div class="gradient-toggle active" data-category="essential">
</div>
</div>
<div class="category-description">
These cookies are necessary for the website to function and cannot be switched off. They are usually only set in response to actions made by you.
</div>
</div>
<div class="cookie-category">
<div class="category-header">
<span class="category-title">Analytics Cookies</span>
<div class="gradient-toggle" data-category="analytics">
</div>
</div>
<div class="category-description">
These cookies help us understand how visitors interact with our website by collecting and reporting information anonymously.
</div>
</div>
<div class="cookie-category">
<div class="category-header">
<span class="category-title">Marketing Cookies</span>
<div class="gradient-toggle" data-category="marketing">
</div>
</div>
<div class="category-description">
These cookies are used to deliver advertisements more relevant to you and your interests based on your browsing behavior.
</div>
</div>
<div class="cookie-category">
<div class="category-header">
<span class="category-title">Functional Cookies</span>
<div class="gradient-toggle" data-category="functional">
</div>
</div>
<div class="category-description">
These cookies enable enhanced functionality and personalization, such as remembering your preferences and settings.
</div>
</div>
<div class="settings-actions">
<button class="gradient-btn btn-decline" onclick="saveSettings(false)">Save Preferences</button>
<button class="gradient-btn btn-accept" onclick="saveSettings(true)">Accept All</button>
</div>
</div>
</div>
<script>
class DynamicGradientCookieBanner {
constructor(options = {}) {
this.options = {
autoShow: true,
showDelay: 1000,
storageKey: 'gradient_cookie_consent',
expiryDays: 365,
enableParticles: true,
particleCount: 20,
onAccept: null,
onDecline: null,
onSettingsSave: null,
...options
};
this.banner = document.getElementById('gradientCookieBanner');
this.modal = document.getElementById('cookieSettingsModal');
this.consent = this.getStoredConsent();
this.init();
}
init() {
if (this.options.autoShow && !this.consent) {
setTimeout(() => this.show(), this.options.showDelay);
}
this.setupEventListeners();
this.loadSettings();
if (this.options.enableParticles) {
this.createParticles();
}
}
setupEventListeners() {
// Toggle switches
document.querySelectorAll('.gradient-toggle').forEach(toggle => {
toggle.addEventListener('click', () => {
if (toggle.dataset.category !== 'essential') {
toggle.classList.toggle('active');
this.animateToggle(toggle);
}
});
});
// Modal backdrop click
this.modal.addEventListener('click', (e) => {
if (e.target === this.modal) {
this.closeSettings();
}
});
// Keyboard navigation
document.addEventListener('keydown', (e) => {
if (e.key === 'Escape') {
this.closeSettings();
}
});
// Button hover effects
document.querySelectorAll('.gradient-btn').forEach(btn => {
btn.addEventListener('mouseenter', () => {
this.createRipple(btn);
});
});
}
animateToggle(toggle) {
toggle.style.transform = 'scale(0.95)';
setTimeout(() => {
toggle.style.transform = 'scale(1)';
}, 150);
}
createRipple(button) {
const ripple = document.createElement('span');
const rect = button.getBoundingClientRect();
const size = Math.max(rect.width, rect.height);
ripple.style.width = ripple.style.height = size + 'px';
ripple.style.left = '50%';
ripple.style.top = '50%';
ripple.style.transform = 'translate(-50%, -50%) scale(0)';
ripple.style.position = 'absolute';
ripple.style.borderRadius = '50%';
ripple.style.background = 'rgba(255, 255, 255, 0.3)';
ripple.style.pointerEvents = 'none';
ripple.style.animation = 'ripple 0.6s ease-out';
button.style.position = 'relative';
button.style.overflow = 'hidden';
button.appendChild(ripple);
setTimeout(() => {
ripple.remove();
}, 600);
}
createParticles() {
for (let i = 0; i < this.options.particleCount; i++) {
setTimeout(() => {
this.createParticle();
}, i * 300);
}
setInterval(() => {
this.createParticle();
}, 2000);
}
createParticle() {
const particle = document.createElement('div');
particle.className = 'particle';
particle.style.left = Math.random() * 100 + '%';
particle.style.animationDelay = Math.random() * 2 + 's';
particle.style.animationDuration = (Math.random() * 3 + 3) + 's';
document.body.appendChild(particle);
setTimeout(() => {
particle.remove();
}, 6000);
}
show() {
this.banner.classList.add('show');
this.animateEntrance();
}
hide() {
this.banner.classList.remove('show');
}
animateEntrance() {
const elements = this.banner.querySelectorAll('.cookie-icon, .cookie-content, .cookie-actions');
elements.forEach((el, index) => {
el.style.opacity = '0';
el.style.transform = 'translateY(20px)';
setTimeout(() => {
el.style.transition = 'all 0.6s cubic-bezier(0.4, 0, 0.2, 1)';
el.style.opacity = '1';
el.style.transform = 'translateY(0)';
}, index * 150);
});
}
accept() {
const consent = {
essential: true,
analytics: true,
marketing: true,
functional: true,
timestamp: Date.now()
};
this.saveConsent(consent);
this.hide();
if (this.options.onAccept) {
this.options.onAccept(consent);
}
}
decline() {
const consent = {
essential: true,
analytics: false,
marketing: false,
functional: false,
timestamp: Date.now()
};
this.saveConsent(consent);
this.hide();
if (this.options.onDecline) {
this.options.onDecline(consent);
}
}
openSettings() {
this.modal.classList.add('show');
document.body.style.overflow = 'hidden';
this.animateModalEntrance();
}
closeSettings() {
this.modal.classList.remove('show');
document.body.style.overflow = '';
}
animateModalEntrance() {
const categories = this.modal.querySelectorAll('.cookie-category');
categories.forEach((category, index) => {
category.style.opacity = '0';
category.style.transform = 'translateX(-20px)';
setTimeout(() => {
category.style.transition = 'all 0.4s cubic-bezier(0.4, 0, 0.2, 1)';
category.style.opacity = '1';
category.style.transform = 'translateX(0)';
}, index * 100);
});
}
saveSettings(acceptAll = false) {
const toggles = document.querySelectorAll('.gradient-toggle');
const consent = { timestamp: Date.now() };
toggles.forEach(toggle => {
const category = toggle.dataset.category;
if (acceptAll) {
consent[category] = true;
toggle.classList.add('active');
} else {
consent[category] = toggle.classList.contains('active');
}
});
this.saveConsent(consent);
this.closeSettings();
this.hide();
if (this.options.onSettingsSave) {
this.options.onSettingsSave(consent);
}
}
loadSettings() {
if (this.consent) {
document.querySelectorAll('.gradient-toggle').forEach(toggle => {
const category = toggle.dataset.category;
if (this.consent[category]) {
toggle.classList.add('active');
} else {
toggle.classList.remove('active');
}
});
}
}
saveConsent(consent) {
const expiryDate = new Date();
expiryDate.setDate(expiryDate.getDate() + this.options.expiryDays);
const consentData = {
...consent,
expiry: expiryDate.getTime()
};
localStorage.setItem(this.options.storageKey, JSON.stringify(consentData));
this.consent = consent;
}
getStoredConsent() {
try {
const stored = localStorage.getItem(this.options.storageKey);
if (stored) {
const data = JSON.parse(stored);
if (data.expiry && Date.now() < data.expiry) {
return data;
} else {
localStorage.removeItem(this.options.storageKey);
}
}
} catch (e) {
console.error('Error reading cookie consent:', e);
}
return null;
}
reset() {
localStorage.removeItem(this.options.storageKey);
this.consent = null;
this.show();
}
getConsent() {
return this.consent;
}
updateGradient(gradient) {
const root = document.documentElement;
root.style.setProperty('--primary-gradient', gradient);
}
setParticles(enabled) {
this.options.enableParticles = enabled;
if (enabled) {
this.createParticles();
} else {
document.querySelectorAll('.particle').forEach(p => p.remove());
}
}
}
// Add ripple animation CSS
const style = document.createElement('style');
style.textContent = `
@keyframes ripple {
to {
transform: translate(-50%, -50%) scale(2);
opacity: 0;
}
}
`;
document.head.appendChild(style);
// Initialize the banner
const cookieBanner = new DynamicGradientCookieBanner({
onAccept: (consent) => {
console.log('Cookies accepted:', consent);
// Initialize analytics, marketing scripts, etc.
},
onDecline: (consent) => {
console.log('Cookies declined:', consent);
// Load only essential scripts
},
onSettingsSave: (consent) => {
console.log('Settings saved:', consent);
// Load scripts based on user preferences
}
});
// Global functions for demo
function showCookieBanner() {
cookieBanner.reset();
}
function acceptCookies() {
cookieBanner.accept();
}
function declineCookies() {
cookieBanner.decline();
}
function openSettings() {
cookieBanner.openSettings();
}
function closeSettings() {
cookieBanner.closeSettings();
}
function saveSettings(acceptAll) {
cookieBanner.saveSettings(acceptAll);
}
</script>
</body>
</html>