When it comes to managing events, customer support, or project tasks, having well-crafted tickets can make all the difference. In this article, we will explore 10 ticket examples that showcase best practices and innovative approaches.
From simple event tickets to complex support tickets, these examples will provide valuable insights and inspiration for creating your own effective ticketing system.
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 love Subframe for its drag-and-drop interface and intuitive, responsive canvas. Create pixel-perfect UI effortlessly, ensuring every ticket design is flawless.
Join the community of satisfied users and elevate your design game. 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
Ready to elevate your UI design game? With Subframe, you can create pixel-perfect UIs, including tickets, in minutes. Enjoy the efficiency of a drag-and-drop interface and beautifully crafted components.
Start creating stunning designs immediately. Sign up for free and experience the difference today!
<html> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Event Booking Platform</title> <style> :root { --primary: #FF3366; --secondary: #6C63FF; --tertiary: #20E3B2; --dark: #1A1A2E; --light: #FFFFFF; --gray: #F5F5F7; --card-shadow: 0 8px 24px rgba(0, 0, 0, 0.1); --ticket-shadow: 0 12px 30px rgba(255, 51, 102, 0.15); --transition: all 0.3s cubic-bezier(0.25, 0.8, 0.25, 1); } * { margin: 0; padding: 0; box-sizing: border-box; font-family: 'Inter', -apple-system, BlinkMacSystemFont, sans-serif; } body { background-color: var(--gray); color: var(--dark); font-size: 16px; line-height: 1.5; display: flex; flex-direction: column; align-items: center; justify-content: flex-start; height: 100vh; overflow-x: hidden; padding: 1.5rem; } .container { max-width: 700px; width: 100%; margin: 0 auto; height: 100%; display: flex; flex-direction: column; } .header { text-align: center; margin-bottom: 1.5rem; } .header h1 { font-size: 2.5rem; font-weight: 800; background: linear-gradient(90deg, var(--primary), var(--secondary)); -webkit-background-clip: text; background-clip: text; color: transparent; letter-spacing: -0.03em; line-height: 1.1; margin-bottom: 0.5rem; } .header p { color: #666; font-size: 1rem; max-width: 90%; margin: 0 auto; } .event-filter { display: flex; gap: 0.5rem; margin-bottom: 1.5rem; overflow-x: auto; padding-bottom: 0.5rem; -ms-overflow-style: none; scrollbar-width: none; } .event-filter::-webkit-scrollbar { display: none; } .filter-btn { background-color: transparent; border: 1px solid rgba(0, 0, 0, 0.1); padding: 0.5rem 1rem; border-radius: 2rem; font-weight: 500; font-size: 0.875rem; cursor: pointer; white-space: nowrap; transition: var(--transition); } .filter-btn.active { background-color: var(--primary); color: white; border-color: var(--primary); } .filter-btn:hover:not(.active) { background-color: rgba(0, 0, 0, 0.05); } .tickets-container { display: grid; grid-template-columns: 1fr; gap: 1.25rem; overflow-y: auto; padding-right: 0.5rem; flex-grow: 1; } .ticket { background: var(--light); border-radius: 16px; box-shadow: var(--card-shadow); overflow: hidden; position: relative; transition: var(--transition); cursor: pointer; } .ticket:hover { transform: translateY(-5px); box-shadow: var(--ticket-shadow); } .ticket-top { height: 120px; position: relative; overflow: hidden; } .ticket-image { width: 100%; height: 100%; object-fit: cover; transition: transform 0.5s ease; } .ticket:hover .ticket-image { transform: scale(1.1); } .ticket-date { position: absolute; top: 1rem; left: 1rem; background: rgba(255, 255, 255, 0.9); padding: 0.375rem 0.75rem; border-radius: 8px; font-weight: 600; font-size: 0.875rem; backdrop-filter: blur(5px); display: flex; align-items: center; gap: 0.5rem; } .ticket-date svg { width: 16px; height: 16px; color: var(--primary); } .ticket-content { padding: 1.25rem; position: relative; } .ticket-title { font-size: 1.25rem; font-weight: 700; margin-bottom: 0.5rem; line-height: 1.3; } .ticket-venue { display: flex; align-items: center; font-size: 0.875rem; color: #666; margin-bottom: 0.75rem; gap: 0.375rem; } .ticket-venue svg { width: 14px; height: 14px; color: #666; } .ticket-price { font-weight: 700; font-size: 1.125rem; color: var(--primary); display: flex; align-items: center; justify-content: space-between; margin-top: 1rem; } .ticket-badge { background-color: rgba(255, 51, 102, 0.1); color: var(--primary); font-size: 0.75rem; font-weight: 600; padding: 0.25rem 0.75rem; border-radius: 1rem; } .ticket-details { height: 0; overflow: hidden; opacity: 0; transition: all 0.4s ease; padding: 0 1.25rem; } .ticket:hover .ticket-details { height: auto; opacity: 1; padding: 0 1.25rem 1.25rem 1.25rem; } .details-list { display: flex; flex-direction: column; gap: 0.75rem; border-top: 1px solid rgba(0, 0, 0, 0.1); padding-top: 1rem; margin-top: 0.5rem; } .details-item { display: flex; justify-content: space-between; font-size: 0.875rem; } .details-label { color: #666; } .details-value { font-weight: 500; } .select-btn { background-color: var(--dark); color: white; border: none; border-radius: 8px; padding: 0.75rem 1.5rem; font-weight: 600; width: 100%; margin-top: 1rem; cursor: pointer; transition: var(--transition); display: flex; align-items: center; justify-content: center; gap: 0.5rem; } .select-btn:hover { background-color: #000; transform: translateY(-2px); } .purchase-overlay { position: fixed; top: 0; left: 0; right: 0; bottom: 0; background-color: rgba(0, 0, 0, 0.5); display: flex; align-items: center; justify-content: center; z-index: 100; opacity: 0; pointer-events: none; transition: opacity 0.3s ease; } .purchase-modal { background-color: white; border-radius: 16px; width: 90%; max-width: 500px; padding: 2rem; transform: translateY(20px); transition: transform 0.4s cubic-bezier(0.175, 0.885, 0.32, 1.275); box-shadow: 0 24px 60px rgba(0, 0, 0, 0.15); } .purchase-overlay.active { opacity: 1; pointer-events: all; } .purchase-overlay.active .purchase-modal { transform: translateY(0); } .modal-header { text-align: center; margin-bottom: 1.5rem; } .modal-title { font-size: 1.75rem; font-weight: 700; margin-bottom: 0.5rem; color: var(--dark); } .modal-subtitle { color: #666; font-size: 0.9375rem; } .selected-ticket { background-color: var(--gray); border-radius: 12px; padding: 1.25rem; margin-bottom: 1.5rem; } .selected-header { display: flex; justify-content: space-between; align-items: flex-start; margin-bottom: 1rem; } .selected-title { font-size: 1.125rem; font-weight: 700; line-height: 1.3; } .selected-price { font-weight: 700; font-size: 1.25rem; color: var(--primary); } .selected-info { display: flex; flex-direction: column; gap: 0.5rem; font-size: 0.875rem; } .modal-actions { display: flex; gap: 1rem; margin-top: 1.5rem; } .modal-actions button { flex: 1; padding: 0.9375rem; border-radius: 8px; font-weight: 600; cursor: pointer; transition: var(--transition); } .cancel-btn { background-color: transparent; border: 1px solid rgba(0, 0, 0, 0.1); color: var(--dark); } .cancel-btn:hover { background-color: rgba(0, 0, 0, 0.05); } .confirm-btn { background-color: var(--primary); border: none; color: white; } .confirm-btn:hover { background-color: #e02e5c; transform: translateY(-2px); } .success-animation { display: none; text-align: center; } .checkmark { width: 80px; height: 80px; margin: 0 auto 1.5rem; border-radius: 50%; display: block; stroke-width: 2; stroke: #fff; stroke-miterlimit: 10; background: var(--tertiary); box-shadow: 0 0 0 var(--tertiary); animation: fill .4s ease-in-out .4s forwards, scale .3s ease-in-out .9s both; } .checkmark-circle { stroke-dasharray: 166; stroke-dashoffset: 166; stroke-width: 2; stroke-miterlimit: 10; stroke: #fff; fill: none; animation: stroke 0.6s cubic-bezier(0.65, 0, 0.45, 1) forwards; } .checkmark-check { transform-origin: 50% 50%; stroke-dasharray: 48; stroke-dashoffset: 48; animation: stroke 0.3s cubic-bezier(0.65, 0, 0.45, 1) 0.8s forwards; } @keyframes stroke { 100% { stroke-dashoffset: 0; } } @keyframes scale { 0%, 100% { transform: none; } 50% { transform: scale3d(1.1, 1.1, 1); } } @keyframes fill { 100% { box-shadow: 0 0 0 2px #fff, 0 0 0 10px var(--tertiary); } } @media (max-width: 550px) { .header h1 { font-size: 2rem; } .modal-actions { flex-direction: column; } } @media (min-width: 550px) { .tickets-container { grid-template-columns: repeat(2, 1fr); } } /* Pulse animation for badges */ @keyframes pulse { 0% { transform: scale(1); } 50% { transform: scale(1.05); } 100% { transform: scale(1); } } .ticket-badge.pulse { animation: pulse 2s infinite; } /* Shimmer effect for selected tickets */ .shimmer { position: relative; overflow: hidden; } .shimmer::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: shimmer 2s infinite; } @keyframes shimmer { 100% { left: 150%; } } </style> </head> <body> <div class="container"> <div class="header"> <h1>Next Stage Live</h1> <p>Find and book the hottest live events in your city</p> </div> <div class="event-filter"> <button class="filter-btn active">All Events</button> <button class="filter-btn">Concerts</button> <button class="filter-btn">Comedy</button> <button class="filter-btn">Festivals</button> <button class="filter-btn">Theater</button> <button class="filter-btn">Sports</button> </div> <div class="tickets-container"> <div class="ticket" data-id="1"> <div class="ticket-top"> <img src="https://images.unsplash.com/photo-1470229722913-7c0e2dbbafd3?ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D&auto=format&fit=crop&w=500&q=80" alt="Concert" class="ticket-image"> <div class="ticket-date"> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor"> <path d="M12,14a1,1,0,1,0-1-1A1,1,0,0,0,12,14Zm5,0a1,1,0,1,0-1-1A1,1,0,0,0,17,14Zm-5,4a1,1,0,1,0-1-1A1,1,0,0,0,12,18Zm5,0a1,1,0,1,0-1-1A1,1,0,0,0,17,18ZM7,14a1,1,0,1,0-1-1A1,1,0,0,0,7,14ZM19,4H18V3a1,1,0,0,0-2,0V4H8V3A1,1,0,0,0,6,3V4H5A3,3,0,0,0,2,7V19a3,3,0,0,0,3,3H19a3,3,0,0,0,3-3V7A3,3,0,0,0,19,4Zm1,15a1,1,0,0,1-1,1H5a1,1,0,0,1-1-1V10H20Zm0-11H4V7A1,1,0,0,1,5,6H19a1,1,0,0,1,1,1ZM7,18a1,1,0,1,0-1-1A1,1,0,0,0,7,18Z"/> </svg> Sept 23, 2023 </div> </div> <div class="ticket-content"> <h3 class="ticket-title">Electric Pulse Festival</h3> <div class="ticket-venue"> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor"> <path d="M12,2a8,8,0,0,0-8,8c0,5.4,7.05,11.5,7.35,11.76a1,1,0,0,0,1.3,0C13,21.5,20,15.4,20,10A8,8,0,0,0,12,2Zm0,17.65c-2.13-2-6-6.31-6-9.65a6,6,0,0,1,12,0C18,13.34,14.13,17.66,12,19.65ZM12,6a4,4,0,1,0,4,4A4,4,0,0,0,12,6Zm0,6a2,2,0,1,1,2-2A2,2,0,0,1,12,12Z"/> </svg> Centra Amphitheater </div> <div class="ticket-price"> <span>$89.00</span> <span class="ticket-badge pulse">Hot Seller</span> </div> </div> <div class="ticket-details"> <div class="details-list"> <div class="details-item"> <span class="details-label">Artists</span> <span class="details-value">Lumen Echo, The Drift, Nova Pulse</span> </div> <div class="details-item"> <span class="details-label">Time</span> <span class="details-value">Doors 6PM | Show 7:30PM</span> </div> <div class="details-item"> <span class="details-label">Age</span> <span class="details-value">18+ with valid ID</span> </div> </div> <button class="select-btn"> Select Ticket <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"> <polyline points="9 18 15 12 9 6"></polyline> </svg> </button> </div> </div> <div class="ticket" data-id="2"> <div class="ticket-top"> <img src="https://images.unsplash.com/photo-1579869847514-7c1a19d2d2ad?ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D&auto=format&fit=crop&w=500&q=80" alt="Comedy Show" class="ticket-image"> <div class="ticket-date"> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor"> <path d="M12,14a1,1,0,1,0-1-1A1,1,0,0,0,12,14Zm5,0a1,1,0,1,0-1-1A1,1,0,0,0,17,14Zm-5,4a1,1,0,1,0-1-1A1,1,0,0,0,12,18Zm5,0a1,1,0,1,0-1-1A1,1,0,0,0,17,18ZM7,14a1,1,0,1,0-1-1A1,1,0,0,0,7,14ZM19,4H18V3a1,1,0,0,0-2,0V4H8V3A1,1,0,0,0,6,3V4H5A3,3,0,0,0,2,7V19a3,3,0,0,0,3,3H19a3,3,0,0,0,3-3V7A3,3,0,0,0,19,4Zm1,15a1,1,0,0,1-1,1H5a1,1,0,0,1-1-1V10H20Zm0-11H4V7A1,1,0,0,1,5,6H19a1,1,0,0,1,1,1ZM7,18a1,1,0,1,0-1-1A1,1,0,0,0,7,18Z"/> </svg> Sept 29, 2023 </div> </div> <div class="ticket-content"> <h3 class="ticket-title">Comedy Night Extravaganza</h3> <div class="ticket-venue"> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor"> <path d="M12,2a8,8,0,0,0-8,8c0,5.4,7.05,11.5,7.35,11.76a1,1,0,0,0,1.3,0C13,21.5,20,15.4,20,10A8,8,0,0,0,12,2Zm0,17.65c-2.13-2-6-6.31-6-9.65a6,6,0,0,1,12,0C18,13.34,14.13,17.66,12,19.65ZM12,6a4,4,0,1,0,4,4A4,4,0,0,0,12,6Zm0,6a2,2,0,1,1,2-2A2,2,0,0,1,12,12Z"/> </svg> Laugh Factory Downtown </div> <div class="ticket-price"> <span>$45.00</span> <span class="ticket-badge">Almost Sold Out</span> </div> </div> <div class="ticket-details"> <div class="details-list"> <div class="details-item"> <span class="details-label">Performers</span> <span class="details-value">Maya Richards, Jay Kapoor, Sam Wild</span> </div> <div class="details-item"> <span class="details-label">Time</span> <span class="details-value">Doors 7PM | Show 8PM</span> </div> <div class="details-item"> <span class="details-label">Age</span> <span class="details-value">21+ with valid ID</span> </div> </div> <button class="select-btn"> Select Ticket <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"> <polyline points="9 18 15 12 9 6"></polyline> </svg> </button> </div> </div> <div class="ticket" data-id="3"> <div class="ticket-top"> <img src="https://images.unsplash.com/photo-1507676184212-d03ab07a01bf?ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D&auto=format&fit=crop&w=500&q=80" alt="Theater" class="ticket-image"> <div class="ticket-date"> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor"> <path d="M12,14a1,1,0,1,0-1-1A1,1,0,0,0,12,14Zm5,0a1,1,0,1,0-1-1A1,1,0,0,0,17,14Zm-5,4a1,1,0,1,0-1-1A1,1,0,0,0,12,18Zm5,0a1,1,0,1,0-1-1A1,1,0,0,0,17,18ZM7,14a1,1,0,1,0-1-1A1,1,0,0,0,7,14ZM19,4H18V3a1,1,0,0,0-2,0V4H8V3A1,1,0,0,0,6,3V4H5A3,3,0,0,0,2,7V19a3,3,0,0,0,3,3H19a3,3,0,0,0,3-3V7A3,3,0,0,0,19,4Zm1,15a1,1,0,0,1-1,1H5a1,1,0,0,1-1-1V10H20Zm0-11H4V7A1,1,0,0,1,5,6H19a1,1,0,0,1,1,1ZM7,18a1,1,0,1,0-1-1A1,1,0,0,0,7,18Z"/> </svg> Oct 5, 2023 </div> </div> <div class="ticket-content"> <h3 class="ticket-title">Aurora: Modern Ballet Showcase</h3> <div class="ticket-venue"> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor"> <path d="M12,2a8,8,0,0,0-8,8c0,5.4,7.05,11.5,7.35,11.76a1,1,0,0,0,1.3,0C13,21.5,20,15.4,20,10A8,8,0,0,0,12,2Zm0,17.65c-2.13-2-6-6.31-6-9.65a6,6,0,0,1,12,0C18,13.34,14.13,17.66,12,19.65ZM12,6a4,4,0,1,0,4,4A4,4,0,0,0,12,6Zm0,6a2,2,0,1,1,2-2A2,2,0,0,1,12,12Z"/> </svg> Meridian Arts Center </div> <div class="ticket-price"> <span>$65.00</span> <span class="ticket-badge">New Performance</span> </div> </div> <div class="ticket-details"> <div class="details-list"> <div class="details-item"> <span class="details-label">Company</span> <span class="details-value">Metropolitan Ballet Company</span> </div> <div class="details-item"> <span class="details-label">Time</span> <span class="details-value">Doors 6:30PM | Show 7:30PM</span> </div> <div class="details-item"> <span class="details-label">Duration</span> <span class="details-value">2 hours with intermission</span> </div> </div> <button class="select-btn"> Select Ticket <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"> <polyline points="9 18 15 12 9 6"></polyline> </svg> </button> </div> </div> <div class="ticket" data-id="4"> <div class="ticket-top"> <img src="https://images.unsplash.com/photo-1459749411175-04bf5292ceea?ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D&auto=format&fit=crop&w=500&q=80" alt="Festival" class="ticket-image"> <div class="ticket-date"> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor"> <path d="M12,14a1,1,0,1,0-1-1A1,1,0,0,0,12,14Zm5,0a1,1,0,1,0-1-1A1,1,0,0,0,17,14Zm-5,4a1,1,0,1,0-1-1A1,1,0,0,0,12,18Zm5,0a1,1,0,1,0-1-1A1,1,0,0,0,17,18ZM7,14a1,1,0,1,0-1-1A1,1,0,0,0,7,14ZM19,4H18V3a1,1,0,0,0-2,0V4H8V3A1,1,0,0,0,6,3V4H5A3,3,0,0,0,2,7V19a3,3,0,0,0,3,3H19a3,3,0,0,0,3-3V7A3,3,0,0,0,19,4Zm1,15a1,1,0,0,1-1,1H5a1,1,0,0,1-1-1V10H20Zm0-11H4V7A1,1,0,0,1,5,6H19a1,1,0,0,1,1,1ZM7,18a1,1,0,1,0-1-1A1,1,0,0,0,7,18Z"/> </svg> Oct 12-14, 2023 </div> </div> <div class="ticket-content"> <h3 class="ticket-title">Harvest Moon Food & Music Festival</h3> <div class="ticket-venue"> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor"> <path d="M12,2a8,8,0,0,0-8,8c0,5.4,7.05,11.5,7.35,11.76a1,1,0,0,0,1.3,0C13,21.5,20,15.4,20,10A8,8,0,0,0,12,2Zm0,17.65c-2.13-2-6-6.31-6-9.65a6,6,0,0,1,12,0C18,13.34,14.13,17.66,12,19.65ZM12,6a4,4,0,1,0,4,4A4,4,0,0,0,12,6Zm0,6a2,2,0,1,1,2-2A2,2,0,0,1,12,12Z"/> </svg> Riverfront Park </div> <div class="ticket-price"> <span>$125.00</span> <span class="ticket-badge pulse">Weekend Pass</span> </div> </div> <div class="ticket-details"> <div class="details-list"> <div class="details-item"> <span class="details-label">Features</span> <span class="details-value">30+ Food Vendors, 4 Music Stages</span> </div> <div class="details-item"> <span class="details-label">Hours</span> <span class="details-value">11AM - 10PM Daily</span> </div> <div class="details-item"> <span class="details-label">Options</span> <span class="details-value">Single day tickets also available</span> </div> </div> <button class="select-btn"> Select Ticket <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"> <polyline points="9 18 15 12 9 6"></polyline> </svg> </button> </div> </div> </div> </div> <div class="purchase-overlay"> <div class="purchase-modal"> <div class="modal-content"> <div class="modal-header"> <h2 class="modal-title">Complete Your Booking</h2> <p class="modal-subtitle">You're almost there! Review your selection below.</p> </div> <div class="selected-ticket"> <div class="selected-header"> <div class="selected-event-info"> <h3 class="selected-title"></h3> </div> <div class="selected-price"></div> </div> <div class="selected-info"> <p class="selected-date"></p> <p class="selected-venue"></p> </div> </div> <div class="modal-actions"> <button class="cancel-btn">Cancel</button> <button class="confirm-btn shimmer">Confirm Purchase</button> </div> </div> <div class="success-animation"> <svg class="checkmark" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 52 52"> <circle class="checkmark-circle" cx="26" cy="26" r="25" fill="none"/> <path class="checkmark-check" fill="none" d="M14.1 27.2l7.1 7.2 16.7-16.8"/> </svg> <h2 class="modal-title">Booking Confirmed!</h2> <p class="modal-subtitle">Your tickets have been sent to your email.</p> </div> </div> </div> <script> document.addEventListener('DOMContentLoaded', function() { const tickets = document.querySelectorAll('.ticket'); const filterBtns = document.querySelectorAll('.filter-btn'); const overlay = document.querySelector('.purchase-overlay'); const cancelBtn = document.querySelector('.cancel-btn'); const confirmBtn = document.querySelector('.confirm-btn'); const modalContent = document.querySelector('.modal-content'); const successAnimation = document.querySelector('.success-animation'); let currentTicket = null; // Filter buttons functionality filterBtns.forEach(btn => { btn.addEventListener('click', function() { filterBtns.forEach(b => b.classList.remove('active')); this.classList.add('active'); // Animation for filter change const ticketsContainer = document.querySelector('.tickets-container'); ticketsContainer.style.opacity = '0.6'; setTimeout(() => { ticketsContainer.style.opacity = '1'; }, 300);
<html> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Customer Support Portal</title> <style> :root { --primary: #6b7cff; --primary-light: #eceeff; --high-priority: #ff7b7b; --high-priority-light: #fff0f0; --medium-priority: #ffcd7b; --medium-priority-light: #fffbf0; --low-priority: #7bdeff; --low-priority-light: #f0faff; --text: #3a3c4a; --text-light: #8b8c99; --background: #fafbfc; --card: #ffffff; --border: #eaedf2; --unread: #e6f7ff; --success: #84d8aa; } * { margin: 0; padding: 0; box-sizing: border-box; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif; } body { background-color: var(--background); color: var(--text); display: flex; justify-content: center; align-items: flex-start; min-height: 100vh; padding: 20px; } .container { max-width: 700px; width: 100%; height: 700px; display: flex; flex-direction: column; background-color: var(--card); border-radius: 16px; box-shadow: 0 4px 20px rgba(0, 0, 0, 0.05); overflow: hidden; } .header { padding: 20px 24px; border-bottom: 1px solid var(--border); display: flex; justify-content: space-between; align-items: center; } .header h1 { font-size: 1.4rem; font-weight: 600; color: var(--text); } .search-container { display: flex; align-items: center; background-color: var(--background); border-radius: 8px; padding: 0 16px; transition: all 0.2s ease; border: 1px solid transparent; } .search-container:focus-within { border-color: var(--primary); box-shadow: 0 0 0 3px rgba(107, 124, 255, 0.1); } .search-container input { border: none; background: transparent; padding: 12px 0; outline: none; color: var(--text); font-size: 0.9rem; width: 200px; } .search-container svg { color: var(--text-light); margin-right: 8px; } .filter-bar { padding: 12px 24px; display: flex; gap: 12px; border-bottom: 1px solid var(--border); background-color: var(--background); } .filter-button { background: none; border: none; padding: 8px 12px; border-radius: 6px; font-size: 0.85rem; color: var(--text-light); cursor: pointer; transition: all 0.2s ease; } .filter-button:hover { background-color: rgba(107, 124, 255, 0.1); color: var(--primary); } .filter-button.active { background-color: var(--primary); color: white; } .ticket-count { margin-left: auto; color: var(--text-light); font-size: 0.85rem; display: flex; align-items: center; } .ticket-list { flex: 1; overflow-y: auto; padding: 12px 16px; } .ticket { padding: 16px 20px; border-radius: 10px; margin-bottom: 12px; background-color: var(--card); border: 1px solid var(--border); transition: all 0.25s cubic-bezier(0.2, 0.8, 0.2, 1); cursor: pointer; position: relative; overflow: hidden; } .ticket:hover { box-shadow: 0 6px 14px rgba(0, 0, 0, 0.06); transform: translateY(-2px); } .ticket.unread { background-color: var(--unread); border-left: 3px solid var(--primary); } .ticket.unread:before { content: ''; position: absolute; top: 0; left: 0; width: 100%; height: 0; background-color: rgba(107, 124, 255, 0.05); transition: height 0.3s ease; z-index: 0; } .ticket.unread:hover:before { height: 100%; } .ticket-header { display: flex; justify-content: space-between; align-items: flex-start; margin-bottom: 10px; position: relative; z-index: 1; } .ticket-title { font-weight: 600; font-size: 0.95rem; color: var(--text); margin-bottom: 4px; } .ticket-info { display: flex; align-items: center; color: var(--text-light); font-size: 0.8rem; gap: 8px; } .ticket-id { background-color: var(--background); padding: 3px 6px; border-radius: 4px; font-family: 'SFMono-Regular', Consolas, 'Liberation Mono', Menlo, monospace; } .priority-badge { padding: 4px 8px; border-radius: 4px; font-size: 0.75rem; font-weight: 500; } .priority-high { background-color: var(--high-priority-light); color: var(--high-priority); } .priority-medium { background-color: var(--medium-priority-light); color: var(--medium-priority); } .priority-low { background-color: var(--low-priority-light); color: var(--low-priority); } .ticket-content { color: var(--text-light); font-size: 0.9rem; line-height: 1.5; margin-bottom: 12px; position: relative; z-index: 1; } .ticket-footer { display: flex; justify-content: space-between; align-items: center; position: relative; z-index: 1; } .ticket-tags { display: flex; gap: 6px; } .ticket-tag { background-color: var(--background); padding: 4px 8px; border-radius: 4px; font-size: 0.75rem; color: var(--text-light); } .ticket-time { font-size: 0.8rem; color: var(--text-light); } .ticket-actions { display: flex; gap: 6px; opacity: 0; transition: opacity 0.2s ease; } .ticket:hover .ticket-actions { opacity: 1; } .action-button { background: none; border: none; color: var(--text-light); padding: 4px; border-radius: 4px; cursor: pointer; transition: all 0.2s ease; } .action-button:hover { background-color: var(--background); color: var(--primary); } .ticket-drawer { height: 0; overflow: hidden; transition: height 0.3s ease; background-color: var(--background); border-radius: 8px; margin-top: 10px; position: relative; z-index: 1; } .ticket.expanded .ticket-drawer { height: 160px; padding: 16px; } .drawer-header { display: flex; justify-content: space-between; margin-bottom: 12px; } .drawer-title { font-weight: 600; font-size: 0.9rem; } .messages { display: flex; flex-direction: column; gap: 10px; margin-bottom: 16px; } .message { display: flex; gap: 10px; } .message-avatar { width: 32px; height: 32px; border-radius: 50%; background-color: var(--primary-light); display: flex; justify-content: center; align-items: center; color: var(--primary); font-weight: 600; font-size: 0.8rem; flex-shrink: 0; } .message-content { background-color: var(--card); padding: 10px; border-radius: 8px; font-size: 0.85rem; line-height: 1.5; color: var(--text); flex: 1; } .message-footer { display: flex; justify-content: space-between; font-size: 0.75rem; color: var(--text-light); margin-top: 4px; } .quick-reply { display: flex; gap: 8px; } .quick-reply-input { flex: 1; padding: 8px 12px; border-radius: 6px; border: 1px solid var(--border); outline: none; font-size: 0.85rem; } .quick-reply-input:focus { border-color: var(--primary); box-shadow: 0 0 0 3px rgba(107, 124, 255, 0.1); } .reply-button { background-color: var(--primary); color: white; border: none; border-radius: 6px; padding: 0 12px; font-size: 0.85rem; cursor: pointer; transition: background-color 0.2s ease; } .reply-button:hover { background-color: #5a69e7; } .empty-state { display: none; flex-direction: column; align-items: center; justify-content: center; height: 100%; padding: 40px; text-align: center; } .empty-illustration { width: 120px; height: 120px; background-color: var(--primary-light); border-radius: 50%; display: flex; align-items: center; justify-content: center; margin-bottom: 24px; } .empty-title { font-weight: 600; font-size: 1.1rem; margin-bottom: 8px; } .empty-message { color: var(--text-light); font-size: 0.9rem; line-height: 1.5; margin-bottom: 20px; } .create-button { background-color: var(--primary); color: white; border: none; border-radius: 6px; padding: 10px 18px; font-size: 0.9rem; cursor: pointer; transition: all 0.2s ease; } .create-button:hover { background-color: #5a69e7; transform: translateY(-2px); } /* Tooltip */ .tooltip { position: relative; } .tooltip:hover:after { content: attr(data-tooltip); position: absolute; bottom: 125%; left: 50%; transform: translateX(-50%); background-color: rgba(0, 0, 0, 0.8); color: white; padding: 6px 10px; border-radius: 4px; font-size: 0.75rem; white-space: nowrap; z-index: 10; } .tooltip:hover:before { content: ''; position: absolute; bottom: 115%; left: 50%; transform: translateX(-50%); border-width: 5px; border-style: solid; border-color: rgba(0, 0, 0, 0.8) transparent transparent transparent; z-index: 10; } /* Notification badge */ .notif-badge { background-color: var(--primary); color: white; font-size: 0.7rem; border-radius: 10px; padding: 2px 6px; margin-left: 6px; } /* Loading pulse animation for skeleton */ @keyframes pulse { 0% { opacity: 0.6; } 50% { opacity: 0.3; } 100% { opacity: 0.6; } } .skeleton { animation: pulse 1.5s infinite; background-color: var(--border); border-radius: 4px; } /* Status indicator animation */ .status-indicator { width: 8px; height: 8px; border-radius: 50%; margin-right: 6px; display: inline-block; } .status-resolved { background-color: var(--success); } .status-open { background-color: var(--primary); position: relative; } .status-open:after { content: ''; position: absolute; top: 0; left: 0; width: 100%; height: 100%; border-radius: 50%; background-color: var(--primary); animation: pulse-ring 1.5s infinite; } @keyframes pulse-ring { 0% { transform: scale(1); opacity: 0.8; } 100% { transform: scale(2.5); opacity: 0; } } /* Responsive styling */ @media (max-width: 600px) { .search-container input { width: 130px; } .filter-button { padding: 6px 8px; font-size: 0.8rem; } .header h1 { font-size: 1.2rem; } .ticket-actions { opacity: 1; } } @media (max-width: 450px) { .ticket-tags { display: none; } .search-container input { width: 100px; } .filter-bar { overflow-x: auto; padding: 12px 16px; } } /* Focus styles for accessibility */ :focus { outline: 2px solid var(--primary); outline-offset: 2px; } /* For focus within elements */ button:focus:not(:focus-visible) { outline: none; } </style> </head> <body> <div class="container"> <div class="header"> <h1>Support Tickets</h1> <div class="search-container"> <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" viewBox="0 0 16 16"> <path d="M11.742 10.344a6.5 6.5 0 1 0-1.397 1.398h-.001c.03.04.062.078.098.115l3.85 3.85a1 1 0 0 0 1.415-1.414l-3.85-3.85a1.007 1.007 0 0 0-.115-.1zM12 6.5a5.5 5.5 0 1 1-11 0 5.5 5.5 0 0 1 11 0z"/> </svg> <input type="text" placeholder="Search tickets..." id="search-input"> </div> </div> <div class="filter-bar"> <button class="filter-button active" data-filter="all">All</button> <button class="filter-button" data-filter="unread">Unread <span class="notif-badge">3</span></button> <button class="filter-button" data-filter="high">High priority</button> <span class="ticket-count">12 tickets</span> </div> <div class="ticket-list" id="ticket-list"> <div class="ticket unread" data-id="T-2498"> <div class="ticket-header"> <div> <div class="ticket-title">PayPal integration failing during checkout</div> <div class="ticket-info"> <span class="ticket-id">T-2498</span> <span class="status-indicator status-open"></span> <span>Open</span> </div> </div> <div class="priority-badge priority-high">High priority</div> </div> <div class="ticket-content"> Customers are getting timeout errors when trying to connect to PayPal during checkout. This is affecting approximately 23% of transactions since the latest deployment. Need urgent assistance. </div> <div class="ticket-footer"> <div class="ticket-tags"> <div class="ticket-tag">Payment</div> <div class="ticket-tag">Integration</div> </div> <div class="ticket-actions"> <button class="action-button tooltip" data-tooltip="Assign"> <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" 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> </button> <button class="action-button tooltip reply-action" data-tooltip="Quick reply"> <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" viewBox="0 0 16 16"> <path d="M2.678 11.894a1 1 0 0 1 .287.801 10.97 10.97 0 0 1-.398 2c1.395-.323 2.247-.697 2.634-.893a1 1 0 0 1 .71-.074A8.06 8.06 0 0 0 8 14c3.996 0 7-2.807 7-6 0-3.192-3.004-6-7-6S1 4.808 1 8c0 1.468.617 2.83 1.678 3.894zm-.493 3.905a21.682 21.682 0 0 1-.713.129c-.2.032-.352-.176-.273-.362a9.68 9.68 0 0 0 .244-.637l.003-.01c.248-.72.45-1.548.524-2.319C.743 11.37 0 9.76 0 8c0-3.866 3.582-7 8-7s8 3.134 8 7-3.582 7-8 7a9.06 9.06 0 0 1-2.347-.306c-.52.263-1.639.742-3.468 1.105z"/> </svg> </button> <button class="action-button tooltip" data-tooltip="Mark as read"> <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" viewBox="0 0 16 16"> <path d="M8.97 4.97a.75.75 0 0 1 1.07 1.05l-3.99 4.99a.75.75 0 0 1-1.08.02L2.324 8.384a.75.75 0 1 1 1.06-1.06l2.094 2.093L8.95 4.992a.252.252 0 0 1 .02-.022zm-.92 5.14.92.92a.75.75 0 0 0 1.079-.02l3.992-4.99a.75.75 0 1 0-1.091-1.028L9.477 9.417l-.485-.486-.943 1.179z"/> </svg> </button> </div> <div class="ticket-time">14 minutes ago</div> </div> <div class="ticket-drawer"> <div class="drawer-header"> <div class="drawer-title">Conversation</div> </div> <div class="messages"> <div class="message"> <div class="message-avatar">JD</div> <div class="message-content"> We're receiving timeout errors (Error code: P-4030) when connecting to PayPal API. Logs show connection issues since 2:15 PM. Customers are abandoning carts. <div class="message-footer"> <span>John Doe • 14 min ago</span> </div> </div> </div> </div> <div class="quick-reply"> <input type="text" class="quick-reply-input" placeholder="Type a quick reply..."> <button class="reply-button">Send</button> </div> </div> </div> <div class="ticket unread" data-id="T-2497"> <div class="ticket-header"> <div> <div class="ticket-title">Missing order confirmation emails</div> <div class="ticket-info"> <span class="ticket-id">T-2497</span> <span class="status-indicator status-open"></span> <span>Open</span> </div> </div> <div class="priority-badge priority-medium">Medium priority</div> </div> <div class="ticket-content"> Order confirmation emails not being sent since this morning. Database shows orders are being created correctly, but the email service isn't triggering. Customers are contacting support for order status. </div> <div class="ticket-footer"> <div class="ticket-tags"> <div class="ticket-tag">Email</div> <div class="ticket-tag">Orders</div> </div> <div class="ticket-actions"> <button class="action-button tooltip" data-tooltip="Assign"> <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" 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> </button> <button class="action-button tooltip reply-action" data-tooltip="Quick reply"> <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" viewBox="0 0 16 16"> <path d="M2.678 11.894a1 1 0 0 1 .287.801 10.97 10.97 0 0 1-.398 2c1.395-.323 2.247-.697 2.634-.893a1 1 0 0 1 .71-.074A8.06 8.06 0 0 0 8 14c3.996 0 7-2.807 7-6 0-3.192-3.004-6-7-6S1 4.808 1 8c0 1.468.617 2.83 1.678 3.894zm-.493 3.905a21.682 21.682 0 0 1-.713.129c-.2.032-.352-.176-.273-.362a9.68 9.68 0 0 0 .244-.637l.003-.01c.248-.72.45-1.548.524-2.319C.743 11.37 0 9.76 0 8c0-3.866 3.582-7 8-7s8 3.134 8 7-3.582 7-8 7a9.06 9.06 0 0 1-2.347-.306c-.52.263-1.639.742-3.468 1.105z"/> </svg> </button> <button class="action-button tooltip" data-tooltip="Mark as read"> <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" viewBox="0 0 16 16"> <path d="M8.97 4.97a.75.75 0 0 1 1.07 1.05l-3.99 4.99a.75.75 0 0 1-1.08.02L2.324 8.384a.75.75 0 1 1 1.06-1.06l2.094 2.093L8.95 4.992a.252.252 0 0 1 .02-.022zm-.92 5.14.92.92a.75.75 0 0 0 1.079-.02l3.992-4.99a.75.75 0 1 0-1.091-1.028L9.477 9.417l-.485-.486-.943 1.179z"/> </svg> </button> </div> <div class="ticket-time">35 minutes ago</div> </div> <div class="ticket-drawer"> <div class="drawer-header"> <div class="drawer-title">Conversation</div> </div> <div class="messages"> <div class="message"> <div class="message-avatar">SE</div> <div class="message-content"> Started at approximately 9:30 AM EST. We've checked our SendGrid account and there are no reported outages. API calls seem to be going through but emails aren't delivering. <div class="message-footer"> <span>Sarah Evans • 35 min ago</span> </div> </div> </div> </div> <div class="quick-reply"> <input type="text" class="quick-reply-input" placeholder="Type a quick reply..."> <button class="reply-button">Send</button> </div> </div> </div> <div class="ticket unread" data-id="T-2496"> <div class="ticket-header"> <div> <div class="ticket-title">Bulk product import failures</div> <div class="ticket-info"> <span class="ticket-id">T-2496</span> <span class="status-indicator status-open"></span> <span>Open</span> </div> </div> <div class="priority-badge priority-high">High priority</div> </div> <div class="ticket-content"> CSV product import tool is crashing when handling files over 200 products. Error log shows "memory_limit exceeded" but our server should have adequate resources. Marketing team needs to upload 1500+ products today. </div> <div class="ticket-footer"> <div class="ticket-tags"> <div class="ticket-tag">Import</div> <div class="ticket-tag">Products</div> </div> <div class="ticket-actions"> <button class="action-button tooltip" data-tooltip="Assign"> <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" 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> </button> <button class="action-button tooltip reply-action" data-tooltip="Quick reply"> <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" viewBox="0 0 16 16"> <path d="M2.678 11.894a1 1 0 0 1 .287.801 10.97 10.97 0 0 1-.398 2c1.395-.323 2.247-.697 2.634-.893a1 1 0 0 1 .71-.074A8.06 8.06 0 0 0 8 14c3.996 0 7-2.807 7-6 0-3.192-3.004-6-7-6S1 4.808 1 8c0 1.468.617 2.83 1.678 3.894zm-.493 3.905a21.682 21.682 0 0 1-.713.129c-.2.032-.352-.176-.273-.362a9.68 9.68 0 0 0 .244-.637l.003-.01c.248-.72.45-1.548.524-2.319C.743 11.37 0 9.76 0 8c0-3.866 3.582-7 8-7s8 3.134 8 7-3.582 7-8 7a9.06 9.06 0 0 1-2.347-.306c-.52.263-1.639.742-3.468 1.105z"/> </svg> </button> <button class="action-button tooltip" data-tooltip="Mark as read"> <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" viewBox="0 0 16 16"> <path d="M8.97 4.97a.75.75 0 0 1 1.07 1.05l-3.99 4.99a.75.75 0 0 1-1.08.02L2.324 8.384a.75.75 0 1 1 1.06-1.06l2.094 2.093L8.95 4.992a.252.252 0 0 1 .02-.022zm-.92 5.14.92.92a.75.75 0 0 0 1.079-.02l3.992-4.99a.75.75 0 1 0-1.091-1.028L9.477 9.417l-.485-.486-.943 1.179z"/> </svg> </button> </div> <div class="ticket-time">52 minutes ago</div> </div> <div class="ticket-drawer"> <div class="drawer-header"> <div class="drawer-title">Conversation</div> </div> <div class="messages"> <div class="message"> <div class="message-avatar">MP</div> <div class="message-content"> We need this resolved ASAP as we're launching a new product line today. Smaller batches work but that would take hours to complete all imports. Server monitoring doesn't show any unusual resource usage. <div class="message-footer"> <span>Michael Peters • 52 min ago</span> </div> </div> </div> </div> <div class="quick-reply"> <input type="text" class="quick-reply-input" placeholder="Type a quick reply..."> <button class="reply-button">Send</button> </div> </div> </div> <div class="ticket" data-id="T-2495"> <div class="ticket-header"> <div> <div class="ticket-title">Admin dashboard loading slowly</div> <div class="ticket-info"> <span class="ticket-id">T-2495</span> <span class="status-indicator status-open"></span> <span>Open</span> </div> </div> <div class="priority-badge priority-medium">Medium priority</div> </div> <div class="ticket-content"> Admin dashboard is taking 15-20 seconds to load. Analytics widgets are particularly slow. This started after yesterday's update to the reporting module. Chrome dev tools show slow network requests to /api/reports/*. </div> <div class="ticket-footer"> <div class="ticket-tags"> <div class="ticket-tag">Admin</div> <div class="ticket-tag">Performance</div> </div> <div class="ticket-actions"> <button class="action-button tooltip" data-tooltip="Assign"> <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" 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> </button> <button class="action-button tooltip reply-action" data-tooltip="Quick reply"> <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" viewBox="0 0 16 16"> <path d="M2.678 11.894a1 1 0 0 1 .287.801 10.97 10.97 0 0 1-.398 2c1.395-.323 2.247-.697 2.634-.893a1 1 0 0 1 .71-.074A8.06 8.06 0 0 0 8 14c3.996 0 7-2.807 7-6 0-3.192-
<html> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>NeoTransit Ticket Portal</title> <style> :root { --neon-blue: #2de2e6; --neon-purple: #a742f5; --neon-pink: #ff3e9d; --dark-bg: #0f0b21; --darker-bg: #060412; --glass-bg: rgba(15, 11, 33, 0.75); --ticket-width: 320px; } * { margin: 0; padding: 0; box-sizing: border-box; font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; } body { background: var(--darker-bg); color: white; min-height: 100vh; display: flex; justify-content: center; align-items: center; overflow-x: hidden; position: relative; } .container { width: 100%; max-width: 700px; min-height: 700px; padding: 2rem 1rem; display: flex; flex-direction: column; justify-content: flex-start; align-items: center; position: relative; overflow: hidden; } .container::before { content: ""; position: absolute; top: 0; left: 0; width: 100%; height: 100%; background: radial-gradient(circle at 20% 20%, rgba(42, 226, 230, 0.03) 0%, transparent 70%), radial-gradient(circle at 80% 80%, rgba(167, 66, 245, 0.03) 0%, transparent 70%); z-index: -1; } .grid-lines { position: absolute; top: 0; left: 0; width: 100%; height: 100%; background-image: linear-gradient(to right, rgba(255,255,255,0.03) 1px, transparent 1px), linear-gradient(to bottom, rgba(255,255,255,0.03) 1px, transparent 1px); background-size: 20px 20px; z-index: -1; } .app-header { margin-bottom: 2.5rem; text-align: center; width: 100%; } .logo { font-size: 2.2rem; font-weight: 700; letter-spacing: 1px; margin-bottom: 0.7rem; background: linear-gradient(90deg, var(--neon-blue), var(--neon-purple)); -webkit-background-clip: text; -webkit-text-fill-color: transparent; position: relative; display: inline-block; } .logo::after { content: ""; position: absolute; bottom: 0; left: 0; width: 100%; height: 3px; background: linear-gradient(90deg, var(--neon-blue), var(--neon-purple)); border-radius: 3px; } .tagline { font-size: 0.9rem; opacity: 0.7; letter-spacing: 0.5px; } .ticket-container { position: relative; width: var(--ticket-width); perspective: 1000px; margin-bottom: 2rem; } .ticket { width: 100%; height: 190px; background: var(--dark-bg); border-radius: 16px; position: relative; transform-style: preserve-3d; transition: transform 0.5s ease-out; box-shadow: 0 8px 20px rgba(0, 0, 0, 0.3), 0 0 0 1px rgba(255, 255, 255, 0.1); overflow: hidden; cursor: pointer; } .ticket-front, .ticket-back { position: absolute; width: 100%; height: 100%; backface-visibility: hidden; border-radius: 16px; padding: 1.2rem; display: flex; flex-direction: column; } .ticket-back { transform: rotateY(180deg); background: var(--dark-bg); } .ticket-front { background: var(--dark-bg); } .ticket-front::before { content: ''; position: absolute; top: 0; left: 0; width: 100%; height: 100%; background: linear-gradient(45deg, transparent 48%, rgba(255, 255, 255, 0.03) 50%, transparent 52%); background-size: 10px 10px; z-index: 0; } .ticket-border { position: absolute; top: 0; left: 0; width: 100%; height: 100%; border-radius: 16px; border: 2px solid transparent; background: linear-gradient(var(--dark-bg), var(--dark-bg)) padding-box, linear-gradient(90deg, var(--neon-blue), var(--neon-purple), var(--neon-pink)) border-box; pointer-events: none; z-index: 1; } .ticket-header { display: flex; justify-content: space-between; align-items: flex-start; margin-bottom: 0.8rem; position: relative; z-index: 2; } .ticket-type { color: white; font-weight: 700; letter-spacing: 0.5px; font-size: 1.2rem; } .ticket-status { padding: 0.3rem 0.7rem; background: rgba(42, 226, 230, 0.15); color: var(--neon-blue); border-radius: 20px; font-size: 0.75rem; font-weight: 600; text-transform: uppercase; letter-spacing: 0.5px; animation: pulse 2s infinite; } @keyframes pulse { 0% { opacity: 0.6; } 50% { opacity: 1; } 100% { opacity: 0.6; } } .ticket-validity { margin-top: auto; display: flex; flex-direction: column; position: relative; z-index: 2; } .expiry-label { font-size: 0.8rem; opacity: 0.6; margin-bottom: 0.2rem; } .expiry-time { font-size: 1.8rem; font-weight: 600; letter-spacing: 1px; color: var(--neon-pink); } .qr-container { display: flex; justify-content: center; align-items: center; height: 100%; } .qr-code { width: 140px; height: 140px; padding: 0.5rem; background: white; position: relative; border-radius: 8px; box-shadow: 0 5px 15px rgba(0, 0, 0, 0.2); } .qr-scanning { position: absolute; top: 0; left: 0; width: 100%; height: 4px; background: var(--neon-blue); box-shadow: 0 0 10px var(--neon-blue); animation: scan 1.5s ease-in-out infinite; opacity: 0; border-radius: 2px; } @keyframes scan { 0% { top: 0; opacity: 1; } 100% { top: calc(100% - 4px); opacity: 1; } } .ticket-info { display: flex; gap: 1rem; margin: 1rem 0; position: relative; z-index: 2; } .ticket-info-item { flex: 1; } .info-label { font-size: 0.7rem; opacity: 0.6; margin-bottom: 0.2rem; text-transform: uppercase; } .info-value { font-size: 0.9rem; font-weight: 600; letter-spacing: 0.5px; } .metro-line { position: relative; z-index: 2; display: flex; align-items: center; gap: 0.5rem; margin: 0.5rem 0; } .line-indicator { width: 12px; height: 12px; border-radius: 50%; background: var(--neon-purple); display: inline-block; } .route-info { font-size: 0.9rem; } .tickets-tab { width: 100%; max-width: var(--ticket-width); margin-top: 2rem; } .tabs { display: flex; justify-content: space-between; margin-bottom: 1.5rem; position: relative; } .tab { padding: 0.7rem 0; flex: 1; text-align: center; cursor: pointer; font-size: 0.85rem; color: rgba(255, 255, 255, 0.6); transition: all 0.3s; position: relative; } .tab.active { color: white; } .tab-indicator { position: absolute; bottom: 0; height: 3px; width: 33.333%; background: linear-gradient(90deg, var(--neon-blue), var(--neon-purple)); border-radius: 3px; transition: all 0.3s ease; } .tab:nth-child(1).active ~ .tab-indicator { left: 0; } .tab:nth-child(2).active ~ .tab-indicator { left: 33.333%; } .tab:nth-child(3).active ~ .tab-indicator { left: 66.666%; } .action-button { margin-top: 1.5rem; width: 100%; padding: 1rem; border: none; border-radius: 30px; background: linear-gradient(90deg, var(--neon-blue), var(--neon-purple)); color: white; font-weight: 600; font-size: 1rem; cursor: pointer; transition: all 0.3s; position: relative; overflow: hidden; } .action-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: left 0.5s; } .action-button:hover::before { left: 100%; } .quick-actions { display: flex; justify-content: space-between; width: 100%; max-width: var(--ticket-width); margin-top: 2rem; } .quick-action { display: flex; flex-direction: column; align-items: center; gap: 0.5rem; cursor: pointer; transition: all 0.3s; } .quick-action:hover { transform: translateY(-3px); } .action-icon { width: 40px; height: 40px; border-radius: 50%; background: var(--glass-bg); display: flex; justify-content: center; align-items: center; box-shadow: 0 4px 10px rgba(0, 0, 0, 0.2), 0 0 0 1px rgba(255, 255, 255, 0.1); } .action-icon i { color: var(--neon-blue); font-size: 1.2rem; } .action-label { font-size: 0.7rem; opacity: 0.8; } .swipe-instruction { margin-top: 1rem; font-size: 0.75rem; opacity: 0.6; display: flex; align-items: center; gap: 0.3rem; justify-content: center; } .swipe-arrow { display: inline-block; animation: swipeHint 1.5s infinite; } @keyframes swipeHint { 0%, 100% { transform: translateX(0); } 50% { transform: translateX(5px); } } .time-left-indicator { width: 100%; height: 4px; background: rgba(255, 255, 255, 0.1); border-radius: 2px; margin-top: 0.5rem; overflow: hidden; position: relative; z-index: 2; } .time-progress { height: 100%; width: 75%; background: linear-gradient(90deg, var(--neon-blue), var(--neon-purple)); border-radius: 2px; position: relative; } .validate-container { width: 100%; position: relative; z-index: 2; display: none; } .validate-animation { width: 100%; height: 100%; display: flex; justify-content: center; align-items: center; flex-direction: column; gap: 1rem; animation: fadeIn 0.3s forwards; } @keyframes fadeIn { from { opacity: 0; } to { opacity: 1; } } .validate-circle { width: 80px; height: 80px; border-radius: 50%; border: 3px solid var(--neon-blue); display: flex; justify-content: center; align-items: center; position: relative; box-shadow: 0 0 15px rgba(42, 226, 230, 0.3); } .validate-check { color: var(--neon-blue); font-size: 2.5rem; opacity: 0; transform: scale(0.5); animation: checkmark 0.5s 0.2s forwards; } @keyframes checkmark { from { opacity: 0; transform: scale(0.5); } to { opacity: 1; transform: scale(1); } } .validate-text { font-size: 1.2rem; font-weight: 600; letter-spacing: 0.5px; color: white; } .validated-time { font-size: 0.9rem; opacity: 0.7; margin-top: 0.5rem; } .glowing-dots { position: absolute; width: 100%; height: 100%; top: 0; left: 0; z-index: -1; overflow: hidden; } .dot { position: absolute; width: 2px; height: 2px; background: var(--neon-blue); border-radius: 50%; opacity: 0.4; } /* Responsive styles */ @media (max-width: 400px) { .container { padding: 1rem 0.5rem; } :root { --ticket-width: 280px; } .ticket { height: 180px; } .logo { font-size: 1.8rem; } .action-button { padding: 0.8rem; } } /* Icons and FontAwesome alternative */ .icon { width: 1em; height: 1em; display: inline-block; stroke-width: 0; stroke: currentColor; fill: currentColor; font-style: normal; font-weight: normal; speak: none; margin-right: 0.2em; text-align: center; font-variant: normal; text-transform: none; line-height: 1em; } .ic-qrcode::before { content: "⎔"; } .ic-history::before { content: "⏱"; } .ic-reload::before { content: "↻"; } .ic-share::before { content: "⇱"; } .ic-check::before { content: "✓"; } /* This class is used for JS interactions */ .flipped { transform: rotateY(180deg); } .hidden { display: none; } .visible { display: block; } </style> </head> <body> <div class="glowing-dots" id="glowingDots"></div> <div class="grid-lines"></div> <div class="container"> <div class="app-header"> <h1 class="logo">NeoTransit</h1> <p class="tagline">Smart Urban Mobility System</p> </div> <div class="ticket-container" id="ticketContainer"> <div class="ticket" id="ticket"> <div class="ticket-front"> <div class="ticket-border"></div> <div class="ticket-header"> <div class="ticket-type">One-Way Pass</div> <div class="ticket-status">Active</div> </div> <div class="metro-line"> <span class="line-indicator"></span> <span class="route-info">Quantum Line Q7</span> </div> <div class="ticket-info"> <div class="ticket-info-item"> <div class="info-label">From</div> <div class="info-value">Central Hub</div> </div> <div class="ticket-info-item"> <div class="info-label">To</div> <div class="info-value">Nova Station</div> </div> </div> <div class="validate-container" id="validateContainer"> <div class="validate-animation"> <div class="validate-circle"> <div class="validate-check"><span class="ic-check"></span></div> </div> <div class="validate-text">Ticket Validated</div> <div class="validated-time">05:32 PM • Station P12</div> </div> </div> <div class="ticket-validity" id="ticketValidity"> <div class="expiry-label">Valid until</div> <div class="expiry-time" id="expiryTime">05:47 PM</div> <div class="time-left-indicator"> <div class="time-progress" id="timeProgress"></div> </div> </div> </div> <div class="ticket-back"> <div class="ticket-border"></div> <div class="qr-container"> <div class="qr-code"> <svg width="140" height="140" viewBox="0 0 140 140" fill="none" xmlns="http://www.w3.org/2000/svg"> <rect width="140" height="140" fill="white"/> <rect x="20" y="20" width="10" height="10" fill="black"/> <rect x="30" y="20" width="10" height="10" fill="black"/> <rect x="40" y="20" width="10" height="10" fill="black"/> <rect x="50" y="20" width="10" height="10" fill="black"/> <rect x="60" y="20" width="10" height="10" fill="black"/> <rect x="70" y="20" width="10" height="10" fill="black"/> <rect x="100" y="20" width="10" height="10" fill="black"/> <rect x="20" y="30" width="10" height="10" fill="black"/> <rect x="70" y="30" width="10" height="10" fill="black"/> <rect x="90" y="30" width="10" height="10" fill="black"/> <rect x="110" y="30" width="10" height="10" fill="black"/> <rect x="20" y="40" width="10" height="10" fill="black"/> <rect x="40" y="40" width="10" height="10" fill="black"/> <rect x="50" y="40" width="10" height="10" fill="black"/> <rect x="60" y="40" width="10" height="10" fill="black"/> <rect x="70" y="40" width="10" height="10" fill="black"/> <rect x="80" y="40" width="10" height="10" fill="black"/> <rect x="110" y="40" width="10" height="10" fill="black"/> <rect x="20" y="50" width="10" height="10" fill="black"/> <rect x="40" y="50" width="10" height="10" fill="black"/> <rect x="50" y="50" width="10" height="10" fill="black"/> <rect x="60" y="50" width="10" height="10" fill="black"/> <rect x="70" y="50" width="10" height="10" fill="black"/> <rect x="100" y="50" width="10" height="10" fill="black"/> <rect x="20" y="60" width="10" height="10" fill="black"/> <rect x="40" y="60" width="10" height="10" fill="black"/> <rect x="50" y="60" width="10" height="10" fill="black"/> <rect x="60" y="60" width="10" height="10" fill="black"/> <rect x="70" y="60" width="10" height="10" fill="black"/> <rect x="90" y="60" width="10" height="10" fill="black"/> <rect x="110" y="60" width="10" height="10" fill="black"/> <rect x="20" y="70" width="10" height="10" fill="black"/> <rect x="70" y="70" width="10" height="10" fill="black"/> <rect x="90" y="70" width="10" height="10" fill="black"/> <rect x="20" y="80" width="10" height="10" fill="black"/> <rect x="30" y="80" width="10" height="10" fill="black"/> <rect x="40" y="80" width="10" height="10" fill="black"/> <rect x="50" y="80" width="10" height="10" fill="black"/> <rect x="60" y="80" width="10" height="10" fill="black"/> <rect x="70" y="80" width="10" height="10" fill="black"/> <rect x="90" y="80" width="10" height="10" fill="black"/> <rect x="110" y="80" width="10" height="10" fill="black"/> <rect x="30" y="90" width="10" height="10" fill="black"/> <rect x="50" y="90" width="10" height="10" fill="black"/> <rect x="70" y="90" width="10" height="10" fill="black"/> <rect x="80" y="90" width="10" height="10" fill="black"/> <rect x="30" y="100" width="10" height="10" fill="black"/> <rect x="40" y="100" width="10" height="10" fill="black"/> <rect x="60" y="100" width="10" height="10" fill="black"/> <rect x="80" y="100" width="10" height="10" fill="black"/> <rect x="90" y="100" width="10" height="10" fill="black"/> <rect x="100" y="100" width="10" height="10" fill="black"/> <rect x="110" y="100" width="10" height="10" fill="black"/> <rect x="20" y="110" width="10" height="10" fill="black"/> <rect x="40" y="110" width="10" height="10" fill="black"/> <rect x="50" y="110" width="10" height="10" fill="black"/> <rect x="60" y="110" width="10" height="10" fill="black"/> <rect x="70" y="110" width="10" height="10" fill="black"/> <rect x="80" y="110" width="10" height="10" fill="black"/> <rect x="100" y="110" width="10" height="10" fill="black"/> </svg> <div class="qr-scanning" id="qrScanner"></div> </div> </div> </div> </div> <div class="swipe-instruction"> <span>Tap to flip</span> <span class="swipe-arrow">→</span> </div> </div> <div class="tickets-tab"> <div class="tabs"> <div class="tab active">Active</div> <div class="tab">Upcoming</div> <div class="tab">History</div> <div class="tab-indicator"></div> </div> <button class="action-button" id="validateButton">Validate Ticket</button> </div> <div class="quick-actions"> <div class="quick-action"> <div class="action-icon"> <span class="icon ic-qrcode"></span> </div> <div class="action-label">Scan QR</div> </div> <div class="quick-action"> <div class="action-icon"> <span class="icon ic-history"></span> </div> <div class="action-label">History</div> </div> <div class="quick-action"> <div class="action-icon"> <span class="icon ic-reload"></span> </div> <div class="action-label">Refresh</div> </div> <div class="quick-action"> <div class="action-icon"> <span class="icon ic-share"></span> </div> <div class="action-label">Share</div> </div> </div> </div> <script> document.addEventListener('DOMContentLoaded', function() { // Ticket flip functionality const ticket = document.getElementById('ticket'); ticket.addEventListener('click', function() { this.classList.toggle('flipped'); }); // Tab switching const tabs = document.querySelectorAll('.tab'); tabs.forEach(tab => { tab.addEventListener('click', function() { tabs.forEach(t => t.classList.remove('active')); this.classList.add('active'); }); }); // Validation animation const validateButton = document.getElementById('validateButton'); const validateContainer = document.getElementById('validateContainer'); const ticketValidity = document.getElementById('ticketValidity'); const qrScanner = document.getElementById('qrScanner'); validateButton.addEventListener('click', function() { validateContainer.style.display = 'block'; ticketValidity.style.display = 'none'; // Revert back after 3 seconds setTimeout(() => { validateContainer.style.display = 'none'; ticketValidity.style.display = 'block'; }, 3000); }); // QR code scanning animation function startQRScanning() { qrScanner.style.opacity = '1'; // Stop scanning after a few seconds setTimeout(() => { qrScanner.style.opacity = '0'; }, 5000); } // Start QR scanning when ticket is flipped to back ticket.addEventListener('transitionend', function() { if (this.classList.contains('flipped')) { startQRScanning(); } }); // Dynamic time update function updateTimeProgress() { const timeProgress = document.getElementById('timeProgress'); let width = parseFloat(getComputedStyle(timeProgress).width); const parentWidth = parseFloat(getComputedStyle(timeProgress.parentElement).width); const percentage = (width / parentWidth) * 100; // Decrease by 0.5% every second if (percentage > 0) { const newPercentage = percentage - 0.05; timeProgress.style.width = `${newPercentage}%`; // Change color when time is running out if (newPercentage < 20) { timeProgress.style.background = 'linear-gradient(90deg, #ff3e9d, #ff3e9d)'; } } } // Update time every second setInterval(updateTimeProgress, 1000); // Create glowing dots const glowingDots = document.getElementById('glowingDots'); const dotsCount = 30; for (let i = 0; i < dotsCount; i++) { const dot = document.createElement('div'); dot.classList.add('dot'); // Random position const posX = Math.random() * 100; const posY = Math.random() * 100; // Random size const size = Math.random() * 2 + 1; dot.style.left = `${posX}%`; dot.style.top = `${posY}%`; dot.style.width = `${size}px`; dot.style.height = `${size}px`; // Random opacity dot.style.opacity = Math.random() * 0.5 + 0.1; // Random blur const blur = Math.random() * 3; dot.style.filter = `blur(${blur}px)`; // Random glow color const colors = ['var(--neon-blue)', 'var(--neon-purple)', 'var(--neon-pink)']; const randomColor = colors[Math.floor(Math.random() * colors.length)]; dot.style.boxShadow = `0 0 ${Math.random() * 5 + 2}px ${randomColor}`; dot.style.background = randomColor; glowingDots.appendChild(dot); } // Simulated real-time updates function simulateTimeUpdate() { const expiryTime = document.getElementById('expiryTime'); const now = new Date(); const minutes = now.getMinutes(); const hours = now.getHours() % 12 || 12; const ampm = now.getHours() >= 12 ? 'PM' : 'AM'; // Add 15 minutes to current time for expiry const expiryMinutes = (minutes + 15) % 60; const expiryHours = hours + (minutes + 15 >= 60 ? 1 : 0); const formattedExpiry = `${expiryHours}:${expiryMinutes.toString().padStart(2, '0')} ${ampm}`; expiryTime.textContent = formattedExpiry; } // Set initial expiry time simulateTimeUpdate(); }); </script> </body> </html>
<html> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Concert Ticket Interface</title> <style> @import url('https://fonts.googleapis.com/css2?family=Abril+Fatface&family=Playfair+Display:wght@700&family=Dancing+Script:wght@700&family=Roboto:wght@400;700&display=swap'); * { margin: 0; padding: 0; box-sizing: border-box; } body { font-family: 'Roboto', sans-serif; background: #1a1a1a; color: #fff; display: flex; justify-content: center; align-items: center; min-height: 700px; overflow-x: hidden; padding: 20px; } .container { width: 100%; max-width: 650px; position: relative; } .ticket-header { text-align: center; margin-bottom: 30px; } .ticket-header h1 { font-family: 'Playfair Display', serif; font-size: 2.5rem; background: linear-gradient(to right, #FF9D6C, #FF6B95); -webkit-background-clip: text; background-clip: text; color: transparent; margin-bottom: 10px; position: relative; display: inline-block; } .ticket-header h1::after { content: ''; position: absolute; width: 40%; height: 4px; bottom: -8px; left: 30%; background: linear-gradient(to right, #FF9D6C, #FF6B95); border-radius: 4px; } .ticket-header p { font-family: 'Dancing Script', cursive; font-size: 1.3rem; color: #ddd; margin-top: 15px; } .ticket-container { display: grid; grid-template-columns: repeat(auto-fill, minmax(280px, 1fr)); gap: 30px; margin-bottom: 40px; } .ticket { position: relative; background: linear-gradient(145deg, #2d2d2d, #232323); border-radius: 16px; overflow: hidden; cursor: pointer; transition: all 0.4s cubic-bezier(0.175, 0.885, 0.32, 1.275); box-shadow: 0 10px 20px rgba(0, 0, 0, 0.2); transform-style: preserve-3d; transform: perspective(1000px); } .ticket::before { content: ''; position: absolute; top: 0; left: 0; width: 100%; height: 100%; background: linear-gradient(135deg, rgba(255, 107, 149, 0.1), rgba(255, 157, 108, 0.1)); opacity: 0; transition: opacity 0.4s ease; z-index: 1; } .ticket:hover::before { opacity: 1; } .ticket:hover { transform: perspective(1000px) rotateX(10deg) translateY(-10px); box-shadow: 0 20px 25px rgba(0, 0, 0, 0.3); } .ticket-inner { padding: 20px; position: relative; z-index: 2; } .ticket-gradient { height: 80px; background: linear-gradient(45deg, #FF6B95, #FF9D6C); position: relative; margin-bottom: 15px; border-radius: 10px 10px 0 0; overflow: hidden; } .ticket-gradient::after { content: ''; position: absolute; width: 100%; height: 100%; background: 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.1' fill-rule='evenodd'/%3E%3C/svg%3E"); opacity: 0.4; } .event-name { font-family: 'Abril Fatface', cursive; font-size: 1.4rem; color: #fff; margin-bottom: 6px; } .event-details { margin-bottom: 15px; color: #ccc; } .event-details div { margin-bottom: 5px; display: flex; align-items: center; } .event-details i { margin-right: 8px; color: #FF6B95; font-size: 0.9rem; } .ticket-price { display: flex; justify-content: space-between; align-items: center; margin-top: 15px; border-top: 1px dashed rgba(255, 255, 255, 0.2); padding-top: 15px; position: relative; } .price { font-family: 'Playfair Display', serif; font-size: 1.5rem; color: #FF9D6C; } .ticket-price::before { content: ''; position: absolute; left: -8px; top: -15px; width: 15px; height: 15px; background: #1a1a1a; border-radius: 50%; } .ticket-price::after { content: ''; position: absolute; right: -8px; top: -15px; width: 15px; height: 15px; background: #1a1a1a; border-radius: 50%; } .select-btn { background: none; border: 2px solid #FF6B95; color: #FF6B95; padding: 8px 15px; border-radius: 30px; font-weight: bold; cursor: pointer; transition: all 0.3s ease; position: relative; overflow: hidden; z-index: 1; } .select-btn::before { content: ''; position: absolute; top: 0; left: 0; width: 0%; height: 100%; background: linear-gradient(to right, #FF6B95, #FF9D6C); transition: all 0.3s ease; z-index: -1; } .select-btn:hover::before { width: 100%; } .select-btn:hover { color: #fff; } .selected .ticket-inner { position: relative; } .selected .ticket-inner::before { content: ''; position: absolute; top: 0; left: 0; width: 100%; height: 100%; background: url("data:image/svg+xml,%3Csvg width='44' height='12' viewBox='0 0 44 12' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M20 12v-2L0 0v10l4 2h16zm18 0l4-2V0L22 10v2h16zM20 0v8L4 0h16zm18 0L22 8V0h16z' fill='%23ffffff' fill-opacity='0.1' fill-rule='evenodd'/%3E%3C/svg%3E"); z-index: -1; } .selected { background: linear-gradient(145deg, #3d3d3d, #323232); transform: perspective(1000px) rotateX(0) translateY(0); box-shadow: 0 5px 15px rgba(0, 0, 0, 0.3); } .selected .select-btn { background: linear-gradient(to right, #FF6B95, #FF9D6C); color: #fff; border: none; } .selected .select-btn::before { width: 0; } .selected .select-btn::after { content: '✓'; margin-left: 5px; } .cart-container { background: linear-gradient(145deg, #2d2d2d, #232323); border-radius: 16px; padding: 20px; margin-top: 30px; box-shadow: 0 10px 20px rgba(0, 0, 0, 0.15); } .cart-header { display: flex; justify-content: space-between; align-items: center; margin-bottom: 15px; padding-bottom: 15px; border-bottom: 1px solid rgba(255, 255, 255, 0.1); } .cart-title { font-family: 'Playfair Display', serif; font-size: 1.3rem; color: #fff; } .cart-count { background: linear-gradient(to right, #FF6B95, #FF9D6C); color: #fff; width: 28px; height: 28px; border-radius: 50%; display: flex; justify-content: center; align-items: center; font-weight: bold; font-size: 0.9rem; } .cart-empty { text-align: center; padding: 20px; color: #999; font-style: italic; } .cart-items { max-height: 150px; overflow-y: auto; margin-bottom: 15px; padding-right: 5px; } .cart-items::-webkit-scrollbar { width: 5px; } .cart-items::-webkit-scrollbar-track { background: #333; border-radius: 10px; } .cart-items::-webkit-scrollbar-thumb { background: #FF6B95; border-radius: 10px; } .cart-item { display: flex; justify-content: space-between; align-items: center; padding: 10px 0; border-bottom: 1px dashed rgba(255, 255, 255, 0.1); animation: fadeIn 0.3s ease forwards; } @keyframes fadeIn { from { opacity: 0; transform: translateY(10px); } to { opacity: 1; transform: translateY(0); } } .cart-item-info { flex: 1; } .cart-item-name { font-weight: bold; margin-bottom: 3px; color: #ddd; } .cart-item-details { font-size: 0.8rem; color: #999; } .cart-item-price { font-weight: bold; color: #FF9D6C; } .remove-btn { background: none; border: none; color: #FF6B95; cursor: pointer; margin-left: 10px; font-size: 1.2rem; transition: all 0.2s ease; } .remove-btn:hover { color: #ff5050; transform: scale(1.1); } .cart-total { display: flex; justify-content: space-between; padding-top: 15px; border-top: 1px solid rgba(255, 255, 255, 0.1); font-weight: bold; } .total-label { color: #ddd; } .total-amount { font-family: 'Playfair Display', serif; color: #FF9D6C; font-size: 1.2rem; } .checkout-btn { display: block; width: 100%; background: linear-gradient(to right, #FF6B95, #FF9D6C); border: none; color: #fff; padding: 12px; border-radius: 8px; font-weight: bold; cursor: pointer; margin-top: 15px; transition: transform 0.3s ease, box-shadow 0.3s ease; box-shadow: 0 5px 15px rgba(255, 107, 149, 0.3); position: relative; overflow: hidden; } .checkout-btn:hover { transform: translateY(-3px); box-shadow: 0 8px 20px rgba(255, 107, 149, 0.4); } .checkout-btn:active { transform: translateY(0); } .checkout-btn::after { content: ''; position: absolute; top: 50%; left: 50%; width: 150%; height: 200%; background: rgba(255, 255, 255, 0.2); border-radius: 50%; transform: translate(-50%, -50%) scale(0); opacity: 0; transition: transform 0.6s ease, opacity 0.6s ease; } .checkout-btn:hover::after { transform: translate(-50%, -50%) scale(1); opacity: 1; } /* Tear animation */ @keyframes tear { 0% { clip-path: polygon(0 0, 100% 0, 100% 100%, 0 100%); } 20% { clip-path: polygon(0 0, 100% 0, 100% 100%, 60% 90%, 40% 100%, 0 100%); } 40% { clip-path: polygon(0 0, 100% 0, 100% 100%, 75% 90%, 60% 100%, 50% 85%, 40% 100%, 25% 90%, 0 100%); } 100% { clip-path: polygon(0 0, 100% 0, 100% 100%, 85% 85%, 75% 100%, 65% 85%, 60% 100%, 50% 85%, 40% 100%, 35% 85%, 25% 100%, 15% 85%, 0 100%); } } .torn { animation: tear 0.4s ease forwards; } @media (max-width: 700px) { .ticket-container { grid-template-columns: 1fr; } .ticket-header h1 { font-size: 2rem; } .ticket-header p { font-size: 1.1rem; } } /* Animations for the interface */ @keyframes pulse { 0% { box-shadow: 0 0 0 0 rgba(255, 107, 149, 0.6); } 70% { box-shadow: 0 0 0 15px rgba(255, 107, 149, 0); } 100% { box-shadow: 0 0 0 0 rgba(255, 107, 149, 0); } } .pulse { animation: pulse 1.5s infinite; } </style> </head> <body> <div class="container"> <div class="ticket-header"> <h1>Astral Rhythms Tour</h1> <p>Select your tickets for an unforgettable night</p> </div> <div class="ticket-container"> <div class="ticket" data-price="89.99" data-name="VIP Experience" data-date="Nov 15, 2023" data-time="7:00 PM" data-venue="Nebula Arena"> <div class="ticket-gradient"></div> <div class="ticket-inner"> <h3 class="event-name">VIP Experience</h3> <div class="event-details"> <div><i>📅</i> Nov 15, 2023</div> <div><i>⏰</i> 7:00 PM</div> <div><i>📍</i> Nebula Arena</div> <div><i>✨</i> Front Row + Backstage Access</div> </div> <div class="ticket-price"> <span class="price">$89.99</span> <button class="select-btn">Select</button> </div> </div> </div> <div class="ticket" data-price="59.99" data-name="Premium Seating" data-date="Nov 15, 2023" data-time="7:00 PM" data-venue="Nebula Arena"> <div class="ticket-gradient"></div> <div class="ticket-inner"> <h3 class="event-name">Premium Seating</h3> <div class="event-details"> <div><i>📅</i> Nov 15, 2023</div> <div><i>⏰</i> 7:00 PM</div> <div><i>📍</i> Nebula Arena</div> <div><i>✨</i> Center Rows 1-10</div> </div> <div class="ticket-price"> <span class="price">$59.99</span> <button class="select-btn">Select</button> </div> </div> </div> <div class="ticket" data-price="39.99" data-name="General Admission" data-date="Nov 15, 2023" data-time="7:00 PM" data-venue="Nebula Arena"> <div class="ticket-gradient"></div> <div class="ticket-inner"> <h3 class="event-name">General Admission</h3> <div class="event-details"> <div><i>📅</i> Nov 15, 2023</div> <div><i>⏰</i> 7:00 PM</div> <div><i>📍</i> Nebula Arena</div> <div><i>✨</i> Standard Seating</div> </div> <div class="ticket-price"> <span class="price">$39.99</span> <button class="select-btn">Select</button> </div> </div> </div> <div class="ticket" data-price="129.99" data-name="Ultimate Fan Package" data-date="Nov 15, 2023" data-time="7:00 PM" data-venue="Nebula Arena"> <div class="ticket-gradient"></div> <div class="ticket-inner"> <h3 class="event-name">Ultimate Fan Package</h3> <div class="event-details"> <div><i>📅</i> Nov 15, 2023</div> <div><i>⏰</i> 7:00 PM</div> <div><i>📍</i> Nebula Arena</div> <div><i>✨</i> VIP + Merchandise Bundle</div> </div> <div class="ticket-price"> <span class="price">$129.99</span> <button class="select-btn">Select</button> </div> </div> </div> </div> <div class="cart-container"> <div class="cart-header"> <h3 class="cart-title">Your Selected Tickets</h3> <div class="cart-count">0</div> </div> <div class="cart-items"> <div class="cart-empty">No tickets selected yet</div> </div> <div class="cart-total"> <span class="total-label">Total:</span> <span class="total-amount">$0.00</span> </div> <button class="checkout-btn">Proceed to Checkout</button> </div> </div> <script> document.addEventListener('DOMContentLoaded', function() { const tickets = document.querySelectorAll('.ticket'); const cartItems = document.querySelector('.cart-items'); const cartCount = document.querySelector('.cart-count'); const totalAmount = document.querySelector('.total-amount'); const checkoutBtn = document.querySelector('.checkout-btn'); let selectedTickets = []; // Initialize with empty cart message updateCartDisplay(); tickets.forEach(ticket => { const selectBtn = ticket.querySelector('.select-btn'); selectBtn.addEventListener('click', function() { if (ticket.classList.contains('selected')) { // Deselect the ticket ticket.classList.remove('selected'); ticket.classList.add('torn'); setTimeout(() => { ticket.classList.remove('torn'); }, 400); // Remove from selected tickets array const ticketName = ticket.dataset.name; selectedTickets = selectedTickets.filter(item => item.name !== ticketName); } else { // Select the ticket with flash animation ticket.classList.add('selected'); selectBtn.classList.add('pulse'); setTimeout(() => { selectBtn.classList.remove('pulse'); }, 1500); // Add to selected tickets array selectedTickets.push({ name: ticket.dataset.name, price: parseFloat(ticket.dataset.price), date: ticket.dataset.date, time: ticket.dataset.time, venue: ticket.dataset.venue }); } updateCartDisplay(); }); // Add 3D tilt effect on mousemove ticket.addEventListener('mousemove', function(e) { const rect = ticket.getBoundingClientRect(); const x = e.clientX - rect.left; const y = e.clientY - rect.top; const centerX = rect.width / 2; const centerY = rect.height / 2; const moveX = (x - centerX) / 20; const moveY = (y - centerY) / 20; ticket.style.transform = `perspective(1000px) rotateX(${-moveY}deg) rotateY(${moveX}deg) translateY(-5px)`; }); // Reset transform on mouseout ticket.addEventListener('mouseleave', function() { if (!ticket.classList.contains('selected')) { ticket.style.transform = 'perspective(1000px) rotateX(0) translateY(0)'; } else { ticket.style.transform = 'perspective(1000px) rotateX(0) translateY(0)'; } }); }); function updateCartDisplay() { // Update count cartCount.textContent = selectedTickets.length; // Clear cart items cartItems.innerHTML = ''; if (selectedTickets.length === 0) { cartItems.innerHTML = '<div class="cart-empty">No tickets selected yet</div>'; totalAmount.textContent = '$0.00'; checkoutBtn.disabled = true; checkoutBtn.style.opacity = '0.7'; } else { checkoutBtn.disabled = false; checkoutBtn.style.opacity = '1'; // Calculate total let total = 0; selectedTickets.forEach(ticket => { total += ticket.price; const cartItem = document.createElement('div'); cartItem.classList.add('cart-item'); cartItem.innerHTML = ` <div class="cart-item-info"> <div class="cart-item-name">${ticket.name}</div> <div class="cart-item-details">${ticket.date} at ${ticket.time}</div> </div> <div class="cart-item-price">$${ticket.price.toFixed(2)}</div> <button class="remove-btn" data-name="${ticket.name}">×</button> `; cartItems.appendChild(cartItem); }); totalAmount.textContent = `$${total.toFixed(2)}`; // Add event listeners to remove buttons const removeButtons = document.querySelectorAll('.remove-btn'); removeButtons.forEach(btn => { btn.addEventListener('click', function() { const ticketName = btn.dataset.name; // Find and "torn" the corresponding ticket before removing tickets.forEach(ticket => { if (ticket.dataset.name === ticketName) { ticket.classList.remove('selected'); ticket.classList.add('torn'); setTimeout(() => { ticket.classList.remove('torn'); }, 400); } }); // Remove from selected tickets selectedTickets = selectedTickets.filter(item => item.name !== ticketName); // Update cart updateCartDisplay(); }); }); } } // Checkout button animation and functionality checkoutBtn.addEventListener('click', function(e) { if (selectedTickets.length === 0) return; // Create ripple effect const ripple = document.createElement('span'); ripple.classList.add('ripple'); this.appendChild(ripple); // Show success message const successMessage = document.createElement('div'); successMessage.style.position = 'fixed'; successMessage.style.top = '50%'; successMessage.style.left = '50%'; successMessage.style.transform = 'translate(-50%, -50%)'; successMessage.style.background = 'rgba(0, 0, 0, 0.8)'; successMessage.style.color = '#fff'; successMessage.style.padding = '20px'; successMessage.style.borderRadius = '10px'; successMessage.style.zIndex = '1000'; successMessage.style.textAlign = 'center'; successMessage.innerHTML = '<h3 style="margin-bottom: 10px;">Checkout Successful!</h3><p>Your tickets have been reserved.</p>'; document.body.appendChild(successMessage); setTimeout(() => { document.body.removeChild(successMessage); }, 2000); }); }); </script> </body> </html>
<html> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>BugFlow | Bug Tracking System</title> <style> :root { --color-primary: #3F51B5; --color-primary-light: #7986CB; --color-primary-dark: #303F9F; --color-secondary: #2196F3; --color-success: #4CAF50; --color-warning: #FF9800; --color-danger: #F44336; --color-info: #00BCD4; --color-light: #F5F7FA; --color-dark: #272D3B; --color-gray: #EEEEEE; --color-text: #333; --color-text-light: #777; --shadow-sm: 0 1px 3px rgba(0,0,0,0.12), 0 1px 2px rgba(0,0,0,0.24); --shadow-md: 0 4px 6px rgba(0,0,0,0.1), 0 1px 3px rgba(0,0,0,0.08); --shadow-lg: 0 10px 15px -3px rgba(0,0,0,0.1), 0 4px 6px -2px rgba(0,0,0,0.05); --transition: all 0.3s cubic-bezier(0.25, 0.8, 0.25, 1); --border-radius: 8px; } * { margin: 0; padding: 0; box-sizing: border-box; font-family: 'Inter', -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif; } body { background-color: #f9fafb; color: var(--color-text); display: flex; flex-direction: column; height: 100vh; overflow: hidden; } .container { max-width: 700px; margin: 0 auto; padding: 10px; height: 100%; display: flex; flex-direction: column; } header { display: flex; justify-content: space-between; align-items: center; padding: 12px 0; border-bottom: 1px solid #eee; margin-bottom: 12px; } .logo { display: flex; align-items: center; gap: 8px; font-weight: 600; font-size: 1.2rem; color: var(--color-primary); } .logo-icon { background-color: var(--color-primary); color: white; width: 32px; height: 32px; border-radius: 8px; display: flex; align-items: center; justify-content: center; } .search-bar { display: flex; align-items: center; background-color: white; border-radius: 6px; padding: 6px 12px; box-shadow: var(--shadow-sm); transition: var(--transition); border: 1px solid #eee; flex: 1; max-width: 240px; } .search-bar:focus-within { box-shadow: 0 0 0 2px var(--color-primary-light); border-color: var(--color-primary-light); } .search-bar input { border: none; outline: none; width: 100%; padding: 6px; font-size: 0.9rem; } .search-icon { color: var(--color-text-light); margin-right: 6px; } .filters { display: flex; gap: 10px; margin-bottom: 15px; flex-wrap: wrap; } .filter { padding: 6px 12px; background-color: white; border-radius: var(--border-radius); box-shadow: var(--shadow-sm); cursor: pointer; font-size: 0.8rem; transition: var(--transition); display: flex; align-items: center; gap: 6px; border: 1px solid #e5e7eb; } .filter:hover { transform: translateY(-1px); box-shadow: var(--shadow-md); } .filter.active { background-color: var(--color-primary); color: white; border-color: var(--color-primary); } .tickets-container { flex: 1; overflow-y: auto; display: flex; flex-direction: column; gap: 12px; padding-right: 6px; mask-image: linear-gradient(to bottom, transparent, black 10px, black 90%, transparent); -webkit-mask-image: linear-gradient(to bottom, transparent, black 10px, black 90%, transparent); padding-top: 5px; padding-bottom: 10px; } .tickets-container::-webkit-scrollbar { width: 8px; } .tickets-container::-webkit-scrollbar-track { background: #f1f1f1; border-radius: 10px; } .tickets-container::-webkit-scrollbar-thumb { background: #c5c5c5; border-radius: 10px; } .tickets-container::-webkit-scrollbar-thumb:hover { background: #a8a8a8; } .ticket { background-color: white; border-radius: var(--border-radius); box-shadow: var(--shadow-sm); padding: 16px; transition: var(--transition); cursor: pointer; position: relative; overflow: hidden; border: 1px solid #eee; } .ticket:hover { transform: translateY(-2px); box-shadow: var(--shadow-md); } .ticket-header { display: flex; justify-content: space-between; align-items: flex-start; margin-bottom: 12px; } .ticket-id { font-size: 0.8rem; color: var(--color-text-light); font-weight: 500; } .status-badge { padding: 4px 8px; border-radius: 12px; font-size: 0.7rem; font-weight: 600; display: inline-flex; align-items: center; gap: 4px; } .status-badge.new { background-color: rgba(33, 150, 243, 0.15); color: var(--color-secondary); } .status-badge.in-progress { background-color: rgba(255, 152, 0, 0.15); color: var(--color-warning); } .status-badge.resolved { background-color: rgba(76, 175, 80, 0.15); color: var(--color-success); } .status-badge.critical { background-color: rgba(244, 67, 54, 0.15); color: var(--color-danger); } .ticket-title { font-weight: 600; margin-bottom: 8px; font-size: 1rem; } .ticket-description { color: var(--color-text-light); font-size: 0.9rem; margin-bottom: 16px; line-height: 1.4; } .ticket-meta { display: flex; justify-content: space-between; font-size: 0.8rem; color: var(--color-text-light); } .ticket-assignee { display: flex; align-items: center; gap: 6px; } .avatar { width: 24px; height: 24px; border-radius: 50%; background-color: var(--color-primary-light); display: flex; align-items: center; justify-content: center; color: white; font-size: 0.7rem; font-weight: 600; } .ticket-priority { display: flex; align-items: center; gap: 6px; } .priority-indicator { display: flex; gap: 2px; } .priority-dot { width: 6px; height: 6px; border-radius: 50%; background-color: #ddd; } .priority-dot.filled { background-color: var(--color-danger); } .ticket-tag { display: inline-block; padding: 3px 8px; background-color: var(--color-gray); border-radius: 4px; font-size: 0.7rem; margin-right: 6px; color: var(--color-text); } .ticket-actions { display: flex; gap: 8px; margin-top: 16px; } .ticket-btn { padding: 6px 12px; border-radius: 4px; background-color: var(--color-light); border: 1px solid #e5e7eb; cursor: pointer; transition: var(--transition); font-size: 0.75rem; display: flex; align-items: center; gap: 4px; } .ticket-btn:hover { background-color: #e5e7eb; } .ticket-btn.primary { background-color: var(--color-primary); color: white; border-color: var(--color-primary); } .ticket-btn.primary:hover { background-color: var(--color-primary-dark); } .ticket-time { font-size: 0.75rem; color: var(--color-text-light); } .ticket::before { content: ''; position: absolute; top: 0; left: 0; width: 4px; height: 100%; } .ticket.new::before { background-color: var(--color-secondary); } .ticket.in-progress::before { background-color: var(--color-warning); } .ticket.resolved::before { background-color: var(--color-success); } .ticket.critical::before { background-color: var(--color-danger); } .add-btn { position: fixed; bottom: 20px; right: 20px; width: 56px; height: 56px; border-radius: 50%; background-color: var(--color-primary); color: white; display: flex; align-items: center; justify-content: center; box-shadow: var(--shadow-lg); cursor: pointer; transition: var(--transition); border: none; font-size: 1.5rem; } .add-btn:hover { transform: scale(1.05); background-color: var(--color-primary-dark); } .ticket.expanded { border-color: var(--color-primary-light); } .ticket-tags { display: flex; flex-wrap: wrap; gap: 6px; margin-bottom: 12px; } .status-dropdown { position: absolute; top: calc(100% + 5px); right: 10px; background-color: white; border-radius: var(--border-radius); box-shadow: var(--shadow-md); overflow: hidden; z-index: 10; display: none; animation: slideIn 0.2s ease-out; } .status-dropdown.active { display: block; } .status-option { padding: 8px 16px; font-size: 0.8rem; cursor: pointer; transition: background-color 0.2s; display: flex; align-items: center; gap: 8px; } .status-option:hover { background-color: var(--color-gray); } .status-dot { width: 8px; height: 8px; border-radius: 50%; } .status-dot.new { background-color: var(--color-secondary); } .status-dot.in-progress { background-color: var(--color-warning); } .status-dot.resolved { background-color: var(--color-success); } .status-dot.critical { background-color: var(--color-danger); } @keyframes slideIn { from { opacity: 0; transform: translateY(-10px); } to { opacity: 1; transform: translateY(0); } } @keyframes pulse { 0% { box-shadow: 0 0 0 0 rgba(63, 81, 181, 0.7); } 70% { box-shadow: 0 0 0 10px rgba(63, 81, 181, 0); } 100% { box-shadow: 0 0 0 0 rgba(63, 81, 181, 0); } } .ticket-highlight { animation: pulse 1.5s infinite; } /* Modal */ .modal-overlay { position: fixed; top: 0; left: 0; right: 0; bottom: 0; background-color: rgba(0, 0, 0, 0.5); display: flex; align-items: center; justify-content: center; z-index: 1000; opacity: 0; visibility: hidden; transition: all 0.3s; } .modal-overlay.active { opacity: 1; visibility: visible; } .modal { background-color: white; border-radius: var(--border-radius); width: 90%; max-width: 500px; max-height: 90vh; overflow-y: auto; padding: 24px; position: relative; transform: translateY(20px); transition: all 0.3s; } .modal-overlay.active .modal { transform: translateY(0); } .modal-header { display: flex; justify-content: space-between; align-items: center; margin-bottom: 20px; } .modal-title { font-size: 1.2rem; font-weight: 600; color: var(--color-primary); } .modal-close { background: none; border: none; font-size: 1.5rem; cursor: pointer; color: var(--color-text-light); } .form-group { margin-bottom: 16px; } .form-label { display: block; margin-bottom: 6px; font-weight: 500; font-size: 0.9rem; } .form-input { width: 100%; padding: 10px; border-radius: var(--border-radius); border: 1px solid #ddd; font-size: 0.9rem; transition: var(--transition); } .form-input:focus { outline: none; border-color: var(--color-primary-light); box-shadow: 0 0 0 2px rgba(63, 81, 181, 0.2); } .form-textarea { min-height: 100px; resize: vertical; } .form-select { width: 100%; padding: 10px; border-radius: var(--border-radius); border: 1px solid #ddd; font-size: 0.9rem; transition: var(--transition); appearance: none; background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 24 24' fill='none' stroke='%23333' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='6 9 12 15 18 9'%3E%3C/polyline%3E%3C/svg%3E"); background-repeat: no-repeat; background-position: right 10px center; background-size: 16px; } .form-select:focus { outline: none; border-color: var(--color-primary-light); box-shadow: 0 0 0 2px rgba(63, 81, 181, 0.2); } .form-actions { display: flex; justify-content: flex-end; gap: 10px; margin-top: 24px; } .btn { padding: 10px 16px; border-radius: var(--border-radius); font-size: 0.9rem; font-weight: 500; cursor: pointer; transition: var(--transition); border: none; } .btn-secondary { background-color: var(--color-light); color: var(--color-text); } .btn-secondary:hover { background-color: #e5e7eb; } .btn-primary { background-color: var(--color-primary); color: white; } .btn-primary:hover { background-color: var(--color-primary-dark); } /* For very small screens */ @media (max-width: 400px) { .filters { gap: 6px; } .filter { padding: 4px 8px; font-size: 0.7rem; } .ticket { padding: 12px; } .ticket-title { font-size: 0.9rem; } .ticket-description { font-size: 0.8rem; } .search-bar { max-width: 140px; } } /* Animations and Effects */ .ripple { position: relative; overflow: hidden; } .ripple-effect { position: absolute; border-radius: 50%; background-color: rgba(255, 255, 255, 0.4); transform: scale(0); animation: ripple-animation 0.6s linear; z-index: 0; } @keyframes ripple-animation { to { transform: scale(2.5); opacity: 0; } } /* Badge for new tickets */ .new-badge { position: absolute; top: -5px; right: -5px; background-color: var(--color-danger); color: white; border-radius: 50%; width: 20px; height: 20px; display: flex; align-items: center; justify-content: center; font-size: 0.7rem; font-weight: 600; box-shadow: var(--shadow-sm); transform: scale(0); animation: pop-in 0.3s forwards; } @keyframes pop-in { 0% { transform: scale(0); } 80% { transform: scale(1.2); } 100% { transform: scale(1); } } /* Empty state */ .empty-state { display: flex; flex-direction: column; align-items: center; justify-content: center; padding: 40px 20px; text-align: center; color: var(--color-text-light); display: none; } .empty-state svg { margin-bottom: 16px; color: var(--color-primary-light); } .empty-state h3 { margin-bottom: 8px; font-weight: 600; } .empty-state p { margin-bottom: 16px; font-size: 0.9rem; } </style> </head> <body> <div class="container"> <header> <div class="logo"> <div class="logo-icon"> <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"> <path d="M12 19l7-7 3 3-7 7-3-3z"></path> <path d="M18 13l-1.5-7.5L2 2l3.5 14.5L13 18l5-5z"></path> <path d="M2 2l7.586 7.586"></path> <circle cx="11" cy="11" r="2"></circle> </svg> </div> <span>BugFlow</span> </div> <div class="search-bar"> <div class="search-icon"> <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"> <circle cx="11" cy="11" r="8"></circle> <line x1="21" y1="21" x2="16.65" y2="16.65"></line> </svg> </div> <input type="text" placeholder="Search tickets..." id="search-input"> </div> </header> <div class="filters"> <div class="filter active ripple" data-filter="all"> <svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"> <line x1="8" y1="6" x2="21" y2="6"></line> <line x1="8" y1="12" x2="21" y2="12"></line> <line x1="8" y1="18" x2="21" y2="18"></line> <line x1="3" y1="6" x2="3.01" y2="6"></line> <line x1="3" y1="12" x2="3.01" y2="12"></line> <line x1="3" y1="18" x2="3.01" y2="18"></line> </svg> All Tickets </div> <div class="filter ripple" data-filter="new"> <svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"> <circle cx="12" cy="12" r="10"></circle> <polyline points="12 6 12 12 16 14"></polyline> </svg> New </div> <div class="filter ripple" data-filter="in-progress"> <svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"> <polyline points="1 4 1 10 7 10"></polyline> <polyline points="23 20 23 14 17 14"></polyline> <path d="M20.49 9A9 9 0 0 0 5.64 5.64L1 10m22 4l-4.64 4.36A9 9 0 0 1 3.51 15"></path> </svg> In Progress </div> <div class="filter ripple" data-filter="critical"> <svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"> <polygon points="7.86 2 16.14 2 22 7.86 22 16.14 16.14 22 7.86 22 2 16.14 2 7.86 7.86 2"></polygon> <line x1="12" y1="8" x2="12" y2="12"></line> <line x1="12" y1="16" x2="12.01" y2="16"></line> </svg> Critical </div> <div class="filter ripple" data-filter="resolved"> <svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"> <path d="M22 11.08V12a10 10 0 1 1-5.93-9.14"></path> <polyline points="22 4 12 14.01 9 11.01"></polyline> </svg> Resolved </div> </div> <div class="tickets-container" id="tickets-container"> <!-- Ticket 1 --> <div class="ticket new" data-status="new"> <div class="ticket-header"> <span class="ticket-id">BUG-1024</span> <div class="status-badge new change-status" data-ticket="BUG-1024"> <svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"> <circle cx="12" cy="12" r="10"></circle> <polyline points="12 6 12 12 16 14"></polyline> </svg> New </div> </div> <h3 class="ticket-title">API Authentication Token Expires Too Quickly</h3> <div class="ticket-tags"> <span class="ticket-tag">API</span> <span class="ticket-tag">Authentication</span> </div> <p class="ticket-description">Users report that their API tokens are expiring after 30 minutes instead of the promised 24 hours. This requires constant re-authentication and disrupts automated workflows.</p> <div class="ticket-meta"> <div class="ticket-assignee"> <div class="avatar">JD</div> <span>Jane Doe</span> </div> <div class="ticket-priority"> <span>Priority:</span> <div class="priority-indicator"> <span class="priority-dot filled"></span> <span class="priority-dot filled"></span> <span class="priority-dot"></span> </div> </div> </div> <div class="ticket-actions"> <button class="ticket-btn"> <svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"> <path d="M11 4H4a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2v-7"></path> <path d="M18.5 2.5a2.121 2.121 0 0 1 3 3L12 15l-4 1 1-4 9.5-9.5z"></path> </svg> Comment </button> <button class="ticket-btn primary"> <svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"> <polyline points="9 11 12 14 22 4"></polyline> <path d="M21 12v7a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h11"></path> </svg> Take Action </button> </div> <div class="status-dropdown" id="dropdown-BUG-1024"> <div class="status-option" data-status="new"> <span class="status-dot new"></span> New </div> <div class="status-option" data-status="in-progress"> <span class="status-dot in-progress"></span> In Progress </div> <div class="status-option" data-status="critical"> <span class="status-dot critical"></span> Critical </div> <div class="status-option" data-status="resolved"> <span class="status-dot resolved"></span> Resolved </div> </div> </div> <!-- Ticket 2 --> <div class="ticket in-progress" data-status="in-progress"> <div class="ticket-header"> <span class="ticket-id">BUG-1023</span> <div class="status-badge in-progress change-status" data-ticket="BUG-1023"> <svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"> <polyline points="1 4 1 10 7 10"></polyline> <polyline points="23 20 23 14 17 14"></polyline> <path d="M20.49 9A9 9 0 0 0 5.64 5.64L1 10m22 4l-4.64 4.36A9 9 0 0 1 3.51 15"></path> </svg> In Progress </div> </div> <h3 class="ticket-title">Dashboard Metrics Not Updating in Real-Time</h3> <div class="ticket-tags"> <span class="ticket-tag">Dashboard</span> <span class="ticket-tag">Real-Time</span> </div> <p class="ticket-description">Users are experiencing a 5-minute delay in dashboard metric updates. The system should refresh data every 30 seconds according to specifications.</p> <div class="ticket-meta"> <div class="ticket-assignee"> <div class="avatar">MS</div> <span>Mike Smith</span> </div> <div class="ticket-priority"> <span>Priority:</span> <div class="priority-indicator"> <span class="priority-dot filled"></span> <span class="priority-dot filled"></span> <span class="priority-dot filled"></span> </div> </div> </div> <div class="ticket-actions"> <button class="ticket-btn"> <svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"> <path d="M11 4H4a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2v-7"></path> <path d="M18.5 2.5a2.121 2.121 0 0 1 3 3L12 15l-4 1 1-4 9.5-9.5z"></path> </svg> Comment </button> <button class="ticket-btn primary"> <svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"> <polyline points="9 11 12 14 22 4"></polyline> <path d="M21 12v7a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h11"></path> </svg> Take Action </button> </div> <div class="status-dropdown" id="dropdown-BUG-1023"> <div class="status-option" data-status="new"> <span class="status-dot new"></span> New </div> <div class="status-option" data-status="in-progress"> <span class="status-dot in-progress"></span> In Progress </div> <div class="status-option" data-status="critical"> <span class="status-dot critical"></span> Critical </div> <div class="status-option" data-status="resolved"> <span class="status-dot resolved"></span> Resolved </div> </div> </div> <!-- Ticket 3 --> <div class="ticket critical" data-status="critical"> <div class="ticket-header"> <span class="ticket-id">BUG-1022</span> <div class="status-badge critical change-status" data-ticket="BUG-1022"> <svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"> <polygon points="7.86 2 16.14 2 22 7.86 22 16.14 16.14 22 7.86 22 2 16.14 2 7.86 7.86 2"></polygon> <line x1="12" y1="8" x2="12" y2="12"></line> <line x1="12" y1="16" x2="12.01" y2="16"></line> </svg> Critical </div> </div> <h3 class="ticket-title">Payment Processing Failure on Checkout</h3> <div class="ticket-tags"> <span class="ticket-tag">Payment</span> <span class="ticket-tag">Critical</span> </div> <p class="ticket-description">Customers are unable to complete purchases. The payment gateway integration is returning error code 5023 when processing Visa cards. Revenue impact estimated at $20K/hour.</p> <div class="ticket-meta"> <div class="ticket-assignee"> <div class="avatar">KL</div> <span>Kevin Lee</span> </div> <div class="ticket-priority"> <span>Priority:</span> <div class="priority-indicator"> <span class="priority-dot filled"></span> <span class="priority-dot filled"></span> <span class="priority-dot filled"></span> </div> </div> </div> <div class="ticket-actions"> <button class="ticket-btn"> <svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"> <path d="M11 4H4a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2v-7"></path> <path d="M18.5 2.5a2.121 2.121 0 0 1 3 3L12 15l-4 1 1-4 9.5-9.5z"></path> </svg> Comment </button
<html> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Horizon HR Portal</title> <style> :root { --primary: #2c3e50; --secondary: #34495e; --accent: #3498db; --accent-light: #5dade2; --light: #ecf0f1; --gray-light: #f5f7fa; --gray: #bdc3c7; --success: #27ae60; --warning: #f39c12; --danger: #e74c3c; --info: #2980b9; --font-main: 'Inter', -apple-system, BlinkMacSystemFont, sans-serif; --shadow-sm: 0 1px 3px rgba(0,0,0,0.08); --shadow: 0 4px 6px rgba(0,0,0,0.1); --shadow-lg: 0 10px 15px -3px rgba(0,0,0,0.1); --transition: all 0.3s ease; } * { margin: 0; padding: 0; box-sizing: border-box; } body { font-family: var(--font-main); background-color: var(--gray-light); color: var(--primary); line-height: 1.6; display: flex; flex-direction: column; height: 100vh; overflow-x: hidden; max-width: 700px; margin: 0 auto; position: relative; } .portal-container { display: flex; flex-direction: column; height: 100%; max-height: 700px; overflow: hidden; background: #fff; border-radius: 8px; box-shadow: var(--shadow-lg); } header { padding: 1.2rem 1.5rem; background: var(--primary); color: white; display: flex; justify-content: space-between; align-items: center; border-top-left-radius: 8px; border-top-right-radius: 8px; } .logo { display: flex; align-items: center; gap: 12px; } .logo-icon { width: 30px; height: 30px; background: var(--accent); border-radius: 6px; display: flex; align-items: center; justify-content: center; } .logo-text { font-size: 1.25rem; font-weight: 600; letter-spacing: -0.5px; } .user-info { display: flex; align-items: center; gap: 12px; } .user-avatar { width: 32px; height: 32px; border-radius: 50%; background: var(--accent); display: flex; align-items: center; justify-content: center; font-weight: 600; font-size: 0.875rem; } .tab-nav { background: var(--secondary); padding: 0 1.5rem; display: flex; gap: 1.5rem; } .tab-link { color: rgba(255,255,255,0.7); text-decoration: none; padding: 0.875rem 0; font-size: 0.9rem; font-weight: 500; position: relative; transition: var(--transition); } .tab-link.active { color: white; } .tab-link.active:after { content: ''; position: absolute; bottom: 0; left: 0; right: 0; height: 3px; background: var(--accent); border-top-left-radius: 3px; border-top-right-radius: 3px; } .tab-link:hover { color: white; } .content { padding: 1.5rem; overflow-y: auto; flex: 1; } .filters { display: flex; align-items: center; margin-bottom: 1.5rem; gap: 12px; flex-wrap: wrap; } .search-container { flex: 1; min-width: 200px; position: relative; } .search-icon { position: absolute; left: 12px; top: 50%; transform: translateY(-50%); color: var(--gray); } .search-input { width: 100%; padding: 0.625rem 0.625rem 0.625rem 2.5rem; border: 1px solid var(--gray); border-radius: 6px; font-size: 0.875rem; transition: var(--transition); } .search-input:focus { outline: none; border-color: var(--accent); box-shadow: 0 0 0 3px rgba(52, 152, 219, 0.2); } .filter-btn { padding: 0.625rem 1rem; background: var(--light); border: 1px solid var(--gray); border-radius: 6px; font-size: 0.875rem; font-weight: 500; color: var(--primary); cursor: pointer; display: flex; align-items: center; gap: 8px; transition: var(--transition); } .filter-btn:hover { background: var(--gray-light); } .filter-btn.active { background: var(--accent); color: white; border-color: var(--accent); } .tickets-container { display: flex; flex-direction: column; gap: 12px; } .ticket { border: 1px solid var(--gray); border-radius: 8px; padding: 1rem; transition: var(--transition); position: relative; overflow: hidden; } .ticket:hover { box-shadow: var(--shadow); border-color: var(--accent-light); } .ticket-header { display: flex; justify-content: space-between; align-items: flex-start; margin-bottom: 0.5rem; } .ticket-title { font-size: 1rem; font-weight: 600; color: var(--primary); flex: 1; } .ticket-title[contenteditable="true"] { border-bottom: 2px solid var(--accent); outline: none; padding-bottom: 2px; } .ticket-id { font-size: 0.75rem; color: var(--gray); font-weight: 500; } .ticket-body { display: flex; gap: 1rem; flex-wrap: wrap; } .ticket-info { flex: 1; min-width: 200px; } .ticket-description { font-size: 0.875rem; margin-bottom: 0.75rem; line-height: 1.5; color: var(--secondary); } .ticket-meta { display: flex; gap: 1rem; font-size: 0.8125rem; color: var(--secondary); } .ticket-meta-item { display: flex; align-items: center; gap: 4px; } .ticket-meta-item i { font-size: 0.875rem; color: var(--accent); } .ticket-progress { width: 180px; } .progress-label { display: flex; justify-content: space-between; font-size: 0.75rem; font-weight: 500; margin-bottom: 0.5rem; } .progress-status { color: var(--primary); } .progress-percentage { color: var(--accent); } .progress-bar-container { height: 6px; background: var(--light); border-radius: 6px; overflow: hidden; } .progress-bar { height: 100%; background: var(--accent); border-radius: 6px; transition: width 0.5s ease; } .progress-steps { display: flex; justify-content: space-between; margin-top: 10px; position: relative; } .progress-steps:before { content: ''; position: absolute; top: 7px; left: 18px; right: 18px; height: 2px; background: var(--light); z-index: 1; } .progress-step { width: 16px; height: 16px; background: var(--light); border: 2px solid var(--gray); border-radius: 50%; z-index: 2; position: relative; transition: var(--transition); } .progress-step.active { background: var(--accent); border-color: var(--accent); } .progress-step.completed { background: var(--success); border-color: var(--success); } .progress-step-tooltip { position: absolute; bottom: 24px; left: 50%; transform: translateX(-50%); background: var(--primary); color: white; padding: 4px 8px; border-radius: 4px; font-size: 0.75rem; white-space: nowrap; opacity: 0; visibility: hidden; transition: var(--transition); } .progress-step-tooltip:after { content: ''; position: absolute; top: 100%; left: 50%; transform: translateX(-50%); border-width: 4px; border-style: solid; border-color: var(--primary) transparent transparent transparent; } .progress-step:hover .progress-step-tooltip { opacity: 1; visibility: visible; } .ticket-actions { display: flex; justify-content: flex-end; margin-top: 1rem; gap: 8px; } .action-btn { padding: 0.375rem 0.75rem; border-radius: 4px; font-size: 0.75rem; font-weight: 500; cursor: pointer; border: none; display: flex; align-items: center; gap: 4px; transition: var(--transition); } .action-btn-primary { background: var(--accent); color: white; } .action-btn-primary:hover { background: var(--accent-light); } .action-btn-secondary { background: var(--light); color: var(--primary); } .action-btn-secondary:hover { background: var(--gray); color: var(--secondary); } .new-ticket-btn { position: fixed; bottom: 2rem; right: 2rem; width: 56px; height: 56px; border-radius: 50%; background: var(--accent); color: white; display: flex; align-items: center; justify-content: center; box-shadow: var(--shadow-lg); cursor: pointer; transition: var(--transition); z-index: 10; } .new-ticket-btn:hover { background: var(--accent-light); transform: translateY(-3px); } .tag { display: inline-flex; align-items: center; padding: 2px 8px; border-radius: 4px; font-size: 0.75rem; font-weight: 500; margin-right: 6px; } .tag-hr { background: rgba(52, 152, 219, 0.1); color: var(--accent); } .tag-payroll { background: rgba(241, 196, 15, 0.1); color: var(--warning); } .tag-benefits { background: rgba(39, 174, 96, 0.1); color: var(--success); } .tag-urgent { background: rgba(231, 76, 60, 0.1); color: var(--danger); } /* Modal styles */ .modal { position: fixed; top: 0; left: 0; width: 100%; height: 100%; background: rgba(0, 0, 0, 0.5); display: flex; align-items: center; justify-content: center; z-index: 100; opacity: 0; visibility: hidden; transition: all 0.3s ease; } .modal.active { opacity: 1; visibility: visible; } .modal-content { background: white; border-radius: 8px; width: 90%; max-width: 500px; max-height: 80vh; overflow-y: auto; box-shadow: var(--shadow-lg); transform: translateY(20px); transition: all 0.3s ease; } .modal.active .modal-content { transform: translateY(0); } .modal-header { padding: 1.25rem 1.5rem; border-bottom: 1px solid var(--gray); display: flex; justify-content: space-between; align-items: center; } .modal-title { font-size: 1.25rem; font-weight: 600; color: var(--primary); } .modal-close { background: none; border: none; cursor: pointer; color: var(--gray); font-size: 1.25rem; transition: var(--transition); } .modal-close:hover { color: var(--danger); } .modal-body { padding: 1.5rem; } .form-group { margin-bottom: 1.25rem; } .form-label { display: block; margin-bottom: 0.5rem; font-size: 0.875rem; font-weight: 500; color: var(--secondary); } .form-control { width: 100%; padding: 0.625rem; border: 1px solid var(--gray); border-radius: 6px; font-family: var(--font-main); font-size: 0.875rem; transition: var(--transition); } .form-control:focus { outline: none; border-color: var(--accent); box-shadow: 0 0 0 3px rgba(52, 152, 219, 0.2); } .form-select { width: 100%; padding: 0.625rem; border: 1px solid var(--gray); border-radius: 6px; font-family: var(--font-main); font-size: 0.875rem; appearance: none; background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' fill='%23bdc3c7' viewBox='0 0 16 16'%3E%3Cpath d='M7.247 11.14 2.451 5.658C1.885 5.013 2.345 4 3.204 4h9.592a1 1 0 0 1 .753 1.659l-4.796 5.48a1 1 0 0 1-1.506 0z'/%3E%3C/svg%3E"); background-repeat: no-repeat; background-position: right 12px center; transition: var(--transition); } .form-select:focus { outline: none; border-color: var(--accent); box-shadow: 0 0 0 3px rgba(52, 152, 219, 0.2); } .modal-footer { padding: 1rem 1.5rem; border-top: 1px solid var(--gray); display: flex; justify-content: flex-end; gap: 12px; } .loading-indicator { position: absolute; top: 0; left: 0; width: 0; height: 2px; background: linear-gradient(90deg, var(--accent) 0%, var(--accent-light) 100%); z-index: 10; transition: width 0.5s ease; } .shimmer-effect { position: absolute; top: 0; left: 0; width: 100%; height: 100%; background: linear-gradient( 90deg, rgba(255, 255, 255, 0) 0%, rgba(255, 255, 255, 0.6) 50%, rgba(255, 255, 255, 0) 100% ); animation: shimmer 2s infinite; } @keyframes shimmer { 0% { transform: translateX(-100%); } 100% { transform: translateX(100%); } } .notification { position: fixed; top: 20px; right: 20px; padding: 1rem; background: white; border-radius: 6px; box-shadow: var(--shadow-lg); display: flex; align-items: center; gap: 10px; z-index: 200; transform: translateY(-20px); opacity: 0; transition: all 0.3s ease; } .notification.show { transform: translateY(0); opacity: 1; } .notification-icon { width: 24px; height: 24px; border-radius: 50%; background: var(--success); color: white; display: flex; align-items: center; justify-content: center; font-size: 0.875rem; } .notification-message { font-size: 0.875rem; font-weight: 500; } @media (max-width: 600px) { .ticket-body { flex-direction: column; } .ticket-progress { width: 100%; } .tab-nav { overflow-x: auto; -webkit-overflow-scrolling: touch; scroll-behavior: smooth; padding-bottom: 4px; } .tab-link { white-space: nowrap; } .filters { flex-direction: column; align-items: stretch; } } /* Custom scrollbar */ .content::-webkit-scrollbar { width: 8px; } .content::-webkit-scrollbar-track { background: var(--gray-light); } .content::-webkit-scrollbar-thumb { background: var(--gray); border-radius: 4px; } .content::-webkit-scrollbar-thumb:hover { background: var(--secondary); } /* Utilities */ .text-success { color: var(--success); } .text-warning { color: var(--warning); } .text-danger { color: var(--danger); } .text-info { color: var(--info); } .text-primary { color: var(--primary); } .text-secondary { color: var(--secondary); } .ml-auto { margin-left: auto; } .font-weight-bold { font-weight: 600; } .font-weight-medium { font-weight: 500; } .text-sm { font-size: 0.875rem; } .text-xs { font-size: 0.75rem; } </style> </head> <body> <div class="portal-container"> <header> <div class="logo"> <div class="logo-icon"> <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" viewBox="0 0 16 16"> <path d="M8 11a3 3 0 1 0 0-6 3 3 0 0 0 0 6z"/> <path d="M4.285 9.567a4 4 0 0 1 7.43 0 .5.5 0 0 1-.858.514 3 3 0 0 0-5.714 0 .5.5 0 0 1-.858-.514z"/> <path d="M8 2a6 6 0 1 0 0 12A6 6 0 0 0 8 2zm0 1a5 5 0 1 1 0 10A5 5 0 0 1 8 3z"/> </svg> </div> <span class="logo-text">Horizon HR</span> </div> <div class="user-info"> <span class="text-sm">Sarah Chen</span> <div class="user-avatar">SC</div> </div> </header> <nav class="tab-nav"> <a href="#" class="tab-link active">My Requests</a> <a href="#" class="tab-link">Approvals</a> <a href="#" class="tab-link">Team View</a> <a href="#" class="tab-link">Analytics</a> </nav> <div class="loading-indicator" id="loadingIndicator"></div> <main class="content"> <div class="filters"> <div class="search-container"> <div class="search-icon"> <svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" fill="currentColor" viewBox="0 0 16 16"> <path d="M11.742 10.344a6.5 6.5 0 1 0-1.397 1.398h-.001c.03.04.062.078.098.115l3.85 3.85a1 1 0 0 0 1.415-1.414l-3.85-3.85a1.007 1.007 0 0 0-.115-.1zM12 6.5a5.5 5.5 0 1 1-11 0 5.5 5.5 0 0 1 11 0z"/> </svg> </div> <input type="text" class="search-input" placeholder="Search requests..."> </div> <button class="filter-btn active"> <svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" fill="currentColor" viewBox="0 0 16 16"> <path d="M14 1a1 1 0 0 1 1 1v12a1 1 0 0 1-1 1H2a1 1 0 0 1-1-1V2a1 1 0 0 1 1-1h12zM2 0a2 2 0 0 0-2 2v12a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V2a2 2 0 0 0-2-2H2z"/> <path d="M8 4a.5.5 0 0 1 .5.5v3h3a.5.5 0 0 1 0 1h-3v3a.5.5 0 0 1-1 0v-3h-3a.5.5 0 0 1 0-1h3v-3A.5.5 0 0 1 8 4z"/> </svg> All </button> <button class="filter-btn"> <svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" fill="currentColor" viewBox="0 0 16 16"> <path d="M8 9.5a1.5 1.5 0 1 0 0-3 1.5 1.5 0 0 0 0 3z"/> </svg> In Progress </button> <button class="filter-btn"> <svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" fill="currentColor" viewBox="0 0 16 16"> <path d="M10.97 4.97a.75.75 0 0 1 1.07 1.05l-3.99 4.99a.75.75 0 0 1-1.08.02L4.324 8.384a.75.75 0 1 1 1.06-1.06l2.094 2.093 3.473-4.425a.267.267 0 0 1 .02-.022z"/> </svg> Approved </button> </div> <div class="tickets-container"> <div class="ticket"> <div class="ticket-header"> <h3 class="ticket-title" id="title-1">Parental Leave Application</h3> <span class="ticket-id">REQ-2023-0472</span> </div> <div class="ticket-body"> <div class="ticket-info"> <p class="ticket-description">Request for 12 weeks of parental leave starting January 15th, 2024. All required documentation has been uploaded to the benefits portal.</p> <div class="ticket-meta"> <div class="ticket-meta-item"> <i> <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> </i> <span>Nov 23, 2023</span> </div> <div class="ticket-meta-item"> <i> <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> </i> <span>Michael Torres</span> </div> <div class="tag tag-benefits">Benefits</div> </div> </div> <div class="ticket-progress"> <div class="progress-label"> <span class="progress-status">Approval in Progress</span> <span class="progress-percentage">65%</span> </div> <div class="progress-bar-container"> <div class="progress-bar" style="width: 65%;"></div> </div> <div class="progress-steps"> <div class="progress-step completed"> <div class="progress-step-tooltip">Submitted</div> </div> <div class="progress-step completed"> <div class="progress-step-tooltip">HR Review</div> </div> <div class="progress-step active"> <div class="progress-step-tooltip">Manager Approval</div> </div> <div class="progress-step"> <div class="progress-step-tooltip">Benefits Processing</div> </div> <div class="progress-step"> <div class="progress-step-tooltip">Completed</div> </div> </div> </div> </div> <div class="ticket-actions"> <button class="action-btn action-btn-secondary edit-ticket" data-id="1"> <svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" fill="currentColor" viewBox="0 0 16 16"> <path d="M12.854.146a.5.5 0 0 0-.707 0L10.5 1.793 14.207 5.5l1.647-1.646a.5.5 0 0 0 0-.708l-3-3zm.646 6.061L9.793 2.5 3.293 9H3.5a.5.5 0 0 1 .5.5v.5h.5a.5.5 0 0 1 .5.5v.5h.5a.5.5 0 0 1 .5.5v.5h.5a.5.5 0 0 1 .5.5v.207l6.5-6.5zm-7.468 7.468A.5.5 0 0 1 6 13.5V13h-.5a.5.5 0 0 1-.5-.5V12h-.5a.5.5 0 0 1-.5-.5V11h-.5a.5.5 0 0 1-.5-.5V10h-.5a.499.499 0 0 1-.175-.032l-.179.178a.5.5 0 0 0-.11.168l-2 5a.5.5 0 0 0 .65.65l5-2a.5.5 0 0 0 .168-.11l.178-.178z"/> </svg> Edit </button> <button class="action-btn action-btn-primary"> <svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" fill="currentColor" viewBox="0 0 16 16"> <path d="M13.5 1a1.5 1.5 0 1 0 0 3 1.5 1.5 0 0 0 0-3zM11 2.5a2.5 2.5 0 1 1 .603 1.628l-6.718 3.12a2.499 2.499 0 0 1 0 1.504l6.718 3.12a2.5 2.5 0 1 1-.488.876l-6.718-3.12a2.5 2.5 0 1 1 0-3.256l6.718-3.12A2.5 2.5 0 0 1 11 2.5z"/> </svg> Share </button> </div> </div> <div class="ticket"> <div class="ticket-header"> <h3 class="ticket-title" id="title-2">Quarterly Bonus Review</h3> <span class="ticket-id">REQ-2023-0458</span> </div> <div class="ticket-body"> <div class="ticket-info"> <p class="ticket-description">Performance evaluation and bonus recommendation for Q3 2023. Team exceeded targets by 12% with significant contributions from new hires.</p> <div class="ticket-meta"> <div class="ticket-meta-item"> <i> <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> </i> <span>Nov 10, 2023</span> </div> <div class="ticket-meta-item"> <i> <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> </i> <span>Sarah Chen</span> </div> <div class="tag tag-payroll">Payroll</div> <div class="tag tag-urgent">Urgent</div> </div> </div> <div class="ticket-progress"> <div class="progress-label"> <span class="progress-status">Finance Review</span> <span class="progress-percentage">80%</span> </div> <div class="progress-bar-container"> <div class="progress-bar" style="width: 80%;"></div> </div> <div class="progress-steps"> <div class="progress-step completed"> <div class="progress-step-tooltip">Submitted</div> </div> <div class="progress-step completed"> <div class="progress-step-tooltip">Manager Review</div> </div> <div class="progress-step completed"> <div class="progress-step-tooltip">HR Approval</div> </div> <div class="progress-step active"> <div class="progress-step-tooltip">Finance Review</div> </div> <div class="progress-step"> <div class="progress-step-tooltip">Completed</div> </div> </div> </div> </div> <div class="ticket-actions"> <button class="action-btn action-btn-secondary edit-ticket" data-id="2"> <svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" fill="currentColor" viewBox="0 0 16 16"> <path d="M12.854.146a.5.5 0 0 0-.707 0L10.5 1.793 14.207 5.5l1.647-1.646a.5.5 0 0 0 0-.708l-3-3zm.646 6.061L9.793 2.5 3.293 9H3.5a.5.5 0 0 1 .5.5v.5h.5a.5.5 0 0 1 .5.5v.5h.5a.5.5 0 0 1 .5.5v.5h.5a.5.5 0 0 1 .5.5v.207l6.5-6.5zm-7.468 7.468A.
<html> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Mobile Help Desk</title> <style> :root { --primary: #4a6ff3; --primary-light: #e7ecff; --success: #32D74B; --warning: #FFD60A; --danger: #FF453A; --dark: #292d36; --light: #f9fafc; --gray: #8e8e93; --gray-light: #ebebeb; --shadow: 0 4px 12px rgba(0, 0, 0, 0.08); --border-radius: 12px; --transition: all 0.3s ease; } * { margin: 0; padding: 0; box-sizing: border-box; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif; } body { background-color: var(--light); color: var(--dark); max-width: 700px; height: 700px; margin: 0 auto; padding: 20px; overflow-x: hidden; } .app-container { display: flex; flex-direction: column; height: 100%; max-width: 100%; position: relative; overflow: hidden; } .header { display: flex; justify-content: space-between; align-items: center; margin-bottom: 20px; position: relative; z-index: 10; } .header h1 { font-size: 24px; font-weight: 600; } .search-bar { display: flex; align-items: center; background-color: white; border-radius: var(--border-radius); padding: 10px 16px; box-shadow: var(--shadow); margin-bottom: 20px; transition: var(--transition); } .search-bar:focus-within { box-shadow: 0 6px 16px rgba(74, 111, 243, 0.15); transform: translateY(-2px); } .search-bar input { flex: 1; border: none; outline: none; font-size: 16px; padding-left: 8px; } .search-bar i { color: var(--gray); } .tabs { display: flex; gap: 15px; margin-bottom: 20px; border-bottom: 1px solid var(--gray-light); position: relative; } .tab { padding: 10px 5px; font-size: 14px; font-weight: 500; color: var(--gray); cursor: pointer; position: relative; transition: var(--transition); } .tab.active { color: var(--primary); } .tab-indicator { position: absolute; height: 3px; background-color: var(--primary); bottom: -1px; transition: var(--transition); border-radius: 3px 3px 0 0; } .tickets-container { flex: 1; overflow-y: auto; padding-right: 5px; mask-image: linear-gradient(to bottom, transparent, black 10px, black 90%, transparent); -webkit-mask-image: linear-gradient(to bottom, transparent, black 10px, black 90%, transparent); padding-bottom: 60px; } .tickets-container::-webkit-scrollbar { width: 6px; } .tickets-container::-webkit-scrollbar-thumb { background-color: rgba(142, 142, 147, 0.3); border-radius: 3px; } .ticket { background-color: white; border-radius: var(--border-radius); padding: 16px; margin-bottom: 12px; box-shadow: var(--shadow); position: relative; overflow: hidden; cursor: pointer; transform-origin: center; transition: var(--transition); } .ticket:active { transform: scale(0.98); } .ticket:hover { box-shadow: 0 6px 16px rgba(0, 0, 0, 0.12); transform: translateY(-2px); } .ticket-header { display: flex; justify-content: space-between; align-items: center; margin-bottom: 10px; } .ticket-id { font-size: 12px; color: var(--gray); } .ticket-status { display: inline-block; padding: 4px 8px; border-radius: 12px; font-size: 12px; font-weight: 500; } .status-new { background-color: var(--primary-light); color: var(--primary); } .status-in-progress { background-color: rgba(255, 214, 10, 0.15); color: #B08C00; } .status-resolved { background-color: rgba(50, 215, 75, 0.15); color: #1D7A2C; } .ticket-title { font-weight: 600; margin-bottom: 8px; font-size: 16px; } .ticket-desc { font-size: 14px; color: var(--gray); margin-bottom: 12px; display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; } .ticket-meta { display: flex; justify-content: space-between; align-items: center; font-size: 12px; color: var(--gray); } .ticket-user { display: flex; align-items: center; } .ticket-avatar { width: 20px; height: 20px; border-radius: 50%; margin-right: 6px; background-color: var(--primary-light); display: flex; align-items: center; justify-content: center; color: var(--primary); font-size: 10px; font-weight: 600; } .priority-indicator { position: absolute; top: 0; left: 0; width: 4px; height: 100%; } .priority-high { background-color: var(--danger); } .priority-medium { background-color: var(--warning); } .priority-low { background-color: var(--success); } .add-ticket-btn { position: fixed; bottom: 20px; right: 20px; width: 56px; height: 56px; border-radius: 50%; background-color: var(--primary); color: white; display: flex; align-items: center; justify-content: center; box-shadow: 0 4px 12px rgba(74, 111, 243, 0.3); cursor: pointer; z-index: 100; transition: var(--transition); } .add-ticket-btn:hover { transform: translateY(-3px); box-shadow: 0 6px 16px rgba(74, 111, 243, 0.4); } .add-ticket-btn:active { transform: scale(0.95); } .add-ticket-btn i { font-size: 24px; } .empty-state { display: none; flex-direction: column; align-items: center; justify-content: center; height: 100%; text-align: center; padding: 20px; } .empty-state-icon { font-size: 60px; color: var(--gray-light); margin-bottom: 20px; } .empty-state h3 { font-size: 18px; margin-bottom: 8px; } .empty-state p { color: var(--gray); font-size: 14px; max-width: 260px; } /* Ticket Modal */ .modal { position: fixed; top: 0; left: 0; width: 100%; height: 100%; background-color: rgba(0, 0, 0, 0.5); display: flex; align-items: center; justify-content: center; z-index: 1000; opacity: 0; visibility: hidden; transition: opacity 0.3s ease, visibility 0.3s ease; } .modal.active { opacity: 1; visibility: visible; } .modal-content { background-color: white; border-radius: var(--border-radius); width: 90%; max-width: 500px; max-height: 90vh; overflow-y: auto; transform: translateY(20px); opacity: 0; transition: transform 0.3s ease, opacity 0.3s ease; } .modal.active .modal-content { transform: translateY(0); opacity: 1; } .modal-header { display: flex; justify-content: space-between; align-items: center; padding: 16px; border-bottom: 1px solid var(--gray-light); } .modal-title { font-size: 18px; font-weight: 600; } .modal-close { background: none; border: none; font-size: 20px; cursor: pointer; color: var(--gray); } .modal-body { padding: 16px; } .form-group { margin-bottom: 16px; } .form-label { display: block; margin-bottom: 8px; font-size: 14px; font-weight: 500; } .form-control { width: 100%; padding: 12px; border: 1px solid var(--gray-light); border-radius: var(--border-radius); font-size: 16px; transition: var(--transition); } .form-control:focus { outline: none; border-color: var(--primary); box-shadow: 0 0 0 3px rgba(74, 111, 243, 0.15); } .form-select { width: 100%; padding: 12px; border: 1px solid var(--gray-light); border-radius: var(--border-radius); font-size: 16px; appearance: none; background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='%238e8e93' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='6 9 12 15 18 9'%3E%3C/polyline%3E%3C/svg%3E"); background-repeat: no-repeat; background-position: right 12px center; background-size: 16px; } .form-textarea { min-height: 100px; resize: vertical; } .modal-footer { padding: 16px; display: flex; justify-content: flex-end; gap: 12px; border-top: 1px solid var(--gray-light); } .btn { padding: 12px 20px; border-radius: var(--border-radius); font-size: 14px; font-weight: 500; cursor: pointer; transition: var(--transition); border: none; } .btn:active { transform: scale(0.98); } .btn-secondary { background-color: var(--gray-light); color: var(--dark); } .btn-primary { background-color: var(--primary); color: white; box-shadow: 0 2px 8px rgba(74, 111, 243, 0.2); } .btn-primary:hover { background-color: #3a5cdb; box-shadow: 0 4px 12px rgba(74, 111, 243, 0.3); } /* Ticket Detail Modal */ .ticket-detail-header { position: relative; padding: 20px 16px; } .ticket-detail-status { margin-bottom: 12px; } .ticket-detail-title { font-size: 20px; font-weight: 600; margin-bottom: 8px; } .ticket-detail-meta { display: flex; justify-content: space-between; font-size: 14px; color: var(--gray); } .ticket-detail-content { padding: 16px; } .detail-section { margin-bottom: 24px; } .detail-section-title { font-size: 16px; font-weight: 600; margin-bottom: 8px; color: var(--dark); } .detail-section-content { font-size: 14px; line-height: 1.5; color: var(--dark); } .detail-divider { height: 1px; background-color: var(--gray-light); margin: 16px 0; } .actions-group { display: flex; gap: 8px; margin-top: 16px; } .action-btn { padding: 8px 12px; border-radius: var(--border-radius); font-size: 13px; font-weight: 500; cursor: pointer; transition: var(--transition); border: 1px solid var(--gray-light); background-color: white; display: flex; align-items: center; gap: 4px; } .action-btn i { font-size: 14px; } .action-btn:hover { background-color: var(--gray-light); } .action-btn-primary { background-color: var(--primary); color: white; border: none; } .action-btn-primary:hover { background-color: #3a5cdb; } .comment-item { display: flex; gap: 12px; margin-bottom: 16px; } .comment-avatar { width: 32px; height: 32px; border-radius: 50%; background-color: var(--primary-light); display: flex; align-items: center; justify-content: center; color: var(--primary); font-size: 14px; font-weight: 600; flex-shrink: 0; } .comment-content { flex: 1; } .comment-header { display: flex; justify-content: space-between; margin-bottom: 4px; } .comment-author { font-weight: 500; font-size: 14px; } .comment-time { font-size: 12px; color: var(--gray); } .comment-text { font-size: 14px; line-height: 1.4; } .comment-form { display: flex; gap: 8px; margin-top: 16px; } .comment-input { flex: 1; padding: 10px; border: 1px solid var(--gray-light); border-radius: 18px; font-size: 14px; } .comment-input:focus { outline: none; border-color: var(--primary); } .comment-submit { background-color: var(--primary); color: white; border: none; border-radius: 50%; width: 36px; height: 36px; display: flex; align-items: center; justify-content: center; cursor: pointer; } /* Pulse Animation */ @keyframes pulse { 0% { box-shadow: 0 0 0 0 rgba(74, 111, 243, 0.4); } 70% { box-shadow: 0 0 0 10px rgba(74, 111, 243, 0); } 100% { box-shadow: 0 0 0 0 rgba(74, 111, 243, 0); } } .pulse { animation: pulse 2s infinite; } /* Ripple Effect */ .ripple { position: relative; overflow: hidden; } .ripple:after { content: ""; position: absolute; top: 50%; left: 50%; width: 5px; height: 5px; background: rgba(255, 255, 255, 0.5); opacity: 0; border-radius: 100%; transform: scale(1, 1) translate(-50%); transform-origin: 50% 50%; } .ripple:focus:not(:active)::after { animation: ripple 1s ease-out; } @keyframes ripple { 0% { transform: scale(0, 0); opacity: 0.5; } 20% { transform: scale(25, 25); opacity: 0.3; } 100% { opacity: 0; transform: scale(40, 40); } } /* Responsive adjustments */ @media (max-width: 500px) { body { padding: 15px; } .header h1 { font-size: 20px; } .ticket-title { font-size: 15px; } .ticket-desc { font-size: 13px; } .tab { font-size: 13px; } } /* Loading effect */ .loading-skeleton { display: none; animation: pulse-bg 1.5s infinite; background: linear-gradient(90deg, var(--gray-light) 0%, #f0f0f0 50%, var(--gray-light) 100%); background-size: 200% 100%; border-radius: var(--border-radius); } .loading .loading-skeleton { display: block; } .skeleton-ticket { height: 120px; margin-bottom: 12px; } @keyframes pulse-bg { 0% { background-position: 0% 0%; } 100% { background-position: -200% 0%; } } /* Notification badge */ .notification-badge { position: absolute; top: -5px; right: -5px; background-color: var(--danger); color: white; border-radius: 50%; width: 18px; height: 18px; display: flex; align-items: center; justify-content: center; font-size: 10px; font-weight: 500; box-shadow: 0 2px 4px rgba(255, 69, 58, 0.3); } /* User menu */ .user-menu { position: relative; display: flex; align-items: center; } .user-menu-avatar { width: 32px; height: 32px; border-radius: 50%; background-color: var(--primary-light); color: var(--primary); display: flex; align-items: center; justify-content: center; font-size: 14px; font-weight: 600; cursor: pointer; border: 1px solid rgba(74, 111, 243, 0.2); transition: var(--transition); } .user-menu-avatar:hover { transform: scale(1.05); box-shadow: 0 2px 8px rgba(74, 111, 243, 0.2); } /* Filter bar */ .filter-bar { display: flex; align-items: center; justify-content: space-between; margin-bottom: 15px; } .filter-btn { background-color: white; border: 1px solid var(--gray-light); border-radius: var(--border-radius); padding: 6px 12px; font-size: 13px; display: flex; align-items: center; gap: 5px; cursor: pointer; transition: var(--transition); } .filter-btn:hover { background-color: var(--gray-light); } .sort-btn { background-color: white; border: none; display: flex; align-items: center; color: var(--gray); font-size: 13px; cursor: pointer; } .sort-btn i { margin-left: 3px; transition: var(--transition); } .sort-btn.descending i { transform: rotate(180deg); } </style> </head> <body> <div class="app-container"> <div class="header"> <h1>Helpdesk</h1> <div class="user-menu"> <div class="user-menu-avatar" id="user-avatar"> JD </div> </div> </div> <div class="search-bar"> <i class="fas fa-search"></i> <input type="text" placeholder="Search tickets..." id="search-input"> </div> <div class="tabs"> <div class="tab active" data-tab="all">All tickets</div> <div class="tab" data-tab="open">Open</div> <div class="tab" data-tab="my">My tickets</div> <div class="tab-indicator"></div> </div> <div class="filter-bar"> <button class="filter-btn"> <i class="fas fa-filter"></i> Filter </button> <button class="sort-btn" id="sort-btn"> Date <i class="fas fa-chevron-down"></i> </button> </div> <div class="tickets-container" id="tickets-list"> <!-- Tickets will be populated here via JavaScript --> <div class="loading-skeleton skeleton-ticket"></div> <div class="loading-skeleton skeleton-ticket"></div> <div class="loading-skeleton skeleton-ticket"></div> </div> <div class="empty-state" id="empty-state"> <div class="empty-state-icon"> <i class="fas fa-ticket-alt"></i> </div> <h3>No tickets found</h3> <p>Tickets you open or are assigned to you will appear here.</p> </div> <div class="add-ticket-btn ripple pulse" id="add-ticket-btn"> <i class="fas fa-plus"></i> </div> </div> <!-- New Ticket Modal --> <div class="modal" id="new-ticket-modal"> <div class="modal-content"> <div class="modal-header"> <h2 class="modal-title">New Support Ticket</h2> <button class="modal-close">×</button> </div> <div class="modal-body"> <div class="form-group"> <label class="form-label">Title</label> <input type="text" class="form-control" id="ticket-title" placeholder="Brief description of the issue"> </div> <div class="form-group"> <label class="form-label">Description</label> <textarea class="form-control form-textarea" id="ticket-description" placeholder="Please provide detailed information about your issue..."></textarea> </div> <div class="form-group"> <label class="form-label">Category</label> <select class="form-select" id="ticket-category"> <option value="hardware">Hardware Problem</option> <option value="software">Software Issue</option> <option value="network">Network Issue</option> <option value="account">Account Access</option> <option value="other">Other</option> </select> </div> <div class="form-group"> <label class="form-label">Priority</label> <select class="form-select" id="ticket-priority"> <option value="low">Low - Not time sensitive</option> <option value="medium" selected>Medium - Normal priority</option> <option value="high">High - Urgent issue</option> </select> </div> </div> <div class="modal-footer"> <button class="btn btn-secondary" id="cancel-ticket">Cancel</button> <button class="btn btn-primary ripple" id="submit-ticket">Submit Ticket</button> </div> </div> </div> <!-- Ticket Detail Modal --> <div class="modal" id="ticket-detail-modal"> <div class="modal-content"> <div class="modal-header"> <h2 class="modal-title">Ticket Details</h2> <button class="modal-close">×</button> </div> <div class="ticket-detail-header"> <span class="ticket-status status-new ticket-detail-status" id="detail-status">New</span> <h1 class="ticket-detail-title" id="detail-title">Loading...</h1> <div class="ticket-detail-meta"> <span class="ticket-id" id="detail-id">TKT-12345</span> <span id="detail-date">Jul 15, 2023</span> </div> </div> <div class="ticket-detail-content"> <div class="detail-section"> <h3 class="detail-section-title">Description</h3> <p class="detail-section-content" id="detail-description"> Loading ticket details... </p> </div> <div class="detail-divider"></div> <div class="detail-section"> <h3 class="detail-section-title">Information</h3> <div class="detail-section-content"> <p><strong>Requester:</strong> <span id="detail-requester">John Doe</span></p> <p><strong>Category:</strong> <span id="detail-category">Software Issue</span></p> <p><strong>Priority:</strong> <span id="detail-priority">Medium</span></p> </div> </div> <div class="actions-group"> <button class="action-btn" id="reassign-btn"> <i class="fas fa-user-plus"></i> Reassign </button> <button class="action-btn" id="change-status-btn"> <i class="fas fa-sync-alt"></i> Change Status </button> <button class="action-btn action-btn-primary" id="resolve-btn"> <i class="fas fa-check"></i> Resolve Ticket </button> </div> <div class="detail-divider"></div> <div class="detail-section"> <h3 class="detail-section-title">Comments</h3> <div id="comments-container"> <div class="comment-item"> <div class="comment-avatar">TS</div> <div class="comment-content"> <div class="comment-header"> <span class="comment-author">Tech Support</span> <span class="comment-time">2 hours ago</span> </div> <div class="comment-text"> We're looking into this issue. Have you tried restarting your device? </div> </div> </div> </div> <div class="comment-form"> <input type="text" class="comment-input" placeholder="Add a comment..." id="comment-input"> <button class="comment-submit" id="comment-submit"> <i class="fas fa-paper-plane"></i> </button> </div> </div> </div> </div> </div> <!-- Icon Library --> <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.4/css/all.min.css"> <script> document.addEventListener('DOMContentLoaded', function() { // Elements const ticketsList = document.getElementById('tickets-list'); const tabs = document.querySelectorAll('.tab'); const tabIndicator = document.querySelector('.tab-indicator'); const addTicketBtn = document.getElementById('add-ticket-btn'); const newTicketModal = document.getElementById('new-ticket-modal'); const ticketDetailModal = document.getElementById('ticket-detail-modal'); const closeModalBtns = document.querySelectorAll('.modal-close'); const cancelTicketBtn = document.getElementById('cancel-ticket'); const submitTicketBtn = document.getElementById('submit-ticket'); const searchInput = document.getElementById('search-input'); const emptyState = document.getElementById('empty-state'); const sortBtn = document.getElementById('sort-btn'); const commentInput = document.getElementById('comment-input'); const commentSubmit = document.getElementById('comment-submit'); const resolveBtn = document.getElementById('resolve-btn'); // State let tickets = []; let currentTab = 'all'; let sortDescending = true; let searchTerm = ''; // Initialize tab indicator position updateTabIndicator(); // Sample data const sampleTickets = [ { id: 'TKT-4872', title: 'Unable to Connect to VPN After Password Reset', description: 'After resetting my password this morning, I can no longer connect to the company VPN. I've tried restarting my laptop and clearing cache but still no success.', status: 'new', priority: 'high', category: 'network', createdBy: 'John Doe', createdAt: new Date(2023, 6, 17, 9, 23), assignedTo: null, comments: [ { author: 'Tech Support', avatar: 'TS', text: 'We're looking into this. Are you using the new VPN client that was rolled out last week?', time: new Date(2023, 6, 17, 10, 15) } ] }, { id: 'TKT-4871', title: 'Email Sync Issues on Mobile App', description: 'The company email app on my phone isn't syncing properly. New emails show up in my desktop client but not on mobile. I've already verified network connectivity.', status: 'in-progress', priority: 'medium', category: 'software', createdBy: 'Alice Chen', createdAt: new Date(2023, 6, 16, 14, 5), assignedTo: 'Support Team', comments: [] }, { id: 'TKT-4869', title: 'Request for Dual Monitors', description: 'I'd like to request an additional monitor for my workstation. My current projects involve comparing multiple documents simultaneously, and an extra screen would boost my productivity.', status: 'new', priority: 'low', category: 'hardware', createdBy: 'Raj Patel', createdAt: new Date(2023, 6, 15, 11, 47), assignedTo: null, comments: [] }, { id: 'TKT-4865', title: 'Access Required for Analytics Dashboard', description: 'I need access to the marketing analytics dashboard to pull data for the quarterly report. My current permissions only allow viewing basic stats.', status: 'resolved', priority: 'medium', category: 'account', createdBy: 'Maria Lopez', createdAt: new Date(2023, 6, 14, 16, 32), assignedTo: 'Admin Team', comments: [ { author: 'Admin Support', avatar: 'AS', text: 'Access granted. You should be able to view all analytics sections now.', time: new Date(2023, 6, 14, 17, 20) }, { author: 'Maria Lopez', avatar: 'ML', text: 'Perfect, thank you! I can access everything now.', time: new Date(2023, 6, 14, 17, 45) } ] }, { id: 'TKT-4863', title: 'Printer on 3rd Floor Not Working', description: 'The shared printer near the conference room on the 3rd floor is showing a "Hardware Error" message and won't print any documents.', status: 'in-progress', priority: 'high', category: 'hardware', createdBy: 'James Wilson', createdAt: new Date(2023, 6, 13, 9, 12), assignedTo: 'Maintenance', comments: [ { author: 'Maintenance Team', avatar: 'MT', text: 'We've dispatched a technician to take a look. Should be resolved within an hour.', time: new Date(2023, 6, 13, 9, 30) } ] } ]; // Initialize app init(); function init() { // Load tickets (would normally be from an API) tickets = sampleTickets; setTimeout(() => { renderTickets(); }, 1200); // Simulate loading delay for demo } function renderTickets() { // Clear loading skeletons ticketsList.innerHTML = ''; // Filter tickets based on current tab let filteredTickets = filterTickets(); // Sort tickets filteredTickets = sortTickets(filteredTickets); // If no tickets match the filters, show empty state if (filteredTickets.length === 0) { emptyState.style.display = 'flex'; } else { emptyState.style.display = 'none'; // Create ticket elements filteredTickets.forEach(ticket => { const ticketElement = createTicketElement(ticket); ticketsList.appendChild(ticketElement); }); } } function createTicketElement(ticket) { const ticketDiv = document.createElement('div'); ticketDiv.className = 'ticket'; ticketDiv.dataset.ticketId = ticket.id; // Set priority indicator class const priorityClass = `priority-${ticket.priority}`; // Set status class const statusClass = `status-${ticket.status.replace(' ', '-')}`; const statusText = ticket.status.charAt(0).toUpperCase() + ticket.status.slice(1); // Format date const formattedDate = formatDate(ticket.createdAt); // Get the first letter of first and last name for avatar const nameInitials = ticket.createdBy.split(' ').map(n => n[0]).join(''); ticketDiv.innerHTML = ` <div class="priority-indicator ${priorityClass}"></div> <div class="ticket-header"> <span class="ticket-id">${ticket.id}</span> <span class="ticket-status ${statusClass}">${statusText}</span> </div> <h3 class="ticket-title">${ticket.title}</h3> <p
<html> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Vintage Exclusive Event Ticket</title> <style> * { margin: 0; padding: 0; box-sizing: border-box; font-family: 'Didot', serif; } :root { --cream: #f8f4e3; --gold: #d4af37; --deep-burgundy: #800020; --navy: #0a0a40; --dark-gray: #333; } body { width: 100%; height: 100vh; display: flex; justify-content: center; align-items: center; background-color: #282828; background-image: radial-gradient(#383838 1px, transparent 1px); background-size: 20px 20px; overflow: hidden; } .container { width: 100%; max-width: 650px; height: 650px; position: relative; perspective: 1200px; } .ticket-wrapper { width: 100%; height: 100%; position: relative; transform-style: preserve-3d; transition: transform 1s ease; } .ticket { width: 100%; height: 350px; margin: 50px auto; background: var(--cream); border-radius: 10px; box-shadow: 0 15px 30px rgba(0, 0, 0, 0.3); position: relative; overflow: hidden; transform-style: preserve-3d; transition: all 0.6s cubic-bezier(0.23, 1, 0.32, 1); } .ticket:before { content: ''; position: absolute; top: 0; left: 0; width: 100%; height: 100%; background: linear-gradient(135deg, rgba(255, 255, 255, 0.1) 0%, rgba(255, 255, 255, 0) 100%); pointer-events: none; } .ticket:after { 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='%23d4af37' fill-opacity='0.1' fill-rule='evenodd'/%3E%3C/svg%3E"); opacity: 0.2; pointer-events: none; } .ticket-inner { padding: 20px; height: 100%; display: flex; flex-direction: column; justify-content: space-between; position: relative; z-index: 2; } .ticket-header { display: flex; justify-content: space-between; align-items: center; border-bottom: 1px dashed var(--gold); padding-bottom: 15px; } .emblem { width: 70px; height: 70px; border: 2px solid var(--gold); border-radius: 50%; display: flex; align-items: center; justify-content: center; background: rgba(212, 175, 55, 0.05); box-shadow: 0 0 10px rgba(212, 175, 55, 0.2); } .emblem span { font-size: 12px; text-transform: uppercase; font-weight: bold; color: var(--deep-burgundy); letter-spacing: 2px; text-align: center; } .ticket-number { font-size: 14px; font-weight: bold; color: var(--dark-gray); font-family: 'Courier New', monospace; letter-spacing: 1px; } .ticket-title { text-align: center; margin: 15px 0; } .ticket-title h1 { font-size: 28px; color: var(--deep-burgundy); text-transform: uppercase; letter-spacing: 3px; margin-bottom: 5px; text-shadow: 1px 1px 0 rgba(0, 0, 0, 0.1); } .ticket-title h2 { font-size: 16px; color: var(--navy); font-weight: normal; font-style: italic; } .ticket-details { display: flex; justify-content: space-between; margin: 20px 0; } .detail-group { text-align: center; } .detail-label { font-size: 12px; text-transform: uppercase; color: var(--dark-gray); margin-bottom: 5px; letter-spacing: 1px; } .detail-value { font-size: 18px; font-weight: bold; color: var(--navy); } .ticket-footer { display: flex; justify-content: space-between; align-items: center; border-top: 1px dashed var(--gold); padding-top: 15px; position: relative; } .qr-code { width: 80px; height: 80px; background-color: white; padding: 8px; box-shadow: 0 0 5px rgba(0, 0, 0, 0.1); position: relative; overflow: hidden; } .qr-inner { 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 fill='%23000000' d='M0,0 L100,0 L100,100 L0,100 Z M10,10 L10,40 L40,40 L40,10 Z M50,10 L50,15 L55,15 L55,10 Z M65,10 L65,15 L60,15 L60,20 L55,20 L55,25 L50,25 L50,35 L55,35 L55,40 L60,40 L60,35 L65,35 L65,25 L60,25 L60,20 L65,20 L65,15 L70,15 L70,10 Z M75,10 L75,15 L85,15 L85,25 L90,25 L90,10 Z M15,15 L15,35 L35,35 L35,15 Z M55,15 L55,20 L60,20 L60,15 Z M20,20 L20,30 L30,30 L30,20 Z M50,20 L50,25 L55,25 L55,20 Z M75,20 L75,25 L80,25 L80,20 Z M85,20 L85,25 L90,25 L90,20 Z M60,25 L60,30 L65,30 L65,25 Z M75,25 L75,40 L90,40 L90,30 L85,30 L85,35 L80,35 L80,30 L75,30 Z M50,30 L50,35 L55,35 L55,30 Z M10,45 L10,50 L15,50 L15,55 L20,55 L20,65 L15,65 L15,70 L10,70 L10,90 L40,90 L40,65 L30,65 L30,60 L25,60 L25,55 L20,55 L20,50 L15,50 L15,45 Z M45,45 L45,50 L50,50 L50,45 Z M55,45 L55,50 L50,50 L50,55 L45,55 L45,65 L50,65 L50,60 L55,60 L55,55 L60,55 L60,50 L65,50 L65,45 Z M75,45 L75,50 L70,50 L70,55 L65,55 L65,70 L70,70 L70,75 L60,75 L60,80 L55,80 L55,90 L75,90 L75,75 L80,75 L80,65 L75,65 L75,60 L80,60 L80,55 L85,55 L85,50 L90,50 L90,45 Z M15,50 L15,55 L20,55 L20,50 Z M50,50 L50,55 L45,55 L45,60 L50,60 L50,55 L55,55 L55,50 Z M65,50 L65,55 L70,55 L70,50 Z M25,55 L25,60 L30,60 L30,55 Z M80,55 L80,60 L85,60 L85,55 Z M50,60 L50,65 L55,65 L55,60 Z M85,60 L85,65 L90,65 L90,60 Z M15,65 L15,70 L20,70 L20,65 Z M45,65 L45,70 L50,70 L50,65 Z M60,65 L60,70 L65,70 L65,65 Z M70,65 L70,70 L75,70 L75,65 Z M15,75 L15,85 L35,85 L35,75 Z M45,75 L45,80 L50,80 L50,75 Z M75,75 L75,80 L80,80 L80,85 L90,85 L90,75 Z M45,80 L45,85 L50,85 L50,80 Z M60,80 L60,85 L65,85 L65,80 Z'%3E%3C/path%3E%3C/svg%3E"); background-size: contain; transition: transform 0.3s ease; } .qr-inner:hover { transform: scale(1.08); } .qr-scanner-line { position: absolute; top: 0; left: 0; width: 100%; height: 3px; background: rgba(255, 0, 0, 0.6); box-shadow: 0 0 5px rgba(255, 0, 0, 0.8); animation: scan 2s linear infinite; opacity: 0; transition: opacity 0.3s ease; } .qr-code:hover .qr-scanner-line { opacity: 1; } @keyframes scan { 0% { top: 0; } 100% { top: 100%; } } .ticket-note { font-size: 11px; font-style: italic; color: var(--dark-gray); max-width: 200px; text-align: right; } /* Perforated edges */ .ticket:before { content: ''; position: absolute; top: 0; left: -5px; height: 100%; width: 10px; background-image: linear-gradient(90deg, transparent 0%, transparent 50%, var(--cream) 50%, var(--cream) 100%); background-size: 10px 10px; z-index: 3; } .ticket:after { content: ''; position: absolute; top: 0; right: -5px; height: 100%; width: 10px; background-image: linear-gradient(90deg, var(--cream) 0%, var(--cream) 50%, transparent 50%, transparent 100%); background-size: 10px 10px; z-index: 3; } /* Booking form */ .booking-form { width: 100%; height: 350px; background: linear-gradient(145deg, var(--navy), #0f0f4d); color: white; position: absolute; top: 50px; left: 0; border-radius: 10px; padding: 30px; box-shadow: 0 15px 30px rgba(0, 0, 0, 0.5); transform: translateY(100%) scale(0.9); opacity: 0; transition: all 0.5s cubic-bezier(0.175, 0.885, 0.32, 1.275); z-index: 10; } .form-active .booking-form { transform: translateY(0) scale(1); opacity: 1; } .form-header { text-align: center; margin-bottom: 20px; } .form-header h2 { font-size: 24px; color: var(--gold); letter-spacing: 2px; margin-bottom: 5px; } .form-header p { font-size: 14px; opacity: 0.8; } .form-group { margin-bottom: 15px; } label { display: block; font-size: 14px; margin-bottom: 5px; color: var(--gold); } input, select { width: 100%; padding: 10px; background: rgba(255, 255, 255, 0.1); border: 1px solid rgba(255, 255, 255, 0.2); border-radius: 5px; color: white; font-size: 16px; transition: all 0.3s ease; } input:focus, select:focus { outline: none; border-color: var(--gold); box-shadow: 0 0 0 2px rgba(212, 175, 55, 0.3); } .form-row { display: flex; gap: 15px; } .form-group.half { flex: 1; } .button { background: var(--gold); color: var(--navy); border: none; padding: 12px 25px; border-radius: 5px; font-size: 16px; font-weight: bold; cursor: pointer; letter-spacing: 1px; transition: all 0.3s ease; display: inline-block; margin-top: 10px; box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1); } .button:hover { background: #e5c254; transform: translateY(-2px); box-shadow: 0 6px 10px rgba(0, 0, 0, 0.15); } .back-button { background: transparent; color: white; border: 1px solid rgba(255, 255, 255, 0.3); margin-right: 10px; } .back-button:hover { background: rgba(255, 255, 255, 0.1); transform: translateY(-2px); } .buttons { display: flex; justify-content: center; margin-top: 20px; } /* Confirmation screen */ .confirmation { width: 100%; height: 350px; background: linear-gradient(145deg, #125868, #0f3c46); color: white; position: absolute; top: 50px; left: 0; border-radius: 10px; padding: 30px; display: flex; flex-direction: column; align-items: center; justify-content: center; text-align: center; transform: translateY(100%) scale(0.9) rotateY(90deg); opacity: 0; transition: all 0.6s cubic-bezier(0.175, 0.885, 0.32, 1.275); z-index: 5; } .confirmation-active .confirmation { transform: translateY(0) scale(1) rotateY(0); opacity: 1; } .confirmation-icon { width: 80px; height: 80px; border-radius: 50%; background: rgba(255, 255, 255, 0.1); display: flex; align-items: center; justify-content: center; margin-bottom: 20px; position: relative; } .confirmation-icon:before { content: ''; width: 40px; height: 20px; border-left: 4px solid var(--gold); border-bottom: 4px solid var(--gold); transform: rotate(-45deg); position: absolute; top: 25px; left: 20px; } .confirmation h2 { font-size: 28px; color: white; margin-bottom: 15px; } .confirmation p { font-size: 16px; opacity: 0.9; max-width: 300px; margin: 0 auto 20px auto; line-height: 1.4; } .shine { position: absolute; top: 0; left: 0; width: 50px; height: 100%; background: linear-gradient( to right, rgba(255, 255, 255, 0) 0%, rgba(255, 255, 255, 0.3) 50%, rgba(255, 255, 255, 0) 100% ); transform: skewX(-20deg); animation: shine 4s infinite; } @keyframes shine { 0% { left: -100px; opacity: 0; } 10% { opacity: 0.5; } 20% { left: 120%; opacity: 0; } 100% { left: 120%; opacity: 0; } } .ticket-pull { position: absolute; bottom: 10px; left: 50%; transform: translateX(-50%); background: var(--deep-burgundy); color: var(--cream); padding: 10px 20px; border-radius: 5px; font-size: 14px; cursor: pointer; box-shadow: 0 4px 10px rgba(0, 0, 0, 0.2); opacity: 0.9; transition: all 0.3s ease; z-index: 20; } .ticket-pull:hover { transform: translateX(-50%) translateY(-3px); box-shadow: 0 6px 12px rgba(0, 0, 0, 0.3); opacity: 1; } .form-active .ticket-pull, .confirmation-active .ticket-pull { opacity: 0; transform: translateX(-50%) translateY(20px); pointer-events: none; } /* Embossed details */ .embossed { position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); font-size: 120px; color: rgba(128, 0, 32, 0.05); font-weight: bold; letter-spacing: 5px; text-transform: uppercase; pointer-events: none; user-select: none; } /* Media Queries */ @media (max-width: 650px) { .container { width: 90%; height: 600px; } .ticket, .booking-form, .confirmation { width: 100%; height: 320px; } .ticket-title h1 { font-size: 22px; } .ticket-title h2 { font-size: 14px; } .detail-label { font-size: 10px; } .detail-value { font-size: 16px; } .qr-code { width: 70px; height: 70px; } .embossed { font-size: 80px; } } /* Animation utilities */ .slide-up { animation: slideUp 0.8s cubic-bezier(0.175, 0.885, 0.32, 1.275) forwards; } @keyframes slideUp { 0% { opacity: 0; transform: translateY(20px); } 100% { opacity: 1; transform: translateY(0); } } .delay-1 { animation-delay: 0.1s; } .delay-2 { animation-delay: 0.2s; } .delay-3 { animation-delay: 0.3s; } .delay-4 { animation-delay: 0.4s; } </style> </head> <body> <div class="container"> <div class="ticket-wrapper"> <!-- Main Ticket --> <div class="ticket"> <span class="embossed">VIP</span> <div class="shine"></div> <div class="ticket-inner"> <div class="ticket-header slide-up"> <div class="emblem"> <span>Exclusive Access</span> </div> <div class="ticket-number">#JM-19240617</div> </div> <div class="ticket-title slide-up delay-1"> <h1>Moonlight Gala</h1> <h2>Annual Charity Soirée</h2> </div> <div class="ticket-details slide-up delay-2"> <div class="detail-group"> <div class="detail-label">Date</div> <div class="detail-value">June 17, 2024</div> </div> <div class="detail-group"> <div class="detail-label">Time</div> <div class="detail-value">8:00 PM</div> </div> <div class="detail-group"> <div class="detail-label">Venue</div> <div class="detail-value">Grand Pavilion</div> </div> </div> <div class="ticket-footer slide-up delay-3"> <div class="qr-code"> <div class="qr-inner"></div> <div class="qr-scanner-line"></div> </div> <div class="ticket-note"> This ticket grants exclusive VIP entry and complimentary champagne service. </div> </div> </div> </div> <!-- Booking Form --> <div class="booking-form"> <div class="form-header"> <h2>SECURE YOUR INVITATION</h2> <p>Complete the details below to reserve your exclusive ticket</p> </div> <div class="form-group"> <label for="fullname">Full Name</label> <input type="text" id="fullname" placeholder="As it appears on your ID"> </div> <div class="form-row"> <div class="form-group half"> <label for="email">Email Address</label> <input type="email" id="email" placeholder="For confirmation"> </div> <div class="form-group half"> <label for="phone">Phone Number</label> <input type="tel" id="phone" placeholder="For contact"> </div> </div> <div class="form-group"> <label for="guest-type">Guest Category</label> <select id="guest-type"> <option value="" disabled selected>Select a category</option> <option value="vip">VIP Attendee</option> <option value="patron">Patron Benefactor</option> <option value="sponsor">Corporate Sponsor</option> </select> </div> <div class="buttons"> <button class="button back-button" id="back-to-ticket">Return</button> <button class="button" id="confirm-booking">Confirm Booking</button> </div> </div> <!-- Confirmation Screen --> <div class="confirmation"> <div class="confirmation-icon"></div> <h2>Reservation Confirmed</h2> <p>Your exclusive invitation has been secured. A detailed confirmation has been sent to your email.</p> <button class="button" id="view-ticket">View Your Ticket</button> </div> </div> <button class="ticket-pull" id="book-ticket">Reserve Your Exclusive Invitation</button> </div> <script> document.addEventListener('DOMContentLoaded', function() { const ticketPull = document.getElementById('book-ticket'); const backToTicket = document.getElementById('back-to-ticket'); const confirmBooking = document.getElementById('confirm-booking'); const viewTicket = document.getElementById('view-ticket'); const ticketWrapper = document.querySelector('.ticket-wrapper'); const ticket = document.querySelector('.ticket'); // Initialize staggered animations const animatedElements = document.querySelectorAll('.slide-up'); animatedElements.forEach(el => { el.style.opacity = 0; setTimeout(() => { el.style.opacity = 1; }, 300); }); // Ticket hover effect ticket.addEventListener('mousemove', function(e) { const boundingRect = ticket.getBoundingClientRect(); const mouseX = e.clientX - boundingRect.left; const mouseY = e.clientY - boundingRect.top; const centerX = boundingRect.width / 2; const centerY = boundingRect.height / 2; const rotateY = (mouseX - centerX) / 15; const rotateX = (centerY - mouseY) / 15; ticket.style.transform = `perspective(1000px) rotateX(${rotateX}deg) rotateY(${rotateY}deg)`; }); ticket.addEventListener('mouseleave', function() { ticket.style.transform = 'perspective(1000px) rotateX(0) rotateY(0)'; }); // Form navigation ticketPull.addEventListener('click', function() { ticketWrapper.classList.add('form-active'); ticket.style.transform = 'perspective(1000px) rotateX(10deg) rotateY(0) scale(0.95)'; }); backToTicket.addEventListener('click', function() { ticketWrapper.classList.remove('form-active'); ticket.style.transform = 'perspective(1000px) rotateX(0) rotateY(0) scale(1)'; }); confirmBooking.addEventListener('click', function() { // Simple validation const fullname = document.getElementById('fullname').value; const email = document.getElementById('email').value; const phone = document.getElementById('phone').value; const guestType = document.getElementById('guest-type').value; if (fullname && email && phone && guestType) { ticketWrapper.classList.remove('form-active'); ticketWrapper.classList.add('confirmation-active'); // Rotate ticket to a nice display angle ticket.style.transform = 'perspective(1000px) rotateX(5deg) rotateY(-10deg) scale(0.85) translateY(-40px)'; } else { // Add a shake animation to the form const form = document.querySelector('.booking-form'); form.style.animation = 'shake 0.5s ease-in-out'; setTimeout(() => { form.style.animation = ''; }, 500); } }); viewTicket.addEventListener('click', function() { ticketWrapper.classList.remove('confirmation-active'); ticket.style.transform = 'perspective(1000px) rotateX(0) rotateY(0)'; // Reset form fields document.getElementById('fullname').value = ''; document.getElementById('email').value = ''; document.getElementById('phone').value = ''; document.getElementById('guest-type').selectedIndex = 0; }); // Add a subtle floating animation to the ticket setInterval(() => { if (!ticketWrapper.classList.contains('form-active') && !ticketWrapper.classList.contains('confirmation-active')) { const randomX = (Math.random() - 0.5) * 2; const randomY = (Math.random() - 0.5) * 2; ticket.style.transform = `perspective(1000px) translate(${randomX}px, ${randomY}px)`; setTimeout(() => { if (!ticketWrapper.classList.contains('form-active') && !ticketWrapper.classList.contains('confirmation-active')) { ticket.style.transform = 'perspective(1000px) translate(0, 0)'; } }, 500); } }, 3000); // Make the QR code interactive const qrCode = document.querySelector('.qr-inner'); qrCode.addEventListener('mouseover', function() { this.style.transition = 'transform 0.3s ease'; this.style.transform = 'scale(1.08)'; }); qrCode.addEventListener('mouseout', function() { this.style.transform = 'scale(1)'; }); // Add shake animation for form validation document.head.insertAdjacentHTML('beforeend', ` <style> @keyframes shake { 0%, 100% { transform: translateX(0); } 20%, 60% { transform: translateX(-5px); } 40%, 80% { transform: translateX(5px); } } </style> `); }); </script> </body> </html>
<html> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <style> :root { --primary-color: #91785D; --secondary-color: #E6DFD7; --accent-color: #415D43; --text-color: #3A3630; --light-text: #6B645A; --white: #FFFFFF; --transition: all 0.3s cubic-bezier(0.25, 0.8, 0.25, 1); } * { margin: 0; padding: 0; box-sizing: border-box; font-family: 'Inter', sans-serif; } body { background-color: var(--secondary-color); color: var(--text-color); height: 100vh; display: flex; align-items: center; justify-content: center; overflow-x: hidden; padding: 20px; } .museum-ticket-system { background-color: var(--white); border-radius: 16px; width: 100%; max-width: 650px; height: 600px; overflow: hidden; position: relative; box-shadow: 0 15px 35px rgba(58, 54, 48, 0.1); display: flex; flex-direction: column; } .header { padding: 24px; background-color: var(--primary-color); color: var(--white); display: flex; justify-content: space-between; align-items: center; } .logo { font-size: 20px; font-weight: 700; letter-spacing: 0.5px; display: flex; align-items: center; } .logo-icon { margin-right: 12px; width: 36px; height: 36px; border: 2px solid var(--white); border-radius: 50%; display: flex; align-items: center; justify-content: center; } .date-info { font-size: 14px; opacity: 0.8; } .content { padding: 24px; flex: 1; overflow-y: auto; position: relative; } .tabs { display: flex; border-bottom: 1px solid rgba(58, 54, 48, 0.1); margin-bottom: 20px; } .tab { padding: 8px 20px; cursor: pointer; color: var(--light-text); font-size: 15px; position: relative; transition: var(--transition); } .tab.active { color: var(--primary-color); font-weight: 600; } .tab.active::after { content: ''; position: absolute; bottom: -1px; left: 0; width: 100%; height: 2px; background-color: var(--primary-color); } .ticket-options { display: flex; flex-direction: column; gap: 16px; } .ticket-option { background-color: rgba(230, 223, 215, 0.4); border-radius: 12px; padding: 20px; cursor: pointer; transition: var(--transition); position: relative; overflow: hidden; border: 1px solid transparent; } .ticket-option:hover { background-color: rgba(230, 223, 215, 0.7); transform: translateY(-2px); } .ticket-option.selected { border-color: var(--primary-color); background-color: rgba(145, 120, 93, 0.08); } .ticket-header { display: flex; justify-content: space-between; align-items: center; margin-bottom: 8px; } .ticket-title { font-weight: 600; font-size: 17px; } .ticket-price { font-weight: 700; color: var(--primary-color); font-size: 18px; } .ticket-description { font-size: 14px; color: var(--light-text); line-height: 1.5; margin-bottom: 16px; } .ticket-details { max-height: 0; overflow: hidden; transition: max-height 0.4s ease-out; } .ticket-option.selected .ticket-details { max-height: 500px; } .ticket-features { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 10px; } .ticket-feature { background-color: rgba(145, 120, 93, 0.12); padding: 6px 12px; border-radius: 20px; font-size: 13px; color: var(--primary-color); display: flex; align-items: center; font-weight: 500; } .ticket-feature svg { margin-right: 5px; } .quantity-selector { display: flex; align-items: center; margin-top: 16px; } .quantity-btn { width: 32px; height: 32px; border-radius: 50%; border: 1px solid var(--light-text); background: transparent; cursor: pointer; display: flex; align-items: center; justify-content: center; font-size: 16px; transition: var(--transition); } .quantity-btn:hover { background-color: var(--primary-color); color: var(--white); border-color: var(--primary-color); } .quantity { margin: 0 16px; font-weight: 600; width: 24px; text-align: center; } .view-map-btn { margin-top: 16px; background-color: rgba(65, 93, 67, 0.1); color: var(--accent-color); border: none; padding: 10px 16px; border-radius: 8px; font-weight: 500; font-size: 14px; cursor: pointer; transition: var(--transition); display: flex; align-items: center; width: fit-content; } .view-map-btn:hover { background-color: rgba(65, 93, 67, 0.2); } .view-map-btn svg { margin-right: 8px; } .museum-map { position: fixed; top: 50%; left: 50%; transform: translate(-50%, -50%) scale(0.9); width: 90%; max-width: 600px; background-color: var(--white); border-radius: 16px; padding: 24px; box-shadow: 0 20px 60px rgba(0, 0, 0, 0.2); z-index: 1000; opacity: 0; visibility: hidden; transition: all 0.3s ease; } .museum-map.active { opacity: 1; visibility: visible; transform: translate(-50%, -50%) scale(1); } .map-header { display: flex; justify-content: space-between; align-items: center; margin-bottom: 20px; } .map-title { font-weight: 600; font-size: 18px; } .close-map { background: none; border: none; cursor: pointer; color: var(--text-color); font-size: 22px; } .map-content { position: relative; height: 400px; border-radius: 12px; overflow: hidden; background-color: var(--secondary-color); } .map-image { width: 100%; height: 100%; object-fit: cover; } .map-overlay { position: absolute; top: 0; left: 0; width: 100%; height: 100%; pointer-events: none; } .exhibit-point { position: absolute; width: 20px; height: 20px; border-radius: 50%; background-color: var(--accent-color); transform: translate(-50%, -50%); pointer-events: all; cursor: pointer; box-shadow: 0 0 0 5px rgba(65, 93, 67, 0.3); animation: pulse 2s infinite; } @keyframes pulse { 0% { box-shadow: 0 0 0 0 rgba(65, 93, 67, 0.5); } 70% { box-shadow: 0 0 0 10px rgba(65, 93, 67, 0); } 100% { box-shadow: 0 0 0 0 rgba(65, 93, 67, 0); } } .tooltip { position: absolute; background-color: var(--white); border-radius: 8px; padding: 10px; width: 200px; box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15); transform: translateY(-100%); margin-top: -10px; opacity: 0; visibility: hidden; transition: var(--transition); z-index: 10; pointer-events: all; } .exhibit-point:hover .tooltip { opacity: 1; visibility: visible; } .tooltip-title { font-weight: 600; font-size: 14px; margin-bottom: 5px; } .tooltip-description { font-size: 12px; color: var(--light-text); } .backdrop { position: fixed; top: 0; left: 0; width: 100%; height: 100%; background-color: rgba(0, 0, 0, 0.5); z-index: 999; opacity: 0; visibility: hidden; transition: var(--transition); } .backdrop.active { opacity: 1; visibility: visible; } .checkout-bar { background-color: var(--white); padding: 20px 24px; border-top: 1px solid rgba(58, 54, 48, 0.1); display: flex; justify-content: space-between; align-items: center; box-shadow: 0 -5px 15px rgba(0, 0, 0, 0.03); } .total-price { display: flex; flex-direction: column; } .total-label { font-size: 14px; color: var(--light-text); margin-bottom: 4px; } .price-value { font-weight: 700; font-size: 22px; color: var(--primary-color); } .purchase-btn { background-color: var(--accent-color); color: var(--white); border: none; padding: 14px 28px; border-radius: 10px; font-weight: 600; font-size: 16px; cursor: pointer; transition: var(--transition); display: flex; align-items: center; } .purchase-btn:hover { background-color: #364d37; transform: translateY(-2px); } .purchase-btn svg { margin-left: 10px; } .success-message { position: fixed; top: 50%; left: 50%; transform: translate(-50%, -50%) scale(0.9); width: 90%; max-width: 400px; background-color: var(--white); border-radius: 16px; padding: 30px; box-shadow: 0 20px 60px rgba(0, 0, 0, 0.2); z-index: 1000; opacity: 0; visibility: hidden; transition: all 0.3s ease; text-align: center; } .success-message.active { opacity: 1; visibility: visible; transform: translate(-50%, -50%) scale(1); } .success-icon { width: 80px; height: 80px; background-color: rgba(65, 93, 67, 0.1); border-radius: 50%; display: flex; align-items: center; justify-content: center; margin: 0 auto 20px; color: var(--accent-color); } .success-title { font-weight: 700; font-size: 20px; margin-bottom: 10px; } .success-text { color: var(--light-text); margin-bottom: 25px; line-height: 1.5; } .close-success { background-color: var(--primary-color); color: var(--white); border: none; padding: 12px 24px; border-radius: 10px; font-weight: 600; font-size: 16px; cursor: pointer; transition: var(--transition); } .close-success:hover { background-color: #7d674f; } /* Loading animation */ .loading-effect { display: inline-block; position: relative; width: 80px; height: 80px; margin: 0 auto; } .loading-effect div { position: absolute; top: 33px; width: 13px; height: 13px; border-radius: 50%; background: var(--primary-color); animation-timing-function: cubic-bezier(0, 1, 1, 0); } .loading-effect div:nth-child(1) { left: 8px; animation: loading1 0.6s infinite; } .loading-effect div:nth-child(2) { left: 8px; animation: loading2 0.6s infinite; } .loading-effect div:nth-child(3) { left: 32px; animation: loading2 0.6s infinite; } .loading-effect div:nth-child(4) { left: 56px; animation: loading3 0.6s infinite; } @keyframes loading1 { 0% { transform: scale(0); } 100% { transform: scale(1); } } @keyframes loading2 { 0% { transform: translate(0, 0); } 100% { transform: translate(24px, 0); } } @keyframes loading3 { 0% { transform: scale(1); } 100% { transform: scale(0); } } @media (max-width: 600px) { .header { padding: 16px; } .content { padding: 16px; } .tab { padding: 8px 12px; font-size: 14px; } .checkout-bar { padding: 16px; } .purchase-btn { padding: 12px 20px; font-size: 14px; } .ticket-title { font-size: 16px; } .price-value { font-size: 20px; } } </style> </head> <body> <div class="museum-ticket-system"> <div class="header"> <div class="logo"> <div class="logo-icon"> <svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"> <polygon points="12 2 2 7 12 12 22 7 12 2"></polygon> <polyline points="2 17 12 22 22 17"></polyline> <polyline points="2 12 12 17 22 12"></polyline> </svg> </div> TERRA MUSEUM </div> <div class="date-info" id="current-date">Today's Date</div> </div> <div class="content"> <div class="tabs"> <div class="tab active" data-tab="tickets">Tickets</div> <div class="tab" data-tab="exhibitions">Exhibitions</div> <div class="tab" data-tab="hours">Hours & Info</div> </div> <div class="ticket-options"> <div class="ticket-option" data-price="22"> <div class="ticket-header"> <div class="ticket-title">General Admission</div> <div class="ticket-price">$22</div> </div> <div class="ticket-description">Full access to all permanent collections and special exhibitions. Perfect for experiencing the rich cultural heritage on display.</div> <div class="ticket-details"> <div class="ticket-features"> <div class="ticket-feature"> <svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"> <circle cx="12" cy="12" r="10"></circle> <polyline points="12 6 12 12 16 14"></polyline> </svg> All-day access </div> <div class="ticket-feature"> <svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"> <path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"></path> <polyline points="14 2 14 8 20 8"></polyline> <line x1="16" y1="13" x2="8" y2="13"></line> <line x1="16" y1="17" x2="8" y2="17"></line> <polyline points="10 9 9 9 8 9"></polyline> </svg> Digital guides </div> <div class="ticket-feature"> <svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"> <path d="M17 21v-2a4 4 0 0 0-4-4H5a4 4 0 0 0-4 4v2"></path> <circle cx="9" cy="7" r="4"></circle> <path d="M23 21v-2a4 4 0 0 0-3-3.87"></path> <path d="M16 3.13a4 4 0 0 1 0 7.75"></path> </svg> No guided tour </div> </div> <div class="quantity-selector"> <button class="quantity-btn minus">-</button> <div class="quantity">1</div> <button class="quantity-btn plus">+</button> </div> <button class="view-map-btn" data-ticket="general"> <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"> <polygon points="1 6 1 22 8 18 16 22 23 18 23 2 16 6 8 2 1 6"></polygon> <line x1="8" y1="2" x2="8" y2="18"></line> <line x1="16" y1="6" x2="16" y2="22"></line> </svg> View Access Map </button> </div> </div> <div class="ticket-option" data-price="35"> <div class="ticket-header"> <div class="ticket-title">Curator's Tour</div> <div class="ticket-price">$35</div> </div> <div class="ticket-description">Enhanced experience with expert-led small group tours of our most significant artifacts. Get deeper insights into our collections.</div> <div class="ticket-details"> <div class="ticket-features"> <div class="ticket-feature"> <svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"> <circle cx="12" cy="12" r="10"></circle> <polyline points="12 6 12 12 16 14"></polyline> </svg> All-day access </div> <div class="ticket-feature"> <svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"> <path d="M17 21v-2a4 4 0 0 0-4-4H5a4 4 0 0 0-4 4v2"></path> <circle cx="9" cy="7" r="4"></circle> <path d="M23 21v-2a4 4 0 0 0-3-3.87"></path> <path d="M16 3.13a4 4 0 0 1 0 7.75"></path> </svg> Expert guide </div> <div class="ticket-feature"> <svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"> <path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"></path> <polyline points="14 2 14 8 20 8"></polyline> <line x1="16" y1="13" x2="8" y2="13"></line> <line x1="16" y1="17" x2="8" y2="17"></line> <polyline points="10 9 9 9 8 9"></polyline> </svg> Exclusive catalog </div> <div class="ticket-feature"> <svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"> <path d="M20 21v-2a4 4 0 0 0-4-4H8a4 4 0 0 0-4 4v2"></path> <circle cx="12" cy="7" r="4"></circle> </svg> Small groups </div> </div> <div class="quantity-selector"> <button class="quantity-btn minus">-</button> <div class="quantity">0</div> <button class="quantity-btn plus">+</button> </div> <button class="view-map-btn" data-ticket="curator"> <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"> <polygon points="1 6 1 22 8 18 16 22 23 18 23 2 16 6 8 2 1 6"></polygon> <line x1="8" y1="2" x2="8" y2="18"></line> <line x1="16" y1="6" x2="16" y2="22"></line> </svg> View Tour Route </button> </div> </div> <div class="ticket-option" data-price="16"> <div class="ticket-header"> <div class="ticket-title">Student/Senior</div> <div class="ticket-price">$16</div> </div> <div class="ticket-description">Discounted access for students and seniors over 65. Valid ID required at entry. Includes access to all permanent exhibits.</div> <div class="ticket-details"> <div class="ticket-features"> <div class="ticket-feature"> <svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"> <circle cx="12" cy="12" r="10"></circle> <polyline points="12 6 12 12 16 14"></polyline> </svg> All-day access </div> <div class="ticket-feature"> <svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"> <rect x="3" y="4" width="18" height="18" rx="2" ry="2"></rect> <line x1="16" y1="2" x2="16" y2="6"></line> <line x1="8" y1="2" x2="8" y2="6"></line> <line x1="3" y1="10" x2="21" y2="10"></line> </svg> ID required </div> <div class="ticket-feature"> <svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"> <path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"></path> <polyline points="14 2 14 8 20 8"></polyline> <line x1="16" y1="13" x2="8" y2="13"></line> <line x1="16" y1="17" x2="8" y2="17"></line> <polyline points="10 9 9 9 8 9"></polyline> </svg> Digital guides </div> </div> <div class="quantity-selector"> <button class="quantity-btn minus">-</button> <div class="quantity">0</div> <button class="quantity-btn plus">+</button> </div> <button class="view-map-btn" data-ticket="student"> <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"> <polygon points="1 6 1 22 8 18 16 22 23 18 23 2 16 6 8 2 1 6"></polygon> <line x1="8" y1="2" x2="8" y2="18"></line> <line x1="16" y1="6" x2="16" y2="22"></line> </svg> View Access Map </button> </div> </div> </div> </div> <div class="checkout-bar"> <div class="total-price"> <div class="total-label">Total amount</div> <div class="price-value">$22.00</div> </div> <button class="purchase-btn"> Get Tickets <svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"> <path d="M5 12h14"></path> <path d="M12 5l7 7-7 7"></path> </svg> </button> </div> </div> <div class="backdrop"></div> <div class="museum-map"> <div class="map-header"> <div class="map-title">Museum Exhibition Map</div> <button class="close-map">×</button> </div> <div class="map-content"> <svg class="map-image" viewBox="0 0 800 600" width="100%" height="100%"> <rect x="50" y="50" width="700" height="500" rx="10" fill="#E6DFD7" stroke="#91785D" stroke-width="3"/> <!-- Main Hall --> <rect x="150" y="150" width="500" height="300" rx="5" fill="#FFFFFF" stroke="#91785D" stroke-width="2"/> <text x="400" y="180" text-anchor="middle" font-size="16" fill="#3A3630" font-weight="bold">Main Hall</text> <!-- Exhibition Rooms --> <rect x="150" y="150" width="150" height="150" rx="5" fill="#FFFFFF" stroke="#91785D" stroke-width="2"/> <text x="225" y="225" text-anchor="middle" font-size="14" fill="#3A3630">Ancient History</text> <rect x="300" y="150" width="150" height="150" rx="5" fill="#FFFFFF" stroke="#91785D" stroke-width="2"/> <text x="375" y="225" text-anchor="middle" font-size="14" fill="#3A3630">Modern Art</text> <rect x="450" y="150" width="200" height="150" rx="5" fill="#FFFFFF" stroke="#91785D" stroke-width="2"/> <text x="550" y="225" text-anchor="middle" font-size="14" fill="#3A3630">Special Exhibition</text> <rect x="150" y="300" width="250" height="150" rx="5" fill="#FFFFFF" stroke="#91785D" stroke-width="2"/> <text x="275" y="375" text-anchor="middle" font-size="14" fill="#3A3630">Natural History</text> <rect x="400" y="300" width="250" height="150" rx="5" fill="#FFFFFF" stroke="#91785D" stroke-width="2"/> <text x="525" y="375" text-anchor="middle" font-size="14" fill="#3A3630">Cultural Artifacts</text> <!-- Entrance --> <rect x="350" y="450" width="100" height="50" rx="5" fill="#91785D"/> <text x="400" y="480" text-anchor="middle" font-size="14" fill="#FFFFFF">ENTRANCE</text> <!-- Walkways --> <line x1="400" y1="450" x2="400" y2="300" stroke="#91785D" stroke-width="10" stroke-linecap="round"/> <line x1="300" y1="300" x2="500" y2="300" stroke="#91785D" stroke-width="10" stroke-linecap="round"/> <line x1="225" y1="300" x2="225" y2="150" stroke="#91785D" stroke-width="10" stroke-linecap="round"/> <line x1="375" y1="300" x2="375" y2="150" stroke="#91785D" stroke-width="10" stroke-linecap="round"/> <line x1="525" y1="300" x2="525" y2="150" stroke="#91785D" stroke-width="10" stroke-linecap="round"/> <!-- North indicator --> <polygon points="750,75 730,100 770,100" fill="#415D43"/> <text x="750" y="120" text-anchor="middle" font-size="14" fill="#415D43" font-weight="bold">N</text> </svg> <div class="map-overlay"> <div class="exhibit-point" style="top: 35%; left: 28%;"> <div class="tooltip"> <div class="tooltip-title">Early Civilization Artifacts</div> <div class="tooltip-description">Featuring pottery and tools from 5000 BCE</div> </div> </div> <div class="exhibit-point" style="top: 35%; left: 47%;"> <div class="tooltip"> <div class="tooltip-title">Contemporary Art Gallery</div> <div class="tooltip-description">Rotating exhibit of modern artists</div> </div> </div> <div class="exhibit-point" style="top: 35%; left: 69%;"> <div class="tooltip"> <div class="tooltip-title">Terra: Our Changing Planet</div> <div class="tooltip-description">Limited time exhibition on climate change</div> </div> </div> <div class="exhibit-point" style="top: 65%; left: 34%;"> <div class="tooltip"> <div class="tooltip-title">Dinosaur Hall</div> <div class="tooltip-description">Complete T-Rex skeleton and fossil collection</div> </div> </div> <div class="exhibit-point" style="top: 65%; left: 66%;"> <div class="tooltip"> <div class="tooltip-title">Indigenous Cultures</div> <div class="tooltip-description">Cultural artifacts from indigenous communities</div> </div> </div> </div> </div> </div> <div class="success-message"> <div class="success-icon"> <svg xmlns="http://www.w3.org/2000/svg" width="36" height="36" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"> <path d="M22 11.08V12a10 10 0 1 1-5.93-9.14"></path> <polyline points="22 4 12 14.01 9 11.01"></polyline> </svg> </div> <h2 class="success-title">Tickets Confirmed!</h2> <p class="success-text">Your museum tickets have been reserved successfully. You'll receive a confirmation email with QR codes for entry.</p> <button class="close-success">Done</button> </div> <script> document.addEventListener('DOMContent
<html> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>CineVerse Ticketing</title> <style> :root { --primary: #4E1A3D; --primary-light: #732F5D; --secondary: #F5B700; --dark: #1C1B29; --light: #F8F9FA; --success: #42B883; --error: #E63946; --neutral: #9CA3AF; --animation-speed: 0.3s; } * { margin: 0; padding: 0; box-sizing: border-box; font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; } body { background-color: var(--dark); color: var(--light); display: flex; justify-content: center; align-items: center; min-height: 700px; width: 100%; overflow-x: hidden; perspective: 1000px; } .container { width: 100%; max-width: 680px; padding: 20px; margin: 0 auto; height: 660px; display: flex; flex-direction: column; } header { text-align: center; margin-bottom: 25px; position: relative; } .logo { font-size: 26px; font-weight: bold; margin-bottom: 5px; color: var(--secondary); letter-spacing: 1px; } .logo span { color: var(--light); } h1 { font-size: 22px; margin-bottom: 8px; font-weight: 600; } .tabs { display: flex; justify-content: center; gap: 10px; margin-bottom: 20px; } .tab { padding: 8px 16px; background: rgba(255, 255, 255, 0.1); border-radius: 20px; cursor: pointer; transition: all var(--animation-speed) ease; } .tab.active { background: var(--primary); color: var(--light); font-weight: 500; } .tab:hover:not(.active) { background: rgba(255, 255, 255, 0.2); } .movie-selection { display: flex; gap: 15px; overflow-x: auto; padding: 10px 0; margin-bottom: 20px; scrollbar-width: thin; scrollbar-color: var(--primary) var(--dark); } .movie-selection::-webkit-scrollbar { height: 6px; } .movie-selection::-webkit-scrollbar-track { background: rgba(255, 255, 255, 0.1); border-radius: 10px; } .movie-selection::-webkit-scrollbar-thumb { background-color: var(--primary); border-radius: 10px; } .movie-card { min-width: 120px; border-radius: 12px; overflow: hidden; position: relative; cursor: pointer; transition: transform var(--animation-speed) ease; transform-style: preserve-3d; box-shadow: 0 4px 12px rgba(0, 0, 0, 0.2); } .movie-card:hover { transform: translateY(-5px) rotateY(5deg); } .movie-card.selected { border: 2px solid var(--secondary); box-shadow: 0 0 15px rgba(245, 183, 0, 0.5); } .movie-card img { width: 100%; height: 160px; object-fit: cover; display: block; } .movie-info { padding: 10px; background: var(--primary); } .movie-title { font-size: 14px; font-weight: 600; margin-bottom: 4px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; } .movie-meta { display: flex; justify-content: space-between; font-size: 12px; color: var(--neutral); } .movie-rating { display: flex; align-items: center; gap: 2px; } .movie-rating i { color: var(--secondary); font-size: 10px; } .showtime-section { margin-bottom: 20px; } .section-title { font-size: 16px; margin-bottom: 12px; display: flex; align-items: center; gap: 8px; } .section-title i { color: var(--secondary); } .date-selection { display: flex; gap: 10px; overflow-x: auto; padding: 5px 0; margin-bottom: 15px; scrollbar-width: none; } .date-selection::-webkit-scrollbar { display: none; } .date-item { min-width: 60px; padding: 10px; background: rgba(255, 255, 255, 0.1); border-radius: 8px; text-align: center; cursor: pointer; transition: all var(--animation-speed) ease; user-select: none; } .date-item.selected { background: var(--primary); box-shadow: 0 4px 8px rgba(0, 0, 0, 0.2); } .date-item:hover:not(.selected) { background: rgba(255, 255, 255, 0.15); } .date-day { font-size: 14px; font-weight: 600; } .date-date { font-size: 12px; color: var(--neutral); } .time-slots { display: grid; grid-template-columns: repeat(auto-fill, minmax(80px, 1fr)); gap: 10px; margin-bottom: 15px; } .time-slot { padding: 8px; background: rgba(255, 255, 255, 0.1); border-radius: 8px; text-align: center; cursor: pointer; transition: all var(--animation-speed) ease; position: relative; overflow: hidden; } .time-slot::before { content: ""; position: absolute; width: 100%; height: 3px; bottom: 0; left: 0; background-color: var(--secondary); transform: scaleX(0); transition: transform var(--animation-speed) ease; transform-origin: bottom right; } .time-slot:hover::before { transform: scaleX(1); transform-origin: bottom left; } .time-slot.selected { background: var(--primary); color: var(--light); } .time-slot.premium { border: 1px dashed var(--secondary); } .time-slot.premium::after { content: "Premium"; position: absolute; top: -8px; right: -20px; background: var(--secondary); color: var(--dark); font-size: 8px; padding: 2px 20px; transform: rotate(45deg); } .time-slot.almost-full { background: rgba(230, 57, 70, 0.2); } .time-slot.disabled { opacity: 0.5; cursor: not-allowed; text-decoration: line-through; } .time { font-size: 14px; font-weight: 600; } .screen-section { margin-bottom: 20px; position: relative; } .screen { height: 20px; background: var(--secondary); border-radius: 50%; margin-bottom: 30px; position: relative; transform: perspective(500px) rotateX(-30deg); box-shadow: 0 6px 20px rgba(245, 183, 0, 0.3); } .screen::before { content: "SCREEN"; position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); color: var(--dark); font-size: 10px; font-weight: bold; letter-spacing: 2px; } .seats-grid { display: grid; grid-template-columns: repeat(10, 1fr); gap: 8px; margin-bottom: 15px; } .seat { aspect-ratio: 1/1; background: rgba(255, 255, 255, 0.1); border-radius: 4px; cursor: pointer; transition: all var(--animation-speed) ease; position: relative; } .seat:hover:not(.unavailable) { transform: scale(1.1); background: rgba(255, 255, 255, 0.25); } .seat.selected { background: var(--success); box-shadow: 0 0 8px rgba(66, 184, 131, 0.6); } .seat.unavailable { background: var(--neutral); opacity: 0.3; cursor: not-allowed; } .seat.premium { border: 1px solid var(--secondary); } .legend { display: flex; justify-content: center; gap: 20px; margin-top: 10px; font-size: 12px; } .legend-item { display: flex; align-items: center; gap: 5px; } .legend-marker { width: 12px; height: 12px; border-radius: 2px; } .legend-marker.available { background: rgba(255, 255, 255, 0.1); } .legend-marker.selected { background: var(--success); } .legend-marker.unavailable { background: var(--neutral); opacity: 0.3; } .legend-marker.premium { background: rgba(255, 255, 255, 0.1); border: 1px solid var(--secondary); } .summary-section { background: rgba(0, 0, 0, 0.2); border-radius: 12px; padding: 15px; display: flex; flex-direction: column; gap: 12px; } .summary-row { display: flex; justify-content: space-between; align-items: center; } .summary-label { font-size: 14px; color: var(--neutral); } .summary-value { font-size: 14px; font-weight: 600; } .summary-total { padding-top: 10px; border-top: 1px dashed rgba(255, 255, 255, 0.1); } .summary-total .summary-value { font-size: 18px; color: var(--secondary); } .book-button { background: var(--secondary); color: var(--dark); border: none; border-radius: 8px; padding: 12px; font-weight: 600; font-size: 16px; cursor: pointer; transition: all var(--animation-speed) ease; margin-top: 10px; position: relative; overflow: hidden; } .book-button:hover { transform: translateY(-2px); box-shadow: 0 4px 12px rgba(245, 183, 0, 0.4); } .book-button:active { transform: translateY(0); } .book-button::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: all 0.5s ease; } .book-button:hover::after { left: 100%; } .ticket-confirmation { position: fixed; top: 0; left: 0; width: 100%; height: 100%; display: flex; justify-content: center; align-items: center; background: rgba(28, 27, 41, 0.95); z-index: 1000; opacity: 0; pointer-events: none; transition: opacity var(--animation-speed) ease; } .ticket-confirmation.active { opacity: 1; pointer-events: all; } .ticket { background: var(--light); color: var(--dark); width: 280px; border-radius: 12px; overflow: hidden; box-shadow: 0 10px 30px rgba(0, 0, 0, 0.3); transform: rotateX(10deg) rotateY(0deg); transition: all var(--animation-speed) ease; animation: ticketAppear 0.6s ease forwards; } @keyframes ticketAppear { 0% { transform: rotateX(90deg) translateY(100px); opacity: 0; } 100% { transform: rotateX(0deg) translateY(0px); opacity: 1; } } .ticket:hover { transform: rotateX(0deg) rotateY(0deg) translateY(-5px); } .ticket-header { background: var(--primary); padding: 15px; color: var(--light); text-align: center; position: relative; } .ticket-logo { font-size: 18px; font-weight: bold; margin-bottom: 5px; color: var(--secondary); } .ticket-title { font-size: 16px; margin-bottom: 5px; } .ticket-subtitle { font-size: 12px; color: var(--neutral); } .ticket-body { padding: 15px; position: relative; } .ticket-body::before, .ticket-body::after { content: ""; position: absolute; width: 20px; height: 20px; background: var(--dark); border-radius: 50%; top: -10px; } .ticket-body::before { left: -10px; } .ticket-body::after { right: -10px; } .ticket-info { display: flex; flex-direction: column; gap: 10px; } .ticket-info-row { display: flex; justify-content: space-between; } .ticket-label { font-size: 12px; color: var(--neutral); } .ticket-value { font-size: 13px; font-weight: 600; text-align: right; } .ticket-seats { display: flex; flex-wrap: wrap; gap: 5px; } .ticket-seat { font-size: 12px; padding: 3px 6px; background: var(--primary-light); color: var(--light); border-radius: 4px; } .ticket-qr { display: flex; justify-content: center; margin: 15px 0; } .ticket-qr img { width: 100px; height: 100px; } .ticket-footer { text-align: center; font-size: 11px; padding: 10px; background: rgba(0, 0, 0, 0.05); color: var(--neutral); position: relative; } .close-ticket { position: absolute; top: 10px; right: 10px; background: none; border: none; color: var(--light); font-size: 20px; cursor: pointer; opacity: 0.7; transition: opacity var(--animation-speed) ease; } .close-ticket:hover { opacity: 1; } @media (max-width: 600px) { .container { padding: 15px; height: 660px; } h1 { font-size: 20px; } .time-slots { grid-template-columns: repeat(auto-fill, minmax(70px, 1fr)); } .seats-grid { gap: 6px; } .summary-section { padding: 10px; } } @keyframes pulse { 0% { transform: scale(1); } 50% { transform: scale(1.05); } 100% { transform: scale(1); } } .pulse { animation: pulse 2s infinite; } /* Icon Classes */ .icon { font-style: normal; } </style> </head> <body> <div class="container"> <header> <div class="logo">Cine<span>Verse</span></div> <h1>Book Your Perfect Movie Experience</h1> </header> <div class="tabs"> <div class="tab active">Now Showing</div> <div class="tab">Coming Soon</div> <div class="tab">Experiences</div> </div> <div class="movie-selection"> <div class="movie-card" data-movie="Dune: Part Two"> <img src="https://via.placeholder.com/120x160/4E1A3D/F8F9FA?text=Dune:+Part+Two" alt="Dune: Part Two"> <div class="movie-info"> <div class="movie-title">Dune: Part Two</div> <div class="movie-meta"> <span>Sci-Fi</span> <div class="movie-rating"><i class="icon">★</i> 8.9</div> </div> </div> </div> <div class="movie-card selected" data-movie="Blade Runner 2099"> <img src="https://via.placeholder.com/120x160/732F5D/F8F9FA?text=Blade+Runner+2099" alt="Blade Runner 2099"> <div class="movie-info"> <div class="movie-title">Blade Runner 2099</div> <div class="movie-meta"> <span>Sci-Fi</span> <div class="movie-rating"><i class="icon">★</i> 9.1</div> </div> </div> </div> <div class="movie-card" data-movie="Interstellar: Eclipse"> <img src="https://via.placeholder.com/120x160/4E1A3D/F8F9FA?text=Interstellar:+Eclipse" alt="Interstellar: Eclipse"> <div class="movie-info"> <div class="movie-title">Interstellar: Eclipse</div> <div class="movie-meta"> <span>Sci-Fi</span> <div class="movie-rating"><i class="icon">★</i> 8.7</div> </div> </div> </div> <div class="movie-card" data-movie="The Eternal Sunshine"> <img src="https://via.placeholder.com/120x160/732F5D/F8F9FA?text=Eternal+Sunshine" alt="The Eternal Sunshine"> <div class="movie-info"> <div class="movie-title">The Eternal Sunshine</div> <div class="movie-meta"> <span>Drama</span> <div class="movie-rating"><i class="icon">★</i> 8.4</div> </div> </div> </div> <div class="movie-card" data-movie="Neo Tokyo Drift"> <img src="https://via.placeholder.com/120x160/4E1A3D/F8F9FA?text=Neo+Tokyo+Drift" alt="Neo Tokyo Drift"> <div class="movie-info"> <div class="movie-title">Neo Tokyo Drift</div> <div class="movie-meta"> <span>Action</span> <div class="movie-rating"><i class="icon">★</i> 7.9</div> </div> </div> </div> </div> <div class="showtime-section"> <div class="section-title"> <i class="icon">📅</i> Select Date & Time </div> <div class="date-selection"> <div class="date-item"> <div class="date-day">Mon</div> <div class="date-date">15 May</div> </div> <div class="date-item"> <div class="date-day">Tue</div> <div class="date-date">16 May</div> </div> <div class="date-item selected"> <div class="date-day">Wed</div> <div class="date-date">17 May</div> </div> <div class="date-item"> <div class="date-day">Thu</div> <div class="date-date">18 May</div> </div> <div class="date-item"> <div class="date-day">Fri</div> <div class="date-date">19 May</div> </div> <div class="date-item"> <div class="date-day">Sat</div> <div class="date-date">20 May</div> </div> <div class="date-item"> <div class="date-day">Sun</div> <div class="date-date">21 May</div> </div> </div> <div class="time-slots"> <div class="time-slot"> <div class="time">10:30 AM</div> </div> <div class="time-slot disabled"> <div class="time">12:45 PM</div> </div> <div class="time-slot selected"> <div class="time">3:20 PM</div> </div> <div class="time-slot premium"> <div class="time">5:45 PM</div> </div> <div class="time-slot almost-full"> <div class="time">8:15 PM</div> </div> <div class="time-slot premium"> <div class="time">10:30 PM</div> </div> </div> </div> <div class="screen-section"> <div class="screen"></div> <div class="seats-grid"> <!-- Seats will be populated by JavaScript --> </div> <div class="legend"> <div class="legend-item"> <div class="legend-marker available"></div> <span>Available</span> </div> <div class="legend-item"> <div class="legend-marker selected"></div> <span>Selected</span> </div> <div class="legend-item"> <div class="legend-marker unavailable"></div> <span>Unavailable</span> </div> <div class="legend-item"> <div class="legend-marker premium"></div> <span>Premium</span> </div> </div> </div> <div class="summary-section"> <div class="summary-row"> <div class="summary-label">Movie</div> <div class="summary-value">Blade Runner 2099</div> </div> <div class="summary-row"> <div class="summary-label">Date & Time</div> <div class="summary-value">Wed, 17 May • 3:20 PM</div> </div> <div class="summary-row"> <div class="summary-label">Seats</div> <div class="summary-value">D5, D6</div> </div> <div class="summary-row summary-total"> <div class="summary-label">Total</div> <div class="summary-value">$28.50</div> </div> <button class="book-button">Complete Booking</button> </div> </div> <div class="ticket-confirmation"> <div class="ticket"> <div class="ticket-header"> <button class="close-ticket">×</button> <div class="ticket-logo">CineVerse</div> <div class="ticket-title">Blade Runner 2099</div> <div class="ticket-subtitle">Your ticket is confirmed!</div> </div> <div class="ticket-body"> <div class="ticket-info"> <div class="ticket-info-row"> <div class="ticket-label">Date</div> <div class="ticket-value">Wed, 17 May 2023</div> </div> <div class="ticket-info-row"> <div class="ticket-label">Time</div> <div class="ticket-value">3:20 PM</div> </div> <div class="ticket-info-row"> <div class="ticket-label">Cinema</div> <div class="ticket-value">CineVerse IMAX</div> </div> <div class="ticket-info-row"> <div class="ticket-label">Seats</div> <div class="ticket-seats"> <div class="ticket-seat">D5</div> <div class="ticket-seat">D6</div> </div> </div> </div> <div class="ticket-qr"> <img src="https://api.qrserver.com/v1/create-qr-code/?size=100x100&data=CINEVERSE-BR2099-17MAY-320PM-D5D6" alt="QR Code"> </div> </div> <div class="ticket-footer"> Present this ticket at the entrance. Enjoy your movie! </div> </div> </div> <script> document.addEventListener('DOMContentLoaded', function() { // Generate seats const seatsGrid = document.querySelector('.seats-grid'); const rows = ['A', 'B', 'C', 'D', 'E', 'F']; const unavailableSeats = ['A3', 'A4', 'B5', 'B6', 'C1', 'C2', 'E7', 'E8', 'F9', 'F10']; const premiumSeats = ['D4', 'D5', 'D6', 'D7', 'E4', 'E5', 'E6', 'E7']; rows.forEach(row => { for (let i = 1; i <= 10; i++) { const seatId = `${row}${i}`; const seatEl = document.createElement('div'); seatEl.classList.add('seat'); seatEl.dataset.seat = seatId; if (unavailableSeats.includes(seatId)) { seatEl.classList.add('unavailable'); } if (premiumSeats.includes(seatId)) { seatEl.classList.add('premium'); } seatsGrid.appendChild(seatEl); } }); // Select D5 and D6 as default selected seats document.querySelector('.seat[data-seat="D5"]').classList.add('selected'); document.querySelector('.seat[data-seat="D6"]').classList.add('selected'); // Movie selection const movieCards = document.querySelectorAll('.movie-card'); movieCards.forEach(card => { card.addEventListener('click', function() { // Remove selected class from all cards movieCards.forEach(c => c.classList.remove('selected')); // Add selected class to clicked card this.classList.add('selected'); // Update summary document.querySelector('.summary-row:first-child .summary-value').textContent = this.dataset.movie; }); }); // Date selection const dateItems = document.querySelectorAll('.date-item'); dateItems.forEach(item => { item.addEventListener('click', function() { dateItems.forEach(d => d.classList.remove('selected')); this.classList.add('selected'); // Update summary date const day = this.querySelector('.date-day').textContent; const date = this.querySelector('.date-date').textContent; const time = document.querySelector('.time-slot.selected .time').textContent; document.querySelector('.summary-row:nth-child(2) .summary-value').textContent = `${day}, ${date} • ${time}`; }); }); // Time selection const timeSlots = document.querySelectorAll('.time-slot:not(.disabled)'); timeSlots.forEach(slot => { slot.addEventListener('click', function() { timeSlots.forEach(t => t.classList.remove('selected')); this.classList.add('selected'); // Update summary time const selectedDate = document.querySelector('.date-item.selected'); const day = selectedDate.querySelector('.date-day').textContent; const date = selectedDate.querySelector('.date-date').textContent; const time = this.querySelector('.time').textContent; document.querySelector('.summary-row:nth-child(2) .summary-value').textContent = `${day}, ${date} • ${time}`; }); }); // Seat selection const seats = document.querySelectorAll('.seat:not(.unavailable)'); let selectedSeats = ['D5', 'D6']; // Default selected seats seats.forEach(seat => { seat.addEventListener('click', function() { const seatId = this.dataset.seat; if (this.classList.contains('selected')) { // Deselect this.classList.remove('selected'); selectedSeats = selectedSeats.filter(id => id !== seatId); } else { // Select this.classList.add('selected'); selectedSeats.push(seatId); } // Update summary seats and total updateSeatSummary(); }); }); function updateSeatSummary() { // Sort seats for better readability selectedSeats.sort(); const seatsText = selectedSeats.join(', '); document.querySelector('.summary-row:nth-child(3) .summary-value').textContent = seatsText; // Update total based on number of seats and whether they're premium let total = 0; selectedSeats.forEach(seatId => { if (premiumSeats.includes(seatId)) { total += 15.50; // Premium price } else { total += 13.00; // Regular price } }); document.querySelector('.summary-total .summary-value').textContent = `$${total.toFixed(2)}`; // Update ticket seats const ticketSeats = document.querySelector('.ticket-seats'); ticketSeats.innerHTML = ''; selectedSeats.forEach(seatId => { const seatEl = document.createElement('div'); seatEl.classList.add('ticket-seat'); seatEl.textContent = seatId; ticketSeats.appendChild(seatEl); }); } // Booking button const bookButton = document.querySelector('.book-button'); const ticketConfirmation = document.querySelector('.ticket-confirmation'); const closeTicket = document.querySelector('.close-ticket'); bookButton.addEventListener('click', function() { // Add pulse animation before showing ticket this.classList.add('pulse'); setTimeout(() => { this.classList.remove('pulse'); ticketConfirmation.classList.add('active'); }, 800); }); closeTicket.addEventListener('click', function() { ticketConfirmation.classList.remove('active'); }); // Close ticket when clicking outside ticketConfirmation.addEventListener('click', function(e) { if (e.target === this) { this.classList.remove('active'); } }); // Hover effects for movie cards movieCards.forEach(card => { card.addEventListener('mouseover', function() { const others = Array.from(movieCards).filter(c => c !== this); others.forEach(c => { c.style.opacity = '0.7'; c.style.transform = 'scale(0.95)'; }); }); card.addEventListener('mouseout', function() { movieCards.forEach(c => { c.style.opacity = '1'; c.style.transform = ''; }); }); }); }); </script> </body> </html>