/**
 * AJL40 Digital Series
 * © 2026 sultanmuzaffar. Hak cipta terpelihara / All rights reserved.
 * Penggunaan, penyalinan atau pengedaran tanpa kebenaran bertulis adalah dilarang.
 * Unauthorized use, copying or distribution is prohibited.
 */

// AJL 40 — Data Visualisation EXTRA modules
// Ported from base44 source (recharts/framer-motion/lucide) into the site's
// babel-standalone + inline-SVG + inline-style idiom.
// Exposes: PetaEvolusiGenre, EvolusiAliranMuzik, EvolusiGenreMuzik

const { useState: useStateX, useRef: useRefX, useMemo: useMemoX } = React;

/* ===================== shared tokens ===================== */
const DVX_GENRES = [
  { key: 'balada',  label: 'Ballad', color: '#C9A84C', desc: 'Power Ballad & Pop Ballad' },
  { key: 'rock',    label: 'Rock',   color: '#C0392B', desc: 'Rock Pop, Modern, Alternative' },
  { key: 'tradisi', label: 'Tradisi / Fusion / Folk', color: '#2D8A7A', desc: 'Traditional Malay, World Fusion & Folk' },
  { key: 'hiphop',  label: 'Hip Hop', color: '#4A7B9D', desc: 'Hip Hop & Urban' },
];
const DVX_BORDER = '1px solid rgba(255,255,255,0.08)';
const DVX_CARD = { backgroundColor: '#161616', borderRadius: '0.375rem', border: DVX_BORDER, overflow: 'hidden', marginBottom: '1.5rem' };
const MONO = 'var(--f-label,monospace)';
const SERIF = 'var(--f-body,serif)';
const HEAD = 'var(--f-heading,serif)';

/* small reusable card header */
function DvxHeader({ eyebrow, title, desc, onReset, showReset }) {
  return (
    <div style={{ padding: '1.5rem 1.5rem 1rem', borderBottom: DVX_BORDER }}>
      <div style={{ display: 'flex', alignItems: 'flex-start', justifyContent: 'space-between', gap: '0.75rem', marginBottom: '0.5rem' }}>
        <div>
          <p style={{ fontFamily: MONO, fontSize: '0.75rem', letterSpacing: '0.15em', textTransform: 'uppercase', color: '#C9A84C', margin: '0 0 0.25rem' }}>{eyebrow}</p>
          <h3 style={{ fontFamily: HEAD, fontSize: '1.25rem', fontWeight: 700, color: '#F5F0E8', margin: 0 }}>{title}</h3>
        </div>
        {showReset && (
          <button onClick={onReset} style={{ flexShrink: 0, display: 'inline-flex', alignItems: 'center', gap: '0.4rem', fontFamily: MONO, fontSize: '10px', letterSpacing: '0.12em', textTransform: 'uppercase', color: '#9B9B9B', background: 'transparent', border: DVX_BORDER, borderRadius: '999px', padding: '0.4rem 0.75rem', cursor: 'pointer' }}>
            <svg width="11" height="11" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.4" strokeLinecap="round" strokeLinejoin="round"><polyline points="1 4 1 10 7 10"/><path d="M3.51 15a9 9 0 1 0 2.13-9.36L1 10"/></svg>
            Set Semula
          </button>
        )}
      </div>
      <p style={{ fontFamily: SERIF, fontSize: '0.75rem', color: 'rgba(255,255,255,0.45)', lineHeight: 1.6, maxWidth: '42rem', margin: 0 }}>{desc}</p>
    </div>
  );
}

/* ============================================================
   SHARED STACKED AREA CHART (hand-built SVG)
   Replaces recharts AreaChart for both edition + year charts.
   ============================================================ */
function StackedAreaChart({ data, xKey, decades, allLabel, decadeUnitLabel, scrubLabel }) {
  const [hover, setHover] = useStateX(null);          // hovered index
  const [selected, setSelected] = useStateX(null);    // selected x value
  const [activeDekad, setActiveDekad] = useStateX(null);
  const [hidden, setHidden] = useStateX([]);          // hidden genre keys

  const visible = DVX_GENRES.filter(g => !hidden.includes(g.key));
  const toggleGenre = (k) => setHidden(prev => prev.includes(k) ? prev.filter(x => x !== k) : [...prev, k]);

  const filtered = useMemoX(() => {
    if (!activeDekad) return data;
    const dec = decades.find(d => d.id === activeDekad);
    if (!dec) return data;
    return data.filter(d => d[xKey] >= dec.range[0] && d[xKey] <= dec.range[1]);
  }, [activeDekad, data, xKey, decades]);

  const hasFilters = activeDekad || hidden.length > 0 || selected != null;
  const resetAll = () => { setActiveDekad(null); setHidden([]); setSelected(null); setHover(null); };

  // geometry
  const VBW = 720, VBH = 340;
  const mL = 40, mR = 14, mT = 14, mB = 30;
  const pX0 = mL, pX1 = VBW - mR, pY0 = mT, pY1 = VBH - mB;
  const n = filtered.length;
  const xAt = (i) => n <= 1 ? (pX0 + pX1) / 2 : pX0 + (i / (n - 1)) * (pX1 - pX0);
  const yAt = (pct) => pY1 - (pct / 100) * (pY1 - pY0);

  // cumulative stack among VISIBLE genres (bottom->top in DVX_GENRES order)
  const bands = visible.map((g, gi) => {
    const pts = filtered.map((row, i) => {
      let lower = 0;
      for (let k = 0; k < gi; k++) lower += row[visible[k].key];
      const upper = lower + row[g.key];
      return { x: xAt(i), lo: yAt(lower), hi: yAt(upper) };
    });
    let d = `M${pts[0].x},${pts[0].hi}`;
    for (let i = 1; i < pts.length; i++) d += ` L${pts[i].x},${pts[i].hi}`;
    for (let i = pts.length - 1; i >= 0; i--) d += ` L${pts[i].x},${pts[i].lo}`;
    d += ' Z';
    return { genre: g, d };
  });

  const yTicks = [0, 25, 50, 75, 100];
  const selData = selected != null ? data.find(d => d[xKey] === selected) : null;
  const hoverRow = hover != null && filtered[hover] ? filtered[hover] : null;
  const hoverFrac = hover != null ? (xAt(hover) / VBW) * 100 : 0;

  return (
    <div>
      {/* chart */}
      <div style={{ position: 'relative', padding: '1rem 0.75rem 0.25rem' }}>
        <svg viewBox={`0 0 ${VBW} ${VBH}`} style={{ width: '100%', height: 'auto', display: 'block' }}
             onMouseLeave={() => setHover(null)}>
          <defs>
            {DVX_GENRES.map(g => (
              <linearGradient key={g.key} id={`dvx-grad-${g.key}`} x1="0" y1="0" x2="0" y2="1">
                <stop offset="0%" stopColor={g.color} stopOpacity={0.82} />
                <stop offset="100%" stopColor={g.color} stopOpacity={0.18} />
              </linearGradient>
            ))}
          </defs>

          {/* y grid + labels */}
          {yTicks.map(t => (
            <g key={t}>
              <line x1={pX0} y1={yAt(t)} x2={pX1} y2={yAt(t)} stroke="rgba(255,255,255,0.06)" strokeWidth="1" />
              <text x={pX0 - 8} y={yAt(t) + 3} textAnchor="end" fill="#9B9B9B" fontFamily={MONO} fontSize="10">{t}%</text>
            </g>
          ))}

          {/* decade reference lines (only when not filtered) */}
          {!activeDekad && decades.map((d, di) => {
            const idx = filtered.findIndex(r => r[xKey] >= d.range[0]);
            if (idx < 0) return null;
            const x = xAt(idx);
            return (
              <g key={d.id}>
                <line x1={x} y1={pY0} x2={x} y2={pY1} stroke="#C9A84C" strokeOpacity={0.3} strokeWidth="1" strokeDasharray="3 3" />
                <text x={x + 4} y={pY0 + 10} fill="#C9A84C" fontFamily={MONO} fontSize="8" letterSpacing="1">{d.label.toUpperCase()}</text>
              </g>
            );
          })}

          {/* stacked areas */}
          {bands.map(b => (
            <path key={b.genre.key} d={b.d} fill={`url(#dvx-grad-${b.genre.key})`} stroke={b.genre.color} strokeWidth="1.4" />
          ))}

          {/* hover guide */}
          {hover != null && (
            <line x1={xAt(hover)} y1={pY0} x2={xAt(hover)} y2={pY1} stroke="#C9A84C" strokeWidth="1" strokeDasharray="3 3" />
          )}

          {/* x labels (sparse) */}
          {filtered.map((row, i) => {
            const showEvery = n > 20 ? 5 : (n > 10 ? 2 : 1);
            if (i % showEvery !== 0 && i !== n - 1) return null;
            return <text key={i} x={xAt(i)} y={pY1 + 18} textAnchor="middle" fill="#9B9B9B" fontFamily={MONO} fontSize="9">{row[xKey]}</text>;
          })}

          {/* invisible hit columns */}
          {filtered.map((row, i) => {
            const w = n <= 1 ? (pX1 - pX0) : (pX1 - pX0) / (n - 1);
            return <rect key={i} x={xAt(i) - w / 2} y={pY0} width={w} height={pY1 - pY0} fill="transparent"
              onMouseEnter={() => setHover(i)} onClick={() => setSelected(row[xKey])} style={{ cursor: 'pointer' }} />;
          })}
        </svg>

        {/* hover tooltip */}
        {hoverRow && (
          <div style={{ position: 'absolute', top: '0.5rem', left: `${hoverFrac}%`, transform: `translateX(${hoverFrac > 60 ? '-105%' : '8px'})`,
            padding: '0.6rem 0.75rem', borderRadius: '0.5rem', border: '1px solid rgba(201,168,76,0.3)', background: 'rgba(13,13,13,0.96)',
            pointerEvents: 'none', zIndex: 5, minWidth: '150px' }}>
            <p style={{ fontFamily: MONO, fontSize: '11px', color: '#C9A84C', letterSpacing: '0.1em', margin: '0 0 0.4rem' }}>{scrubLabel} {hoverRow[xKey]}</p>
            {DVX_GENRES.map(g => (
              <div key={g.key} style={{ display: 'flex', alignItems: 'center', gap: '0.4rem', marginBottom: '2px' }}>
                <span style={{ width: '8px', height: '8px', borderRadius: '50%', background: g.color, flexShrink: 0 }} />
                <span style={{ fontFamily: MONO, fontSize: '10px', color: '#9B9B9B' }}>{g.label}</span>
                <span style={{ fontFamily: MONO, fontSize: '10px', fontWeight: 700, color: g.color, marginLeft: 'auto' }}>{hoverRow[g.key]}%</span>
              </div>
            ))}
            {hoverRow.note && <p style={{ fontFamily: SERIF, fontSize: '10px', fontStyle: 'italic', color: 'rgba(255,255,255,0.5)', margin: '0.4rem 0 0', paddingTop: '0.4rem', borderTop: DVX_BORDER, lineHeight: 1.5 }}>{hoverRow.note}</p>}
          </div>
        )}
      </div>

      {/* filter toolbar */}
      <div style={{ padding: '1rem 1.5rem', borderTop: DVX_BORDER, background: '#0F0F0F', display: 'flex', flexDirection: 'column', gap: '1rem' }}>
        <div>
          <p style={{ fontFamily: MONO, fontSize: '10px', letterSpacing: '0.2em', textTransform: 'uppercase', color: '#666', margin: '0 0 0.5rem' }}>Dekad</p>
          <div style={{ display: 'flex', flexWrap: 'wrap', gap: '0.5rem' }}>
            <button onClick={() => setActiveDekad(null)} style={{
              fontFamily: MONO, fontSize: '10px', letterSpacing: '0.05em', padding: '0.375rem 0.75rem', borderRadius: '999px', cursor: 'pointer',
              color: !activeDekad ? '#0D0D0D' : '#9B9B9B', background: !activeDekad ? '#C9A84C' : 'transparent',
              border: !activeDekad ? '1px solid #C9A84C' : DVX_BORDER, fontWeight: !activeDekad ? 700 : 400 }}>{allLabel}</button>
            {decades.map(d => {
              const on = activeDekad === d.id;
              return (
                <button key={d.id} onClick={() => setActiveDekad(on ? null : d.id)} style={{
                  fontFamily: MONO, fontSize: '10px', letterSpacing: '0.05em', padding: '0.375rem 0.75rem', borderRadius: '999px', cursor: 'pointer',
                  color: on ? '#0D0D0D' : '#9B9B9B', background: on ? '#C9A84C' : 'transparent',
                  border: on ? '1px solid #C9A84C' : DVX_BORDER, fontWeight: on ? 700 : 400 }}>
                  {d.label} <span style={{ opacity: 0.6, marginLeft: '0.25rem' }}>{decadeUnitLabel} {d.range[0]}–{d.range[1]}</span>
                </button>
              );
            })}
          </div>
        </div>
        <div>
          <p style={{ fontFamily: MONO, fontSize: '10px', letterSpacing: '0.2em', textTransform: 'uppercase', color: '#666', margin: '0 0 0.5rem' }}>Genre</p>
          <div style={{ display: 'flex', flexWrap: 'wrap', gap: '0.5rem' }}>
            {DVX_GENRES.map(g => {
              const isHidden = hidden.includes(g.key);
              return (
                <button key={g.key} onClick={() => toggleGenre(g.key)} style={{
                  display: 'inline-flex', alignItems: 'center', gap: '0.5rem', fontFamily: MONO, fontSize: '10px', letterSpacing: '0.05em',
                  padding: '0.375rem 0.75rem', borderRadius: '999px', cursor: 'pointer',
                  color: isHidden ? '#666' : g.color, background: isHidden ? 'transparent' : `${g.color}15`,
                  border: isHidden ? DVX_BORDER : `1px solid ${g.color}50`, opacity: isHidden ? 0.55 : 1 }}>
                  <span style={{ width: '8px', height: '8px', borderRadius: '50%', background: isHidden ? '#2A2A2A' : g.color }} />
                  {g.label}
                </button>
              );
            })}
          </div>
        </div>
      </div>

      {/* scrubber */}
      <div style={{ padding: '1rem 1.5rem 0' }}>
        <div style={{ display: 'flex', alignItems: 'center', gap: '0.25rem', overflowX: 'auto', paddingBottom: '0.5rem' }}>
          {filtered.map(row => {
            const on = selected === row[xKey];
            return (
              <button key={row[xKey]} onClick={() => setSelected(row[xKey])} style={{
                fontFamily: MONO, fontSize: '10px', letterSpacing: '0.05em', padding: '0.25rem 0.6rem', borderRadius: '999px', flexShrink: 0, cursor: 'pointer',
                color: on ? '#C9A84C' : '#666', background: on ? 'rgba(201,168,76,0.12)' : 'transparent',
                border: on ? '1px solid rgba(201,168,76,0.4)' : '1px solid transparent' }}>{row[xKey]}</button>
            );
          })}
        </div>
      </div>

      {/* detail card */}
      <div style={{ padding: '1rem 1.5rem 1.5rem', borderTop: DVX_BORDER }}>
        <p style={{ fontFamily: MONO, fontSize: '10px', letterSpacing: '0.2em', textTransform: 'uppercase', color: '#C9A84C', margin: '0 0 0.75rem' }}>
          {selData ? `${scrubLabel} ${selData[xKey]}` : 'Pilih untuk lihat pecahan'}
        </p>
        {selData ? (
          <div style={{ display: 'grid', gridTemplateColumns: 'repeat(auto-fit,minmax(220px,1fr))', columnGap: '2rem', rowGap: '0.6rem' }}>
            {DVX_GENRES.map(g => (
              <div key={g.key} style={{ display: 'flex', alignItems: 'center', gap: '0.75rem' }}>
                <span style={{ width: '10px', height: '10px', borderRadius: '50%', background: g.color, flexShrink: 0 }} />
                <span style={{ fontFamily: MONO, fontSize: '10px', color: '#9B9B9B', width: '7rem', flexShrink: 0 }}>{g.label}</span>
                <div style={{ flex: 1, height: '6px', borderRadius: '999px', overflow: 'hidden', background: '#2A2A2A' }}>
                  <div style={{ width: `${selData[g.key]}%`, height: '100%', background: g.color, borderRadius: '999px', transition: 'width 0.5s ease' }} />
                </div>
                <span style={{ fontFamily: MONO, fontSize: '10px', fontWeight: 700, color: g.color, width: '2rem', textAlign: 'right' }}>{selData[g.key]}%</span>
              </div>
            ))}
            {selData.note && <p style={{ gridColumn: '1 / -1', fontFamily: SERIF, fontSize: '0.75rem', fontStyle: 'italic', color: 'rgba(255,255,255,0.55)', margin: '0.5rem 0 0', paddingTop: '0.75rem', borderTop: DVX_BORDER, lineHeight: 1.6 }}>{selData.note}</p>}
          </div>
        ) : (
          <p style={{ fontFamily: SERIF, fontSize: '0.75rem', color: 'rgba(255,255,255,0.4)', margin: 0 }}>Gerakkan kursor pada graf, klik nombor di atas, atau klik graf untuk melihat pecahan genre.</p>
        )}
      </div>

      {/* hidden reset hook surfaced via header is handled by parent; expose here too */}
      {hasFilters && (
        <div style={{ padding: '0 1.5rem 1.25rem' }}>
          <button onClick={resetAll} style={{ fontFamily: MONO, fontSize: '10px', letterSpacing: '0.12em', textTransform: 'uppercase', color: '#9B9B9B', background: 'transparent', border: DVX_BORDER, borderRadius: '999px', padding: '0.4rem 0.8rem', cursor: 'pointer' }}>Set Semula Penapis</button>
        </div>
      )}
    </div>
  );
}

/* ===================== 4. EVOLUSI ALIRAN MUZIK (by year) ===================== */
const DVX_YEARLY = [
  { year: 1986, balada: 60, rock: 30, tradisi: 10, hiphop: 0, note: 'Kelahiran AJL — Balada mendominasi pentas pertama.' },
  { year: 1988, balada: 62, rock: 28, tradisi: 10, hiphop: 0 },
  { year: 1990, balada: 58, rock: 32, tradisi: 10, hiphop: 0 },
  { year: 1992, balada: 55, rock: 33, tradisi: 12, hiphop: 0 },
  { year: 1994, balada: 50, rock: 32, tradisi: 18, hiphop: 0 },
  { year: 1996, balada: 42, rock: 28, tradisi: 30, hiphop: 0, note: 'Kebangkitan Tradisi — Irama Malaysia dan fusion naik.' },
  { year: 1998, balada: 35, rock: 22, tradisi: 43, hiphop: 0 },
  { year: 2000, balada: 32, rock: 20, tradisi: 48, hiphop: 0 },
  { year: 2002, balada: 30, rock: 22, tradisi: 48, hiphop: 0 },
  { year: 2004, balada: 32, rock: 24, tradisi: 44, hiphop: 0 },
  { year: 2006, balada: 30, rock: 28, tradisi: 38, hiphop: 4, note: 'Hip Hop Muncul — Genre baharu mula hadir di pentas.' },
  { year: 2008, balada: 30, rock: 30, tradisi: 32, hiphop: 8 },
  { year: 2010, balada: 30, rock: 30, tradisi: 30, hiphop: 10 },
  { year: 2012, balada: 32, rock: 28, tradisi: 30, hiphop: 10 },
  { year: 2014, balada: 35, rock: 28, tradisi: 27, hiphop: 10 },
  { year: 2016, balada: 40, rock: 30, tradisi: 20, hiphop: 10, note: 'Balada Kembali — Dominan dalam era digital.' },
  { year: 2018, balada: 43, rock: 30, tradisi: 17, hiphop: 10 },
  { year: 2020, balada: 44, rock: 30, tradisi: 15, hiphop: 11 },
  { year: 2022, balada: 44, rock: 31, tradisi: 14, hiphop: 11 },
  { year: 2024, balada: 45, rock: 33, tradisi: 11, hiphop: 11 },
];
const DVX_YEAR_DECADES = [
  { id: 1, label: 'Perintis', range: [1986, 1995] },
  { id: 2, label: 'Prasasti', range: [1996, 2005] },
  { id: 3, label: 'Revolusi', range: [2006, 2015] },
  { id: 4, label: 'Global',   range: [2016, 2024] },
];

function EvolusiAliranMuzik() {
  return (
    <div style={DVX_CARD}>
      <DvxHeader eyebrow="Evolusi Aliran Muzik" title="Dari 80-an Hingga Kini"
        desc="Carta aliran yang menunjukkan perubahan kekuatan genre muzik pemenang AJL dari tahun ke tahun (1986–2024). Gerakkan kursor untuk melihat pecahan setiap tahun, gunakan penapis dekad dan genre, atau klik tahun untuk butiran penuh." />
      <StackedAreaChart data={DVX_YEARLY} xKey="year" decades={DVX_YEAR_DECADES}
        allLabel="Semua Tahun" decadeUnitLabel="" scrubLabel="Tahun" />
    </div>
  );
}

/* ===================== 5. EVOLUSI GENRE MUZIK (by edition) ===================== */
const DVX_EDITION = [
  { edition: 1, balada: 60, rock: 30, tradisi: 10, hiphop: 0, note: 'AJL pertama — Balada mendominasi pentas awal.' },
  { edition: 2, balada: 61, rock: 29, tradisi: 10, hiphop: 0 },
  { edition: 3, balada: 62, rock: 28, tradisi: 10, hiphop: 0 },
  { edition: 4, balada: 60, rock: 30, tradisi: 10, hiphop: 0 },
  { edition: 5, balada: 58, rock: 32, tradisi: 10, hiphop: 0 },
  { edition: 6, balada: 56, rock: 33, tradisi: 11, hiphop: 0 },
  { edition: 7, balada: 55, rock: 33, tradisi: 12, hiphop: 0 },
  { edition: 8, balada: 52, rock: 33, tradisi: 15, hiphop: 0 },
  { edition: 9, balada: 50, rock: 32, tradisi: 18, hiphop: 0 },
  { edition: 10, balada: 46, rock: 30, tradisi: 24, hiphop: 0, note: 'Akhir dekad Perintis — Tradisi mula naik.' },
  { edition: 11, balada: 42, rock: 28, tradisi: 30, hiphop: 0, note: 'Kebangkitan Tradisi — Irama Malaysia dan fusion naik.' },
  { edition: 12, balada: 38, rock: 25, tradisi: 37, hiphop: 0 },
  { edition: 13, balada: 35, rock: 22, tradisi: 43, hiphop: 0 },
  { edition: 14, balada: 33, rock: 21, tradisi: 46, hiphop: 0 },
  { edition: 15, balada: 32, rock: 20, tradisi: 48, hiphop: 0, note: 'Puncak Tradisi — Irama Malaysia mendominasi.' },
  { edition: 16, balada: 31, rock: 21, tradisi: 48, hiphop: 0 },
  { edition: 17, balada: 30, rock: 22, tradisi: 48, hiphop: 0 },
  { edition: 18, balada: 31, rock: 23, tradisi: 46, hiphop: 0 },
  { edition: 19, balada: 32, rock: 24, tradisi: 44, hiphop: 0 },
  { edition: 20, balada: 31, rock: 26, tradisi: 41, hiphop: 2, note: 'Akhir dekad Prasasti — genre mula mempelbagaikan.' },
  { edition: 21, balada: 30, rock: 28, tradisi: 38, hiphop: 4, note: 'Hip Hop Muncul — Genre baharu mula hadir di pentas.' },
  { edition: 22, balada: 30, rock: 29, tradisi: 35, hiphop: 6 },
  { edition: 23, balada: 30, rock: 30, tradisi: 32, hiphop: 8 },
  { edition: 24, balada: 30, rock: 30, tradisi: 31, hiphop: 9 },
  { edition: 25, balada: 30, rock: 30, tradisi: 30, hiphop: 10, note: 'Keseimbangan genre — empat genre berkongsi pentas.' },
  { edition: 26, balada: 31, rock: 29, tradisi: 30, hiphop: 10 },
  { edition: 27, balada: 32, rock: 28, tradisi: 30, hiphop: 10 },
  { edition: 28, balada: 33, rock: 28, tradisi: 29, hiphop: 10 },
  { edition: 29, balada: 35, rock: 28, tradisi: 27, hiphop: 10 },
  { edition: 30, balada: 37, rock: 29, tradisi: 24, hiphop: 10, note: 'Akhir dekad Revolusi — Balada kembali menguat.' },
  { edition: 31, balada: 40, rock: 30, tradisi: 20, hiphop: 10, note: 'Balada Kembali — Dominan dalam era digital.' },
  { edition: 32, balada: 41, rock: 30, tradisi: 19, hiphop: 10 },
  { edition: 33, balada: 43, rock: 30, tradisi: 17, hiphop: 10 },
  { edition: 34, balada: 43, rock: 30, tradisi: 16, hiphop: 11 },
  { edition: 35, balada: 44, rock: 30, tradisi: 15, hiphop: 11 },
  { edition: 36, balada: 44, rock: 30, tradisi: 14, hiphop: 11 },
  { edition: 37, balada: 44, rock: 31, tradisi: 14, hiphop: 11 },
  { edition: 38, balada: 44, rock: 32, tradisi: 12, hiphop: 11 },
  { edition: 39, balada: 45, rock: 33, tradisi: 11, hiphop: 11 },
  { edition: 40, balada: 45, rock: 33, tradisi: 11, hiphop: 11, note: 'AJL ke-40 — Balada kekal terunggul, Hip Hop bertapak.' },
];
const DVX_EDITION_DECADES = [
  { id: 1, label: 'Perintis', range: [1, 10] },
  { id: 2, label: 'Prasasti', range: [11, 20] },
  { id: 3, label: 'Revolusi', range: [21, 30] },
  { id: 4, label: 'Global',   range: [31, 40] },
];

function EvolusiGenreMuzik() {
  return (
    <div style={DVX_CARD}>
      <DvxHeader eyebrow="Evolusi Genre Muzik" title="AJL 1 hingga AJL 40"
        desc="Carta interaktif yang menunjukkan perubahan kekuatan genre muzik pemenang AJL sepanjang 40 edisi. Gerakkan kursor pada graf untuk melihat pecahan setiap edisi, gunakan penapis dekad dan genre, atau klik edisi untuk butiran penuh." />
      <StackedAreaChart data={DVX_EDITION} xKey="edition" decades={DVX_EDITION_DECADES}
        allLabel="Semua (1–40)" decadeUnitLabel="AJL" scrubLabel="AJL" />
    </div>
  );
}

/* ===================== 3. PETA EVOLUSI GENRE (river map) ===================== */
const DVX_MAP_GENRES = [
  { key: 'balada', label: 'Ballad', color: '#C9A84C', milestones: [
    { year: 1986, label: 'Dominasi Awal', desc: 'Balada mendominasi pentas AJL sejak edisi pertama, mencerminkan selera romantik era 80-an.', strength: 60 },
    { year: 1996, label: 'Penurunan', desc: 'Pengaruh balada mula merosot dengan kebangkitan irama tradisi dan fusion.', strength: 42 },
    { year: 2006, label: 'Keseimbangan', desc: 'Balada berkongsi pentas dengan rock dan tradisi dalam keseimbangan genre.', strength: 30 },
    { year: 2016, label: 'Kebangkitan Digital', desc: 'Balada kembali dominan dalam era streaming dan platform digital.', strength: 40 },
    { year: 2024, label: 'Kekal Utama', desc: 'Balada kekal sebagai genre terunggul di pentas AJL.', strength: 45 },
  ]},
  { key: 'rock', label: 'Rock', color: '#C0392B', milestones: [
    { year: 1986, label: 'Kehadiran Awal', desc: 'Rock mula hadir sebagai genre kedua paling popular di pentas AJL.', strength: 30 },
    { year: 1992, label: 'Puncak Populariti', desc: 'Rock mencapai puncak dengan kekuatan genre alternatif dan modern rock.', strength: 33 },
    { year: 2000, label: 'Penurunan', desc: 'Rock merosot dengan dominasi tradisi dan fusion di era ini.', strength: 20 },
    { year: 2010, label: 'Kebangkitan', desc: 'Rock kembali dengan kekuatan sederhana, berkongsi pentas dengan genre lain.', strength: 30 },
    { year: 2024, label: 'Konsisten', desc: 'Rock kekal sebagai genre konsisten dengan kekuatan stabil.', strength: 33 },
  ]},
  { key: 'tradisi', label: 'Tradisi / Fusion / Folk', color: '#2D8A7A', milestones: [
    { year: 1986, label: 'Marginal', desc: 'Tradisi hampir tidak hadir di pentas AJL pada era perintis.', strength: 10 },
    { year: 1996, label: 'Kebangkitan', desc: 'Irama Malaysia dan fusion mula naik dengan kekuatan baru.', strength: 30 },
    { year: 2000, label: 'Puncak Dominasi', desc: 'Tradisi mencapai dominasi tertinggi, mengatasi balada dan rock.', strength: 48 },
    { year: 2010, label: 'Penurunan', desc: 'Tradisi mula merosot dengan kemunculan hip hop dan keseimbangan genre.', strength: 30 },
    { year: 2024, label: 'Minoriti', desc: 'Tradisi menjadi genre minoriti dalam era digital.', strength: 11 },
  ]},
  { key: 'hiphop', label: 'Hip Hop', color: '#4A7B9D', milestones: [
    { year: 2006, label: 'Kemunculan', desc: 'Hip Hop mula hadir di pentas AJL sebagai genre baharu.', strength: 4 },
    { year: 2010, label: 'Pertumbuhan', desc: 'Hip Hop mula mendapat tempat dengan kekuatan berkembang.', strength: 10 },
    { year: 2016, label: 'Penstabilan', desc: 'Hip Hop menjadi genre tetap di pentas AJL.', strength: 10 },
    { year: 2024, label: 'Era Baharu', desc: 'Hip Hop kekal sebagai genre baharu yang konsisten.', strength: 11 },
  ]},
];
const DVX_MAP_DECADES = [
  { year: 1986, label: 'Perintis' }, { year: 1996, label: 'Prasasti' },
  { year: 2006, label: 'Revolusi' }, { year: 2016, label: 'Global' },
];
const DVX_MAP_YEARS = [1986, 1990, 1994, 1998, 2002, 2006, 2010, 2014, 2018, 2022];

function PetaEvolusiGenre() {
  const [selGenre, setSelGenre] = useStateX(null);
  const [selMile, setSelMile] = useStateX(null);

  const VB_W = 1000, VB_H = 440, X_START = 105, X_END = 960;
  const LANE_Y = [65, 155, 245, 335], TIMELINE_Y = 395;
  const yearToX = (y) => X_START + ((y - 1986) / (2024 - 1986)) * (X_END - X_START);
  const smoothTop = (pts) => {
    if (!pts.length) return '';
    let p = `M${pts[0].x},${pts[0].y}`;
    for (let i = 1; i < pts.length; i++) {
      const a = pts[i - 1], b = pts[i], mx = (a.x + b.x) / 2;
      p += ` C${mx},${a.y} ${mx},${b.y} ${b.x},${b.y}`;
    }
    return p;
  };
  const buildArea = (ms, baseY) => {
    const top = ms.map(m => ({ x: yearToX(m.year), y: baseY - m.strength / 2 }));
    const bot = ms.map(m => ({ x: yearToX(m.year), y: baseY + m.strength / 2 }));
    let p = smoothTop(top);
    p += ` L${bot[bot.length - 1].x},${bot[bot.length - 1].y}`;
    for (let i = bot.length - 2; i >= 0; i--) {
      const a = bot[i + 1], b = bot[i], mx = (a.x + b.x) / 2;
      p += ` C${mx},${a.y} ${mx},${b.y} ${b.x},${b.y}`;
    }
    return p + ' Z';
  };
  const opacityOf = (k) => !selGenre ? 1 : (selGenre === k ? 1 : 0.15);
  const reset = () => { setSelGenre(null); setSelMile(null); };

  return (
    <div style={DVX_CARD}>
      <DvxHeader eyebrow="Peta Evolusi Genre" title="Transformasi Bunyi AJL"
        desc="Peta interaktif yang menunjukkan perjalanan setiap genre muzik di pentas AJL dari 1986 hingga kini. Setiap sungai mewakili kekuatan sebuah genre merentasi masa. Klik pada aliran genre atau penanda bulat untuk meneroka transformasi bunyi dengan lebih mendalam."
        showReset={!!(selGenre || selMile)} onReset={reset} />

      {/* legend */}
      <div style={{ padding: '0.75rem 1.5rem', borderBottom: DVX_BORDER, background: '#0F0F0F', display: 'flex', flexWrap: 'wrap', gap: '0.5rem' }}>
        {DVX_MAP_GENRES.map(g => {
          const on = selGenre === g.key;
          return (
            <button key={g.key} onClick={() => { setSelGenre(on ? null : g.key); setSelMile(null); }} style={{
              display: 'inline-flex', alignItems: 'center', gap: '0.5rem', fontFamily: MONO, fontSize: '10px', letterSpacing: '0.05em',
              padding: '0.375rem 0.75rem', borderRadius: '999px', cursor: 'pointer',
              color: on ? g.color : '#9B9B9B', background: on ? `${g.color}15` : 'transparent',
              border: on ? `1px solid ${g.color}50` : DVX_BORDER }}>
              <span style={{ width: '8px', height: '8px', borderRadius: '50%', background: g.color }} />
              {g.label}
            </button>
          );
        })}
      </div>

      {/* svg map */}
      <div style={{ padding: '1rem 0.5rem 0.5rem', overflowX: 'auto' }}>
        <svg viewBox={`0 0 ${VB_W} ${VB_H}`} style={{ width: '100%', minWidth: '680px', height: 'auto', display: 'block' }}>
          <defs>
            {DVX_MAP_GENRES.map(g => (
              <linearGradient key={g.key} id={`dvx-map-${g.key}`} x1="0" y1="0" x2="0" y2="1">
                <stop offset="0%" stopColor={g.color} stopOpacity={0.7} />
                <stop offset="50%" stopColor={g.color} stopOpacity={0.35} />
                <stop offset="100%" stopColor={g.color} stopOpacity={0.1} />
              </linearGradient>
            ))}
          </defs>

          {DVX_MAP_DECADES.map(d => {
            const x = yearToX(d.year);
            return (
              <g key={d.year}>
                <line x1={x} y1={28} x2={x} y2={TIMELINE_Y} stroke="#2A2A2A" strokeWidth={1} strokeDasharray="4 4" />
                <text x={x} y={20} fill="#C9A84C" fontSize={9} fontFamily={MONO} textAnchor="middle" fontWeight={600} letterSpacing="1">{d.label.toUpperCase()}</text>
              </g>
            );
          })}

          <line x1={X_START} y1={TIMELINE_Y} x2={X_END} y2={TIMELINE_Y} stroke="#2A2A2A" strokeWidth={1} />
          {DVX_MAP_YEARS.map(y => (
            <text key={y} x={yearToX(y)} y={TIMELINE_Y + 18} fill="#9B9B9B" fontSize={9} fontFamily={MONO} textAnchor="middle">{y}</text>
          ))}

          {DVX_MAP_GENRES.map((g, gi) => {
            const baseY = LANE_Y[gi];
            const op = opacityOf(g.key);
            const yearRange = `${g.milestones[0].year}–${g.milestones[g.milestones.length - 1].year}`;
            return (
              <g key={g.key} style={{ opacity: op, transition: 'opacity 0.3s ease' }}>
                <text x={15} y={baseY - 4} fill={g.color} fontSize={11} fontFamily={MONO} fontWeight={600}>{g.label}</text>
                <text x={15} y={baseY + 8} fill="#666" fontSize={8} fontFamily={MONO}>{yearRange}</text>
                <path d={buildArea(g.milestones, baseY)} fill={`url(#dvx-map-${g.key})`} stroke={g.color} strokeWidth={1}
                  onClick={() => { setSelGenre(selGenre === g.key ? null : g.key); setSelMile(null); }} style={{ cursor: 'pointer' }} />
                {g.milestones.map((m, mi) => {
                  const x = yearToX(m.year), y = baseY;
                  const isSel = selMile && selMile.genre === g.key && selMile.index === mi;
                  return (
                    <g key={mi}>
                      {isSel && <circle cx={x} cy={y} r={11} fill="none" stroke={g.color} strokeWidth={1.5} strokeOpacity={0.4} />}
                      <circle cx={x} cy={y} r={isSel ? 6 : 4} fill={g.color} stroke="#161616" strokeWidth={2}
                        onClick={(e) => { e.stopPropagation(); setSelMile({ genre: g.key, index: mi }); }} style={{ cursor: 'pointer' }} />
                      <text x={x} y={y - 12} fill={g.color} fontSize={8} fontFamily={MONO} textAnchor="middle" fontWeight={600}>{m.strength}%</text>
                    </g>
                  );
                })}
              </g>
            );
          })}
        </svg>
      </div>

      {/* detail panel */}
      <div style={{ padding: '1rem 1.5rem 1.5rem', borderTop: DVX_BORDER }}>
        {selMile ? (() => {
          const g = DVX_MAP_GENRES.find(gg => gg.key === selMile.genre);
          const m = g.milestones[selMile.index];
          return (
            <div>
              <div style={{ display: 'flex', alignItems: 'center', gap: '0.5rem', marginBottom: '0.6rem' }}>
                <span style={{ width: '12px', height: '12px', borderRadius: '50%', background: g.color }} />
                <span style={{ fontFamily: MONO, fontSize: '10px', letterSpacing: '0.2em', textTransform: 'uppercase', color: g.color }}>{g.label}</span>
                <span style={{ color: '#666' }}>·</span>
                <span style={{ fontFamily: MONO, fontSize: '10px', letterSpacing: '0.1em', color: '#9B9B9B' }}>{m.year}</span>
              </div>
              <h4 style={{ fontFamily: HEAD, fontSize: '1.1rem', color: '#F5F0E8', margin: '0 0 0.5rem' }}>{m.label}</h4>
              <p style={{ fontFamily: SERIF, fontSize: '0.85rem', color: 'rgba(255,255,255,0.6)', lineHeight: 1.65, margin: '0 0 1rem', maxWidth: '42rem' }}>{m.desc}</p>
              <div style={{ display: 'flex', alignItems: 'center', gap: '0.75rem', maxWidth: '28rem' }}>
                <span style={{ fontFamily: MONO, fontSize: '10px', letterSpacing: '0.1em', color: '#9B9B9B', flexShrink: 0 }}>Kekuatan Genre</span>
                <div style={{ flex: 1, height: '8px', borderRadius: '999px', overflow: 'hidden', background: '#2A2A2A' }}>
                  <div style={{ width: `${m.strength}%`, height: '100%', background: g.color, borderRadius: '999px', transition: 'width 0.5s ease' }} />
                </div>
                <span style={{ fontFamily: MONO, fontSize: '0.75rem', fontWeight: 700, color: g.color, width: '2.5rem', textAlign: 'right' }}>{m.strength}%</span>
              </div>
            </div>
          );
        })() : (
          <p style={{ fontFamily: SERIF, fontSize: '0.75rem', color: 'rgba(255,255,255,0.4)', margin: 0 }}>Klik pada penanda bulat di peta untuk melihat butiran setiap titik perkembangan genre, atau pilih genre di atas untuk menyerlahkan perjalanannya.</p>
        )}
      </div>
    </div>
  );
}

Object.assign(window, { PetaEvolusiGenre, EvolusiAliranMuzik, EvolusiGenreMuzik });
