Mursey

*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }

“`
:root {
–ink: #0f0d0a;
–paper: #f5f0e8;
–cream: #ede6d6;
–rust: #b84c2b;
–gold: #c9963a;
–muted: #7a7060;
–serif: ‘Playfair Display’, Georgia, serif;
–mono: ‘Courier Prime’, ‘Courier New’, monospace;
}

html { scroll-behavior: smooth; }

body {
background: var(–paper);
color: var(–ink);
font-family: var(–mono);
overflow-x: hidden;
cursor: none;
}

/* Custom cursor */
.cursor {
position: fixed;
width: 12px; height: 12px;
background: var(–rust);
border-radius: 50%;
pointer-events: none;
z-index: 9999;
transform: translate(-50%, -50%);
transition: transform 0.1s, width 0.2s, height 0.2s;
mix-blend-mode: multiply;
}
.cursor-ring {
position: fixed;
width: 36px; height: 36px;
border: 1.5px solid var(–rust);
border-radius: 50%;
pointer-events: none;
z-index: 9998;
transform: translate(-50%, -50%);
transition: transform 0.15s ease-out, width 0.3s, height 0.3s, opacity 0.3s;
opacity: 0.5;
}

/* Noise overlay */
body::before {
content: ”;
position: fixed;
inset: 0;
background-image: url(“data:image/svg+xml,%3Csvg viewBox=’0 0 200 200′ xmlns=’http://www.w3.org/2000/svg’%3E%3Cfilter id=’n’%3E%3CfeTurbulence type=’fractalNoise’ baseFrequency=’0.75′ numOctaves=’4′ stitchTiles=’stitch’/%3E%3C/filter%3E%3Crect width=’100%25′ height=’100%25′ filter=’url(%23n)’ opacity=’0.04’/%3E%3C/svg%3E”);
pointer-events: none;
z-index: 1;
opacity: 0.4;
}

/* ── NAV ── */
nav {
position: fixed;
top: 0; left: 0; right: 0;
z-index: 100;
display: flex;
justify-content: space-between;
align-items: center;
padding: 1.4rem 3rem;
mix-blend-mode: multiply;
}
.nav-logo {
font-family: var(–serif);
font-size: 1.1rem;
font-weight: 900;
letter-spacing: 0.25em;
text-transform: uppercase;
color: var(–ink);
text-decoration: none;
}
.nav-links { display: flex; gap: 2.5rem; list-style: none; }
.nav-links a {
font-size: 0.7rem;
letter-spacing: 0.2em;
text-transform: uppercase;
text-decoration: none;
color: var(–muted);
transition: color 0.2s;
}
.nav-links a:hover { color: var(–rust); }

/* ── HERO ── */
#hero {
min-height: 100vh;
display: grid;
grid-template-columns: 1fr 1fr;
position: relative;
overflow: hidden;
}

.hero-left {
display: flex;
flex-direction: column;
justify-content: flex-end;
padding: 8rem 3rem 5rem 3rem;
position: relative;
z-index: 2;
}

.hero-tag {
font-size: 0.65rem;
letter-spacing: 0.3em;
text-transform: uppercase;
color: var(–rust);
margin-bottom: 1.5rem;
opacity: 0;
animation: fadeUp 0.8s 0.3s forwards;
}

.hero-title {
font-family: var(–serif);
font-size: clamp(5rem, 9vw, 8.5rem);
font-weight: 900;
font-style: italic;
line-height: 0.88;
color: var(–ink);
opacity: 0;
animation: fadeUp 0.9s 0.5s forwards;
}

.hero-title span {
display: block;
color: var(–rust);
}

.hero-sub {
margin-top: 2rem;
font-size: 0.75rem;
letter-spacing: 0.15em;
line-height: 1.8;
color: var(–muted);
max-width: 320px;
opacity: 0;
animation: fadeUp 0.8s 0.8s forwards;
}

.hero-cta {
margin-top: 3rem;
display: inline-flex;
align-items: center;
gap: 1rem;
font-size: 0.7rem;
letter-spacing: 0.2em;
text-transform: uppercase;
text-decoration: none;
color: var(–ink);
border-bottom: 1px solid var(–ink);
padding-bottom: 0.3rem;
opacity: 0;
animation: fadeUp 0.8s 1s forwards;
transition: color 0.2s, border-color 0.2s;
}
.hero-cta:hover { color: var(–rust); border-color: var(–rust); }
.hero-cta::after { content: ‘→’; }

.hero-right {
position: relative;
background: var(–cream);
overflow: hidden;
opacity: 0;
animation: fadeIn 1.2s 0.4s forwards;
}

/* Decorative score lines */
.hero-right::before {
content: ”;
position: absolute;
inset: 0;
background-image: repeating-linear-gradient(
0deg,
transparent,
transparent 28px,
rgba(15,13,10,0.07) 28px,
rgba(15,13,10,0.07) 29px
);
pointer-events: none;
}

.hero-art {
position: absolute;
inset: 0;
display: flex;
align-items: center;
justify-content: center;
}

.hero-art svg {
width: 60%;
opacity: 0.13;
}

.hero-number {
position: absolute;
bottom: 3rem;
right: 3rem;
font-family: var(–serif);
font-size: 10rem;
font-weight: 900;
color: var(–ink);
opacity: 0.04;
line-height: 1;
user-select: none;
}

/* Vertical rule */
.v-rule {
position: absolute;
left: 50%;
top: 10%;
bottom: 10%;
width: 1px;
background: var(–ink);
opacity: 0.12;
}

/* Scroll indicator */
.scroll-hint {
position: absolute;
bottom: 2.5rem;
left: 3rem;
display: flex;
align-items: center;
gap: 0.8rem;
font-size: 0.6rem;
letter-spacing: 0.25em;
text-transform: uppercase;
color: var(–muted);
opacity: 0;
animation: fadeIn 1s 1.4s forwards;
}
.scroll-line {
width: 40px;
height: 1px;
background: var(–muted);
position: relative;
overflow: hidden;
}
.scroll-line::after {
content: ”;
position: absolute;
left: -100%;
top: 0;
width: 100%;
height: 100%;
background: var(–rust);
animation: scanLine 2s 1.8s infinite;
}

/* ── SECTION BASE ── */
section {
position: relative;
z-index: 2;
}

.section-label {
font-size: 0.6rem;
letter-spacing: 0.35em;
text-transform: uppercase;
color: var(–rust);
margin-bottom: 1rem;
}

.section-title {
font-family: var(–serif);
font-size: clamp(2.5rem, 4vw, 3.8rem);
font-weight: 700;
line-height: 1.1;
color: var(–ink);
}

/* ── ABOUT ── */
#about {
padding: 9rem 3rem;
display: grid;
grid-template-columns: 1fr 2fr;
gap: 6rem;
align-items: start;
border-top: 1px solid rgba(15,13,10,0.12);
}

.about-left { position: sticky; top: 8rem; }

.about-body {
font-size: 1rem;
line-height: 1.9;
color: var(–ink);
font-family: var(–mono);
}

.about-body p { margin-bottom: 1.5rem; }

.members {
margin-top: 3.5rem;
display: grid;
grid-template-columns: 1fr 1fr;
gap: 2rem;
}

.member-card {
padding: 1.8rem;
border: 1px solid rgba(15,13,10,0.12);
position: relative;
background: var(–cream);
transition: transform 0.3s, box-shadow 0.3s;
}
.member-card:hover {
transform: translateY(-4px);
box-shadow: 6px 6px 0 var(–rust);
}
.member-card::before {
content: attr(data-num);
position: absolute;
top: 1rem; right: 1.2rem;
font-family: var(–serif);
font-size: 3rem;
font-weight: 900;
color: var(–ink);
opacity: 0.05;
}

.member-name {
font-family: var(–serif);
font-size: 1.3rem;
font-weight: 700;
font-style: italic;
margin-bottom: 0.4rem;
}
.member-role {
font-size: 0.65rem;
letter-spacing: 0.2em;
text-transform: uppercase;
color: var(–rust);
}

/* ── PORTFOLIO ── */
#portfolio {
padding: 9rem 3rem;
border-top: 1px solid rgba(15,13,10,0.12);
background: var(–ink);
color: var(–paper);
}

#portfolio .section-label { color: var(–gold); }
#portfolio .section-title { color: var(–paper); }

.portfolio-header {
display: flex;
justify-content: space-between;
align-items: flex-end;
margin-bottom: 4rem;
}

.portfolio-grid {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 1.5px;
}

.portfolio-item {
aspect-ratio: 4/3;
background: #1a1814;
position: relative;
overflow: hidden;
cursor: none;
}

.portfolio-item:first-child {
grid-column: span 2;
aspect-ratio: auto;
}

.portfolio-bg {
position: absolute;
inset: 0;
background: linear-gradient(135deg, #1e1b15, #2a2520);
transition: transform 0.6s ease;
}

/* Musical note pattern per card */
.portfolio-item:nth-child(1) .portfolio-bg { background: linear-gradient(135deg, #1e1b15 0%, #2e2318 100%); }
.portfolio-item:nth-child(2) .portfolio-bg { background: linear-gradient(135deg, #181c1e 0%, #1e2828 100%); }
.portfolio-item:nth-child(3) .portfolio-bg { background: linear-gradient(135deg, #1e1518 0%, #2a1e20 100%); }
.portfolio-item:nth-child(4) .portfolio-bg { background: linear-gradient(135deg, #181618 0%, #241824 100%); }

.portfolio-item:hover .portfolio-bg { transform: scale(1.04); }

.portfolio-lines {
position: absolute;
inset: 0;
background-image: repeating-linear-gradient(
0deg,
transparent,
transparent 22px,
rgba(255,255,255,0.04) 22px,
rgba(255,255,255,0.04) 23px
);
}

.portfolio-content {
position: absolute;
inset: 0;
padding: 2rem;
display: flex;
flex-direction: column;
justify-content: flex-end;
background: linear-gradient(to top, rgba(0,0,0,0.7) 0%, transparent 60%);
}

.portfolio-type {
font-size: 0.58rem;
letter-spacing: 0.3em;
text-transform: uppercase;
color: var(–gold);
margin-bottom: 0.5rem;
}

.portfolio-name {
font-family: var(–serif);
font-size: 1.5rem;
font-weight: 700;
font-style: italic;
color: var(–paper);
margin-bottom: 0.3rem;
}

.portfolio-detail {
font-size: 0.65rem;
letter-spacing: 0.1em;
color: rgba(245,240,232,0.5);
}

/* Large decorative note */
.deco-note {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
font-size: 8rem;
opacity: 0.04;
pointer-events: none;
user-select: none;
transition: opacity 0.4s;
}
.portfolio-item:hover .deco-note { opacity: 0.07; }

/* ── CONTACT ── */
#contact {
padding: 9rem 3rem;
border-top: 1px solid rgba(15,13,10,0.12);
display: grid;
grid-template-columns: 1fr 1fr;
gap: 6rem;
align-items: center;
}

.contact-left .section-title {
margin-bottom: 2rem;
}

.contact-intro {
font-size: 0.85rem;
line-height: 1.9;
color: var(–muted);
max-width: 380px;
}

.contact-form {
display: flex;
flex-direction: column;
gap: 0;
}

.form-row {
border-top: 1px solid rgba(15,13,10,0.15);
display: flex;
align-items: stretch;
}
.form-row:last-of-type { border-bottom: 1px solid rgba(15,13,10,0.15); }

.form-label {
font-size: 0.58rem;
letter-spacing: 0.25em;
text-transform: uppercase;
color: var(–muted);
min-width: 80px;
padding: 1.2rem 0;
display: flex;
align-items: center;
}

.form-input {
flex: 1;
background: transparent;
border: none;
outline: none;
font-family: var(–mono);
font-size: 0.85rem;
color: var(–ink);
padding: 1.2rem 1rem;
resize: none;
}

.form-input::placeholder { color: rgba(15,13,10,0.25); }

.form-input:focus {
background: rgba(184,76,43,0.03);
}

.form-submit {
margin-top: 2.5rem;
display: inline-flex;
align-items: center;
gap: 1rem;
background: var(–ink);
color: var(–paper);
border: none;
padding: 1.1rem 2.5rem;
font-family: var(–mono);
font-size: 0.7rem;
letter-spacing: 0.2em;
text-transform: uppercase;
cursor: none;
transition: background 0.2s, transform 0.15s;
align-self: flex-start;
}
.form-submit:hover { background: var(–rust); transform: translateX(4px); }
.form-submit::after { content: ‘→’; }

/* ── FOOTER ── */
footer {
padding: 2.5rem 3rem;
border-top: 1px solid rgba(15,13,10,0.12);
display: flex;
justify-content: space-between;
align-items: center;
position: relative;
z-index: 2;
}

.footer-name {
font-family: var(–serif);
font-size: 0.9rem;
font-weight: 700;
font-style: italic;
color: var(–ink);
}

.footer-copy {
font-size: 0.6rem;
letter-spacing: 0.15em;
color: var(–muted);
}

/* ── ANIMATIONS ── */
@keyframes fadeUp {
from { opacity: 0; transform: translateY(24px); }
to { opacity: 1; transform: translateY(0); }
}
@keyframes fadeIn {
from { opacity: 0; }
to { opacity: 1; }
}
@keyframes scanLine {
from { left: -100%; }
to { left: 100%; }
}

/* Scroll reveal */
.reveal {
opacity: 0;
transform: translateY(30px);
transition: opacity 0.7s ease, transform 0.7s ease;
}
.reveal.visible {
opacity: 1;
transform: translateY(0);
}

/* ── LISTEN / MUSIC PLAYER ── */
#listen {
padding: 9rem 3rem;
border-top: 1px solid rgba(15,13,10,0.12);
background: var(–cream);
}

.listen-header {
display: flex;
justify-content: space-between;
align-items: flex-end;
margin-bottom: 4rem;
}

.player-wrap {
display: grid;
grid-template-columns: 1fr 1.6fr;
gap: 3rem;
align-items: start;
}

/* Track list */
.tracklist {
border-top: 1px solid rgba(15,13,10,0.15);
}

.track-row {
display: flex;
align-items: center;
gap: 1.2rem;
padding: 1.1rem 0;
border-bottom: 1px solid rgba(15,13,10,0.1);
cursor: none;
transition: background 0.2s;
position: relative;
}
.track-row:hover { background: rgba(184,76,43,0.04); }
.track-row.active { background: rgba(184,76,43,0.06); }
.track-row.active .track-title { color: var(–rust); }

.track-num {
font-family: var(–serif);
font-size: 0.75rem;
color: var(–muted);
min-width: 1.8rem;
text-align: right;
font-style: italic;
transition: opacity 0.2s;
}
.track-row.active .track-num,
.track-row:hover .track-num { opacity: 0; }

.track-play-icon {
position: absolute;
left: 0;
font-size: 0.7rem;
color: var(–rust);
opacity: 0;
transition: opacity 0.2s;
}
.track-row:hover .track-play-icon,
.track-row.active .track-play-icon { opacity: 1; }
.track-row.active.playing .track-play-icon::after { content: ‘▐▐’; }
.track-row.active:not(.playing) .track-play-icon::after { content: ‘▶’; }
.track-row:not(.active):hover .track-play-icon::after { content: ‘▶’; }

.track-info { flex: 1; }
.track-title {
font-family: var(–serif);
font-size: 1rem;
font-weight: 700;
font-style: italic;
color: var(–ink);
transition: color 0.2s;
}
.track-meta {
font-size: 0.6rem;
letter-spacing: 0.15em;
text-transform: uppercase;
color: var(–muted);
margin-top: 0.2rem;
}
.track-duration {
font-size: 0.65rem;
color: var(–muted);
font-family: var(–mono);
}

/* Player card */
.player-card {
background: var(–ink);
color: var(–paper);
padding: 2.5rem;
position: sticky;
top: 8rem;
}

.player-now-label {
font-size: 0.58rem;
letter-spacing: 0.3em;
text-transform: uppercase;
color: var(–gold);
margin-bottom: 1.5rem;
}

.player-track-title {
font-family: var(–serif);
font-size: 1.8rem;
font-weight: 700;
font-style: italic;
line-height: 1.15;
margin-bottom: 0.4rem;
}

.player-track-meta {
font-size: 0.65rem;
letter-spacing: 0.15em;
text-transform: uppercase;
color: rgba(245,240,232,0.4);
margin-bottom: 2rem;
}

/* Waveform visualizer (canvas) */
.waveform-wrap {
margin-bottom: 1rem;
position: relative;
height: 60px;
cursor: none;
}
#waveCanvas {
width: 100%;
height: 100%;
display: block;
}

/* Progress bar */
.progress-wrap {
position: relative;
height: 2px;
background: rgba(245,240,232,0.15);
margin-bottom: 0.6rem;
cursor: none;
}
.progress-fill {
height: 100%;
background: var(–rust);
width: 0%;
transition: width 0.3s linear;
pointer-events: none;
}
.progress-handle {
position: absolute;
top: 50%;
transform: translate(-50%, -50%);
width: 10px; height: 10px;
background: var(–paper);
border-radius: 50%;
left: 0%;
transition: left 0.3s linear;
pointer-events: none;
}

.time-row {
display: flex;
justify-content: space-between;
font-size: 0.6rem;
color: rgba(245,240,232,0.4);
margin-bottom: 2rem;
font-family: var(–mono);
}

/* Controls */
.player-controls {
display: flex;
align-items: center;
justify-content: center;
gap: 2rem;
}

.ctrl-btn {
background: none;
border: none;
color: rgba(245,240,232,0.5);
font-size: 1rem;
cursor: none;
padding: 0.4rem;
transition: color 0.2s, transform 0.15s;
line-height: 1;
}
.ctrl-btn:hover { color: var(–paper); transform: scale(1.1); }

.ctrl-play {
width: 52px; height: 52px;
border-radius: 50%;
border: 1.5px solid rgba(245,240,232,0.3) !important;
display: flex; align-items: center; justify-content: center;
font-size: 1.1rem !important;
color: var(–paper) !important;
transition: border-color 0.2s, background 0.2s, transform 0.15s !important;
}
.ctrl-play:hover { border-color: var(–rust) !important; background: rgba(184,76,43,0.15) !important; }

/* Volume */
.volume-row {
display: flex;
align-items: center;
gap: 0.8rem;
margin-top: 1.8rem;
}
.vol-icon { font-size: 0.75rem; color: rgba(245,240,232,0.4); }
.vol-slider {
flex: 1;
-webkit-appearance: none;
height: 2px;
background: rgba(245,240,232,0.15);
outline: none;
cursor: none;
}
.vol-slider::-webkit-slider-thumb {
-webkit-appearance: none;
width: 10px; height: 10px;
background: var(–paper);
border-radius: 50%;
cursor: none;
}

/* ── RESPONSIVE ── */
@media (max-width: 900px) {
#hero { grid-template-columns: 1fr; }
.hero-right { display: none; }
.v-rule { display: none; }
#about { grid-template-columns: 1fr; gap: 3rem; }
.about-left { position: static; }
.members { grid-template-columns: 1fr; }
.portfolio-grid { grid-template-columns: 1fr; }
.portfolio-item:first-child { grid-column: span 1; }
#contact { grid-template-columns: 1fr; gap: 3rem; }
nav { padding: 1.2rem 1.5rem; }
#hero, #about, #portfolio, #listen, #contact { padding-left: 1.5rem; padding-right: 1.5rem; }
.player-wrap { grid-template-columns: 1fr; }
.player-card { position: static; }
footer { padding: 2rem 1.5rem; }
}
“`

Two voices. One sound.

Mursey

Guitar. Vocals. Percussion.
Acoustic duo forging something raw,
intimate, and entirely their own.

Explore the work

01

Scroll

Who
we are

Mursey is the creative partnership of Harry Hussey and Carolynn — two guitarists, two voices, one shared musical vision. Built on layered acoustics and close-knit harmonies, their sound lives somewhere between folk intimacy and something harder to name.

Together they write, arrange, and perform everything themselves — no backing tracks, no fuss. Just the instruments, the voices, and whatever a room can hold.

“`

Harry Hussey

Guitar & Vocals

Carolynn

Guitar, Vocals & Percussion

“`

The Work

“`

EP · 2024

Still Water

6 tracks — self-recorded, self-released

Live · 2024

The Barn Sessions

Acoustic live set · filmed

Single · 2023

Hollow Road

Debut release

Touring

On the Road

Available for bookings & shows

“`

Listen

“`

Now Playing

Still Water

EP · 2024

0:00
0:00



“`

Book
or connect

For show bookings, collaborations, press inquiries, or just to say hello — send a message and we’ll be in touch.

“`

Name
Email
Subject
Message

“`

Mursey
Harry Hussey & Carolynn · All rights reserved

// Custom cursor
const cursor = document.getElementById(‘cursor’);
const ring = document.getElementById(‘cursorRing’);
let mx = 0, my = 0, rx = 0, ry = 0;

document.addEventListener(‘mousemove’, e => {
mx = e.clientX; my = e.clientY;
cursor.style.left = mx + ‘px’;
cursor.style.top = my + ‘px’;
});

(function animRing() {
rx += (mx – rx) * 0.12;
ry += (my – ry) * 0.12;
ring.style.left = rx + ‘px’;
ring.style.top = ry + ‘px’;
requestAnimationFrame(animRing);
})();

document.querySelectorAll(‘a, button, input, textarea’).forEach(el => {
el.addEventListener(‘mouseenter’, () => {
cursor.style.width = ’20px’;
cursor.style.height = ’20px’;
ring.style.width = ’56px’;
ring.style.height = ’56px’;
ring.style.opacity = ‘0.8’;
});
el.addEventListener(‘mouseleave’, () => {
cursor.style.width = ’12px’;
cursor.style.height = ’12px’;
ring.style.width = ’36px’;
ring.style.height = ’36px’;
ring.style.opacity = ‘0.5’;
});
});

// Scroll reveal
const reveals = document.querySelectorAll(‘.reveal’);
const obs = new IntersectionObserver(entries => {
entries.forEach(e => {
if (e.isIntersecting) {
e.target.classList.add(‘visible’);
obs.unobserve(e.target);
}
});
}, { threshold: 0.15 });
reveals.forEach(r => obs.observe(r));

// ── MUSIC PLAYER ──
const tracks = [
{ title: ‘Still Water’, meta: ‘EP · 2024’, src: null, duration: ‘3:42’ },
{ title: ‘Hollow Road’, meta: ‘Single · 2023’, src: null, duration: ‘4:11’ },
{ title: ‘Low Light’, meta: ‘EP · 2024’, src: null, duration: ‘3:28’ },
{ title: ‘Riverbed’, meta: ‘EP · 2024’, src: null, duration: ‘5:03’ },
{ title: ‘Paper Walls’, meta: ‘EP · 2024’, src: null, duration: ‘3:55’ },
{ title: ‘The Long Way’, meta: ‘EP · 2024’, src: null, duration: ‘4:30’ },
];

let currentIdx = 0;
let isPlaying = false;
const audio = new Audio();
audio.volume = 0.8;

// Build tracklist
const tl = document.getElementById(‘tracklist’);
tracks.forEach((t, i) => {
const row = document.createElement(‘div’);
row.className = ‘track-row’ + (i === 0 ? ‘ active’ : ”);
row.dataset.idx = i;
row.innerHTML = `

${String(i+1).padStart(2,’0′)}

${t.title}
${t.meta}

${t.duration}
`;
row.addEventListener(‘click’, () => selectTrack(i));
tl.appendChild(row);
});

function selectTrack(idx) {
currentIdx = idx;
const t = tracks[idx];
document.getElementById(‘playerTitle’).textContent = t.title;
document.getElementById(‘playerMeta’).textContent = t.meta;
document.getElementById(‘timeTotal’).textContent = t.duration;
document.getElementById(‘progressFill’).style.width = ‘0%’;
document.getElementById(‘progressHandle’).style.left = ‘0%’;
document.getElementById(‘timeCurrent’).textContent = ‘0:00’;

// Update active row
document.querySelectorAll(‘.track-row’).forEach((r,i) => {
r.classList.toggle(‘active’, i === idx);
r.classList.remove(‘playing’);
});

if (t.src) {
audio.src = t.src;
if (isPlaying) audio.play();
} else {
// Demo mode: simulate playback with fake progress
audio.src = ”;
if (isPlaying) startFakePlay();
}
drawWave(idx);
}

// Play / pause
const btnPlay = document.getElementById(‘btnPlay’);
btnPlay.addEventListener(‘click’, togglePlay);

function togglePlay() {
isPlaying = !isPlaying;
btnPlay.innerHTML = isPlaying ? ‘▮▮’ : ‘▶’;
const activeRow = document.querySelector(‘.track-row.active’);
if (isPlaying) {
activeRow && activeRow.classList.add(‘playing’);
if (tracks[currentIdx].src) { audio.play(); }
else { startFakePlay(); }
} else {
activeRow && activeRow.classList.remove(‘playing’);
audio.pause();
clearInterval(fakeTimer);
}
}

document.getElementById(‘btnPrev’).addEventListener(‘click’, () => {
selectTrack((currentIdx – 1 + tracks.length) % tracks.length);
});
document.getElementById(‘btnNext’).addEventListener(‘click’, () => {
selectTrack((currentIdx + 1) % tracks.length);
});

// Volume
document.getElementById(‘volSlider’).addEventListener(‘input’, e => {
audio.volume = parseFloat(e.target.value);
});

// Real audio progress
audio.addEventListener(‘timeupdate’, () => {
if (!audio.duration) return;
const pct = (audio.currentTime / audio.duration) * 100;
document.getElementById(‘progressFill’).style.width = pct + ‘%’;
document.getElementById(‘progressHandle’).style.left = pct + ‘%’;
document.getElementById(‘timeCurrent’).textContent = fmtTime(audio.currentTime);
});
audio.addEventListener(‘ended’, () => {
selectTrack((currentIdx + 1) % tracks.length);
});

// Seek on progress bar click
document.getElementById(‘progressWrap’).addEventListener(‘click’, e => {
const rect = e.currentTarget.getBoundingClientRect();
const pct = (e.clientX – rect.left) / rect.width;
if (audio.duration) {
audio.currentTime = pct * audio.duration;
} else {
fakeProgress = pct * fakeDuration;
}
});

// Fake playback for demo (no real audio file)
let fakeTimer, fakeProgress = 0, fakeDuration = 0;
function startFakePlay() {
clearInterval(fakeTimer);
// Parse duration string to seconds
const parts = tracks[currentIdx].duration.split(‘:’);
fakeDuration = parseInt(parts[0]) * 60 + parseInt(parts[1]);
document.getElementById(‘timeTotal’).textContent = tracks[currentIdx].duration;
fakeTimer = setInterval(() => {
if (!isPlaying) { clearInterval(fakeTimer); return; }
fakeProgress += 0.5;
if (fakeProgress >= fakeDuration) {
fakeProgress = 0;
clearInterval(fakeTimer);
isPlaying = false;
btnPlay.innerHTML = ‘▶’;
document.querySelector(‘.track-row.active’)?.classList.remove(‘playing’);
return;
}
const pct = (fakeProgress / fakeDuration) * 100;
document.getElementById(‘progressFill’).style.width = pct + ‘%’;
document.getElementById(‘progressHandle’).style.left = pct + ‘%’;
document.getElementById(‘timeCurrent’).textContent = fmtTime(fakeProgress);
}, 500);
}

function fmtTime(s) {
const m = Math.floor(s / 60);
const sec = Math.floor(s % 60);
return m + ‘:’ + String(sec).padStart(2,’0′);
}

// Waveform canvas
const canvas = document.getElementById(‘waveCanvas’);
const ctx2d = canvas.getContext(‘2d’);

function drawWave(seed) {
canvas.width = canvas.offsetWidth * window.devicePixelRatio;
canvas.height = canvas.offsetHeight * window.devicePixelRatio;
ctx2d.clearRect(0, 0, canvas.width, canvas.height);

const bars = 60;
const barW = canvas.width / bars;
const h = canvas.height;
// Seeded pseudo-random heights
for (let i = 0; i < bars; i++) {
const rng = Math.abs(Math.sin((seed * 7 + i) * 9.3)) * 0.7 + 0.1;
const barH = rng * h * 0.85;
const x = i * barW + barW * 0.15;
const y = (h – barH) / 2;
ctx2d.fillStyle = i drawWave(currentIdx));

function handleSubmit() {
const btn = document.querySelector(‘.form-submit’);
btn.textContent = ‘Sent ✓’;
btn.style.background = ‘#4a7c59’;
btn.style.pointerEvents = ‘none’;
}