// Slide compositions for the V1 dashboard deck.
// Each slide is 1920×1080. SlideFrame provides shared header + footer chrome.

const SlideFrame = ({ eyebrow, title, sub, children, footer = true, slideIndex, totalSlides, periodLabel, headerRight, padding = "56px 80px 32px" }) => (
  <div data-screen-label={`${String(slideIndex).padStart(2, "0")} ${title || "Slide"}`}
    style={{
      width: 1920, height: 1080,
      background: "var(--bg-base)",
      color: "#000",
      fontFamily: "var(--font-body)",
      padding,
      display: "flex", flexDirection: "column",
      overflow: "hidden",
      boxSizing: "border-box",
    }}>
    {/* Slide header */}
    {(eyebrow || title) && (
      <header style={{ display: "flex", justifyContent: "space-between", alignItems: "flex-end", gap: 24, marginBottom: 32, flexShrink: 0 }}>
        <div>
          {eyebrow && (
            <div style={{
              fontSize: 24, fontWeight: 700, letterSpacing: ".12em", textTransform: "uppercase",
              color: "var(--grey-700)", marginBottom: 14,
              fontFamily: "var(--font-num)",
            }}>{eyebrow}</div>
          )}
          {title && (
            <h1 style={{
              fontFamily: "var(--font-display)", fontWeight: 800, fontSize: 52,
              letterSpacing: "-0.015em", margin: 0, color: "#000", lineHeight: 1.05,
              maxWidth: 1300,
            }}>{title}</h1>
          )}
          {sub && (
            <p style={{ fontSize: 24, color: "var(--grey-700)", marginTop: 16, marginBottom: 0, fontWeight: 500, maxWidth: 1200, lineHeight: 1.4 }}>{sub}</p>
          )}
        </div>
        {headerRight && <div style={{ flexShrink: 0 }}>{headerRight}</div>}
      </header>
    )}

    {/* Slide content */}
    <div style={{ flex: 1, minHeight: 0, display: "flex", flexDirection: "column" }}>
      {children}
    </div>

    {/* Slide footer */}
    {footer && (
      <footer style={{ display: "flex", justifyContent: "space-between", alignItems: "center", marginTop: 24, paddingTop: 20, borderTop: "1px solid var(--grey-100)", flexShrink: 0, fontSize: 24, color: "var(--grey-700)", fontWeight: 500 }}>
        <div style={{ display: "flex", alignItems: "center", gap: 18 }}>
          <img src="ds/myinvestor-logo.png" alt="MyInvestor" style={{ height: 22 }} />
          <span style={{ color: "var(--grey-400)" }}>·</span>
          <span>UX Insights · General Review</span>
        </div>
        <div style={{ display: "flex", alignItems: "center", gap: 18 }}>
          <span>{periodLabel}</span>
          <span style={{ color: "var(--grey-400)" }}>·</span>
          <span style={{ fontFamily: "var(--font-num)", fontVariantNumeric: "tabular-nums", color: "#000", fontWeight: 700 }}>
            {String(slideIndex).padStart(2, "0")} / {String(totalSlides).padStart(2, "0")}
          </span>
        </div>
      </footer>
    )}
  </div>
);

// ─── 01 · Portada ───────────────────────────────────────────────────
const SlideCover = ({ data, slideIndex, totalSlides }) => (
  <div data-screen-label="01 Portada"
    style={{
      width: 1920, height: 1080, background: "#fff",
      fontFamily: "var(--font-body)", color: "#000",
      padding: "80px 96px", boxSizing: "border-box",
      display: "flex", flexDirection: "column", justifyContent: "space-between",
      position: "relative", overflow: "hidden",
    }}>
    {/* Subtle brand-blue tint top-left */}
    <div aria-hidden style={{
      position: "absolute", top: -300, left: -200, width: 900, height: 900,
      background: "radial-gradient(circle, rgba(0,70,222,.08) 0%, rgba(0,70,222,0) 70%)",
      pointerEvents: "none",
    }} />

    <header style={{ position: "relative", display: "flex", justifyContent: "space-between", alignItems: "flex-start" }}>
      <img src="ds/myinvestor-logo.png" alt="MyInvestor" style={{ height: 34 }} />
      <span style={{ fontSize: 24, fontWeight: 700, color: "var(--grey-700)", textTransform: "uppercase", letterSpacing: ".12em", fontFamily: "var(--font-num)" }}>
        General Review · Semanal
      </span>
    </header>

    <main style={{ position: "relative" }}>
      <div style={{
        display: "inline-flex", alignItems: "center", gap: 8,
        padding: "10px 20px", borderRadius: 999,
        background: "var(--brand-blue-soft)", color: "var(--brand-blue)",
        fontSize: 24, fontWeight: 800, letterSpacing: ".06em", textTransform: "uppercase",
        marginBottom: 36,
      }}>
        UX Insights
      </div>
      <h1 style={{
        fontFamily: "var(--font-display)", fontWeight: 900, fontSize: 132,
        letterSpacing: "-0.025em", margin: 0, color: "#000", lineHeight: 0.95,
        maxWidth: 1500,
      }}>KPIs de experiencia</h1>
      <p style={{ fontFamily: "var(--font-display)", fontSize: 48, color: "var(--grey-700)", marginTop: 28, marginBottom: 0, fontWeight: 500, lineHeight: 1.15 }}>
        {data.period.range}
      </p>
      <p style={{ fontSize: 26, color: "var(--grey-700)", marginTop: 28, fontWeight: 500, maxWidth: 1100, lineHeight: 1.45 }}>
        Comparado con la semana anterior ({data.period.prevRange}). Fuentes: App Store, Google Play y Trustpilot.
      </p>
    </main>

    <footer style={{ position: "relative", display: "flex", justifyContent: "space-between", alignItems: "flex-end", fontSize: 24, color: "var(--grey-700)", fontWeight: 500 }}>
      <div>
        <div style={{ fontSize: 22, fontWeight: 700, color: "var(--grey-400)", textTransform: "uppercase", letterSpacing: ".12em", marginBottom: 10 }}>Preparado por</div>
        <div style={{ fontSize: 26, fontWeight: 800, color: "#000" }}>Equipo de Diseño · UX MyInvestor</div>
      </div>
      <div>
        <div style={{ fontSize: 22, fontWeight: 700, color: "var(--grey-400)", textTransform: "uppercase", letterSpacing: ".12em", marginBottom: 10 }}>Actualizado</div>
        <div style={{ fontSize: 24, fontWeight: 700, color: "#000", fontFamily: "var(--font-num)" }}>{data.generatedAt}</div>
      </div>
      <span style={{ fontFamily: "var(--font-num)", fontSize: 24, fontWeight: 700, color: "var(--grey-400)" }}>
        {String(slideIndex).padStart(2, "0")} / {String(totalSlides).padStart(2, "0")}
      </span>
    </footer>
  </div>
);

// ─── 02 · Rating de las stores ─────────────────────────────────────
const SlideStoreRating = ({ data, slideIndex, totalSlides, periodLabel }) => (
  <SlideFrame
    eyebrow="01 · Rating de las stores"
    title="Nota global de la app en cada tienda"
    sub="Nota actual, evolución diaria de las últimas 2 semanas y volumen de valoraciones / descargas frente a la semana anterior."
    slideIndex={slideIndex} totalSlides={totalSlides} periodLabel={periodLabel}
  >
    <div style={{ display: "grid", gridTemplateColumns: `repeat(${data.stores.length}, 1fr)`, gap: 24, flex: 1 }}>
      {data.stores.map(s => <SlideStoreCard key={s.id} store={s} />)}
    </div>
  </SlideFrame>
);

const SlideStoreCard = ({ store }) => {
  const dRating = +(store.rating - store.ratingPrev).toFixed(1);
  const sparkValues = store.fullHistory ? store.fullHistory.map(h => h.rating) : store.daily;
  const sparkFirst  = store.fullHistory?.[0]?.date ?? null;
  const sparkLast   = store.fullHistory?.[store.fullHistory.length - 1]?.date ?? null;
  return (
    <div style={{
      background: "#fff", border: "1px solid var(--grey-100)", borderRadius: 24,
      padding: 36, display: "flex", flexDirection: "column", gap: 28,
    }}>
      <div style={{ display: "flex", alignItems: "center", justifyContent: "space-between", gap: 16 }}>
        <div style={{ display: "flex", alignItems: "center", gap: 16 }}>
          <div style={{ transform: "scale(1.35)", transformOrigin: "left center" }}>
            <StoreLogo id={store.id} />
          </div>
          <div style={{ marginLeft: 16 }}>
            <div style={{ fontFamily: "var(--font-display)", fontWeight: 800, fontSize: 26, lineHeight: 1.1 }}>{store.name}</div>
            <div style={{ fontSize: 22, color: "var(--grey-700)", fontWeight: 600, textTransform: "uppercase", letterSpacing: ".1em", marginTop: 6 }}>{store.sub}</div>
          </div>
        </div>
      </div>

      <div style={{ display: "flex", alignItems: "flex-end", justifyContent: "space-between", gap: 12 }}>
        <div>
          <div style={{ display: "flex", alignItems: "baseline", gap: 8 }}>
            <span style={{ fontFamily: "var(--font-num)", fontSize: 110, fontWeight: 900, letterSpacing: "-0.025em", lineHeight: 1, color: "#000" }}>
              {store.rating.toFixed(1).replace(".", ",")}
            </span>
            <span style={{ fontFamily: "var(--font-num)", fontSize: 32, color: "var(--grey-400)", fontWeight: 600 }}>/ 5</span>
          </div>
          <div style={{ display: "flex", alignItems: "center", gap: 14, marginTop: 18 }}>
            <Stars value={Math.round(store.rating)} size={26} />
            <Delta value={dRating} size={22} />
          </div>
        </div>
        {/* Sparkline con historial real + fechas */}
        <div style={{ display: "flex", flexDirection: "column", gap: 8, flexShrink: 0 }}>
          <div style={{ overflow: "hidden", lineHeight: 0, borderRadius: 2 }}>
            <Sparkline data={sparkValues} w={260} h={80} color="var(--brand-blue)" accent />
          </div>
          {sparkFirst && (
            <div style={{ display: "flex", justifyContent: "space-between", width: 260 }}>
              <span style={{ fontSize: 18, color: "var(--grey-700)", fontWeight: 700, fontFamily: "var(--font-num)", letterSpacing: ".04em" }}>{sparkFirst}</span>
              <span style={{ fontSize: 18, color: "var(--grey-700)", fontWeight: 700, fontFamily: "var(--font-num)", letterSpacing: ".04em" }}>{sparkLast}</span>
            </div>
          )}
        </div>
      </div>

      <div style={{ display: "grid", gridTemplateColumns: store.downloads != null ? "1fr 1fr" : "1fr", gap: 16, borderTop: "1px solid var(--grey-100)", paddingTop: 24 }}>
        <SlideMetric label="Valoraciones" value={fmt(store.reviews)} delta={store.reviewsDelta} />
        {store.downloads != null && (
          <SlideMetric label="Descargas" value={fmt(store.downloads)} delta={store.downloadsDelta} />
        )}
      </div>
    </div>
  );
};

const SlideMetric = ({ label, value, delta, suffix = "", invert = false }) => (
  <div style={{ display: "flex", flexDirection: "column", gap: 10 }}>
    <span style={{ fontSize: 22, color: "var(--grey-700)", fontWeight: 700, textTransform: "uppercase", letterSpacing: ".1em" }}>{label}</span>
    <div style={{ display: "flex", alignItems: "baseline", gap: 14 }}>
      <span style={{ fontFamily: "var(--font-num)", fontSize: 38, fontWeight: 800, color: "#000" }}>{value}{suffix}</span>
      <Delta value={delta} suffix={suffix === "%" ? " pts" : ""} invert={invert} size={22} />
    </div>
  </div>
);

// ─── 03 · Evolución comparada ──────────────────────────────────────
const SlideRatingEvolution = ({ data, slideIndex, totalSlides, periodLabel }) => (
  <SlideFrame
    eyebrow="01 · Rating de las stores"
    title="Evolución de la nota media · últimas 12 semanas"
    sub="Cada punto es el promedio semanal de las valoraciones recibidas en esa semana. Comparativa entre las tres fuentes."
    slideIndex={slideIndex} totalSlides={totalSlides} periodLabel={periodLabel}
    headerRight={<DeckLegendStores data={data} />}
  >
    <div style={{ flex: 1, minHeight: 0, background: "#fff", border: "1px solid var(--grey-100)", borderRadius: 24, display: "flex", flexDirection: "column", padding: "24px 32px" }}>
      <LineChart
        height={590}
        yTicks={4}
        yFormat={(v) => v.toFixed(1).replace(".", ",")}
        xLabel={(d) => d.x}
        showLegend={false}
        axisFontSize={22}
        padding={{ l: 80, r: 24, t: 18, b: 52 }}
        series={data.stores.map((s, i) => ({
          name: s.name,
          color: ["var(--chart-1)", "var(--chart-3)", "var(--chart-2)"][i],
          data: s.fullHistory
            ? s.fullHistory.slice(-12).map(h => ({ x: h.date.replace("/26", ""), y: h.rating }))
            : s.weeks.map((y, j) => ({ x: `S${j + 10}`, y })),
        }))}
      />
    </div>
  </SlideFrame>
);

const DeckLegendStores = ({ data }) => (
  <div style={{ display: "flex", gap: 28 }}>
    {data.stores.map((s, i) => (
      <span key={s.id} style={{ display: "inline-flex", alignItems: "center", gap: 10, fontSize: 22, fontWeight: 700 }}>
        <span style={{ width: 22, height: 4, background: ["var(--chart-1)", "var(--chart-3)", "var(--chart-2)"][i], borderRadius: 2 }} />
        {s.name}
      </span>
    ))}
  </div>
);

// ─── 04 · Distribución de estrellas ────────────────────────────────
const SlideStars = ({ data, slideIndex, totalSlides, periodLabel }) => (
  <SlideFrame
    eyebrow="01 · Rating de las stores"
    title="Cómo se reparten las valoraciones"
    sub="Porcentaje de reseñas por número de estrellas, en cada tienda."
    slideIndex={slideIndex} totalSlides={totalSlides} periodLabel={periodLabel}
  >
    <div style={{ display: "grid", gridTemplateColumns: `repeat(${data.stores.length}, 1fr)`, gap: 24, flex: 1 }}>
      {data.stores.map(s => (
        <div key={s.id} style={{ background: "#fff", border: "1px solid var(--grey-100)", borderRadius: 24, padding: 36, display: "flex", flexDirection: "column", gap: 28 }}>
          <div style={{ display: "flex", alignItems: "center", gap: 18 }}>
            <div style={{ transform: "scale(1.4)", transformOrigin: "left center" }}><StoreLogo id={s.id} /></div>
            <div style={{ marginLeft: 18 }}>
              <div style={{ fontFamily: "var(--font-display)", fontWeight: 800, fontSize: 28 }}>{s.name}</div>
              <div style={{ fontSize: 22, color: "var(--grey-700)", fontWeight: 500, marginTop: 8 }}>
                <span style={{ fontFamily: "var(--font-num)", fontWeight: 800, color: "#000" }}>{s.rating.toFixed(1).replace(".", ",")}</span>
                {" · "}
                <span style={{ fontFamily: "var(--font-num)" }}>{fmt(s.reviews)}</span> valoraciones
              </div>
            </div>
          </div>
          <div style={{ flex: 1 }}>
            <SlideRatingBars stars={s.stars} />
          </div>
        </div>
      ))}
    </div>
  </SlideFrame>
);

// Larger version of RatingBars for slide.
const SlideRatingBars = ({ stars }) => {
  const order = [5, 4, 3, 2, 1];
  return (
    <div style={{ display: "flex", flexDirection: "column", gap: 18, justifyContent: "center", height: "100%" }}>
      {order.map((k) => {
        const v = stars[k] || 0;
        const tone = k >= 4 ? "var(--pos-600)" : k === 3 ? "var(--grey-700)" : "var(--neg-600)";
        return (
          <div key={k} style={{ display: "grid", gridTemplateColumns: "72px 1fr 72px", alignItems: "center", gap: 18 }}>
            <span style={{ fontSize: 22, fontWeight: 700, color: "var(--grey-700)", fontFamily: "var(--font-num)", display: "flex", alignItems: "center", gap: 6 }}>
              {k}{" "}<span style={{ color: "var(--premium-gold)", fontSize: 24 }}>★</span>
            </span>
            <div style={{ position: "relative", height: 18, background: "var(--grey-100)", borderRadius: 9, overflow: "hidden" }}>
              <div style={{ position: "absolute", inset: 0, width: `${v}%`, background: tone, borderRadius: 9 }} />
            </div>
            <span style={{ fontSize: 24, color: "#000", textAlign: "right", fontFamily: "var(--font-num)", fontWeight: 800 }}>{v}%</span>
          </div>
        );
      })}
    </div>
  );
};

// ─── 05 · Descargas por SO ─────────────────────────────────────────
const SlideDownloads = ({ data, slideIndex, totalSlides, periodLabel, splitChart = "donut" }) => {
  const d = data.downloads;
  const total = d.totalWeek;
  const totalDelta = +(((d.totalWeek - d.totalWeekPrev) / d.totalWeekPrev) * 100).toFixed(1);
  const iosDelta = +(((d.ios - d.iosPrev) / d.iosPrev) * 100).toFixed(1);
  const andDelta = +(((d.android - d.androidPrev) / d.androidPrev) * 100).toFixed(1);
  return (
    <SlideFrame
      eyebrow="02 · Descargas por sistema operativo"
      title="Volumen y reparto entre iOS y Android"
      sub="Descargas totales de la semana, evolución de las últimas 7 semanas y proporción por sistema operativo."
      slideIndex={slideIndex} totalSlides={totalSlides} periodLabel={periodLabel}
    >
      <div style={{ display: "grid", gridTemplateColumns: "1.3fr 1fr", gap: 24, flex: 1 }}>
        {/* Total + sparkline + per-SO breakdown */}
        <div style={{ background: "#fff", border: "1px solid var(--grey-100)", borderRadius: 24, padding: 48, display: "flex", flexDirection: "column", gap: 36 }}>
          <div style={{ display: "flex", justifyContent: "space-between", alignItems: "flex-start", gap: 24 }}>
            <div>
              <div style={{ fontSize: 24, fontWeight: 700, color: "var(--grey-700)", textTransform: "uppercase", letterSpacing: ".12em" }}>Descargas totales</div>
              <div style={{ fontFamily: "var(--font-num)", fontSize: 156, fontWeight: 900, letterSpacing: "-0.025em", lineHeight: 0.95, color: "#000", marginTop: 16 }}>
                {fmt(total)}
              </div>
              <div style={{ marginTop: 20, display: "flex", alignItems: "center", gap: 16 }}>
                <Delta value={totalDelta} suffix=" %" size={24} />
                <span style={{ fontSize: 24, color: "var(--grey-700)", fontWeight: 500 }}>vs sem. anterior · {fmt(d.totalWeekPrev)}</span>
              </div>
            </div>
            <div style={{ width: 340 }}>
              <Sparkline data={d.weekly.map(w => w.ios + w.android)} w={340} h={120} color="var(--brand-blue)" accent />
              <div style={{ display: "flex", justifyContent: "space-between", marginTop: 10, fontSize: 22, color: "var(--grey-700)", fontFamily: "var(--font-num)", fontWeight: 600 }}>
                <span>{d.weekly[0].w}</span>
                <span>{d.weekly[d.weekly.length - 1].w}</span>
              </div>
            </div>
          </div>

          <div style={{ display: "grid", gridTemplateColumns: "1fr 1fr", gap: 28, paddingTop: 32, borderTop: "1px solid var(--grey-100)" }}>
            <SlideSOMetric color="var(--chart-3)" label="iOS · App Store" value={d.ios} delta={iosDelta} />
            <SlideSOMetric color="var(--chart-1)" label="Android · Google Play" value={d.android} delta={andDelta} />
          </div>
        </div>

        {/* Donut */}
        <div style={{ background: "#fff", border: "1px solid var(--grey-100)", borderRadius: 24, padding: 48, display: "flex", flexDirection: "column", gap: 28 }}>
          <div>
            <div style={{ fontSize: 24, fontWeight: 700, color: "var(--grey-700)", textTransform: "uppercase", letterSpacing: ".12em" }}>Reparto por SO</div>
            <h3 style={{ fontFamily: "var(--font-display)", fontWeight: 800, fontSize: 24, margin: "8px 0 0", color: "#000" }}>iOS vs Android</h3>
          </div>
          <div style={{ flex: 1, display: "flex", alignItems: "center", justifyContent: "center" }}>
            {splitChart === "donut"
              ? <DonutChart ios={d.ios} android={d.android} size={360} slideMode />
              : <div style={{ width: "100%" }}><SplitBar ios={d.ios} android={d.android} /></div>}
          </div>
        </div>
      </div>
    </SlideFrame>
  );
};

const SlideSOMetric = ({ color, label, value, delta }) => (
  <div>
    <div style={{ display: "flex", alignItems: "center", gap: 12 }}>
      <span style={{ width: 18, height: 18, borderRadius: 4, background: color }} />
      <span style={{ fontSize: 22, color: "var(--grey-700)", fontWeight: 700, textTransform: "uppercase", letterSpacing: ".1em" }}>{label}</span>
    </div>
    <div style={{ display: "flex", alignItems: "baseline", gap: 16, marginTop: 14 }}>
      <span style={{ fontFamily: "var(--font-num)", fontSize: 56, fontWeight: 800, color: "#000", letterSpacing: "-0.01em" }}>{fmt(value)}</span>
      <Delta value={delta} suffix=" %" size={22} />
    </div>
  </div>
);

// SplitBar copy with bigger sizing for slide.
const SplitBar = ({ ios, android }) => {
  const total = ios + android;
  const fIos = ios / total;
  return (
    <div style={{ display: "flex", flexDirection: "column", gap: 28, width: "100%" }}>
      <div style={{ display: "flex", height: 120, borderRadius: 20, overflow: "hidden" }}>
        <div style={{ width: `${fIos * 100}%`, background: "var(--chart-3)", display: "flex", flexDirection: "column", justifyContent: "center", padding: "0 28px", color: "#000" }}>
          <div style={{ fontFamily: "var(--font-num)", fontWeight: 800, fontSize: 36 }}>{fmt(ios)}</div>
          <div style={{ fontSize: 22, fontWeight: 700, textTransform: "uppercase", letterSpacing: ".1em", marginTop: 6 }}>iOS · {Math.round(fIos * 100)} %</div>
        </div>
        <div style={{ width: `${(1 - fIos) * 100}%`, background: "var(--chart-1)", display: "flex", flexDirection: "column", justifyContent: "center", padding: "0 28px", color: "#fff" }}>
          <div style={{ fontFamily: "var(--font-num)", fontWeight: 800, fontSize: 36 }}>{fmt(android)}</div>
          <div style={{ fontSize: 22, fontWeight: 700, textTransform: "uppercase", letterSpacing: ".1em", marginTop: 6 }}>Android · {Math.round((1 - fIos) * 100)} %</div>
        </div>
      </div>
      <div style={{ fontSize: 24, color: "var(--grey-700)", textAlign: "center", fontWeight: 500 }}>
        Total: <strong style={{ color: "#000", fontFamily: "var(--font-num)", fontWeight: 800 }}>{fmt(total)}</strong> descargas esta semana.
      </div>
    </div>
  );
};

// ─── 06 · Reseñas críticas ─────────────────────────────────────────
const SlideReviews = ({ data, slideIndex, totalSlides, periodLabel }) => {
  const [active, setActive] = React.useState(data.criticalCategories[0].id);
  const cat = data.criticalCategories.find(c => c.id === active);
  return (
    <SlideFrame
      eyebrow="03 · Resumen de reseñas críticas"
      title="Reseñas más críticas de la semana, agrupadas por categoría"
      sub="Cada categoría muestra una reseña representativa del tipo de problema reportado."
      slideIndex={slideIndex} totalSlides={totalSlides} periodLabel={periodLabel}
    >
      <div style={{ display: "grid", gridTemplateColumns: "0.9fr 1.1fr", gap: 24, flex: 1, minHeight: 0 }}>
        {/* Categorías */}
        <div style={{ background: "#fff", border: "1px solid var(--grey-100)", borderRadius: 24, display: "flex", flexDirection: "column", overflow: "hidden" }}>
          <div style={{ padding: "28px 32px 20px", display: "flex", justifyContent: "space-between", alignItems: "center", flexShrink: 0 }}>
            <div style={{ fontFamily: "var(--font-display)", fontWeight: 800, fontSize: 26 }}>Categorías ({data.criticalCategories.length})</div>
            <span style={{ fontSize: 22, color: "var(--grey-700)", fontWeight: 500 }}>
              {data.criticalCategories.reduce((a, c) => a + c.count, 0)} reseñas críticas
            </span>
          </div>
          <div style={{ borderTop: "1px solid var(--grey-100)", flex: 1, overflowY: "auto" }}>
            {data.criticalCategories.map(c => (
              <SlideCategoryRow key={c.id} c={c} active={c.id === active} onClick={() => setActive(c.id)} />
            ))}
          </div>
        </div>
        {/* Detalle */}
        <SlideReviewDetail cat={cat} />
      </div>
    </SlideFrame>
  );
};

const SlideCategoryRow = ({ c, active, onClick }) => {
  const delta = c.count - c.countPrev;
  const status = STATUS_TONES[c.status] || STATUS_TONES.estable;
  return (
    <button onClick={onClick}
      style={{
        width: "100%", textAlign: "left", padding: "13px 28px",
        background: active ? "var(--grey-50)" : "#fff",
        borderLeft: active ? "4px solid var(--brand-blue)" : "4px solid transparent",
        border: "0", borderBottom: "1px solid var(--grey-100)", cursor: "pointer",
        display: "grid", gridTemplateColumns: "1fr auto auto", alignItems: "center", gap: 16,
        fontFamily: "inherit",
      }}>
      <div style={{ display: "flex", flexDirection: "column", gap: 10 }}>
        <span style={{ fontWeight: 700, fontSize: 24, color: "#000" }}>{c.name}</span>
        <div style={{ display: "flex", alignItems: "center", gap: 12 }}>
          <Pill tone={status.tone} style={{ padding: "4px 12px", fontSize: 14 }}>{status.label}</Pill>
          <span style={{ fontSize: 22, color: "var(--grey-700)", fontWeight: 500 }}>
            ★ media {c.avgStars.toFixed(1).replace(".", ",")}
          </span>
        </div>
      </div>
      <div style={{ textAlign: "right" }}>
        <div style={{ fontFamily: "var(--font-num)", fontSize: 38, fontWeight: 800, color: "#000", lineHeight: 1, marginBottom: 8 }}>{c.count}</div>
        <Delta value={delta} invert size={20} />
      </div>
      <span style={{ color: "var(--grey-400)", fontSize: 30, marginLeft: 6 }}>›</span>
    </button>
  );
};

const SlideReviewDetail = ({ cat }) => {
  const status = STATUS_TONES[cat.status] || STATUS_TONES.estable;
  const delta = cat.count - cat.countPrev;
  return (
    <div style={{ background: "#fff", border: "1px solid var(--grey-100)", borderRadius: 24, padding: 40, display: "flex", flexDirection: "column", gap: 24, minHeight: 0 }}>
      <div style={{ display: "flex", justifyContent: "space-between", alignItems: "flex-start", gap: 16 }}>
        <div>
          <div style={{ fontSize: 22, fontWeight: 700, letterSpacing: ".12em", textTransform: "uppercase", color: "var(--grey-700)", marginBottom: 14 }}>
            Reseña representativa
          </div>
          <div style={{ fontFamily: "var(--font-display)", fontWeight: 800, fontSize: 40, letterSpacing: "-0.01em" }}>{cat.name}</div>
        </div>
        <Pill tone={status.tone} style={{ fontSize: 16, padding: "6px 16px" }}>{status.label}</Pill>
      </div>

      <div style={{ display: "grid", gridTemplateColumns: "repeat(3, 1fr)", gap: 16, padding: "24px 0", borderTop: "1px solid var(--grey-100)", borderBottom: "1px solid var(--grey-100)" }}>
        <SlideMiniStat label="Reseñas críticas" value={cat.count} delta={delta} invert />
        <SlideMiniStat label="★ media" value={cat.avgStars.toFixed(1).replace(".", ",")} />
        <SlideMiniStat label="Sentimiento" value={cat.sentiment.toFixed(2).replace(".", ",")} sub="−1 muy neg · +1 muy pos" />
      </div>

      <div style={{ flex: 1, minHeight: 0, display: "flex", flexDirection: "column", gap: 18 }}>
        <div style={{ display: "flex", alignItems: "center", gap: 14 }}>
          <Stars value={cat.sampleStars} size={26} />
          <span style={{ fontSize: 22, color: "var(--grey-700)", fontWeight: 500 }}>{cat.sampleStore} · {cat.sampleDate}</span>
        </div>
        <blockquote style={{ margin: 0, fontFamily: "var(--font-display)", fontWeight: 600, fontSize: 30, lineHeight: 1.4, letterSpacing: "-0.005em", color: "#000" }}>
          “{cat.sample}”
        </blockquote>
        <div style={{ fontSize: 22, color: "var(--grey-700)", fontWeight: 500 }}>— {cat.sampleAuthor}</div>
      </div>
    </div>
  );
};

const SlideMiniStat = ({ label, value, sub, delta, invert }) => (
  <div>
    <div style={{ fontSize: 22, fontWeight: 700, color: "var(--grey-700)", textTransform: "uppercase", letterSpacing: ".1em" }}>{label}</div>
    <div style={{ display: "flex", alignItems: "baseline", gap: 12, marginTop: 12 }}>
      <span style={{ fontFamily: "var(--font-num)", fontSize: 44, fontWeight: 800, color: "#000" }}>{value}</span>
      {delta != null && <Delta value={delta} invert={invert} size={22} />}
    </div>
    {sub && <div style={{ fontSize: 18, color: "var(--grey-400)", marginTop: 6, fontWeight: 500 }}>{sub}</div>}
  </div>
);

// ─── 07 · Heatmap de menciones ─────────────────────────────────────
const SlideHeatmap = ({ data, slideIndex, totalSlides, periodLabel }) => {
  const weeks = ["S14", "S15", "S16", "S17", "S18", "S19", "S20", "S21"];
  return (
    <SlideFrame
      eyebrow="03 · Resumen de reseñas críticas"
      title="Heatmap de menciones críticas · últimas 8 semanas"
      sub="Cuántas reseñas críticas mencionan cada categoría, semana a semana. Permite detectar problemas emergentes."
      slideIndex={slideIndex} totalSlides={totalSlides} periodLabel={periodLabel}
    >
      <div style={{ background: "#fff", border: "1px solid var(--grey-100)", borderRadius: 24, padding: 40, flex: 1, display: "flex", flexDirection: "column", gap: 32 }}>
        <SlideHeatmapGrid rows={data.extras.topicHeat} weekLabels={weeks} />
        <div style={{ display: "flex", alignItems: "center", gap: 24, fontSize: 22, color: "var(--grey-700)", fontWeight: 500, paddingTop: 20, borderTop: "1px solid var(--grey-100)" }}>
          <span>Menor</span>
          <div style={{ display: "flex", height: 16, width: 320, borderRadius: 8, overflow: "hidden" }}>
            {[96, 84, 72, 60, 48, 36].map(l => <div key={l} style={{ flex: 1, background: `hsl(220 100% ${l}%)` }} />)}
          </div>
          <span>Mayor</span>
          <span style={{ marginLeft: "auto", fontSize: 24, fontWeight: 500, color: "var(--grey-700)" }}>
            <strong style={{ color: "#000", fontWeight: 700 }}>Login y acceso</strong> es la categoría que más ha emergido (+126 % en 4 semanas).
          </span>
        </div>
      </div>
    </SlideFrame>
  );
};

const SlideHeatmapGrid = ({ rows, weekLabels }) => {
  const allVals = rows.flatMap(r => r.weeks);
  const max = Math.max(...allVals);
  const tone = (v) => `hsl(220 100% ${96 - (v / max) * 60}%)`;
  return (
    <div style={{ display: "grid", gridTemplateColumns: `300px repeat(${weekLabels.length}, 1fr)`, gap: 6, flex: 1 }}>
      <div />
      {weekLabels.map((w, i) => (
        <div key={i} style={{ textAlign: "center", fontSize: 22, fontWeight: 700, color: "var(--grey-700)", letterSpacing: ".1em", textTransform: "uppercase", paddingBottom: 10 }}>{w}</div>
      ))}
      {rows.map((r) => (
        <React.Fragment key={r.name}>
          <div style={{ fontSize: 22, fontWeight: 700, color: "#000", display: "flex", alignItems: "center", paddingRight: 16 }}>{r.name}</div>
          {r.weeks.map((v, wi) => (
            <div key={wi}
              style={{
                height: 68, background: tone(v),
                borderRadius: 8,
                display: "flex", alignItems: "center", justifyContent: "center",
                fontSize: 26, fontWeight: 800, fontFamily: "var(--font-num)",
                color: v / max > 0.55 ? "#fff" : "#000",
              }}>{v}</div>
          ))}
        </React.Fragment>
      ))}
    </div>
  );
};

// ─── 08 · Atención a reseñas ───────────────────────────────────────
const SlideResponse = ({ data, slideIndex, totalSlides, periodLabel }) => (
  <SlideFrame
    eyebrow="04 · KPIs adicionales"
    title="Atención a reseñas y satisfacción"
    sub="Cómo de rápido y a cuántas reseñas responde el equipo, y un proxy de NPS a partir de la distribución de estrellas."
    slideIndex={slideIndex} totalSlides={totalSlides} periodLabel={periodLabel}
  >
    <div style={{ display: "grid", gridTemplateColumns: "repeat(3, 1fr)", gap: 24, flex: 1 }}>
      <SlideBigStat
        label="Tasa de respuesta"
        value={`${data.extras.responseRate.now} %`}
        delta={data.extras.responseRate.now - data.extras.responseRate.prev}
        suffix=" pts"
        sub="Porcentaje de reseñas con respuesta del equipo en los últimos 7 días."
      />
      <SlideBigStat
        label="Tiempo medio respuesta"
        value={`${data.extras.responseTimeH.now.toString().replace(".", ",")} h`}
        delta={+(data.extras.responseTimeH.now - data.extras.responseTimeH.prev).toFixed(1)}
        suffix=" h" invert
        sub="Tiempo medio desde que se publica una reseña hasta la primera respuesta."
      />
      <SlideBigStat
        label="NPS estimado"
        value={data.extras.nps.now}
        delta={data.extras.nps.now - data.extras.nps.prev}
        sub="Proxy basado en la distribución de 5★/1★. No sustituye al NPS oficial."
      />
    </div>
  </SlideFrame>
);

const SlideBigStat = ({ label, value, delta, suffix, invert, sub }) => (
  <div style={{ background: "#fff", border: "1px solid var(--grey-100)", borderRadius: 24, padding: 48, display: "flex", flexDirection: "column", gap: 24, justifyContent: "space-between" }}>
    <div>
      <div style={{ fontSize: 24, fontWeight: 700, color: "var(--grey-700)", textTransform: "uppercase", letterSpacing: ".12em" }}>{label}</div>
      <div style={{ fontFamily: "var(--font-num)", fontSize: 120, fontWeight: 900, color: "#000", marginTop: 32, letterSpacing: "-0.025em", lineHeight: 1 }}>{value}</div>
      <div style={{ marginTop: 22 }}>
        {delta != null && <Delta value={delta} suffix={suffix || ""} invert={invert} size={26} />}
      </div>
    </div>
    {sub && <p style={{ fontSize: 24, color: "var(--grey-700)", margin: 0, lineHeight: 1.5, fontWeight: 500 }}>{sub}</p>}
  </div>
);

// ─── 09 · Cierre ───────────────────────────────────────────────────
const SlideClose = ({ data, slideIndex, totalSlides, periodLabel }) => (
  <div data-screen-label="09 Cierre"
    style={{ width: 1920, height: 1080, background: "var(--premium-bg)", color: "#fff", fontFamily: "var(--font-body)", padding: "80px 96px", boxSizing: "border-box", display: "flex", flexDirection: "column", justifyContent: "space-between", position: "relative", overflow: "hidden" }}>
    <div aria-hidden style={{ position: "absolute", inset: 0, pointerEvents: "none", background: "radial-gradient(40% 50% at 80% 20%, rgba(0,70,222,.25) 0%, rgba(0,0,0,0) 60%), radial-gradient(40% 50% at 20% 100%, rgba(244,192,57,.10) 0%, rgba(0,0,0,0) 60%)" }} />

    <header style={{ position: "relative", display: "flex", justifyContent: "space-between", alignItems: "center" }}>
      <img src="ds/myinvestor-logo.png" alt="MyInvestor" style={{ height: 30, filter: "brightness(0) invert(1)" }} />
      <span style={{ fontSize: 24, fontWeight: 700, color: "rgba(255,255,255,.6)", textTransform: "uppercase", letterSpacing: ".12em", fontFamily: "var(--font-num)" }}>
        Cierre · Fuentes y siguientes pasos
      </span>
    </header>

    <main style={{ position: "relative", display: "grid", gridTemplateColumns: "1fr 1fr", gap: 80 }}>
      <div>
        <h2 style={{ fontFamily: "var(--font-display)", fontWeight: 800, fontSize: 88, letterSpacing: "-0.025em", margin: 0, lineHeight: 1.05 }}>
          Gracias.
        </h2>
        <p style={{ fontSize: 26, color: "rgba(255,255,255,.7)", marginTop: 32, lineHeight: 1.5, fontWeight: 500, maxWidth: 780 }}>
          Este reporte se actualiza cada lunes y se presenta en la General Review semanal. Para preguntas o propuestas de mejora del dashboard, escribid al equipo de UX.
        </p>
        <div style={{ marginTop: 56, display: "flex", gap: 20, alignItems: "center" }}>
          <a href="#" style={{ display: "inline-flex", alignItems: "center", gap: 12, padding: "20px 36px", borderRadius: 36, background: "var(--premium-gold)", color: "var(--premium-bg)", fontWeight: 800, fontSize: 24, textDecoration: "none" }}>
            Abrir en MyInvestor UX
          </a>
          <span style={{ fontSize: 22, color: "rgba(255,255,255,.5)" }}>ux@myinvestor.es</span>
        </div>
      </div>

      <div>
        <div style={{ fontSize: 24, fontWeight: 700, color: "rgba(255,255,255,.55)", textTransform: "uppercase", letterSpacing: ".12em", marginBottom: 28 }}>Fuentes de datos</div>
        <ul style={{ listStyle: "none", padding: 0, margin: 0, display: "flex", flexDirection: "column", gap: 22, fontSize: 24 }}>
          <li style={{ display: "flex", alignItems: "center", gap: 20, paddingBottom: 22, borderBottom: "1px solid rgba(255,255,255,.1)" }}>
            <span style={{ width: 44, height: 44, display: "grid", placeItems: "center", color: "#fff", transform: "scale(1.4)" }}>{ICONS.appstore}</span>
            <div style={{ marginLeft: 12 }}><strong style={{ fontSize: 26 }}>App Store Connect</strong><div style={{ fontSize: 22, color: "rgba(255,255,255,.55)", fontWeight: 500, marginTop: 4 }}>Valoraciones, reseñas, descargas iOS</div></div>
          </li>
          <li style={{ display: "flex", alignItems: "center", gap: 20, paddingBottom: 22, borderBottom: "1px solid rgba(255,255,255,.1)" }}>
            <span style={{ width: 44, height: 44, display: "grid", placeItems: "center", transform: "scale(1.4)" }}>{ICONS.playstore}</span>
            <div style={{ marginLeft: 12 }}><strong style={{ fontSize: 26 }}>Google Play Console</strong><div style={{ fontSize: 22, color: "rgba(255,255,255,.55)", fontWeight: 500, marginTop: 4 }}>Valoraciones, reseñas, descargas Android</div></div>
          </li>
          <li style={{ display: "flex", alignItems: "center", gap: 20 }}>
            <span style={{ width: 44, height: 44, display: "grid", placeItems: "center", transform: "scale(1.4)" }}>{ICONS.trustpilot}</span>
            <div style={{ marginLeft: 12 }}><strong style={{ fontSize: 26 }}>Trustpilot Business</strong><div style={{ fontSize: 22, color: "rgba(255,255,255,.55)", fontWeight: 500, marginTop: 4 }}>Reseñas y atención a clientes web</div></div>
          </li>
        </ul>
      </div>
    </main>

    <footer style={{ position: "relative", display: "flex", justifyContent: "space-between", alignItems: "flex-end", fontSize: 22, color: "rgba(255,255,255,.5)", fontWeight: 500 }}>
      <span>Datos ficticios — esquema visual sin datos reales. v0.1 · esquema · MyInvestor UX.</span>
      <span style={{ fontFamily: "var(--font-num)", fontWeight: 700 }}>
        {String(slideIndex).padStart(2, "0")} / {String(totalSlides).padStart(2, "0")}
      </span>
    </footer>
  </div>
);

Object.assign(window, {
  SlideFrame, SlideCover, SlideStoreRating, SlideRatingEvolution,
  SlideStars, SlideDownloads, SlideReviews, SlideHeatmap, SlideResponse, SlideClose,
});
