"use client";

import { useEffect, useRef, useState, useCallback } from "react";
import { useRouter } from "next/navigation";
import { useAppDispatch, useAppSelector } from "@/store/hooks";
import {
  togglePlay,
  setProgress,
  setVolume,
  toggleShuffle,
  toggleRepeat,
  playNext,
  playPrev,
  setTrack,
  setRepeat,
} from "@/store/slices/playerSlice";
import { audioPlayer } from "@/lib/audioPlayer";
import { LYRICS } from "@/features/music/data";
import type { MusicItem } from "@/services/musicSectionService";
import { ContentActionsModal } from "@/components/shared/ContentActionsModal";
import { CT } from "@/config/contentTypes";
import Image from "next/image";

/* ─── types ──────────────────────────────────────────────────────────────── */
const SPEED_OPTIONS = [0.5, 0.75, 1, 1.25, 1.5, 2] as const;
type SpeedValue = (typeof SPEED_OPTIONS)[number];
const TIMER_MINS = [0, 5, 10, 15, 20, 30, 45, 60];

/* ─── helpers ─────────────────────────────────────────────────────────────── */
function fmtSecs(s: number) {
  if (!isFinite(s) || isNaN(s)) return "0:00";
  return `${Math.floor(s / 60)}:${(Math.floor(s) % 60).toString().padStart(2, "0")}`;
}
function currentTime(pct: number) {
  const d = audioPlayer.audio.duration;
  return !d || isNaN(d) ? "0:00" : fmtSecs((pct / 100) * d);
}
function totalDur() {
  const d = audioPlayer.audio.duration;
  return !d || isNaN(d) ? "--:--" : fmtSecs(d);
}

/* ─── EQ bars ─────────────────────────────────────────────────────────────── */
function EqBars({ size = 12 }: { size?: number }) {
  return (
    <div className="flex items-end gap-[2px]" style={{ height: size }}>
      {[0.55, 1, 0.7, 0.9, 0.45].map((h, i) => (
        <span
          key={i}
          style={{
            display: "block",
            width: 2.5,
            height: size,
            background: "var(--accent)",
            borderRadius: 2,
            transformOrigin: "bottom",
            animation: `npEq ${0.45 + h * 0.45}s ease-in-out ${i * 0.09}s infinite`,
          }}
        />
      ))}
    </div>
  );
}

/* ─── Seekbar with drag ───────────────────────────────────────────────────── */
function SeekBar({
  progress,
  dispatch,
}: {
  progress: number;
  dispatch: ReturnType<typeof useAppDispatch>;
}) {
  const barRef = useRef<HTMLDivElement>(null);
  const [dragging, setDragging] = useState(false);
  const [local, setLocal] = useState(progress);
  const [hoverX, setHoverX] = useState<number | null>(null);

  useEffect(() => {
    if (!dragging) setLocal(progress);
  }, [progress, dragging]);

  const pct = useCallback((ex: number) => {
    if (!barRef.current) return 0;
    const r = barRef.current.getBoundingClientRect();
    return Math.max(0, Math.min(100, ((ex - r.left) / r.width) * 100));
  }, []);

  const commit = useCallback(
    (p: number) => {
      dispatch(setProgress(p));
      const d = audioPlayer.audio.duration;
      if (d && isFinite(d)) audioPlayer.seek((p / 100) * d);
    },
    [dispatch],
  );

  useEffect(() => {
    if (!dragging) return;
    const mv = (e: MouseEvent) => setLocal(pct(e.clientX));
    const up = (e: MouseEvent) => {
      commit(pct(e.clientX));
      setDragging(false);
    };
    window.addEventListener("mousemove", mv);
    window.addEventListener("mouseup", up);
    return () => {
      window.removeEventListener("mousemove", mv);
      window.removeEventListener("mouseup", up);
    };
  }, [dragging, pct, commit]);

  const shown = dragging ? local : progress;
  const tipPct = hoverX !== null ? pct(hoverX) : null;

  return (
    <div
      style={{
        position: "relative",
        width: "100%",
        paddingTop: 10,
        cursor: "pointer",
      }}
    >
      {tipPct !== null && (
        <div
          style={{
            position: "absolute",
            top: -2,
            left: `${tipPct}%`,
            transform: "translateX(-50%)",
            background: "rgba(0,0,0,0.85)",
            color: "#fff",
            fontSize: 10,
            fontWeight: 600,
            padding: "2px 7px",
            borderRadius: 5,
            pointerEvents: "none",
            zIndex: 5,
            whiteSpace: "nowrap",
          }}
        >
          {currentTime(tipPct)}
        </div>
      )}
      <div
        ref={barRef}
        onMouseMove={(e) => setHoverX(e.clientX)}
        onMouseLeave={() => setHoverX(null)}
        onMouseDown={(e) => {
          setLocal(pct(e.clientX));
          setDragging(true);
        }}
        onClick={(e) => commit(pct(e.clientX))}
        className="np-seek-track"
      >
        <div className="np-seek-fill" style={{ width: `${shown}%` }}>
          <div
            className={`np-seek-thumb${dragging ? " np-seek-thumb-vis" : ""}`}
          />
        </div>
      </div>
    </div>
  );
}

/* ─── Volume slider ───────────────────────────────────────────────────────── */
function VolumeSlider({
  volume,
  onChange,
}: {
  volume: number;
  onChange: (v: number) => void;
}) {
  const barRef = useRef<HTMLDivElement>(null);
  const [drag, setDrag] = useState(false);

  const pct = useCallback((ex: number) => {
    if (!barRef.current) return 0;
    const r = barRef.current.getBoundingClientRect();
    return Math.round(
      Math.max(0, Math.min(100, ((ex - r.left) / r.width) * 100)),
    );
  }, []);

  useEffect(() => {
    if (!drag) return;
    const mv = (e: MouseEvent) => onChange(pct(e.clientX));
    const up = () => setDrag(false);
    window.addEventListener("mousemove", mv);
    window.addEventListener("mouseup", up);
    return () => {
      window.removeEventListener("mousemove", mv);
      window.removeEventListener("mouseup", up);
    };
  }, [drag, pct, onChange]);

  const muted = volume === 0;

  return (
    <div
      style={{
        display: "flex",
        alignItems: "center",
        gap: 8,
        flex: 1,
        minWidth: 0,
        maxWidth: 150,
      }}
    >
      <button
        onClick={() => onChange(muted ? 70 : 0)}
        style={{
          color: "var(--text-muted)",
          display: "flex",
          alignItems: "center",
          justifyContent: "center",
          flexShrink: 0,
        }}
        className="np-icon-btn"
      >
        {muted ? (
          <svg width="15" height="15" viewBox="0 0 24 24" fill="currentColor">
            <polygon points="11 5 6 9 2 9 2 15 6 15 11 19" />
            <line
              x1="23"
              y1="9"
              x2="17"
              y2="15"
              stroke="currentColor"
              strokeWidth="2"
              strokeLinecap="round"
            />
            <line
              x1="17"
              y1="9"
              x2="23"
              y2="15"
              stroke="currentColor"
              strokeWidth="2"
              strokeLinecap="round"
            />
          </svg>
        ) : volume < 60 ? (
          <svg width="15" height="15" viewBox="0 0 24 24" fill="currentColor">
            <polygon points="11 5 6 9 2 9 2 15 6 15 11 19" />
            <path
              d="M15.5 8.5a5 5 0 0 1 0 7"
              fill="none"
              stroke="currentColor"
              strokeWidth="1.8"
              strokeLinecap="round"
            />
          </svg>
        ) : (
          <svg width="15" height="15" viewBox="0 0 24 24" fill="currentColor">
            <polygon points="11 5 6 9 2 9 2 15 6 15 11 19" />
            <path
              d="M15.5 8.5a5 5 0 0 1 0 7"
              fill="none"
              stroke="currentColor"
              strokeWidth="1.8"
              strokeLinecap="round"
            />
            <path
              d="M19 5a9 9 0 0 1 0 14"
              fill="none"
              stroke="currentColor"
              strokeWidth="1.8"
              strokeLinecap="round"
            />
          </svg>
        )}
      </button>
      <div
        ref={barRef}
        className="np-vol-track"
        onMouseDown={(e) => {
          onChange(pct(e.clientX));
          setDrag(true);
        }}
        onClick={(e) => onChange(pct(e.clientX))}
      >
        <div className="np-vol-fill" style={{ width: `${volume}%` }} />
      </div>
    </div>
  );
}

/* ─── Queue row ───────────────────────────────────────────────────────────── */
function QueueRow({
  track,
  idx,
  active,
  onPlay,
}: {
  track: MusicItem;
  idx: number;
  active: boolean;
  onPlay: () => void;
}) {
  const ref = useRef<HTMLButtonElement>(null);
  useEffect(() => {
    if (active)
      ref.current?.scrollIntoView({ block: "nearest", behavior: "smooth" });
  }, [active]);

  return (
    <button
      ref={ref}
      onClick={onPlay}
      className={`np-q-row${active ? " np-q-row-active" : ""}`}
    >
      <span className="np-q-num">
        {active ? (
          <EqBars size={11} />
        ) : (
          <span style={{ color: "var(--text-muted)", fontSize: 10 }}>
            {idx + 1}
          </span>
        )}
      </span>
      <div className="np-q-art">
        {track.thumbnail ? (
          <Image
            src={track.thumbnail}
            alt={track.title}
            fill
            className="object-cover"
            sizes="36px"
            unoptimized
          />
        ) : (
          <span
            style={{
              position: "absolute",
              inset: 0,
              display: "flex",
              alignItems: "center",
              justifyContent: "center",
              fontSize: 16,
              color: "var(--text-muted)",
            }}
          >
            ♪
          </span>
        )}
      </div>
      <div style={{ minWidth: 0, flex: 1 }}>
        <p className={`np-q-name${active ? " np-q-name-on" : ""}`}>
          {track.title}
        </p>
        <p className="np-q-artist">{track.channelName}</p>
      </div>
      {track.duration && <span className="np-q-dur">{track.duration}</span>}
    </button>
  );
}

/* ─── More options sheet ──────────────────────────────────────────────────── */
function MoreSheet({
  track,
  onClose,
  onTimer,
  onActions,
}: {
  track: MusicItem;
  onClose: () => void;
  onTimer: () => void;
  onActions: () => void;
}) {
  const router = useRouter();

  const handleDownload = async () => {
    const url = track.audioUrl;
    if (!url) return;
    try {
      const res = await fetch(url, { mode: "cors" });
      const blob = await res.blob();
      const blobUrl = URL.createObjectURL(blob);
      const a = document.createElement("a");
      a.href = blobUrl;
      a.download = `${track.title}.mp3`;
      document.body.appendChild(a);
      a.click();
      document.body.removeChild(a);
      URL.revokeObjectURL(blobUrl);
    } catch {
      // CORS-restricted CDN — open directly so browser handles the save
      const a = document.createElement("a");
      a.href = url;
      a.download = `${track.title}.mp3`;
      a.target = "_blank";
      a.rel = "noopener noreferrer";
      document.body.appendChild(a);
      a.click();
      document.body.removeChild(a);
    }
  };

  const rows = [
    { label: "Add to Playlist", icon: "♥", cb: onActions },
    { label: "Share", icon: "↗", cb: () => {} },
    { label: "Download", icon: "⇩", cb: handleDownload },
    { label: "Report", icon: "⚑", cb: onActions },
    { label: "Sleep Timer", icon: "⏱", cb: onTimer },
    {
      label: "Go to Artist",
      icon: "👤",
      cb: () =>
        track.channelUserId && router.push(`/profile/${track.channelUserId}`),
    },
  ];
  return (
    <>
      <div
        onClick={onClose}
        style={{
          position: "fixed",
          inset: 0,
          zIndex: 410,
          background: "rgba(0,0,0,0.55)",
          backdropFilter: "blur(10px)",
        }}
      />
      <div
        className="np-sheet"
        style={{
          animation: "npSlideUp 0.3s cubic-bezier(0.34,1.2,0.64,1) both",
        }}
      >
        <div
          style={{
            width: 40,
            height: 4,
            background: "var(--sheet-handle)",
            borderRadius: 2,
            margin: "0 auto 16px",
          }}
        />
        <div
          style={{
            display: "flex",
            alignItems: "center",
            gap: 12,
            padding: "0 0 16px",
            borderBottom: "1px solid var(--border-soft)",
            marginBottom: 8,
          }}
        >
          <div
            style={{
              width: 46,
              height: 46,
              borderRadius: 8,
              overflow: "hidden",
              position: "relative",
              background: "var(--card)",
              flexShrink: 0,
            }}
          >
            {(track.thumbnail || track.landscapeImg) && (
              <Image
                src={track.thumbnail || track.landscapeImg}
                alt={track.title}
                fill
                className="object-cover"
                sizes="46px"
                unoptimized
              />
            )}
          </div>
          <div style={{ minWidth: 0, flex: 1 }}>
            <p
              style={{
                fontSize: 13,
                fontWeight: 600,
                color: "var(--text-primary)",
                overflow: "hidden",
                textOverflow: "ellipsis",
                whiteSpace: "nowrap",
              }}
            >
              {track.title}
            </p>
            <p
              style={{ fontSize: 11, color: "var(--text-muted)", marginTop: 2 }}
            >
              {track.channelName}
            </p>
          </div>
          <button
            onClick={onClose}
            className="np-icon-btn"
            style={{ flexShrink: 0 }}
          >
            <svg
              width="18"
              height="18"
              viewBox="0 0 24 24"
              fill="none"
              stroke="currentColor"
              strokeWidth="2"
              strokeLinecap="round"
            >
              <line x1="18" y1="6" x2="6" y2="18" />
              <line x1="6" y1="6" x2="18" y2="18" />
            </svg>
          </button>
        </div>
        {rows.map((r, i) => (
          <button
            key={i}
            onClick={() => {
              r.cb();
              onClose();
            }}
            className="np-sheet-row"
          >
            <span className="np-sheet-icon">{r.icon}</span>
            <span
              style={{
                fontSize: 13,
                fontWeight: 500,
                color: "var(--text-secondary)",
              }}
            >
              {r.label}
            </span>
          </button>
        ))}
        <div style={{ height: 16 }} />
      </div>
    </>
  );
}

/* ─── Sleep timer sheet ───────────────────────────────────────────────────── */
function TimerSheet({
  onClose,
  onSet,
}: {
  onClose: () => void;
  onSet: (m: number) => void;
}) {
  return (
    <>
      <div
        onClick={onClose}
        style={{
          position: "fixed",
          inset: 0,
          zIndex: 410,
          background: "rgba(0,0,0,0.55)",
          backdropFilter: "blur(10px)",
        }}
      />
      <div
        className="np-sheet"
        style={{
          animation: "npSlideUp 0.3s cubic-bezier(0.34,1.2,0.64,1) both",
        }}
      >
        <div
          style={{
            width: 40,
            height: 4,
            background: "var(--sheet-handle)",
            borderRadius: 2,
            margin: "0 auto 20px",
          }}
        />
        <p
          style={{
            fontSize: 14,
            fontWeight: 700,
            color: "var(--text-primary)",
            marginBottom: 16,
          }}
        >
          Sleep Timer
        </p>
        <div
          style={{
            display: "grid",
            gridTemplateColumns: "repeat(4,1fr)",
            gap: 8,
          }}
        >
          {TIMER_MINS.map((m) => (
            <button
              key={m}
              onClick={() => {
                onSet(m);
                onClose();
              }}
              style={{
                height: 40,
                borderRadius: 12,
                fontSize: 12,
                fontWeight: 600,
                background:
                  m === 0 ? "rgba(244,63,94,0.08)" : "var(--btn-ghost)",
                color: m === 0 ? "#f43f5e" : "var(--text-secondary)",
                border: `1px solid ${m === 0 ? "rgba(244,63,94,0.2)" : "var(--border)"}`,
                transition: "all 130ms ease",
              }}
            >
              {m === 0 ? "Off" : `${m}m`}
            </button>
          ))}
        </div>
        <div style={{ height: 16 }} />
      </div>
    </>
  );
}

/* ─── Right panel ─────────────────────────────────────────────────────────── */
const RTABS = ["Lyrics", "Up Next"] as const;
type RTab = (typeof RTABS)[number];

function RightPanel({
  track,
  queue,
  dispatch,
}: {
  track: MusicItem;
  queue: MusicItem[];
  dispatch: ReturnType<typeof useAppDispatch>;
}) {
  const [tab, setTab] = useState<RTab>("Lyrics");
  return (
    <aside className="np-right">
      <div className="np-right-tabs">
        {RTABS.map((t) => (
          <button
            key={t}
            onClick={() => setTab(t)}
            className={`np-rtab${tab === t ? " np-rtab-on" : ""}`}
          >
            {t}
          </button>
        ))}
      </div>
      <div className="np-right-body scrollbar-thin">
        {tab === "Lyrics" && (
          <div
            style={{
              display: "flex",
              flexDirection: "column",
              alignItems: "center",
              textAlign: "center",
              gap: 2,
            }}
          >
            {LYRICS.map((l, i) => (
              <p key={i} className={`np-lyr-line np-lyr-${l.state}`}>
                {l.line}
              </p>
            ))}
            <p
              style={{
                color: "var(--text-muted)",
                fontSize: 10,
                marginTop: 28,
                opacity: 0.6,
              }}
            >
              Synchronized Lyrics · Doliplay
            </p>
          </div>
        )}
        {tab === "Up Next" && (
          <div>
            <p
              style={{
                fontSize: 10,
                fontWeight: 600,
                letterSpacing: "0.1em",
                textTransform: "uppercase",
                color: "var(--text-muted)",
                marginBottom: 10,
              }}
            >
              Queue · {queue.length}
            </p>
            {queue.length === 0 ? (
              <p
                style={{
                  fontSize: 12,
                  color: "var(--text-muted)",
                  textAlign: "center",
                  paddingTop: 32,
                }}
              >
                Queue is empty
              </p>
            ) : (
              queue.map((t, i) => (
                <QueueRow
                  key={t.id}
                  track={t}
                  idx={i}
                  active={t.id === track.id}
                  onPlay={() => {
                    if (t.audioUrl?.trim()) dispatch(setTrack(t));
                  }}
                />
              ))
            )}
          </div>
        )}
      </div>
    </aside>
  );
}

/* ═══════════════════════════════════════════════════════════════════════════
   MAIN
═══════════════════════════════════════════════════════════════════════════ */
export default function NowPlayingModal() {
  const dispatch = useAppDispatch();
  const router = useRouter();
  const {
    currentTrack,
    queue,
    isPlaying,
    progress,
    volume,
    isShuffle,
    isRepeat,
  } = useAppSelector((s) => s.player);

  const [liked, setLiked] = useState(false);
  const [speed, setSpeed] = useState<SpeedValue>(1);
  const [actionsOpen, setActionsOpen] = useState(false);
  const [moreOpen, setMoreOpen] = useState(false);
  const [timerOpen, setTimerOpen] = useState(false);
  const [timerMins, setTimerMins] = useState(0);
  const [mobTab, setMobTab] = useState<"player" | "queue" | "lyrics">("player");
  const [isMobile, setIsMobile] = useState(true);
  const [isWide, setIsWide] = useState(false);
  const timerRef = useRef<ReturnType<typeof setTimeout> | null>(null);

  useEffect(() => {
    if (!currentTrack) router.replace("/");
  }, [currentTrack, router]);

  /* viewport size — drives conditional rendering of desktop panels */
  useEffect(() => {
    const mqMob  = window.matchMedia("(max-width:720px)");
    const mqWide = window.matchMedia("(min-width:1081px)");
    const update = () => { setIsMobile(mqMob.matches); setIsWide(mqWide.matches); };
    update();
    mqMob.addEventListener("change", update);
    mqWide.addEventListener("change", update);
    return () => { mqMob.removeEventListener("change", update); mqWide.removeEventListener("change", update); };
  }, []);

  /* keyboard shortcuts */
  useEffect(() => {
    const h = (e: KeyboardEvent) => {
      const t = (e.target as HTMLElement).tagName;
      if (t === "INPUT" || t === "TEXTAREA" || t === "SELECT") return;
      if (moreOpen || timerOpen || actionsOpen) return;
      switch (e.code) {
        case "Space":
          e.preventDefault();
          dispatch(togglePlay());
          break;
        case "ArrowRight": {
          const d = audioPlayer.audio.duration;
          if (d)
            audioPlayer.seek(Math.min(d, audioPlayer.audio.currentTime + 10));
          break;
        }
        case "ArrowLeft":
          audioPlayer.seek(Math.max(0, audioPlayer.audio.currentTime - 10));
          break;
        case "ArrowUp":
          e.preventDefault();
          dispatch(setVolume(Math.min(100, volume + 5)));
          break;
        case "ArrowDown":
          e.preventDefault();
          dispatch(setVolume(Math.max(0, volume - 5)));
          break;
        case "KeyN":
          dispatch(playNext());
          break;
        case "KeyP":
          dispatch(playPrev());
          break;
        case "KeyS":
          dispatch(toggleShuffle());
          break;
        case "KeyR":
          dispatch(toggleRepeat());
          break;
      }
    };
    window.addEventListener("keydown", h);
    return () => window.removeEventListener("keydown", h);
  }, [dispatch, volume, moreOpen, timerOpen, actionsOpen]);

  /* playback speed */
  useEffect(() => {
    audioPlayer.audio.playbackRate = speed;
  }, [speed]);

  /* sleep timer */
  const applySleepTimer = useCallback(
    (m: number) => {
      if (timerRef.current) clearTimeout(timerRef.current);
      setTimerMins(m);
      if (m > 0)
        timerRef.current = setTimeout(() => {
          dispatch(togglePlay());
          setTimerMins(0);
        }, m * 60_000);
    },
    [dispatch],
  );

  if (!currentTrack) return null;

  const img = currentTrack.thumbnail || currentTrack.landscapeImg || "";
  const handleVol = (v: number) => {
    dispatch(setVolume(v));
    audioPlayer.setVolume(v);
  };

  return (
    <>
      {/* ─── styles ─────────────────────────────────────────────────────── */}
      <style>{`
        @keyframes npEq        { 0%,100%{transform:scaleY(0.12)} 50%{transform:scaleY(1)} }
        @keyframes npGlow      { 0%,100%{opacity:.3} 50%{opacity:.6} }
        @keyframes npFloat     { 0%,100%{transform:translateY(0)} 50%{transform:translateY(-7px)} }
        @keyframes npVinyl     { from{transform:rotate(0deg)} to{transform:rotate(360deg)} }
        @keyframes npPulse     { 0%{transform:scale(1);opacity:.6} 100%{transform:scale(1.28);opacity:0} }
        @keyframes npIn        { from{opacity:0;transform:translateY(14px)} to{opacity:1;transform:translateY(0)} }
        @keyframes npFade      { from{opacity:0} to{opacity:1} }
        @keyframes npSlideUp   { from{transform:translateY(100%)} to{transform:translateY(0)} }

        /* root */
        .np-root { position:fixed;inset:0;z-index:100;overflow:hidden; }
        .np-bg   { position:absolute;inset:0;z-index:0;overflow:hidden; }

        .np-bg img {
          position:absolute;top:-25%;left:-25%;width:150%;height:150%;
          filter:blur(90px) saturate(130%) brightness(0.7);object-fit:cover;
        }
        .dark .np-bg img { filter:blur(90px) saturate(180%) brightness(0.1); }
        .np-bg-ov {
          position:absolute;inset:0;
          background:linear-gradient(145deg,rgba(255,253,250,0.91) 0%,rgba(248,250,255,0.88) 50%,rgba(255,253,250,0.91) 100%);
        }
        .dark .np-bg-ov {
          background:linear-gradient(145deg,rgba(8,8,22,0.97) 0%,rgba(12,18,38,0.93) 50%,rgba(8,8,22,0.97) 100%);
        }

        /* layout */
        .np-layout { position:relative;z-index:10;display:grid;grid-template-columns:272px 1fr 300px;height:100vh;overflow:hidden; }
        @media(max-width:1080px){ .np-layout{grid-template-columns:248px 1fr;} .np-right{display:none;} }
        @media(max-width:720px)  { .np-layout{grid-template-columns:1fr;} .np-left{display:none;} }

        /* left panel */
        .np-left { border-right:1px solid var(--border-soft);overflow-y:auto;display:flex;flex-direction:column;scrollbar-width:none;animation:npFade .4s ease both; }
        .np-left::-webkit-scrollbar{display:none;}
        .np-back-btn { display:flex;align-items:center;gap:8px;padding:10px 16px;color:var(--text-muted);font-size:12px;font-weight:600;width:100%;transition:color 140ms ease;border-radius:0; }
        .np-back-btn:hover{color:var(--text-primary);}
        .np-section-label { font-size:9.5px;font-weight:700;letter-spacing:.14em;text-transform:uppercase;color:var(--text-muted);padding:14px 18px 6px; }
        .np-current-card { padding:8px 18px 14px; }
        .np-current-card p { font-size:12px;font-weight:600;color:var(--text-primary);line-height:1.4; }
        .np-current-card span { font-size:11px;color:var(--text-muted); }
        .np-divider { height:1px;background:var(--border-soft);margin:6px 14px; }

        /* queue rows */
        .np-q-row { display:grid;grid-template-columns:20px 36px 1fr auto;align-items:center;gap:10px;padding:7px 16px;width:100%;text-align:left;border-left:3px solid transparent;transition:background 120ms ease; }
        .np-q-row:hover { background:var(--btn-ghost-hover); }
        .np-q-row-active { background:rgba(var(--accent-rgb),.07);border-left-color:var(--accent); }
        .np-q-art { width:36px;height:36px;border-radius:5px;overflow:hidden;position:relative;background:var(--card);flex-shrink:0; }
        .np-q-name { font-size:11.5px;font-weight:500;color:var(--text-secondary);overflow:hidden;text-overflow:ellipsis;white-space:nowrap; }
        .np-q-name-on { color:var(--accent); }
        .np-q-artist { font-size:10px;color:var(--text-muted);overflow:hidden;text-overflow:ellipsis;white-space:nowrap;margin-top:1px; }
        .np-q-num { display:flex;align-items:center;justify-content:center;min-width:20px; }
        .np-q-dur { font-size:10px;color:var(--text-muted);white-space:nowrap;font-variant-numeric:tabular-nums; }

        /* center */
        .np-center { overflow-y:auto;display:flex;flex-direction:column;align-items:center;justify-content:center;scrollbar-width:none;padding-bottom:24px; }
        .np-center::-webkit-scrollbar{display:none;}
        .np-player { width:100%;max-width:400px;padding:36px 28px 32px;display:flex;flex-direction:column;align-items:center;animation:npIn .5s ease both; }
        @media(max-width:720px){ .np-player{max-width:100%;padding:64px 22px calc(env(safe-area-inset-bottom,0px) + 74px);} }

        /* art */
        .np-art-wrap  { position:relative;width:256px;height:256px;margin:0 auto; }
        @media(max-width:720px){ .np-art-wrap{width:min(60vw,220px);height:min(60vw,220px);} }
        .np-art-float { width:100%;height:100%;animation:npFloat 5.5s ease-in-out infinite; }
        .np-art-glow  { position:absolute;inset:-24px;border-radius:50%;filter:blur(44px);background:var(--accent);opacity:.2;pointer-events:none;animation:npGlow 3.5s ease-in-out infinite;transition:opacity .5s ease; }
        .dark .np-art-glow  { opacity:.35; }
        .np-art-glow.on { opacity:.4; }
        .dark .np-art-glow.on { opacity:.65; }

        .np-art-disc  { width:100%;height:100%;border-radius:50%;overflow:hidden;position:relative;background:linear-gradient(135deg,#eaeaf2,#d8d8e8);box-shadow:0 16px 52px rgba(0,0,0,.14),0 4px 16px rgba(0,0,0,.08); }
        .dark .np-art-disc  { background:linear-gradient(135deg,#12122a,#0b1a30);box-shadow:0 12px 48px rgba(0,0,0,.65); }
        .np-art-disc.spin { animation:npVinyl 14s linear infinite; }
        .np-art-center{ position:absolute;inset:0;display:flex;align-items:center;justify-content:center;pointer-events:none;z-index:2; }
        .np-art-center::after { content:'';width:22px;height:22px;border-radius:50%;background:#f0f0f5;box-shadow:0 0 0 1px rgba(0,0,0,0.12),0 0 0 3px rgba(0,0,0,.05);display:block; }
        .dark .np-art-center::after { background:#0b0b1a;box-shadow:0 0 0 1px rgba(255,255,255,0.06),0 0 0 2px rgba(0,0,0,.4); }
        .np-art-note  { position:absolute;inset:0;display:flex;align-items:center;justify-content:center;font-size:56px;color:var(--text-muted); }

        /* meta */
        .np-meta { margin-top:26px;text-align:center;width:100%; }
        .np-meta-title  { font-size:21px;font-weight:700;color:var(--text-primary);letter-spacing:-.025em;line-height:1.25; }
        @media(max-width:480px){ .np-meta-title{font-size:18px;} }
        .np-meta-artist { font-size:13px;color:var(--text-muted);margin-top:5px; }
        .np-meta-acts   { display:flex;align-items:center;justify-content:center;gap:14px;margin-top:14px; }
        .np-act-btn { width:30px;height:30px;display:flex;align-items:center;justify-content:center;border-radius:50%;color:var(--text-muted);transition:all 150ms ease; }
        .np-act-btn:hover { color:var(--text-primary);transform:scale(1.12); }
        .np-act-btn.liked { color:var(--accent); }
        @media(max-width:720px){ .np-act-btn{width:44px;height:44px;} }

        /* seek */
        .np-seek-track { height:4px;background:var(--btn-ghost-hover);border-radius:2px;position:relative;transition:height 140ms ease;overflow:visible; }
        .np-seek-track:hover { height:6px; }
        @media(max-width:720px){ .np-seek-track{height:5px;} .np-seek-track:hover{height:5px;} }
        .np-seek-fill  { height:100%;background:var(--accent);border-radius:2px;position:relative;pointer-events:none; }
        .np-seek-thumb { position:absolute;right:-7px;top:50%;transform:translateY(-50%) scale(0);width:14px;height:14px;border-radius:50%;background:var(--text-primary);box-shadow:0 2px 8px rgba(0,0,0,.18);transition:transform 140ms ease;pointer-events:none; }
        .np-seek-track:hover .np-seek-thumb, .np-seek-thumb-vis { transform:translateY(-50%) scale(1)!important; }
        @media(max-width:720px){ .np-seek-thumb{transform:translateY(-50%) scale(1)!important;width:16px;height:16px;right:-8px;} }
        .np-seek-times { display:flex;justify-content:space-between;margin-top:5px;font-size:10px;color:var(--text-muted);font-variant-numeric:tabular-nums; }

        /* controls */
        .np-controls { display:flex;align-items:center;justify-content:center;gap:20px;margin-top:18px; }
        @media(max-width:720px){ .np-controls{gap:8px;margin-top:22px;} }
        .np-ctrl { display:flex;align-items:center;justify-content:center;padding:7px;border-radius:9px;color:var(--text-muted);transition:all 140ms ease; }
        .np-ctrl:hover  { color:var(--text-primary);background:var(--btn-ghost-hover); }
        @media(max-width:720px){ .np-ctrl{padding:11px;} }
        .np-ctrl.on     { color:var(--accent); }
        .np-ctrl.dim    { color:var(--border); }
        .dark .np-ctrl.dim { color:#3a3a4a; }
        .np-play { position:relative;width:56px;height:56px;border-radius:50%;background:var(--accent);display:flex;align-items:center;justify-content:center;box-shadow:0 8px 24px rgba(var(--accent-rgb),.32);transition:transform 140ms ease,box-shadow 140ms ease; }
        .np-play:hover  { transform:scale(1.07);box-shadow:0 12px 32px rgba(var(--accent-rgb),.48); }
        @media(max-width:720px){ .np-play{width:64px;height:64px;} }
        .np-play.on::after { content:'';position:absolute;inset:-6px;border-radius:50%;border:1.5px solid rgba(var(--accent-rgb),.45);animation:npPulse 2s ease-out infinite;pointer-events:none; }

        /* secondary */
        .np-secondary { display:flex;align-items:center;justify-content:space-between;width:100%;margin-top:14px;gap:10px; }
        @media(max-width:720px){ .np-secondary{justify-content:center;gap:8px;margin-top:20px;} }
        .np-vol-wrapper { display:flex;align-items:center;gap:8px;flex:1;min-width:0; }
        @media(max-width:720px){ .np-vol-wrapper{display:none;} }
        .np-vol-track { flex:1;height:3px;background:var(--btn-ghost-hover);border-radius:2px;cursor:pointer;position:relative;transition:height 140ms ease;min-width:0; }
        .np-vol-track:hover { height:5px; }
        .np-vol-fill  { height:100%;background:var(--text-secondary);border-radius:2px;pointer-events:none; }
        .np-icon-btn  { display:flex;align-items:center;justify-content:center;color:var(--text-muted);transition:color 140ms ease;cursor:pointer; }
        .np-icon-btn:hover { color:var(--text-primary); }

        /* speed */
        .np-speed { display:flex;align-items:center;gap:2px;background:var(--btn-ghost);border-radius:8px;padding:3px; }
        .np-spd   { font-size:9.5px;font-weight:700;color:var(--text-muted);padding:3px 6px;border-radius:6px;transition:all 120ms ease;cursor:pointer; }
        .np-spd:hover { color:var(--text-secondary); }
        .np-spd.on { background:rgba(var(--accent-rgb),.14);color:var(--accent); }
        @media(max-width:720px){ .np-spd{padding:4px 5px;font-size:9px;} }

        /* keyboard hint */
        .np-kbd-hint { font-size:9.5px;color:var(--text-muted);text-align:center;margin-top:18px;letter-spacing:.03em;opacity:0.5; }
        @media(max-width:720px){ .np-kbd-hint{display:none;} }

        /* right panel */
        .np-right { border-left:1px solid var(--border-soft);display:flex;flex-direction:column;overflow:hidden;animation:npFade .45s ease .1s both; }
        .np-right-tabs { display:flex;padding:0 18px;border-bottom:1px solid var(--border-soft);flex-shrink:0; }
        .np-rtab { font-size:12px;font-weight:500;color:var(--text-muted);padding:13px 14px 12px;border-bottom:2px solid transparent;transition:color 140ms ease,border-color 140ms ease; }
        .np-rtab:hover { color:var(--text-secondary); }
        .np-rtab.np-rtab-on { color:var(--text-primary);border-bottom-color:var(--accent); }
        .np-right-body { flex:1;overflow-y:auto;padding:20px 18px; }

        /* lyrics */
        .np-lyr-line  { font-size:14px;line-height:1.65;padding:3px 0;transition:all 240ms ease; }
        .np-lyr-past  { color:var(--border); }
        .dark .np-lyr-past { color:#3a3a4a; }
        .np-lyr-future{ color:var(--text-muted); }
        .np-lyr-current{ color:var(--accent);font-size:17px;font-weight:600; }

        /* bottom sheet */
        .np-sheet { position:fixed;bottom:0;left:0;right:0;z-index:420;max-width:500px;margin:0 auto;border-radius:20px 20px 0 0;background:var(--sheet-bg);border:1px solid var(--sheet-border);border-bottom:none;padding:20px 20px 0; }
        .np-sheet-row { display:flex;align-items:center;gap:14px;padding:12px 4px;width:100%;text-align:left;transition:background 120ms ease;border-radius:8px; }
        .np-sheet-row:hover { background:var(--btn-ghost-hover); }
        .np-sheet-icon { width:32px;height:32px;border-radius:50%;background:var(--btn-ghost);display:flex;align-items:center;justify-content:center;font-size:13px;flex-shrink:0; }

        /* ── MOBILE TOP BAR ───────────────────────────────────────────────── */
        .np-topbar { position:fixed;top:0;left:0;right:0;z-index:20;height:56px;display:none;align-items:center;justify-content:space-between;padding:0 8px; }
        @media(max-width:720px){ .np-topbar{display:flex;} }
        .np-topbar-btn { width:44px;height:44px;border-radius:50%;background:rgba(var(--accent-rgb),0.07);display:flex;align-items:center;justify-content:center;color:var(--text-secondary);transition:background 140ms ease,color 140ms ease;flex-shrink:0;-webkit-tap-highlight-color:transparent; }
        .np-topbar-btn:active { background:var(--btn-ghost-hover);color:var(--text-primary); }
        .np-topbar-center { display:flex;flex-direction:column;align-items:center;gap:2px;overflow:hidden; }
        .np-topbar-eyebrow { font-size:9px;font-weight:700;letter-spacing:.14em;text-transform:uppercase;color:var(--text-muted);opacity:0.7; }
        .np-topbar-track { font-size:12px;font-weight:600;color:var(--text-primary);max-width:160px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap; }

        /* ── MOBILE OVERLAY PANELS ───────────────────────────────────────── */
        .np-mob-panel {
          display:none;
          position:fixed;
          top:56px;
          bottom:calc(56px + env(safe-area-inset-bottom,0px));
          left:0;right:0;
          z-index:25;
          overflow-y:auto;
          scrollbar-width:none;
          -webkit-overflow-scrolling:touch;
          background:rgba(248,248,252,0.96);
          backdrop-filter:blur(20px);
          -webkit-backdrop-filter:blur(20px);
        }
        .dark .np-mob-panel {
          background:rgba(8,8,22,0.97);
        }
        .np-mob-panel::-webkit-scrollbar { display:none; }
        @media(max-width:720px){ .np-mob-panel.np-mob-visible { display:block; } }
        .np-mob-q-row { display:grid;grid-template-columns:20px 44px 1fr auto;align-items:center;gap:10px;padding:10px 20px;width:100%;text-align:left;border-left:3px solid transparent;transition:background 120ms ease;-webkit-tap-highlight-color:transparent; }
        .np-mob-q-row:active { background:var(--btn-ghost-hover); }
        .np-mob-q-row-active { border-left-color:var(--accent);background:rgba(var(--accent-rgb),.06); }

        /* ── MOBILE TAB BAR ──────────────────────────────────────────────── */
        .np-mobtabs {
          display:none;
          position:fixed;
          bottom:0;left:0;right:0;
          z-index:30;
          background:var(--bg);
          backdrop-filter:blur(24px);
          -webkit-backdrop-filter:blur(24px);
          border-top:1px solid var(--border-soft);
          height:calc(56px + env(safe-area-inset-bottom,0px));
          padding-bottom:env(safe-area-inset-bottom,0px);
        }
        @media(max-width:720px){ .np-mobtabs{display:flex;align-items:stretch;} }
        .np-mobtab {
          flex:1;display:flex;flex-direction:column;align-items:center;justify-content:center;
          gap:4px;padding:0;
          font-size:9px;font-weight:700;letter-spacing:.05em;text-transform:uppercase;
          color:var(--text-muted);transition:color 140ms ease;
          -webkit-tap-highlight-color:transparent;
        }
        .np-mobtab.on { color:var(--accent); }
        .np-mobtab:active { opacity:0.65; }
      `}</style>

      <div className="np-root">
        {/* ambient bg */}
        <div className="np-bg">
          {img && <img src={img} alt="" aria-hidden />}
          <div className="np-bg-ov" />
        </div>

        <div
          className="np-layout"
          style={{
            gridTemplateColumns: isMobile
              ? "1fr"
              : isWide
                ? "272px 1fr 300px"
                : "248px 1fr",
          }}
        >
          {/* ── LEFT: Queue — desktop only (JS-driven, reliable on all viewports) ── */}
          {!isMobile && (
            <div className="np-left">
              <div style={{ padding: "20px 0 8px" }}>
                <button className="np-back-btn" onClick={() => router.back()}>
                  <svg
                    width="15"
                    height="15"
                    viewBox="0 0 24 24"
                    fill="none"
                    stroke="currentColor"
                    strokeWidth="2.2"
                    strokeLinecap="round"
                    strokeLinejoin="round"
                  >
                    <polyline points="15 18 9 12 15 6" />
                  </svg>
                  Back
                </button>
              </div>

              <div className="np-divider" />
              <div className="np-section-label">Now Playing</div>
              <div className="np-current-card">
                <p className="line-clamp-2">{currentTrack.title}</p>
                <span>{currentTrack.channelName}</span>
              </div>

              <div className="np-divider" />
              <div className="np-section-label">Queue · {queue.length}</div>

              <div style={{ flex: 1, paddingBottom: 24 }}>
                {queue.length === 0 ? (
                  <p
                    style={{
                      fontSize: 11,
                      color: "var(--text-muted)",
                      padding: "12px 18px",
                    }}
                  >
                    Queue is empty
                  </p>
                ) : (
                  queue.map((t, i) => (
                    <QueueRow
                      key={t.id}
                      track={t}
                      idx={i}
                      active={t.id === currentTrack.id}
                      onPlay={() => {
                        if (t.audioUrl?.trim()) dispatch(setTrack(t));
                      }}
                    />
                  ))
                )}
              </div>
            </div>
          )}

          {/* ── CENTER: Player ── */}
          <div className="np-center">
            <div className="np-player">
              {/* Album art */}
              <div className="np-art-wrap">
                <div className="np-art-float">
                  <div className={`np-art-glow${isPlaying ? " on" : ""}`} />
                  <div className={`np-art-disc${isPlaying ? " spin" : ""}`}>
                    {img ? (
                      <img
                        src={img}
                        alt={currentTrack.title}
                        style={{
                          position: "absolute",
                          inset: 0,
                          width: "100%",
                          height: "100%",
                          objectFit: "cover",
                        }}
                      />
                    ) : (
                      <div className="np-art-note">♪</div>
                    )}
                    <div className="np-art-center" />
                  </div>
                </div>
              </div>

              {/* Meta */}
              <div className="np-meta">
                <p className="np-meta-title line-clamp-2">
                  {currentTrack.title}
                </p>
                <p className="np-meta-artist">
                  {currentTrack.channelName || "Unknown Artist"}
                </p>
                <div className="np-meta-acts">
                  <button
                    className={`np-act-btn${liked ? " liked" : ""}`}
                    onClick={() => setLiked((p) => !p)}
                    title={liked ? "Unlike" : "Like"}
                  >
                    <svg
                      width="19"
                      height="19"
                      viewBox="0 0 24 24"
                      fill={liked ? "currentColor" : "none"}
                      stroke="currentColor"
                      strokeWidth="1.8"
                      strokeLinecap="round"
                      strokeLinejoin="round"
                    >
                      <path d="M20.84 4.61a5.5 5.5 0 0 0-7.78 0L12 5.67l-1.06-1.06a5.5 5.5 0 0 0-7.78 7.78l1.06 1.06L12 21.23l7.78-7.78 1.06-1.06a5.5 5.5 0 0 0 0-7.78z" />
                    </svg>
                  </button>
                  <button className="np-act-btn" title="Share">
                    <svg
                      width="17"
                      height="17"
                      viewBox="0 0 24 24"
                      fill="none"
                      stroke="currentColor"
                      strokeWidth="1.8"
                      strokeLinecap="round"
                      strokeLinejoin="round"
                    >
                      <circle cx="18" cy="5" r="3" />
                      <circle cx="6" cy="12" r="3" />
                      <circle cx="18" cy="19" r="3" />
                      <line x1="8.59" y1="13.51" x2="15.42" y2="17.49" />
                      <line x1="15.41" y1="6.51" x2="8.59" y2="10.49" />
                    </svg>
                  </button>
                  <button
                    className="np-act-btn"
                    title="More options"
                    onClick={() => setMoreOpen(true)}
                  >
                    <svg
                      width="17"
                      height="17"
                      viewBox="0 0 24 24"
                      fill="currentColor"
                    >
                      <circle cx="5" cy="12" r="2" />
                      <circle cx="12" cy="12" r="2" />
                      <circle cx="19" cy="12" r="2" />
                    </svg>
                  </button>
                </div>
              </div>

              {/* Seek */}
              <div style={{ width: "100%", marginTop: 22 }}>
                <SeekBar progress={progress} dispatch={dispatch} />
                <div className="np-seek-times">
                  <span>{currentTime(progress)}</span>
                  <span>{totalDur()}</span>
                </div>
              </div>

              {/* Main controls */}
              <div className="np-controls">
                <button
                  className={`np-ctrl${isShuffle ? " on" : " dim"}`}
                  onClick={() => dispatch(toggleShuffle())}
                  title="Shuffle (S)"
                >
                  <svg
                    width="19"
                    height="19"
                    viewBox="0 0 24 24"
                    fill="none"
                    stroke="currentColor"
                    strokeWidth="1.8"
                    strokeLinecap="round"
                    strokeLinejoin="round"
                  >
                    <polyline points="16 3 21 3 21 8" />
                    <line x1="4" y1="20" x2="21" y2="3" />
                    <polyline points="21 16 21 21 16 21" />
                    <line x1="15" y1="15" x2="21" y2="21" />
                    <line x1="4" y1="4" x2="9" y2="9" />
                  </svg>
                </button>

                <button
                  className="np-ctrl"
                  onClick={() => dispatch(playPrev())}
                  title="Previous (P)"
                >
                  <svg
                    width="24"
                    height="24"
                    viewBox="0 0 24 24"
                    fill="currentColor"
                  >
                    <polygon points="19 20 9 12 19 4 19 20" />
                    <rect x="5" y="5" width="2.5" height="14" rx="1.25" />
                  </svg>
                </button>

                <button
                  className={`np-play${isPlaying ? " on" : ""}`}
                  onClick={() => dispatch(togglePlay())}
                  title="Play/Pause (Space)"
                >
                  {isPlaying ? (
                    <svg width="21" height="21" viewBox="0 0 24 24" fill="#fff">
                      <rect x="5" y="4" width="4.5" height="16" rx="1.5" />
                      <rect x="14.5" y="4" width="4.5" height="16" rx="1.5" />
                    </svg>
                  ) : (
                    <svg
                      width="21"
                      height="21"
                      viewBox="0 0 24 24"
                      fill="#fff"
                      style={{ marginLeft: 3 }}
                    >
                      <polygon points="6 4 20 12 6 20 6 4" />
                    </svg>
                  )}
                </button>

                <button
                  className="np-ctrl"
                  onClick={() => {
                    dispatch(setRepeat(false));
                    dispatch(playNext());
                  }}
                  title="Next (N)"
                >
                  <svg
                    width="24"
                    height="24"
                    viewBox="0 0 24 24"
                    fill="currentColor"
                  >
                    <polygon points="5 4 15 12 5 20 5 4" />
                    <rect x="16.5" y="5" width="2.5" height="14" rx="1.25" />
                  </svg>
                </button>

                <button
                  className={`np-ctrl${isRepeat ? " on" : " dim"}`}
                  onClick={() => dispatch(toggleRepeat())}
                  title="Repeat (R)"
                >
                  <svg
                    width="19"
                    height="19"
                    viewBox="0 0 24 24"
                    fill="none"
                    stroke="currentColor"
                    strokeWidth="1.8"
                    strokeLinecap="round"
                    strokeLinejoin="round"
                  >
                    <polyline points="17 1 21 5 17 9" />
                    <path d="M3 11V9a4 4 0 0 1 4-4h14" />
                    <polyline points="7 23 3 19 7 15" />
                    <path d="M21 13v2a4 4 0 0 1-4 4H3" />
                  </svg>
                </button>
              </div>

              {/* Secondary: volume + speed + timer badge */}
              <div className="np-secondary">
                <div className="np-vol-wrapper">
                  <VolumeSlider volume={volume} onChange={handleVol} />
                </div>
                <div className="np-speed">
                  {SPEED_OPTIONS.map((s) => (
                    <button
                      key={s}
                      className={`np-spd${speed === s ? " on" : ""}`}
                      onClick={() => setSpeed(s)}
                    >
                      {s === 1 ? "1×" : `${s}×`}
                    </button>
                  ))}
                </div>
                {timerMins > 0 && (
                  <button
                    onClick={() => applySleepTimer(0)}
                    title="Cancel sleep timer"
                    style={{
                      fontSize: 10,
                      fontWeight: 700,
                      padding: "3px 8px",
                      borderRadius: 8,
                      background: "rgba(var(--accent-rgb),.1)",
                      color: "var(--accent)",
                      flexShrink: 0,
                    }}
                  >
                    ⏱ {timerMins}m
                  </button>
                )}
              </div>

              {/* Keyboard hint — hidden on mobile via CSS */}
              <p className="np-kbd-hint">
                Space · ← → seek · ↑ ↓ vol · N P S R
              </p>
            </div>
          </div>

          {/* ── RIGHT: Lyrics / Up Next — wide desktop only ── */}
          {!isMobile && isWide && (
            <RightPanel track={currentTrack} queue={queue} dispatch={dispatch} />
          )}
        </div>

        {/* ── MOBILE-ONLY ELEMENTS (JS-driven, reliable across all viewports) ── */}
        {isMobile && (
          <>
            {/* Top bar */}
            <div className="np-topbar" style={{ display: "flex" }}>
              <button onClick={() => router.back()} className="np-topbar-btn">
                <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.2" strokeLinecap="round" strokeLinejoin="round">
                  <polyline points="15 18 9 12 15 6" />
                </svg>
              </button>
              <div className="np-topbar-center">
                <span className="np-topbar-eyebrow">Now Playing</span>
                <span className="np-topbar-track">{currentTrack.title}</span>
              </div>
              <button onClick={() => setMoreOpen(true)} className="np-topbar-btn">
                <svg width="17" height="17" viewBox="0 0 24 24" fill="currentColor">
                  <circle cx="5" cy="12" r="2" />
                  <circle cx="12" cy="12" r="2" />
                  <circle cx="19" cy="12" r="2" />
                </svg>
              </button>
            </div>

            {/* Queue overlay */}
            {mobTab === "queue" && (
              <div className="np-mob-panel np-mob-visible">
                <div style={{ padding: "16px 20px 6px", position: "sticky", top: 0, zIndex: 1 }}>
                  <p style={{ fontSize: "9.5px", fontWeight: 700, letterSpacing: ".14em", textTransform: "uppercase", color: "var(--text-muted)" }}>
                    Queue · {queue.length}
                  </p>
                </div>
                {queue.length === 0 ? (
                  <p style={{ fontSize: 12, color: "var(--text-muted)", textAlign: "center", padding: "32px 20px" }}>Queue is empty</p>
                ) : (
                  queue.map((t, i) => (
                    <QueueRow
                      key={t.id}
                      track={t}
                      idx={i}
                      active={t.id === currentTrack.id}
                      onPlay={() => {
                        if (t.audioUrl?.trim()) { dispatch(setTrack(t)); setMobTab("player"); }
                      }}
                    />
                  ))
                )}
              </div>
            )}

            {/* Lyrics overlay */}
            {mobTab === "lyrics" && (
              <div className="np-mob-panel np-mob-visible">
                <div style={{ padding: "24px 28px 28px", display: "flex", flexDirection: "column", alignItems: "center", textAlign: "center", gap: 2 }}>
                  {LYRICS.map((l, i) => (
                    <p key={i} className={`np-lyr-line np-lyr-${l.state}`}>{l.line}</p>
                  ))}
                  <p style={{ color: "var(--text-muted)", fontSize: 10, marginTop: 28, opacity: 0.5 }}>
                    Synchronized Lyrics · Doliplay
                  </p>
                </div>
              </div>
            )}

            {/* Bottom tab bar */}
            <div className="np-mobtabs" style={{ display: "flex" }}>
          <button
            className={`np-mobtab${mobTab === "player" ? " on" : ""}`}
            onClick={() => setMobTab("player")}
          >
            <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round">
              <path d="M9 18V5l12-2v13" />
              <circle cx="6" cy="18" r="3" />
              <circle cx="18" cy="16" r="3" />
            </svg>
            Player
          </button>
          <button
            className={`np-mobtab${mobTab === "queue" ? " on" : ""}`}
            onClick={() => setMobTab("queue")}
          >
            <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round">
              <line x1="8" y1="6" x2="21" y2="6" />
              <line x1="8" y1="12" x2="21" y2="12" />
              <line x1="8" y1="18" x2="21" y2="18" />
              <line x1="3" y1="6" x2="3.01" y2="6" />
              <line x1="3" y1="12" x2="3.01" y2="12" />
              <line x1="3" y1="18" x2="3.01" y2="18" />
            </svg>
            Queue
          </button>
          <button
            className={`np-mobtab${mobTab === "lyrics" ? " on" : ""}`}
            onClick={() => setMobTab("lyrics")}
          >
            <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round">
              <path d="M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z" />
            </svg>
            Lyrics
          </button>
          <button className="np-mobtab" onClick={() => setMoreOpen(true)}>
            <svg width="16" height="16" viewBox="0 0 24 24" fill="currentColor">
              <circle cx="5" cy="12" r="1.8" />
              <circle cx="12" cy="12" r="1.8" />
              <circle cx="19" cy="12" r="1.8" />
            </svg>
            More
          </button>
        </div>
          </>
        )}
      </div>

      {/* overlays */}
      {moreOpen && (
        <MoreSheet
          track={currentTrack}
          onClose={() => setMoreOpen(false)}
          onTimer={() => {
            setMoreOpen(false);
            setTimerOpen(true);
          }}
          onActions={() => {
            setMoreOpen(false);
            setActionsOpen(true);
          }}
        />
      )}
      {timerOpen && (
        <TimerSheet
          onClose={() => setTimerOpen(false)}
          onSet={applySleepTimer}
        />
      )}
      {actionsOpen && (
        <ContentActionsModal
          context={{
            contentId: currentTrack.id,
            contentType: currentTrack.contentType ?? CT.MUSIC,
            channelId: currentTrack.channelId ?? "",
            channelUserId: currentTrack.channelUserId ?? "",
            title: currentTrack.title,
            thumbnail: currentTrack.thumbnail,
            channelName: currentTrack.channelName,
          }}
          onClose={() => setActionsOpen(false)}
        />
      )}
    </>
  );
}
