// CAREER PROJECTION, granular & realistic
// Replaces per-year stream inputs with a single milestone slider + curve.
// PRO and SoundExchange now quarterly recurring (driven by streams).

const CAREER_YEARS = 10;

const DEFAULT_YEARS = [
  { year: 1, placements: 0,  perPlacement: 0,    beatSales: 0,     kitSales: 0,    label: "Learning the craft" },
  { year: 2, placements: 0,  perPlacement: 0,    beatSales: 200,   kitSales: 0,    label: "First beats online" },
  { year: 3, placements: 1,  perPlacement: 300,  beatSales: 800,   kitSales: 400,  label: "First real placement" },
  { year: 4, placements: 3,  perPlacement: 800,  beatSales: 2500,  kitSales: 1800, label: "Building the network" },
  { year: 5, placements: 6,  perPlacement: 2500, beatSales: 5000,  kitSales: 4500, label: "Catalog compounds" },
  { year: 6, placements: 10, perPlacement: 4500, beatSales: 8000,  kitSales: 8000, label: "Industry rates apply" },
  { year: 7, placements: 14, perPlacement: 6500, beatSales: 12000, kitSales: 13000, label: "Real income" },
  { year: 8, placements: 18, perPlacement: 9000, beatSales: 16000, kitSales: 19000, label: "Career tier" },
  { year: 9, placements: 22, perPlacement: 11000, beatSales: 20000, kitSales: 24000, label: "Established catalog" },
  { year: 10, placements: 26, perPlacement: 13000, beatSales: 25000, kitSales: 30000, label: "Full compound" },
];

// Stepped slider, thumb position matches labeled milestones (linear 0–500M did not).
const STREAM_STOPS = [
  0,
  10_000_000,
  20_000_000,
  50_000_000,
  100_000_000,
  200_000_000,
  500_000_000,
];

const STREAM_TICKS = [
  { value: 0, label: "0" },
  { value: 50_000_000, label: "50M" },
  { value: 100_000_000, label: "100M" },
  { value: 200_000_000, label: "200M" },
  { value: 500_000_000, label: "500M" },
];

function formatStreams(n) {
  if (!n || n < 1) return "0";
  if (n >= 1_000_000_000) {
    const b = n / 1_000_000_000;
    return Number.isInteger(b) ? `${b}B` : `${b.toFixed(2)}B`;
  }
  if (n >= 1_000_000) {
    const m = n / 1_000_000;
    return Number.isInteger(m) ? `${m}M` : `${m.toFixed(1)}M`;
  }
  if (n >= 1_000) return `${Math.round(n / 1000)}K`;
  return String(n);
}

function streamStopIndexFor(value) {
  let best = 0;
  let bestDiff = Infinity;
  STREAM_STOPS.forEach((v, i) => {
    const diff = Math.abs(v - value);
    if (diff < bestDiff) {
      bestDiff = diff;
      best = i;
    }
  });
  return best;
}

function cloneYears(rows) {
  return rows.map((y) => ({ ...y }));
}

function defaultMoments() {
  return {
    proAdvance:           { active: false, year: 5, amount: 25000 },
    coPub:                { active: false, year: 6, amount: 75000 },
    adminPub:             { active: false, year: 4, amount: 15000 },
    masterRoyaltyAdvance: { active: false, year: 5, amount: 20000 },
    execProdAdvance:      { active: false, year: 6, amount: 50000 },
    brandDeal:            { active: false, year: 6, amount: 75000 },
    sampleLicense:        { active: false, year: 7, amount: 35000 },
    catalogSale:          { active: false, year: 10, amount: 250000 },
  };
}


// Streaming rate constants (per 1,000 streams)
const RATE_MECH      = 0.30;  // mechanical, MLC / HFA
const RATE_PERF      = 0.70;  // performance, your PRO checks (quarterly)
const RATE_MASTER_I  = 3.30;  // master, independent (full)
const RATE_MASTER_S  = 1.40;  // master, signed (after label takes their cut)
const RATE_SX        = 0.20;  // SoundExchange, digital perf to master (quarterly)
const GROWTH_EXP     = 2.6;   // curve shape exponent

function CareerProjection({ embedded }) {
  const [showRoyaltyAssumptions, setShowRoyaltyAssumptions] = React.useState(false);

  const [yearsData, setYearsData] = React.useState(() => cloneYears(DEFAULT_YEARS));
  const [avgPubSplit, setAvgPubSplit] = React.useState(50);
  const [dealType, setDealType] = React.useState("independent");
  const [indieOwnership, setIndieOwnership] = React.useState(15);
  const [signedPoints, setSignedPoints] = React.useState(3);
  const avgMasterShare = dealType === "independent" ? indieOwnership : signedPoints;
  const [streamStopIndex, setStreamStopIndex] = React.useState(() => streamStopIndexFor(20_000_000));
  const streamsAtTarget = STREAM_STOPS[streamStopIndex];
  const [targetYear, setTargetYear] = React.useState(CAREER_YEARS);
  const [showLineItems, setShowLineItems] = React.useState(false);
  const [moments, setMoments] = React.useState(() => JSON.parse(JSON.stringify(defaultMoments())));

  const updateYear = (yr, patch) => {
    setYearsData((ys) => ys.map((y) => (y.year === yr ? { ...y, ...patch } : y)));
  };
  const resetDefaults = () => {
    setYearsData(cloneYears(DEFAULT_YEARS));
    setAvgPubSplit(50);
    setDealType("independent");
    setIndieOwnership(15);
    setSignedPoints(3);
    setStreamStopIndex(streamStopIndexFor(20_000_000));
    setTargetYear(CAREER_YEARS);
    setMoments(JSON.parse(JSON.stringify(defaultMoments())));
  };
  const zeroAll = () => setYearsData((ys) => ys.map((y) => ({ ...y, placements: 0, perPlacement: 0, beatSales: 0, kitSales: 0 })));
  const toggleMoment = (k) => setMoments((m) => ({ ...m, [k]: { ...m[k], active: !m[k].active } }));
  const setMomentYear = (k, y) => setMoments((m) => ({ ...m, [k]: { ...m[k], year: y } }));
  const setMomentAmt = (k, a) => setMoments((m) => ({ ...m, [k]: { ...m[k], amount: a } }));

  // Annual streams at year y via power curve
  const annualStreams = (y) => {
    if (y <= 0) return 0;
    if (y >= targetYear) return streamsAtTarget;
    return streamsAtTarget * Math.pow(y / targetYear, GROWTH_EXP);
  };

  const masterRate = dealType === "independent" ? RATE_MASTER_I : RATE_MASTER_S;

  // Compute everything per year
  const computed = yearsData.map((y) => {
    const streams = annualStreams(y.year);
    const pubBase = streams / 1000; // per-1K multiplier

    const placementIncome = y.placements * y.perPlacement;
    const productIncome   = y.beatSales + y.kitSales;

    // Royalties (recurring, paid quarterly in practice)
    const mech      = pubBase * RATE_MECH * (avgPubSplit / 100);
    const proChecks = pubBase * RATE_PERF * (avgPubSplit / 100); // PRO quarterly checks
    const master    = pubBase * masterRate * (avgMasterShare / 100);
    const sx        = pubBase * RATE_SX * (avgMasterShare / 100); // SoundExchange quarterly

    const royaltyIncome = mech + proChecks + master + sx;

    // One-time spikes
    let oneTime = 0;
    const events = [];
    Object.entries(moments).forEach(([k, m]) => {
      if (m.active && m.year === y.year) {
        oneTime += m.amount;
        events.push({ key: k, amount: m.amount });
      }
    });

    const total = placementIncome + productIncome + royaltyIncome + oneTime;
    return { ...y, streams, placementIncome, productIncome, mech, proChecks, master, sx, royaltyIncome, oneTime, events, total };
  });

  const maxYear = Math.max(...computed.map((d) => d.total), 1);
  const cumulative = computed.reduce((a, d) => a + d.total, 0);

  return (
    <section className={`section rule-top${embedded ? " chapter-embedded" : ""}`} id="career">
      <div className="page">
        {!embedded ? (
          <>
            {/* HEADER */}
            <div className="grid-12" style={{ alignItems: "end", marginBottom: 56 }}>
              <div style={{ gridColumn: "span 1" }} className="hide-mobile">
                <span className="vert">PROJECTION · 10 YR</span>
              </div>
              <div style={{ gridColumn: "span 7" }}>
                <span className="eyebrow">The Long Game</span>
                <h2 className="h-section" style={{ marginTop: 16 }}>
                  The real curve.<br/>
                  <em>Year</em> by <em>year</em>, in <em>your</em> numbers.
                </h2>
              </div>
              <div style={{ gridColumn: "span 4" }}>
                <p className="lede">
                  Pick a starting scenario, set your stream milestone, watch the curve. Open Advanced when you want every line item.
                </p>
              </div>
            </div>
          </>
        ) : (
          <div style={{ marginBottom: 32 }}>
            <span className="eyebrow">Free Tool · The Standard</span>
            <h2 className="h-section" style={{ marginTop: 16 }}>
              The real <em>10-year curve</em>.
            </h2>
          </div>
        )}

        {/* CATALOG CONTEXT */}
        <div style={{ marginBottom: 28, padding: "24px 26px", border: "1px solid var(--rule-strong)", background: "rgba(212,166,74,0.04)" }}>
          <div style={{ display: "flex", justifyContent: "space-between", alignItems: "baseline", marginBottom: 18, flexWrap: "wrap", gap: 8 }}>
            <span className="eyebrow no-mark" style={{ color: "var(--gold)" }}>Catalog milestone</span>
            <span className="caption">Streams + royalty assumptions</span>
          </div>

          <div className="grid-12" style={{ gap: 24, alignItems: "start", marginBottom: 24 }}>
            <ContextSlider span={4}
              label="Avg publishing split"
              note="50% if you wrote the music. Lower if you've assigned away pub. Drives mech + PRO check math."
              value={avgPubSplit} setValue={setAvgPubSplit} min={0} max={100} step={1} suffix="%" />
            <div style={{ gridColumn: "span 8" }}>
              <span className="field-label">Master side · choose your setup</span>
              <div style={{ marginBottom: 14 }}>
                <GlassSegmented
                  full
                  items={[
                    { id: "independent", label: "Independent", sub: "Master via distro · ownership %" },
                    { id: "signed", label: "Signed", sub: "Label deal · points out of 100" },
                  ]}
                  active={dealType}
                  onChange={setDealType}
                  ariaLabel="Master setup"
                />
              </div>
              {dealType === "independent" ? (
                <ContextSlider span={12}
                  label="Avg ownership % of master across catalog"
                  note={`Indie typical 10–25%. Master pool is ~$${RATE_MASTER_I.toFixed(2)}/1K streams (no label takes a cut).`}
                  value={indieOwnership} setValue={setIndieOwnership} min={0} max={50} step={1} suffix="%" />
              ) : (
                <ContextSlider span={12}
                  label="Avg points across catalog (out of 100)"
                  note={`Signed typical 2–5 points. Master pool is ~$${RATE_MASTER_S.toFixed(2)}/1K streams (label keeps the rest before paying your points).`}
                  value={signedPoints} setValue={setSignedPoints} min={0} max={10} step={0.5} suffix=" pts" />
              )}
            </div>
          </div>

          {/* Streams milestone slider */}
          <div style={{ padding: "20px 22px", background: "rgba(0,0,0,0.2)", border: "1px solid var(--rule)" }}>
            <div style={{ display: "flex", justifyContent: "space-between", alignItems: "flex-start", marginBottom: 16, flexWrap: "wrap", gap: 12 }}>
              <div>
                <span className="field-label" style={{ marginBottom: 6, display: "block" }}>Streams milestone</span>
                <div style={{ display: "flex", alignItems: "baseline", gap: 8 }}>
                  <span style={{ fontFamily: "var(--sans)", fontWeight: 800, fontSize: "clamp(28px, 3vw, 38px)", color: "var(--gold)", letterSpacing: "-0.025em", fontVariantNumeric: "tabular-nums", lineHeight: 1 }}>
                    {formatStreams(streamsAtTarget)}
                  </span>
                  <span style={{ fontFamily: "var(--sans)", fontWeight: 500, fontSize: 14, color: "var(--ink-3)" }}>streams / yr</span>
                </div>
              </div>
              <div style={{ display: "flex", alignItems: "center", gap: 8, paddingTop: 4 }}>
                <span style={{ fontFamily: "var(--sans)", fontSize: 13, color: "var(--ink-3)", fontWeight: 500 }}>by year</span>
                <select value={targetYear} onChange={(e) => { setTargetYear(Number(e.target.value)); }} style={{
                  background: "rgba(212,166,74,0.10)", color: "var(--gold)", border: "1px solid var(--rule-gold)",
                  fontFamily: "var(--mono)", fontSize: 12, padding: "5px 10px", appearance: "none", cursor: "pointer", fontWeight: 700,
                }}>
                  {Array.from({ length: CAREER_YEARS }, (_, i) => i + 1).map((y) => (
                    <option key={y} value={y} style={{ background: "var(--bg)" }}>YEAR {y}</option>
                  ))}
                </select>
              </div>
            </div>
            <StreamsMilestoneSlider
              stopIndex={streamStopIndex}
              onStopIndexChange={(i) => { setStreamStopIndex(i); }}
            />
            <p className="caption" style={{ marginTop: 12, color: "var(--ink-3)", lineHeight: 1.4 }}>
              ★ Earlier years scale down on a curve. Year 1 starts near zero. Streams ramp to this milestone. PRO checks and SoundExchange are the quarterly recurring portions of these royalties.
            </p>
          </div>
        </div>

        <div className="grid-12" style={{ gap: 36, alignItems: "start" }}>
          {/* LEFT: per-year editor + one-time spikes */}
          <div style={{ gridColumn: "span 6", display: "flex", flexDirection: "column", gap: 20 }}>
            <div style={{ padding: "20px 24px", border: "1px solid var(--rule-strong)", background: "rgba(255,255,255,0.015)" }}>
              <div style={{ display: "flex", justifyContent: "space-between", alignItems: "baseline", marginBottom: 6 }}>
                <span className="eyebrow no-mark" style={{ color: "var(--gold)" }}>Year-by-Year Activity</span>
                <div style={{ display: "flex", gap: 8 }}>
                  <MiniBtn label="↺ Defaults" onClick={resetDefaults} />
                  <MiniBtn label="∅ Clear" onClick={zeroAll} />
                </div>
              </div>
              <p className="body-text" style={{ fontSize: 13, lineHeight: 1.5, color: "var(--ink-3)", margin: "6px 0 16px" }}>
                Producer fees, beat sales, and kit sales. The active-income side of your career. Royalties fill in automatically from the streams curve above.
              </p>

              {/* Header row */}
              <div style={{ display: "grid", gridTemplateColumns: "48px 0.9fr 1fr 1fr 1fr", gap: 6, padding: "0 0 10px", borderBottom: "1px solid var(--rule-strong)" }}>
                <div className="caption" style={{ fontSize: 9 }}>YR</div>
                <div className="caption" style={{ fontSize: 9 }}>Placements</div>
                <div className="caption" style={{ fontSize: 9 }}>$ / Placement</div>
                <div className="caption" style={{ fontSize: 9 }}>Beat $</div>
                <div className="caption" style={{ fontSize: 9 }}>Kit $</div>
              </div>

              {yearsData.map((y) => (
                <YearRow key={y.year} y={y} onChange={(patch) => updateYear(y.year, patch)} />
              ))}
            </div>

            <div style={{ padding: "20px 24px", border: "1px solid var(--rule-gold)", background: "rgba(212,166,74,0.04)" }}>
              <div style={{ display: "flex", justifyContent: "space-between", alignItems: "baseline", marginBottom: 6 }}>
                <span className="eyebrow no-mark" style={{ color: "var(--gold)" }}>One-Time Spikes</span>
                <span className="caption">Advances · deals · windfalls</span>
              </div>
              <p className="body-text" style={{ fontSize: 13, lineHeight: 1.5, color: "var(--ink-3)", margin: "6px 0 16px" }}>
                Lump sums that land in a single year. PRO and SoundExchange <span className="gold">checks</span> are recurring (already in the curve). PRO <span className="gold">advances</span> are separate, one-time, and recoupable from future checks.
              </p>
              <div style={{ display: "flex", flexDirection: "column", gap: 8 }}>
                {MONEY_MOMENTS.map((m) => (
                  <MomentRow
                    key={m.id}
                    moment={m}
                    state={moments[m.id]}
                    onToggle={() => toggleMoment(m.id)}
                    onYearChange={(yr) => setMomentYear(m.id, yr)}
                    onAmountChange={(a) => setMomentAmt(m.id, a)}
                    maxYear={CAREER_YEARS}
                  />
                ))}
              </div>
            </div>
          </div>

          {/* Chart + breakdown */}
          <div style={{ gridColumn: "span 6" }} className="career-print-root">
            <div style={{ padding: "32px 32px 36px", background: "var(--bg-rise)", border: "1px solid var(--rule-strong)" }}>
              <div style={{ display: "flex", justifyContent: "space-between", alignItems: "baseline", marginBottom: 24, flexWrap: "wrap", gap: 12 }}>
                <div>
                  <span className="eyebrow no-mark">{CAREER_YEARS}-Year Income Curve</span>
                  <div style={{ display: "flex", alignItems: "baseline", gap: 10, marginTop: 6 }}>
                    <div style={{ fontFamily: "var(--sans)", fontWeight: 800, fontSize: "clamp(28px, 3.4vw, 40px)", letterSpacing: "-0.025em", lineHeight: 1, color: "var(--gold)" }}>
                      ${formatNum(cumulative)}
                    </div>
                    <span className="caption">cumulative · {CAREER_YEARS} years</span>
                  </div>
                </div>
                <div style={{ display: "flex", gap: 14, flexWrap: "wrap", alignItems: "center" }} className="career-no-print">
                  <LegendChip color="var(--gold)" label="Producer fees" />
                  <LegendChip color="#6ab8e8" label="Products / services" />
                  <LegendChip color="#b889ff" label="Royalties (PRO·MLC·Master·SX)" />
                  <LegendChip color="#7acf99" label="One-time spikes" />
                  <button type="button" onClick={() => window.print()} className="btn btn-ghost" style={{ padding: "6px 12px", fontSize: 11 }}>
                    Print summary
                  </button>
                </div>
              </div>

              <div style={{ overflowX: "auto", marginBottom: 12 }}>
              <div style={{ display: "grid", gridTemplateColumns: `repeat(${CAREER_YEARS}, minmax(52px, 1fr))`, gap: 6, alignItems: "end", height: 280, minWidth: 520 }}>
                {computed.map((d) => (
                  <YearBar key={d.year} d={d} max={maxYear} />
                ))}
              </div>
              </div>
              <div style={{ display: "grid", gridTemplateColumns: `repeat(${CAREER_YEARS}, minmax(52px, 1fr))`, gap: 6, minWidth: 520 }}>
                {computed.map((d) => (
                  <div key={d.year} style={{ textAlign: "center" }}>
                    <div style={{ fontFamily: "var(--mono)", fontSize: 10, letterSpacing: "0.12em", color: "var(--ink-3)" }}>YR {d.year}</div>
                    <div style={{ fontFamily: "var(--sans)", fontWeight: 700, fontSize: 14, color: d.total > 0 ? "var(--gold)" : "var(--ink-3)", fontVariantNumeric: "tabular-nums", marginTop: 2 }}>
                      {d.total >= 1000 ? `$${Math.round(d.total / 1000)}K` : d.total > 0 ? `$${Math.round(d.total)}` : "-"}
                    </div>
                    <div className="caption" style={{ fontSize: 9, marginTop: 2 }}>{d.label}</div>
                  </div>
                ))}
              </div>

              <p style={{ fontFamily: "var(--serif)", fontStyle: "italic", fontSize: 16, lineHeight: 1.4, marginTop: 32, paddingTop: 20, borderTop: "1px solid var(--rule)", color: "var(--ink-2)" }}>
                ★ Year 1 looks like nothing. Year 4 looks like a job. <span className="gold">Year {CAREER_YEARS} is the compound, every placement still paying you back, four times a year.</span>
              </p>
              <p className="caption career-print-only" style={{ display: "none", marginTop: 12, color: "var(--ink-3)" }}>
                Milestone: {formatStreams(streamsAtTarget)} streams/yr by year {targetYear} · {dealType} · pub {avgPubSplit}% · master {avgMasterShare}%
              </p>

            </div>

            {/* Detail breakdown */}
            <div style={{ marginTop: 16, padding: "20px 22px", border: "1px solid var(--rule)" }} className="career-no-print">
              <div style={{ display: "flex", justifyContent: "space-between", alignItems: "baseline", marginBottom: showLineItems ? 12 : 0, flexWrap: "wrap", gap: 8 }}>
                <span className="eyebrow no-mark">Per-year line items</span>
                <MiniBtn label={showLineItems ? "Hide detail" : "Show detail"} onClick={() => setShowLineItems((v) => !v)} />
              </div>
              {!showLineItems && (
                <p className="caption" style={{ color: "var(--ink-3)", lineHeight: 1.4 }}>
                  Fee, product, royalty, and spike breakdown by year, expand when you want the spreadsheet view.
                </p>
              )}
              {showLineItems && <div style={{ overflowX: "auto" }}>
                <div style={{ minWidth: 880 }}>
                  <div style={{ display: "grid", gridTemplateColumns: "44px repeat(8, 1fr)", gap: 6, paddingBottom: 8, borderBottom: "1px solid var(--rule)" }}>
                    {["YR", "Fees", "Products", "Mech", "PRO", "Master", "SX", "Spike", "Total"].map((h) => (
                      <div key={h} className="caption" style={{ fontSize: 9 }}>{h}</div>
                    ))}
                  </div>
                  {computed.map((d) => (
                    <div key={d.year} style={{ display: "grid", gridTemplateColumns: "44px repeat(8, 1fr)", gap: 6, padding: "8px 0", borderBottom: "1px dashed var(--rule)", fontFamily: "var(--mono)", fontSize: 11, fontVariantNumeric: "tabular-nums", alignItems: "baseline" }}>
                      <span style={{ color: "var(--gold)" }}>YR {d.year}</span>
                      <Cell value={d.placementIncome} color="var(--ink-2)" />
                      <Cell value={d.productIncome} color="#6ab8e8" />
                      <Cell value={d.mech} color="#b889ff" small />
                      <Cell value={d.proChecks} color="#b889ff" small />
                      <Cell value={d.master} color="#b889ff" />
                      <Cell value={d.sx} color="#b889ff" small />
                      <Cell value={d.oneTime} color="#7acf99" plus />
                      <Cell value={d.total} color="var(--ink)" bold />
                    </div>
                  ))}
                </div>
              </div>}
              {showLineItems && (
              <p className="caption" style={{ marginTop: 14, color: "var(--ink-3)", lineHeight: 1.4 }}>
                Mech = mechanicals (MLC). PRO = performance checks (BMI/ASCAP). Master = streaming master. SX = SoundExchange digital performance. All four pay quarterly.
              </p>
              )}
            </div>
          </div>
        </div>

        <p className="caption" style={{ marginTop: 32, color: "var(--ink-3)" }}>
          ★ Math notes: ${RATE_MECH.toFixed(2)}/1K (mech) + ${RATE_PERF.toFixed(2)}/1K (perf) + ${dealType === "independent" ? RATE_MASTER_I.toFixed(2) : RATE_MASTER_S.toFixed(2)}/1K (master) + ${RATE_SX.toFixed(2)}/1K (SX), each multiplied by your share. Stream curve ramps via power function, earlier years are deliberately low.
        </p>
      </div>
    </section>
  );
}

const MONEY_MOMENTS = [
  { id: "proAdvance",           label: "PRO writer advance",            note: "One-time advance from BMI/ASCAP, recoupable from your future PRO checks. $10K–$100K typical. PRO checks above continue alongside." },
  { id: "coPub",                label: "Co-publishing deal advance",     note: "Trade half your publishing for an upfront sum. $50K–$500K. Halves your pub upside long-term." },
  { id: "adminPub",             label: "Admin publishing deal advance",  note: "Keep your publishing, pay an admin (10–25%) to collect for you. Smaller upfront, $5K–$50K." },
  { id: "masterRoyaltyAdvance", label: "Master royalty advance",         note: "Label prepays your master royalties on a per-project basis. $5K–$50K typical. Recoupable from your master side only, doesn't touch your fee or pub." },
  { id: "execProdAdvance",      label: "Executive Producer advance",     note: "You executive-produce an album or project. EP advance is paid upfront against future credits + royalties. $25K–$250K depending on artist tier." },
  { id: "brandDeal",            label: "Brand / endorsement deal",       note: "Beats, Native Instruments, plugin partnerships, hardware spots. One-time payments $25K–$500K. Sometimes recurring, set the year it lands." },
  { id: "sampleLicense",        label: "Sample license windfall",         note: "Your old beat gets sampled in someone else's record. You negotiate a clearance: master + pub piece going forward, plus an upfront. $5K–$100K upfront, more if it's a major hit." },
  { id: "catalogSale",          label: "Catalog sale / asset sale",      note: "You sell your master and/or publishing catalog. Career-redefining lump. $100K–$10M+ depending on catalog value. Once-in-a-career event." },
];

// ---------- Year row editor ----------
function YearRow({ y, onChange }) {
  const empty = y.placements === 0 && y.perPlacement === 0 && y.beatSales === 0 && y.kitSales === 0;
  return (
    <div style={{ padding: "10px 0", borderBottom: "1px dashed var(--rule)", display: "grid", gridTemplateColumns: "48px 0.9fr 1fr 1fr 1fr", gap: 6, alignItems: "center", opacity: empty ? 0.55 : 1, transition: "opacity 0.2s ease" }}>
      <div>
        <div style={{ fontFamily: "var(--mono)", fontSize: 11, color: "var(--gold)", letterSpacing: "0.14em", fontWeight: 700 }}>YR {y.year}</div>
        <div className="caption" style={{ fontSize: 8, color: "var(--ink-4)", marginTop: 2 }}>{y.label}</div>
      </div>
      <CellInput value={y.placements}   onChange={(v) => onChange({ placements: v })}   step={1} />
      <CellInput value={y.perPlacement} onChange={(v) => onChange({ perPlacement: v })} step={100} prefix="$" />
      <CellInput value={y.beatSales}    onChange={(v) => onChange({ beatSales: v })}    step={100} prefix="$" />
      <CellInput value={y.kitSales}     onChange={(v) => onChange({ kitSales: v })}     step={100} prefix="$" />
    </div>
  );
}

function CellInput({ value, onChange, step = 1, prefix = "" }) {
  return (
    <input
      type="number"
      value={value}
      step={step}
      min={0}
      onChange={(e) => onChange(Math.max(0, Number(e.target.value) || 0))}
      style={{
        background: value > 0 ? "rgba(212,166,74,0.08)" : "rgba(255,255,255,0.02)",
        border: `1px solid ${value > 0 ? "var(--rule-gold)" : "var(--rule)"}`,
        color: value > 0 ? "var(--gold)" : "var(--ink-3)",
        fontFamily: "var(--mono)",
        fontSize: 12,
        fontWeight: value > 0 ? 600 : 400,
        padding: "6px 6px",
        width: "100%",
        outline: "none",
        appearance: "textfield",
        fontVariantNumeric: "tabular-nums",
        transition: "all 0.18s ease",
      }}
    />
  );
}

function Cell({ value, color, bold, plus, small }) {
  if (!value || value < 1) return <span style={{ color: "var(--ink-4)" }}>-</span>;
  return (
    <span style={{ color, fontWeight: bold ? 700 : 400, fontSize: small ? 10 : 11 }}>
      {plus ? "+" : ""}${value >= 1000 ? Math.round(value / 1000) + "K" : Math.round(value)}
    </span>
  );
}


function StreamsMilestoneSlider({ stopIndex, onStopIndexChange }) {
  const maxIdx = STREAM_STOPS.length - 1;
  const pct = maxIdx > 0 ? (stopIndex / maxIdx) * 100 : 0;

  return (
    <div>
      {/* Track + stop dots + range input layered */}
      <div style={{ position: "relative", height: 20 }}>
        <input
          type="range"
          min={0}
          max={maxIdx}
          step={1}
          value={stopIndex}
          onChange={(e) => onStopIndexChange(Number(e.target.value))}
          className="pu-slider"
          style={{ width: "100%", "--pu-pct": `${pct}%`, position: "absolute", top: "50%", transform: "translateY(-50%)", margin: 0, zIndex: 3 }}
        />
        {STREAM_STOPS.map((_, i) => {
          const left = (i / maxIdx) * 100;
          const active = i <= stopIndex;
          return (
            <div
              key={i}
              style={{
                position: "absolute",
                left: `${left}%`,
                top: "50%",
                transform: "translate(-50%, -50%)",
                width: i === stopIndex ? 8 : 5,
                height: i === stopIndex ? 8 : 5,
                background: active ? "var(--gold)" : "rgba(255,255,255,0.15)",
                pointerEvents: "none",
                zIndex: 2,
                transition: "all 0.15s ease",
              }}
            />
          );
        })}
      </div>

      {/* Tick labels — edge-pinned to prevent overflow */}
      <div style={{ position: "relative", height: 20, marginTop: 6 }}>
        {STREAM_TICKS.map((tick, i) => {
          const idx = streamStopIndexFor(tick.value);
          const isFirst = i === 0;
          const isLast = i === STREAM_TICKS.length - 1;
          const left = (idx / maxIdx) * 100;
          const active = idx === stopIndex;
          return (
            <span
              key={tick.label}
              className="caption"
              style={{
                position: "absolute",
                ...(isFirst  ? { left: 0 }                                   : {}),
                ...(isLast   ? { right: 0 }                                  : {}),
                ...(!isFirst && !isLast ? { left: `${left}%`, transform: "translateX(-50%)" } : {}),
                whiteSpace: "nowrap",
                color: active ? "var(--gold)" : "var(--ink-4)",
                fontWeight: active ? 700 : 400,
                transition: "color 0.15s ease",
              }}
            >
              {tick.label}{isLast ? " / yr" : ""}
            </span>
          );
        })}
      </div>
    </div>
  );
}

function ContextSlider({ span, label, note, value, setValue, min, max, step, prefix = "", suffix = "" }) {
  return (
    <div style={{ gridColumn: `span ${span}` }}>
      <div style={{ display: "flex", justifyContent: "space-between", alignItems: "baseline", marginBottom: 8 }}>
        <span style={{ fontFamily: "var(--sans)", fontWeight: 600, fontSize: 13, color: "var(--ink)" }}>{label}</span>
        <span style={{ fontFamily: "var(--sans)", fontWeight: 800, fontSize: 22, color: "var(--gold)", letterSpacing: "-0.02em", fontVariantNumeric: "tabular-nums" }}>
          {prefix}{value}{suffix}
        </span>
      </div>
      <input
        type="range" min={min} max={max} step={step} value={value}
        onChange={(e) => setValue(Number(e.target.value))}
        className="pu-slider"
        style={{ width: "100%", "--pu-pct": `${((value - min) / (max - min)) * 100}%` }}
      />
      <p className="caption" style={{ marginTop: 8, color: "var(--ink-3)", lineHeight: 1.4 }}>{note}</p>
    </div>
  );
}

// ---------- Big moments row ----------
function MomentRow({ moment, state, onToggle, onYearChange, onAmountChange, maxYear }) {
  return (
    <div style={{ background: state.active ? "rgba(212,166,74,0.10)" : "rgba(255,255,255,0.02)", border: `1px solid ${state.active ? "rgba(212,166,74,0.4)" : "var(--rule)"}`, padding: "10px 12px", transition: "all 0.18s ease" }}>
      <div style={{ display: "flex", alignItems: "center", gap: 12, flexWrap: "wrap" }}>
        <button onClick={onToggle} style={{
          width: 32, height: 18, padding: 0, border: "none",
          background: state.active ? "var(--gold)" : "rgba(255,255,255,0.1)",
          cursor: "pointer", position: "relative",
          transition: "background 0.18s ease",
          flexShrink: 0,
        }}>
          <span style={{ position: "absolute", top: 2, left: state.active ? 16 : 2, width: 14, height: 14, background: state.active ? "#16110a" : "var(--ink-2)", transition: "left 0.18s ease" }}></span>
        </button>
        <div style={{ flex: 1, minWidth: 0 }}>
          <div style={{ fontFamily: "var(--sans)", fontWeight: 600, fontSize: 13, color: state.active ? "var(--ink)" : "var(--ink-3)", letterSpacing: "-0.005em" }}>
            {moment.label}
          </div>
        </div>
        {state.active && (
          <div style={{ display: "flex", alignItems: "center", gap: 8 }}>
            <select value={state.year} onChange={(e) => onYearChange(Number(e.target.value))} style={{
              background: "rgba(0,0,0,0.3)", color: "var(--gold)", border: "1px solid var(--rule-gold)",
              fontFamily: "var(--mono)", fontSize: 10, padding: "3px 6px", appearance: "none", cursor: "pointer",
            }}>
              {Array.from({ length: maxYear }, (_, i) => i + 1).map((y) => (
                <option key={y} value={y} style={{ background: "var(--bg)" }}>YR {y}</option>
              ))}
            </select>
            <input
              type="number"
              value={state.amount}
              onChange={(e) => onAmountChange(Math.max(0, Number(e.target.value) || 0))}
              step="500"
              style={{
                background: "rgba(0,0,0,0.3)", color: "var(--gold)", border: "1px solid var(--rule-gold)",
                fontFamily: "var(--mono)", fontSize: 11, padding: "3px 6px", width: 80, textAlign: "right",
              }}
            />
          </div>
        )}
      </div>
      {state.active && (
        <p style={{ fontFamily: "var(--mono)", fontSize: 10, lineHeight: 1.45, color: "var(--ink-3)", margin: "8px 0 0", letterSpacing: "0.02em" }}>
          {moment.note}
        </p>
      )}
    </div>
  );
}

function LegendChip({ color, label }) {
  return (
    <span style={{ display: "flex", alignItems: "center", gap: 6, fontFamily: "var(--mono)", fontSize: 10, letterSpacing: "0.14em", color: "var(--ink-3)" }}>
      <span style={{ width: 10, height: 10, background: color, display: "inline-block" }}></span>
      <span>{label.toUpperCase()}</span>
    </span>
  );
}

function YearBar({ d, max }) {
  const segments = [
    { v: d.placementIncome, color: "var(--gold)" },
    { v: d.productIncome,   color: "#6ab8e8" },
    { v: d.royaltyIncome,   color: "#b889ff" },
    { v: d.oneTime,         color: "#7acf99" },
  ];
  const totalPct = max > 0 ? (d.total / max) * 100 : 0;
  return (
    <div style={{ height: "100%", position: "relative", display: "flex", flexDirection: "column-reverse" }}>
      <div style={{ height: `${totalPct}%`, display: "flex", flexDirection: "column-reverse", transition: "height 0.5s cubic-bezier(0.2,0.8,0.2,1)" }}>
        {segments.map((s, i) => {
          const segPct = d.total > 0 ? (s.v / d.total) * 100 : 0;
          if (segPct <= 0) return null;
          return (
            <div key={i} style={{
              height: `${segPct}%`,
              background: s.color,
              transition: "height 0.4s ease, background 0.2s ease",
              borderTop: i > 0 ? "1px solid rgba(0,0,0,0.3)" : "none",
            }}></div>
          );
        })}
      </div>
      {d.oneTime > 0 && (
        <div style={{
          position: "absolute",
          top: `${Math.max(0, 100 - totalPct - 4)}%`,
          left: "50%",
          transform: "translateX(-50%) rotate(45deg)",
          width: 10, height: 10,
          background: "#7acf99",
          boxShadow: "0 0 0 2px var(--bg-rise)",
        }}></div>
      )}
    </div>
  );
}

function MiniBtn({ label, onClick }) {
  return (
    <button onClick={onClick} style={{
      background: "transparent",
      border: "1px solid var(--rule-strong)",
      color: "var(--ink-3)",
      fontFamily: "var(--mono)",
      fontSize: 10,
      letterSpacing: "0.14em",
      padding: "4px 8px",
      cursor: "pointer",
      transition: "all 0.18s ease",
    }}
    onMouseEnter={(e) => { e.currentTarget.style.borderColor = "var(--gold)"; e.currentTarget.style.color = "var(--gold)"; }}
    onMouseLeave={(e) => { e.currentTarget.style.borderColor = "var(--rule-strong)"; e.currentTarget.style.color = "var(--ink-3)"; }}
    >{label}</button>
  );
}

window.CareerProjection = CareerProjection;
