// HAUMS — Signal v3
// Ported from the Claude Design "Signal v3" canvas into production React
// (babel-standalone). Light theme, Space Grotesk + Instrument Sans.
// Audio uses the real audio/*.m4a files; every gated download + the Join form
// route through subscribeToLaylo -> /api/laylo-subscribe (Laylo GraphQL proxy).

const { useState, useEffect, useRef } = React;

// ─────────────────────────────────────────────────────────────────────────────
// Config / data — audio paths, images, and gifts all match the real assets.

const ACC = "#3A45E0";      // accent (Signal v3 default)
const MAX = 30;             // preview cap, seconds
const SHOW_LIVE_SET = true; // design "showLiveSet" tweak (shipped on)

const TRACKS = [
  { n: "01", t: "Lost on Mars", d: "6:05", src: "audio/01-lost-on-mars.m4a" },
  { n: "02", t: "Lost on Mars (Club Mix)", d: "7:09", src: "audio/02-lost-on-mars-club-mix.m4a" },
  { n: "03", t: "Awake Me (Club Mix)", d: "6:03", src: "audio/03-awake-me-club-mix.m4a" },
  { n: "04", t: "Resist and It Persists", d: "4:35", src: "audio/04-resist-and-it-persists.m4a" },
  { n: "05", t: "Resist and It Persists (Club Mix)", d: "4:50", src: "audio/05-resist-and-it-persists-club-mix.m4a" },
  { n: "06", t: "Power of Love", d: "5:14", src: "audio/06-power-of-love.m4a" },
  { n: "07", t: "Reality", d: "5:43", src: "audio/07-reality.m4a" },
  { n: "08", t: "Steps", d: "7:29", src: "audio/08-steps.m4a" },
  { n: "09", t: "Into the Quantum", d: "6:39", src: "audio/09-into-the-quantum.m4a" },
  { n: "10", t: "Beyond the Veil", d: "7:37", src: "audio/10-beyond-the-veil.m4a" },
];

const SET = { title: "HAUMS Live · Set 001", src: "audio/haums-set-001.m4a", filename: "HAUMS - Live Set 001.m4a" };

const GIFTS = [
  { id: "track", name: "An unreleased track", desc: "A piece of music not on streaming. For the listeners." },
  { id: "ableton", name: "An Ableton project", desc: "A stripped session of one of my tracks. For the producers." },
  { id: "meditation", name: "A guided audio journey", desc: "A short sound piece for meditation and integration. For the seekers." },
  { id: "pdf", name: "A consciousness primer (PDF)", desc: "“The Tarot of the Self” — a short read on archetypes, energy, and the work." },
];

// ─────────────────────────────────────────────────────────────────────────────
// Laylo — fire-and-forget signup via the serverless proxy. Never blocks UX.

const subscribeToLaylo = ({ email, phone }) => {
  try {
    fetch("/api/laylo-subscribe", {
      method: "POST",
      headers: { "Content-Type": "application/json" },
      body: JSON.stringify({ email: email || "", phoneNumber: phone || "" }),
      keepalive: true,
    }).catch(() => {});
  } catch (e) {
    /* no-op — signup still succeeds locally */
  }
};

// ─────────────────────────────────────────────────────────────────────────────
// Helpers

const fmt = (s) => {
  if (!s || !isFinite(s)) return "0:00";
  const m = Math.floor(s / 60);
  const sec = Math.floor(s % 60);
  return m + ":" + String(sec).padStart(2, "0");
};

const dlTrack = (tr) => {
  const a = document.createElement("a");
  a.href = tr.src;
  a.download = "HAUMS - " + tr.t + ".m4a";
  document.body.appendChild(a);
  a.click();
  document.body.removeChild(a);
};

const dlFile = (src, fn) => {
  const a = document.createElement("a");
  a.href = src;
  a.download = fn || src.split("/").pop();
  document.body.appendChild(a);
  a.click();
  document.body.removeChild(a);
};

// Hash routing — keeps shareable URLs + browser back/forward working.
const VIEW_TO_HASH = { home: "", music: "free-music", shows: "shows", about: "about", updates: "updates" };
const hashToView = () => {
  const r = (typeof location !== "undefined" ? location.hash : "").replace(/^#\/?/, "");
  if (r === "free-music" || r === "music") return "music";
  if (r === "shows") return "shows";
  if (r === "about") return "about";
  if (r === "updates" || r === "join") return "updates"; // legacy #join still resolves
  return "home";
};

// Shared compliance footer — Laylo SMS opt-in requires linking Terms + Privacy.
const LayloConsent = ({ context }) => (
  <p style={{ fontSize: 11, lineHeight: 1.5, color: "rgba(21,23,30,.42)", margin: "14px 0 0", textAlign: "center" }}>
    By {context} you agree to receive emails &amp; SMS from HAUMS via Laylo. Msg &amp; data rates may apply. Reply STOP to
    unsubscribe. See Laylo's{" "}
    <a href="https://laylo.com/terms" target="_blank" rel="noopener noreferrer" style={{ color: ACC }}>Terms</a> &amp;{" "}
    <a href="https://laylo.com/privacy" target="_blank" rel="noopener noreferrer" style={{ color: ACC }}>Privacy Policy</a>.
  </p>
);

// ─────────────────────────────────────────────────────────────────────────────
// App

class App extends React.Component {
  constructor(props) {
    super(props);
    this.albumAudio = React.createRef();
    this.setAudio = React.createRef();
    this.waveRef = React.createRef();
    this.heroWaveRef = React.createRef();
    this.rootRef = React.createRef();
    this.tickWave = this.tickWave.bind(this);
    this.onHash = this.onHash.bind(this);
    this.onMedia = this.onMedia.bind(this);
    this._mql = typeof window !== "undefined" && window.matchMedia ? window.matchMedia("(max-width: 640px)") : null;
    this.state = {
      view: hashToView(),
      isMobile: this._mql ? this._mql.matches : false,
      idx: 0, playing: false, cur: 0, previewEnded: false,
      setPlaying: false, setCur: 0, setPreviewEnded: false,
      modalOpen: false, modalKind: "album", modalTrack: null, modalDone: false,
      mForm: { name: "", email: "", phone: "", city: "", address: "" },
      jForm: { name: "", email: "", phone: "", city: "", address: "", gift: "" },
      jSubmitted: false,
    };
  }

  componentDidMount() {
    this.attach(this.albumAudio.current, "album");
    this.attach(this.setAudio.current, "set");
    if (this.rootRef.current) this.rootRef.current.style.setProperty("--acc", ACC);
    window.addEventListener("hashchange", this.onHash);
    if (this._mql) { this._mql.addEventListener ? this._mql.addEventListener("change", this.onMedia) : this._mql.addListener(this.onMedia); }
    this._raf = requestAnimationFrame(this.tickWave);
  }
  componentWillUnmount() {
    window.removeEventListener("hashchange", this.onHash);
    if (this._mql) { this._mql.removeEventListener ? this._mql.removeEventListener("change", this.onMedia) : this._mql.removeListener(this.onMedia); }
    if (this._raf) cancelAnimationFrame(this._raf);
  }
  onHash() { this.setState({ view: hashToView() }); try { window.scrollTo(0, 0); } catch (e) {} }
  onMedia(e) { this.setState({ isMobile: e.matches }); }

  attach(a, which) {
    if (!a) return;
    a.addEventListener("timeupdate", () => {
      const cur = a.currentTime;
      if (cur >= MAX) {
        a.pause();
        a.currentTime = MAX;
        this.setState(which === "album" ? { previewEnded: true } : { setPreviewEnded: true });
      }
      this.setState(which === "album" ? { cur } : { setCur: cur });
    });
    a.addEventListener("play", () => this.setState(which === "album" ? { playing: true } : { setPlaying: true }));
    a.addEventListener("pause", () => this.setState(which === "album" ? { playing: false } : { setPlaying: false }));
  }

  tickWave() {
    const t = performance.now() / 1000;
    const active = this.state.playing;
    const w = this.waveRef.current;
    if (w) {
      const ch = w.children;
      for (let i = 0; i < ch.length; i++) {
        const seed = Math.sin(i * 12.345) * 0.5 + 0.5;
        const h = active ? 8 + (Math.sin(t * 4 + i * 0.45) + 1) * 24 * (0.35 + seed * 0.65) : 6 + seed * 10;
        ch[i].style.height = h.toFixed(1) + "px";
      }
    }
    const hw = this.heroWaveRef.current;
    if (hw) {
      const ch = hw.children;
      for (let i = 0; i < ch.length; i++) {
        const seed = Math.sin(i * 9.7) * 0.5 + 0.5;
        const h = active ? 4 + (Math.sin(t * 5 + i * 0.7) + 1) * 8 * (0.4 + seed * 0.6) : 4 + seed * 4;
        ch[i].style.height = h.toFixed(1) + "px";
      }
    }
    this._raf = requestAnimationFrame(this.tickWave);
  }

  setView(v) { try { location.hash = VIEW_TO_HASH[v] || ""; } catch (e) { this.setState({ view: v }); } }

  // Player controls
  togglePlay() {
    const a = this.albumAudio.current; if (!a) return;
    if (a.paused) { if (a.currentTime >= MAX) { a.currentTime = 0; this.setState({ previewEnded: false }); } a.play().catch(() => {}); }
    else a.pause();
  }
  playIndex(i) {
    this.setState({ idx: i, cur: 0, previewEnded: false }, () => {
      const a = this.albumAudio.current; if (a) setTimeout(() => a.play().catch(() => {}), 0);
    });
  }
  next() { this.playIndex((this.state.idx + 1) % TRACKS.length); }
  prev() { this.playIndex((this.state.idx - 1 + TRACKS.length) % TRACKS.length); }
  seek(e) {
    const a = this.albumAudio.current; if (!a) return;
    const r = e.currentTarget.getBoundingClientRect();
    const pct = (e.clientX - r.left) / r.width;
    a.currentTime = Math.max(0, Math.min(1, pct)) * MAX;
    if (a.currentTime < MAX) this.setState({ previewEnded: false });
  }
  toggleSet() {
    const a = this.setAudio.current; if (!a) return;
    if (a.paused) { if (a.currentTime >= MAX) { a.currentTime = 0; this.setState({ setPreviewEnded: false }); } a.play().catch(() => {}); }
    else a.pause();
  }

  // Modal + downloads (each gated by a Laylo signup)
  openModal(kind, track) {
    this.setState({ modalOpen: true, modalKind: kind, modalTrack: track || null, modalDone: false });
    try { document.body.style.overflow = "hidden"; } catch (e) {}
  }
  closeModal() { this.setState({ modalOpen: false }); try { document.body.style.overflow = ""; } catch (e) {} }
  submitModal(e) {
    e.preventDefault();
    const f = this.state.mForm;
    subscribeToLaylo({ email: f.email, phone: f.phone });
    if (this.state.modalKind === "album") dlTrack(this.state.modalTrack || TRACKS[0]);
    else dlFile(SET.src, SET.filename);
    this.setState({ modalDone: true });
  }
  dlAll() { TRACKS.forEach((tr, i) => setTimeout(() => dlTrack(tr), i * 350)); }
  submitJoin(e) {
    e.preventDefault();
    const f = this.state.jForm;
    subscribeToLaylo({ email: f.email, phone: f.phone });
    this.setState({ jSubmitted: true });
  }

  mField(k) { return (e) => this.setState({ mForm: { ...this.state.mForm, [k]: e.target.value } }); }
  jField(k) { return (e) => this.setState({ jForm: { ...this.state.jForm, [k]: e.target.value } }); }

  // ── Render pieces ──────────────────────────────────────────────────────────

  renderNav() {
    const s = this.state;
    const home = s.view === "home";
    const link = (label, view, onClick) => {
      const on = s.view === view;
      return (
        <button
          className="hm3-navlink"
          onClick={onClick}
          style={{
            background: on ? ACC : "transparent", color: on ? "#fff" : "#15171E",
            border: "none", cursor: "pointer", padding: "8px 16px", borderRadius: 9,
            fontSize: 13, fontWeight: 600, letterSpacing: ".02em",
          }}
        >
          {label}
        </button>
      );
    };
    return (
      <nav style={{ position: home ? "fixed" : "sticky", top: 0, left: 0, right: 0, zIndex: 80, display: "flex", justifyContent: "center", padding: "18px 20px" }}>
        <div style={{
          display: "flex", flexWrap: "wrap", alignItems: "center", justifyContent: "center", gap: "8px 22px",
          width: "100%", maxWidth: 1120, background: "rgba(255,255,255,.72)",
          backdropFilter: "blur(16px) saturate(150%)", WebkitBackdropFilter: "blur(16px) saturate(150%)",
          border: "1px solid rgba(21,23,30,.08)", borderRadius: 16, padding: "12px 20px", boxShadow: "0 6px 22px rgba(21,23,30,.06)",
        }}>
          <button onClick={() => this.setView("home")} style={{ display: "inline-flex", alignItems: "center", gap: 9, background: "none", border: "none", cursor: "pointer", padding: 0 }}>
            <span style={{ width: 9, height: 9, borderRadius: "50%", background: ACC, animation: "hm3-pulse 2s ease-in-out infinite" }} />
            <span className="hm3-wordmark" style={{ fontFamily: "'Space Grotesk'", fontWeight: 700, fontSize: 18, letterSpacing: ".28em", color: "#15171E" }}>HAUMS</span>
          </button>
          <div style={{ display: "flex", gap: 8, justifyContent: "center" }}>
            {link("Free Music", "music", () => this.setView("music"))}
            {link("Shows", "shows", () => this.setView("shows"))}
            {link("About", "about", () => this.setView("about"))}
            {link("Updates", "updates", () => this.setView("updates"))}
          </div>
        </div>
      </nav>
    );
  }

  renderHome() {
    const s = this.state;
    const heroLabel = (s.playing ? "Now playing — " : "Press play — ") + TRACKS[s.idx].t;
    const portal = (img, tag, title, sub, view) => (
      <button
        className="hm3-card"
        onClick={() => this.setView(view)}
        style={{ textAlign: "left", background: "#fff", border: "1px solid rgba(21,23,30,.09)", borderRadius: 16, overflow: "hidden", cursor: "pointer", padding: 0 }}
      >
        <div style={{ position: "relative", aspectRatio: "16/11", overflow: "hidden" }}>
          <img src={img} alt={title} style={{ width: "100%", height: "100%", objectFit: "cover", display: "block" }} />
          <span style={{ position: "absolute", top: 12, left: 14, fontSize: 11, letterSpacing: ".14em", textTransform: "uppercase", color: "#fff", background: "rgba(12,14,22,.5)", padding: "4px 9px", borderRadius: 20, fontWeight: 600 }}>{tag}</span>
        </div>
        <div style={{ padding: "18px 20px 20px", display: "flex", justifyContent: "space-between", alignItems: "center" }}>
          <div>
            <div style={{ fontFamily: "'Space Grotesk'", fontWeight: 700, fontSize: 21, color: "#15171E" }}>{title}</div>
            <div style={{ fontSize: 13, color: "rgba(21,23,30,.55)", marginTop: 2 }}>{sub}</div>
          </div>
          <span style={{ width: 34, height: 34, borderRadius: "50%", background: "color-mix(in oklch,var(--acc,#3A45E0),transparent 88%)", color: ACC, display: "grid", placeItems: "center", fontSize: 15, flex: "none" }}>→</span>
        </div>
      </button>
    );
    const mobile = s.isMobile;
    const heroPieces = (
      <React.Fragment>
        <div style={{ display: "inline-flex", alignItems: "center", gap: 10, fontSize: 12, letterSpacing: ".24em", textTransform: "uppercase", color: "rgba(255,255,255,.82)", fontWeight: 600 }}>
          <span style={{ width: 22, height: 1, background: "rgba(255,255,255,.55)" }} />Melodic · Organic · Progressive House<span style={{ width: 22, height: 1, background: "rgba(255,255,255,.55)" }} />
        </div>
        <p style={{ fontFamily: "'Space Grotesk'", fontWeight: 500, fontSize: "clamp(26px,3.6vw,48px)", lineHeight: 1.1, letterSpacing: "-.015em", color: "#fff", margin: 0, maxWidth: 640, textShadow: "0 2px 34px rgba(0,0,0,.45)" }}>
          The Music Didn't Change.<br />You Did.
        </p>
        <button className="hm3-lift" onClick={() => this.togglePlay()} style={{ display: "inline-flex", alignItems: "center", gap: 13, background: "rgba(255,255,255,.13)", backdropFilter: "blur(12px)", WebkitBackdropFilter: "blur(12px)", border: "1px solid rgba(255,255,255,.3)", color: "#fff", borderRadius: 999, padding: "8px 22px 8px 8px", fontSize: 13.5, fontWeight: 600, cursor: "pointer" }}>
          <span style={{ width: 42, height: 42, borderRadius: "50%", background: ACC, color: "#fff", display: "grid", placeItems: "center", fontSize: 15, flex: "none" }}>{s.playing ? "❚❚" : "▶"}</span>
          <span>{heroLabel}</span>
          <span ref={this.heroWaveRef} style={{ display: "flex", alignItems: "flex-end", gap: 2.5, height: 22, flex: "none" }}>
            {Array.from({ length: 16 }).map((_, i) => (
              <span key={i} style={{ width: 2.5, height: 6, borderRadius: 2, background: "rgba(255,255,255,.72)" }} />
            ))}
          </span>
        </button>
        <div style={{ display: "flex", gap: 12, justifyContent: "center", flexWrap: "wrap", marginTop: 2 }}>
          <button className="hm3-lift" onClick={() => this.setView("music")} style={{ display: "inline-flex", alignItems: "center", gap: 10, background: ACC, color: "#fff", border: "none", borderRadius: 12, padding: "14px 26px", fontSize: 14, fontWeight: 600, cursor: "pointer", boxShadow: "0 12px 30px color-mix(in oklch,var(--acc,#3A45E0),transparent 55%)" }}>Get the album — free ↓</button>
          <button className="hm3-glass" onClick={() => this.setView("about")} style={{ display: "inline-flex", alignItems: "center", gap: 8, background: "rgba(255,255,255,.1)", backdropFilter: "blur(10px)", WebkitBackdropFilter: "blur(10px)", color: "#fff", border: "1px solid rgba(255,255,255,.34)", borderRadius: 12, padding: "14px 24px", fontSize: 14, fontWeight: 600, cursor: "pointer" }}>Who is HAUMS →</button>
        </div>
      </React.Fragment>
    );
    return (
      <div>
        {mobile ? (
          // Mobile: full concert image (uncropped — HAUMS wordmark intact), centered in a full-height dark
          // backdrop so it fills the screen; top + bottom fades blend the image into the #0b0d14 background.
          <section style={{ background: "#0b0d14", color: "#fff", minHeight: "100dvh", display: "flex", flexDirection: "column", justifyContent: "center", paddingTop: 88 }}>
            <div style={{ position: "relative" }}>
              <img src="images/haums-hero.jpg" alt="HAUMS live" style={{ width: "100%", display: "block" }} />
              <div style={{ position: "absolute", left: 0, right: 0, top: -1, height: 72, background: "linear-gradient(180deg,#0b0d14,transparent)", pointerEvents: "none" }} />
              <div style={{ position: "absolute", left: 0, right: 0, bottom: -1, height: 96, background: "linear-gradient(180deg,transparent,#0b0d14)", pointerEvents: "none" }} />
            </div>
            <div style={{ display: "flex", flexDirection: "column", alignItems: "center", textAlign: "center", gap: 18, padding: "14px 24px 48px" }}>
              {heroPieces}
            </div>
          </section>
        ) : (
          // Desktop: full-bleed image with content overlaid at the bottom.
          <section style={{ position: "relative", width: "100%", height: "100dvh", overflow: "hidden", background: "#0b0d14" }}>
            <img src="images/haums-hero.jpg" alt="HAUMS live" style={{ position: "absolute", inset: 0, zIndex: 1, width: "100%", height: "100%", objectFit: "cover", objectPosition: "center 42%", display: "block" }} />
            <div style={{ position: "absolute", zIndex: 2, inset: 0, background: "linear-gradient(180deg,transparent 38%,rgba(11,13,20,.4) 64%,rgba(11,13,20,.88))", pointerEvents: "none" }} />
            <div style={{ position: "absolute", zIndex: 3, left: 0, right: 0, bottom: 0, padding: "0 24px 7dvh", display: "flex", flexDirection: "column", alignItems: "center", textAlign: "center", gap: 22 }}>
              {heroPieces}
            </div>
          </section>
        )}

        <section style={{ maxWidth: 1120, margin: "0 auto", padding: "56px 24px 20px" }}>
          <div style={{ display: "flex", alignItems: "baseline", justifyContent: "space-between", flexWrap: "wrap", gap: 10, marginBottom: 26 }}>
            <h2 style={{ fontFamily: "'Space Grotesk'", fontWeight: 700, fontSize: "clamp(26px,3.4vw,40px)", letterSpacing: "-.02em", margin: 0 }}>Inside HAUMS.</h2>
            <span style={{ fontSize: 12, letterSpacing: ".18em", textTransform: "uppercase", color: "rgba(21,23,30,.42)", fontWeight: 600 }}>The music · the shows · the story</span>
          </div>
          <div style={{ display: "grid", gridTemplateColumns: "repeat(auto-fit,minmax(240px,1fr))", gap: 16 }}>
            {portal("images/squaring-the-circle.webp", "Listen", "Music", "Album · Live sets", "music")}
            {portal("images/haums-booth.jpg", "Live", "Shows", "Tour · Live sets", "shows")}
            {portal("images/haums-portrait.jpg", "Story", "About", "The artist · the why", "about")}
          </div>
        </section>

        <section style={{ maxWidth: 1120, margin: "0 auto", padding: "20px 24px 100px" }}>
          <div style={{ position: "relative", overflow: "hidden", borderRadius: 20, background: "linear-gradient(120deg,#15171E,#26306b)", color: "#fff", padding: "clamp(34px,5vw,56px)", textAlign: "center" }}>
            <div style={{ fontSize: 12, letterSpacing: ".22em", textTransform: "uppercase", color: "rgba(255,255,255,.6)", fontWeight: 600 }}>New music · new shows</div>
            <h2 style={{ fontFamily: "'Space Grotesk'", fontWeight: 700, fontSize: "clamp(28px,4vw,46px)", letterSpacing: "-.02em", margin: "12px 0 10px" }}>Never miss a drop.</h2>
            <p style={{ fontSize: 17, lineHeight: 1.6, color: "rgba(255,255,255,.8)", margin: "0 auto 26px", maxWidth: 460 }}>Every release and every show reaches the list before anywhere else. No noise — just the work.</p>
            <button className="hm3-lift" onClick={() => this.setView("updates")} style={{ display: "inline-flex", alignItems: "center", gap: 10, background: "#fff", color: "#15171E", border: "none", borderRadius: 12, padding: "15px 32px", fontSize: 14.5, fontWeight: 700, cursor: "pointer" }}>Never Miss a Drop →</button>
          </div>
        </section>
      </div>
    );
  }

  renderMusic() {
    const s = this.state;
    const track = TRACKS[s.idx];
    const activeTint = "color-mix(in oklch, var(--acc,#3A45E0), transparent 90%)";
    const barPct = Math.min(s.cur / MAX, 1) * 100 + "%";
    const setBarPct = Math.min(s.setCur / MAX, 1) * 100 + "%";
    return (
      <div>
        <section style={{ maxWidth: 860, margin: "0 auto", padding: "76px 24px 6px", textAlign: "center" }}>
          <div style={{ fontSize: 12, letterSpacing: ".22em", textTransform: "uppercase", color: "rgba(21,23,30,.5)", fontWeight: 600 }}>Free Music · Debut Album</div>
          <h1 style={{ fontFamily: "'Space Grotesk'", fontWeight: 700, fontSize: "clamp(42px,7vw,86px)", lineHeight: .98, letterSpacing: "-.03em", margin: "14px 0 0" }}>Squaring the Circle</h1>
          <p style={{ color: "rgba(21,23,30,.64)", fontSize: 17, lineHeight: 1.7, maxWidth: 600, margin: "22px auto 0" }}>
            Ten tracks about the space between who you were and who you're becoming. Preview any track, then take the whole album{" "}
            <em style={{ fontStyle: "normal", color: ACC, fontWeight: 600 }}>free</em>.
          </p>
        </section>

        <section style={{ maxWidth: 1000, margin: "0 auto", padding: "40px 24px 18px" }}>
          <div style={{ background: "#fff", border: "1px solid rgba(21,23,30,.09)", borderRadius: 22, padding: 28, boxShadow: "0 22px 60px rgba(21,23,30,.08)" }}>
            <div style={{ display: "flex", flexWrap: "wrap", gap: 20, alignItems: "center" }}>
              <div style={{ position: "relative", width: 110, flex: "none", aspectRatio: "1", borderRadius: 14, overflow: "hidden", cursor: "pointer" }} onClick={() => this.togglePlay()}>
                <img src="images/squaring-the-circle.webp" alt="cover" style={{ width: "100%", height: "100%", objectFit: "cover", display: "block" }} />
                <span style={{ position: "absolute", inset: 0, display: "grid", placeItems: "center", background: "rgba(12,14,22,.2)" }}>
                  <span style={{ width: 44, height: 44, borderRadius: "50%", background: ACC, color: "#fff", display: "grid", placeItems: "center", fontSize: 15 }}>{s.playing ? "❚❚" : "▶"}</span>
                </span>
              </div>
              <div style={{ flex: 1, minWidth: 190 }}>
                <div style={{ fontSize: 11, letterSpacing: ".16em", textTransform: "uppercase", color: "rgba(21,23,30,.42)", fontWeight: 600 }}>Now previewing · 30s</div>
                <h3 style={{ fontFamily: "'Space Grotesk'", fontWeight: 700, fontSize: 26, margin: "5px 0 3px", color: "#15171E", whiteSpace: "nowrap", overflow: "hidden", textOverflow: "ellipsis" }}>{track.t}</h3>
                <div style={{ fontSize: 13.5, color: "rgba(21,23,30,.5)" }}>Track {track.n} · HAUMS — 2025</div>
              </div>
              <button className="hm3-lift" onClick={() => this.openModal("album", track)} style={{ display: "inline-flex", alignItems: "center", gap: 8, background: ACC, color: "#fff", border: "none", borderRadius: 12, padding: "13px 22px", fontSize: 13.5, fontWeight: 600, cursor: "pointer", whiteSpace: "nowrap" }}>Get album ↓</button>
            </div>

            <div ref={this.waveRef} style={{ display: "flex", alignItems: "center", gap: 3, height: 66, margin: "22px 0 10px" }}>
              {Array.from({ length: 80 }).map((_, i) => (
                <span key={i} style={{ flex: 1, height: 8, borderRadius: 2, background: "color-mix(in oklch,var(--acc,#3A45E0),transparent 55%)" }} />
              ))}
            </div>

            <div style={{ display: "flex", alignItems: "center", gap: 14, fontSize: 12, color: "rgba(21,23,30,.55)", fontVariantNumeric: "tabular-nums" }}>
              <button onClick={() => this.prev()} style={{ background: "none", border: "none", cursor: "pointer", fontSize: 14, color: "rgba(21,23,30,.55)" }}>◀◀</button>
              <button onClick={() => this.togglePlay()} style={{ width: 44, height: 44, borderRadius: "50%", background: "#15171E", color: "#fff", border: "none", cursor: "pointer", fontSize: 15, display: "grid", placeItems: "center", flex: "none" }}>{s.playing ? "❚❚" : "▶"}</button>
              <button onClick={() => this.next()} style={{ background: "none", border: "none", cursor: "pointer", fontSize: 14, color: "rgba(21,23,30,.55)" }}>▶▶</button>
              <span>{fmt(s.cur)}</span>
              <span onClick={(e) => this.seek(e)} style={{ flex: 1, height: 5, borderRadius: 3, background: "rgba(21,23,30,.1)", cursor: "pointer", position: "relative" }}>
                <span style={{ display: "block", height: "100%", borderRadius: 3, background: ACC, width: barPct }} />
              </span>
              <span>0:30 / {track.d}</span>
            </div>
          </div>

          <ul style={{ listStyle: "none", margin: "20px 0 0", padding: 0, display: "grid", gap: 8 }}>
            {TRACKS.map((tr, i) => {
              const on = i === s.idx;
              return (
                <li key={tr.n} style={{
                  display: "grid", gridTemplateColumns: "36px 1fr auto auto", alignItems: "center", gap: 14, padding: "13px 18px",
                  background: on ? activeTint : "#fff",
                  border: "1px solid " + (on ? "color-mix(in oklch, var(--acc,#3A45E0), transparent 60%)" : "rgba(21,23,30,.08)"),
                  borderRadius: 12, color: on ? ACC : "#15171E", fontWeight: on ? 600 : 500, transition: "background .15s",
                }}>
                  <button onClick={() => this.playIndex(i)} style={{ background: "none", border: "none", cursor: "pointer", fontSize: 13, fontWeight: 700, color: "inherit", fontVariantNumeric: "tabular-nums", textAlign: "left" }}>{on && s.playing ? "▶" : tr.n}</button>
                  <button onClick={() => this.playIndex(i)} style={{ background: "none", border: "none", cursor: "pointer", fontSize: 15, color: "inherit", textAlign: "left", fontWeight: "inherit", overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap" }}>{tr.t}</button>
                  <button onClick={(e) => { e.stopPropagation(); this.openModal("album", tr); }} title="Download full track" style={{ background: "none", border: "none", cursor: "pointer", fontSize: 15, color: ACC }}>↓</button>
                  <span style={{ fontSize: 13, color: "rgba(21,23,30,.42)", fontVariantNumeric: "tabular-nums" }}>{tr.d}</span>
                </li>
              );
            })}
          </ul>
        </section>

        {SHOW_LIVE_SET && (
          <section style={{ maxWidth: 1000, margin: "0 auto", padding: "24px 24px 100px" }}>
            <div style={{ display: "flex", alignItems: "center", gap: 8, margin: "14px 0 20px" }}>
              <span style={{ width: 8, height: 8, background: ACC }} />
              <span style={{ fontFamily: "'Space Grotesk'", fontWeight: 700, fontSize: 18 }}>Live Set</span>
            </div>
            <div style={{ background: "#fff", border: "1px solid rgba(21,23,30,.09)", borderRadius: 20, overflow: "hidden", display: "grid", gridTemplateColumns: "repeat(auto-fit,minmax(260px,1fr))", boxShadow: "0 22px 60px rgba(21,23,30,.08)" }}>
              <div style={{ position: "relative", cursor: "pointer", minHeight: 230 }} onClick={() => this.toggleSet()}>
                <img src="images/haums-set-001.jpg" alt="Live Set 001" style={{ position: "absolute", inset: 0, width: "100%", height: "100%", objectFit: "cover" }} />
                <div style={{ position: "absolute", inset: 0, display: "grid", placeItems: "center", background: "rgba(12,14,22,.24)" }}>
                  <span style={{ width: 64, height: 64, borderRadius: "50%", background: ACC, color: "#fff", display: "grid", placeItems: "center", fontSize: 19 }}>{s.setPlaying ? "❚❚" : "▶"}</span>
                </div>
                <span style={{ position: "absolute", bottom: 12, right: 14, fontSize: 12, color: "#fff", background: "rgba(12,14,22,.5)", padding: "3px 9px", borderRadius: 20 }}>57:16</span>
              </div>
              <div style={{ padding: 28 }}>
                <div style={{ fontSize: 11, letterSpacing: ".16em", textTransform: "uppercase", color: "rgba(21,23,30,.42)", fontWeight: 600 }}>Live Set · 30s Preview</div>
                <h3 style={{ fontFamily: "'Space Grotesk'", fontWeight: 700, fontSize: 24, margin: "7px 0 10px" }}>HAUMS Live · Set 001</h3>
                <p style={{ fontSize: 15, color: "rgba(21,23,30,.64)", lineHeight: 1.65, margin: "0 0 18px" }}>Fifty-seven minutes, unbroken. The full arc of a HAUMS set — the descent, the build, the release. Meant to be played start to finish.</p>
                <span style={{ display: "block", height: 5, borderRadius: 3, background: "rgba(21,23,30,.1)", marginBottom: 18 }}>
                  <span style={{ display: "block", height: "100%", borderRadius: 3, background: ACC, width: setBarPct }} />
                </span>
                <div style={{ display: "flex", gap: 12, flexWrap: "wrap" }}>
                  <button onClick={() => this.toggleSet()} style={{ background: "#fff", border: "1px solid rgba(21,23,30,.14)", borderRadius: 12, padding: "11px 20px", fontSize: 13, fontWeight: 600, cursor: "pointer" }}>{s.setPlaying ? "❚❚" : "▶"} Preview</button>
                  <button className="hm3-lift" onClick={() => this.openModal("set", null)} style={{ display: "inline-flex", alignItems: "center", gap: 8, background: ACC, color: "#fff", border: "none", borderRadius: 12, padding: "11px 22px", fontSize: 13, fontWeight: 600, cursor: "pointer" }}>Download free ↓</button>
                </div>
              </div>
            </div>
          </section>
        )}
      </div>
    );
  }

  renderAbout() {
    return (
      <div style={{ maxWidth: 900, margin: "0 auto", padding: "76px 24px 100px" }}>
        <div style={{ textAlign: "center" }}>
          <div style={{ fontSize: 12, letterSpacing: ".22em", textTransform: "uppercase", color: "rgba(21,23,30,.5)", fontWeight: 600 }}>About · HAUMS</div>
          <h1 style={{ fontFamily: "'Space Grotesk'", fontWeight: 700, fontSize: "clamp(36px,5.4vw,64px)", lineHeight: 1.03, letterSpacing: "-.025em", margin: "16px 0 0" }}>
            It's not the music that changed.<br /><span style={{ color: ACC }}>It's that you did.</span>
          </h1>
        </div>

        <div style={{ position: "relative", margin: "42px 0 0", borderRadius: 20, overflow: "hidden", boxShadow: "0 26px 70px rgba(21,23,30,.22)" }}>
          <img src="images/haums-portrait.jpg" alt="HAUMS" style={{ width: "100%", display: "block" }} />
          <div style={{ position: "absolute", inset: 0, display: "grid", placeItems: "center" }}>
            <span style={{ width: 72, height: 72, borderRadius: "50%", background: ACC, color: "#fff", display: "grid", placeItems: "center", fontSize: 20, boxShadow: "0 12px 30px rgba(12,14,22,.4)" }}>▶</span>
          </div>
          <span style={{ position: "absolute", bottom: 16, left: 0, right: 0, textAlign: "center", fontSize: 11, letterSpacing: ".2em", textTransform: "uppercase", color: "#fff", fontWeight: 600, textShadow: "0 1px 8px rgba(0,0,0,.6)" }}>Film dropping soon</span>
        </div>

        <div style={{ maxWidth: 640, margin: "44px auto 0" }}>
          <p style={{ fontFamily: "'Space Grotesk'", fontWeight: 500, fontSize: 23, lineHeight: 1.4, color: "#15171E", margin: "0 0 22px" }}>I make music for people who still love this — but feel like they've outgrown where it used to take them.</p>
          <p style={{ fontSize: 17, lineHeight: 1.75, color: "rgba(21,23,30,.7)", margin: "0 0 18px" }}>You go out and it doesn't hit the same. You feel disconnected even when you're surrounded by people. You're growing, and the room hasn't caught up. That's not you losing it — that's you changing. My whole catalog is built for that moment.</p>
          <p style={{ fontSize: 17, lineHeight: 1.75, color: "rgba(21,23,30,.7)", margin: 0 }}>Melodic, organic, progressive house with a deeper tone underneath. I chase songs that do three things at once — <em style={{ fontStyle: "normal", color: ACC, fontWeight: 600 }}>make you think, make you feel, make you move.</em> When a track does all three, I put it out.</p>
        </div>

        <div style={{ display: "grid", gridTemplateColumns: "repeat(auto-fit,minmax(200px,1fr))", gap: 14, margin: "48px 0 0" }}>
          <div style={{ background: "#fff", border: "1px solid rgba(21,23,30,.09)", borderRadius: 14, padding: 20 }}>
            <div style={{ fontFamily: "'Space Grotesk'", fontWeight: 700, fontSize: 28, color: ACC }}>#1</div>
            <div style={{ fontSize: 13, color: "rgba(21,23,30,.6)", marginTop: 4 }}>Beatport Organic House</div>
          </div>
          <div style={{ background: "#fff", border: "1px solid rgba(21,23,30,.09)", borderRadius: 14, padding: 20 }}>
            <div style={{ fontFamily: "'Space Grotesk'", fontWeight: 700, fontSize: 16 }}>Supported by</div>
            <div style={{ fontSize: 13, color: "rgba(21,23,30,.6)", marginTop: 4 }}>Tiësto · Nora En Pure · Vintage Culture</div>
          </div>
          <div style={{ background: "#fff", border: "1px solid rgba(21,23,30,.09)", borderRadius: 14, padding: 20 }}>
            <div style={{ fontFamily: "'Space Grotesk'", fontWeight: 700, fontSize: 16 }}>Live</div>
            <div style={{ fontSize: 13, color: "rgba(21,23,30,.6)", marginTop: 4 }}>Nashville · Tulum · and beyond</div>
          </div>
        </div>

        <div style={{ display: "flex", gap: 12, justifyContent: "center", flexWrap: "wrap", marginTop: 46 }}>
          <button className="hm3-lift" onClick={() => this.setView("updates")} style={{ display: "inline-flex", alignItems: "center", gap: 10, background: ACC, color: "#fff", border: "none", borderRadius: 12, padding: "15px 30px", fontSize: 14, fontWeight: 600, cursor: "pointer" }}>Never Miss a Drop →</button>
          <button onClick={() => this.setView("music")} style={{ background: "#fff", border: "1px solid rgba(21,23,30,.14)", borderRadius: 12, padding: "15px 28px", fontSize: 14, fontWeight: 600, cursor: "pointer" }}>Hear the music →</button>
        </div>
      </div>
    );
  }

  renderShows() {
    return (
      <div>
        <section style={{ position: "relative", minHeight: 380, display: "grid", placeItems: "center", textAlign: "center", overflow: "hidden" }}>
          <img src="images/haums-set-001.jpg" alt="HAUMS live" style={{ position: "absolute", inset: 0, width: "100%", height: "100%", objectFit: "cover" }} />
          <div style={{ position: "absolute", inset: 0, background: "linear-gradient(180deg,rgba(12,14,22,.5),rgba(12,14,22,.74))" }} />
          <div style={{ position: "relative", padding: "78px 24px", maxWidth: 640 }}>
            <div style={{ fontSize: 12, letterSpacing: ".24em", textTransform: "uppercase", color: "rgba(255,255,255,.75)", fontWeight: 600 }}>Live</div>
            <h1 style={{ fontFamily: "'Space Grotesk'", fontWeight: 700, fontSize: "clamp(40px,6vw,72px)", letterSpacing: "-.025em", margin: "14px 0 0", color: "#fff" }}>Shows</h1>
            <p style={{ color: "rgba(255,255,255,.84)", fontSize: 17, lineHeight: 1.65, margin: "18px auto 0", maxWidth: 500 }}>The set is built to move a room — melodic, organic, progressive, deep. Here's where to catch it live.</p>
          </div>
        </section>

        <section style={{ maxWidth: 720, margin: "0 auto", padding: "56px 24px 100px" }}>
          <div style={{ background: "#fff", border: "1px solid rgba(21,23,30,.09)", borderRadius: 18, padding: "48px 28px", textAlign: "center" }}>
            <div style={{ fontSize: 11.5, letterSpacing: ".2em", textTransform: "uppercase", color: "rgba(21,23,30,.42)", fontWeight: 600 }}>Upcoming</div>
            <h2 style={{ fontFamily: "'Space Grotesk'", fontWeight: 700, fontSize: "clamp(24px,3.2vw,34px)", letterSpacing: "-.02em", margin: "12px 0 12px" }}>No dates on the calendar right now.</h2>
            <p style={{ fontSize: 16, lineHeight: 1.7, color: "rgba(21,23,30,.66)", margin: "0 auto 28px", maxWidth: 460 }}>The next run gets announced to the list first — usually before tickets go public. Get on it and you'll never miss a show near you.</p>
            <button className="hm3-lift" onClick={() => this.setView("updates")} style={{ display: "inline-flex", alignItems: "center", gap: 10, background: ACC, color: "#fff", border: "none", borderRadius: 12, padding: "15px 30px", fontSize: 14, fontWeight: 600, cursor: "pointer" }}>Never Miss a Drop →</button>
          </div>
          <div style={{ textAlign: "center", marginTop: 26, fontSize: 13, letterSpacing: ".04em", color: "rgba(21,23,30,.5)" }}>Previously live in <span style={{ color: "#15171E", fontWeight: 600 }}>Nashville</span> · <span style={{ color: "#15171E", fontWeight: 600 }}>Tulum</span></div>
        </section>
      </div>
    );
  }

  renderUpdates() {
    const s = this.state;
    const activeTint = "color-mix(in oklch, var(--acc,#3A45E0), transparent 90%)";
    const field = (num, label, key, opts) => (
      <label style={{ display: "block", marginBottom: opts && opts.inRow ? 0 : 14 }}>
        <span style={{ display: "block", fontSize: 11.5, letterSpacing: ".06em", textTransform: "uppercase", color: "rgba(21,23,30,.5)", fontWeight: 600, marginBottom: 7 }}>{num} — {label}</span>
        <input
          className="hm3-input"
          required={!(opts && opts.optional)}
          type={(opts && opts.type) || "text"}
          value={s.jForm[key]}
          onChange={this.jField(key)}
          placeholder={(opts && opts.placeholder) || label}
          style={{ width: "100%", background: "#F6F7F9", border: "1px solid rgba(21,23,30,.12)", borderRadius: 11, padding: "13px 15px", fontSize: 15 }}
        />
      </label>
    );
    return (
      <div>
        <section style={{ position: "relative", minHeight: 400, display: "grid", placeItems: "center", textAlign: "center", overflow: "hidden" }}>
          <img src="images/haums-booth.jpg" alt="HAUMS live" style={{ position: "absolute", inset: 0, width: "100%", height: "100%", objectFit: "cover" }} />
          <div style={{ position: "absolute", inset: 0, background: "linear-gradient(180deg,rgba(12,14,22,.55),rgba(12,14,22,.72))" }} />
          <div style={{ position: "relative", padding: "78px 24px", maxWidth: 640 }}>
            <div style={{ fontSize: 12, letterSpacing: ".24em", textTransform: "uppercase", color: "rgba(255,255,255,.75)", fontWeight: 600 }}>The list</div>
            <h1 style={{ fontFamily: "'Space Grotesk'", fontWeight: 700, fontSize: "clamp(40px,6vw,72px)", letterSpacing: "-.025em", margin: "14px 0 0", color: "#fff" }}>Never miss a drop.</h1>
            <p style={{ color: "rgba(255,255,255,.84)", fontSize: 17, lineHeight: 1.65, margin: "18px auto 0", maxWidth: 500 }}>New music and new shows reach this list first — usually before anywhere else. The first word, straight from HAUMS.</p>
          </div>
        </section>

        <section style={{ maxWidth: 680, margin: "0 auto", padding: "56px 24px 100px" }}>
          <p style={{ textAlign: "center", fontSize: 17, lineHeight: 1.7, color: "rgba(21,23,30,.7)", margin: "0 0 40px" }}>Get on the list and you'll hear every release and show before anyone else — plus free music to start. No noise. Just the work.</p>

          <div style={{ fontSize: 11.5, letterSpacing: ".2em", textTransform: "uppercase", color: "rgba(21,23,30,.42)", fontWeight: 600, marginBottom: 16 }}>Start with something free · pick one</div>
          <div style={{ display: "grid", gridTemplateColumns: "repeat(auto-fit,minmax(200px,1fr))", gap: 12, marginBottom: 36 }}>
            {GIFTS.map((g) => {
              const sel = s.jForm.gift === g.id;
              return (
                <button
                  key={g.id}
                  className="hm3-card"
                  onClick={() => this.setState({ jForm: { ...s.jForm, gift: g.id } })}
                  aria-pressed={sel}
                  style={{ textAlign: "left", background: sel ? activeTint : "#fff", border: sel ? "1.5px solid " + ACC : "1px solid rgba(21,23,30,.09)", borderRadius: 14, padding: 18, cursor: "pointer" }}
                >
                  <div style={{ fontFamily: "'Space Grotesk'", fontWeight: 700, fontSize: 16, color: "#15171E", marginBottom: 6 }}>{g.name}</div>
                  <div style={{ fontSize: 13, color: "rgba(21,23,30,.58)", lineHeight: 1.55 }}>{g.desc}</div>
                </button>
              );
            })}
          </div>

          {s.jSubmitted ? (
            <div style={{ textAlign: "center", background: "#fff", border: "1px solid rgba(21,23,30,.09)", borderRadius: 18, padding: "52px 28px" }}>
              <div style={{ width: 70, height: 70, borderRadius: "50%", background: "color-mix(in oklch,var(--acc,#3A45E0),transparent 86%)", color: ACC, display: "grid", placeItems: "center", fontSize: 26, margin: "0 auto 18px" }}>✓</div>
              <h3 style={{ fontFamily: "'Space Grotesk'", fontWeight: 700, fontSize: 29, margin: "0 0 8px" }}>You're on the list.</h3>
              <p style={{ fontSize: 16, color: "rgba(21,23,30,.64)", margin: 0 }}>Your first text from me arrives within the hour.</p>
            </div>
          ) : (
            <form onSubmit={(e) => this.submitJoin(e)} style={{ background: "#fff", border: "1px solid rgba(21,23,30,.09)", borderRadius: 18, padding: 28 }}>
              <div style={{ display: "flex", justifyContent: "space-between", alignItems: "center", marginBottom: 20, fontSize: 11, letterSpacing: ".16em", textTransform: "uppercase", fontWeight: 600 }}>
                <span style={{ color: ACC }}>Get on the list</span><span style={{ color: "rgba(21,23,30,.4)" }}>Fields · 5/5</span>
              </div>
              {field("01", "Name", "name", { placeholder: "Full name" })}
              {field("02", "Email", "email", { type: "email", placeholder: "you@signal.com" })}
              {field("03", "Phone (for SMS)", "phone", { type: "tel", placeholder: "+1 555 000 0000" })}
              <div style={{ display: "grid", gridTemplateColumns: "1fr 1fr", gap: 12, marginBottom: 20 }}>
                {field("04", "City", "city", { placeholder: "City", inRow: true })}
                {field("05", "Address", "address", { placeholder: "Optional (vinyl)", optional: true, inRow: true })}
              </div>
              <button type="submit" className="hm3-lift" style={{ width: "100%", display: "flex", alignItems: "center", justifyContent: "center", gap: 10, background: ACC, color: "#fff", border: "none", borderRadius: 12, padding: 16, fontSize: 15, fontWeight: 600, cursor: "pointer" }}>Never Miss a Drop →</button>
              <LayloConsent context="joining" />
              <p style={{ fontSize: 12.5, color: ACC, margin: "12px 0 0", textAlign: "center", fontWeight: 600 }}>Your first text from me arrives within the hour.</p>
            </form>
          )}
        </section>
      </div>
    );
  }

  renderFooter() {
    const link = (label, href) => (
      <a href={href} target="_blank" rel="noopener noreferrer" className="hm3-link" style={{ textDecoration: "none", color: "rgba(21,23,30,.68)" }}>{label} ↗</a>
    );
    return (
      <footer style={{ borderTop: "1px solid rgba(21,23,30,.1)", padding: "52px 24px 44px", textAlign: "center" }}>
        <div style={{ display: "inline-flex", alignItems: "center", gap: 10, justifyContent: "center" }}>
          <span style={{ width: 9, height: 9, borderRadius: "50%", background: ACC }} />
          <span style={{ fontFamily: "'Space Grotesk'", fontWeight: 700, fontSize: 22, letterSpacing: ".26em" }}>HAUMS</span>
        </div>
        <div style={{ fontSize: 14, color: "rgba(21,23,30,.5)", marginTop: 10 }}>The music, the shows, the people.</div>
        <div style={{ display: "flex", gap: 20, justifyContent: "center", flexWrap: "wrap", margin: "24px 0 0", fontSize: 13, fontWeight: 500 }}>
          {link("SoundCloud", "https://soundcloud.com/haums")}{link("Spotify", "https://open.spotify.com/artist/2rHkapXIPIa4EVvMC8Nm6G")}{link("Apple Music", "https://music.apple.com/us/artist/haums/1518626537")}{link("Instagram", "https://www.instagram.com/haumsmusic/")}{link("YouTube", "https://www.youtube.com/channel/UCFWrWqW8FHs1jzRxlaI0sTQ")}
        </div>
        <div style={{ fontSize: 12, color: "rgba(21,23,30,.5)", marginTop: 20 }}>Booking, Press &amp; Demos · <a href="mailto:contact@haumsmusic.com" style={{ color: ACC }}>contact@haumsmusic.com</a></div>
        <div style={{ fontSize: 11, letterSpacing: ".14em", textTransform: "uppercase", color: "rgba(21,23,30,.34)", marginTop: 16 }}>© MMXXVI · All frequencies reserved</div>
      </footer>
    );
  }

  renderModal() {
    const s = this.state;
    if (!s.modalOpen) return null;
    const isAlbum = s.modalKind === "album";
    const mTitle = isAlbum ? ((s.modalTrack ? s.modalTrack.t : "The album") + " + all 10 tracks.") : "HAUMS Live · Set 001";
    const field = (num, label, key, opts) => (
      <label style={{ display: "block", marginBottom: opts && opts.inRow ? 0 : 14 }}>
        <span style={{ display: "block", fontSize: 11, letterSpacing: ".06em", textTransform: "uppercase", color: "rgba(21,23,30,.5)", fontWeight: 600, marginBottom: 6 }}>{num} — {label}</span>
        <input
          className="hm3-input"
          required={!(opts && opts.optional)}
          type={(opts && opts.type) || "text"}
          value={s.mForm[key]}
          onChange={this.mField(key)}
          placeholder={(opts && opts.placeholder) || label}
          style={{ width: "100%", background: "#F6F7F9", border: "1px solid rgba(21,23,30,.12)", borderRadius: 11, padding: "12px 14px", fontSize: 15 }}
        />
      </label>
    );
    return (
      <div onClick={() => this.closeModal()} style={{ position: "fixed", inset: 0, zIndex: 200, background: "rgba(12,14,22,.55)", backdropFilter: "blur(6px)", display: "grid", placeItems: "center", padding: 22, animation: "hm3-fade .25s ease" }}>
        <div onClick={(e) => e.stopPropagation()} role="dialog" aria-modal="true" style={{ position: "relative", width: "100%", maxWidth: 520, maxHeight: "88vh", overflow: "auto", background: "#fff", borderRadius: 20, padding: 34, boxShadow: "0 40px 100px rgba(12,14,22,.4)" }}>
          <button onClick={() => this.closeModal()} aria-label="Close" style={{ position: "absolute", top: 16, right: 18, background: "none", border: "none", fontSize: 24, cursor: "pointer", color: "rgba(21,23,30,.5)", lineHeight: 1 }}>×</button>

          {s.modalDone ? (
            <div>
              <div style={{ fontSize: 11, letterSpacing: ".16em", textTransform: "uppercase", color: ACC, fontWeight: 600 }}>{isAlbum ? "You're in · all 10 tracks" : "You're in · live set"}</div>
              <h3 style={{ fontFamily: "'Space Grotesk'", fontWeight: 700, fontSize: 28, margin: "8px 0 10px" }}>{isAlbum ? "The album is yours." : "It's yours."}</h3>
              <p style={{ fontSize: 15, color: "rgba(21,23,30,.66)", lineHeight: 1.6, margin: "0 0 20px" }}>
                {isAlbum
                  ? "It's downloading now. Grab any track below — or take the whole album in one click. No catch."
                  : "“HAUMS Live · Set 001” is downloading now. No catch — if it resonates, you'll hear from me first."}
              </p>
              {isAlbum && (
                <div>
                  <button onClick={() => this.dlAll()} style={{ width: "100%", display: "flex", alignItems: "center", justifyContent: "center", gap: 10, background: ACC, color: "#fff", border: "none", borderRadius: 12, padding: 15, fontSize: 14, fontWeight: 600, cursor: "pointer", marginBottom: 16 }}>Download whole album ↓</button>
                  <ul style={{ listStyle: "none", margin: 0, padding: 0, display: "grid", gap: 6 }}>
                    {TRACKS.map((tr) => (
                      <li key={tr.n} style={{ display: "grid", gridTemplateColumns: "30px 1fr auto", alignItems: "center", gap: 12, padding: "11px 15px", background: "#F6F7F9", borderRadius: 10 }}>
                        <span style={{ fontSize: 12, color: "rgba(21,23,30,.42)", fontVariantNumeric: "tabular-nums" }}>{tr.n}</span>
                        <span style={{ fontSize: 14 }}>{tr.t}</span>
                        <button onClick={() => dlTrack(tr)} style={{ background: "none", border: "none", cursor: "pointer", color: ACC, fontSize: 15 }}>↓</button>
                      </li>
                    ))}
                  </ul>
                </div>
              )}
            </div>
          ) : (
            <div>
              <div style={{ fontSize: 11, letterSpacing: ".16em", textTransform: "uppercase", color: ACC, fontWeight: 600 }}>{isAlbum ? "Free · entire album" : "Free · live set"}</div>
              <h3 style={{ fontFamily: "'Space Grotesk'", fontWeight: 700, fontSize: 25, lineHeight: 1.15, margin: "8px 0 10px" }}>{mTitle}</h3>
              <p style={{ fontSize: 15, color: "rgba(21,23,30,.66)", lineHeight: 1.6, margin: "0 0 22px" }}>
                {isAlbum
                  ? "Drop your info and the full album is yours — every track, full length, free. Plus the first word on every release."
                  : "Drop your info and it's yours — full length, free. Plus the first word on every release and live experience."}
              </p>
              <form onSubmit={(e) => this.submitModal(e)}>
                {field("01", "Name", "name", { placeholder: "Full name" })}
                {field("02", "Email", "email", { type: "email", placeholder: "you@signal.com" })}
                {field("03", "Phone (for tour SMS)", "phone", { type: "tel", placeholder: "+1 555 000 0000" })}
                <div style={{ display: "grid", gridTemplateColumns: "1fr 1fr", gap: 12, marginBottom: 20 }}>
                  {field("04", "City", "city", { placeholder: "City", inRow: true })}
                  {field("05", "Address", "address", { placeholder: "Optional", optional: true, inRow: true })}
                </div>
                <button type="submit" style={{ width: "100%", display: "flex", alignItems: "center", justifyContent: "center", gap: 10, background: ACC, color: "#fff", border: "none", borderRadius: 12, padding: 16, fontSize: 15, fontWeight: 600, cursor: "pointer" }}>{isAlbum ? "Get the album" : "Get it free"} ↓</button>
                <LayloConsent context="submitting" />
              </form>
            </div>
          )}
        </div>
      </div>
    );
  }

  render() {
    const s = this.state;
    return (
      <div ref={this.rootRef} style={{ minHeight: "100vh", background: "#EEF0F4", color: "#15171E", fontFamily: "'Instrument Sans',system-ui,sans-serif", fontSize: 16, lineHeight: 1.6, WebkitFontSmoothing: "antialiased", overflowX: "hidden" }}>
        <audio ref={this.albumAudio} src={TRACKS[s.idx].src} preload="none" />
        <audio ref={this.setAudio} src={SET.src} preload="none" />

        {this.renderNav()}
        {s.view === "home" && this.renderHome()}
        {s.view === "music" && this.renderMusic()}
        {s.view === "shows" && this.renderShows()}
        {s.view === "about" && this.renderAbout()}
        {s.view === "updates" && this.renderUpdates()}
        {this.renderFooter()}
        {this.renderModal()}
      </div>
    );
  }
}

ReactDOM.createRoot(document.getElementById("root")).render(<App />);
