// MySkills v2 — karty hero (240px), sparkline jako main visual,
// hero number 72px serif, subtelny gradient kategorii, brak stref w tle.

// ————————————————————————————————————————————————————————
// Dane
// ————————————————————————————————————————————————————————

const MS_SKILLS = [
  {
    id: "weryfikacja",
    name: "Rozmowa z kandydatem — weryfikacja",
    category: "trudne",
    scenarios: [
      { name: "Senior — culture fit", attempts: [
          { score: 48, date: "7 mar" },
          { score: 52, date: "14 mar" },
        ]
      },
      { name: "Mid — kompetencje techniczne", attempts: [
          { score: 55, date: "20 mar" },
        ]
      },
    ],
  },
  {
    id: "feedback-trudny",
    name: "Trudny feedback korygujący",
    category: "feedback",
    scenarios: [
      { name: "Marek — spóźniony PR", attempts: [
          { score: 45, date: "3 mar" },
          { score: 52, date: "10 mar" },
          { score: 58, date: "18 mar" },
          { score: 71, date: "2 kwi" },
        ]
      },
      { name: "Anna — niski engagement", attempts: [
          { score: 65, date: "14 mar" },
          { score: 64, date: "22 mar" },
        ]
      },
    ],
  },
  {
    id: "opor",
    name: "Rozmowa z oporującym zespołem",
    category: "zmiana",
    scenarios: [
      { name: "Jakub — sceptyk AI", attempts: [
          { score: 58, date: "10 mar" },
          { score: 65, date: "22 mar" },
          { score: 71, date: "1 kwi" },
        ]
      },
    ],
  },
  {
    id: "dev-1on1",
    name: "Feedback rozwojowy 1:1",
    category: "feedback",
    scenarios: [
      { name: "Junior — brak inicjatywy", attempts: [
          { score: 62, date: "2 mar" },
          { score: 68, date: "9 mar" },
          { score: 72, date: "16 mar" },
        ]
      },
      { name: "Senior — pivot kariery", attempts: [
          { score: 75, date: "24 mar" },
          { score: 82, date: "5 kwi" },
        ]
      },
    ],
  },
  {
    id: "notebook-lm",
    name: "Wprowadzenie Notebook LM",
    category: "komunikacja",
    scenarios: [
      { name: "Sesja onboardingowa zespołu", attempts: [
          { score: 90, date: "15 kwi" },
        ]
      },
    ],
  },
];

// Kolory kategorii (gradient overlay + accent per skill)
const CATEGORY_COLORS = {
  feedback:    { hue: "267 85% 68%", hex: "#a78bfa", name: "Feedback" },
  leadership:  { hue: "189 94% 43%", hex: "#06b6d4", name: "Leadership" },
  zmiana:      { hue: "25 95% 53%",  hex: "#f97316", name: "Zmiana" },
  komunikacja: { hue: "217 91% 60%", hex: "#3b82f6", name: "Komunikacja" },
  trudne:      { hue: "0 72% 51%",   hex: "#dc2626", name: "Trudne rozmowy" },
  negocjacje:  { hue: "32 95% 44%",  hex: "#d97706", name: "Negocjacje" },
};

// Kolor stanu wyniku (linia/kropki/hero number)
const scoreColor = (v) => {
  if (v >= 80) return "#10b981"; // zielony
  if (v >= 60) return "#a78bfa"; // fioletowy (primary)
  if (v >= 40) return "#f59e0b"; // pomarańczowy
  return "#ef4444";              // czerwony
};

// ————————————————————————————————————————————————————————
// Helpers
// ————————————————————————————————————————————————————————

const flatAttempts = (sk) => sk.scenarios.flatMap(sc =>
  sc.attempts.map(a => ({ ...a, scenario: sc.name }))
);

const verbalStatus = (attempts) => {
  if (!attempts.length) return { kind: "none", text: "Jeszcze nie ćwiczone" };
  if (attempts.length === 1) {
    const v = attempts[0].score;
    if (v >= 85) return { kind: "mastered", text: `Biegłość — ${v}% w jedynej próbie` };
    return { kind: "first", text: "Pierwsza próba — zobaczmy co dalej" };
  }
  const scores = attempts.map(a => a.score);
  const last = scores[scores.length - 1];
  const prev = scores[scores.length - 2];
  const first = scores[0];
  const last3 = scores.slice(-3);
  const last3min = Math.min(...last3);

  if (last3.length === 3 && last3min >= 85) {
    return { kind: "mastered", text: `Opanowane — ostatnie 3 próby powyżej 85%` };
  }
  if (last - first >= 8) {
    return { kind: "rising", text: `Rośniesz — z ${first}% do ${last}% przez ${attempts.length} prób` };
  }
  if (prev - last >= 6) {
    return { kind: "drop", text: "Spadek — ostatnia próba słabsza niż poprzednia" };
  }
  if (last3.length === 3 && Math.max(...last3) - Math.min(...last3) <= 6) {
    const avg = Math.round(last3.reduce((a,b)=>a+b,0)/3);
    return { kind: "plateau", text: `Plateau — ostatnie 3 próby w okolicach ${avg}%` };
  }
  return { kind: "rising", text: `W rozwoju — ostatnio ${last}%` };
};

// Today = 17 kwi (hardcoded w v1)
const fakeDaysSince = (sk) => {
  const flat = flatAttempts(sk);
  if (!flat.length) return 999;
  const lastDate = flat[flat.length - 1].date;
  const months = { sty:0, lut:1, mar:2, kwi:3, maj:4 };
  const [d, m] = lastDate.split(" ");
  const day = parseInt(d, 10);
  const mo = months[m];
  if (mo === undefined) return 30;
  const todayDays = 3*30 + 17;
  const attemptDays = mo*30 + day;
  return Math.max(0, todayDays - attemptDays);
};

const contextCTA = (attempts, daysSinceLast) => {
  if (!attempts.length) return { label: "Zacznij", kind: "start" };
  const last = attempts[attempts.length - 1].score;
  const last3 = attempts.slice(-3).map(a => a.score);
  const mastered = last3.length === 3 && Math.min(...last3) >= 85;
  if (mastered) return { label: "Doskonal", kind: "refine" };
  if (daysSinceLast >= 30) return { label: "Wróć do tego", kind: "return" };
  if (last >= 85) return { label: "Doskonal", kind: "refine" };
  if (last >= 70) return { label: "Spróbuj w wariancie", kind: "variant" };
  return { label: "Wróć do tego", kind: "retry" };
};

const attentionScore = (sk) => {
  const flat = flatAttempts(sk);
  if (!flat.length) return -1;
  const last = flat[flat.length - 1].score;
  const days = fakeDaysSince(sk);
  const lowScorePenalty = Math.max(0, 70 - last);
  return lowScorePenalty * 2 + days;
};

// ————————————————————————————————————————————————————————
// Monotone cubic interpolation (smooth sparkline)
// Zwraca atrybut d dla <path>
// ————————————————————————————————————————————————————————

const monotonePath = (points) => {
  if (points.length < 2) return "";
  const n = points.length;
  // Tangenty (Fritsch-Carlson)
  const dx = [], dy = [], m = [];
  for (let i = 0; i < n - 1; i++) {
    dx.push(points[i+1].x - points[i].x);
    dy.push(points[i+1].y - points[i].y);
  }
  m[0] = dy[0] / dx[0];
  for (let i = 1; i < n - 1; i++) {
    const s1 = dy[i-1] / dx[i-1];
    const s2 = dy[i] / dx[i];
    m[i] = (s1 * s2 <= 0) ? 0 : (s1 + s2) / 2;
  }
  m[n-1] = dy[n-2] / dx[n-2];

  let d = `M ${points[0].x} ${points[0].y}`;
  for (let i = 0; i < n - 1; i++) {
    const h = dx[i];
    const x1 = points[i].x + h / 3;
    const y1 = points[i].y + m[i] * h / 3;
    const x2 = points[i+1].x - h / 3;
    const y2 = points[i+1].y - m[i+1] * h / 3;
    d += ` C ${x1} ${y1}, ${x2} ${y2}, ${points[i+1].x} ${points[i+1].y}`;
  }
  return d;
};

// ————————————————————————————————————————————————————————
// Główny ekran
// ————————————————————————————————————————————————————————

const MySkills = ({ setRoute, setActiveScenario }) => {
  const [sortBy, setSortBy] = React.useState("attention");
  const [variantFor, setVariantFor] = React.useState(null);
  const [expandedId, setExpandedId] = React.useState(null);

  const isMastered = (sk) => {
    const flat = flatAttempts(sk);
    if (!flat.length) return false;
    if (flat.length === 1) return flat[0].score >= 90;
    const last3 = flat.slice(-3).map(a => a.score);
    return last3.length === 3 && Math.min(...last3) >= 85;
  };

  const mastered = MS_SKILLS.filter(isMastered);
  const active = MS_SKILLS.filter(sk => !isMastered(sk));

  const sortFns = {
    attention: (a, b) => attentionScore(b) - attentionScore(a),
    recent:    (a, b) => fakeDaysSince(a) - fakeDaysSince(b),
    best: (a, b) => {
      const fa = flatAttempts(a).map(x=>x.score);
      const fb = flatAttempts(b).map(x=>x.score);
      return (fb.length?Math.max(...fb):0) - (fa.length?Math.max(...fa):0);
    },
    most: (a, b) => flatAttempts(b).length - flatAttempts(a).length,
  };
  const activeSorted = [...active].sort(sortFns[sortBy]);

  // Quick insight
  const insight = (() => {
    const risers = active.map(sk => {
      const flat = flatAttempts(sk);
      if (flat.length < 2) return null;
      const delta = flat[flat.length-1].score - flat[0].score;
      return { sk, delta };
    }).filter(x => x && x.delta >= 10).sort((a,b)=>b.delta - a.delta);
    const weakest = active.map(sk => {
      const flat = flatAttempts(sk);
      if (!flat.length) return null;
      return { sk, last: flat[flat.length-1].score };
    }).filter(x => x && x.last < 65).sort((a,b)=>a.last - b.last);
    if (risers.length && weakest.length) {
      return `Ostatnio rośniesz w ${risers[0].sk.name.toLowerCase()} (+${risers[0].delta}%). Warto popracować nad ${weakest[0].sk.name.toLowerCase()}.`;
    }
    return null;
  })();

  const goBriefing = (sk, overrideScenario) => {
    const skillId = "s-" + sk.id;
    if (typeof getScenarioForSkill === "function") {
      const sc = getScenarioForSkill(skillId, sk.name);
      if (sc && overrideScenario) sc.title = overrideScenario;
      if (sc && setActiveScenario) setActiveScenario(sc);
    }
    setRoute("briefing");
  };

  return (
    <div className="screen slide-up">
      <h1 className="page-title" style={{ marginBottom: 12 }}>
        Moje <em>umiejętności</em>
      </h1>
      <div className="subtitle" style={{ marginBottom: insight ? 16 : 32 }}>
        Wracaj do tych samych aż się przełamiesz, próbuj nowych wariantów żeby przetestować się w innym kontekście.
      </div>

      {insight && (
        <div style={{
          padding: "16px 22px",
          marginBottom: 36,
          borderLeft: "2px solid #a78bfa",
          background: "linear-gradient(90deg, rgba(167,139,250,.1) 0%, transparent 70%)",
          fontSize: 15,
          lineHeight: 1.5,
          color: "var(--fg-2)",
          fontStyle: "italic",
          fontFamily: "var(--serif)",
        }}>
          {insight}
        </div>
      )}

      {/* Sort header */}
      <div style={{
        display: "flex",
        justifyContent: "space-between",
        alignItems: "center",
        marginBottom: 24,
      }}>
        <div className="eyebrow" style={{ color: "var(--fg-3)" }}>
          W rozwoju · {activeSorted.length}
        </div>
        <MSSortDropdown value={sortBy} onChange={setSortBy} />
      </div>

      {/* Hero cards */}
      <div style={{ display: "flex", flexDirection: "column", gap: 20 }}>
        {activeSorted.map(sk => (
          <MSHeroCard
            key={sk.id}
            skill={sk}
            expanded={expandedId === sk.id}
            onToggle={() => setExpandedId(expandedId === sk.id ? null : sk.id)}
            onCTA={(cta) => {
              if (cta.kind === "variant") setVariantFor(sk.name);
              else goBriefing(sk);
            }}
            onScenarioReplay={(scName) => goBriefing(sk, scName)}
          />
        ))}
      </div>

      {/* Mastered */}
      {mastered.length > 0 && (
        <div style={{ marginTop: 56 }}>
          <div className="eyebrow" style={{ color: "var(--fg-3)", marginBottom: 16 }}>
            Opanowane · {mastered.length}
          </div>
          <div style={{ display: "flex", flexDirection: "column", gap: 10 }}>
            {mastered.map(sk => (
              <MSMasteredCompact
                key={sk.id}
                skill={sk}
                onRefresh={() => goBriefing(sk)}
              />
            ))}
          </div>
        </div>
      )}

      {/* Footer CTA */}
      <div style={{
        marginTop: 64,
        paddingTop: 32,
        borderTop: "1px solid var(--line)",
        textAlign: "center",
      }}>
        <button className="btn ghost" onClick={()=>setRoute("rpg-library")}>
          Znajdź nowe umiejętności do przećwiczenia <Icon name="arrow-right" size={13}/>
        </button>
      </div>

      <VariantModal
        open={!!variantFor}
        skillName={variantFor}
        onCancel={()=>setVariantFor(null)}
        onReady={()=>{ setVariantFor(null); setRoute("briefing"); }}
      />
    </div>
  );
};

// ————————————————————————————————————————————————————————
// Sort dropdown
// ————————————————————————————————————————————————————————

const MSSortDropdown = ({ value, onChange }) => {
  const [open, setOpen] = React.useState(false);
  const options = [
    { id: "attention", label: "Co wymaga uwagi" },
    { id: "recent",    label: "Ostatnio ćwiczone" },
    { id: "best",      label: "Najwyższy wynik" },
    { id: "most",      label: "Najwięcej prób" },
  ];
  const current = options.find(o => o.id === value);

  React.useEffect(() => {
    if (!open) return;
    const h = () => setOpen(false);
    setTimeout(() => document.addEventListener("click", h, { once: true }), 0);
    return () => document.removeEventListener("click", h);
  }, [open]);

  return (
    <div style={{ position: "relative" }}>
      <button
        className="btn ghost sm"
        onClick={(e) => { e.stopPropagation(); setOpen(o => !o); }}
        style={{ fontSize: 12, color: "var(--fg-3)" }}
      >
        Sortuj: {current.label} <Icon name={open?"chevron-down":"chevron-right"} size={11}/>
      </button>
      {open && (
        <div
          onClick={(e) => e.stopPropagation()}
          style={{
            position: "absolute",
            right: 0,
            top: "calc(100% + 4px)",
            background: "var(--bg-2)",
            border: "1px solid var(--line)",
            borderRadius: 8,
            padding: 4,
            zIndex: 10,
            minWidth: 200,
            boxShadow: "0 8px 24px rgba(0,0,0,.4)",
          }}
        >
          {options.map(o => (
            <button
              key={o.id}
              onClick={() => { onChange(o.id); setOpen(false); }}
              style={{
                display: "block",
                width: "100%",
                textAlign: "left",
                padding: "9px 12px",
                background: "none",
                border: "none",
                color: o.id === value ? "#a78bfa" : "var(--fg-2)",
                fontSize: 13,
                cursor: "pointer",
                borderRadius: 4,
              }}
              onMouseEnter={e => e.currentTarget.style.background = "var(--bg-3)"}
              onMouseLeave={e => e.currentTarget.style.background = "none"}
            >
              {o.label}
            </button>
          ))}
        </div>
      )}
    </div>
  );
};

// ————————————————————————————————————————————————————————
// Karta hero (240px)
// ————————————————————————————————————————————————————————

const MSHeroCard = ({ skill, expanded, onToggle, onCTA, onScenarioReplay }) => {
  const flat = flatAttempts(skill);
  const hasAttempts = flat.length > 0;
  const last = hasAttempts ? flat[flat.length - 1] : null;
  const days = fakeDaysSince(skill);
  const status = verbalStatus(flat);
  const cta = contextCTA(flat, days);
  const cat = CATEGORY_COLORS[skill.category] || CATEGORY_COLORS.feedback;
  const accent = hasAttempts ? scoreColor(last.score) : "#a78bfa";

  const [hover, setHover] = React.useState(false);

  const statusColor =
    status.kind === "drop" ? "#f59e0b" :
    status.kind === "mastered" ? "#10b981" :
    "rgba(255,255,255,.85)";

  return (
    <div
      onMouseEnter={()=>setHover(true)}
      onMouseLeave={()=>setHover(false)}
      style={{
        position: "relative",
        background: "#1a1a1a",
        border: `1px solid ${hover ? "rgba(255,255,255,.10)" : "rgba(255,255,255,.05)"}`,
        borderRadius: 16,
        overflow: "hidden",
        boxShadow: "0 4px 24px rgba(0,0,0,.3)",
        transition: "border-color .2s, transform .2s",
    }}>
      {/* Gradient overlay kategorii */}
      <div style={{
        position: "absolute",
        inset: 0,
        background: `linear-gradient(135deg, ${cat.hex}${hover ? "1f" : "14"} 0%, transparent 60%)`,
        pointerEvents: "none",
        transition: "background .2s",
      }}/>

      {/* Main content */}
      <div style={{
        position: "relative",
        display: "grid",
        gridTemplateColumns: "minmax(0, 4fr) minmax(0, 5fr) minmax(0, 3fr)",
        gap: 28,
        minHeight: 260,
        padding: "32px 32px",
        alignItems: "stretch",
      }}>
        {/* LEFT */}
        <div style={{ display: "flex", flexDirection: "column", gap: 10, minWidth: 0 }}>
          {/* Category chip */}
          <div style={{
            display: "inline-flex",
            alignItems: "center",
            gap: 6,
            fontSize: 10,
            letterSpacing: ".1em",
            textTransform: "uppercase",
            color: cat.hex,
            fontFamily: "var(--mono)",
            opacity: .85,
          }}>
            <span style={{ width: 6, height: 6, borderRadius: "50%", background: cat.hex }}/>
            {cat.name}
          </div>
          <div style={{
            fontFamily: "var(--serif)",
            fontSize: 24,
            lineHeight: 1.25,
            letterSpacing: "-.01em",
            color: "white",
          }}>
            {skill.name}
          </div>
          {hasAttempts && (
            <div style={{
              fontSize: 13,
              color: "rgba(255,255,255,.55)",
              lineHeight: 1.5,
            }}>
              Ostatnio: <em style={{ fontStyle: "italic", color: "rgba(255,255,255,.75)" }}>{last.scenario}</em> · {last.date}
            </div>
          )}
          <div style={{
            marginTop: 12,
            paddingTop: 12,
            borderTop: "1px solid rgba(255,255,255,.06)",
            fontSize: 14,
            color: statusColor,
            lineHeight: 1.5,
            fontWeight: 450,
          }}>
            {status.text}
          </div>
        </div>

        {/* CENTER: sparkline */}
        <div style={{ position: "relative", display: "flex", alignItems: "stretch" }}>
          <MSHeroSparkline attempts={flat} color={accent} />
        </div>

        {/* RIGHT: hero number + CTA */}
        <div style={{ display: "flex", flexDirection: "column", justifyContent: "center", alignItems: "flex-end" }}>
          {hasAttempts && (
            <div style={{ textAlign: "right", marginBottom: 20 }}>
              <div style={{
                fontFamily: "var(--serif)",
                fontSize: 72,
                lineHeight: 1,
                fontWeight: 500,
                letterSpacing: "-.02em",
                color: accent,
                display: "flex",
                alignItems: "baseline",
                gap: 4,
                justifyContent: "flex-end",
              }}>
                {last.score}
                <span style={{ fontSize: 28, opacity: .6 }}>%</span>
              </div>
              <div style={{
                marginTop: 8,
                fontSize: 11,
                letterSpacing: ".1em",
                textTransform: "uppercase",
                color: "rgba(255,255,255,.45)",
                fontFamily: "var(--mono)",
              }}>
                ostatni wynik
              </div>
            </div>
          )}
          <MSOutlineButton
            color={accent}
            onClick={(e) => { e.stopPropagation(); onCTA(cta); }}
          >
            {cta.label} →
          </MSOutlineButton>
          <button
            onClick={(e) => { e.stopPropagation(); onToggle(); }}
            style={{
              marginTop: 14,
              background: "none",
              border: "none",
              cursor: "pointer",
              color: "rgba(255,255,255,.4)",
              fontSize: 11,
              letterSpacing: ".08em",
              textTransform: "uppercase",
              fontFamily: "var(--mono)",
              display: "inline-flex",
              alignItems: "center",
              gap: 4,
              padding: 4,
            }}
            onMouseEnter={e => e.currentTarget.style.color = "rgba(255,255,255,.7)"}
            onMouseLeave={e => e.currentTarget.style.color = "rgba(255,255,255,.4)"}
          >
            <Icon name={expanded ? "chevron-down" : "chevron-right"} size={11}/>
            {expanded ? "zwiń" : "rozwiń"}
          </button>
        </div>
      </div>

      {/* Expanded */}
      {expanded && (
        <div style={{
          position: "relative",
          borderTop: "1px dashed rgba(255,255,255,.1)",
          padding: "24px 32px 28px",
        }}>
          <div style={{
            fontSize: 11,
            letterSpacing: ".1em",
            textTransform: "uppercase",
            color: "rgba(255,255,255,.45)",
            fontFamily: "var(--mono)",
            marginBottom: 16,
          }}>
            Scenariusze
          </div>
          <div>
            {skill.scenarios.map((sc, i) => (
              <MSScenarioRow
                key={i}
                scenario={sc}
                isLast={i === skill.scenarios.length - 1}
                onReplay={() => onScenarioReplay(sc.name)}
              />
            ))}
          </div>
          <div style={{
            marginTop: 20,
            fontSize: 13,
            color: "rgba(255,255,255,.5)",
            fontStyle: "italic",
            lineHeight: 1.5,
            fontFamily: "var(--serif)",
          }}>
            Każdy scenariusz to inny kontekst i inna postać. Powtarzaj aż każdy mieści się powyżej 80%.
          </div>
        </div>
      )}
    </div>
  );
};

// ————————————————————————————————————————————————————————
// Outline button — color matches accent
// ————————————————————————————————————————————————————————

const MSOutlineButton = ({ color, onClick, children }) => {
  const [hover, setHover] = React.useState(false);
  return (
    <button
      onClick={onClick}
      onMouseEnter={()=>setHover(true)}
      onMouseLeave={()=>setHover(false)}
      style={{
        height: 40,
        padding: "0 20px",
        borderRadius: 999,
        border: `1px solid ${color}`,
        background: hover ? color : "transparent",
        color: hover ? "#0a0a0a" : color,
        fontSize: 13,
        fontWeight: 500,
        letterSpacing: ".01em",
        cursor: "pointer",
        transition: "background .15s, color .15s",
        whiteSpace: "nowrap",
        fontFamily: "var(--sans)",
      }}>
      {children}
    </button>
  );
};

// ————————————————————————————————————————————————————————
// Hero sparkline (180px wysokości wewnętrznej, monotone cubic, glow)
// ————————————————————————————————————————————————————————

const MSHeroSparkline = ({ attempts, color }) => {
  const W = 440, H = 176;
  const PAD_X = 20, PAD_Y = 20;
  const n = attempts.length;
  const svgRef = React.useRef(null);
  const [hoveredIdx, setHoveredIdx] = React.useState(null);
  const [hoverPos, setHoverPos] = React.useState(null);

  if (n === 0) {
    return (
      <div style={{
        width: "100%",
        display: "flex",
        alignItems: "center",
        justifyContent: "center",
        color: "rgba(255,255,255,.3)",
        fontFamily: "var(--mono)",
        fontSize: 11,
        letterSpacing: ".1em",
      }}>
        — BRAK PRÓB —
      </div>
    );
  }

  // Pozycje w układzie SVG. Y: 0% w bottom, 100% w top. Padding 8% góra/dół.
  const yAt = (s) => PAD_Y + (H - 2*PAD_Y) * (1 - s/100);

  const pts = attempts.map((a, i) => ({
    x: n === 1 ? W/2 : PAD_X + (W - 2*PAD_X) * (i/(n-1)),
    y: yAt(a.score),
    s: a.score,
    date: a.date,
    scenario: a.scenario,
    idx: i,
  }));

  const linePath = n >= 2 ? monotonePath(pts) : "";
  const y80 = yAt(80);

  // Area path (glow pod linią)
  const areaPath = n >= 2
    ? linePath + ` L ${pts[n-1].x} ${H - PAD_Y + 24} L ${pts[0].x} ${H - PAD_Y + 24} Z`
    : "";

  const gradId = `ms-glow-${color.replace(/[^a-z0-9]/gi, "")}`;

  return (
    <div style={{
      position: "relative",
      width: "100%",
      height: H,
      alignSelf: "center",
    }}>
      <svg
        ref={svgRef}
        viewBox={`0 0 ${W} ${H}`}
        preserveAspectRatio="none"
        style={{ width: "100%", height: "100%", display: "block", overflow: "visible" }}
      >
        <defs>
          <linearGradient id={gradId} x1="0" y1="0" x2="0" y2="1">
            <stop offset="0%" stopColor={color} stopOpacity=".28"/>
            <stop offset="100%" stopColor={color} stopOpacity="0"/>
          </linearGradient>
          <filter id={`${gradId}-blur`} x="-50%" y="-50%" width="200%" height="200%">
            <feGaussianBlur stdDeviation="4"/>
          </filter>
        </defs>

        {/* 80% threshold line */}
        <line
          x1={0} y1={y80} x2={W} y2={y80}
          stroke="rgba(255,255,255,.15)"
          strokeWidth="1"
          strokeDasharray="3 4"
        />

        {/* Area fill (fade gradient) */}
        {n >= 2 && (
          <path d={areaPath} fill={`url(#${gradId})`}/>
        )}

        {/* Line */}
        {n >= 2 && (
          <path
            d={linePath}
            fill="none"
            stroke={color}
            strokeWidth="2"
            strokeLinecap="round"
            strokeLinejoin="round"
          />
        )}

        {/* Dots */}
        {pts.map((p, i) => {
          const isLast = i === pts.length - 1;
          const dotColor = scoreColor(p.s);
          return (
            <g key={i}>
              {isLast && (
                <>
                  {/* Glow */}
                  <circle
                    cx={p.x} cy={p.y}
                    r={16}
                    fill={dotColor}
                    opacity=".25"
                    filter={`url(#${gradId}-blur)`}
                  />
                  <circle
                    cx={p.x} cy={p.y}
                    r={10}
                    fill={dotColor}
                    opacity=".35"
                  />
                </>
              )}
              <circle
                cx={p.x} cy={p.y}
                r={isLast ? 6 : 4}
                fill={dotColor}
                stroke="#1a1a1a"
                strokeWidth={isLast ? 2 : 1.5}
                style={{ cursor: "pointer" }}
                onMouseEnter={(e) => {
                  const rect = svgRef.current.getBoundingClientRect();
                  setHoveredIdx(i);
                  setHoverPos({
                    x: (p.x / W) * rect.width,
                    y: (p.y / H) * rect.height,
                  });
                }}
                onMouseLeave={() => { setHoveredIdx(null); setHoverPos(null); }}
              />
            </g>
          );
        })}
      </svg>

      {/* Last dot label */}
      {pts.length > 0 && (() => {
        const last = pts[pts.length - 1];
        const xPct = (last.x / W) * 100;
        const yPct = (last.y / H) * 100;
        return (
          <div style={{
            position: "absolute",
            left: `${xPct}%`,
            top: `${yPct}%`,
            transform: "translate(-50%, calc(-100% - 16px))",
            background: "rgba(0,0,0,.75)",
            color: "white",
            fontSize: 12,
            fontFamily: "var(--mono)",
            padding: "3px 8px",
            borderRadius: 4,
            letterSpacing: ".02em",
            pointerEvents: "none",
            whiteSpace: "nowrap",
            border: `1px solid ${scoreColor(last.s)}40`,
          }}>
            {last.s}%
          </div>
        );
      })()}

      {/* Tooltip (hover any dot) */}
      {hoveredIdx !== null && hoverPos && (
        <div style={{
          position: "absolute",
          left: hoverPos.x,
          top: hoverPos.y,
          transform: `translate(${hoverPos.x > 220 ? "-105%" : "5%"}, -120%)`,
          background: "rgba(0,0,0,.92)",
          border: `1px solid ${scoreColor(pts[hoveredIdx].s)}50`,
          borderRadius: 6,
          padding: "8px 11px",
          fontSize: 11,
          lineHeight: 1.4,
          color: "rgba(255,255,255,.85)",
          pointerEvents: "none",
          zIndex: 5,
          boxShadow: "0 6px 18px rgba(0,0,0,.5)",
          whiteSpace: "nowrap",
          minWidth: 160,
        }}>
          <div style={{ fontFamily: "var(--mono)", fontSize: 10, letterSpacing: ".06em", color: "rgba(255,255,255,.5)" }}>
            PRÓBA {pts[hoveredIdx].idx + 1}
          </div>
          <div style={{
            fontFamily: "var(--serif)",
            fontSize: 16,
            color: scoreColor(pts[hoveredIdx].s),
            marginTop: 2,
          }}>
            {pts[hoveredIdx].s}%
          </div>
          <div style={{ marginTop: 3 }}>
            {pts[hoveredIdx].date} · <em style={{ fontStyle: "italic" }}>{pts[hoveredIdx].scenario}</em>
          </div>
        </div>
      )}
    </div>
  );
};

// ————————————————————————————————————————————————————————
// Scenario row (expanded)
// ————————————————————————————————————————————————————————

const MSScenarioRow = ({ scenario, isLast, onReplay }) => {
  const a = scenario.attempts;
  const empty = a.length === 0;
  const last = empty ? null : a[a.length - 1].score;
  const lastDate = empty ? null : a[a.length - 1].date;
  const accent = empty ? "rgba(255,255,255,.25)" : scoreColor(last);

  return (
    <div style={{
      display: "grid",
      gridTemplateColumns: "minmax(0, 4fr) minmax(0, 4fr) minmax(0, 2fr)",
      gap: 24,
      alignItems: "center",
      padding: "14px 0",
      borderBottom: isLast ? "none" : "1px solid rgba(255,255,255,.06)",
    }}>
      <div>
        <div style={{ fontSize: 14, color: "rgba(255,255,255,.9)", marginBottom: 3 }}>
          {scenario.name}
        </div>
        <div style={{
          fontSize: 11,
          fontFamily: "var(--mono)",
          color: "rgba(255,255,255,.4)",
          letterSpacing: ".06em",
        }}>
          {empty
            ? "NIE PODJĘTY"
            : `${a.length} PRÓB${a.length === 1 ? "A" : a.length < 5 ? "Y" : ""} · OSTATNIO ${lastDate}`}
        </div>
      </div>
      <div style={{ display: "flex", alignItems: "center" }}>
        <MSMiniSparkline attempts={a} color={accent} />
      </div>
      <div style={{ display: "flex", alignItems: "center", justifyContent: "flex-end", gap: 16 }}>
        {!empty && (
          <div style={{
            fontFamily: "var(--serif)",
            fontSize: 20,
            color: accent,
            lineHeight: 1,
          }}>
            {last}%
          </div>
        )}
        <button
          onClick={onReplay}
          style={{
            background: "none",
            border: "none",
            cursor: "pointer",
            color: "rgba(255,255,255,.55)",
            fontSize: 12,
            fontFamily: "var(--sans)",
            padding: 0,
          }}
          onMouseEnter={e => e.currentTarget.style.color = "white"}
          onMouseLeave={e => e.currentTarget.style.color = "rgba(255,255,255,.55)"}
        >
          {empty ? "Spróbuj →" : "Powtórz →"}
        </button>
      </div>
    </div>
  );
};

const MSMiniSparkline = ({ attempts, color }) => {
  const W = 140, H = 40, PAD_X = 4, PAD_Y = 4;
  const n = attempts.length;
  if (n === 0) return (
    <div style={{ color: "rgba(255,255,255,.3)", fontSize: 11, fontFamily: "var(--mono)" }}>—</div>
  );
  if (n === 1) {
    const v = attempts[0].score;
    const x = PAD_X + (W - 2*PAD_X) * (v/100);
    return (
      <svg width={W} height={H}>
        <line x1={PAD_X} y1={H-6} x2={W-PAD_X} y2={H-6} stroke="rgba(255,255,255,.1)" strokeWidth="1"/>
        <circle cx={x} cy={H-6} r="4" fill={color}/>
      </svg>
    );
  }
  const pts = attempts.map((a, i) => ({
    x: PAD_X + (W - 2*PAD_X) * (i/(n-1)),
    y: PAD_Y + (H - 2*PAD_Y) * (1 - a.score/100),
    s: a.score,
  }));
  const path = monotonePath(pts);
  return (
    <svg width={W} height={H}>
      <path d={path} fill="none" stroke={color} strokeWidth="1.5" strokeLinecap="round"/>
      {pts.map((p, i) => (
        <circle
          key={i}
          cx={p.x} cy={p.y}
          r={i === pts.length - 1 ? 3 : 2}
          fill={scoreColor(p.s)}
        />
      ))}
    </svg>
  );
};

// ————————————————————————————————————————————————————————
// Mastered compact card (80px)
// ————————————————————————————————————————————————————————

const MSMasteredCompact = ({ skill, onRefresh }) => {
  const flat = flatAttempts(skill);
  const best = Math.max(...flat.map(a => a.score));
  const cat = CATEGORY_COLORS[skill.category] || CATEGORY_COLORS.feedback;
  const [hover, setHover] = React.useState(false);

  return (
    <div
      onMouseEnter={()=>setHover(true)}
      onMouseLeave={()=>setHover(false)}
      style={{
        position: "relative",
        background: "#151515",
        border: `1px solid ${hover ? "rgba(16,185,129,.25)" : "rgba(255,255,255,.04)"}`,
        borderRadius: 12,
        overflow: "hidden",
        transition: "border-color .2s",
      }}>
      <div style={{
        position: "absolute", inset: 0,
        background: `linear-gradient(135deg, ${cat.hex}08 0%, transparent 50%)`,
        pointerEvents: "none",
      }}/>
      <div style={{
        position: "relative",
        display: "grid",
        gridTemplateColumns: "minmax(0, 5fr) minmax(0, 3fr) auto auto",
        gap: 24,
        height: 80,
        padding: "0 24px",
        alignItems: "center",
      }}>
        <div>
          <div style={{
            fontFamily: "var(--serif)",
            fontSize: 17,
            color: "rgba(255,255,255,.82)",
            letterSpacing: "-.005em",
            marginBottom: 4,
          }}>
            {skill.name}
          </div>
          <div style={{
            fontSize: 11,
            fontFamily: "var(--mono)",
            color: "rgba(255,255,255,.4)",
            letterSpacing: ".06em",
          }}>
            NAJLEPSZY {best}% · {flat.length} {flat.length === 1 ? "PRÓBA" : "PRÓB"}
          </div>
        </div>
        <div style={{ display: "flex", alignItems: "center" }}>
          <MSMiniSparkline attempts={flat} color="#10b981"/>
        </div>
        <div style={{
          display: "inline-flex",
          alignItems: "center",
          gap: 6,
          fontSize: 10,
          letterSpacing: ".12em",
          textTransform: "uppercase",
          color: "#10b981",
          padding: "5px 10px",
          border: "1px solid rgba(16,185,129,.35)",
          borderRadius: 999,
          fontFamily: "var(--mono)",
        }}>
          ✓ Opanowane
        </div>
        <button
          onClick={onRefresh}
          style={{
            background: "none",
            border: "none",
            cursor: "pointer",
            color: "rgba(255,255,255,.5)",
            fontSize: 12,
            padding: "6px 4px",
          }}
          onMouseEnter={e => e.currentTarget.style.color = "white"}
          onMouseLeave={e => e.currentTarget.style.color = "rgba(255,255,255,.5)"}
        >
          Odśwież →
        </button>
      </div>
    </div>
  );
};

Object.assign(window, { MySkills });
