Ribbons are versatile design elements that can add a touch of elegance and functionality to any user interface. Whether used for navigation, highlighting important information, or simply enhancing visual appeal, ribbons are a powerful tool in a designer's arsenal.
In this article, we will explore ten stunning ribbon examples that showcase their diverse applications and creative implementations. From minimalist designs to intricate patterns, these examples will inspire you to incorporate ribbons into your next project.
CODE1
Here's the code:
CODETEXT1
CODE2
Here's the code:
CODETEXT2
CODE3
Here's the code:
CODETEXT3
CODE4
Here's the code:
CODETEXT4
CODE5
Here's the code:
CODETEXT5
Designers and developers, elevate your UI game with Subframe's drag-and-drop interface and intuitive, responsive canvas. Create pixel-perfect ribbons effortlessly, loved by professionals for its ease and precision.
Ready to transform your designs? Start for free today!
CODE6
Here's the code:
CODETEXT6
CODE7
Here's the code:
CODETEXT7
CODE8
Here's the code:
CODETEXT8
CODE9
Here's the code:
CODETEXT9
CODE10
Here's the code:
CODETEXT10
Unlock the power of Subframe and design pixel-perfect UIs with unmatched efficiency. Whether you're crafting intricate ribbons or entire interfaces, Subframe's intuitive tools make it effortless.
Ready to elevate your design game? Start for free and begin creating stunning UIs immediately!
<html> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>E-commerce Sale Ribbon</title> <style> * { margin: 0; padding: 0; box-sizing: border-box; font-family: 'Poppins', sans-serif; } body { display: flex; justify-content: center; align-items: center; min-height: 100vh; background-color: #f8f9fa; overflow: hidden; } .container { width: 100%; max-width: 700px; height: 700px; display: flex; flex-direction: column; align-items: center; justify-content: center; padding: 20px; position: relative; } .product-card { width: 300px; height: 400px; background-color: white; border-radius: 20px; box-shadow: 0 10px 30px rgba(0, 0, 0, 0.1); overflow: hidden; position: relative; transition: transform 0.4s ease, box-shadow 0.4s ease; } .product-card:hover { transform: translateY(-10px); box-shadow: 0 15px 35px rgba(0, 0, 0, 0.15); } .product-image { width: 100%; height: 250px; background-image: url('https://images.unsplash.com/photo-1523275335684-37898b6baf30?ixlib=rb-1.2.1&auto=format&fit=crop&w=1350&q=80'); background-size: cover; background-position: center; position: relative; } .ribbon-container { position: absolute; top: 20px; right: -50px; transform: rotate(45deg); z-index: 10; overflow: hidden; transition: all 0.3s ease; } .sale-ribbon { width: 200px; height: 40px; background: linear-gradient(135deg, #FF416C 0%, #FF4B2B 100%); display: flex; justify-content: center; align-items: center; color: white; font-weight: 600; font-size: 16px; letter-spacing: 1px; box-shadow: 0 5px 15px rgba(255, 75, 43, 0.4); position: relative; transition: all 0.3s ease; cursor: pointer; } .sale-ribbon::before { content: ""; position: absolute; top: 0; left: 0; width: 100%; height: 100%; background: linear-gradient(45deg, rgba(255, 255, 255, 0.2) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.2) 50%, rgba(255, 255, 255, 0.2) 75%, transparent 75%, transparent); background-size: 10px 10px; opacity: 0; transition: opacity 0.3s ease, transform 0.5s ease; } .sale-ribbon:hover::before { opacity: 1; animation: stripe-animation 10s linear infinite; } @keyframes stripe-animation { 0% { background-position: 0 0; } 100% { background-position: 50px 0; } } .sale-ribbon:hover { transform: scale(1.05); box-shadow: 0 8px 20px rgba(255, 75, 43, 0.6); } .sale-text { position: relative; z-index: 2; display: flex; align-items: center; } .percentage { font-size: 22px; margin-right: 5px; font-weight: 700; } .cta-icon { margin-left: 10px; transition: transform 0.3s ease; } .sale-ribbon:hover .cta-icon { transform: translateX(5px); } .product-details { padding: 20px; } .product-title { font-size: 18px; font-weight: 600; color: #333; margin-bottom: 10px; } .product-price { display: flex; align-items: center; gap: 10px; margin-bottom: 15px; } .original-price { font-size: 16px; color: #888; text-decoration: line-through; } .discounted-price { font-size: 20px; font-weight: 700; color: #FF416C; } .cta-button { width: 100%; padding: 12px 0; background: linear-gradient(135deg, #FF416C 0%, #FF4B2B 100%); border: none; border-radius: 8px; color: white; font-weight: 600; font-size: 14px; cursor: pointer; transition: all 0.3s ease; position: relative; overflow: hidden; } .cta-button::before { content: ""; position: absolute; top: 0; left: -100%; width: 100%; height: 100%; background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.3), transparent); transition: left 0.6s ease; } .cta-button:hover::before { left: 100%; } .cta-button:hover { transform: translateY(-2px); box-shadow: 0 5px 15px rgba(255, 75, 43, 0.4); } .sale-timer { position: absolute; bottom: 20px; left: 50%; transform: translateX(-50%); background-color: rgba(255, 255, 255, 0.9); padding: 10px 20px; border-radius: 30px; box-shadow: 0 5px 15px rgba(0, 0, 0, 0.1); font-size: 14px; color: #333; font-weight: 600; display: flex; align-items: center; transition: all 0.3s ease; } .sale-timer:hover { transform: translateX(-50%) scale(1.05); box-shadow: 0 8px 20px rgba(0, 0, 0, 0.15); } .timer-icon { margin-right: 8px; color: #FF416C; } .countdown { font-weight: 700; color: #FF416C; } @media (max-width: 500px) { .product-card { width: 85%; height: auto; } .product-image { height: 200px; } .sale-ribbon { width: 180px; height: 35px; font-size: 14px; } .percentage { font-size: 18px; } .product-details { padding: 15px; } .product-title { font-size: 16px; } .original-price { font-size: 14px; } .discounted-price { font-size: 18px; } .cta-button { padding: 10px 0; } .sale-timer { bottom: 15px; padding: 8px 15px; font-size: 12px; } } </style> </head> <body> <div class="container"> <div class="product-card"> <div class="product-image"> <div class="ribbon-container"> <div class="sale-ribbon"> <div class="sale-text"> <span class="percentage">40%</span> FLASH SALE <span class="cta-icon">→</span> </div> </div> </div> </div> <div class="product-details"> <h3 class="product-title">Premium Wireless Headphones</h3> <div class="product-price"> <span class="original-price">$199.99</span> <span class="discounted-price">$119.99</span> </div> <button class="cta-button">ADD TO CART</button> </div> </div> <div class="sale-timer"> <span class="timer-icon">⏱</span> Ends in: <span class="countdown" id="countdown">23:59:59</span> </div> </div> <script> // Animated hover effect for the ribbon const ribbon = document.querySelector('.sale-ribbon'); ribbon.addEventListener('mouseenter', () => { ribbon.style.transform = 'scale(1.05)'; }); ribbon.addEventListener('mouseleave', () => { ribbon.style.transform = 'scale(1)'; }); // Countdown timer functionality function updateCountdown() { // Get current time const now = new Date(); // Set end time to end of today const endOfDay = new Date(); endOfDay.setHours(23, 59, 59); // Calculate remaining time const diff = endOfDay - now; if (diff > 0) { // Calculate hours, minutes, seconds const hours = Math.floor(diff / (1000 * 60 * 60)); const minutes = Math.floor((diff % (1000 * 60 * 60)) / (1000 * 60)); const seconds = Math.floor((diff % (1000 * 60)) / 1000); // Format with leading zeros const formattedHours = String(hours).padStart(2, '0'); const formattedMinutes = String(minutes).padStart(2, '0'); const formattedSeconds = String(seconds).padStart(2, '0'); // Display countdown document.getElementById('countdown').textContent = `${formattedHours}:${formattedMinutes}:${formattedSeconds}`; } else { // Reset timer if day ended document.getElementById('countdown').textContent = "00:00:00"; } } // Initial call updateCountdown(); // Update every second setInterval(updateCountdown, 1000); // Add pulse animation to button on hover const button = document.querySelector('.cta-button'); button.addEventListener('click', function(e) { e.preventDefault(); // Create ripple effect const ripple = document.createElement('span'); this.appendChild(ripple); const x = e.clientX - e.target.getBoundingClientRect().left; const y = e.clientY - e.target.getBoundingClientRect().top; ripple.style.left = `${x}px`; ripple.style.top = `${y}px`; // Show added to cart message this.textContent = "✓ ADDED TO CART"; // Reset button after delay setTimeout(() => { this.textContent = "ADD TO CART"; }, 2000); }); </script> </body> </html>
<html> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Gaming Achievement Banner</title> <style> * { margin: 0; padding: 0; box-sizing: border-box; font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; } body { width: 100%; height: 100vh; display: flex; justify-content: center; align-items: center; overflow: hidden; background-color: #1a1a2e; padding: 20px; position: relative; } .achievement-container { width: 100%; max-width: 650px; position: relative; opacity: 0; transform: translateY(50px); animation: slide-in 0.8s cubic-bezier(0.25, 1, 0.5, 1) forwards 0.3s; } @keyframes slide-in { 0% { opacity: 0; transform: translateY(50px); } 100% { opacity: 1; transform: translateY(0); } } .achievement-banner { width: 100%; background: linear-gradient(135deg, #0b132b, #1c2541); border-radius: 12px; padding: 20px; box-shadow: 0 10px 25px rgba(0, 0, 0, 0.3); position: relative; overflow: hidden; z-index: 1; border: 1px solid rgba(255, 255, 255, 0.1); } .achievement-banner::before { content: ''; position: absolute; top: -50%; left: -50%; width: 200%; height: 200%; background: radial-gradient(ellipse at center, rgba(255, 255, 255, 0.1) 0%, rgba(0, 0, 0, 0) 70%); z-index: -1; animation: pulse 3s ease-in-out infinite; } @keyframes pulse { 0% { transform: scale(1); opacity: 0.5; } 50% { transform: scale(1.05); opacity: 0.7; } 100% { transform: scale(1); opacity: 0.5; } } .ribbon { position: absolute; top: 0; right: 0; width: 120px; height: 120px; overflow: hidden; z-index: 1; } .ribbon-content { position: absolute; top: 25px; right: -25px; width: 150px; height: 30px; transform: rotate(45deg); background: linear-gradient(90deg, #ff00cc, #3333ff); box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2); display: flex; align-items: center; justify-content: center; animation: glow 2s ease-in-out infinite; } @keyframes glow { 0% { filter: brightness(100%) drop-shadow(0 0 3px rgba(255, 0, 204, 0.5)); } 50% { filter: brightness(120%) drop-shadow(0 0 8px rgba(51, 51, 255, 0.8)); } 100% { filter: brightness(100%) drop-shadow(0 0 3px rgba(255, 0, 204, 0.5)); } } .ribbon-text { color: white; font-weight: bold; font-size: 12px; text-transform: uppercase; letter-spacing: 1px; text-shadow: 0 1px 2px rgba(0, 0, 0, 0.6); } .achievement-icon { width: 80px; height: 80px; background: radial-gradient(circle, #3a506b, #1c2541); border-radius: 50%; display: flex; justify-content: center; align-items: center; margin-right: 20px; position: relative; border: 3px solid #5bc0be; box-shadow: 0 0 15px rgba(91, 192, 190, 0.5); } .achievement-icon svg { width: 40px; height: 40px; fill: #5bc0be; filter: drop-shadow(0 0 3px rgba(91, 192, 190, 0.8)); } .achievement-content { display: flex; align-items: center; position: relative; } .achievement-details { flex: 1; } .achievement-title { font-size: 22px; font-weight: 700; color: #ffffff; margin-bottom: 5px; text-shadow: 0 2px 4px rgba(0, 0, 0, 0.3); display: flex; align-items: center; } .achievement-desc { font-size: 14px; color: #b3b3cc; margin-bottom: 12px; line-height: 1.4; } .achievement-points { display: inline-block; background: linear-gradient(90deg, #ff00cc, #3333ff); padding: 5px 12px; border-radius: 20px; color: white; font-weight: bold; font-size: 14px; margin-left: 10px; box-shadow: 0 2px 5px rgba(0, 0, 0, 0.2); animation: pulse-xp 2s ease-in-out infinite; } @keyframes pulse-xp { 0% { transform: scale(1); } 50% { transform: scale(1.05); } 100% { transform: scale(1); } } .progress-container { width: 100%; height: 6px; background-color: rgba(255, 255, 255, 0.1); border-radius: 3px; margin-top: 10px; overflow: hidden; position: relative; } .progress-bar { height: 100%; width: 0%; background: linear-gradient(90deg, #ff00cc, #3333ff); border-radius: 3px; position: relative; transition: width 1.5s cubic-bezier(0.25, 1, 0.5, 1); } .progress-bar::after { content: ''; position: absolute; top: 0; left: 0; right: 0; bottom: 0; background: linear-gradient(90deg, transparent 0%, rgba(255, 255, 255, 0.2) 50%, transparent 100%); animation: shine 2s infinite linear; } @keyframes shine { 0% { transform: translateX(-100%); } 100% { transform: translateX(100%); } } .share-button { margin-top: 15px; background: rgba(255, 255, 255, 0.1); border: none; color: #5bc0be; padding: 8px 16px; border-radius: 4px; font-size: 14px; cursor: pointer; transition: all 0.3s ease; display: flex; align-items: center; gap: 8px; } .share-button:hover { background: rgba(91, 192, 190, 0.2); transform: translateY(-2px); } .share-button svg { width: 16px; height: 16px; fill: #5bc0be; } .particles { position: absolute; top: 0; left: 0; width: 100%; height: 100%; pointer-events: none; z-index: 0; } .particle { position: absolute; width: 10px; height: 10px; background: linear-gradient(90deg, #ff00cc, #3333ff); border-radius: 50%; animation: particle-fade 1.5s ease-out forwards; opacity: 0; } @keyframes particle-fade { 0% { transform: translateY(0) scale(0); opacity: 1; } 100% { transform: translateY(-100px) scale(1); opacity: 0; } } .replay-btn { position: absolute; bottom: 20px; left: 50%; transform: translateX(-50%); background: rgba(91, 192, 190, 0.2); border: 1px solid rgba(91, 192, 190, 0.5); color: #5bc0be; padding: 10px 20px; border-radius: 30px; font-size: 14px; cursor: pointer; transition: all 0.3s ease; box-shadow: 0 2px 10px rgba(0, 0, 0, 0.2); } .replay-btn:hover { background: rgba(91, 192, 190, 0.3); transform: translateX(-50%) translateY(-2px); box-shadow: 0 4px 15px rgba(0, 0, 0, 0.3); } /* Responsive Design */ @media (max-width: 600px) { .achievement-content { flex-direction: column; text-align: center; } .achievement-icon { margin-right: 0; margin-bottom: 15px; } .ribbon { width: 80px; height: 80px; } .ribbon-content { top: 15px; right: -30px; width: 120px; height: 25px; } .ribbon-text { font-size: 10px; } .achievement-title { flex-direction: column; gap: 8px; } .achievement-points { margin-left: 0; } } </style> </head> <body> <div class="achievement-container"> <div class="achievement-banner"> <div class="ribbon"> <div class="ribbon-content"> <span class="ribbon-text">Unlocked!</span> </div> </div> <div class="achievement-content"> <div class="achievement-icon"> <svg viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"> <path d="M12 2L8.5 8.5L2 9.5L7 14L5.5 21L12 17.5L18.5 21L17 14L22 9.5L15.5 8.5L12 2Z"/> </svg> </div> <div class="achievement-details"> <h2 class="achievement-title"> Dragon Slayer <span class="achievement-points">+500 XP</span> </h2> <p class="achievement-desc">Defeated the Elder Dragon in under 10 minutes without taking damage. Only 2% of players have achieved this!</p> <div class="progress-container"> <div class="progress-bar"></div> </div> <button class="share-button"> <svg viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"> <path d="M18 16.08c-.76 0-1.44.3-1.96.77L8.91 12.7c.05-.23.09-.46.09-.7s-.04-.47-.09-.7l7.05-4.11c.54.5 1.25.81 2.04.81 1.66 0 3-1.34 3-3s-1.34-3-3-3-3 1.34-3 3c0 .24.04.47.09.7L8.04 9.81C7.5 9.31 6.79 9 6 9c-1.66 0-3 1.34-3 3s1.34 3 3 3c.79 0 1.5-.31 2.04-.81l7.12 4.16c-.05.21-.08.43-.08.65 0 1.61 1.31 2.92 2.92 2.92s2.92-1.31 2.92-2.92c0-1.61-1.31-2.92-2.92-2.92zM18 4c.55 0 1 .45 1 1s-.45 1-1 1-1-.45-1-1 .45-1 1-1zM6 13c-.55 0-1-.45-1-1s.45-1 1-1 1 .45 1 1-.45 1-1 1zm12 7.02c-.55 0-1-.45-1-1s.45-1 1-1 1 .45 1 1-.45 1-1 1z"/> </svg> Share Achievement </button> </div> </div> </div> </div> <div class="particles"></div> <button class="replay-btn">Replay Animation</button> <script> document.addEventListener('DOMContentLoaded', function() { // Initialize the animation startAnimation(); // Add replay button functionality document.querySelector('.replay-btn').addEventListener('click', function() { resetAnimation(); setTimeout(startAnimation, 100); }); // Setup share button document.querySelector('.share-button').addEventListener('click', function() { this.innerHTML = '<svg viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path d="M9 16.17L4.83 12l-1.42 1.41L9 19 21 7l-1.41-1.41L9 16.17z"/></svg> Shared!'; setTimeout(() => { this.innerHTML = '<svg viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path d="M18 16.08c-.76 0-1.44.3-1.96.77L8.91 12.7c.05-.23.09-.46.09-.7s-.04-.47-.09-.7l7.05-4.11c.54.5 1.25.81 2.04.81 1.66 0 3-1.34 3-3s-1.34-3-3-3-3 1.34-3 3c0 .24.04.47.09.7L8.04 9.81C7.5 9.31 6.79 9 6 9c-1.66 0-3 1.34-3 3s1.34 3 3 3c.79 0 1.5-.31 2.04-.81l7.12 4.16c-.05.21-.08.43-.08.65 0 1.61 1.31 2.92 2.92 2.92s2.92-1.31 2.92-2.92c0-1.61-1.31-2.92-2.92-2.92zM18 4c.55 0 1 .45 1 1s-.45 1-1 1-1-.45-1-1 .45-1 1-1zM6 13c-.55 0-1-.45-1-1s.45-1 1-1 1 .45 1 1-.45 1-1 1zm12 7.02c-.55 0-1-.45-1-1s.45-1 1-1 1 .45 1 1-.45 1-1 1z"/></svg> Share Achievement'; }, 2000); // Simulate social sharing (in real app, this would open share dialogs) createParticles(10, event); }); }); function startAnimation() { // Animate the progress bar setTimeout(() => { document.querySelector('.progress-bar').style.width = '100%'; }, 500); // Create initial celebration particles createParticles(30); // Create more particles at intervals setTimeout(() => createParticles(10), 500); setTimeout(() => createParticles(10), 1000); } function resetAnimation() { // Reset container const container = document.querySelector('.achievement-container'); container.style.opacity = '0'; container.style.transform = 'translateY(50px)'; // Reset progress bar document.querySelector('.progress-bar').style.width = '0%'; // Clear all particles document.querySelector('.particles').innerHTML = ''; } function createParticles(count, event = null) { const particlesContainer = document.querySelector('.particles'); const banner = document.querySelector('.achievement-banner'); const bannerRect = banner.getBoundingClientRect(); for (let i = 0; i < count; i++) { const particle = document.createElement('div'); particle.classList.add('particle'); // Position particles let x, y; if (event) { // If triggered by click, create particles near click x = event.clientX - bannerRect.left; y = event.clientY - bannerRect.top; } else { // Random position around the banner x = Math.random() * bannerRect.width; y = Math.random() * bannerRect.height; } // Randomize size const size = 5 + Math.random() * 10; // Set styles particle.style.width = `${size}px`; particle.style.height = `${size}px`; particle.style.left = `${x}px`; particle.style.top = `${y}px`; // Random delay particle.style.animationDelay = `${Math.random() * 0.5}s`; // Random direction const angle = Math.random() * Math.PI * 2; const distance = 30 + Math.random() * 70; const translateX = Math.cos(angle) * distance; const translateY = Math.sin(angle) * distance; particle.style.animationName = 'none'; // Add to DOM particlesContainer.appendChild(particle); // Force reflow void particle.offsetWidth; // Custom animation particle.style.animationName = 'particle-fade'; // Remove after animation setTimeout(() => { if (particle.parentNode) { particle.parentNode.removeChild(particle); } }, 1500); } } </script> </body> </html>
<html> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Event Timeline Accessory</title> <style> :root { --primary: #2c3e50; --secondary: #3498db; --accent: #e74c3c; --light: #ecf0f1; --dark: #2c3e50; } * { margin: 0; padding: 0; box-sizing: border-box; font-family: 'Helvetica Neue', Arial, sans-serif; } body { background-color: var(--light); color: var(--dark); display: flex; flex-direction: column; align-items: center; justify-content: center; min-height: 100vh; padding: 20px; overflow-x: hidden; } .container { width: 100%; max-width: 700px; height: 700px; display: flex; flex-direction: column; position: relative; overflow: hidden; } .header { text-align: center; margin-bottom: 40px; position: relative; z-index: 10; } h1 { font-size: 2.5rem; color: var(--primary); margin-bottom: 10px; font-weight: 800; letter-spacing: -0.5px; } .sub-title { font-size: 1.1rem; color: var(--secondary); font-weight: 400; } .timeline-container { position: relative; margin-top: 30px; flex-grow: 1; overflow-y: auto; padding: 0 20px; } .ribbon-path { position: absolute; left: 50%; top: 0; height: 100%; width: 40px; transform: translateX(-50%); z-index: 1; } .ribbon { position: absolute; width: 8px; height: 100%; background: linear-gradient(to bottom, var(--secondary), var(--accent)); left: 50%; transform: translateX(-50%); border-radius: 4px; z-index: 1; box-shadow: 0 0 20px rgba(52, 152, 219, 0.3); } .events { position: relative; z-index: 2; padding-bottom: 50px; } .event { display: flex; margin-bottom: 60px; position: relative; opacity: 0; transform: translateY(30px); transition: opacity 0.5s ease, transform 0.5s ease; } .event.visible { opacity: 1; transform: translateY(0); } .event:nth-child(odd) { flex-direction: row; } .event:nth-child(even) { flex-direction: row-reverse; } .event-content { width: calc(50% - 30px); background: white; padding: 25px; border-radius: 12px; box-shadow: 0 10px 30px rgba(0, 0, 0, 0.08); position: relative; cursor: pointer; transition: transform 0.3s ease, box-shadow 0.3s ease; overflow: hidden; } .event-content:hover { transform: translateY(-5px); box-shadow: 0 15px 35px rgba(0, 0, 0, 0.12); } .event-content::before { content: ''; position: absolute; width: 20px; height: 20px; background: white; top: 50%; transform: translateY(-50%) rotate(45deg); z-index: -1; } .event:nth-child(odd) .event-content::before { right: -10px; } .event:nth-child(even) .event-content::before { left: -10px; } .event-date { position: absolute; width: 60px; height: 60px; background: var(--primary); border-radius: 50%; display: flex; align-items: center; justify-content: center; color: white; font-weight: 700; top: 50%; left: 50%; transform: translate(-50%, -50%); z-index: 3; box-shadow: 0 0 0 8px rgba(255, 255, 255, 0.7); transition: all 0.3s ease; } .event:hover .event-date { transform: translate(-50%, -50%) scale(1.1); background: var(--accent); } .event-dot { position: absolute; width: 16px; height: 16px; background: var(--secondary); border-radius: 50%; top: 50%; left: 50%; transform: translate(-50%, -50%); z-index: 2; box-shadow: 0 0 0 4px rgba(52, 152, 219, 0.3); transition: all 0.3s ease; } .event:hover .event-dot { background: var(--accent); box-shadow: 0 0 0 8px rgba(231, 76, 60, 0.3); } .spacer { width: 50%; } .event-title { font-size: 1.3rem; margin-bottom: 15px; color: var(--primary); font-weight: 700; position: relative; } .event-title::after { content: ''; position: absolute; bottom: -7px; left: 0; width: 50px; height: 3px; background: var(--secondary); transition: width 0.3s ease; } .event-content:hover .event-title::after { width: 100px; background: var(--accent); } .event-time { display: inline-block; padding: 4px 12px; background: var(--light); border-radius: 20px; font-size: 0.9rem; margin-bottom: 15px; color: var(--primary); font-weight: 600; } .event-description { font-size: 0.95rem; color: #555; line-height: 1.6; margin-bottom: 15px; max-height: 0; overflow: hidden; transition: max-height 0.5s ease, margin-bottom 0.5s ease; } .event-content.expanded .event-description { max-height: 300px; margin-bottom: 15px; } .event-location { display: flex; align-items: center; font-size: 0.9rem; color: #777; margin-top: 15px; } .location-icon { width: 16px; height: 16px; margin-right: 8px; fill: var(--secondary); } .event-link { display: inline-flex; align-items: center; margin-top: 15px; font-weight: 600; color: var(--secondary); text-decoration: none; transition: color 0.3s ease; opacity: 0; transform: translateY(10px); transition: opacity 0.3s ease, transform 0.3s ease, color 0.3s ease; } .event-content.expanded .event-link { opacity: 1; transform: translateY(0); } .event-link:hover { color: var(--accent); } .event-link svg { width: 16px; height: 16px; margin-left: 8px; transition: transform 0.3s ease; } .event-link:hover svg { transform: translateX(5px); } .pulse-animation { position: absolute; width: 60px; height: 60px; border-radius: 50%; background: rgba(52, 152, 219, 0.4); top: 50%; left: 50%; transform: translate(-50%, -50%) scale(0); animation: pulse 2s infinite; z-index: 1; } @keyframes pulse { 0% { transform: translate(-50%, -50%) scale(0); opacity: 1; } 100% { transform: translate(-50%, -50%) scale(1.5); opacity: 0; } } .current-time-indicator { position: absolute; width: 12px; height: 12px; border-radius: 50%; background: var(--accent); left: 50%; transform: translateX(-50%); z-index: 4; box-shadow: 0 0 0 4px rgba(231, 76, 60, 0.5); } .current-time-indicator::before { content: 'Now'; position: absolute; top: -25px; left: 50%; transform: translateX(-50%); background: var(--accent); color: white; padding: 3px 8px; border-radius: 4px; font-size: 0.8rem; font-weight: 700; white-space: nowrap; } /* Responsive styles */ @media (max-width: 600px) { .ribbon-path { left: 30px; } .event { flex-direction: row !important; margin-left: 30px; } .event-content { width: calc(100% - 60px); } .event:nth-child(odd) .event-content::before, .event:nth-child(even) .event-content::before { left: -10px; right: auto; } .event-date { left: 30px; transform: translateY(-50%); } .event:hover .event-date { transform: translateY(-50%) scale(1.1); } .event-dot { left: 30px; } .spacer { display: none; } .current-time-indicator { left: 30px; } } /* Animation for loading effect */ @keyframes shimmer { 0% { background-position: -468px 0; } 100% { background-position: 468px 0; } } .loading-shimmer { background: linear-gradient(to right, #f6f7f8 8%, #edeef1 18%, #f6f7f8 33%); background-size: 800px 104px; animation: shimmer 1.5s infinite linear; } /* Focus states for accessibility */ .event-content:focus { outline: 3px solid var(--secondary); } /* Smooth scroll behavior */ .timeline-container { scroll-behavior: smooth; } </style> </head> <body> <div class="container"> <div class="header"> <h1>TechFusion 2024</h1> <p class="sub-title">Where Innovation Meets Opportunity</p> </div> <div class="timeline-container"> <div class="ribbon-path"> <div class="ribbon"></div> <div class="current-time-indicator" id="currentTimeIndicator"></div> </div> <div class="events" id="events"> <!-- Events will be added dynamically via JavaScript --> </div> </div> </div> <script> document.addEventListener('DOMContentLoaded', function() { const events = [ { title: "Opening Keynote", date: "May 15", time: "9:00 AM - 10:30 AM", description: "Join our CEO Amelia Chen as she unveils groundbreaking announcements and our vision for the future of tech. This year's keynote will focus on sustainable innovation and how emerging technologies are shaping industries across the globe.", location: "Main Auditorium", isPast: true, link: "View Keynote Details" }, { title: "AI & Machine Learning Workshop", date: "May 15", time: "11:00 AM - 1:00 PM", description: "Hands-on workshop exploring practical applications of neural networks in business intelligence. Bring your laptop to participate in live coding exercises with our AI specialists. Limited capacity - first come, first served.", location: "Tech Lab B", isPast: true, link: "Reserve Your Spot" }, { title: "Networking Lunch", date: "May 15", time: "1:00 PM - 2:30 PM", description: "Connect with industry leaders, potential collaborators, and peers over a gourmet lunch. Special themed tables will be designated for specific industries and interests to facilitate more meaningful conversations.", location: "Garden Pavilion", isCurrent: true, link: "View Menu & Seating" }, { title: "Panel: The Future of Work", date: "May 15", time: "3:00 PM - 4:30 PM", description: "Expert panelists discuss how technology is transforming workplaces and what skills will be essential in the next decade. Featuring HR leaders from Fortune 500 companies and workforce development specialists.", location: "Conference Room C", isFuture: true, link: "Meet the Panelists" }, { title: "Innovation Showcase", date: "May 16", time: "10:00 AM - 4:00 PM", description: "Explore over 50 cutting-edge demos from startups and established tech companies. This year's showcase features a special focus on sustainable technology and accessibility innovations.", location: "Exhibition Hall", isFuture: true, link: "Browse Exhibitors" }, { title: "Closing Party & Awards", date: "May 16", time: "7:00 PM - 10:00 PM", description: "Celebrate with us as we recognize outstanding achievements and innovations from the conference. Live music, cocktails, and surprise performances will cap off an incredible event.", location: "Skyline Rooftop", isFuture: true, link: "RSVP" } ]; const eventsContainer = document.getElementById('events'); const currentTimeIndicator = document.getElementById('currentTimeIndicator'); // Calculate position for current time indicator const setCurrentTimePosition = () => { const currentEvent = events.find(event => event.isCurrent); if (currentEvent) { const index = events.indexOf(currentEvent); const totalEvents = events.length; const position = ((index + 0.5) / totalEvents) * 100; currentTimeIndicator.style.top = `${position}%`; } else { currentTimeIndicator.style.display = 'none'; } }; // Create event elements events.forEach((event, index) => { const eventElement = document.createElement('div'); eventElement.className = 'event'; eventElement.setAttribute('tabindex', '0'); let statusClass = event.isPast ? 'past' : event.isCurrent ? 'current' : 'future'; eventElement.innerHTML = ` <div class="spacer"></div> <div class="event-content" tabindex="0"> <div class="event-time">${event.time}</div> <h3 class="event-title">${event.title}</h3> <div class="event-description">${event.description}</div> <div class="event-location"> <svg class="location-icon" viewBox="0 0 24 24"> <path d="M12 2C8.13 2 5 5.13 5 9c0 5.25 7 13 7 13s7-7.75 7-13c0-3.87-3.13-7-7-7zm0 9.5c-1.38 0-2.5-1.12-2.5-2.5s1.12-2.5 2.5-2.5 2.5 1.12 2.5 2.5-1.12 2.5-2.5 2.5z"/> </svg> ${event.location} </div> <a href="#" class="event-link" onclick="event.preventDefault();"> ${event.link} <svg viewBox="0 0 24 24"> <path d="M5 12h14M13 5l7 7-7 7"/> </svg> </a> </div> <div class="event-date">${event.date}</div> <div class="event-dot"></div> ${event.isCurrent ? '<div class="pulse-animation"></div>' : ''} `; eventsContainer.appendChild(eventElement); // Add delayed animation for staggered appearance setTimeout(() => { eventElement.classList.add('visible'); }, index * 200); }); // Set the current time indicator position setCurrentTimePosition(); // Add click event listeners to expand/collapse event details document.querySelectorAll('.event-content').forEach(content => { content.addEventListener('click', () => { content.classList.toggle('expanded'); }); // Also toggle with Enter key for accessibility content.addEventListener('keydown', (e) => { if (e.key === 'Enter') { content.classList.toggle('expanded'); } }); }); // Check if elements are in viewport and animate them const observer = new IntersectionObserver((entries) => { entries.forEach(entry => { if (entry.isIntersecting) { entry.target.classList.add('visible'); } }); }, { threshold: 0.1 }); document.querySelectorAll('.event').forEach(event => { observer.observe(event); }); }); </script> </body> </html>
<html> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Educational Learning Platform Ribbon</title> <style> * { margin: 0; padding: 0; box-sizing: border-box; font-family: 'Nunito', sans-serif; } body { display: flex; justify-content: center; align-items: center; height: 100vh; background-color: #f5f7fa; overflow: hidden; } .container { width: 100%; max-width: 700px; height: 700px; padding: 20px; display: flex; flex-direction: column; justify-content: center; align-items: center; position: relative; } .progress-container { width: 100%; max-width: 600px; margin-bottom: 50px; position: relative; } .progress-bar { width: 100%; height: 12px; background-color: #e9ecef; border-radius: 10px; position: relative; overflow: hidden; box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1); } .progress { height: 100%; background: linear-gradient(45deg, #FF5F6D, #FFC371); width: 0%; border-radius: 10px; transition: width 0.8s cubic-bezier(0.65, 0, 0.35, 1); } .modules { display: flex; width: 100%; justify-content: space-between; margin-top: 10px; } .module { width: 30px; height: 30px; background-color: #fff; border-radius: 50%; display: flex; justify-content: center; align-items: center; color: #adb5bd; font-weight: bold; border: 2px solid #dee2e6; cursor: pointer; transition: all 0.3s ease; box-shadow: 0 2px 5px rgba(0, 0, 0, 0.1); z-index: 2; } .module.active { background: linear-gradient(45deg, #FF5F6D, #FFC371); color: white; border-color: transparent; transform: scale(1.1); box-shadow: 0 4px 10px rgba(255, 95, 109, 0.3); } .module.completed { background-color: #4CAF50; color: white; border-color: transparent; } .ribbon-container { position: relative; perspective: 800px; margin-bottom: 40px; transition: transform 0.5s ease; } .ribbon { width: 320px; height: 80px; background-color: #FF9A8B; position: relative; display: flex; justify-content: center; align-items: center; color: white; font-size: 24px; font-weight: bold; text-align: center; border-radius: 4px; box-shadow: 0 8px 16px rgba(0, 0, 0, 0.15); transform: rotate(-2deg); transform-style: preserve-3d; transition: all 0.5s ease; } .ribbon::before, .ribbon::after { content: ''; position: absolute; width: 40px; height: 100%; background-color: #FF9A8B; z-index: -1; } .ribbon::before { left: -20px; transform: skewX(-20deg); } .ribbon::after { right: -20px; transform: skewX(20deg); } .ribbon-shadow { position: absolute; width: 310px; height: 20px; background-color: rgba(0, 0, 0, 0.1); bottom: -25px; left: 5px; border-radius: 50%; filter: blur(10px); transform: rotate(-2deg); z-index: -2; } .ribbon-fold-left, .ribbon-fold-right { position: absolute; width: 20px; height: 20px; background-color: #E57373; bottom: -20px; transform: rotate(45deg); z-index: -1; } .ribbon-fold-left { left: -10px; } .ribbon-fold-right { right: -10px; } .ribbon-cutout { position: absolute; width: 100%; height: 100%; top: 0; left: 0; overflow: hidden; border-radius: 4px; z-index: 1; } .cutout { position: absolute; background-color: white; border-radius: 50%; opacity: 0.2; } .content { max-width: 500px; background-color: white; padding: 30px; border-radius: 12px; box-shadow: 0 10px 30px rgba(0, 0, 0, 0.1); position: relative; overflow: hidden; transition: all 0.3s ease; } .content:hover { transform: translateY(-5px); box-shadow: 0 15px 35px rgba(0, 0, 0, 0.15); } .content h2 { color: #2D3748; margin-bottom: 15px; position: relative; display: inline-block; } .content h2::after { content: ''; position: absolute; width: 50%; height: 4px; background: linear-gradient(45deg, #FF5F6D, #FFC371); bottom: -8px; left: 0; border-radius: 2px; } .content p { color: #4A5568; line-height: 1.6; margin-bottom: 20px; } .btn { background: linear-gradient(45deg, #FF5F6D, #FFC371); color: white; border: none; padding: 12px 25px; border-radius: 50px; font-weight: bold; cursor: pointer; transition: all 0.3s ease; box-shadow: 0 4px 10px rgba(255, 95, 109, 0.3); position: relative; overflow: hidden; } .btn:hover { transform: translateY(-3px); box-shadow: 0 6px 15px rgba(255, 95, 109, 0.4); } .btn:active { transform: translateY(0); box-shadow: 0 2px 5px rgba(255, 95, 109, 0.4); } .btn::after { content: ''; position: absolute; width: 100%; height: 100%; top: 0; left: -100%; background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.2), transparent); transition: 0.5s; } .btn:hover::after { left: 100%; } .confetti { position: absolute; width: 10px; height: 10px; background-color: transparent; top: -50px; animation: fall linear forwards; } @keyframes fall { to { transform: translateY(700px) rotate(360deg); opacity: 0; } } .modules-info { width: 100%; display: flex; justify-content: space-between; margin-top: 5px; font-size: 12px; color: #6c757d; } .module-tooltip { position: absolute; background-color: #343a40; color: white; padding: 8px 12px; border-radius: 5px; font-size: 12px; opacity: 0; transition: opacity 0.3s; pointer-events: none; transform: translateY(-30px); z-index: 10; white-space: nowrap; } .module-tooltip::after { content: ''; position: absolute; top: 100%; left: 50%; margin-left: -5px; border-width: 5px; border-style: solid; border-color: #343a40 transparent transparent transparent; } @media (max-width: 700px) { .ribbon { width: 280px; font-size: 20px; } .ribbon-shadow { width: 270px; } .progress-container { max-width: 100%; } .content { padding: 20px; } .btn { padding: 10px 20px; } } @media (max-width: 500px) { .ribbon { width: 240px; height: 60px; font-size: 18px; } .ribbon-shadow { width: 230px; } .modules { margin-top: 5px; } .module { width: 25px; height: 25px; font-size: 12px; } .content h2 { font-size: 20px; } .content p { font-size: 14px; } } </style> </head> <body> <div class="container"> <div class="ribbon-container"> <div class="ribbon"> <div class="ribbon-cutout" id="ribbonCutout"></div> <span id="ribbonText">Module 1 Complete!</span> </div> <div class="ribbon-shadow"></div> <div class="ribbon-fold-left"></div> <div class="ribbon-fold-right"></div> </div> <div class="progress-container"> <div class="progress-bar"> <div class="progress" id="progress"></div> </div> <div class="modules"> <div class="module active" data-module="1">1</div> <div class="module" data-module="2">2</div> <div class="module" data-module="3">3</div> <div class="module" data-module="4">4</div> <div class="module" data-module="5">5</div> </div> <div class="modules-info"> <span>Fundamentals</span> <span>Advanced</span> </div> </div> <div class="content"> <h2>Introduction to Photosynthesis</h2> <p>You've just mastered the basics of how plants convert sunlight into energy! Explore the importance of chlorophyll, light absorption, and the chemical processes that make our planet green.</p> <p>Ready to learn about cellular respiration in Module 2?</p> <button class="btn" id="nextModuleBtn">Continue to Next Module</button> </div> </div> <script> document.addEventListener('DOMContentLoaded', function() { const progress = document.getElementById('progress'); const modules = document.querySelectorAll('.module'); const nextModuleBtn = document.getElementById('nextModuleBtn'); const ribbonText = document.getElementById('ribbonText'); const ribbonCutout = document.getElementById('ribbonCutout'); const ribbon = document.querySelector('.ribbon'); const ribbonContainer = document.querySelector('.ribbon-container'); const content = document.querySelector('.content'); let currentModule = 1; let progressValue = 20; // Add cutout circles to ribbon for paper-cutout effect function createCutouts() { const colors = ['#FF9A8B', '#FFB480', '#FFC797', '#FFCDA5', '#FFD3A5']; for (let i = 0; i < 20; i++) { const size = Math.random() * 15 + 5; const cutout = document.createElement('div'); cutout.classList.add('cutout'); cutout.style.width = `${size}px`; cutout.style.height = `${size}px`; cutout.style.top = `${Math.random() * 100}%`; cutout.style.left = `${Math.random() * 100}%`; cutout.style.backgroundColor = colors[Math.floor(Math.random() * colors.length)]; ribbonCutout.appendChild(cutout); } } // Update module content based on current module function updateModuleContent() { const moduleContent = { 1: { title: "Introduction to Photosynthesis", description: "You've just mastered the basics of how plants convert sunlight into energy! Explore the importance of chlorophyll, light absorption, and the chemical processes that make our planet green.", nextText: "Ready to learn about cellular respiration in Module 2?" }, 2: { title: "Cellular Respiration", description: "Great progress! You've now understood how cells convert nutrients into energy. Explore the intricacies of glycolysis, the Krebs cycle, and the electron transport chain.", nextText: "Ready to explore the fascinating world of DNA in Module 3?" }, 3: { title: "DNA Structure & Replication", description: "Amazing work! You've decoded the blueprint of life itself. From nucleotides to the double helix, you now understand how genetic information is stored and copied.", nextText: "Ready to learn about protein synthesis in Module 4?" }, 4: { title: "Protein Synthesis", description: "You're on a roll! You've mastered how genetic information flows from DNA to RNA to protein. Transcription, translation, and the genetic code have no more secrets for you.", nextText: "One last module to complete your biology journey!" }, 5: { title: "Genetics & Inheritance", description: "Congratulations! You've completed the entire course and now understand how traits are passed from one generation to the next. From Mendel's peas to modern genetics, you're now an expert!", nextText: "You've completed all modules - well done!" } }; content.querySelector('h2').textContent = moduleContent[currentModule].title; const paragraphs = content.querySelectorAll('p'); paragraphs[0].textContent = moduleContent[currentModule].description; paragraphs[1].textContent = moduleContent[currentModule].nextText; if (currentModule === 5) { nextModuleBtn.textContent = "Review Course"; createConfetti(); } else { nextModuleBtn.textContent = "Continue to Next Module"; } // Update ribbon text ribbonText.textContent = `Module ${currentModule} Complete!`; // Animate ribbon ribbonContainer.style.transform = 'scale(1.1)'; setTimeout(() => { ribbonContainer.style.transform = 'scale(1)'; }, 500); } // Create confetti effect for celebration function createConfetti() { const colors = ['#FF5F6D', '#FFC371', '#38ef7d', '#11998e', '#FF9A8B']; for (let i = 0; i < 100; i++) { const confetti = document.createElement('div'); confetti.classList.add('confetti'); confetti.style.left = `${Math.random() * 100}%`; confetti.style.backgroundColor = colors[Math.floor(Math.random() * colors.length)]; confetti.style.width = `${Math.random() * 10 + 5}px`; confetti.style.height = `${Math.random() * 10 + 5}px`; confetti.style.animationDuration = `${Math.random() * 3 + 2}s`; document.body.appendChild(confetti); setTimeout(() => { confetti.remove(); }, 5000); } } // Update progress bar and module indicators function updateProgress() { progress.style.width = `${progressValue}%`; modules.forEach((module, index) => { const moduleNum = index + 1; if (moduleNum < currentModule) { module.classList.add('completed'); module.classList.remove('active'); } else if (moduleNum === currentModule) { module.classList.add('active'); module.classList.remove('completed'); } else { module.classList.remove('active'); module.classList.remove('completed'); } }); } // Add event listeners for module selection modules.forEach(module => { module.addEventListener('click', function() { const moduleNum = parseInt(this.getAttribute('data-module')); if (moduleNum <= Math.max(currentModule, 1)) { currentModule = moduleNum; progressValue = currentModule * 20; updateProgress(); updateModuleContent(); } }); // Add tooltips module.addEventListener('mouseenter', function() { const moduleNum = parseInt(this.getAttribute('data-module')); const topics = [ "Photosynthesis", "Cellular Respiration", "DNA Structure", "Protein Synthesis", "Genetics" ]; const tooltip = document.createElement('div'); tooltip.classList.add('module-tooltip'); tooltip.textContent = topics[moduleNum-1]; const rect = this.getBoundingClientRect(); tooltip.style.left = `${rect.left + rect.width/2 - 60}px`; tooltip.style.top = `${rect.top - 40}px`; document.body.appendChild(tooltip); setTimeout(() => tooltip.style.opacity = '1', 10); this.addEventListener('mouseleave', function handler() { tooltip.style.opacity = '0'; setTimeout(() => tooltip.remove(), 300); this.removeEventListener('mouseleave', handler); }); }); }); // Add 3D hover effect to ribbon ribbonContainer.addEventListener('mousemove', function(e) { const rect = this.getBoundingClientRect(); const x = e.clientX - rect.left; const y = e.clientY - rect.top; const centerX = rect.width / 2; const centerY = rect.height / 2; const angleX = (y - centerY) / 25; const angleY = (centerX - x) / 25; ribbon.style.transform = `rotate(-2deg) rotateX(${angleX}deg) rotateY(${angleY}deg)`; }); ribbonContainer.addEventListener('mouseleave', function() { ribbon.style.transform = 'rotate(-2deg) rotateX(0) rotateY(0)'; }); // Next module button handler nextModuleBtn.addEventListener('click', function() { if (currentModule < 5) { currentModule++; progressValue = currentModule * 20; updateProgress(); updateModuleContent(); // Add animation to content content.style.transform = 'translateY(10px) scale(0.98)'; content.style.opacity = '0.8'; setTimeout(() => { content.style.transform = 'translateY(0) scale(1)'; content.style.opacity = '1'; }, 300); } else if (currentModule === 5) { // Reset to first module for demo purposes currentModule = 1; progressValue = currentModule * 20; updateProgress(); updateModuleContent(); } }); // Initialize progress.style.width = `${progressValue}%`; createCutouts(); // Add random rotation to ribbon for playful effect ribbon.style.transform = `rotate(${Math.random() * 4 - 2}deg)`; // Initial 3D animation setTimeout(() => { ribbon.style.transform = 'rotate(-2deg) rotateX(5deg) rotateY(5deg)'; setTimeout(() => { ribbon.style.transform = 'rotate(-2deg) rotateX(0) rotateY(0)'; }, 1000); }, 500); }); </script> </body> </html>
<html> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Corporate Intranet Badge</title> <style> * { margin: 0; padding: 0; box-sizing: border-box; font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; } body { display: flex; flex-direction: column; align-items: center; justify-content: center; min-height: 100vh; background-color: #f5f6fa; padding: 20px; } .badge-container { width: 100%; max-width: 650px; background-color: white; border-radius: 12px; box-shadow: 0 6px 20px rgba(0, 0, 50, 0.08); overflow: hidden; position: relative; } .ribbon-header { position: relative; height: 60px; background: linear-gradient(135deg, #2c3e50, #34495e); display: flex; align-items: center; justify-content: space-between; padding: 0 20px; color: white; overflow: hidden; } .ribbon-header::before { content: ''; position: absolute; top: 0; left: 0; width: 100%; height: 100%; background-image: url("data:image/svg+xml,%3Csvg width='100' height='100' viewBox='0 0 100 100' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M11 18c3.866 0 7-3.134 7-7s-3.134-7-7-7-7 3.134-7 7 3.134 7 7 7zm48 25c3.866 0 7-3.134 7-7s-3.134-7-7-7-7 3.134-7 7 3.134 7 7 7zm-43-7c1.657 0 3-1.343 3-3s-1.343-3-3-3-3 1.343-3 3 1.343 3 3 3zm63 31c1.657 0 3-1.343 3-3s-1.343-3-3-3-3 1.343-3 3 1.343 3 3 3zM34 90c1.657 0 3-1.343 3-3s-1.343-3-3-3-3 1.343-3 3 1.343 3 3 3zm56-76c1.657 0 3-1.343 3-3s-1.343-3-3-3-3 1.343-3 3 1.343 3 3 3zM12 86c2.21 0 4-1.79 4-4s-1.79-4-4-4-4 1.79-4 4 1.79 4 4 4zm28-65c2.21 0 4-1.79 4-4s-1.79-4-4-4-4 1.79-4 4 1.79 4 4 4zm23-11c2.76 0 5-2.24 5-5s-2.24-5-5-5-5 2.24-5 5 2.24 5 5 5zm-6 60c2.21 0 4-1.79 4-4s-1.79-4-4-4-4 1.79-4 4 1.79 4 4 4zm29 22c2.76 0 5-2.24 5-5s-2.24-5-5-5-5 2.24-5 5 2.24 5 5 5zM32 63c2.76 0 5-2.24 5-5s-2.24-5-5-5-5 2.24-5 5 2.24 5 5 5zm57-13c2.76 0 5-2.24 5-5s-2.24-5-5-5-5 2.24-5 5 2.24 5 5 5zm-9-21c1.105 0 2-.895 2-2s-.895-2-2-2-2 .895-2 2 .895 2 2 2zM60 91c1.105 0 2-.895 2-2s-.895-2-2-2-2 .895-2 2 .895 2 2 2zM35 41c1.105 0 2-.895 2-2s-.895-2-2-2-2 .895-2 2 .895 2 2 2zM12 60c1.105 0 2-.895 2-2s-.895-2-2-2-2 .895-2 2 .895 2 2 2z' fill='%23ffffff' fill-opacity='0.05' fill-rule='evenodd'/%3E%3C/svg%3E"); opacity: 0.5; } .ribbon-text { font-size: 18px; font-weight: 600; letter-spacing: 0.5px; position: relative; z-index: 1; } .notification-count { background-color: #e74c3c; color: white; border-radius: 12px; padding: 2px 10px; font-size: 14px; font-weight: bold; position: relative; transition: all 0.3s ease; transform-origin: center; box-shadow: 0 2px 5px rgba(0, 0, 0, 0.2); z-index: 1; } .notification-count.pulse { animation: pulse 1.5s infinite; } @keyframes pulse { 0% { transform: scale(1); box-shadow: 0 2px 5px rgba(0, 0, 0, 0.2); } 50% { transform: scale(1.1); box-shadow: 0 5px 15px rgba(0, 0, 0, 0.3); } 100% { transform: scale(1); box-shadow: 0 2px 5px rgba(0, 0, 0, 0.2); } } .badge-content { padding: 20px; } .status-filters { display: flex; margin-bottom: 20px; border-bottom: 1px solid #eaeaea; padding-bottom: 15px; } .status-filter { margin-right: 15px; padding: 8px 15px; border-radius: 20px; font-size: 14px; cursor: pointer; transition: all 0.3s ease; background-color: #f0f2f5; color: #5a6474; border: none; outline: none; } .status-filter:hover { background-color: #e1e5eb; } .status-filter.active { background-color: #2c3e50; color: white; box-shadow: 0 3px 8px rgba(44, 62, 80, 0.3); } .status-updates { display: flex; flex-direction: column; gap: 15px; max-height: 350px; overflow-y: auto; padding-right: 10px; } .status-updates::-webkit-scrollbar { width: 6px; } .status-updates::-webkit-scrollbar-track { background: #f1f1f1; border-radius: 10px; } .status-updates::-webkit-scrollbar-thumb { background: #c1c9d6; border-radius: 10px; } .status-updates::-webkit-scrollbar-thumb:hover { background: #95a5a6; } .status-item { padding: 15px; border-radius: 8px; background-color: #f8f9fa; border-left: 4px solid transparent; display: flex; flex-direction: column; transition: all 0.3s ease; position: relative; transform: translateX(0); opacity: 1; } .status-item:hover { background-color: #f0f2f5; transform: translateX(5px); box-shadow: 0 3px 10px rgba(0, 0, 0, 0.05); } .status-item.critical { border-left-color: #e74c3c; } .status-item.warning { border-left-color: #f39c12; } .status-item.info { border-left-color: #3498db; } .status-item.success { border-left-color: #27ae60; } .status-header { display: flex; justify-content: space-between; align-items: center; margin-bottom: 8px; } .status-title { font-weight: 600; color: #2c3e50; font-size: 15px; } .status-badge { padding: 3px 8px; border-radius: 4px; font-size: 12px; font-weight: 600; text-transform: uppercase; } .status-badge.critical { background-color: rgba(231, 76, 60, 0.15); color: #c0392b; } .status-badge.warning { background-color: rgba(243, 156, 18, 0.15); color: #d35400; } .status-badge.info { background-color: rgba(52, 152, 219, 0.15); color: #2980b9; } .status-badge.success { background-color: rgba(39, 174, 96, 0.15); color: #27ae60; } .status-message { color: #5a6474; font-size: 14px; line-height: 1.5; } .status-footer { display: flex; justify-content: space-between; align-items: center; margin-top: 10px; font-size: 12px; color: #95a5a6; } .status-time { display: flex; align-items: center; } .status-time svg { margin-right: 4px; } .status-author { display: flex; align-items: center; } .status-author svg { margin-right: 4px; } .dismiss-btn { position: absolute; top: 10px; right: 10px; background: none; border: none; color: #bdc3c7; cursor: pointer; font-size: 12px; padding: 3px; border-radius: 50%; width: 18px; height: 18px; display: flex; align-items: center; justify-content: center; opacity: 0; transition: all 0.2s ease; } .status-item:hover .dismiss-btn { opacity: 1; } .dismiss-btn:hover { background-color: rgba(0, 0, 0, 0.05); color: #7f8c8d; } .status-actions { display: flex; gap: 10px; margin-top: 10px; } .action-btn { padding: 6px 12px; border-radius: 4px; font-size: 12px; border: none; cursor: pointer; transition: all 0.2s ease; display: flex; align-items: center; } .action-btn svg { margin-right: 5px; } .action-btn.primary { background-color: #34495e; color: white; } .action-btn.primary:hover { background-color: #2c3e50; } .action-btn.secondary { background-color: #f5f6fa; color: #7f8c8d; } .action-btn.secondary:hover { background-color: #ecf0f1; } .empty-state { display: none; flex-direction: column; align-items: center; justify-content: center; padding: 40px 20px; text-align: center; } .empty-state svg { width: 80px; height: 80px; color: #bdc3c7; margin-bottom: 15px; } .empty-state-title { font-size: 16px; font-weight: 600; color: #2c3e50; margin-bottom: 8px; } .empty-state-message { font-size: 14px; color: #7f8c8d; max-width: 300px; line-height: 1.5; } .add-status { position: absolute; bottom: 20px; right: 20px; width: 50px; height: 50px; border-radius: 50%; background: linear-gradient(135deg, #3498db, #2980b9); color: white; display: flex; align-items: center; justify-content: center; cursor: pointer; box-shadow: 0 4px 10px rgba(52, 152, 219, 0.4); transition: all 0.3s ease; border: none; } .add-status:hover { transform: scale(1.05); box-shadow: 0 6px 15px rgba(52, 152, 219, 0.5); } .add-status:active { transform: scale(0.95); } @media (max-width: 600px) { .ribbon-header { height: 50px; padding: 0 15px; } .ribbon-text { font-size: 16px; } .status-filters { overflow-x: auto; padding-bottom: 10px; margin-bottom: 15px; } .status-filter { flex-shrink: 0; font-size: 12px; padding: 6px 12px; } .status-updates { max-height: 300px; } .status-item { padding: 12px; } .status-title { font-size: 14px; } .status-message { font-size: 13px; } .add-status { width: 45px; height: 45px; bottom: 15px; right: 15px; } } /* Animation for new items */ @keyframes slideIn { from { opacity: 0; transform: translateY(20px); } to { opacity: 1; transform: translateY(0); } } .slide-in { animation: slideIn 0.4s ease-out forwards; } /* Fade out animation for dismissed items */ @keyframes fadeOut { from { opacity: 1; transform: translateX(0); } to { opacity: 0; transform: translateX(20px); } } .fade-out { animation: fadeOut 0.3s ease-out forwards; } </style> </head> <body> <div class="badge-container"> <div class="ribbon-header"> <div class="ribbon-text">Service Status Updates</div> <div class="notification-count pulse">5</div> </div> <div class="badge-content"> <div class="status-filters"> <button class="status-filter active" data-filter="all">All Updates</button> <button class="status-filter" data-filter="critical">Critical</button> <button class="status-filter" data-filter="warning">Warning</button> <button class="status-filter" data-filter="info">Information</button> <button class="status-filter" data-filter="success">Resolved</button> </div> <div class="status-updates"> <div class="status-item critical slide-in" data-category="critical"> <button class="dismiss-btn"> <svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" fill="currentColor" viewBox="0 0 16 16"> <path d="M4.646 4.646a.5.5 0 0 1 .708 0L8 7.293l2.646-2.647a.5.5 0 0 1 .708.708L8.707 8l2.647 2.646a.5.5 0 0 1-.708.708L8 8.707l-2.646 2.647a.5.5 0 0 1-.708-.708L7.293 8 4.646 5.354a.5.5 0 0 1 0-.708z"/> </svg> </button> <div class="status-header"> <div class="status-title">ERP System Outage</div> <div class="status-badge critical">Critical</div> </div> <div class="status-message">Database connectivity issues affecting all financial modules. IT team is investigating the root cause. Expected resolution within 60 minutes.</div> <div class="status-actions"> <button class="action-btn primary"> <svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" fill="currentColor" viewBox="0 0 16 16"> <path d="M8 15A7 7 0 1 1 8 1a7 7 0 0 1 0 14zm0 1A8 8 0 1 0 8 0a8 8 0 0 0 0 16z"/> <path d="m8.93 6.588-2.29.287-.082.38.45.083c.294.07.352.176.288.469l-.738 3.468c-.194.897.105 1.319.808 1.319.545 0 1.178-.252 1.465-.598l.088-.416c-.2.176-.492.246-.686.246-.275 0-.375-.193-.304-.533L8.93 6.588zM9 4.5a1 1 0 1 1-2 0 1 1 0 0 1 2 0z"/> </svg> View Details </button> <button class="action-btn secondary"> <svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" fill="currentColor" viewBox="0 0 16 16"> <path d="M.05 3.555A2 2 0 0 1 2 2h12a2 2 0 0 1 1.95 1.555L8 8.414.05 3.555ZM0 4.697v7.104l5.803-3.558L0 4.697ZM6.761 8.83l-6.57 4.027A2 2 0 0 0 2 14h12a2 2 0 0 0 1.808-1.144l-6.57-4.027L8 9.586l-1.239-.757Zm3.436-.586L16 11.801V4.697l-5.803 3.546Z"/> </svg> Notify Team </button> </div> <div class="status-footer"> <div class="status-time"> <svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" fill="currentColor" viewBox="0 0 16 16"> <path d="M8 3.5a.5.5 0 0 0-1 0V9a.5.5 0 0 0 .252.434l3.5 2a.5.5 0 0 0 .496-.868L8 8.71V3.5z"/> <path d="M8 16A8 8 0 1 0 8 0a8 8 0 0 0 0 16zm7-8A7 7 0 1 1 1 8a7 7 0 0 1 14 0z"/> </svg> 10 minutes ago </div> <div class="status-author"> <svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" fill="currentColor" viewBox="0 0 16 16"> <path d="M8 8a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm2-3a2 2 0 1 1-4 0 2 2 0 0 1 4 0zm4 8c0 1-1 1-1 1H3s-1 0-1-1 1-4 6-4 6 3 6 4zm-1-.004c-.001-.246-.154-.986-.832-1.664C11.516 10.68 10.289 10 8 10c-2.29 0-3.516.68-4.168 1.332-.678.678-.83 1.418-.832 1.664h10z"/> </svg> IT Operations </div> </div> </div> <div class="status-item warning slide-in" data-category="warning"> <button class="dismiss-btn"> <svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" fill="currentColor" viewBox="0 0 16 16"> <path d="M4.646 4.646a.5.5 0 0 1 .708 0L8 7.293l2.646-2.647a.5.5 0 0 1 .708.708L8.707 8l2.647 2.646a.5.5 0 0 1-.708.708L8 8.707l-2.646 2.647a.5.5 0 0 1-.708-.708L7.293 8 4.646 5.354a.5.5 0 0 1 0-.708z"/> </svg> </button> <div class="status-header"> <div class="status-title">CRM Performance Degradation</div> <div class="status-badge warning">Warning</div> </div> <div class="status-message">Customer relationship management system experiencing elevated response times. Engineering team has implemented temporary capacity increase while investigating.</div> <div class="status-footer"> <div class="status-time"> <svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" fill="currentColor" viewBox="0 0 16 16"> <path d="M8 3.5a.5.5 0 0 0-1 0V9a.5.5 0 0 0 .252.434l3.5 2a.5.5 0 0 0 .496-.868L8 8.71V3.5z"/> <path d="M8 16A8 8 0 1 0 8 0a8 8 0 0 0 0 16zm7-8A7 7 0 1 1 1 8a7 7 0 0 1 14 0z"/> </svg> 1 hour ago </div> <div class="status-author"> <svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" fill="currentColor" viewBox="0 0 16 16"> <path d="M8 8a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm2-3a2 2 0 1 1-4 0 2 2 0 0 1 4 0zm4 8c0 1-1 1-1 1H3s-1 0-1-1 1-4 6-4 6 3 6 4zm-1-.004c-.001-.246-.154-.986-.832-1.664C11.516 10.68 10.289 10 8 10c-2.29 0-3.516.68-4.168 1.332-.678.678-.83 1.418-.832 1.664h10z"/> </svg> Systems Engineering </div> </div> </div> <div class="status-item info slide-in" data-category="info"> <button class="dismiss-btn"> <svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" fill="currentColor" viewBox="0 0 16 16"> <path d="M4.646 4.646a.5.5 0 0 1 .708 0L8 7.293l2.646-2.647a.5.5 0 0 1 .708.708L8.707 8l2.647 2.646a.5.5 0 0 1-.708.708L8 8.707l-2.646 2.647a.5.5 0 0 1-.708-.708L7.293 8 4.646 5.354a.5.5 0 0 1 0-.708z"/> </svg> </button> <div class="status-header"> <div class="status-title">Email Security Update Deployment</div> <div class="status-badge info">Information</div> </div> <div class="status-message">Enhanced security measures being implemented for all corporate email accounts. No downtime expected, but increased authentication requirements will be activated starting at 3 PM today.</div> <div class="status-actions"> <button class="action-btn secondary"> <svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" fill="currentColor" viewBox="0 0 16 16"> <path d="M8 15A7 7 0 1 1 8 1a7 7 0 0 1 0 14zm0 1A8 8 0 1 0 8 0a8 8 0 0 0 0 16z"/> <path d="m8.93 6.588-2.29.287-.082.38.45.083c.294.07.352.176.288.469l-.738 3.468c-.194.897.105 1.319.808 1.319.545 0 1.178-.252 1.465-.598l.088-.416c-.2.176-.492.246-.686.246-.275 0-.375-.193-.304-.533L8.93 6.588zM9 4.5a1 1 0 1 1-2 0 1 1 0 0 1 2 0z"/> </svg> Learn More </button> </div> <div class="status-footer"> <div class="status-time"> <svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" fill="currentColor" viewBox="0 0 16 16"> <path d="M8 3.5a.5.5 0 0 0-1 0V9a.5.5 0 0 0 .252.434l3.5 2a.5.5 0 0 0 .496-.868L8 8.71V3.5z"/> <path d="M8 16A8 8 0 1 0 8 0a8 8 0 0 0 0 16zm7-8A7 7 0 1 1 1 8a7 7 0 0 1 14 0z"/> </svg> 3 hours ago </div> <div class="status-author"> <svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" fill="currentColor" viewBox="0 0 16 16"> <path d="M8 8a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm2-3a2 2 0 1 1-4 0 2 2 0 0 1 4 0zm4 8c0 1-1 1-1 1H3s-1 0-1-1 1-4 6-4 6 3 6 4zm-1-.004c-.001-.246-.154-.986-.832-1.664C11.516 10.68 10.289 10 8 10c-2.29 0-3.516.68-4.168 1.332-.678.678-.83 1.418-.832 1.664h10z"/> </svg> Security Team </div> </div> </div> <div class="status-item warning slide-in" data-category="warning"> <button class="dismiss-btn"> <svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" fill="currentColor" viewBox="0 0 16 16"> <path d="M4.646 4.646a.5.5 0 0 1 .708 0L8 7.293l2.646-2.647a.5.5 0 0 1 .708.708L8.707 8l2.647 2.646a.5.5 0 0 1-.708.708L8 8.707l-2.646 2.647a.5.5 0 0 1-.708-.708L7.293 8 4.646 5.354a.5.5 0 0 1 0-.708z"/> </svg> </button> <div class="status-header"> <div class="status-title">VPN Capacity Reaching Limits</div> <div class="status-badge warning">Warning</div> </div> <div class="status-message">Remote access VPN connections approaching 85% capacity. Non-essential remote work should be postponed during peak hours (9-11 AM). Network team is activating additional VPN endpoints.</div> <div class="status-footer"> <div class="status-time"> <svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" fill="currentColor" viewBox="0 0 16 16"> <path d="M8 3.5a.5.5 0 0 0-1 0V9a.5.5 0 0 0 .252.434l3.5 2a.5.5 0 0 0 .496-.868L8 8.71V3.5z"/> <path d="M8 16A8 8 0 1 0 8 0a8 8 0 0 0 0 16zm7-8A7 7 0 1 1 1 8a7 7 0 0 1 14 0z"/> </svg> 5 hours ago </div> <div class="status-author"> <svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" fill="currentColor" viewBox="0 0 16 16"> <path d="M8 8a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm2-3a2 2 0 1 1-4 0 2 2 0 0 1 4 0zm4 8c0 1-1 1-1 1H3s-1 0-1-1 1-4 6-4 6 3 6 4zm-1-.004c-.001-.246-.154-.986-.832-1.664C11.516 10.68 10.289 10 8 10c-2.29 0-3.516.68-4.168 1.332-.678.678-.83 1.418-.832 1.664h10z"/> </svg> Network Infrastructure </div> </div> </div> <div class="status-item success slide-in" data-category="success"> <button class="dismiss-btn"> <svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" fill="currentColor" viewBox="0 0 16 16"> <path d="M4.646 4.646a.5.5 0 0 1 .708 0L8 7.293l2.646-2.647a.5.5 0 0 1 .708.708L8.707 8l2.647 2.646a.5.5 0 0 1-.708.708L8 8.707l-2.646 2.647a.5.5 0 0 1-.708-.708L7.293 8 4.646 5.354a.5.5 0 0 1 0-.708z"/> </svg> </button> <div class="status-header"> <div class="status-title">HR Portal Maintenance Completed</div> <div class="status-badge success">Resolved</div> </div> <div class="status-message">Scheduled maintenance of the employee HR portal has been successfully completed. New benefits enrollment features and improved performance are now available to all staff.</div> <div class="status-footer"> <div class="status-time"> <svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" fill="currentColor" viewBox="0 0 16 16"> <path d="M8 3.5a.5.5 0 0 0-1 0V9a.5.5 0 0 0 .252.434l3.5 2a.5.5 0 0 0 .496-.868L8 8.71V3.5z"/> <path d="M8 16A8 8 0 1 0 8 0a8 8 0 0 0 0 16zm7-8A7 7 0 1 1 1 8a7 7 0 0 1 14 0z"/> </svg> 12 hours ago </div> <div class="status-author"> <svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" fill="currentColor" viewBox="0 0 16 16"> <path d="M8 8a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm2-3a2 2 0 1 1-4 0 2 2 0 0 1 4 0zm4 8c0 1-1 1-1 1H3s-1 0-1-1 1-4 6-4 6 3 6 4zm-1-.004c-.001-.246-.154-.986-.832-1.664C11.516 10.68 10.289 10 8 10c-2.29 0-3.516.68-4.168 1.332-.678.678-.83 1.418-.832 1.664h10z"/> </svg> HR System Admin </div> </div> </div> </div> <div class="empty-state"> <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" viewBox="0 0 16 16"> <path d="M2.5 8a5.5 5.5 0 0 1 8.25-4.764.5.5 0 0 0 .5-.866A6.5 6.5 0 1 0 14.5 8a.5.5 0 0 0-1 0 5.5 5.5 0 1 1-11 0z"/> <path d="M15.354 3.354a.5.5 0 0 0-.708-.708L8 9.293 5.354 6.646a.5.5 0 1 0-.708.708l3 3a.5.5 0 0 0 .708 0l7-7z"/> </svg> <div class="empty-state-title">All caught up!</div> <div class="empty-state-message">No status updates
<html> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Financial Analytics Ribbon</title> <style> * { margin: 0; padding: 0; box-sizing: border-box; font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; } body { width: 100%; height: 100vh; display: flex; justify-content: center; align-items: center; background-color: #f0f2f5; overflow: hidden; } .container { width: 700px; height: 700px; display: flex; flex-direction: column; justify-content: center; align-items: center; padding: 20px; position: relative; overflow: hidden; } .ribbon-container { width: 100%; height: 65%; position: relative; display: flex; justify-content: center; align-items: center; background-color: #fff; border-radius: 12px; box-shadow: 0 10px 30px rgba(0, 0, 0, 0.08); overflow: hidden; transition: all 0.3s ease; } .ribbon-container:hover { box-shadow: 0 15px 40px rgba(0, 0, 0, 0.15); transform: translateY(-5px); } .ribbon { width: 100%; height: 70%; display: flex; position: relative; } .data-point { flex: 1; height: 100%; position: relative; transition: all 0.4s cubic-bezier(0.175, 0.885, 0.32, 1.275); cursor: pointer; overflow: hidden; } .segment { height: 0%; width: 100%; position: absolute; bottom: 0; transition: height 1.2s cubic-bezier(0.19, 1, 0.22, 1); } .data-point:hover { transform: scaleY(1.05); } .data-point:hover .tooltip { opacity: 1; transform: translateY(0); } .tooltip { position: absolute; top: -60px; left: 50%; transform: translateX(-50%) translateY(10px); background-color: #2d3748; color: white; padding: 8px 12px; border-radius: 6px; font-size: 12px; opacity: 0; pointer-events: none; transition: all 0.3s ease; width: max-content; z-index: 10; white-space: nowrap; } .tooltip::after { content: ''; position: absolute; top: 100%; left: 50%; transform: translateX(-50%); border-width: 5px; border-style: solid; border-color: #2d3748 transparent transparent transparent; } .controls { display: flex; align-items: center; justify-content: space-between; width: 100%; padding: 15px 0; margin-top: 20px; } .timeframe-selector { display: flex; gap: 10px; background-color: #fff; border-radius: 8px; padding: 5px; box-shadow: 0 4px 15px rgba(0, 0, 0, 0.05); } .timeframe-btn { padding: 8px 15px; background: none; border: none; cursor: pointer; border-radius: 6px; font-size: 14px; font-weight: 500; color: #6b7280; transition: all 0.2s ease; } .timeframe-btn.active { background-color: #1a202c; color: white; } .timeframe-btn:hover:not(.active) { background-color: #f3f4f6; } .update-status { display: flex; align-items: center; gap: 8px; color: #4b5563; font-size: 14px; font-weight: 500; } .pulse { width: 10px; height: 10px; background-color: #10b981; border-radius: 50%; position: relative; } .pulse::after { content: ''; position: absolute; width: 100%; height: 100%; background-color: #10b981; border-radius: 50%; animation: pulse 2s infinite; } .legend { display: flex; justify-content: space-between; width: 100%; padding: 10px 15px; font-size: 13px; color: #6b7280; background-color: #fff; border-radius: 8px; margin-top: 15px; box-shadow: 0 4px 15px rgba(0, 0, 0, 0.05); } .legend-item { display: flex; align-items: center; gap: 6px; } .legend-color { width: 12px; height: 12px; border-radius: 3px; } .details-panel { position: absolute; bottom: 0; left: 0; width: 100%; background-color: #fff; padding: 20px; border-top-left-radius: 20px; border-top-right-radius: 20px; box-shadow: 0 -10px 20px rgba(0, 0, 0, 0.05); transform: translateY(100%); transition: transform 0.5s cubic-bezier(0.19, 1, 0.22, 1); z-index: 100; } .details-panel.active { transform: translateY(0); } .panel-header { display: flex; justify-content: space-between; align-items: center; margin-bottom: 15px; } .panel-title { font-size: 18px; font-weight: 600; color: #1a202c; } .close-btn { background: none; border: none; cursor: pointer; color: #6b7280; font-size: 16px; padding: 5px; border-radius: 50%; display: flex; align-items: center; justify-content: center; transition: all 0.2s ease; } .close-btn:hover { background-color: #f3f4f6; } .detail-chart { width: 100%; height: 120px; margin: 15px 0; position: relative; overflow: hidden; } .chart-line { position: absolute; bottom: 0; left: 0; width: 100%; height: 2px; background-color: #e5e7eb; } .chart-path { position: absolute; bottom: 0; left: 0; width: 100%; height: 100%; fill: none; stroke: #1a202c; stroke-width: 2; stroke-linecap: round; stroke-linejoin: round; stroke-dasharray: 1000; stroke-dashoffset: 1000; animation: draw 2s forwards; } .metrics { display: grid; grid-template-columns: repeat(2, 1fr); gap: 15px; margin-top: 15px; } .metric-item { background-color: #f8fafc; padding: 12px 15px; border-radius: 8px; border-left: 3px solid #1a202c; } .metric-label { font-size: 12px; color: #6b7280; margin-bottom: 5px; } .metric-value { font-size: 16px; font-weight: 600; color: #1a202c; } .panel-overlay { position: absolute; top: 0; left: 0; width: 100%; height: 100%; background-color: rgba(0, 0, 0, 0.4); opacity: 0; pointer-events: none; transition: opacity 0.3s ease; z-index: 50; } .panel-overlay.active { opacity: 1; pointer-events: all; } .title { font-size: 24px; font-weight: 700; color: #1a202c; margin-bottom: 10px; text-align: center; } .subtitle { font-size: 16px; color: #6b7280; margin-bottom: 30px; text-align: center; max-width: 80%; line-height: 1.5; } @keyframes pulse { 0% { transform: scale(1); opacity: 1; } 100% { transform: scale(2.5); opacity: 0; } } @keyframes draw { to { stroke-dashoffset: 0; } } @media (max-width: 700px) { .container { padding: 15px; } .title { font-size: 20px; } .subtitle { font-size: 14px; max-width: 95%; } .timeframe-btn { padding: 6px 10px; font-size: 12px; } .metrics { grid-template-columns: 1fr; } } </style> </head> <body> <div class="container"> <h1 class="title">Portfolio Performance Analytics</h1> <p class="subtitle">Real-time market data analysis with predictive risk assessment and sector weighting</p> <div class="ribbon-container"> <div class="ribbon" id="ribbon"></div> </div> <div class="controls"> <div class="timeframe-selector"> <button class="timeframe-btn" data-period="daily">Daily</button> <button class="timeframe-btn active" data-period="weekly">Weekly</button> <button class="timeframe-btn" data-period="monthly">Monthly</button> <button class="timeframe-btn" data-period="quarterly">Quarterly</button> </div> <div class="update-status"> <div class="pulse"></div> <span>Live data</span> </div> </div> <div class="legend"> <div class="legend-item"> <div class="legend-color" style="background-color: #000000;"></div> <span>Equity</span> </div> <div class="legend-item"> <div class="legend-color" style="background-color: #404040;"></div> <span>Fixed Income</span> </div> <div class="legend-item"> <div class="legend-color" style="background-color: #808080;"></div> <span>Alternative</span> </div> <div class="legend-item"> <div class="legend-color" style="background-color: #b3b3b3;"></div> <span>Cash</span> </div> </div> <div class="details-panel" id="detailsPanel"> <div class="panel-header"> <h3 class="panel-title" id="detailsTitle">Financial Segment Details</h3> <button class="close-btn" id="closeDetails">✕</button> </div> <div class="detail-chart"> <div class="chart-line"></div> <svg width="100%" height="100%" viewBox="0 0 300 100" preserveAspectRatio="none"> <path class="chart-path" id="chartPath" d="M0,80 C20,70 40,90 60,50 C80,30 100,40 120,45 C140,50 160,20 180,40 C200,60 220,80 240,30 C260,40 280,60 300,50" /> </svg> </div> <div class="metrics"> <div class="metric-item"> <div class="metric-label">Allocation %</div> <div class="metric-value" id="allocationValue">32.4%</div> </div> <div class="metric-item"> <div class="metric-label">YTD Return</div> <div class="metric-value" id="ytdValue">+8.7%</div> </div> <div class="metric-item"> <div class="metric-label">Risk Score</div> <div class="metric-value" id="riskValue">6.2</div> </div> <div class="metric-item"> <div class="metric-label">Volatility</div> <div class="metric-value" id="volatilityValue">Medium</div> </div> </div> </div> <div class="panel-overlay" id="panelOverlay"></div> </div> <script> document.addEventListener('DOMContentLoaded', function() { // Financial data for different time periods const financialData = { daily: [ { name: 'Tech Sector', equity: 28, fixedIncome: 12, alternative: 8, cash: 5 }, { name: 'Healthcare', equity: 22, fixedIncome: 15, alternative: 6, cash: 3 }, { name: 'Consumer Goods', equity: 19, fixedIncome: 18, alternative: 9, cash: 7 }, { name: 'Financial Services', equity: 25, fixedIncome: 20, alternative: 12, cash: 6 }, { name: 'Energy', equity: 16, fixedIncome: 22, alternative: 15, cash: 9 }, { name: 'Real Estate', equity: 21, fixedIncome: 25, alternative: 17, cash: 5 }, { name: 'Utilities', equity: 15, fixedIncome: 28, alternative: 13, cash: 8 }, { name: 'Communications', equity: 24, fixedIncome: 17, alternative: 10, cash: 4 } ], weekly: [ { name: 'Tech Sector', equity: 35, fixedIncome: 15, alternative: 10, cash: 5 }, { name: 'Healthcare', equity: 30, fixedIncome: 20, alternative: 8, cash: 4 }, { name: 'Consumer Goods', equity: 25, fixedIncome: 22, alternative: 12, cash: 8 }, { name: 'Financial Services', equity: 32, fixedIncome: 18, alternative: 15, cash: 7 }, { name: 'Energy', equity: 20, fixedIncome: 25, alternative: 18, cash: 10 }, { name: 'Real Estate', equity: 28, fixedIncome: 30, alternative: 20, cash: 6 }, { name: 'Utilities', equity: 18, fixedIncome: 35, alternative: 15, cash: 9 }, { name: 'Communications', equity: 30, fixedIncome: 22, alternative: 12, cash: 5 } ], monthly: [ { name: 'Tech Sector', equity: 40, fixedIncome: 18, alternative: 12, cash: 6 }, { name: 'Healthcare', equity: 35, fixedIncome: 22, alternative: 10, cash: 5 }, { name: 'Consumer Goods', equity: 30, fixedIncome: 25, alternative: 15, cash: 10 }, { name: 'Financial Services', equity: 38, fixedIncome: 20, alternative: 18, cash: 8 }, { name: 'Energy', equity: 25, fixedIncome: 28, alternative: 20, cash: 12 }, { name: 'Real Estate', equity: 32, fixedIncome: 35, alternative: 22, cash: 7 }, { name: 'Utilities', equity: 22, fixedIncome: 40, alternative: 18, cash: 10 }, { name: 'Communications', equity: 36, fixedIncome: 25, alternative: 15, cash: 6 } ], quarterly: [ { name: 'Tech Sector', equity: 45, fixedIncome: 20, alternative: 15, cash: 8 }, { name: 'Healthcare', equity: 42, fixedIncome: 25, alternative: 12, cash: 6 }, { name: 'Consumer Goods', equity: 38, fixedIncome: 30, alternative: 18, cash: 12 }, { name: 'Financial Services', equity: 44, fixedIncome: 22, alternative: 20, cash: 10 }, { name: 'Energy', equity: 30, fixedIncome: 32, alternative: 24, cash: 15 }, { name: 'Real Estate', equity: 40, fixedIncome: 38, alternative: 25, cash: 9 }, { name: 'Utilities', equity: 28, fixedIncome: 45, alternative: 20, cash: 12 }, { name: 'Communications', equity: 43, fixedIncome: 28, alternative: 18, cash: 8 } ] }; // Metric data for each segment const metricData = { 'Tech Sector': { allocation: '32.4%', ytd: '+12.7%', risk: '7.8', volatility: 'High' }, 'Healthcare': { allocation: '21.5%', ytd: '+8.3%', risk: '6.2', volatility: 'Medium' }, 'Consumer Goods': { allocation: '15.8%', ytd: '+5.1%', risk: '4.5', volatility: 'Low' }, 'Financial Services': { allocation: '18.9%', ytd: '+7.4%', risk: '6.7', volatility: 'Medium-High' }, 'Energy': { allocation: '8.2%', ytd: '+3.6%', risk: '8.1', volatility: 'High' }, 'Real Estate': { allocation: '12.7%', ytd: '+4.5%', risk: '5.9', volatility: 'Medium' }, 'Utilities': { allocation: '6.3%', ytd: '+2.9%', risk: '3.4', volatility: 'Low' }, 'Communications': { allocation: '14.5%', ytd: '+6.8%', risk: '6.3', volatility: 'Medium' } }; // Chart path configurations for each segment const chartPaths = { 'Tech Sector': "M0,80 C30,40 60,60 90,20 C120,10 150,30 180,15 C210,5 240,25 270,15 C300,5 330,25 360,10", 'Healthcare': "M0,50 C30,40 60,30 90,45 C120,60 150,40 180,35 C210,30 240,40 270,50 C300,60 330,45 360,40", 'Consumer Goods': "M0,60 C30,65 60,55 90,60 C120,50 150,55 180,60 C210,65 240,55 270,50 C300,45 330,55 360,60", 'Financial Services': "M0,40 C30,60 60,30 90,50 C120,40 150,20 180,40 C210,50 240,30 270,20 C300,40 330,50 360,30", 'Energy': "M0,70 C30,60 60,80 90,60 C120,70 150,50 180,70 C210,80 240,60 270,70 C300,50 330,60 360,70", 'Real Estate': "M0,55 C30,45 60,50 90,40 C120,45 150,55 180,50 C210,45 240,35 270,45 C300,55 330,50 360,45", 'Utilities': "M0,65 C30,70 60,65 90,70 C120,65 150,70 180,65 C210,70 240,65 270,70 C300,65 330,70 360,65", 'Communications': "M0,45 C30,35 60,45 90,35 C120,30 150,45 180,30 C210,35 240,25 270,40 C300,30 330,45 360,35" }; // DOM elements const ribbon = document.getElementById('ribbon'); const timeframeBtns = document.querySelectorAll('.timeframe-btn'); const detailsPanel = document.getElementById('detailsPanel'); const closeDetailsBtn = document.getElementById('closeDetails'); const panelOverlay = document.getElementById('panelOverlay'); const detailsTitle = document.getElementById('detailsTitle'); const chartPath = document.getElementById('chartPath'); const allocationValue = document.getElementById('allocationValue'); const ytdValue = document.getElementById('ytdValue'); const riskValue = document.getElementById('riskValue'); const volatilityValue = document.getElementById('volatilityValue'); let currentPeriod = 'weekly'; // Initialize the ribbon with the current period data renderRibbon(currentPeriod); // Handle timeframe button clicks timeframeBtns.forEach(btn => { btn.addEventListener('click', function() { timeframeBtns.forEach(b => b.classList.remove('active')); this.classList.add('active'); currentPeriod = this.dataset.period; renderRibbon(currentPeriod); }); }); // Close details panel closeDetailsBtn.addEventListener('click', function() { detailsPanel.classList.remove('active'); panelOverlay.classList.remove('active'); }); panelOverlay.addEventListener('click', function() { detailsPanel.classList.remove('active'); panelOverlay.classList.remove('active'); }); // Render ribbon with financial data function renderRibbon(period) { ribbon.innerHTML = ''; financialData[period].forEach(item => { const dataPoint = document.createElement('div'); dataPoint.className = 'data-point'; dataPoint.dataset.name = item.name; // Create tooltip const tooltip = document.createElement('div'); tooltip.className = 'tooltip'; tooltip.textContent = item.name; dataPoint.appendChild(tooltip); // Add segments in order (from bottom to top) const segments = [ { type: 'cash', value: item.cash, color: '#b3b3b3' }, { type: 'alternative', value: item.alternative, color: '#808080' }, { type: 'fixedIncome', value: item.fixedIncome, color: '#404040' }, { type: 'equity', value: item.equity, color: '#000000' } ]; // Create and append segments let cumHeight = 0; segments.forEach(segment => { const segmentEl = document.createElement('div'); segmentEl.className = 'segment'; segmentEl.style.backgroundColor = segment.color; segmentEl.style.bottom = cumHeight + '%'; // Set initial height to 0, will be animated segmentEl.style.height = '0%'; dataPoint.appendChild(segmentEl); cumHeight += segment.value; // Store the target height for animation segmentEl.dataset.targetHeight = segment.value + '%'; }); // Add click event for showing details dataPoint.addEventListener('click', function() { const name = this.dataset.name; showDetails(name); }); ribbon.appendChild(dataPoint); }); // Animate segments after a short delay setTimeout(animateSegments, 100); } // Animate the ribbon segments function animateSegments() { const segments = document.querySelectorAll('.segment'); segments.forEach((segment, index) => { setTimeout(() => { segment.style.height = segment.dataset.targetHeight; }, index * 20); }); } // Show details panel for a specific segment function showDetails(segmentName) { detailsTitle.textContent = segmentName; // Set the chart path chartPath.setAttribute('d', chartPaths[segmentName]); // Reset animation chartPath.style.animation = 'none'; chartPath.offsetHeight; // Trigger reflow chartPath.style.animation = 'draw 2s forwards'; // Update metrics const metrics = metricData[segmentName]; allocationValue.textContent = metrics.allocation; ytdValue.textContent = metrics.ytd; riskValue.textContent = metrics.risk; volatilityValue.textContent = metrics.volatility; // Show the panel and overlay detailsPanel.classList.add('active'); panelOverlay.classList.add('active'); } // Simulate real-time updates setInterval(() => { // Get a random segment and slightly modify its value const segments = document.querySelectorAll('.segment'); if (segments.length > 0) { const randomIndex = Math.floor(Math.random() * segments.length); const segment = segments[randomIndex]; // Get current height and add small variation const currentHeight = parseFloat(segment.dataset.targetHeight); const variation = (Math.random() * 2 - 1); // Between -1 and 1 const newHeight = Math.max(5, Math.min(50, currentHeight + variation)) + '%'; // Update the segment segment.dataset.targetHeight = newHeight; segment.style.height = newHeight; // Add a subtle animation effect segment.style.transition = 'height 0.8s cubic-bezier(0.34, 1.56, 0.64, 1)'; setTimeout(() => { segment.style.transition = 'height 1.2s cubic-bezier(0.19, 1, 0.22, 1)'; }, 800); } }, 5000); }); </script> </body> </html>
<html> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Healthcare Record Status</title> <style> :root { --primary: #a5d6e7; --secondary: #f3bbcd; --success: #a8dabc; --warning: #ffd495; --danger: #ffb3b3; --neutral: #e0e4ed; --text: #435675; --shadow: rgba(149, 157, 165, 0.15); } * { margin: 0; padding: 0; box-sizing: border-box; font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; } body { display: flex; justify-content: center; align-items: center; min-height: 100vh; background-color: #f9fafc; color: var(--text); padding: 20px; } .container { max-width: 650px; width: 100%; background-color: white; border-radius: 16px; box-shadow: 0 12px 24px var(--shadow); padding: 30px; position: relative; overflow: hidden; } h1 { font-size: 24px; margin-bottom: 10px; color: #2c3e50; font-weight: 700; } p.subtitle { color: #6c757d; margin-bottom: 30px; line-height: 1.5; font-size: 15px; } .record-form { position: relative; } .form-group { margin-bottom: 20px; position: relative; } label { display: block; margin-bottom: 8px; font-weight: 500; font-size: 14px; color: #4a5568; } input, select { width: 100%; padding: 12px 15px; border: 1px solid #e2e8f0; border-radius: 8px; font-size: 14px; transition: all 0.3s ease; outline: none; background-color: #f8fafc; } input:focus, select:focus { border-color: var(--primary); box-shadow: 0 0 0 3px rgba(165, 214, 231, 0.25); } button { background-color: var(--primary); color: #2c3e50; border: none; padding: 12px 20px; border-radius: 8px; cursor: pointer; font-weight: 600; transition: all 0.3s ease; margin-top: 10px; display: inline-flex; align-items: center; justify-content: center; } button:hover { background-color: #8eccdf; transform: translateY(-2px); } button:active { transform: translateY(0); } .status-ribbon { position: absolute; top: 0; right: 0; width: 150px; height: 150px; overflow: hidden; pointer-events: none; transform: scale(0); transition: transform 0.5s cubic-bezier(0.175, 0.885, 0.32, 1.275); } .status-ribbon-inner { position: absolute; top: 30px; right: -35px; background-color: var(--neutral); color: #435675; padding: 8px 40px; transform: rotate(45deg); box-shadow: 0 3px 10px rgba(0, 0, 0, 0.1); font-size: 13px; font-weight: 600; white-space: nowrap; opacity: 0.95; backdrop-filter: blur(4px); border-bottom: 2px dashed rgba(255, 255, 255, 0.5); width: 200px; text-align: center; } .status-ribbon.show { transform: scale(1); } .status-ribbon.pending .status-ribbon-inner { background-color: var(--warning); } .status-ribbon.complete .status-ribbon-inner { background-color: var(--success); } .status-ribbon.error .status-ribbon-inner { background-color: var(--danger); } .status-ribbon.verified .status-ribbon-inner { background-color: var(--primary); } .status-message { padding: 15px; margin-top: 20px; border-radius: 8px; display: flex; align-items: center; gap: 12px; opacity: 0; transform: translateY(10px); transition: all 0.3s ease; background-color: #f8fafc; max-height: 0; overflow: hidden; border: 0px solid transparent; } .status-message.show { opacity: 1; transform: translateY(0); max-height: 100px; border: 1px solid #e2e8f0; } .status-message .icon { width: 24px; height: 24px; flex-shrink: 0; background-color: var(--neutral); border-radius: 50%; display: flex; align-items: center; justify-content: center; font-size: 12px; color: white; } .status-message.pending .icon { background-color: var(--warning); } .status-message.complete .icon { background-color: var(--success); } .status-message.error .icon { background-color: var(--danger); } .status-message.verified .icon { background-color: var(--primary); } .form-progress { margin-top: 30px; margin-bottom: 15px; } .progress-steps { display: flex; justify-content: space-between; position: relative; margin-bottom: 10px; } .progress-steps::before { content: ""; position: absolute; top: 15px; left: 0; width: 100%; height: 2px; background-color: var(--neutral); z-index: 1; } .progress-step { position: relative; z-index: 2; display: flex; flex-direction: column; align-items: center; width: 60px; } .progress-step .step-icon { width: 30px; height: 30px; border-radius: 50%; background-color: var(--neutral); display: flex; align-items: center; justify-content: center; color: white; font-size: 14px; font-weight: 600; margin-bottom: 8px; transition: all 0.3s ease; } .progress-step .step-label { font-size: 12px; color: #718096; text-align: center; transition: all 0.3s ease; } .progress-step.active .step-icon { background-color: var(--primary); transform: scale(1.2); } .progress-step.active .step-label { color: var(--text); font-weight: 600; } .progress-step.complete .step-icon { background-color: var(--success); } .progress-bar { width: 100%; height: 6px; background-color: var(--neutral); border-radius: 3px; overflow: hidden; } .progress-fill { height: 100%; background-color: var(--primary); width: 0; transition: width 0.5s ease; border-radius: 3px; background-image: linear-gradient(90deg, var(--primary) 0%, var(--secondary) 100%); } .decorative-pattern { position: absolute; bottom: 0; left: 0; width: 100%; height: 5px; background: linear-gradient(90deg, var(--primary), var(--secondary), var(--success), var(--warning), var(--danger)); opacity: 0.7; } @keyframes shimmer { 0% { background-position: -1000px 0; } 100% { background-position: 1000px 0; } } @media (max-width: 550px) { .container { padding: 20px; border-radius: 12px; } h1 { font-size: 20px; } .progress-step { width: 50px; } .progress-step .step-label { font-size: 10px; } .status-ribbon-inner { font-size: 11px; padding: 6px 30px; } } .field-status { position: absolute; right: 10px; top: 39px; width: 20px; height: 20px; border-radius: 50%; display: flex; align-items: center; justify-content: center; color: white; font-size: 12px; opacity: 0; transition: all 0.3s ease; } .field-status.valid { background-color: var(--success); opacity: 1; } .field-status.invalid { background-color: var(--danger); opacity: 1; } .tooltip { position: absolute; bottom: calc(100% + 10px); right: 0; background-color: #2c3e50; color: white; padding: 8px 12px; border-radius: 6px; font-size: 12px; opacity: 0; transform: translateY(5px); transition: all 0.3s ease; pointer-events: none; width: max-content; max-width: 200px; z-index: 10; } .tooltip::after { content: ""; position: absolute; top: 100%; right: 10px; border-width: 6px; border-style: solid; border-color: #2c3e50 transparent transparent transparent; } .field-status:hover + .tooltip { opacity: 1; transform: translateY(0); } .loader { display: none; width: 20px; height: 20px; border: 2px solid #f3f3f3; border-top: 2px solid var(--primary); border-radius: 50%; animation: spin 1s linear infinite; margin-left: 10px; } @keyframes spin { 0% { transform: rotate(0deg); } 100% { transform: rotate(360deg); } } button.processing { background-color: #e2e8f0; color: #718096; cursor: not-allowed; } button.processing .loader { display: inline-block; } </style> </head> <body> <div class="container"> <h1>Patient Record Verification</h1> <p class="subtitle">Complete and verify patient information for electronic health record compliance. All fields require verification to maintain HIPAA standards.</p> <div class="form-progress"> <div class="progress-steps"> <div class="progress-step active" data-step="1"> <div class="step-icon">1</div> <div class="step-label">Input</div> </div> <div class="progress-step" data-step="2"> <div class="step-icon">2</div> <div class="step-label">Validate</div> </div> <div class="progress-step" data-step="3"> <div class="step-icon">3</div> <div class="step-label">Review</div> </div> <div class="progress-step" data-step="4"> <div class="step-icon">4</div> <div class="step-label">Complete</div> </div> </div> <div class="progress-bar"> <div class="progress-fill" style="width: 25%"></div> </div> </div> <form class="record-form" id="healthRecordForm"> <div class="form-group"> <label for="patientId">Patient ID</label> <input type="text" id="patientId" placeholder="e.g. MRN-12345678" required> <div class="field-status" id="patientIdStatus"> <svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" fill="currentColor" viewBox="0 0 16 16"> <path d="M13.854 3.646a.5.5 0 0 1 0 .708l-7 7a.5.5 0 0 1-.708 0l-3.5-3.5a.5.5 0 1 1 .708-.708L6.5 10.293l6.646-6.647a.5.5 0 0 1 .708 0z"/> </svg> </div> <div class="tooltip">Enter a valid MRN with format MRN-12345678</div> </div> <div class="form-group"> <label for="patientName">Patient Full Name</label> <input type="text" id="patientName" placeholder="First Middle Last" required> <div class="field-status" id="patientNameStatus"> <svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" fill="currentColor" viewBox="0 0 16 16"> <path d="M13.854 3.646a.5.5 0 0 1 0 .708l-7 7a.5.5 0 0 1-.708 0l-3.5-3.5a.5.5 0 1 1 .708-.708L6.5 10.293l6.646-6.647a.5.5 0 0 1 .708 0z"/> </svg> </div> <div class="tooltip">Full name required, min 3 characters per name</div> </div> <div class="form-group"> <label for="dateOfBirth">Date of Birth</label> <input type="date" id="dateOfBirth" required> <div class="field-status" id="dateOfBirthStatus"> <svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" fill="currentColor" viewBox="0 0 16 16"> <path d="M13.854 3.646a.5.5 0 0 1 0 .708l-7 7a.5.5 0 0 1-.708 0l-3.5-3.5a.5.5 0 1 1 .708-.708L6.5 10.293l6.646-6.647a.5.5 0 0 1 .708 0z"/> </svg> </div> <div class="tooltip">Patient must be at least 18 years old</div> </div> <div class="form-group"> <label for="recordType">Record Type</label> <select id="recordType" required> <option value="">Select record type</option> <option value="admission">Admission Record</option> <option value="discharge">Discharge Summary</option> <option value="labs">Laboratory Results</option> <option value="imaging">Imaging Reports</option> <option value="prescription">Medication Order</option> </select> <div class="field-status" id="recordTypeStatus"> <svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" fill="currentColor" viewBox="0 0 16 16"> <path d="M13.854 3.646a.5.5 0 0 1 0 .708l-7 7a.5.5 0 0 1-.708 0l-3.5-3.5a.5.5 0 1 1 .708-.708L6.5 10.293l6.646-6.647a.5.5 0 0 1 .708 0z"/> </svg> </div> <div class="tooltip">Required for proper routing</div> </div> <button type="submit" id="submitButton"> Validate Record <span class="loader"></span> </button> </form> <div class="status-message" id="statusMessage"> <div class="icon"> <svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" fill="currentColor" viewBox="0 0 16 16"> <path d="M8 16A8 8 0 1 0 8 0a8 8 0 0 0 0 16zm.93-9.412-1 4.705c-.07.34.029.533.304.533.194 0 .487-.07.686-.246l-.088.416c-.287.346-.92.598-1.465.598-.703 0-1.002-.422-.808-1.319l.738-3.468c.064-.293.006-.399-.287-.47l-.451-.081.082-.381 2.29-.287zM8 5.5a1 1 0 1 1 0-2 1 1 0 0 1 0 2z"/> </svg> </div> <span>Please complete all required fields to continue.</span> </div> <div class="status-ribbon" id="statusRibbon"> <div class="status-ribbon-inner" id="ribbonText">Pending Verification</div> </div> <div class="decorative-pattern"></div> </div> <script> document.addEventListener('DOMContentLoaded', function() { const form = document.getElementById('healthRecordForm'); const statusRibbon = document.getElementById('statusRibbon'); const ribbonText = document.getElementById('ribbonText'); const statusMessage = document.getElementById('statusMessage'); const progressFill = document.querySelector('.progress-fill'); const progressSteps = document.querySelectorAll('.progress-step'); const submitButton = document.getElementById('submitButton'); // Field validation status elements const patientIdStatus = document.getElementById('patientIdStatus'); const patientNameStatus = document.getElementById('patientNameStatus'); const dateOfBirthStatus = document.getElementById('dateOfBirthStatus'); const recordTypeStatus = document.getElementById('recordTypeStatus'); let currentStep = 1; // Input validation functions function validatePatientId(value) { const regex = /^MRN-\d{8}$/; return regex.test(value); } function validatePatientName(value) { const nameParts = value.trim().split(' '); return nameParts.length >= 2 && nameParts.every(part => part.length >= 3); } function validateDateOfBirth(value) { const birthDate = new Date(value); const today = new Date(); const age = today.getFullYear() - birthDate.getFullYear(); return age >= 18; } function validateRecordType(value) { return value !== ''; } // Real-time field validation document.getElementById('patientId').addEventListener('input', function() { const isValid = validatePatientId(this.value); updateFieldStatus(patientIdStatus, isValid); }); document.getElementById('patientName').addEventListener('input', function() { const isValid = validatePatientName(this.value); updateFieldStatus(patientNameStatus, isValid); }); document.getElementById('dateOfBirth').addEventListener('change', function() { const isValid = validateDateOfBirth(this.value); updateFieldStatus(dateOfBirthStatus, isValid); }); document.getElementById('recordType').addEventListener('change', function() { const isValid = validateRecordType(this.value); updateFieldStatus(recordTypeStatus, isValid); }); function updateFieldStatus(element, isValid) { if (isValid) { element.classList.add('valid'); element.classList.remove('invalid'); element.innerHTML = '<svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" fill="currentColor" viewBox="0 0 16 16"><path d="M13.854 3.646a.5.5 0 0 1 0 .708l-7 7a.5.5 0 0 1-.708 0l-3.5-3.5a.5.5 0 1 1 .708-.708L6.5 10.293l6.646-6.647a.5.5 0 0 1 .708 0z"/></svg>'; } else { element.classList.add('invalid'); element.classList.remove('valid'); element.innerHTML = '<svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" fill="currentColor" viewBox="0 0 16 16"><path d="M8 15A7 7 0 1 1 8 1a7 7 0 0 1 0 14zm0 1A8 8 0 1 0 8 0a8 8 0 0 0 0 16z"/><path d="M7.002 11a1 1 0 1 1 2 0 1 1 0 0 1-2 0zM7.1 4.995a.905.905 0 1 1 1.8 0l-.35 3.507a.552.552 0 0 1-1.1 0L7.1 4.995z"/></svg>'; } } // Form submission form.addEventListener('submit', function(e) { e.preventDefault(); // Perform full validation const patientId = document.getElementById('patientId').value; const patientName = document.getElementById('patientName').value; const dateOfBirth = document.getElementById('dateOfBirth').value; const recordType = document.getElementById('recordType').value; const isPatientIdValid = validatePatientId(patientId); const isPatientNameValid = validatePatientName(patientName); const isDateOfBirthValid = validateDateOfBirth(dateOfBirth); const isRecordTypeValid = validateRecordType(recordType); updateFieldStatus(patientIdStatus, isPatientIdValid); updateFieldStatus(patientNameStatus, isPatientNameValid); updateFieldStatus(dateOfBirthStatus, isDateOfBirthValid); updateFieldStatus(recordTypeStatus, isRecordTypeValid); if (isPatientIdValid && isPatientNameValid && isDateOfBirthValid && isRecordTypeValid) { submitButton.classList.add('processing'); submitButton.disabled = true; // Update status message statusMessage.classList.add('show', 'pending'); statusMessage.querySelector('span').textContent = 'Validating record information...'; statusMessage.querySelector('.icon').innerHTML = '<svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" fill="currentColor" viewBox="0 0 16 16"><path d="M8 16A8 8 0 1 0 8 0a8 8 0 0 0 0 16zm.93-9.412-1 4.705c-.07.34.029.533.304.533.194 0 .487-.07.686-.246l-.088.416c-.287.346-.92.598-1.465.598-.703 0-1.002-.422-.808-1.319l.738-3.468c.064-.293.006-.399-.287-.47l-.451-.081.082-.381 2.29-.287zM8 5.5a1 1 0 1 1 0-2 1 1 0 0 1 0 2z"/></svg>'; // Update ribbon statusRibbon.className = 'status-ribbon show pending'; ribbonText.textContent = 'Processing'; // Simulate processing (normally this would be an API call) setTimeout(function() { // Update progress to step 2 currentStep = 2; updateProgress(); // Simulate a 50% chance of validation success const validationSuccess = Math.random() >= 0.5; if (validationSuccess) { // Success state statusRibbon.className = 'status-ribbon show verified'; ribbonText.textContent = 'Record Verified'; statusMessage.className = 'status-message show verified'; statusMessage.querySelector('span').textContent = 'Record validation successful. Proceeding to review stage.'; statusMessage.querySelector('.icon').innerHTML = '<svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" fill="currentColor" viewBox="0 0 16 16"><path d="M13.854 3.646a.5.5 0 0 1 0 .708l-7 7a.5.5 0 0 1-.708 0l-3.5-3.5a.5.5 0 1 1 .708-.708L6.5 10.293l6.646-6.647a.5.5 0 0 1 .708 0z"/></svg>'; // Progress to step 3 after delay setTimeout(function() { currentStep = 3; updateProgress(); // Final completion (step 4) after another delay setTimeout(function() { currentStep = 4; updateProgress(); statusRibbon.className = 'status-ribbon show complete'; ribbonText.textContent = 'Record Complete'; statusMessage.className = 'status-message show complete'; statusMessage.querySelector('span').textContent = 'Record has been successfully processed and stored in the EHR system.'; statusMessage.querySelector('.icon').innerHTML = '<svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" fill="currentColor" viewBox="0 0 16 16"><path d="M13.854 3.646a.5.5 0 0 1 0 .708l-7 7a.5.5 0 0 1-.708 0l-3.5-3.5a.5.5 0 1 1 .708-.708L6.5 10.293l6.646-6.647a.5.5 0 0 1 .708 0z"/></svg>'; submitButton.textContent = 'Record Completed'; submitButton.classList.remove('processing'); submitButton.disabled = true; }, 1500); }, 1500); } else { // Error state statusRibbon.className = 'status-ribbon show error'; ribbonText.textContent = 'Verification Failed'; statusMessage.className = 'status-message show error'; statusMessage.querySelector('span').textContent = 'Unable to verify record. Please check Patient ID and try again.'; statusMessage.querySelector('.icon').innerHTML = '<svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" fill="currentColor" viewBox="0 0 16 16"><path d="M8 15A7 7 0 1 1 8 1a7 7 0 0 1 0 14zm0 1A8 8 0 1 0 8 0a8 8 0 0 0 0 16z"/><path d="M7.002 11a1 1 0 1 1 2 0 1 1 0 0 1-2 0zM7.1 4.995a.905.905 0 1 1 1.8 0l-.35 3.507a.552.552 0 0 1-1.1 0L7.1 4.995z"/></svg>'; submitButton.textContent = 'Try Again'; submitButton.classList.remove('processing'); submitButton.disabled = false; } }, 2000); } else { // Show error message for invalid form statusMessage.classList.add('show', 'error'); statusMessage.querySelector('span').textContent = 'Please correct the highlighted fields before proceeding.'; statusMessage.querySelector('.icon').innerHTML = '<svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" fill="currentColor" viewBox="0 0 16 16"><path d="M8 15A7 7 0 1 1 8 1a7 7 0 0 1 0 14zm0 1A8 8 0 1 0 8 0a8 8 0 0 0 0 16z"/><path d="M7.002 11a1 1 0 1 1 2 0 1 1 0 0 1-2 0zM7.1 4.995a.905.905 0 1 1 1.8 0l-.35 3.507a.552.552 0 0 1-1.1 0L7.1 4.995z"/></svg>'; } }); function updateProgress() { // Update progress bar progressFill.style.width = (currentStep / 4 * 100) + '%'; // Update step indicators progressSteps.forEach(step => { const stepNum = parseInt(step.dataset.step); if (stepNum < currentStep) { step.classList.add('complete'); step.classList.remove('active'); } else if (stepNum === currentStep) { step.classList.add('active'); step.classList.remove('complete'); } else { step.classList.remove('active', 'complete'); } }); } // Initial ribbon setup setTimeout(() => { statusRibbon.classList.add('show'); }, 500); }); </script> </body> </html>
<html> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Travel Booking Ribbon</title> <style> :root { --primary: #c2894e; --secondary: #8a5a3c; --accent: #d1a676; --highlight: #e6c9a8; --text: #3e2c1e; --light: #f5efe6; --shadow: rgba(62, 44, 30, 0.15); } * { margin: 0; padding: 0; box-sizing: border-box; font-family: 'Cormorant Garamond', Georgia, serif; } body { display: flex; justify-content: center; align-items: center; min-height: 100vh; background: var(--light); overflow-x: hidden; padding: 1rem; } .travel-showcase { width: 100%; max-width: 680px; height: 600px; position: relative; overflow: hidden; border-radius: 12px; box-shadow: 0 25px 50px -12px var(--shadow); } .destinations { height: 100%; width: 100%; transition: transform 0.8s cubic-bezier(0.76, 0, 0.24, 1); } .destination { position: absolute; width: 100%; height: 100%; background-size: cover; background-position: center; transition: opacity 0.8s ease; opacity: 0; } .destination.active { opacity: 1; } .destination-content { position: absolute; bottom: 0; width: 100%; padding: 2rem; background: linear-gradient(transparent, rgba(0, 0, 0, 0.7)); color: white; transform: translateY(20px); opacity: 0; transition: all 0.5s ease 0.3s; } .destination.active .destination-content { transform: translateY(0); opacity: 1; } .destination-title { font-size: 2.5rem; font-weight: 700; margin-bottom: 0.5rem; letter-spacing: 1px; } .destination-desc { font-size: 1.1rem; line-height: 1.6; margin-bottom: 1.5rem; max-width: 90%; } .ribbon-container { position: absolute; top: 30px; right: -60px; width: 250px; height: 60px; transform: rotate(45deg); overflow: hidden; z-index: 10; } .ribbon { width: 100%; height: 100%; background: linear-gradient(45deg, var(--secondary), var(--primary), var(--accent)); position: relative; display: flex; justify-content: center; align-items: center; box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2); animation: shimmer 3s infinite linear; transform-style: preserve-3d; } .ribbon::before { content: ""; position: absolute; top: 0; left: 0; right: 0; bottom: 0; background-image: linear-gradient(135deg, transparent 25%, rgba(255, 255, 255, 0.1) 25%, rgba(255, 255, 255, 0.1) 50%, transparent 50%, transparent 75%, rgba(255, 255, 255, 0.1) 75%); background-size: 8px 8px; z-index: 1; } .ribbon-text { color: white; font-size: 1.1rem; font-weight: 600; letter-spacing: 1px; text-transform: uppercase; text-shadow: 1px 1px 2px rgba(0, 0, 0, 0.3); z-index: 2; } .navigation { position: absolute; top: 50%; width: 100%; display: flex; justify-content: space-between; padding: 0 1.5rem; transform: translateY(-50%); z-index: 5; } .nav-btn { background: rgba(255, 255, 255, 0.8); width: 50px; height: 50px; border-radius: 50%; border: none; cursor: pointer; display: flex; justify-content: center; align-items: center; transition: all 0.3s ease; box-shadow: 0 4px 8px var(--shadow); transform: scale(0.9); } .nav-btn:hover { background: white; transform: scale(1); } .nav-btn:focus { outline: none; } .nav-btn svg { width: 24px; height: 24px; fill: var(--text); } .indicators { position: absolute; bottom: 1.5rem; left: 50%; transform: translateX(-50%); display: flex; gap: 12px; z-index: 5; } .indicator { width: 8px; height: 8px; border-radius: 50%; background: rgba(255, 255, 255, 0.5); border: 2px solid rgba(255, 255, 255, 0.8); cursor: pointer; transition: all 0.3s ease; } .indicator.active { background: white; transform: scale(1.3); } .book-button { display: inline-block; background: var(--primary); color: white; padding: 0.6rem 1.5rem; border-radius: 30px; font-size: 1rem; text-decoration: none; font-weight: 600; letter-spacing: 1px; transition: all 0.3s ease; box-shadow: 0 4px 8px rgba(0, 0, 0, 0.2); cursor: pointer; position: relative; overflow: hidden; } .book-button::after { content: ''; position: absolute; top: -50%; left: -50%; width: 200%; height: 200%; background: linear-gradient( rgba(255, 255, 255, 0.3), rgba(255, 255, 255, 0) ); transform: rotate(30deg); opacity: 0; transition: opacity 0.3s; } .book-button:hover { background: var(--secondary); transform: translateY(-3px); } .book-button:hover::after { opacity: 1; animation: sheen 1s forwards; } @keyframes shimmer { 0% { background-position: 0% 50%; } 50% { background-position: 100% 50%; } 100% { background-position: 0% 50%; } } @keyframes sheen { from { transform: rotate(30deg) translateY(0) translateX(-100%); } to { transform: rotate(30deg) translateY(0) translateX(100%); } } /* Responsive adjustments */ @media (max-width: 600px) { .destination-title { font-size: 2rem; } .destination-desc { font-size: 1rem; max-width: 100%; } .ribbon-container { width: 200px; height: 50px; top: 25px; right: -50px; } .ribbon-text { font-size: 0.9rem; } .nav-btn { width: 40px; height: 40px; } } @media (max-width: 400px) { .destination-title { font-size: 1.8rem; } .destination-content { padding: 1.5rem; } } </style> </head> <body> <div class="travel-showcase"> <div class="ribbon-container"> <div class="ribbon"> <div class="ribbon-text">EXCLUSIVE OFFERS</div> </div> </div> <div class="destinations"> <div class="destination active" style="background-image: url('https://images.unsplash.com/photo-1523906834658-6e24ef2386f9?ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D&auto=format&fit=crop&w=800&q=80');"> <div class="destination-content"> <h2 class="destination-title">Venice, Italy</h2> <p class="destination-desc">Wander through centuries of history in the floating city. Book our Venetian Escape package and receive a complimentary gondola serenade.</p> <button class="book-button">Book Now • €799</button> </div> </div> <div class="destination" style="background-image: url('https://images.unsplash.com/photo-1564507592333-c60657eea523?ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D&auto=format&fit=crop&w=800&q=80');"> <div class="destination-content"> <h2 class="destination-title">Kyoto, Japan</h2> <p class="destination-desc">Experience traditional Japanese culture amid ancient temples and serene gardens. Early summer bookings include a private tea ceremony.</p> <button class="book-button">Book Now • ¥108,000</button> </div> </div> <div class="destination" style="background-image: url('https://images.unsplash.com/photo-1589308078059-be1415eab4c3?ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D&auto=format&fit=crop&w=800&q=80');"> <div class="destination-content"> <h2 class="destination-title">Marrakech, Morocco</h2> <p class="destination-desc">Lose yourself in the vibrant souks and majestic riads of the Red City. Book our Heritage Tour and enjoy a desert excursion at sunset.</p> <button class="book-button">Book Now • 7,500 MAD</button> </div> </div> <div class="destination" style="background-image: url('https://images.unsplash.com/photo-1578002171197-b43bf8909e9a?ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D&auto=format&fit=crop&w=800&q=80');"> <div class="destination-content"> <h2 class="destination-title">Santorini, Greece</h2> <p class="destination-desc">Bask in the Mediterranean sun against a backdrop of iconic white-washed buildings. Limited offer: Caldera-view suites at standard room rates.</p> <button class="book-button">Book Now • €950</button> </div> </div> </div> <div class="navigation"> <button class="nav-btn prev"> <svg viewBox="0 0 24 24"> <path d="M15.41 7.41L14 6l-6 6 6 6 1.41-1.41L10.83 12z"/> </svg> </button> <button class="nav-btn next"> <svg viewBox="0 0 24 24"> <path d="M10 6L8.59 7.41 13.17 12l-4.58 4.59L10 18l6-6z"/> </svg> </button> </div> <div class="indicators"> <div class="indicator active" data-index="0"></div> <div class="indicator" data-index="1"></div> <div class="indicator" data-index="2"></div> <div class="indicator" data-index="3"></div> </div> </div> <script> document.addEventListener('DOMContentLoaded', function() { const destinations = document.querySelectorAll('.destination'); const indicators = document.querySelectorAll('.indicator'); const nextBtn = document.querySelector('.next'); const prevBtn = document.querySelector('.prev'); const ribbon = document.querySelector('.ribbon'); let currentIndex = 0; let autoSlideInterval; // Add 3D effect to ribbon document.addEventListener('mousemove', function(e) { const xAxis = (window.innerWidth / 2 - e.pageX) / 25; const yAxis = (window.innerHeight / 2 - e.pageY) / 25; ribbon.style.transform = `rotateY(${xAxis}deg) rotateX(${yAxis}deg)`; }); // Reset ribbon position when mouse leaves document.addEventListener('mouseleave', function() { ribbon.style.transform = 'rotateY(0deg) rotateX(0deg)'; }); // Function to update current slide function updateSlide(index) { // Update destinations destinations.forEach(dest => dest.classList.remove('active')); destinations[index].classList.add('active'); // Update indicators indicators.forEach(ind => ind.classList.remove('active')); indicators[index].classList.add('active'); currentIndex = index; } // Next slide function function nextSlide() { const nextIndex = (currentIndex + 1) % destinations.length; updateSlide(nextIndex); } // Previous slide function function prevSlide() { const prevIndex = (currentIndex - 1 + destinations.length) % destinations.length; updateSlide(prevIndex); } // Event listeners for navigation nextBtn.addEventListener('click', function() { nextSlide(); resetAutoSlide(); }); prevBtn.addEventListener('click', function() { prevSlide(); resetAutoSlide(); }); // Event listeners for indicators indicators.forEach(indicator => { indicator.addEventListener('click', function() { const index = parseInt(this.dataset.index); updateSlide(index); resetAutoSlide(); }); }); // Auto-slide functionality function startAutoSlide() { autoSlideInterval = setInterval(nextSlide, 5000); } function resetAutoSlide() { clearInterval(autoSlideInterval); startAutoSlide(); } // Book buttons const bookButtons = document.querySelectorAll('.book-button'); bookButtons.forEach(button => { button.addEventListener('click', function(e) { e.preventDefault(); // Create a ripple effect const ripple = document.createElement('span'); ripple.classList.add('ripple'); this.appendChild(ripple); // Remove ripple after animation setTimeout(() => { ripple.remove(); }, 500); // Show a "booking" feedback const originalText = this.textContent; this.textContent = "Processing..."; this.style.background = "#8a5a3c"; setTimeout(() => { this.textContent = "Reserved!"; this.style.background = "#4a7c59"; setTimeout(() => { this.textContent = originalText; this.style.background = ""; }, 1500); }, 1000); }); }); // Initialize auto-slide startAutoSlide(); // Add touch swipe support let touchStartX = 0; let touchEndX = 0; const showcase = document.querySelector('.travel-showcase'); showcase.addEventListener('touchstart', e => { touchStartX = e.changedTouches[0].screenX; }); showcase.addEventListener('touchend', e => { touchEndX = e.changedTouches[0].screenX; handleSwipe(); }); function handleSwipe() { if (touchEndX < touchStartX - 50) { // Swipe left, go next nextSlide(); resetAutoSlide(); } if (touchEndX > touchStartX + 50) { // Swipe right, go prev prevSlide(); resetAutoSlide(); } } // Add embossed texture effect to ribbon on hover ribbon.addEventListener('mouseenter', function() { this.style.boxShadow = "inset 0 2px 3px rgba(255,255,255,0.4), inset 0 -2px 3px rgba(0,0,0,0.4), 0 5px 10px rgba(0,0,0,0.3)"; }); ribbon.addEventListener('mouseleave', function() { this.style.boxShadow = "0 5px 10px rgba(0,0,0,0.2)"; }); }); </script> </body> </html>
<html> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Watercolor Ribbon Portfolio Enhancement</title> <style> * { margin: 0; padding: 0; box-sizing: border-box; } body { font-family: 'Cormorant Garamond', serif; background-color: #f8f8f8; color: #333; height: 100vh; display: flex; justify-content: center; align-items: center; overflow: hidden; position: relative; } .container { width: 100%; max-width: 700px; height: 700px; padding: 20px; position: relative; display: flex; flex-direction: column; align-items: center; justify-content: center; overflow: hidden; } .ribbon-container { position: absolute; top: 0; left: 0; width: 100%; height: 100%; pointer-events: none; z-index: 1; } .ribbon { position: absolute; border-radius: 50%; filter: blur(60px); opacity: 0.6; mix-blend-mode: multiply; transition: all 1.5s cubic-bezier(0.25, 1, 0.5, 1); } .portfolio { position: relative; z-index: 2; width: 100%; max-width: 600px; background: rgba(255, 255, 255, 0.85); backdrop-filter: blur(8px); border-radius: 15px; padding: 30px; box-shadow: 0 10px 30px rgba(0, 0, 0, 0.05); text-align: center; transform: translateY(20px); opacity: 0; animation: fadeIn 1s forwards 0.5s; } h1 { font-size: 32px; margin-bottom: 20px; font-weight: 300; letter-spacing: 1px; color: #2c3e50; } p { font-size: 16px; line-height: 1.6; margin-bottom: 25px; color: #555; font-weight: 400; } .gallery { display: grid; grid-template-columns: repeat(2, 1fr); gap: 15px; margin: 30px 0; } .img-container { position: relative; overflow: hidden; border-radius: 8px; height: 140px; cursor: pointer; transition: transform 0.4s ease; } .img-container:hover { transform: scale(1.03); } .img-container img { width: 100%; height: 100%; object-fit: cover; transition: all 0.4s ease; } .img-container:hover img { filter: brightness(1.1); } .img-overlay { position: absolute; bottom: 0; left: 0; right: 0; background: linear-gradient(to top, rgba(0,0,0,0.7), transparent); padding: 10px; color: white; font-size: 14px; transform: translateY(100%); transition: transform 0.3s ease; } .img-container:hover .img-overlay { transform: translateY(0); } .cta { display: inline-block; background: linear-gradient(135deg, #66a6ff 0%, #667eea 100%); color: white; padding: 12px 28px; border-radius: 30px; text-decoration: none; font-size: 16px; font-weight: 500; letter-spacing: 0.5px; box-shadow: 0 4px 15px rgba(102, 126, 234, 0.35); transition: all 0.3s ease; border: none; cursor: pointer; margin-top: 15px; } .cta:hover { transform: translateY(-2px); box-shadow: 0 8px 20px rgba(102, 126, 234, 0.4); } .cta:active { transform: translateY(1px); } .expanded-view { position: fixed; top: 0; left: 0; width: 100%; height: 100%; background: rgba(0, 0, 0, 0.85); backdrop-filter: blur(5px); z-index: 100; display: flex; justify-content: center; align-items: center; opacity: 0; pointer-events: none; transition: opacity 0.3s ease; } .expanded-view.active { opacity: 1; pointer-events: auto; } .expanded-content { width: 90%; max-width: 600px; max-height: 90%; display: flex; flex-direction: column; align-items: center; } .expanded-img { max-width: 100%; max-height: 70vh; border-radius: 8px; box-shadow: 0 5px 25px rgba(0, 0, 0, 0.2); } .expanded-caption { color: white; margin-top: 15px; font-size: 16px; text-align: center; } .close-expanded { position: absolute; top: 20px; right: 20px; width: 40px; height: 40px; border-radius: 50%; background: rgba(255, 255, 255, 0.2); display: flex; justify-content: center; align-items: center; cursor: pointer; transition: background 0.3s ease; } .close-expanded:hover { background: rgba(255, 255, 255, 0.3); } .close-expanded::before, .close-expanded::after { content: ''; position: absolute; width: 20px; height: 2px; background: white; } .close-expanded::before { transform: rotate(45deg); } .close-expanded::after { transform: rotate(-45deg); } @keyframes fadeIn { to { opacity: 1; transform: translateY(0); } } @media (max-width: 600px) { h1 { font-size: 26px; } p { font-size: 15px; } .portfolio { padding: 20px; } .gallery { grid-template-columns: 1fr; } } </style> </head> <body> <div class="container"> <div class="ribbon-container" id="ribbonContainer"></div> <div class="portfolio"> <h1>Fluid Expressions</h1> <p>Elevate your artistic portfolio with our watercolor ribbon element — where delicate opacity variations and soft edges create the perfect backdrop for your creative narrative. Each ribbon flows uniquely, just like your artistic journey.</p> <div class="gallery"> <div class="img-container" data-caption="Abstract landscape using watercolor ribbon technique"> <img src="https://images.unsplash.com/photo-1615639164213-aab04da93c7c?ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D&auto=format&fit=crop&w=880&q=80" alt="Watercolor landscape"> <div class="img-overlay">Abstract Landscape</div> </div> <div class="img-container" data-caption="Portrait series enhanced with fluid motion elements"> <img src="https://images.unsplash.com/photo-1579783901586-d88db74b4fe4?ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D&auto=format&fit=crop&w=890&q=80" alt="Portrait art"> <div class="img-overlay">Portrait Series</div> </div> <div class="img-container" data-caption="Experimental piece showcasing opacity transitions"> <img src="https://images.unsplash.com/photo-1547891654-e66ed7ebb968?ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D&auto=format&fit=crop&w=880&q=80" alt="Experimental art"> <div class="img-overlay">Opacity Study</div> </div> <div class="img-container" data-caption="Mixed media collection with ribbon integration"> <img src="https://images.unsplash.com/photo-1574182245530-967d9b3831af?ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D&auto=format&fit=crop&w=880&q=80" alt="Mixed media"> <div class="img-overlay">Mixed Media</div> </div> </div> <button class="cta" id="customizeRibbon">Customize Ribbon Flow</button> </div> </div> <div class="expanded-view" id="expandedView"> <div class="close-expanded" id="closeExpanded"></div> <div class="expanded-content"> <img src="" alt="" class="expanded-img" id="expandedImg"> <p class="expanded-caption" id="expandedCaption"></p> </div> </div> <script> document.addEventListener('DOMContentLoaded', () => { const ribbonContainer = document.getElementById('ribbonContainer'); const customizeButton = document.getElementById('customizeRibbon'); const expandedView = document.getElementById('expandedView'); const expandedImg = document.getElementById('expandedImg'); const expandedCaption = document.getElementById('expandedCaption'); const closeExpanded = document.getElementById('closeExpanded'); const imgContainers = document.querySelectorAll('.img-container'); // Color palettes for ribbons const palettes = [ ['#f9d5e5', '#eeac99', '#e06377', '#c83349'], ['#dcedc2', '#a8e6cf', '#ffaaa6', '#ff8c94'], ['#08d9d6', '#252a34', '#ff2e63', '#eaeaea'], ['#f9ed69', '#f08a5d', '#b83b5e', '#6a2c70'] ]; let currentPalette = 0; let ribbons = []; // Create initial ribbons createRibbons(); function createRibbons() { // Clear existing ribbons ribbonContainer.innerHTML = ''; ribbons = []; // Create new ribbons const palette = palettes[currentPalette]; const ribbonCount = 5 + Math.floor(Math.random() * 3); for (let i = 0; i < ribbonCount; i++) { const ribbon = document.createElement('div'); ribbon.className = 'ribbon'; const size = 100 + Math.random() * 300; const xPos = Math.random() * 100; const yPos = Math.random() * 100; const color = palette[Math.floor(Math.random() * palette.length)]; const animDuration = 25 + Math.random() * 15; ribbon.style.width = `${size}px`; ribbon.style.height = `${size}px`; ribbon.style.left = `${xPos}%`; ribbon.style.top = `${yPos}%`; ribbon.style.backgroundColor = color; ribbon.style.opacity = 0.2 + Math.random() * 0.4; ribbonContainer.appendChild(ribbon); ribbons.push({ element: ribbon, xPos, yPos, xVelocity: (Math.random() - 0.5) * 0.2, yVelocity: (Math.random() - 0.5) * 0.2, size, growFactor: (Math.random() - 0.5) * 0.03 }); } // Start animation animateRibbons(); } function animateRibbons() { ribbons.forEach(ribbon => { // Update position ribbon.xPos += ribbon.xVelocity; ribbon.yPos += ribbon.yVelocity; // Boundary check and bounce if (ribbon.xPos < -20 || ribbon.xPos > 120) { ribbon.xVelocity *= -1; } if (ribbon.yPos < -20 || ribbon.yPos > 120) { ribbon.yVelocity *= -1; } // Update size ribbon.size += ribbon.size * ribbon.growFactor; if (ribbon.size < 100 || ribbon.size > 400) { ribbon.growFactor *= -1; } // Apply new properties ribbon.element.style.left = `${ribbon.xPos}%`; ribbon.element.style.top = `${ribbon.yPos}%`; ribbon.element.style.width = `${ribbon.size}px`; ribbon.element.style.height = `${ribbon.size}px`; }); requestAnimationFrame(animateRibbons); } // Customize ribbon button customizeButton.addEventListener('click', () => { currentPalette = (currentPalette + 1) % palettes.length; createRibbons(); // Button animation customizeButton.style.transform = 'scale(0.95)'; setTimeout(() => { customizeButton.style.transform = ''; }, 150); }); // Image gallery expanded view imgContainers.forEach(container => { container.addEventListener('click', () => { const img = container.querySelector('img'); const caption = container.getAttribute('data-caption'); expandedImg.src = img.src; expandedCaption.textContent = caption; expandedView.classList.add('active'); }); }); closeExpanded.addEventListener('click', () => { expandedView.classList.remove('active'); }); // Close expanded view when clicking outside the image expandedView.addEventListener('click', (e) => { if (e.target === expandedView) { expandedView.classList.remove('active'); } }); // Keyboard navigation document.addEventListener('keydown', (e) => { if (e.key === 'Escape' && expandedView.classList.contains('active')) { expandedView.classList.remove('active'); } }); // Add font from Google Fonts const fontLink = document.createElement('link'); fontLink.href = 'https://fonts.googleapis.com/css2?family=Cormorant+Garamond:wght@300;400;500&display=swap'; fontLink.rel = 'stylesheet'; document.head.appendChild(fontLink); }); </script> </body> </html>
<html> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>NeoRibbon Pro X7 - Reveal</title> <style> @import url('https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;700;900&display=swap'); * { margin: 0; padding: 0; box-sizing: border-box; } body { font-family: 'Inter', sans-serif; background: #000; width: 100%; height: 100%; overflow: hidden; display: flex; justify-content: center; align-items: center; color: white; perspective: 1000px; } .container { width: 100%; max-width: 700px; height: 700px; display: flex; flex-direction: column; justify-content: center; align-items: center; padding: 20px; position: relative; } .ribbon-container { position: relative; height: 300px; width: 100%; perspective: 800px; } .ribbon { position: absolute; width: 100%; height: 120px; background: linear-gradient(135deg, #2c3e50, #4CA1AF, #C779D0, #FEAC5E); background-size: 300% 300%; animation: gradientFlow 10s ease infinite, hoverFloat 3s ease-in-out infinite; transform-style: preserve-3d; transform: rotateX(30deg) rotateY(0deg); border-radius: 4px; box-shadow: 0 15px 35px rgba(0, 0, 0, 0.5), 0 5px 15px rgba(0, 0, 0, 0.5), 0 0 60px rgba(192, 219, 255, 0.2) inset; transition: transform 0.5s ease, box-shadow 0.5s ease; overflow: hidden; } .ribbon::before { content: ''; position: absolute; top: 0; left: 0; right: 0; bottom: 0; background: linear-gradient(135deg, rgba(255, 255, 255, 0.2) 0%, rgba(255, 255, 255, 0) 50%, rgba(255, 255, 255, 0.2) 100%); pointer-events: none; z-index: 2; } .ribbon::after { content: ''; position: absolute; top: 0; left: -100%; width: 50%; height: 100%; background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.4), transparent); animation: shine 3s infinite; z-index: 1; } .embossed-text { position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); font-size: 2.5rem; font-weight: 900; letter-spacing: 2px; text-transform: uppercase; color: transparent; background-clip: text; -webkit-background-clip: text; background-image: linear-gradient(to bottom, rgba(255, 255, 255, 0.9), rgba(255, 255, 255, 0.3)); text-shadow: 0 1px 0 rgba(255, 255, 255, 0.4), 0 2px 0 rgba(255, 255, 255, 0.3), 0 3px 3px rgba(0, 0, 0, 0.2); white-space: nowrap; z-index: 3; } .product-info { margin-top: 40px; text-align: center; opacity: 0; transform: translateY(30px); transition: opacity 0.8s ease, transform 0.8s ease; } .product-title { font-size: 2.4rem; font-weight: 700; background: linear-gradient(90deg, #4CA1AF, #C779D0); -webkit-background-clip: text; background-clip: text; color: transparent; margin-bottom: 20px; } .product-description { font-size: 1rem; line-height: 1.6; color: #ccc; margin-bottom: 30px; max-width: 600px; } .specs { display: flex; justify-content: center; flex-wrap: wrap; gap: 20px; margin-top: 30px; } .spec-item { background: rgba(255, 255, 255, 0.05); border-radius: 10px; padding: 15px; min-width: 140px; backdrop-filter: blur(5px); border: 1px solid rgba(255, 255, 255, 0.1); transform: translateY(20px); opacity: 0; transition: all 0.4s ease; } .spec-value { font-size: 1.5rem; font-weight: 700; margin-bottom: 5px; background: linear-gradient(90deg, #4CA1AF, #C779D0); -webkit-background-clip: text; background-clip: text; color: transparent; } .spec-label { font-size: 0.8rem; color: #999; text-transform: uppercase; } .cta-button { margin-top: 40px; background: linear-gradient(90deg, #4CA1AF, #C779D0); color: white; font-weight: 600; font-size: 1rem; padding: 12px 30px; border: none; border-radius: 30px; cursor: pointer; position: relative; overflow: hidden; transition: all 0.3s ease; box-shadow: 0 10px 20px rgba(76, 161, 175, 0.3); transform: translateY(20px); opacity: 0; } .cta-button:hover { transform: translateY(-2px); box-shadow: 0 15px 25px rgba(76, 161, 175, 0.4); } .cta-button::before { content: ''; position: absolute; top: 0; left: -100%; width: 100%; height: 100%; background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.2), transparent); transition: all 0.6s ease; } .cta-button:hover::before { left: 100%; } .particles { position: absolute; width: 100%; height: 100%; top: 0; left: 0; pointer-events: none; } .particle { position: absolute; background: linear-gradient(135deg, #4CA1AF, #C779D0); border-radius: 50%; opacity: 0; } @keyframes gradientFlow { 0% { background-position: 0% 50%; } 50% { background-position: 100% 50%; } 100% { background-position: 0% 50%; } } @keyframes hoverFloat { 0%, 100% { transform: rotateX(30deg) rotateY(0deg) translateZ(0); } 50% { transform: rotateX(35deg) rotateY(5deg) translateZ(10px); } } @keyframes shine { 0% { left: -100%; } 20% { left: 100%; } 100% { left: 100%; } } @media (max-width: 600px) { .embossed-text { font-size: 1.8rem; } .product-title { font-size: 1.8rem; } .product-description { font-size: 0.9rem; } .specs { gap: 10px; } .spec-item { min-width: 100px; padding: 10px; } .spec-value { font-size: 1.2rem; } } </style> </head> <body> <div class="container"> <div class="ribbon-container"> <div class="ribbon"> <div class="embossed-text">NeoRibbon</div> </div> </div> <div class="product-info"> <h1 class="product-title">NeoRibbon Pro X7</h1> <p class="product-description">Introducing the revolutionary NeoRibbon Pro X7 — our most advanced visual compositing layer for immersive presentations. With reactive holograms and dynamic environment recognition, your product launches will transcend ordinary displays.</p> <div class="specs"> <div class="spec-item"> <div class="spec-value">3.2ms</div> <div class="spec-label">Response Time</div> </div> <div class="spec-item"> <div class="spec-value">8K</div> <div class="spec-label">Resolution</div> </div> <div class="spec-item"> <div class="spec-value">120Hz</div> <div class="spec-label">Refresh Rate</div> </div> </div> <button class="cta-button">Pre-order Now</button> </div> <div class="particles"></div> </div> <script> document.addEventListener('DOMContentLoaded', function() { // Initialize ribbon hover effect const ribbon = document.querySelector('.ribbon'); const ribbonContainer = document.querySelector('.ribbon-container'); ribbonContainer.addEventListener('mousemove', function(e) { const rect = ribbonContainer.getBoundingClientRect(); const x = e.clientX - rect.left; const y = e.clientY - rect.top; const centerX = rect.width / 2; const centerY = rect.height / 2; const rotateY = ((x - centerX) / centerX) * 15; const rotateX = ((centerY - y) / centerY) * 10; ribbon.style.transform = `rotateX(${30 + rotateX}deg) rotateY(${rotateY}deg) translateZ(0)`; ribbon.style.boxShadow = ` 0 15px 35px rgba(0, 0, 0, 0.5), 0 5px 15px rgba(0, 0, 0, 0.5), ${rotateY / 2}px ${-rotateX / 2}px 60px rgba(192, 219, 255, 0.3) inset `; }); ribbonContainer.addEventListener('mouseleave', function() { ribbon.style.transform = 'rotateX(30deg) rotateY(0deg) translateZ(0)'; ribbon.style.boxShadow = ` 0 15px 35px rgba(0, 0, 0, 0.5), 0 5px 15px rgba(0, 0, 0, 0.5), 0 0 60px rgba(192, 219, 255, 0.2) inset `; }); // Animate product info appearance setTimeout(() => { document.querySelector('.product-info').style.opacity = '1'; document.querySelector('.product-info').style.transform = 'translateY(0)'; // Animate spec items one by one const specItems = document.querySelectorAll('.spec-item'); specItems.forEach((item, index) => { setTimeout(() => { item.style.opacity = '1'; item.style.transform = 'translateY(0)'; }, 200 + index * 150); }); // Animate CTA button setTimeout(() => { document.querySelector('.cta-button').style.opacity = '1'; document.querySelector('.cta-button').style.transform = 'translateY(0)'; }, 800); }, 1000); // Create particles const particlesContainer = document.querySelector('.particles'); const particleCount = 20; for (let i = 0; i < particleCount; i++) { createParticle(); } function createParticle() { const particle = document.createElement('div'); particle.classList.add('particle'); const size = Math.random() * 10 + 3; particle.style.width = `${size}px`; particle.style.height = `${size}px`; const startX = Math.random() * 100; const startY = Math.random() * 100; particle.style.left = `${startX}%`; particle.style.top = `${startY}%`; particlesContainer.appendChild(particle); // Animate particle setTimeout(() => { particle.style.opacity = '0.7'; const duration = Math.random() * 4000 + 2000; const destX = startX + (Math.random() * 20 - 10); const destY = startY - (Math.random() * 40 + 20); particle.style.transition = `opacity 0.5s ease, top ${duration / 1000}s ease, left ${duration / 1000}s ease`; particle.style.top = `${destY}%`; particle.style.left = `${destX}%`; setTimeout(() => { particle.style.opacity = '0'; setTimeout(() => { particlesContainer.removeChild(particle); createParticle(); }, 500); }, duration - 500); }, Math.random() * 1000); } // Handle CTA button click document.querySelector('.cta-button').addEventListener('click', function(e) { e.preventDefault(); // Create ripple effect const ripple = document.createElement('div'); ripple.style.position = 'absolute'; ripple.style.borderRadius = '50%'; ripple.style.backgroundColor = 'rgba(255,255,255,0.3)'; ripple.style.width = '100%'; ripple.style.height = '100%'; ripple.style.transform = 'scale(0)'; ripple.style.transition = 'transform 0.5s ease-out'; ripple.style.left = '0'; ripple.style.top = '0'; this.appendChild(ripple); setTimeout(() => { ripple.style.transform = 'scale(2)'; ripple.style.opacity = '0'; setTimeout(() => { ripple.remove(); }, 500); }, 10); // Show "button clicked" effect this.innerText = "Reserved!"; this.style.background = "linear-gradient(90deg, #67B26F, #4ca2cd)"; setTimeout(() => { this.innerText = "Pre-order Now"; this.style.background = "linear-gradient(90deg, #4CA1AF, #C779D0)"; }, 2000); }); }); </script> </body> </html>