/* Section 3 — Year-1 Forecast (At-a-Glance + Tables + Interactive Calculator) */

/* Counter for fading-in numbers */
function useCounter(target, { duration = 1800, active = false, format = (v) => Math.round(v).toLocaleString() } = {}) {
  const [val, setVal] = React.useState(0);
  React.useEffect(() => {
    if (!active) return;
    let raf;
    const start = performance.now();
    function tick(now) {
      const t = Math.min(1, (now - start) / duration);
      const eased = 1 - Math.pow(1 - t, 3);
      setVal(target * eased);
      if (t < 1) raf = requestAnimationFrame(tick);
    }
    raf = requestAnimationFrame(tick);
    return () => cancelAnimationFrame(raf);
  }, [active, target, duration]);
  return format(val);
}

/* ============ PART A — AT A GLANCE ============ */
const LANES_GLANCE = [
  {
    n: '01',
    tag: 'Recruit Seeding',
    name: 'Age 14+',
    target: 100,
    targetUnit: 'recruits',
    cadence: '4 cases / month each',
    cases: 4800,
    profit: 12000,
    question: 'Will SC actually seed 100 recruits at 4 cases / month?',
    defense: [
      'SC actively pursues 200–400+ prospects per year across all sports.',
      '100 seeded = the top quartile of the active recruiting board.',
      'Underwritten by boosters and alumni sponsors as a charitable contribution — never gifted by the program — and still $2.50/case to NIL.',
    ],
  },
  {
    n: '02',
    tag: 'Direct-to-Consumer',
    name: 'Alumni · Students · Parents',
    target: 2500,
    targetUnit: 'subscribers',
    cadence: '1 case / month each',
    cases: 30000,
    profit: 75000,
    question: 'Will 2,500 alumni households actually subscribe?',
    defense: [
      'SC has ~250–300K living alumni; the Gamecock Club newsletter alone reaches 50K+ households.',
      '2,500 = under 1% conversion — meaningfully below normal D2C benchmarks (2–5%) for a warm, branded audience.',
      'Average subscription LTV at 12 months: $360 per household.',
    ],
  },
  {
    n: '03',
    tag: 'Alumni-Owned Business',
    name: 'Placement & Hospitality',
    target: 100,
    targetUnit: 'businesses',
    cadence: '10 cases / month each',
    cases: 12000,
    profit: 30000,
    question: 'Will 100 alumni-owned businesses commit to 10 cases / month?',
    defense: [
      'SC alumni own thousands of businesses across the state — offices, venues, practices, shops, and more.',
      '100 placements = a single-digit % of the addressable pool. The Gamecock Club already organizes the network.',
      '10 cases / mo = ~2 cases / week. A rounding error for any business with a fridge or a front desk.',
    ],
  },
];

function ForecastGlance({ active }) {
  const total = LANES_GLANCE.reduce((s, l) => s + l.profit, 0);
  return (
    <div>
      {/* Three lane cards */}
      <div className="grid grid-cols-1 md:grid-cols-3 gap-6">
        {LANES_GLANCE.map((lane, i) => (
          <div key={lane.n} className="paper-card paper-card-hover relative flex flex-col">
            {/* Header strip */}
            <div className="garnet-panel px-6 py-4 flex items-center justify-between">
              <div className="font-mono text-[11px] tracking-[0.2em] uppercase opacity-85">Lane {lane.n}</div>
              <div className="font-mono text-[11px] tracking-[0.2em] uppercase">{lane.tag}</div>
            </div>

            <div className="p-6 md:p-8 flex-1 flex flex-col">
              {/* The question — the cake */}
              <div className="font-mono text-[11px] tracking-[0.2em] uppercase text-garnet mb-2">The Assumption</div>
              <h3 className="display font-semibold text-ink text-[22px] md:text-[26px] leading-[1.15] mb-2">
                {lane.question}
              </h3>

              {/* The defense */}
              <div className="font-mono text-[11px] tracking-[0.2em] uppercase text-mute-1 mt-6 mb-3">Why this is conservative</div>
              <ul className="space-y-2.5 mb-6">
                {lane.defense.map((d, j) => (
                  <li key={j} className="flex items-start gap-2.5 font-serif text-[14px] md:text-[15px] text-ink-2 leading-[1.55]">
                    <span className="text-garnet font-mono text-[10px] mt-1.5">▸</span>
                    <span>{d}</span>
                  </li>
                ))}
              </ul>

              {/* The consequence — the cherry */}
              <div className="border-t border-garnet/15 pt-5 mt-auto">
                <div className="grid grid-cols-3 gap-4 mb-4">
                  <div>
                    <div className="font-mono text-[10px] tracking-[0.18em] uppercase text-mute-1 mb-1">Target</div>
                    <div className="num text-ink text-[20px] font-medium">{lane.target.toLocaleString()}</div>
                    <div className="font-mono text-[10px] text-mute-1 tracking-[0.06em] mt-0.5">{lane.targetUnit}</div>
                  </div>
                  <div>
                    <div className="font-mono text-[10px] tracking-[0.18em] uppercase text-mute-1 mb-1">Cadence</div>
                    <div className="num text-ink text-[20px] font-medium">{lane.cadence.split(' ')[0]}</div>
                    <div className="font-mono text-[10px] text-mute-1 tracking-[0.06em] mt-0.5">case / mo</div>
                  </div>
                  <div>
                    <div className="font-mono text-[10px] tracking-[0.18em] uppercase text-mute-1 mb-1">Cases / yr</div>
                    <div className="num text-ink text-[20px] font-medium">{lane.cases.toLocaleString()}</div>
                  </div>
                </div>

                <div className="flex items-end justify-between border-t border-garnet/10 pt-4">
                  <div>
                    <div className="font-mono text-[10px] tracking-[0.18em] uppercase text-mute-1 mb-1">If assumption holds · NIL · Y1</div>
                    <div className="font-serif italic text-mute-1 text-[11px] leading-[1.3]">downstream of the assumption</div>
                  </div>
                  <div className="num text-garnet text-[36px] md:text-[42px] leading-[0.9] font-medium">
                    ${lane.profit.toLocaleString()}
                  </div>
                </div>
              </div>
            </div>
          </div>
        ))}
      </div>

      {/* Total bar */}
      <div className="mt-6 garnet-panel relative overflow-hidden">
        <div className="absolute inset-0 opacity-[0.08]" style={{
          backgroundImage: 'linear-gradient(45deg, rgba(0,0,0,0.4) 25%, transparent 25%, transparent 50%, rgba(0,0,0,0.4) 50%, rgba(0,0,0,0.4) 75%, transparent 75%, transparent)',
          backgroundSize: '24px 24px',
        }} />
        <div className="relative grid grid-cols-1 md:grid-cols-12 items-center">
          {/* Lane rows */}
          <div className="md:col-span-7 grid grid-cols-12 gap-2 px-6 md:px-8 py-6 md:py-7 text-paper">
            <div className="col-span-12 font-mono text-[11px] tracking-[0.2em] uppercase opacity-75 mb-3 border-b border-paper/20 pb-2 grid grid-cols-12 gap-2">
              <span className="col-span-5">Program · If Assumption Holds</span>
              <span className="col-span-3 text-right">Y1 Target</span>
              <span className="col-span-2 text-right">Cases / yr</span>
              <span className="col-span-2 text-right">NIL Profit</span>
            </div>
            {LANES_GLANCE.map(l => (
              <React.Fragment key={l.n}>
                <span className="col-span-5 font-display text-[14px] tracking-[0.06em] uppercase py-1">{l.tag}</span>
                <span className="col-span-3 text-right num text-[14px] py-1">{l.target.toLocaleString()} {l.targetUnit.split(' ')[0]}</span>
                <span className="col-span-2 text-right num text-[14px] py-1">{l.cases.toLocaleString()}</span>
                <span className="col-span-2 text-right num text-[14px] py-1">${l.profit.toLocaleString()}</span>
              </React.Fragment>
            ))}
          </div>

          <div className="md:col-span-5 border-t md:border-t-0 md:border-l border-paper/20 px-6 md:px-8 py-7">
            <div className="font-mono text-[11px] tracking-[0.2em] uppercase opacity-85 text-paper">Y1 Target · If All Three Hold</div>
            <div className="num text-paper leading-[0.9] mt-2" style={{ fontSize: 'clamp(56px, 8vw, 88px)' }}>
              ${total.toLocaleString()}
            </div>
            <div className="font-serif italic text-paper/85 text-[14px] mt-3 leading-[1.45]">
              Downstream of three assumptions. The dollars follow the model — they don't define it.
            </div>
          </div>
        </div>
      </div>
    </div>
  );
}

/* ============ PART B — SELL-THROUGH TABLES ============ */
const FULL_TABLES = [
  {
    laneN: '01',
    laneTag: 'Recruit Seeding',
    columns: ['# Recruits', 'Cases / Mo Each', 'Cases / Yr', 'School Profit / Yr'],
    rows: [
      [100, 2, 2400, 6000],
      [100, 4, 4800, 12000, true],
      [500, 2, 12000, 30000],
      [500, 4, 24000, 60000],
      [1000, 2, 24000, 60000],
      [1000, 4, 48000, 120000],
      [2500, 2, 60000, 150000],
      [2500, 4, 120000, 300000],
    ],
    caption: 'The smallest dollar lane and the highest strategic lane. The Y1 target is conservative on purpose. The real value isn\'t the $12,000 — it\'s the four years of brand familiarity the recruit accumulates before signing day.',
  },
  {
    laneN: '02',
    laneTag: 'DTC Subscribers',
    columns: ['# Subscribers', 'Cases / Mo Each', 'Cases / Yr', 'School Profit / Yr'],
    rows: [
      [500, 1, 6000, 15000],
      [1000, 1, 12000, 30000],
      [2500, 1, 30000, 75000, true],
      [5000, 1, 60000, 150000],
      [10000, 1, 120000, 300000],
      [25000, 1, 300000, 750000],
    ],
    caption: 'At 2,500 alumni / student / parent subscribers each receiving 1 case per month, South Carolina earns $75,000 in Y1 NIL revenue. At 10,000 subscribers, $300,000.',
  },
  {
    laneN: '03',
    laneTag: 'Alumni-Owned Business Placement',
    columns: ['# Businesses', 'Cases / Mo Each', 'Cases / Yr', 'School Profit / Yr'],
    rows: [
      [50, 5, 3000, 7500],
      [100, 5, 6000, 15000],
      [50, 10, 6000, 15000],
      [100, 10, 12000, 30000, true],
      [50, 25, 15000, 37500],
      [100, 25, 30000, 75000],
      [50, 50, 30000, 75000],
      [100, 50, 60000, 150000],
    ],
    caption: 'SC has ~300,000 living alumni. Convert 100 alumni-owned businesses to 10 cases/month each and the school clears $30,000. Scale to 50 cases/month — typical for a hotel or restaurant chain — and it\'s $150,000 from this lane alone.',
  },
];

function ForecastTables() {
  return (
    <div className="space-y-10">
      {FULL_TABLES.map((t) => (
        <div key={t.laneN} className="paper-card overflow-hidden">
          <div className="border-b border-garnet/15 px-6 md:px-8 py-5 flex items-baseline justify-between gap-4">
            <div>
              <div className="font-mono text-[10px] tracking-[0.22em] uppercase text-garnet">Lane {t.laneN}</div>
              <h3 className="display font-semibold text-ink text-[20px] md:text-[24px] tracking-[0.02em] mt-1">{t.laneTag}</h3>
            </div>
            <div className="font-mono text-[9px] tracking-[0.22em] uppercase text-mute-1">Y1 target row in garnet</div>
          </div>

          <div className="overflow-x-auto">
            <table className="w-full text-left">
              <thead>
                <tr className="border-b border-garnet/10">
                  {t.columns.map((c, i) => (
                    <th key={i} className={"px-6 md:px-8 py-3 font-mono text-[9.5px] tracking-[0.18em] uppercase text-mute-1 " + (i > 0 ? 'text-right' : '')}>
                      {c}
                    </th>
                  ))}
                </tr>
              </thead>
              <tbody>
                {t.rows.map((row, i) => {
                  const isTarget = row[4];
                  return (
                    <tr
                      key={i}
                      className={
                        isTarget
                          ? 'bg-garnet text-paper'
                          : 'border-b border-garnet/5 last:border-b-0 hover:bg-paper-2/50'
                      }
                    >
                      <td className={"px-6 md:px-8 py-3 num text-[14px] " + (isTarget ? 'font-medium' : 'text-ink')}>{row[0].toLocaleString()}</td>
                      <td className={"px-6 md:px-8 py-3 text-right num text-[14px] " + (isTarget ? 'font-medium' : 'text-ink')}>{row[1]}</td>
                      <td className={"px-6 md:px-8 py-3 text-right num text-[14px] " + (isTarget ? 'font-medium' : 'text-ink-2')}>{row[2].toLocaleString()}</td>
                      <td className={"px-6 md:px-8 py-3 text-right num text-[16px] " + (isTarget ? 'font-medium' : 'text-garnet')}>
                        ${row[3].toLocaleString()}
                        {isTarget && <span className="ml-3 font-mono text-[9px] tracking-[0.22em] uppercase opacity-85">← Y1 Target</span>}
                      </td>
                    </tr>
                  );
                })}
              </tbody>
            </table>
          </div>

          <div className="border-t border-garnet/10 px-6 md:px-8 py-4 font-serif italic text-mute-1 text-[13px] leading-[1.55]">
            {t.caption}
          </div>
        </div>
      ))}
    </div>
  );
}

/* ============ PART C — INTERACTIVE CALCULATOR ============ */
const PRESETS = {
  CONSERVATIVE: { subs: 1000, biz: 50, bizPerMo: 5, recruits: 100, recruitsPerMo: 2 },
  TARGET: { subs: 2500, biz: 100, bizPerMo: 10, recruits: 100, recruitsPerMo: 4 },
  AGGRESSIVE: { subs: 10000, biz: 100, bizPerMo: 25, recruits: 1000, recruitsPerMo: 4 },
};

function useTweenNumber(target, duration = 320) {
  const [val, setVal] = React.useState(target);
  const fromRef = React.useRef(target);
  React.useEffect(() => {
    const from = fromRef.current;
    const start = performance.now();
    let raf;
    function tick(now) {
      const t = Math.min(1, (now - start) / duration);
      const eased = 1 - Math.pow(1 - t, 3);
      const cur = from + (target - from) * eased;
      setVal(cur);
      if (t < 1) raf = requestAnimationFrame(tick);
      else fromRef.current = target;
    }
    raf = requestAnimationFrame(tick);
    return () => cancelAnimationFrame(raf);
  }, [target, duration]);
  return val;
}

function Calculator() {
  const [state, setState] = React.useState(PRESETS.TARGET);
  const [activePreset, setActivePreset] = React.useState('TARGET');

  // Compute lane subtotals
  const dtcCases = state.subs * 1 * 12; // 1 case / sub / month
  const dtcProfit = dtcCases * 2.50;
  const bizCases = state.biz * state.bizPerMo * 12;
  const bizProfit = bizCases * 2.50;
  const recruitCases = state.recruits * state.recruitsPerMo * 12;
  const recruitProfit = recruitCases * 2.50;
  const total = dtcProfit + bizProfit + recruitProfit;

  const totalTween = useTweenNumber(total, 350);
  const dtcTween = useTweenNumber(dtcProfit, 350);
  const bizTween = useTweenNumber(bizProfit, 350);
  const recruitTween = useTweenNumber(recruitProfit, 350);

  function setPreset(name) {
    setState(PRESETS[name]);
    setActivePreset(name);
  }
  function update(k, v) {
    setState(s => ({ ...s, [k]: v }));
    setActivePreset(null);
  }

  // Snap-detect presets when manually adjusting
  React.useEffect(() => {
    const match = Object.entries(PRESETS).find(([_, p]) =>
      p.subs === state.subs && p.biz === state.biz && p.bizPerMo === state.bizPerMo &&
      p.recruits === state.recruits && p.recruitsPerMo === state.recruitsPerMo
    );
    if (match) setActivePreset(match[0]);
  }, [state]);

  const fmt$ = (v) => '$' + Math.round(v).toLocaleString();
  const fmtN = (v) => Math.round(v).toLocaleString();

  return (
    <div className="paper-card overflow-hidden">
      {/* Header */}
      <div className="border-b border-garnet/15 px-6 md:px-10 py-6 md:py-7 flex flex-col md:flex-row md:items-end md:justify-between gap-4">
        <div>
          <div className="eyebrow mb-3">Run Your Own Scenario</div>
          <h3 className="display text-ink text-[28px] md:text-[40px] leading-[1.0]">
            Don't take our numbers.<br/>
            <span className="text-garnet">Run yours.</span>
          </h3>
          <p className="font-serif italic text-mute-1 text-[14px] md:text-[15px] mt-3">
            Adjust the sliders. The Year-1 NIL revenue updates live. Formula: cases / mo × 12 × nodes × $2.50.
          </p>
        </div>
        <div className="text-right">
          <div className="font-mono text-[9px] tracking-[0.22em] uppercase text-mute-1">Preset</div>
          <div className="flex gap-2 mt-2">
            {['CONSERVATIVE', 'TARGET', 'AGGRESSIVE'].map(n => (
              <button
                key={n}
                onClick={() => setPreset(n)}
                className={
                  "px-4 py-2.5 font-mono text-[10px] tracking-[0.18em] uppercase transition-all border " +
                  (activePreset === n
                    ? 'bg-garnet text-paper border-garnet'
                    : 'bg-paper text-ink-2 border-garnet/25 hover:border-garnet/60 hover:text-garnet')
                }
              >
                {n === 'TARGET' ? 'Target (Y1)' : n.charAt(0) + n.slice(1).toLowerCase()}
              </button>
            ))}
          </div>
        </div>
      </div>

      {/* Sliders */}
      <div className="px-6 md:px-10 py-8 md:py-10 space-y-10">

        {/* Row 1 — Recruit */}
        <SliderRow
          n="01"
          label="Recruit Seeding"
          sub="High-school targets on SC's recruiting board"
          min={50} max={2500} step={50}
          value={state.recruits}
          onChange={(v) => update('recruits', v)}
          tag={`${fmtN(state.recruits)} recruits × ${state.recruitsPerMo} cases / mo`}
          cases={recruitCases}
          profit={recruitTween}
          segmented={{
            label: 'Cases / mo per recruit',
            options: [2, 4],
            value: state.recruitsPerMo,
            onChange: (v) => update('recruitsPerMo', v),
          }}
        />

        {/* Row 2 — DTC */}
        <SliderRow
          n="02"
          label="DTC Subscribers"
          sub="Alumni / Student / Parent households"
          min={500} max={25000} step={500}
          value={state.subs}
          onChange={(v) => update('subs', v)}
          tag={`${fmtN(state.subs)} subscribers · 1 case / mo each`}
          cases={dtcCases}
          profit={dtcTween}
        />

        {/* Row 3 — Alumni Biz */}
        <SliderRow
          n="03"
          label="Alumni-Owned Businesses"
          sub="Offices, venues, practices, shops, tailgates"
          min={25} max={200} step={25}
          value={state.biz}
          onChange={(v) => update('biz', v)}
          tag={`${fmtN(state.biz)} businesses × ${state.bizPerMo} cases / mo`}
          cases={bizCases}
          profit={bizTween}
          segmented={{
            label: 'Cases / mo per business',
            options: [5, 10, 25, 50],
            value: state.bizPerMo,
            onChange: (v) => update('bizPerMo', v),
          }}
        />
      </div>

      {/* Sticky total bar */}
      <div className="garnet-panel relative overflow-hidden">
        <div className="absolute inset-0 opacity-[0.06]" style={{
          backgroundImage: 'linear-gradient(45deg, rgba(0,0,0,0.4) 25%, transparent 25%, transparent 50%, rgba(0,0,0,0.4) 50%, rgba(0,0,0,0.4) 75%, transparent 75%, transparent)',
          backgroundSize: '24px 24px',
        }} />
        <div className="relative px-6 md:px-10 py-8 md:py-10 grid grid-cols-1 md:grid-cols-12 items-center gap-6">
          <div className="md:col-span-4">
            <div className="font-mono text-[10px] tracking-[0.22em] uppercase opacity-80 text-paper">Year-1 NIL Revenue · To South Carolina</div>
            <div className="font-display font-semibold text-paper text-[16px] tracking-[0.06em] uppercase mt-1">Live Total</div>
          </div>
          <div className="md:col-span-5">
            <div className="num text-paper leading-[0.85] tracking-[-0.03em]" style={{ fontSize: 'clamp(56px, 9vw, 104px)' }}>
              {fmt$(totalTween)}
            </div>
          </div>
          <div className="md:col-span-3 font-mono text-[11px] tracking-[0.06em] uppercase text-paper space-y-1.5">
            <div className="flex justify-between border-b border-paper/20 pb-1.5"><span>DTC</span><span className="num">{fmt$(dtcTween)}</span></div>
            <div className="flex justify-between border-b border-paper/20 pb-1.5"><span>Biz Placement</span><span className="num">{fmt$(bizTween)}</span></div>
            <div className="flex justify-between"><span>Recruits</span><span className="num">{fmt$(recruitTween)}</span></div>
          </div>
        </div>
      </div>

      <div className="px-6 md:px-10 py-5 font-serif italic text-mute-1 text-[12px] border-t border-garnet/10">
        School profit = (cases / mo per node) × 12 × (# of nodes) × $2.50 net. Holds across all three lanes. The same formula powers every row in the tables above.
      </div>
    </div>
  );
}

/* Slider row helper */
function SliderRow({ n, label, sub, min, max, step, value, onChange, segmented, tag, cases, profit }) {
  const pct = ((value - min) / (max - min)) * 100;
  return (
    <div className="grid grid-cols-1 md:grid-cols-12 gap-6 md:gap-10 items-start">
      {/* Left — label */}
      <div className="md:col-span-3">
        <div className="font-mono text-[10px] tracking-[0.22em] uppercase text-garnet mb-1">Lane {n}</div>
        <div className="font-display font-semibold text-ink text-[18px] md:text-[20px] tracking-[0.02em] uppercase">{label}</div>
        <div className="font-mono text-[10px] text-mute-1 mt-1 tracking-[0.06em]">{sub}</div>
      </div>

      {/* Middle — slider */}
      <div className="md:col-span-6">
        <div className="flex items-center justify-between mb-3">
          <span className="font-mono text-[9px] tracking-[0.22em] uppercase text-mute-1">{min.toLocaleString()}</span>
          <span className="num text-garnet text-[28px] md:text-[36px] leading-none font-medium">{value.toLocaleString()}</span>
          <span className="font-mono text-[9px] tracking-[0.22em] uppercase text-mute-1">{max.toLocaleString()}</span>
        </div>
        <div className="relative">
          {/* Fill track */}
          <div className="absolute left-0 right-0 top-1/2 -translate-y-1/2 h-1 bg-garnet/15" />
          <div className="absolute left-0 top-1/2 -translate-y-1/2 h-1 bg-garnet" style={{ width: `${pct}%` }} />
          <input
            type="range"
            min={min} max={max} step={step}
            value={value}
            onChange={(e) => onChange(parseInt(e.target.value, 10))}
            className="garnet-range relative z-10"
          />
        </div>

        {/* Segmented control if present */}
        {segmented && (
          <div className="mt-5 flex items-center gap-3">
            <span className="font-mono text-[9px] tracking-[0.18em] uppercase text-mute-1 whitespace-nowrap">{segmented.label}</span>
            <div className="flex gap-1">
              {segmented.options.map(opt => (
                <button
                  key={opt}
                  onClick={() => segmented.onChange(opt)}
                  className={
                    "min-w-[44px] px-3 py-1.5 font-mono text-[11px] border transition-colors " +
                    (segmented.value === opt
                      ? 'bg-garnet text-paper border-garnet'
                      : 'bg-paper text-ink-2 border-garnet/25 hover:border-garnet/60')
                  }
                >
                  {opt}
                </button>
              ))}
            </div>
          </div>
        )}

        <div className="mt-4 font-mono text-[10px] text-mute-1 tracking-[0.08em]">{tag}</div>
      </div>

      {/* Right — output */}
      <div className="md:col-span-3 border-l border-garnet/15 pl-5">
        <div className="font-mono text-[9px] tracking-[0.22em] uppercase text-mute-1 mb-1">Cases / Yr</div>
        <div className="num text-ink text-[18px]">{Math.round(cases).toLocaleString()}</div>
        <div className="font-mono text-[9px] tracking-[0.22em] uppercase text-mute-1 mt-3 mb-1">Profit / Yr</div>
        <div className="num text-garnet text-[28px] md:text-[32px] font-medium">${Math.round(profit).toLocaleString()}</div>
      </div>
    </div>
  );
}

/* ============ MAIN FORECAST SECTION ============ */
function Forecast() {
  const [active, setActive] = React.useState(false);
  const ref = React.useRef(null);
  React.useEffect(() => {
    const el = ref.current;
    if (!el) return;
    const obs = new IntersectionObserver((entries) => {
      entries.forEach(e => { if (e.isIntersecting) { setActive(true); obs.disconnect(); } });
    }, { threshold: 0.1 });
    obs.observe(el);
    return () => obs.disconnect();
  }, []);

  return (
    <section ref={ref} className="relative bg-paper-2 py-28 md:py-36 px-6 md:px-10 border-t border-garnet/15">
      <div className="max-w-[1400px] mx-auto">

        {/* Header */}
        <div className="mb-16 max-w-[1100px]">
          <div className="flex items-center gap-3 mb-6">
            <div className="eyebrow">The Model / 02</div>
            <span className="font-mono text-[10px] tracking-[0.22em] uppercase px-2 py-0.5 border border-garnet/40 text-garnet">Projection</span>
          </div>
          <h2 className="display text-ink text-[40px] md:text-[60px] xl:text-[80px] leading-[0.94]">
            THREE REVENUE LANES.<br/>
            ONE CAN. <span className="text-garnet">ZERO OVERHEAD.</span>
          </h2>
          <div className="hr-thin w-32 mt-10 mb-8" />
          <p className="font-serif text-[17px] md:text-[19px] text-ink-2 leading-[1.6] max-w-[820px]">
            South Carolina has a first-mover opportunity: a school-branded water with three parallel revenue lanes flowing into the NIL collective — direct-to-consumer subscriptions, alumni-owned business placement, and booster-sponsored recruit seeding. Conservatively modeled, the three lanes target a combined <span className="num text-ink">$117,000</span> in Year 1, at <span className="num text-ink">$2.50</span> net profit per case paid direct to the collective.
          </p>
          <p className="font-serif text-[17px] md:text-[19px] text-ink-2 leading-[1.6] max-w-[820px] mt-5">
            The Y1 target is the garnet-highlighted row in each table below — sized so the program proves itself in year one, not so it promises an outcome. Above it sits the upside ceiling. The interactive calculator lets you run your own scenario.
          </p>
        </div>

        {/* Part A */}
        <div className="mb-20">
          <div className="flex items-baseline gap-3 mb-8">
            <span className="font-mono text-[10px] tracking-[0.22em] uppercase text-garnet">Part A</span>
            <span className="font-display text-ink text-[16px] tracking-[0.06em] uppercase">At a Glance</span>
            <span className="flex-1 h-px bg-garnet/15" />
          </div>
          <ForecastGlance active={active} />
        </div>

        {/* Part B */}
        <div className="mb-20">
          <div className="flex items-baseline gap-3 mb-8">
            <span className="font-mono text-[10px] tracking-[0.22em] uppercase text-garnet">Part B</span>
            <span className="font-display text-ink text-[16px] tracking-[0.06em] uppercase">The Full Sell-Through Model</span>
            <span className="flex-1 h-px bg-garnet/15" />
          </div>
          <p className="font-serif italic text-mute-1 text-[15px] mb-8 max-w-[820px]">
            How the model performs at every sell-through level. The Y1 target row in each lane is highlighted in garnet. Below the target is the conservative floor. Above it is the upside ceiling. Every row holds $2.50 / case profit constant.
          </p>
          <ForecastTables />
        </div>

        {/* Part C */}
        <div>
          <div className="flex items-baseline gap-3 mb-8">
            <span className="font-mono text-[10px] tracking-[0.22em] uppercase text-garnet">Part C</span>
            <span className="font-display text-ink text-[16px] tracking-[0.06em] uppercase">Run Your Own Scenario</span>
            <span className="flex-1 h-px bg-garnet/15" />
          </div>
          <Calculator />
        </div>
      </div>
    </section>
  );
}

window.Forecast = Forecast;
