/* Shared visual components for InsideJams · used by landing, gift page, etc. */

// Pseudo-random but stable
const seededRandom = (seed) => {
  let s = seed;
  return () => {
    s = (s * 9301 + 49297) % 233280;
    return s / 233280;
  };
};

// Static waveform
function Waveform({ seed = 7, count = 56, height = 38, color = "currentColor", progress = 0 }) {
  const rand = React.useMemo(() => {
    const r = seededRandom(seed);
    return Array.from({ length: count }, (_, i) => {
      // Smooth-ish envelope: peak in middle
      const env = Math.sin((i / count) * Math.PI);
      const noise = 0.45 + r() * 0.55;
      return Math.max(0.18, env * 0.55 + noise * 0.55);
    });
  }, [seed, count]);

  return (
    <div className="waveform" style={{ height, color }}>
      {rand.map((v, i) => {
        const active = i / count <= progress;
        return (
          <div
            key={i}
            className="bar"
            style={{
              height: `${v * 100}%`,
              opacity: active ? 1 : 0.32,
            }}
          />
        );
      })}
    </div>
  );
}

// Simulated audio player. No real audio · fake progress on play.
function AudioPlayer({ title, artist, duration = 52, accent = "var(--tangerine)", seed = 3, compact = false }) {
  const [playing, setPlaying] = React.useState(false);
  const [t, setT] = React.useState(0);
  React.useEffect(() => {
    if (!playing) return;
    const id = setInterval(() => {
      setT(prev => {
        if (prev >= duration) { setPlaying(false); return 0; }
        return prev + 0.1;
      });
    }, 100);
    return () => clearInterval(id);
  }, [playing, duration]);

  const fmt = (s) => {
    const m = Math.floor(s/60), r = Math.floor(s%60);
    return `${m}:${String(r).padStart(2,"0")}`;
  };
  const progress = t / duration;

  return (
    <div style={{
      display: "flex",
      alignItems: "center",
      gap: compact ? 12 : 16,
      padding: compact ? "10px 14px" : "16px 18px",
      border: "1.5px solid var(--line-strong)",
      borderRadius: 999,
      background: "var(--paper-2)",
    }}>
      <button
        onClick={() => setPlaying(!playing)}
        aria-label={playing ? "Pause" : "Play"}
        style={{
          width: compact ? 36 : 46, height: compact ? 36 : 46,
          borderRadius: "50%",
          border: "none",
          background: accent,
          color: "#fff",
          cursor: "pointer",
          display: "grid",
          placeItems: "center",
          flexShrink: 0,
        }}
      >
        {playing ? (
          <svg width="14" height="14" viewBox="0 0 14 14"><rect x="2" y="1.5" width="3.5" height="11" rx="1" fill="currentColor"/><rect x="8.5" y="1.5" width="3.5" height="11" rx="1" fill="currentColor"/></svg>
        ) : (
          <svg width="14" height="14" viewBox="0 0 14 14"><path d="M3 1.5 L12 7 L3 12.5 Z" fill="currentColor"/></svg>
        )}
      </button>
      {!compact && title && (
        <div style={{ minWidth: 0, flexShrink: 0, maxWidth: 180 }}>
          <div style={{ fontWeight: 600, fontSize: 14, overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap" }}>{title}</div>
          {artist && <div style={{ fontSize: 12, opacity: 0.6, overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap" }}>{artist}</div>}
        </div>
      )}
      <div style={{ flex: 1, minWidth: 60 }}>
        <Waveform seed={seed} count={compact ? 36 : 48} height={compact ? 26 : 34} progress={progress} color={accent} />
      </div>
      <div style={{ fontFamily: "var(--f-mono)", fontSize: 11, opacity: 0.7, minWidth: 70, textAlign: "right" }}>
        {fmt(t)} / {fmt(duration)}
      </div>
    </div>
  );
}

// === Cover Art Templates ===
// Each takes { recipient, title, accent, mood }
function CoverBoldColorful({ recipient, title, w = 360 }) {
  const h = w;
  return (
    <svg viewBox={`0 0 ${w} ${h}`} width="100%" style={{ display: "block", borderRadius: 8 }}>
      <rect width={w} height={h} fill="#FF5C39"/>
      <rect x={w*0.08} y={h*0.08} width={w*0.84} height={h*0.4} fill="#FFD23F"/>
      <circle cx={w*0.72} cy={h*0.32} r={w*0.18} fill="#0E0E0E"/>
      <circle cx={w*0.72} cy={h*0.32} r={w*0.05} fill="#FFD23F"/>
      <text x={w*0.08} y={h*0.62} fontFamily="Fraunces, serif" fontWeight="700" fontSize={w*0.11} fill="#0E0E0E" letterSpacing="-1">FOR</text>
      <text x={w*0.08} y={h*0.76} fontFamily="Fraunces, serif" fontStyle="italic" fontWeight="500" fontSize={w*0.16} fill="#0E0E0E" letterSpacing="-2">{recipient}</text>
      <text x={w*0.08} y={h*0.92} fontFamily="JetBrains Mono, monospace" fontSize={w*0.038} fill="#0E0E0E" letterSpacing="2">{(title || "").toUpperCase().slice(0,28)}</text>
    </svg>
  );
}
function CoverRetro({ recipient, title, w = 360 }) {
  const h = w;
  return (
    <svg viewBox={`0 0 ${w} ${h}`} width="100%" style={{ display: "block", borderRadius: 8 }}>
      <rect width={w} height={h} fill="#F5E9D7"/>
      <rect x="0" y="0" width={w} height={h*0.55} fill="#1B1B1B"/>
      <circle cx={w*0.5} cy={h*0.32} r={w*0.22} fill="#0E0E0E" stroke="#F5E9D7" strokeWidth="1"/>
      <circle cx={w*0.5} cy={h*0.32} r={w*0.16} fill="none" stroke="#F5E9D7" strokeWidth="0.5" opacity="0.4"/>
      <circle cx={w*0.5} cy={h*0.32} r={w*0.10} fill="none" stroke="#F5E9D7" strokeWidth="0.5" opacity="0.4"/>
      <circle cx={w*0.5} cy={h*0.32} r={w*0.05} fill="#FF5C39"/>
      <text x={w*0.5} y={h*0.7} textAnchor="middle" fontFamily="Fraunces, serif" fontWeight="600" fontStyle="italic" fontSize={w*0.13} fill="#1B1B1B">{recipient}</text>
      <line x1={w*0.2} y1={h*0.78} x2={w*0.8} y2={h*0.78} stroke="#1B1B1B" strokeWidth="1"/>
      <text x={w*0.5} y={h*0.88} textAnchor="middle" fontFamily="JetBrains Mono, monospace" fontSize={w*0.034} fill="#1B1B1B" letterSpacing="3">{(title || "").toUpperCase().slice(0,24)}</text>
    </svg>
  );
}
function CoverChaos({ recipient, title, w = 360 }) {
  const h = w;
  return (
    <svg viewBox={`0 0 ${w} ${h}`} width="100%" style={{ display: "block", borderRadius: 8 }}>
      <rect width={w} height={h} fill="#FFD23F"/>
      {[...Array(40)].map((_, i) => {
        const r = (i * 9301) % 233;
        const x = (r * 13) % w;
        const y = ((r + 50) * 7) % h;
        const sz = 4 + (r % 8);
        const colors = ["#FF5C39","#0E0E0E","#FF3CAC","#2B86C5"];
        return <circle key={i} cx={x} cy={y} r={sz} fill={colors[i % colors.length]} opacity="0.85"/>;
      })}
      <g transform={`rotate(-4 ${w/2} ${h/2})`}>
        <rect x={w*0.08} y={h*0.36} width={w*0.84} height={h*0.32} fill="#0E0E0E"/>
        <text x={w*0.5} y={h*0.5} textAnchor="middle" fontFamily="Fraunces, serif" fontWeight="700" fontSize={w*0.075} fill="#FFD23F" letterSpacing="1">HAPPY</text>
        <text x={w*0.5} y={h*0.62} textAnchor="middle" fontFamily="Fraunces, serif" fontStyle="italic" fontSize={w*0.12} fill="#FF5C39">{recipient}</text>
      </g>
      <text x={w*0.5} y={h*0.92} textAnchor="middle" fontFamily="JetBrains Mono, monospace" fontSize={w*0.034} fill="#0E0E0E" letterSpacing="3">{(title || "").toUpperCase().slice(0,28)}</text>
    </svg>
  );
}
function CoverHeartfelt({ recipient, title, w = 360 }) {
  const h = w;
  return (
    <svg viewBox={`0 0 ${w} ${h}`} width="100%" style={{ display: "block", borderRadius: 8 }}>
      <defs>
        <radialGradient id="hf" cx="50%" cy="40%" r="60%">
          <stop offset="0%" stopColor="#FAF1DF"/>
          <stop offset="100%" stopColor="#E8B04F"/>
        </radialGradient>
      </defs>
      <rect width={w} height={h} fill="url(#hf)"/>
      <text x={w*0.5} y={h*0.5} textAnchor="middle" fontFamily="Fraunces, serif" fontStyle="italic" fontWeight="400" fontSize={w*0.18} fill="#1B1B1B">for</text>
      <text x={w*0.5} y={h*0.68} textAnchor="middle" fontFamily="Fraunces, serif" fontStyle="italic" fontWeight="500" fontSize={w*0.18} fill="#1B1B1B">{recipient}</text>
      <line x1={w*0.3} y1={h*0.78} x2={w*0.7} y2={h*0.78} stroke="#1B1B1B" strokeWidth="0.5"/>
      <text x={w*0.5} y={h*0.86} textAnchor="middle" fontFamily="JetBrains Mono, monospace" fontSize={w*0.028} fill="#1B1B1B" letterSpacing="4">{(title || "").toUpperCase().slice(0,28)}</text>
    </svg>
  );
}
function CoverMixtape({ recipient, title, w = 360 }) {
  const h = w;
  return (
    <svg viewBox={`0 0 ${w} ${h}`} width="100%" style={{ display: "block", borderRadius: 8 }}>
      <rect width={w} height={h} fill="#0E0E0E"/>
      <rect x={w*0.06} y={h*0.06} width={w*0.88} height={h*0.88} fill="none" stroke="#F5E9D7" strokeWidth="1"/>
      <text x={w*0.5} y={h*0.18} textAnchor="middle" fontFamily="JetBrains Mono, monospace" fontSize={w*0.032} fill="#F5E9D7" letterSpacing="6">SIDE A · INSIDEJAMS</text>
      {/* cassette */}
      <g transform={`translate(${w*0.18},${h*0.32})`}>
        <rect width={w*0.64} height={h*0.34} fill="#F5E9D7" rx="6"/>
        <rect x={w*0.04} y={h*0.05} width={w*0.56} height={h*0.12} fill="#0E0E0E"/>
        <circle cx={w*0.18} cy={h*0.24} r={w*0.04} fill="#0E0E0E"/>
        <circle cx={w*0.46} cy={h*0.24} r={w*0.04} fill="#0E0E0E"/>
        <text x={w*0.32} y={h*0.13} textAnchor="middle" fontFamily="Fraunces, serif" fontStyle="italic" fontSize={w*0.05} fill="#FF5C39">{recipient}</text>
      </g>
      <text x={w*0.5} y={h*0.82} textAnchor="middle" fontFamily="Fraunces, serif" fontStyle="italic" fontSize={w*0.1} fill="#F5E9D7">{title}</text>
      <text x={w*0.5} y={h*0.92} textAnchor="middle" fontFamily="JetBrains Mono, monospace" fontSize={w*0.026} fill="#F5E9D7" letterSpacing="3" opacity="0.7">A PERSONAL RECORDING · 2026</text>
    </svg>
  );
}
function CoverTrap({ recipient, title, w = 360 }) {
  const h = w;
  return (
    <svg viewBox={`0 0 ${w} ${h}`} width="100%" style={{ display: "block", borderRadius: 8 }}>
      <rect width={w} height={h} fill="#0E0E0E"/>
      <text x={w*0.5} y={h*0.4} textAnchor="middle" fontFamily="Fraunces, serif" fontWeight="700" fontStyle="italic" fontSize={w*0.42} fill="none" stroke="#FF5C39" strokeWidth="1.5">{(recipient || "").slice(0,5).toUpperCase()}</text>
      <text x={w*0.5} y={h*0.55} textAnchor="middle" fontFamily="Fraunces, serif" fontWeight="700" fontStyle="italic" fontSize={w*0.42} fill="#FF5C39">{(recipient || "").slice(0,5).toUpperCase()}</text>
      <rect x={w*0.08} y={h*0.7} width={w*0.84} height={h*0.18} fill="#FFD23F"/>
      <text x={w*0.5} y={h*0.82} textAnchor="middle" fontFamily="JetBrains Mono, monospace" fontWeight="700" fontSize={w*0.044} fill="#0E0E0E" letterSpacing="3">{(title || "").toUpperCase().slice(0,30)}</text>
    </svg>
  );
}

const COVER_TEMPLATES = {
  bold: { name: "Bold Colorful", component: CoverBoldColorful },
  retro: { name: "Retro Album", component: CoverRetro },
  chaos: { name: "Birthday Chaos", component: CoverChaos },
  heartfelt: { name: "Heartfelt Minimal", component: CoverHeartfelt },
  mixtape: { name: "Mixtape", component: CoverMixtape },
  trap: { name: "Rap/Trap Mixtape", component: CoverTrap },
};

function CoverArt({ template = "bold", recipient = "Maya", title = "Untitled", w = 360 }) {
  const T = COVER_TEMPLATES[template]?.component || CoverBoldColorful;
  return <T recipient={recipient} title={title} w={w} />;
}

// === Skeuomorphic cassette tape ===
function SkeuoCassette({ w = 360, title = "For Maya, on her 30th", meta = "ROAST · POP ANTHEM · 0:54", spinning = true, reelRotation = 0, accent = "var(--tangerine)", body = "#15151a", bodyHighlight = "#3a3a44", bodyShadow = "#08080c", labelTone = "warm" }) {
  const h = w * (240 / 360);
  const id = React.useMemo(() => 'cz' + Math.floor(Math.random() * 1e6), []);
  const labelTop = labelTone === "cool" ? "#F2F0E8" : labelTone === "neon" ? "#FFF8C8" : "#FAEAC4";
  const labelBot = labelTone === "cool" ? "#E0DDD2" : labelTone === "neon" ? "#F4E89A" : "#E8D2A4";
  const labelLine = labelTone === "cool" ? "#aaa49a" : "#b8a378";
  const stampColor = labelTone === "cool" ? "#3a3a44" : "#1a1a24";
  return (
    <svg width={w} height={h} viewBox="0 0 360 240" xmlns="http://www.w3.org/2000/svg" style={{ display: "block", filter: "drop-shadow(0 16px 28px rgba(0,0,0,0.28))" }}>
      <defs>
        <linearGradient id={`${id}-body`} x1="0" y1="0" x2="0" y2="1">
          <stop offset="0" stopColor={bodyHighlight}/>
          <stop offset="0.08" stopColor={body}/>
          <stop offset="0.5" stopColor={bodyShadow}/>
          <stop offset="0.92" stopColor={body}/>
          <stop offset="1" stopColor={bodyHighlight}/>
        </linearGradient>
        <linearGradient id={`${id}-label`} x1="0" y1="0" x2="0" y2="1">
          <stop offset="0" stopColor={labelTop}/>
          <stop offset="1" stopColor={labelBot}/>
        </linearGradient>
        <radialGradient id={`${id}-window`} cx="0.5" cy="0.4" r="0.7">
          <stop offset="0" stopColor="#1a1a20"/>
          <stop offset="1" stopColor="#08080c"/>
        </radialGradient>
        <radialGradient id={`${id}-tape`} cx="0.5" cy="0.5" r="0.5">
          <stop offset="0.4" stopColor="#5a3a26"/>
          <stop offset="0.7" stopColor="#3a2418"/>
          <stop offset="1" stopColor="#1a0e08"/>
        </radialGradient>
        <linearGradient id={`${id}-shine`} x1="0" y1="0" x2="0" y2="1">
          <stop offset="0" stopColor="#ffffff" stopOpacity="0.18"/>
          <stop offset="0.5" stopColor="#ffffff" stopOpacity="0"/>
        </linearGradient>
      </defs>

      {/* Body shell */}
      <rect x="2" y="2" width="356" height="236" rx="14" fill={`url(#${id}-body)`} stroke="#000" strokeWidth="0.6"/>
      {/* Top highlight strip */}
      <rect x="6" y="4" width="348" height="60" rx="10" fill={`url(#${id}-shine)`}/>

      {/* Label area · paper sticker */}
      <g>
        <rect x="20" y="20" width="320" height="76" rx="3" fill={`url(#${id}-label)`} stroke={labelLine} strokeWidth="0.5"/>
        {/* Label red stripe */}
        <rect x="20" y="20" width="320" height="10" fill={accent} opacity="0.85"/>
        {/* Three rule lines for handwritten feel */}
        <line x1="32" y1="46" x2="328" y2="46" stroke={labelLine} strokeWidth="0.4"/>
        <line x1="32" y1="64" x2="328" y2="64" stroke={labelLine} strokeWidth="0.4"/>
        <line x1="32" y1="82" x2="328" y2="82" stroke={labelLine} strokeWidth="0.4"/>
        {/* Hand-written title */}
        <text x="32" y="62" fontFamily="'Caprasimo', serif" fontStyle="italic" fontSize="18" fill={stampColor}>{title}</text>
        <text x="32" y="92" fontFamily="'JetBrains Mono', monospace" fontSize="9" fill={stampColor} letterSpacing="0.05em" opacity="0.75">{meta}</text>
        {/* Side A label */}
        <rect x="290" y="76" width="42" height="14" fill={stampColor} rx="1"/>
        <text x="311" y="86" fontFamily="'JetBrains Mono', monospace" fontSize="8" fill={labelTop} letterSpacing="0.1em" textAnchor="middle">SIDE A</text>
      </g>

      {/* Reel/window panel */}
      <g>
        <rect x="46" y="108" width="268" height="92" rx="5" fill={`url(#${id}-window)`} stroke="#000" strokeWidth="0.5"/>
        {/* Inner bevel */}
        <rect x="46" y="108" width="268" height="3" fill="#000" opacity="0.7"/>
        <rect x="46" y="197" width="268" height="3" fill="#fff" opacity="0.05"/>

        {/* Tape ribbon — visible bottom portion connecting reels */}
        <path d="M 105 180 Q 180 196, 255 180" stroke="#1a0e08" strokeWidth="2.4" fill="none"/>

        {/* LEFT reel */}
        <g style={{ transformOrigin: "105px 154px", animation: spinning ? "spin-slow 6s linear infinite" : "none", transform: spinning ? undefined : `rotate(${reelRotation}deg)`, transition: spinning ? "none" : "transform 120ms var(--ease-out)" }}>
          {/* Tape spool — concentric rings for wound tape */}
          <circle cx="105" cy="154" r="32" fill={`url(#${id}-tape)`}/>
          <circle cx="105" cy="154" r="32" fill="none" stroke="#000" strokeWidth="0.4" opacity="0.6"/>
          <circle cx="105" cy="154" r="28" fill="none" stroke="#000" strokeWidth="0.3" opacity="0.5"/>
          <circle cx="105" cy="154" r="24" fill="none" stroke="#000" strokeWidth="0.3" opacity="0.45"/>
          <circle cx="105" cy="154" r="20" fill="none" stroke="#000" strokeWidth="0.3" opacity="0.4"/>
          {/* Hub — toothed cog */}
          <circle cx="105" cy="154" r="14" fill="#0a0a0e" stroke="#3a3a44" strokeWidth="0.6"/>
          {[...Array(8)].map((_, i) => {
            const a = (i * 360 / 8) * Math.PI / 180;
            const x1 = 105 + Math.cos(a) * 9;
            const y1 = 154 + Math.sin(a) * 9;
            const x2 = 105 + Math.cos(a) * 13;
            const y2 = 154 + Math.sin(a) * 13;
            return <line key={i} x1={x1} y1={y1} x2={x2} y2={y2} stroke="#3a3a44" strokeWidth="2" strokeLinecap="round"/>;
          })}
          <circle cx="105" cy="154" r="3" fill={accent}/>
        </g>

        {/* RIGHT reel */}
        <g style={{ transformOrigin: "255px 154px", animation: spinning ? "spin-slow 6s linear infinite" : "none", transform: spinning ? undefined : `rotate(${-reelRotation}deg)`, transition: spinning ? "none" : "transform 120ms var(--ease-out)" }}>
          <circle cx="255" cy="154" r="32" fill={`url(#${id}-tape)`}/>
          <circle cx="255" cy="154" r="32" fill="none" stroke="#000" strokeWidth="0.4" opacity="0.6"/>
          <circle cx="255" cy="154" r="28" fill="none" stroke="#000" strokeWidth="0.3" opacity="0.5"/>
          <circle cx="255" cy="154" r="24" fill="none" stroke="#000" strokeWidth="0.3" opacity="0.45"/>
          <circle cx="255" cy="154" r="20" fill="none" stroke="#000" strokeWidth="0.3" opacity="0.4"/>
          <circle cx="255" cy="154" r="14" fill="#0a0a0e" stroke="#3a3a44" strokeWidth="0.6"/>
          {[...Array(8)].map((_, i) => {
            const a = (i * 360 / 8) * Math.PI / 180;
            const x1 = 255 + Math.cos(a) * 9;
            const y1 = 154 + Math.sin(a) * 9;
            const x2 = 255 + Math.cos(a) * 13;
            const y2 = 154 + Math.sin(a) * 13;
            return <line key={i} x1={x1} y1={y1} x2={x2} y2={y2} stroke="#3a3a44" strokeWidth="2" strokeLinecap="round"/>;
          })}
          <circle cx="255" cy="154" r="3" fill={accent}/>
        </g>

        {/* Felt pressure pad — center bottom */}
        <rect x="172" y="190" width="16" height="6" rx="1" fill="#5a3a26"/>
        <rect x="174" y="191" width="12" height="2" fill="#7a4a30"/>
      </g>

      {/* Screws · 4 corners */}
      {[[16,16],[344,16],[16,224],[344,224]].map(([cx, cy], i) => (
        <g key={i}>
          <circle cx={cx} cy={cy} r="3.4" fill="#0a0a0e" stroke="#444" strokeWidth="0.4"/>
          <line x1={cx-2} y1={cy} x2={cx+2} y2={cy} stroke="#3a3a44" strokeWidth="0.7"/>
        </g>
      ))}

      {/* Bottom · sprocket holes + write-protect tabs */}
      <g>
        <rect x="60" y="218" width="6" height="4" rx="1" fill="#0a0a0e"/>
        <rect x="294" y="218" width="6" height="4" rx="1" fill="#0a0a0e"/>
        <text x="180" y="226" fontFamily="'JetBrains Mono', monospace" fontSize="7" fill="#FAEAC4" opacity="0.5" letterSpacing="0.18em" textAnchor="middle">INSIDEJAMS C-60</text>
      </g>
    </svg>
  );
}

// === Skeuomorphic VU meter ===
function VUMeter({ w = 110, h = 50, level = 0.6, label = "L" }) {
  // Needle angle: -45deg (low) to +45deg (high)
  const angle = -45 + (level * 90);
  return (
    <svg width={w} height={h} viewBox="0 0 110 50" style={{ display: "block" }}>
      <defs>
        <linearGradient id={`vu-bg-${label}`} x1="0" y1="0" x2="0" y2="1">
          <stop offset="0" stopColor="#FAEAC4"/>
          <stop offset="1" stopColor="#E8D2A4"/>
        </linearGradient>
      </defs>
      <rect x="1" y="1" width="108" height="48" rx="4" fill={`url(#vu-bg-${label})`} stroke="#1a1a24" strokeWidth="1"/>
      {/* Scale */}
      {[-45, -30, -15, 0, 15, 30, 45].map((a, i) => {
        const rad = a * Math.PI / 180;
        const inner = 38;
        const outer = i === 3 ? 44 : 42;
        const cx = 55, cy = 50;
        const x1 = cx + Math.sin(rad) * inner;
        const y1 = cy - Math.cos(rad) * inner;
        const x2 = cx + Math.sin(rad) * outer;
        const y2 = cy - Math.cos(rad) * outer;
        const tooHot = a > 15;
        return <line key={i} x1={x1} y1={y1} x2={x2} y2={y2} stroke={tooHot ? "#D93616" : "#1a1a24"} strokeWidth={i === 3 ? 1.2 : 0.7}/>;
      })}
      {/* Arc */}
      <path d="M 25 38 A 30 30 0 0 1 85 38" stroke="#1a1a24" strokeWidth="0.6" fill="none"/>
      {/* "VU" */}
      <text x="55" y="22" fontFamily="'JetBrains Mono', monospace" fontSize="8" fill="#1a1a24" textAnchor="middle" letterSpacing="0.1em">VU · {label}</text>
      {/* Needle */}
      <g style={{ transformOrigin: "55px 50px", transform: `rotate(${angle}deg)`, transition: "transform 200ms ease-out" }}>
        <line x1="55" y1="50" x2="55" y2="8" stroke="#C81D11" strokeWidth="1.2"/>
        <circle cx="55" cy="50" r="2.5" fill="#1a1a24"/>
      </g>
    </svg>
  );
}

Object.assign(window, {
  Waveform, AudioPlayer, CoverArt, COVER_TEMPLATES, SkeuoCassette, VUMeter,
  CoverBoldColorful, CoverRetro, CoverChaos, CoverHeartfelt, CoverMixtape, CoverTrap,
});
