/* ============================================
   TOKENS
   ============================================ */
:root {
  --black: #0a0a0a;
  --surface: #161616;
  --white: #f7f7f2;
  --muted: #8c8c86;
  --lime: #a6283f; /* burgundy accent */

  --font-display: "Bebas Neue", "Helvetica Neue", sans-serif;
  --font-body: "General Sans", "Helvetica Neue", sans-serif;
  --font-script: "Caveat", cursive;

  --section-pad-y: clamp(4rem, 10vw, 8rem);
  --section-pad-x: clamp(1.25rem, 6vw, 5rem);
  --max-width: 1400px;
}

/* ============================================
   RESET
   ============================================ */
*, *::before, *::after { box-sizing: border-box; }
html { scroll-behavior: smooth; scroll-padding-top: 90px; }
body {
  margin: 0;
  background: var(--black);
  color: var(--white);
  font-family: var(--font-body);
  font-size: 16px;
  line-height: 1.5;
  -webkit-font-smoothing: antialiased;
}
h1, h2, p, figure { margin: 0; }
a { color: inherit; text-decoration: none; }

/* ============================================
   STARFIELD — fixed backdrop behind the whole site.
   body keeps a plain black background as a safe
   fallback if JS never runs; the canvas just adds
   stars on top of that once it does.
   ============================================ */
#starfield {
  position: fixed;
  inset: 0;
  width: 100vw;
  height: 100vh;
  z-index: -1;
  display: block;
}
.lime { color: var(--lime); }

a:focus-visible, button:focus-visible {
  outline: 2px solid var(--lime);
  outline-offset: 4px;
}

/* ============================================
   LOGO MARK — reused via <use href="#logo-outer/inner">
   ============================================ */
.nav-logo, .footer-logo { color: var(--lime); }
.nav-logo { width: 22px; height: auto; margin-right: 0.6rem; vertical-align: -5px; }
.footer-logo { width: 14px; height: auto; margin-right: 0.4rem; vertical-align: -2px; opacity: 0.7; }

/* ============================================
   INTRO — logo animates in, then the whole
   overlay fades away. Pure CSS, no JS required.
   ============================================ */
.intro {
  position: fixed;
  inset: 0;
  z-index: 999;
  background: var(--black);
  display: flex;
  align-items: center;
  justify-content: center;
  pointer-events: none;
  animation: introOut 0.7s ease forwards;
  animation-delay: 1.8s;
}
.intro-logo-wrap {
  position: relative;
  width: clamp(96px, 16vw, 180px);
  aspect-ratio: 515 / 595;
}
.intro-piece {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  color: var(--lime);
  opacity: 0;
}
/* Outer piece drops in from above, later exits back upward */
.intro-piece--outer { animation: introOuterPiece 2.5s cubic-bezier(0.45, 0, 0.2, 1) forwards; }
@keyframes introOuterPiece {
  0%   { opacity: 0; transform: translateY(-70px); }
  22%  { opacity: 1; transform: translateY(0); }
  74%  { opacity: 1; transform: translateY(0); }
  100% { opacity: 0; transform: translateY(-70px); }
}
/* Inner piece rises in from below, later exits back downward */
.intro-piece--inner { animation: introInnerPiece 2.5s cubic-bezier(0.45, 0, 0.2, 1) forwards; }
@keyframes introInnerPiece {
  0%   { opacity: 0; transform: translateY(70px); }
  22%  { opacity: 1; transform: translateY(0); }
  74%  { opacity: 1; transform: translateY(0); }
  100% { opacity: 0; transform: translateY(70px); }
}
@keyframes introOut {
  to { opacity: 0; visibility: hidden; }
}
@media (prefers-reduced-motion: reduce) {
  .intro { display: none; }
}

/* ============================================
   REVEAL-ON-SCROLL — progressive enhancement.
   Visible by default; only animates once script.js
   confirms IntersectionObserver support.
   ============================================ */
.reveal { opacity: 1; transform: none; }

html.reveal-ready .reveal {
  opacity: 0;
  transform: translateY(24px);
  transition: opacity 0.7s ease, transform 0.7s ease;
  transition-delay: calc(var(--d, 0) * 90ms);
}
html.reveal-ready .reveal.in-view {
  opacity: 1;
  transform: translateY(0);
}

/* The hero sits in the viewport from the very first frame, so its
   reveal would normally finish while still hidden behind the intro
   overlay. Push its delay out so it plays visibly as the intro clears. */
html.reveal-ready .hero .reveal {
  transition-delay: calc(2300ms + var(--d, 0) * 120ms);
}

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  .reveal { opacity: 1 !important; transform: none !important; transition: none !important; }
  .blur-in { filter: none !important; }
  .dust-canvas { display: none !important; }
  .hw-line path {
    animation: none !important;
    stroke-dashoffset: 0 !important;
    fill-opacity: 1 !important;
  }
  * { animation-duration: 0.001ms !important; transition-duration: 0.001ms !important; }
}

/* ============================================
   PLACEHOLDER PHOTO
   ============================================ */
.placeholder-photo {
  position: relative;
  background: linear-gradient(160deg, #232323, #0a0a0a 70%);
  overflow: hidden;
  display: flex;
  align-items: flex-end;
}
.placeholder-photo::before {
  content: "";
  position: absolute;
  inset: 0;
  opacity: 0.08;
  background-image: radial-gradient(rgba(255, 255, 255, 0.5) 1px, transparent 1px);
  background-size: 4px 4px;
}
.placeholder-label {
  position: relative;
  z-index: 1;
  font-size: 0.7rem;
  letter-spacing: 0.05em;
  text-transform: uppercase;
  color: var(--muted);
  padding: 1rem;
}

/* ============================================
   NAV
   ============================================ */
.nav {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  z-index: 50;
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 1.1rem clamp(1.25rem, 6vw, 5rem);
  font-size: 0.8rem;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  transition: background-color 0.3s ease, backdrop-filter 0.3s ease;
}
.nav.scrolled {
  background-color: rgba(10, 10, 10, 0.7);
  backdrop-filter: blur(10px);
  -webkit-backdrop-filter: blur(10px);
}
.nav-mark { display: flex; align-items: center; font-weight: 600; transition: opacity 0.25s ease; }
.nav-mark:hover { opacity: 0.75; }
.nav-links { display: flex; align-items: center; gap: 2rem; }
.nav-links a { position: relative; transition: color 0.25s ease; }
.nav-links a::after {
  content: "";
  position: absolute;
  left: 0; bottom: -4px;
  width: 100%; height: 1px;
  background: var(--lime);
  transform: scaleX(0);
  transform-origin: right;
  transition: transform 0.3s ease;
}
.nav-links a:hover::after,
.nav-links a.active::after { transform: scaleX(1); transform-origin: left; }
.nav a:hover { color: var(--lime); }
.nav-links a.active { color: var(--lime); }
@media (max-width: 480px) {
  .nav { font-size: 0.7rem; }
  .nav-links { gap: 1rem; }
}

/* ============================================
   SIGNATURE — huge stacked section headline
   ============================================ */
.section-title {
  font-family: var(--font-display);
  font-size: clamp(3rem, 10vw, 7rem);
  line-height: 0.85;
  letter-spacing: 0.01em;
  text-transform: uppercase;
  margin-bottom: 3rem;
}
.section-title span { display: block; }
.section-title.center { text-align: center; }

/* ============================================
   HERO
   ============================================ */
/* ============================================
   HERO SCROLL-SPACE — the hero stays pinned while
   the user scrolls through this taller container,
   giving JS room to drive the exit animation below.
   ============================================ */
.hero-scroll-space {
  position: relative;
  height: 300vh;
}
@media (prefers-reduced-motion: reduce) {
  .hero-scroll-space { height: auto; }
}

.hero {
  position: sticky;
  top: 0;
  min-height: 100vh;
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: center;
  text-align: center;
  padding: var(--section-pad-y) var(--section-pad-x);
  overflow: hidden;
}
@media (prefers-reduced-motion: reduce) {
  .hero { position: relative; }
}
.hero-photo { position: absolute; inset: 0; z-index: 0; }
.hero-scrim {
  position: absolute;
  inset: 0;
  z-index: 1;
  background: linear-gradient(
    rgba(10, 10, 10, 0.55),
    rgba(10, 10, 10, 0.75) 40%,
    rgba(10, 10, 10, 0.75) 60%,
    rgba(10, 10, 10, 0.55)
  );
}
.hero-eyebrow, .hero-title, .scroll-cue { position: relative; z-index: 2; }
.hero-eyebrow {
  font-size: 0.85rem;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--muted);
  margin-bottom: 1rem;
}
.hero-title {
  display: flex;
  flex-direction: column;
  align-items: center;
}
.hw-line {
  display: block;
  height: clamp(3.2rem, 14vw, 7.5rem);
  width: auto;
  max-width: 100%;
  margin: 0.2em 0;
  overflow: visible;
}
.hw-line1 { color: var(--white); }
.hw-line2 {
  color: var(--lime);
  height: 100%;
  max-width: none;
  margin: 0;
}
/* Fixed-footprint slot: reserves the same layout space regardless of
   how large the actual SVG inside grows during the scroll-zoom, so
   growth never reflows the page — it just visually overflows. */
.hw-line2-slot {
  display: flex;
  align-items: center;
  justify-content: center;
  height: clamp(3.2rem, 14vw, 7.5rem);
  width: 100%;
  overflow: visible;
  position: relative;
  margin: 0.2em 0;
}
.hw-line path { fill-opacity: 0; }
@keyframes drawStroke { to { stroke-dashoffset: 0; } }
@keyframes fillIn { to { fill-opacity: 1; } }
.scroll-cue {
  margin-top: 2rem;
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  font-size: 0.8rem;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--muted);
  transition: color 0.25s ease;
}
.scroll-cue:hover { color: var(--lime); }
.scroll-cue span { display: inline-block; animation: bob 1.8s ease-in-out infinite; }
@keyframes bob {
  0%, 100% { transform: translateY(0); }
  50% { transform: translateY(4px); }
}

/* ============================================
   STATEMENT
   ============================================ */
.statement { padding: var(--section-pad-y) var(--section-pad-x); }
.statement-wrap { position: relative; max-width: 900px; margin: 0 auto; }
.statement-text {
  margin: 0 auto;
  text-align: center;
  font-weight: 500;
  font-size: clamp(1.5rem, 4vw, 2.75rem);
  line-height: 1.3;
}

/* Blur-focus entrance: looks like it's arriving from behind/out of
   focus, then sharpens into place as it scrolls into view. Visible
   and sharp by default so it degrades safely without JS/animation. */
.blur-in { filter: blur(0); transform: scale(1); }
html.reveal-ready .blur-in {
  filter: blur(18px);
  transform: scale(1.08);
  transition: opacity 0.9s ease, transform 1.1s cubic-bezier(0.16, 1, 0.3, 1),
    filter 1.1s ease;
}
html.reveal-ready .blur-in.in-view { filter: blur(0); transform: scale(1); }
/* Keep the entrance's slow transform/filter timing, but make the
   opacity handoff to each dust canvas quick, not a lingering fade. */
html.reveal-ready .blur-in.dust-text { transition-duration: 0.15s, 1.1s, 1.1s; }

/* Dust-out exit: canvas overlays its text and takes over visually
   once scrolled past. Size and offset are set in JS — it extends
   past the text box so drifting grains aren't clipped. */
.dust-canvas {
  position: absolute;
  pointer-events: none;
}

/* ============================================
   ABOUT
   ============================================ */
.about { max-width: var(--max-width); margin: 0 auto; padding: var(--section-pad-y) var(--section-pad-x); }
.about-grid {
  display: grid;
  grid-template-columns: 0.8fr 1.2fr;
  gap: clamp(2rem, 5vw, 5rem);
  align-items: center;
}
.about-photo { aspect-ratio: 3 / 4; border-radius: 2px; transition: transform 0.4s cubic-bezier(0.16, 1, 0.3, 1); }
.about-photo:hover { transform: scale(1.02); }
.about-copy p {
  font-size: clamp(1.1rem, 1.8vw, 1.4rem);
  max-width: 52ch;
  margin-bottom: 2rem;
}
.chips { display: flex; flex-wrap: wrap; gap: 0.6rem; }
.chips span {
  font-size: 0.75rem;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  border: 1px solid rgba(255, 255, 255, 0.2);
  padding: 0.4rem 0.75rem;
  color: var(--muted);
  transition: border-color 0.25s ease, color 0.25s ease;
}
.chips span:hover { border-color: var(--lime); color: var(--lime); }
@media (max-width: 700px) {
  .about-grid { grid-template-columns: 1fr; }
}
/* ============================================
   NOW VIBING TO
   ============================================ */
.vibing { max-width: var(--max-width); margin: 0 auto; padding: var(--section-pad-y) var(--section-pad-x); }

/* Minimal: no card chrome, just the art and the info sitting
   in space. Depth comes from motion and the art's own glow. */
.track-card {
  display: flex;
  align-items: center;
  gap: clamp(1.25rem, 4vw, 2.75rem);
  max-width: 720px;
}

.track-art {
  position: relative;
  flex-shrink: 0;
  width: clamp(132px, 24vw, 200px);
  aspect-ratio: 1 / 1;
  border-radius: 10px;
  overflow: hidden;
  background: linear-gradient(145deg, #2a1119, #12060a 70%);
  transition: transform 0.6s cubic-bezier(0.16, 1, 0.3, 1),
    box-shadow 0.6s ease;
}
.track-art img { width: 100%; height: 100%; object-fit: cover; display: block; }
.track-card.is-playing .track-art {
  transform: scale(1.02);
  box-shadow: 0 18px 50px rgba(166, 40, 63, 0.3);
}

/* Play control — barely-there until you approach it. */
.track-play {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  border: none;
  padding: 0;
  cursor: pointer;
  background: rgba(10, 10, 10, 0.32);
  color: var(--white);
  display: flex;
  align-items: center;
  justify-content: center;
  opacity: 0;
  transition: opacity 0.35s ease, background-color 0.35s ease;
}
.track-play:hover,
.track-play:focus-visible { opacity: 1; }
/* Keep it discoverable when idle; recede once music is going. */
.track-card:not(.is-playing) .track-play { opacity: 1; }
/* Touch devices have no hover, so the control must stay reachable
   or there'd be no way to pause once playback starts. */
@media (hover: none) {
  .track-play { opacity: 1; background: rgba(10, 10, 10, 0.22); }
}

.track-play svg {
  position: absolute;
  width: 20%;
  height: 20%;
  transition: opacity 0.3s ease, transform 0.45s cubic-bezier(0.16, 1, 0.3, 1);
  filter: drop-shadow(0 2px 10px rgba(0, 0, 0, 0.5));
}
/* Icons cross-fade and rotate into each other rather than snapping. */
.icon-play { opacity: 1; transform: scale(1) rotate(0deg); }
.icon-pause { opacity: 0; transform: scale(0.6) rotate(-90deg); }
.track-card.is-playing .icon-play { opacity: 0; transform: scale(0.6) rotate(90deg); }
.track-card.is-playing .icon-pause { opacity: 1; transform: scale(1) rotate(0deg); }

/* Soft pulse radiating from the button while playing. */
.track-play-ring {
  position: absolute;
  width: 34%;
  aspect-ratio: 1 / 1;
  border-radius: 50%;
  border: 1px solid var(--lime);
  opacity: 0;
  pointer-events: none;
}
.track-card.is-playing .track-play-ring {
  animation: ringPulse 2.6s cubic-bezier(0.22, 0.61, 0.36, 1) infinite;
}
@keyframes ringPulse {
  0% { opacity: 0.55; transform: scale(0.85); }
  70% { opacity: 0; transform: scale(2.1); }
  100% { opacity: 0; transform: scale(2.1); }
}

.track-info { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 0.85rem; }
.track-text { display: flex; flex-direction: column; }
.track-name {
  font-family: var(--font-display);
  font-size: clamp(1.4rem, 3vw, 2rem);
  text-transform: uppercase;
  letter-spacing: 0.02em;
  line-height: 1.1;
}
.track-artist { color: var(--muted); font-size: 0.85rem; margin-top: 0.25rem; }

/* Waveform doubles as the progress bar and the scrubber. */
.waveform {
  display: flex;
  align-items: center;
  gap: 3px;
  height: 40px;
  width: 100%;
  border: none;
  background: none;
  padding: 0;
  cursor: pointer;
}
.waveform span {
  display: block;
  flex: 1 1 auto;
  max-width: 4px;
  min-width: 2px;
  border-radius: 2px;
  background: var(--lime);
  height: 12%;
  opacity: 0.22;
  transform-origin: center;
  transition: opacity 0.45s ease;
}
.waveform:hover span { opacity: 0.38; }
/* Bars already played stay lit — JS sets this per bar. */
.waveform span.played { opacity: 1; }
.waveform:hover span.played { opacity: 1; }

.track-meta {
  display: flex;
  align-items: center;
  gap: 1rem;
}
.track-time {
  font-size: 0.75rem;
  letter-spacing: 0.06em;
  color: var(--muted);
  font-variant-numeric: tabular-nums;
  min-width: 4.5em;
}
.track-spotify {
  font-size: 0.72rem;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--lime);
  position: relative;
  padding-bottom: 0.15em;
}
.track-spotify::after {
  content: "";
  position: absolute;
  left: 0; bottom: 0;
  width: 100%; height: 1px;
  background: currentColor;
  transform: scaleX(1);
  transform-origin: right;
  transition: transform 0.35s cubic-bezier(0.16, 1, 0.3, 1);
}
.track-spotify:hover::after { transform: scaleX(0); }

.track-status {
  font-size: 0.75rem;
  line-height: 1.5;
  color: var(--muted);
  max-width: 46ch;
}

@media (prefers-reduced-motion: reduce) {
  .track-card.is-playing .track-play-ring { animation: none; }
  .track-art, .track-play, .track-play svg { transition: none; }
}

@media (max-width: 560px) {
  .track-card { flex-direction: column; align-items: flex-start; text-align: left; }
  .track-art { width: min(55vw, 190px); }
  .track-info { width: 100%; }
}


/* ============================================
   CONNECT
   ============================================ */
.contact {
  max-width: var(--max-width);
  margin: 0 auto;
  padding: var(--section-pad-y) var(--section-pad-x);
  text-align: center;
}

.social-list {
  max-width: 460px;
  margin: 0 auto;
  text-align: left;
  border-top: 1px solid rgba(255, 255, 255, 0.12);
}
.social-row {
  display: flex;
  align-items: center;
  gap: 1.1rem;
  padding: 1.15rem 0.25rem;
  border-bottom: 1px solid rgba(255, 255, 255, 0.12);
  transition: background-color 0.3s ease, padding-left 0.3s ease;
}
.social-row:hover { background-color: rgba(166, 40, 63, 0.1); padding-left: 0.75rem; }
.social-icon {
  width: 26px;
  height: 26px;
  flex-shrink: 0;
  color: var(--white);
  transition: color 0.3s ease, transform 0.3s cubic-bezier(0.16, 1, 0.3, 1);
}
.social-icon svg { width: 100%; height: 100%; }
.social-row:hover .social-icon { color: var(--lime); transform: scale(1.08); }
.social-info { display: flex; flex-direction: column; flex: 1; }
.social-platform { font-weight: 600; text-transform: uppercase; letter-spacing: 0.04em; font-size: 0.95rem; }
.social-handle { color: var(--muted); font-size: 0.85rem; margin-top: 0.15rem; }
.social-arrow {
  font-size: 1.3rem;
  color: var(--muted);
  transition: transform 0.3s cubic-bezier(0.16, 1, 0.3, 1), color 0.3s ease;
}
.social-row:hover .social-arrow { color: var(--lime); transform: translateX(4px); }

.contact-email {
  display: inline-block;
  margin-top: 2.5rem;
  font-size: clamp(1.1rem, 2vw, 1.5rem);
  color: var(--lime);
  border-bottom: 1px solid currentColor;
  padding-bottom: 0.2rem;
  transition: opacity 0.25s ease;
}
.contact-email:hover { opacity: 0.75; }

.signature {
  margin-top: 3rem;
  font-family: var(--font-script);
  font-size: 2rem;
  color: var(--white);
}
.footer-note {
  margin-top: 3rem;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 0.7rem;
  letter-spacing: 0.05em;
  text-transform: uppercase;
  color: var(--muted);
}

@media (max-width: 500px) {
  .social-row { gap: 0.85rem; }
  .social-platform { font-size: 0.85rem; }
}
