Barbie’s Heat Map

import React, { useState, useMemo } from "react";

// Sample sector data — swap in a live feed later (Massive/TradingView/etc.)
const SECTORS = [
  { name: "Technology", ticker: "XLK", weight: 31, perf: 2.76, relVol: 1.42, iv: 24, week: 3.4, relStr: 99 },
  { name: "Financials", ticker: "XLF", weight: 13, perf: -0.20, relVol: 0.95, iv: 18, week: 0.8, relStr: 58 },
  { name: "Health Care", ticker: "XLV", weight: 11, perf: -1.29, relVol: 1.05, iv: 16, week: -1.9, relStr: 34 },
  { name: "Consumer Disc.", ticker: "XLY", weight: 11, perf: 0.14, relVol: 1.18, iv: 22, week: 1.1, relStr: 61 },
  { name: "Communication", ticker: "XLC", weight: 9, perf: -0.70, relVol: 1.10, iv: 21, week: 0.5, relStr: 52 },
  { name: "Industrials", ticker: "XLI", weight: 8, perf: 1.35, relVol: 1.22, iv: 19, week: 2.0, relStr: 74 },
  { name: "Consumer Stap.", ticker: "XLP", weight: 6, perf: -1.54, relVol: 0.88, iv: 13, week: -2.2, relStr: 21 },
  { name: "Energy", ticker: "XLE", weight: 4, perf: -0.88, relVol: 1.35, iv: 27, week: -0.6, relStr: 41 },
  { name: "Utilities", ticker: "XLU", weight: 3, perf: -1.48, relVol: 0.79, iv: 14, week: -1.4, relStr: 25 },
  { name: "Materials", ticker: "XLB", weight: 2, perf: 0.34, relVol: 1.02, iv: 20, week: 1.5, relStr: 65 },
  { name: "Real Estate", ticker: "XLRE", weight: 2, perf: -1.98, relVol: 0.91, iv: 17, week: -2.8, relStr: 12 },
];

const METRICS = [
  { key: "perf", label: "Performance", suffix: "%", domain: [-2, 2] },
  { key: "relVol", label: "Rel. Volume", suffix: "x", domain: [0.5, 1.6] },
  { key: "iv", label: "Volatility", suffix: "%", domain: [10, 30] },
];

function colorFor(value, domain) {
  const [lo, hi] = domain;
  const mid = (lo + hi) / 2;
  const t = Math.max(-1, Math.min(1, (value - mid) / (mid - lo)));
  // negative -> deep magenta/plum, positive -> gold/lime edge, near-zero -> charcoal
  if (t >= 0) {
    // 0 -> charcoal, 1 -> gold
    const g1 = [26, 24, 28];
    const g2 = [212, 175, 55];
    const c = g1.map((v, i) => Math.round(v + (g2[i] - v) * t));
    return `rgb(${c.join(",")})`;
  } else {
    const at = -t;
    const g1 = [26, 24, 28];
    const g2 = [255, 45, 120];
    const c = g1.map((v, i) => Math.round(v + (g2[i] - v) * at));
    return `rgb(${c.join(",")})`;
  }
}

function textColorFor(value, domain) {
  const [lo, hi] = domain;
  const mid = (lo + hi) / 2;
  const t = Math.abs((value - mid) / (mid - lo));
  return t > 0.45 ? "#0d0d0d" : "#f5f1ea";
}

export default function BarbieHeatmap() {
  const [metric, setMetric] = useState("perf");
  const [selected, setSelected] = useState(SECTORS[0].ticker);

  const activeMetric = METRICS.find((m) => m.key === metric);
  const selectedSector = SECTORS.find((s) => s.ticker === selected);

  const sorted = useMemo(
    () => [...SECTORS].sort((a, b) => b.weight - a.weight),
    []
  );

  const flowingIn = [...SECTORS].sort((a, b) => b.perf - a.perf).slice(0, 4);
  const flowingOut = [...SECTORS].sort((a, b) => a.perf - b.perf).slice(0, 4);

  return (
    <div
      style={{
        minHeight: "100vh",
        background: "#0d0d0d",
        color: "#f5f1ea",
        fontFamily: "'DM Sans', ui-sans-serif, system-ui, sans-serif",
        padding: "28px 18px 60px",
      }}
    >
      <style>{`
        @import url('https://fonts.googleapis.com/css2?family=Playfair+Display:wght@600;700;900&family=DM+Sans:wght@400;500;700&display=swap');
        .corner { position: relative; }
        .corner::before, .corner::after {
          content: ""; position: absolute; width: 10px; height: 10px;
          border-color: #D4AF37; border-style: solid; opacity: 0.75;
        }
        .corner::before { top: -1px; left: -1px; border-width: 2px 0 0 2px; }
        .corner::after { bottom: -1px; right: -1px; border-width: 0 2px 2px 0; }
        .tile { transition: transform 0.15s ease, box-shadow 0.15s ease; cursor: pointer; }
        .tile:hover { transform: translateY(-2px); box-shadow: 0 6px 24px rgba(255,45,120,0.25); }
        .tab-btn { transition: color 0.15s ease, border-color 0.15s ease; }
        ::-webkit-scrollbar { width: 6px; height: 6px; }
        ::-webkit-scrollbar-thumb { background: #ff2d78; border-radius: 4px; }
      `}</style>

      <div style={{ maxWidth: 980, margin: "0 auto" }}>
        {/* Header */}
        <div style={{ marginBottom: 22 }}>
          <div
            style={{
              fontFamily: "'DM Sans', sans-serif",
              fontSize: 11,
              letterSpacing: "0.18em",
              textTransform: "uppercase",
              color: "#ff2d78",
              marginBottom: 6,
            }}
          >
            Trader Barbie · Command Center
          </div>
          <h1
            style={{
              fontFamily: "'Playfair Display', serif",
              fontWeight: 900,
              fontSize: "clamp(28px, 5vw, 42px)",
              margin: 0,
              lineHeight: 1.05,
            }}
          >
            The Market, Mapped
          </h1>
          <p style={{ color: "#a8a29e", fontSize: 14, marginTop: 8, maxWidth: 520 }}>
            Block size is sector weight. Color is the move. Tap a sector for the why
            behind the color.
          </p>
        </div>

        {/* Tabs */}
        <div
          style={{
            display: "flex",
            gap: 4,
            borderBottom: "1px solid #262626",
            marginBottom: 18,
          }}
        >
          {METRICS.map((m) => (
            <button
              key={m.key}
              onClick={() => setMetric(m.key)}
              className="tab-btn"
              style={{
                background: "none",
                border: "none",
                borderBottom:
                  metric === m.key ? "2px solid #FF2D78" : "2px solid transparent",
                color: metric === m.key ? "#f5f1ea" : "#78716c",
                fontFamily: "'DM Sans', sans-serif",
                fontWeight: 700,
                fontSize: 13,
                padding: "8px 14px",
                cursor: "pointer",
              }}
            >
              {m.label}
            </button>
          ))}
        </div>

        {/* Heatmap grid */}
        <div
          className="corner"
          style={{
            display: "grid",
            gridTemplateColumns: "repeat(6, 1fr)",
            gridAutoRows: "70px",
            gap: 3,
            padding: 4,
            background: "#141212",
            border: "1px solid #262626",
          }}
        >
          {sorted.map((s) => {
            const span = Math.max(1, Math.round((s.weight / 31) * 3));
            const value = s[metric];
            return (
              <div
                key={s.ticker}
                className="tile"
                onClick={() => setSelected(s.ticker)}
                style={{
                  gridColumn: `span ${Math.min(span + 1, 3)}`,
                  gridRow: `span ${s.weight > 15 ? 2 : 1}`,
                  background: colorFor(value, activeMetric.domain),
                  color: textColorFor(value, activeMetric.domain),
                  border:
                    selected === s.ticker
                      ? "2px solid #D4AF37"
                      : "1px solid rgba(0,0,0,0.2)",
                  padding: "8px 10px",
                  display: "flex",
                  flexDirection: "column",
                  justifyContent: "space-between",
                }}
              >
                <div>
                  <div style={{ fontWeight: 700, fontSize: 12.5, lineHeight: 1.15 }}>
                    {s.name}
                  </div>
                  <div style={{ fontSize: 10.5, opacity: 0.75, fontWeight: 500 }}>
                    {s.ticker}
                  </div>
                </div>
                <div style={{ fontFamily: "'Playfair Display', serif", fontWeight: 700, fontSize: 15 }}>
                  {value > 0 ? "+" : ""}
                  {value.toFixed(2)}
                  {activeMetric.suffix}
                </div>
              </div>
            );
          })}
        </div>

        {/* Legend */}
        <div style={{ display: "flex", alignItems: "center", gap: 10, marginTop: 10, fontSize: 11, color: "#78716c" }}>
          <span>{activeMetric.domain[0]}{activeMetric.suffix}</span>
          <div
            style={{
              flex: 1,
              height: 6,
              background: "linear-gradient(90deg, #ff2d78, #1a181c, #D4AF37)",
              borderRadius: 3,
            }}
          />
          <span>+{activeMetric.domain[1]}{activeMetric.suffix}</span>
        </div>

        {/* Detail panel */}
        {selectedSector && (
          <div
            className="corner"
            style={{
              marginTop: 26,
              background: "#141212",
              border: "1px solid #262626",
              padding: "20px 22px",
            }}
          >
            <div style={{ fontSize: 11, letterSpacing: "0.14em", textTransform: "uppercase", color: "#D4AF37" }}>
              Selected sector · {selectedSector.ticker}
            </div>
            <h2
              style={{
                fontFamily: "'Playfair Display', serif",
                fontWeight: 700,
                fontSize: 26,
                margin: "4px 0 4px",
              }}
            >
              {selectedSector.name}
            </h2>
            <div
              style={{
                fontFamily: "'Playfair Display', serif",
                fontWeight: 900,
                fontSize: 22,
                color: selectedSector.perf >= 0 ? "#D4AF37" : "#ff2d78",
                marginBottom: 10,
              }}
            >
              {selectedSector.perf > 0 ? "+" : ""}
              {selectedSector.perf.toFixed(2)}%
            </div>
            <p style={{ fontSize: 13.5, color: "#c9c4bc", maxWidth: 560, lineHeight: 1.5 }}>
              {selectedSector.perf >= 0.5
                ? `Among the day's stronger groups, up ${selectedSector.perf.toFixed(2)}% on ${selectedSector.relVol >= 1.1 ? "above-average" : "lighter-than-usual"} volume. One-week trend ${selectedSector.week > 0 ? "+" : ""}${selectedSector.week.toFixed(1)}%.`
                : selectedSector.perf <= -0.5
                ? `Among the day's weaker groups, down ${Math.abs(selectedSector.perf).toFixed(2)}% on ${selectedSector.relVol >= 1.1 ? "above-average" : "lighter-than-usual"} volume. One-week trend ${selectedSector.week > 0 ? "+" : ""}${selectedSector.week.toFixed(1)}%.`
                : `Roughly flat on the day at ${selectedSector.perf.toFixed(2)}%, trading on ${selectedSector.relVol >= 1.1 ? "above-average" : "lighter-than-usual"} volume. One-week trend ${selectedSector.week > 0 ? "+" : ""}${selectedSector.week.toFixed(1)}%.`}
            </p>

            <div style={{ display: "flex", gap: 26, marginTop: 14, flexWrap: "wrap" }}>
              {[
                ["1D", `${selectedSector.perf > 0 ? "+" : ""}${selectedSector.perf.toFixed(2)}%`],
                ["1W", `${selectedSector.week > 0 ? "+" : ""}${selectedSector.week.toFixed(1)}%`],
                ["Rel Str", selectedSector.relStr],
              ].map(([label, val]) => (
                <div key={label}>
                  <div style={{ fontSize: 10.5, color: "#78716c", letterSpacing: "0.1em", textTransform: "uppercase" }}>
                    {label}
                  </div>
                  <div style={{ fontFamily: "'Playfair Display', serif", fontWeight: 700, fontSize: 18 }}>
                    {val}
                  </div>
                </div>
              ))}
            </div>

            {/* Rotation */}
            <div style={{ display: "grid", gridTemplateColumns: "1fr 1fr", gap: 18, marginTop: 22 }}>
              <div>
                <div style={{ fontSize: 11, letterSpacing: "0.1em", textTransform: "uppercase", color: "#D4AF37", marginBottom: 8 }}>
                  Money flowing in
                </div>
                {flowingIn.map((s) => (
                  <div key={s.ticker} style={{ display: "flex", justifyContent: "space-between", fontSize: 13, padding: "5px 0", borderBottom: "1px solid #1f1f1f" }}>
                    <span>{s.name}</span>
                    <span style={{ color: "#D4AF37", fontWeight: 700 }}>+{s.perf.toFixed(2)}%</span>
                  </div>
                ))}
              </div>
              <div>
                <div style={{ fontSize: 11, letterSpacing: "0.1em", textTransform: "uppercase", color: "#ff2d78", marginBottom: 8 }}>
                  Money flowing out
                </div>
                {flowingOut.map((s) => (
                  <div key={s.ticker} style={{ display: "flex", justifyContent: "space-between", fontSize: 13, padding: "5px 0", borderBottom: "1px solid #1f1f1f" }}>
                    <span>{s.name}</span>
                    <span style={{ color: "#ff2d78", fontWeight: 700 }}>{s.perf.toFixed(2)}%</span>
                  </div>
                ))}
              </div>
            </div>
          </div>
        )}

        <div style={{ marginTop: 20, fontSize: 11, color: "#57534e" }}>
          Sample data for layout preview — wire up a live quotes feed to replace it. Educational purposes only, not financial advice.
        </div>
      </div>
    </div>
  );
}