Files
website-ai-generator/pages/seed-f3131947428795c8.html
T

1163 lines
36 KiB
HTML

<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Vessel — New Release</title>
<script src="https://cdn.tailwindcss.com"></script>
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Playfair+Display:wght@400;700;900&family=Inter:wght@300;400;500;600&display=swap" rel="stylesheet">
<style>
:root {
--bg: #0c0c0c;
--bg-elevated: #141414;
--fg: #f0e8d8;
--muted: #8a7e6f;
--accent: #c9974e;
--accent-light: #e0b87a;
--card: #1a1a1a;
--border: #2a2a2a;
}
* { box-sizing: border-box; margin: 0; padding: 0; }
html { scroll-behavior: smooth; }
body {
font-family: 'Inter', sans-serif;
background: var(--bg);
color: var(--fg);
overflow-x: hidden;
line-height: 1.6;
}
h1, h2, h3, h4, h5, h6 { font-family: 'Playfair Display', serif; }
/* Scroll progress */
#scroll-progress {
position: fixed; top: 0; left: 0; height: 3px;
background: var(--accent);
z-index: 1000;
width: 0%;
transition: width 0.1s linear;
}
/* Loading screen */
#loader {
position: fixed; inset: 0; z-index: 9999;
background: var(--bg);
display: flex; align-items: center; justify-content: center;
flex-direction: column; gap: 1.5rem;
transition: opacity 0.6s ease;
}
#loader.hidden { opacity: 0; pointer-events: none; }
.loader-ring {
width: 48px; height: 48px;
border: 2px solid var(--border);
border-top-color: var(--accent);
border-radius: 50%;
animation: spin 1s linear infinite;
}
@keyframes spin { to { transform: rotate(360deg); } }
/* Hero */
.hero-section {
position: relative;
min-height: 100vh;
display: flex;
align-items: center;
justify-content: center;
overflow: hidden;
}
.hero-bg {
position: absolute; inset: 0;
background: linear-gradient(135deg, #1a1410 0%, #0c0c0c 40%, #1a1410 100%);
}
.hero-grain {
position: absolute; inset: 0;
opacity: 0.04;
background-image: url("data:image/svg+xml,%3Csvg viewBox='0 0 256 256' xmlns='http://www.w3.org/2000/svg'%3E%3Cfilter id='noise'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='4' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23noise)'/%3E%3C/svg%3E");
background-size: 200px 200px;
}
.hero-orb {
position: absolute;
border-radius: 50%;
filter: blur(80px);
opacity: 0.3;
animation: float 8s ease-in-out infinite;
}
.hero-orb-1 {
width: 400px; height: 400px;
background: var(--accent);
top: 10%; left: 15%;
}
.hero-orb-2 {
width: 300px; height: 300px;
background: #3a2a1a;
bottom: 20%; right: 10%;
animation-delay: -3s;
}
.hero-content {
position: relative;
z-index: 2;
text-align: center;
max-width: 900px;
padding: 0 2rem;
}
.hero-label {
font-size: 0.85rem;
letter-spacing: 0.3em;
text-transform: uppercase;
color: var(--muted);
margin-bottom: 1rem;
animation: fadeUp 1s ease 0.3s both;
}
.hero-title {
font-size: clamp(3rem, 8vw, 6.5rem);
font-weight: 900;
line-height: 1.05;
letter-spacing: -0.02em;
margin-bottom: 1rem;
animation: fadeUp 1s ease 0.5s both;
}
.hero-title .highlight {
color: var(--accent);
position: relative;
}
.hero-title .highlight::after {
content: '';
position: absolute;
bottom: 0.15em;
left: 0;
width: 100%;
height: 2px;
background: var(--accent);
opacity: 0.4;
}
.hero-sub {
font-size: clamp(1rem, 2vw, 1.25rem);
color: var(--muted);
font-weight: 300;
margin-bottom: 2.5rem;
animation: fadeUp 1s ease 0.7s both;
}
.hero-cta {
display: inline-block;
padding: 0.9rem 2.2rem;
background: var(--accent);
color: var(--bg);
font-weight: 600;
font-size: 0.95rem;
border-radius: 0;
transition: all 0.3s ease;
text-decoration: none;
animation: fadeUp 1s ease 0.9s both;
}
.hero-cta:hover {
background: var(--accent-light);
transform: translateY(-2px);
box-shadow: 0 8px 30px rgba(201,151,78,0.3);
}
.hero-scroll {
position: absolute;
bottom: 2rem;
left: 50%;
transform: translateX(-50%);
animation: bounce 2s ease-in-out infinite;
z-index: 2;
}
.hero-scroll svg {
width: 24px; height: 24px;
stroke: var(--muted);
}
/* Section styles */
.section {
padding: 6rem 2rem;
max-width: 1200px;
margin: 0 auto;
}
.section-label {
font-size: 0.75rem;
letter-spacing: 0.25em;
text-transform: uppercase;
color: var(--accent);
margin-bottom: 0.75rem;
}
.section-title {
font-size: clamp(2rem, 4vw, 3.2rem);
font-weight: 700;
line-height: 1.15;
margin-bottom: 1rem;
}
.section-desc {
color: var(--muted);
max-width: 600px;
font-size: 1.05rem;
}
/* Track cards */
.tracks-grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(220px, 1fr));
gap: 1.5rem;
margin-top: 2.5rem;
}
.track-card {
background: var(--card);
border: 1px solid var(--border);
border-radius: 12px;
padding: 1.5rem;
transition: all 0.4s cubic-bezier(0.22, 1, 0.36, 1);
cursor: pointer;
position: relative;
overflow: hidden;
}
.track-card::before {
content: '';
position: absolute;
inset: 0;
background: linear-gradient(135deg, rgba(201,151,78,0.05) 0%, transparent 60%);
opacity: 0;
transition: opacity 0.4s ease;
}
.track-card:hover {
border-color: var(--accent);
transform: translateY(-4px);
box-shadow: 0 16px 40px rgba(0,0,0,0.5);
}
.track-card:hover::before {
opacity: 1;
}
.track-number {
font-family: 'Inter', sans-serif;
font-size: 0.75rem;
color: var(--muted);
margin-bottom: 0.5rem;
}
.track-title {
font-size: 1.1rem;
font-weight: 600;
margin-bottom: 0.3rem;
}
.track-artist {
font-size: 0.85rem;
color: var(--muted);
margin-bottom: 0.75rem;
}
.track-duration {
font-size: 0.75rem;
color: var(--muted);
display: flex;
align-items: center;
gap: 0.5rem;
}
.track-duration svg {
width: 12px; height: 12px;
stroke: var(--muted);
}
/* Duration icon */
.duration-icon {
display: inline-flex;
align-items: center;
gap: 4px;
}
.duration-icon svg {
width: 14px; height: 14px;
stroke: var(--muted);
}
/* Artist profile */
.artist-profile {
display: flex;
align-items: center;
gap: 2rem;
padding: 2rem;
background: var(--card);
border: 1px solid var(--border);
border-radius: 16px;
margin-top: 2.5rem;
flex-wrap: wrap;
}
.artist-avatar {
width: 100px; height: 100px;
border-radius: 50%;
border: 3px solid var(--accent);
overflow: hidden;
flex-shrink: 0;
background: var(--bg-elevated);
}
.artist-avatar img {
width: 100%; height: 100%;
object-fit: cover;
}
.artist-info h3 {
font-size: 1.5rem;
font-weight: 700;
margin-bottom: 0.25rem;
}
.artist-info .artist-bio {
color: var(--muted);
font-size: 0.95rem;
margin-bottom: 0.75rem;
}
.artist-info .artist-meta {
display: flex;
gap: 1rem;
flex-wrap: wrap;
}
.artist-meta-item {
display: flex;
align-items: center;
gap: 0.35rem;
color: var(--muted);
font-size: 0.85rem;
}
.artist-meta-item svg {
width: 14px; height: 14px;
stroke: var(--muted);
}
.artist-meta-item strong {
color: var(--fg);
font-weight: 500;
}
/* Info grid */
.info-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
gap: 1.5rem;
margin-top: 2.5rem;
}
.info-item {
background: var(--card);
border: 1px solid var(--border);
border-radius: 10px;
padding: 1.5rem;
text-align: center;
transition: all 0.3s ease;
}
.info-item:hover {
border-color: var(--accent);
transform: translateY(-2px);
}
.info-item .info-icon {
width: 44px; height: 44px;
margin: 0 auto 0.75rem;
display: flex;
align-items: center;
justify-content: center;
background: rgba(201,151,78,0.1);
border-radius: 10px;
}
.info-item .info-icon svg {
width: 22px; height: 22px;
stroke: var(--accent);
}
.info-item .info-value {
font-size: 1.3rem;
font-weight: 700;
color: var(--accent);
margin-bottom: 0.15rem;
}
.info-item .info-label {
font-size: 0.8rem;
color: var(--muted);
}
/* Buttons */
.btn-primary {
display: inline-flex;
align-items: center;
gap: 0.5rem;
padding: 0.85rem 1.8rem;
background: var(--accent);
color: var(--bg);
font-weight: 600;
font-size: 0.95rem;
border-radius: 0;
border: none;
cursor: pointer;
transition: all 0.3s ease;
text-decoration: none;
}
.btn-primary:hover {
background: var(--accent-light);
transform: translateY(-2px);
box-shadow: 0 8px 24px rgba(201,151,78,0.3);
}
.btn-outline {
display: inline-flex;
align-items: center;
gap: 0.5rem;
padding: 0.85rem 1.8rem;
background: transparent;
color: var(--fg);
font-weight: 500;
font-size: 0.95rem;
border: 1px solid var(--border);
border-radius: 0;
cursor: pointer;
transition: all 0.3s ease;
text-decoration: none;
}
.btn-outline:hover {
border-color: var(--accent);
color: var(--accent);
transform: translateY(-2px);
}
/* Image styles */
.image-cover {
position: relative;
border-radius: 12px;
overflow: hidden;
}
.image-cover img {
width: 100%;
height: 100%;
object-fit: cover;
transition: transform 0.6s ease;
}
.image-cover:hover img {
transform: scale(1.03);
}
.image-overlay {
position: absolute;
inset: 0;
background: linear-gradient(to top, rgba(0,0,0,0.7) 0%, transparent 50%);
border-radius: 12px;
}
/* Floating particles */
.particle {
position: absolute;
width: 3px; height: 3px;
background: var(--accent);
border-radius: 50%;
opacity: 0;
animation: particle-float 6s ease-in-out infinite;
}
@keyframes particle-float {
0% { opacity: 0; transform: translateY(0) scale(0); }
30% { opacity: 0.6; }
70% { opacity: 0.3; }
100% { opacity: 0; transform: translateY(-200px) scale(1.5); }
}
/* Noise texture */
.noise-overlay {
position: fixed;
inset: 0;
z-index: 9998;
pointer-events: none;
opacity: 0.03;
background-image: url("data:image/svg+xml,%3Csvg viewBox='0 0 256 256' xmlns='http://www.w3.org/2000/svg'%3E%3Cfilter id='noise'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='4' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23noise)'/%3E%3C/svg%3E");
background-size: 256px 256px;
}
/* Wave animation */
.wave-bar {
display: inline-block;
width: 3px;
background: var(--accent);
border-radius: 2px;
margin: 0 1px;
transition: height 0.15s ease;
}
.wave-bar.active {
animation: wave 0.6s ease-in-out infinite;
}
@keyframes wave {
0%, 100% { height: 4px; }
50% { height: 20px; }
}
/* Parallax */
.parallax-section {
will-change: transform;
}
/* Toast */
.toast {
position: fixed;
bottom: 2rem;
right: 2rem;
background: var(--card);
border: 1px solid var(--accent);
border-radius: 10px;
padding: 1rem 1.5rem;
display: flex;
align-items: center;
gap: 0.75rem;
z-index: 1000;
transform: translateX(120%);
transition: transform 0.4s cubic-bezier(0.22, 1, 0.36, 1);
box-shadow: 0 8px 30px rgba(0,0,0,0.4);
}
.toast.show {
transform: translateX(0);
}
.toast svg {
width: 20px; height: 20px;
stroke: var(--accent);
}
/* Footer */
.site-footer {
padding: 3rem 2rem;
border-top: 1px solid var(--border);
margin-top: 3rem;
max-width: 1200px;
margin-left: auto;
margin-right: auto;
}
.footer-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
gap: 2rem;
}
.footer-brand h3 {
font-size: 1.25rem;
font-weight: 700;
color: var(--fg);
margin-bottom: 0.5rem;
}
.footer-brand p {
color: var(--muted);
font-size: 0.9rem;
}
.footer-links {
display: flex;
flex-wrap: wrap;
gap: 1rem;
}
.footer-links a {
color: var(--muted);
font-size: 0.85rem;
text-decoration: none;
transition: color 0.3s ease;
}
.footer-links a:hover {
color: var(--accent);
}
.footer-bottom {
margin-top: 2rem;
padding-top: 1.5rem;
border-top: 1px solid var(--border);
text-align: center;
color: var(--muted);
font-size: 0.8rem;
}
/* Scroll reveal */
.reveal {
opacity: 0;
transform: translateY(30px);
transition: opacity 0.8s ease, transform 0.8s ease;
}
.reveal.visible {
opacity: 1;
transform: translateY(0);
}
/* Responsive */
@media (max-width: 768px) {
.artist-profile { flex-direction: column; text-align: center; }
.artist-avatar { width: 140px; height: 140px; }
.info-grid { grid-template-columns: repeat(2, 1fr); }
.hero-orb-1 { width: 250px; height: 250px; }
.hero-orb-2 { width: 200px; height: 200px; }
}
@media (max-width: 480px) {
.hero-title { font-size: 2.5rem; }
.tracks-grid { grid-template-columns: 1fr; }
.info-grid { grid-template-columns: 1fr; }
.footer-grid { grid-template-columns: 1fr; }
}
/* Reduced motion */
@media (prefers-reduced-motion: reduce) {
*, *::before, *::after {
animation-duration: 0.01ms !important;
animation-iteration-count: 1 !important;
transition-duration: 0.01ms !important;
}
}
/* Focus styles */
*:focus-visible {
outline: 2px solid var(--accent);
outline-offset: 3px;
}
</style>
</head>
<body>
<div id="loader" aria-label="Loading">
<div class="loader-ring"></div>
<span class="text-sm" style="color: var(--muted);">Loading the next chapter...</span>
</div>
<div id="scroll-progress" aria-hidden="true"></div>
<div class="noise-overlay" aria-hidden="true"></div>
<!-- Toast notification -->
<div class="toast" id="toast" role="alert" aria-live="polite">
<svg 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"/>
<polyline points="22 4 12 14.01 9 11.01"/>
</svg>
<span id="toast-msg">Track added to your queue</span>
</div>
<!-- Navigation -->
<nav class="fixed top-0 left-0 right-0 z-50 transition-all duration-300" id="navbar" style="background: rgba(12,12,12,0.85); backdrop-filter: blur(16px); border-bottom: 1px solid transparent;" aria-label="Main navigation">
<div class="max-w-6xl mx-auto px-6 flex items-center justify-between h-16">
<a href="#" class="flex items-center gap-2" aria-label="Vessel Home">
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="var(--accent)" stroke-width="2">
<circle cx="12" cy="12" r="10"/>
<path d="M12 6v6l4 2"/>
</svg>
<span class="font-bold text-lg" style="color: var(--fg);">Vessel</span>
</a>
<div class="hidden md:flex items-center gap-8">
<a href="#tracks" class="text-sm" style="color: var(--muted); text-decoration: none; transition: color 0.3s;">Tracks</a>
<a href="#artist" class="text-sm" style="color: var(--muted); text-decoration: none; transition: color 0.3s;">About</a>
<a href="#info" class="text-sm" style="color: var(--muted); text-decoration: none; transition: color 0.3s;">Details</a>
<button class="btn-primary text-sm" style="padding: 0.5rem 1.2rem; font-size: 0.85rem;" onclick="showToast('Track queue updated')">
Queue Now
</button>
</div>
<button class="md:hidden" id="mobile-menu-btn" aria-label="Toggle menu" style="background: none; border: none; color: var(--fg); font-size: 1.5rem; cursor: pointer;">
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round">
<line x1="3" y1="6" x2="21" y2="6"/>
<line x1="3" y1="12" x2="21" y2="12"/>
<line x1="3" y1="18" x2="21" y2="18"/>
</svg>
</button>
</div>
<div class="md:hidden hidden" id="mobile-menu">
<div class="px-6 py-4 flex flex-col gap-4">
<a href="#tracks" class="text-sm" style="color: var(--muted); text-decoration: none;">Tracks</a>
<a href="#artist" class="text-sm" style="color: var(--muted); text-decoration: none;">About</a>
<a href="#info" class="text-sm" style="color: var(--muted); text-decoration: none;">Details</a>
<button class="btn-primary text-sm" style="padding: 0.5rem 1.2rem; font-size: 0.85rem; align-self: center;">Queue Now</button>
</div>
</div>
</nav>
<!-- Hero Section -->
<section class="hero-section" aria-label="Hero">
<div class="hero-bg" aria-hidden="true"></div>
<div class="hero-grain" aria-hidden="true"></div>
<div class="hero-orb hero-orb-1" aria-hidden="true"></div>
<div class="hero-orb hero-orb-2" aria-hidden="true"></div>
<div class="hero-content">
<p class="hero-label" style="animation-delay: 0.2s">New Release — March 2025</p>
<h1 class="hero-title">
<span class="highlight">Vessel</span>
<span class="text-2xl sm:text-3xl" style="color: var(--muted); font-weight: 400; margin-left: 0.5rem;">.3</span>
</h1>
<p class="hero-sub">A new chapter. Four songs. One vision. The world is waiting.</p>
<a href="#tracks" class="hero-cta">Explore the Release</a>
</div>
<div class="hero-scroll" aria-hidden="true">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<path d="M12 5v14M5 12l7 7 7-7"/>
</svg>
</div>
</section>
<!-- Track Listing -->
<section id="tracks" class="section" aria-label="Track listing">
<div class="max-w-6xl mx-auto">
<div class="reveal">
<p class="section-label">Now Available</p>
<h2 class="section-title">Track Listing</h2>
<p class="section-desc">Four compositions exploring the spaces between silence and sound.</p>
</div>
<div class="tracks-grid">
<!-- Track 1 -->
<div class="track-card reveal" tabindex="0" role="button" aria-label="Open Track 1: 'Horizon Line'" onclick="addToQueue(1)">
<div class="track-number">Track 01</div>
<h3 class="track-title">Horizon Line</h3>
<p class="track-artist">by Vessel</p>
<div class="track-duration">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" width="12" height="12">
<circle cx="12" cy="12" r="10"/>
<path d="M12 6v6l4 2"/>
</svg>
<span>5:24</span>
</div>
</div>
<!-- Track 2 -->
<div class="track-card reveal" tabindex="0" role="button" aria-label="Open Track 2: 'Widow's Bridge'" onclick="addToQueue(2)">
<div class="track-number">Track 02</div>
<h3 class="track-title">Widow's Bridge</h3>
<p class="track-artist">by Vessel</p>
<div class="track-duration">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" width="12" height="12">
<circle cx="12" cy="12" r="10"/>
<path d="M12 6v6l4 2"/>
</svg>
<span>4:18</span>
</div>
</div>
<!-- Track 3 -->
<div class="track-card reveal" tabindex="0" role="button" aria-label="Open Track 3: 'Still Life'" onclick="addToQueue(3)">
<div class="track-number">Track 03</div>
<h3 class="track-title">Still Life</h3>
<p class="track-artist">by Vessel</p>
<div class="track-duration">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" width="12" height="12">
<circle cx="12" cy="12" r="10"/>
<path d="M12 6v6l4 2"/>
</svg>
<span>6:07</span>
</div>
</div>
<!-- Track 4 -->
<div class="track-card reveal" tabindex="0" role="button" aria-label="Open Track 4: 'Ember Protocol'" onclick="addToQueue(4)">
<div class="track-number">Track 04</div>
<h3 class="track-title">Ember Protocol</h3>
<p class="track-artist">by Vessel</p>
<div class="track-duration">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" width="12" height="12">
<circle cx="12" cy="12" r="10"/>
<path d="M12 6v6l4 2"/>
</svg>
<span>4:53</span>
</div>
</div>
</div>
</div>
</section>
<!-- Artist Profile -->
<section id="artist" class="section" aria-label="Artist profile">
<div class="max-w-6xl mx-auto">
<div class="reveal">
<p class="section-label">The Artist</p>
<h2 class="section-title">Meet Vessel</h2>
<p class="section-desc">A solo project rooted in the tension between minimalism and emotion — a voice that carries the weight of silence.</p>
</div>
<div class="artist-profile reveal">
<div class="artist-avatar" aria-label="Vessel avatar">
<img src="https://images.pexels.com/photo/2021/10/10/pexels-photo-2021-10-10-photo-2021-10-10-photo.jpeg?auto=compress&cs=tinysrgb&w=400&h=400&fit=crop" alt="Portrait of Vessel, a musician" loading="lazy">
</div>
<div class="artist-info">
<h3>Vessel</h3>
<p class="artist-bio">Elena Voss. Singer, songwriter, and sound architect. Based in Portland, Oregon. Producing since 2018.</p>
<div class="artist-meta">
<div class="artist-meta-item">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" width="14" height="14">
<path d="M12 2L2 7l10 5 10-5-10-5z"/>
<path d="M2 17l10 5 10-5"/>
<path d="M2 12l10 5 10-5"/>
</svg>
<strong>5 releases</strong>
</div>
<div class="artist-meta-item">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" width="14" height="14">
<path d="M20.84 4.61a5.5 5.5 0 0 0-7.78 7.78l1.84 1.84a.7.7 0 0 1 0 1.01l-2.23 2.23a6.6 6.6 0 0 0 9.6 9.6l2.23-2.23a.7.7 0 0 1 1.01 0l1.84 1.84a5.5 5.5 0 0 0 7.78-7.78L13.5 12l2.23-2.23"/>
</svg>
<strong>3 years</strong>
</div>
<div class="artist-meta-item">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" width="14" height="14">
<circle cx="12" cy="12" r="10"/>
<path d="M2 12h20"/>
</svg>
<strong>600K+</strong>
</div>
</div>
</div>
</div>
<div class="info-grid reveal">
<div class="info-item">
<div class="info-icon">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" width="22" height="22">
<path d="M12 2L2 7l10 5 10-5-10-5z"/>
</svg>
</div>
<div class="info-value">17</div>
<div class="info-label">Songs</div>
</div>
<div class="info-item">
<div class="info-icon">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" width="22" height="22">
<path d="M12 2L2 7l10 5 10-5-10-5z"/>
</svg>
</div>
<div class="info-value">2025</div>
<div class="info-label">Released</div>
</div>
<div class="info-item">
<div class="info-icon">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" width="22" height="22">
<path d="M12 2L2 7l10 5 10-5-10-5z"/>
</svg>
</div>
<div class="info-value">1.6</div>
<div class="info-label">Avg Rating</div>
</div>
<div class="info-item">
<div class="info-icon">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" width="22" height="22">
<path d="M12 2L2 7l10 5 10-5-10-5z"/>
</svg>
</div>
<div class="info-value">15</div>
<div class="info-label">Countries</div>
</div>
</div>
</div>
</section>
<!-- Details -->
<section id="info" class="section" aria-label="Release details">
<div class="max-w-6xl mx-auto">
<div class="reveal">
<p class="section-label">Release Details</p>
<h2 class="section-title">What's Inside</h2>
<p class="section-desc">The complete collection — formats, tracks, and everything that comes with the release.</p>
</div>
<div class="info-grid reveal">
<div class="info-item">
<div class="info-icon">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" width="22" height="22">
<path d="M12 2L2 7l10 5 10-5-10-5z"/>
</svg>
</div>
<div class="info-value">Digital</div>
<div class="info-label">Available</div>
</div>
<div class="info-item">
<div class="info-icon">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" width="22" height="22">
<path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"/>
<polyline points="7 10 12 15 17 10"/>
<line x1="12" y1="15" x2="12" y2="3"/>
</svg>
</div>
<div class="info-value">320kbps</div>
<div class="info-label">Quality</div>
</div>
<div class="info-item">
<div class="info-icon">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" width="22" height="22">
<circle cx="12" cy="12" r="10"/>
<path d="M12 8v4l3 3"/>
</svg>
</div>
<div class="info-value">March 14</div>
<div class="info-label">Release Date</div>
</div>
<div class="info-item">
<div class="info-icon">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" width="22" height="22">
<path d="M4 19.5A2.5 2.5 0 0 1 6.5 17H20"/>
<path d="M6.5 2H20v20H6.5A2.5 2.5 0 0 1 4 19.5v-15A2.5 2.5 0 0 1 6.5 2z"/>
</svg>
</div>
<div class="info-value">LP + Digital</div>
<div class="info-label">Formats</div>
</div>
</div>
</div>
</section>
<!-- CTA -->
<section class="section" aria-label="Call to action">
<div class="max-w-4xl mx-auto text-center">
<div class="reveal">
<p class="section-label">Get Involved</p>
<h2 class="section-title">Join the Wave</h2>
<p class="section-desc">Sign up for our newsletter and be among the first to know when new music drops.</p>
</div>
<div class="reveal" style="margin-top: 2rem;">
<form id="newsletter-form" style="display: flex; gap: 0.5rem; max-width: 500px; margin: 0 auto;" onsubmit="handleNewsletter(event)" novalidate>
<label for="email-input" class="sr-only" style="position:absolute;width:1px;height:1px;overflow:hidden;clip:rect(0,0,0,0);">Email address</label>
<input type="email" id="email-input" placeholder="your@email.com" required
style="flex:1; padding: 0.85rem 1rem; background: var(--card); border: 1px solid var(--border); border-radius: 0; color: var(--fg); font-size: 0.95rem; outline: none; transition: border-color 0.3s;"
onfocus="this.style.borderColor='var(--accent)'" onblur="this.style.borderColor='var(--border)'"
aria-label="Email address">
<button type="submit" class="btn-primary" style="padding: 0.85rem 1.5rem; font-size: 0.9rem;">Subscribe</button>
</form>
</div>
</div>
</section>
<!-- Footer -->
<footer class="site-footer">
<div class="max-w-6xl mx-auto">
<div class="footer-grid">
<div class="footer-brand">
<h3>Vessel</h3>
<p>A record label and music project. Created with care.</p>
</div>
<div>
<p class="text-sm font-semibold" style="color: var(--fg); margin-bottom: 0.75rem;">Navigation</p>
<div class="footer-links">
<a href="#tracks">Tracks</a>
<a href="#artist">About</a>
<a href="#info">Details</a>
</div>
</div>
<div>
<p class="text-sm font-semibold" style="color: var(--fg); margin-bottom: 0.75rem;">Contact</p>
<div class="footer-links">
<a href="#">hello@vessel.music</a>
<a href="#">@vessel_music</a>
</div>
</div>
</div>
<div class="footer-bottom">
<p>2025 Vessel. All rights reserved.</p>
<p style="margin-top: 0.25rem;">Crafted with care in the Pacific Northwest</p>
</div>
</div>
</footer>
<script>
// --- Loading screen ---
window.addEventListener('load', () => {
setTimeout(() => {
document.getElementById('loader').classList.add('hidden');
}, 800);
});
// --- Scroll progress bar ---
const scrollBar = document.getElementById('scroll-progress');
window.addEventListener('scroll', () => {
const scrollTop = window.scrollY;
const docHeight = document.documentElement.scrollHeight - window.innerHeight;
const progress = (scrollTop / docHeight) * 100;
scrollBar.style.width = progress + '%';
});
// --- Navbar scroll effect ---
const navbar = document.getElementById('navbar');
window.addEventListener('scroll', () => {
if (window.scrollY > 50) {
navbar.style.borderBottomColor = 'var(--border)';
navbar.style.background = 'rgba(12,12,12,0.95)';
} else {
navbar.style.borderBottomColor = 'transparent';
navbar.style.background = 'rgba(12,12,12,0.85)';
}
});
// --- Mobile menu ---
const mobileBtn = document.getElementById('mobile-menu-btn');
const mobileMenu = document.getElementById('mobile-menu');
let menuOpen = false;
mobileBtn.addEventListener('click', () => {
menuOpen = !menuOpen;
mobileMenu.classList.toggle('hidden', !menuOpen);
});
// Close mobile menu on link click
mobileMenu.querySelectorAll('a').forEach(a => {
a.addEventListener('click', () => {
menuOpen = false;
mobileMenu.classList.add('hidden');
});
});
// --- Scroll reveal ---
const revealElements = document.querySelectorAll('.reveal');
const revealObserver = new IntersectionObserver((entries) => {
entries.forEach(entry => {
if (entry.isIntersecting) {
entry.target.classList.add('visible');
}
});
}, {
threshold: 0.1,
rootMargin: '0px 0px -40px 0px'
});
revealElements.forEach(el => revealObserver.observe(el));
// --- Toast ---
function showToast(message) {
const toast = document.getElementById('toast');
const toastMsg = document.getElementById('toast-msg');
toastMsg.textContent = message;
toast.classList.add('show');
setTimeout(() => {
toast.classList.remove('show');
}, 3000);
}
function addToQueue(trackNum) {
showToast(`"Track ${trackNum}" added to your queue`);
}
function handleNewsletter(e) {
e.preventDefault();
const emailInput = document.getElementById('email-input');
const email = emailInput.value;
if (email && email.includes('@') && email.includes('.')) {
showToast('Welcome to the newsletter. Check your inbox.');
emailInput.value = '';
} else {
showToast('Please enter a valid email address.');
}
}
// --- Audio waveform animation (visual only) ---
const waveBars = Array.from({length: 24}, (_, i) => {
const bar = document.createElement('div');
bar.className = 'wave-bar';
bar.style.height = '4px';
bar.style.background = 'var(--accent)';
bar.style.borderRadius = '2px';
bar.style.position = 'absolute';
bar.style.bottom = '0';
bar.style.left = `${i * 1.5}%`;
bar.style.width = '1.5px';
bar.style.transition = 'height 0.3s ease';
document.querySelector('.hero-section').appendChild(bar);
return bar;
});
// Animate wave bars on scroll
let waveAnimated = false;
window.addEventListener('scroll', () => {
if (waveAnimated) return;
const scrollBottom = window.scrollY > window.innerHeight * 0.7;
if (scrollBottom && !waveAnimated) {
waveAnimated = true;
waveBars.forEach(bar => {
const height = Math.random() * 120 + 4;
bar.style.height = height + 'px';
bar.style.background = Math.random() > 0.5 ? 'var(--accent)' : 'var(--accent-light)';
});
setTimeout(() => {
waveBars.forEach(bar => {
bar.style.height = '4px';
bar.style.background = 'var(--accent)';
});
waveAnimated = false;
}, 2000);
}
});
// --- Parallax effect for hero section ---
window.addEventListener('scroll', () => {
const heroContent = document.querySelector('.hero-content');
const scrollY = window.scrollY;
if (scrollY < window.innerHeight) {
heroContent.style.transform = `translateY(${scrollY * 0.15}px)`;
heroContent.style.opacity = 1 - (scrollY / window.innerHeight) * 0.3;
}
});
// --- Smooth scroll for anchor links ---
document.querySelectorAll('a[href^="#"]').forEach(anchor => {
anchor.addEventListener('click', (e) => {
e.preventDefault();
const target = document.querySelector(anchor.getAttribute('href'));
if (target) {
target.scrollIntoView({ behavior: 'smooth' });
}
});
});
// --- Keyboard accessibility for track cards ---
document.querySelectorAll('.track-card').forEach(card => {
card.addEventListener('keydown', (e) => {
if (e.key === 'Enter' || e.key === ' ') {
e.preventDefault();
card.click();
}
});
});
</script>
<div style="position:fixed;right:12px;bottom:12px;z-index:2147483647;background:rgba(17,24,39,.92);color:#fff;padding:8px 10px;border-radius:10px;font:12px/1.3 ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;box-shadow:0 8px 20px rgba(0,0,0,.28)">Generated in 70.17s<br>Model: bloomer010/Ling-3.0-tiny-GGUF:Q4_K_M</div></body>
</html>