// detail.jsx — diepteanalyse van één aandeel.
const { useState: useStateDT, useEffect: useEffectDT } = React;

function relTime(ts) {
  if (!ts) return '';
  const s = Math.round((Date.now() - ts) / 1000);
  if (s < 5) return 'zojuist';
  if (s < 60) return `${s} sec geleden`;
  const m = Math.round(s / 60);
  if (m < 60) return `${m} min geleden`;
  return `${Math.round(m / 60)} uur geleden`;
}

function domainOf(u) {
  try { return new URL(u).hostname.replace(/^www\./, ''); } catch (e) { return u; }
}

function SourceChip({ source }) {
  if (!source) return null;
  const ai = source.kind === 'ai';
  const link = (ai && source.ir) ? { href: source.ir, label: domainOf(source.ir) } : null;
  return (
    <InfoTip className="srcwrap" title={source.label}
             link={link}
             bron={ai
               ? (source.fallback
                   ? 'AI-API niet bereikbaar; historische groei aangehouden.'
                   : (source.ir
                       ? 'Geschat met de AI/GPT-API o.b.v. de officiële investor relations van het bedrijf.'
                       : 'Geschat met de AI/GPT-API. Officiële investor-relations pagina niet met zekerheid gevonden.'))
               : `Recentste gerapporteerde cijfer, opgehaald via ${source.label} (${source.asOf}).`}
             betekenis={ai
               ? `${source.note || 'Vooruitkijkende schatting.'} Verifieer altijd in het laatste jaarverslag / investor relations.`
               : 'Eén betrouwbare cijfer-API als primaire bron — geen schatting.'}>
      <span className={`srcchip srcchip--${ai ? 'ai' : 'api'}`}>{source.short}</span>
    </InfoTip>
  );
}

function Field({ label, value, display, min, max, step, onChange, hint, source }) {
  return (
    <label className="field">
      <div className="field__top">
        <span className="field__lblwrap">
          <span className="field__label">{label}</span>
          <SourceChip source={source} />
        </span>
        <span className="field__val">{display}</span>
      </div>
      <input className="field__range" type="range" min={min} max={max} step={step}
             value={value} onChange={(e) => onChange(Number(e.target.value))} />
      {hint && <span className="field__hint">{hint}</span>}
    </label>
  );
}

function InputsPanel({ stock, ev, onPatch, onReset, onRefresh, refreshing }) {
  const inp = stock.inputs;
  const src = stock.sources || {};
  const set = (k) => (v) => onPatch({ [k]: v });
  const apiCount = Object.values(src).filter((s) => s.kind === 'api').length;
  const aiCount = Object.values(src).filter((s) => s.kind === 'ai').length;
  const aiSrc = src.growth && src.growth.kind === 'ai' ? src.growth : null;
  // CAPM-indicatie voor de disconteringsvoet: risicovrij ~2,5% + bèta × ~5% premie
  const capm = Number.isFinite(stock.beta) ? 0.025 + stock.beta * 0.05 : null;
  return (
    <div className="inputs">
      <div className="inputs__head">
        <div className="inputs__titlerow">
          <h3>Aannames</h3>
          <InfoTip className="srcwrap" title="Hoe cijfers worden opgehaald"
                   bron="Alle gerapporteerde cijfers komen van Yahoo Finance: koersen live, fundamentals per laatste rapportagedatum — één bron, één peildatum."
                   betekenis="Alleen de vooruitkijkende aannames (groei, dividendgroei, verwacht dividend) worden geschat met de AI/GPT-API — altijd met bronvermelding.">
            <span className="helpdot">i</span>
          </InfoTip>
        </div>
        <span className="inputs__sub">Pas aan of haal de meest recente cijfers op</span>
      </div>

      <button className="refreshbtn" onClick={onRefresh} disabled={refreshing}>
        {refreshing
          ? <span className="spin" aria-hidden="true" />
          : <svg width="15" height="15" viewBox="0 0 15 15" aria-hidden="true"><path d="M12.5 7.5a5 5 0 1 1-1.6-3.7M12.5 1.8v2.8H9.7" fill="none" stroke="currentColor" strokeWidth="1.4" strokeLinecap="round" strokeLinejoin="round" /></svg>}
        {refreshing ? 'Cijfers ophalen…' : 'Bijwerken met recente cijfers'}
      </button>

      {stock.refreshedAt && (
        <div className="inputs__src">
          <span className="srcdot"><i className="dot dot--under" />{apiCount} via {PRIMARY_SOURCE.short}</span>
          <span className="srcdot"><i className="dot dot--fair" />{aiCount} via AI-schatting</span>
          <span className="inputs__when">· {relTime(stock.refreshedAt)}{stock.isOffline ? ' (offline — opgeslagen snapshot)' : ''}</span>
        </div>
      )}

      {aiSrc && aiSrc.note && (
        <p className="divnote">
          AI: “{aiSrc.note}”
          {aiSrc.ir && <> · <a href={aiSrc.ir} target="_blank" rel="noopener noreferrer">{domainOf(aiSrc.ir)}</a></>}
        </p>
      )}

      {ev.lens === 'dividend' ? (
        <div className="inputs__grid">
          <Field label="Dividend / aandeel" value={inp.dividend} display={fmtMoney(inp.dividend, stock.currency)}
                 min={0} max={Math.max(8, stock.dividendRate * 2)} step={0.05} onChange={set('dividend')}
                 source={src.dividend} hint="Jaarlijkse uitkering per aandeel" />
          <Field label="Gewenst dividendrendement (y)" value={inp.requiredYield} display={pct(inp.requiredYield)}
                 min={0.02} max={0.12} step={0.0025} onChange={set('requiredYield')}
                 hint="Het dividendrendement dat jij minimaal wilt ontvangen (Simpel rendement: D ÷ y) — stel je eigen eis in" />
          <Field label="Dividendgroei (g)" value={inp.divGrowth} display={pct(inp.divGrowth)}
                 min={0} max={0.30} step={0.005} onChange={set('divGrowth')}
                 source={src.divGrowth} hint="Verwachte jaarlijkse dividendgroei komende 5 jaar (in het model gecapt op 15%); daarna de terminale groei" />
          <Field label="Disconteringsvoet (r)" value={inp.discountRate} display={pct(inp.discountRate)}
                 min={0.05} max={0.14} step={0.0025} onChange={set('discountRate')}
                 hint={`Kostenvoet eigen vermogen: je totale vereiste rendement (dividend + groei), niet het dividendrendement${capm != null ? ` · CAPM-indicatie ≈ ${pct(capm)} bij bèta ${fmtNum(stock.beta, 2)}` : ''}`} />
          <Field label="Terminale groei" value={inp.terminalGrowth} display={pct(inp.terminalGrowth)}
                 min={0.0} max={0.04} step={0.0025} onChange={set('terminalGrowth')}
                 hint="Eeuwigdurende dividendgroei na jaar 5 (moet ≥ 2%-punt onder r liggen)" />
        </div>
      ) : (
        <div className="inputs__grid">
          <Field label="Winstgroei (g)" value={inp.growth} display={pct(inp.growth)}
                 min={0} max={0.30} step={0.005} onChange={set('growth')}
                 source={src.growth} hint="Verwachte winst-/kasstroomgroei" />
          <Field label="Groei-cap" value={inp.growthCap} display={pct(inp.growthCap)}
                 min={0.05} max={0.25} step={0.005} onChange={set('growthCap')}
                 hint="Maximale groei in het DCF-model" />
          <Field label="Disconteringsvoet (r)" value={inp.discountRate} display={pct(inp.discountRate)}
                 min={0.05} max={0.14} step={0.0025} onChange={set('discountRate')}
                 hint={`Kostenvoet eigen vermogen (het DCF rekent met vrije kasstroom aan aandeelhouders)${capm != null ? ` · CAPM-indicatie ≈ ${pct(capm)} bij bèta ${fmtNum(stock.beta, 2)}` : ''}`} />
          <Field label="Terminale groei" value={inp.terminalGrowth} display={pct(inp.terminalGrowth)}
                 min={0.0} max={0.04} step={0.0025} onChange={set('terminalGrowth')}
                 hint="Eeuwigdurende groei na jaar 10 (moet ≥ 2%-punt onder r liggen)" />
        </div>
      )}
      <div className="inputs__safety">
        <Field label="Analisten-K/W" value={inp.fairPE} display={fmtNum(inp.fairPE, 1)}
               min={5} max={60} step={0.5} onChange={set('fairPE')}
               source={src.fairPE} hint="Multiple voor de oranje analistenwaardering-lijn — analisten-P/E + sector" />
        <Field label="Veiligheidsmarge" value={inp.safetyMargin} display={pct(inp.safetyMargin, 0)}
               min={0} max={0.50} step={0.05} onChange={set('safetyMargin')}
               hint="Korting op de reële waarde → koopprijs" />
      </div>
      <button className="ghostbtn" onClick={onReset}>Herstel standaardwaarden</button>
    </div>
  );
}

function FactGrid({ stock }) {
  const src = stock.sources || {};
  const netDebt = (Number.isFinite(stock.totalDebt) && Number.isFinite(stock.totalCash))
    ? stock.totalDebt - stock.totalCash : null;
  const fcfPayout = (stock.dividendRate > 0 && Number.isFinite(stock.shares) && stock.fcf > 0)
    ? (stock.dividendRate * stock.shares) / stock.fcf : null;
  const f = [
    { k: 'K/W (TTM)', sk: 'peTTM', v: fmtNum(stock.peTTM, 1),
      bron: 'Koers ÷ winst per aandeel over de laatste 12 maanden.',
      bet: 'Wat je betaalt per euro winst. Ligt deze boven de normale historische K/W, dan is de koers relatief rijk geprijsd.' },
    { k: 'Verwachte K/W', sk: 'forwardPE', v: fmtNum(stock.forwardPE, 1),
      bron: 'Koers ÷ verwachte WPA komend jaar (analistenconsensus).',
      bet: 'Waardering op toekomstige winst. Lager dan de TTM-K/W wijst op verwachte winstgroei.' },
    { k: 'PEG', sk: 'peg', v: fmtNum(stock.peg, 2),
      bron: 'K/W ÷ verwachte winstgroei (in %).',
      bet: 'Corrigeert de K/W voor groei. Rond 1 = redelijk, < 1 goedkoop, > 1 duur t.o.v. de groei (kern van Peter Lynch).' },
    { k: 'WPA (EPS)', sk: 'eps', v: fmtMoney(stock.eps, stock.currency),
      bron: 'Nettowinst ÷ uitstaande aandelen (laatste 12 maanden).',
      bet: 'De winstbasis voor de Lynch- en Graham-methode én voor de reële-waardeband in de grafiek.' },
    { k: 'Dividend', sk: 'dividend', v: stock.dividendRate > 0 ? `${fmtMoney(stock.dividendRate, stock.currency)} · ${pct(stock.dividendYield)}` : 'Geen',
      bron: 'Laatste jaardividend per aandeel; rendement = dividend ÷ koers.',
      bet: 'De volledige basis voor de dividendlens (Simpel rendement D/y en het 2-fase dividend-discountmodel).' },
    { k: 'Uitkeringsratio', sk: 'payoutRatio', v: stock.payoutRatio > 0 ? pct(stock.payoutRatio, 0) : '—',
      tone: stock.payoutRatio > 1 ? 'over' : null,
      bron: 'Dividend ÷ winst per aandeel.',
      bet: 'Houdbaarheid van het dividend. Onder ~60% is er ruimte voor groei; boven 100% (rood) wordt het dividend niet door winst gedekt.' },
    { k: 'FCF-payout', sk: 'fcf', v: fcfPayout != null ? pct(fcfPayout, 0) : '—',
      tone: fcfPayout > 1 ? 'over' : null,
      bron: 'Totaal uitgekeerd dividend (dividend × aandelen) ÷ vrije kasstroom.',
      bet: 'Dividend-veiligheid op kasstroombasis — wat professionals echt checken. Boven 100% (rood) wordt het dividend niet uit echte kasstroom betaald.' },
    { k: 'Nettoschuld', sk: 'totalDebt', v: netDebt != null ? fmtBig(netDebt, stock.currency) : '—',
      tone: netDebt != null && Number.isFinite(stock.marketCap) && netDebt > stock.marketCap * 0.6 ? 'over' : null,
      bron: 'Totale schuld − kaspositie (laatste rapportage).',
      bet: 'Kan het bedrijf dividend en groei betalen zonder te lenen? Een negatieve nettoschuld betekent meer kas dan schuld. Hoge schuld maakt een “goedkoop” aandeel riskanter dan het lijkt.' },
    { k: 'Schuld / eigen verm.', sk: 'debtToEquity', v: Number.isFinite(stock.debtToEquity) ? `${fmtNum(stock.debtToEquity, 0)}%` : '—',
      tone: stock.debtToEquity > 150 ? 'over' : null,
      bron: 'Totale schuld ÷ eigen vermogen (laatste rapportage).',
      bet: 'Hefboom op de balans. Boven ~150% (rood) leunt het bedrijf zwaar op vreemd vermogen — de waardering verdient dan een extra veiligheidsmarge.' },
    { k: 'Rendement op EV (ROE)', sk: 'returnOnEquity', v: pct(stock.returnOnEquity),
      bron: 'Nettowinst ÷ eigen vermogen (laatste 12 maanden).',
      bet: 'Kwaliteitsmaat: hoeveel winst het bedrijf maakt per euro eigen vermogen. Structureel hoge ROE rechtvaardigt een hogere waardering dan de multiple alleen laat zien.' },
    { k: 'Nettomarge', sk: 'profitMargins', v: pct(stock.profitMargins),
      bron: 'Nettowinst ÷ omzet (laatste 12 maanden).',
      bet: 'Winstgevendheid van de omzet. Dunne marges maken de winst — en dus de waardering — gevoeliger voor tegenwind.' },
    { k: 'Beurswaarde', sk: 'marketCap', v: fmtBig(stock.marketCap, stock.currency),
      bron: 'Koers × aantal uitstaande aandelen.',
      bet: 'Totale marktwaarde van het eigen vermogen. Bepaalt de categorie (small/large cap), niet of het aandeel goedkoop is.' },
    { k: 'Bèta', sk: 'beta', v: fmtNum(stock.beta, 2),
      bron: 'Gevoeligheid van de koers t.o.v. de markt over ~5 jaar.',
      bet: 'Boven 1 beweegt het aandeel heftiger dan de markt → rechtvaardigt een hogere disconteringsvoet in het DCF.' },
    { k: 'Vrije kasstroom', sk: 'fcf', v: fmtBig(stock.fcf, stock.currency),
      bron: 'Operationele kasstroom − investeringen (laatste 12 maanden).',
      bet: 'De kasstroom die het two-stage DCF verdisconteert. Echt geld, lastiger te "sturen" dan boekhoudkundige winst.' },
    { k: 'VKS / aandeel', sk: 'cashflowPerShare', v: fmtMoney(stock.fcfPerShare, stock.currency),
      bron: 'Vrije kasstroom ÷ uitstaande aandelen.',
      bet: 'De startwaarde van de kasstroom in jaar 1 van het DCF-model.' },
    { k: 'Uitstaande aandelen', sk: 'shares', v: fmtBig(stock.shares, '').replace('€', '').trim(),
      bron: 'Aantal uitstaande gewone aandelen.',
      bet: 'De noemer voor WPA en VKS per aandeel. Een dalend aantal (inkoop) verhoogt de waarde per aandeel.' },
    { k: '52-weeks bereik', sk: 'low52', v: `${fmtMoney(stock.low52, stock.currency)} – ${fmtMoney(stock.high52, stock.currency)}`,
      bron: 'Laagste en hoogste slotkoers van de afgelopen 52 weken.',
      bet: 'Context voor het momentum. De positiebalk toont waar de koers binnen dit bereik staat.' },
  ];
  return (
    <div className="facts">
      {f.map((m) => {
        const s = src[m.sk];
        const bron = s ? `${m.bron} Opgehaald via ${s.label} (${s.asOf}).` : m.bron;
        return (
          <InfoTip key={m.k} className="facts__item" title={m.k} bron={bron} betekenis={m.bet}>
            <span className="facts__k">{m.k}{s && <i className={`facts__src facts__src--${s.kind}`} />}<i className="facts__i" aria-hidden="true">i</i></span>
            <span className={`facts__v ${m.tone ? `tone--${m.tone}` : ''}`}>{m.v}</span>
          </InfoTip>
        );
      })}
    </div>
  );
}

function DividendPanel({ stock }) {
  const hist = stock.divHistory || [];
  const pays = stock.dividendRate > 0 || hist.some((h) => h.dividend > 0);
  const g = stock.inputs.divGrowth;
  const src = (stock.sources && (stock.sources.nextDividend || stock.sources.divGrowth)) || null;

  if (stock.price == null) {       // geen live data → niet "geen dividend" suggereren
    return (
      <section className="panel">
        <div className="panel__head"><h3>Dividend</h3></div>
        <div className="divempty">
          <strong>Niet beschikbaar</strong>
          <p>Voor {stock.name} kon geen live dividenddata worden opgehaald.</p>
        </div>
      </section>
    );
  }

  if (!pays) {
    return (
      <section className="panel">
        <div className="panel__head"><h3>Dividend</h3></div>
        <div className="divempty">
          <strong>Keert momenteel geen dividend uit.</strong>
          <p>{stock.name} herinvesteert de vrije kasstroom in groei — gebruik de groeilens voor de waardering.</p>
        </div>
      </section>
    );
  }

  const nextYear = new Date().getFullYear() + 1;
  const proj = []; let prev = stock.dividendRate;
  for (let i = 0; i < 3; i++) {
    let d = (i === 0 && stock.nextDividend > 0) ? stock.nextDividend : prev * (1 + g);
    d = +d.toFixed(2); proj.push({ year: nextYear + i, dividend: d }); prev = d;
  }
  const nz = hist.filter((h) => h.dividend > 0);
  let dcagr = NaN;
  if (nz.length >= 2) {
    const a = nz[0], b = nz[nz.length - 1], yrs = b.year - a.year;
    if (yrs > 0 && a.dividend > 0) dcagr = Math.pow(b.dividend / a.dividend, 1 / yrs) - 1;
  }
  const nextDelta = stock.dividendRate > 0 ? (proj[0].dividend - stock.dividendRate) / stock.dividendRate : NaN;

  return (
    <section className="panel">
      <div className="panel__head">
        <h3>Dividendhistorie &amp; verwachting</h3>
        <span className="panel__sub">Per aandeel · {stock.currency}</span>
      </div>
      <div className="divstats">
        <Stat label="Huidig dividend" value={fmtMoney(stock.dividendRate, stock.currency)} sub={`${pct(stock.dividendYield)} rendement`} />
        <Stat label={`${nz.length}-jaars groei`} value={signedPct(dcagr)} sub="historische dividend-CAGR" />
        <div className="stat">
          <div className="stat__label stat__label--src"><span>Verwacht {proj[0].year}</span><SourceChip source={src} /></div>
          <div className="stat__value tone--under">{fmtMoney(proj[0].dividend, stock.currency)}</div>
          <div className="stat__sub">{signedPct(nextDelta)} t.o.v. nu</div>
        </div>
      </div>
      <DividendChart history={hist} projection={proj} currency={stock.currency} />
      <p className="divnote">
        {src && !src.fallback
          ? 'Verwachting o.b.v. het aangekondigde/voorgestelde dividend uit investor relations, daarna doorgegroeid met de dividendgroei-aanname.'
          : 'Verwachting = projectie met de dividendgroei-aanname. Klik "Bijwerken met recente cijfers" voor een schatting o.b.v. de officiële investor relations.'}
      </p>
    </section>
  );
}

// Nieuws: objectief, ontdubbeld (Yahoo + Google News), met koersreactie op de
// publicatiedag — correlatie, geen bewezen oorzaak (api/news.js).
function relDate(ms) {
  const d = Math.floor((Date.now() - ms) / 86400000);
  if (d <= 0) return 'vandaag';
  if (d === 1) return 'gisteren';
  if (d < 7) return `${d} dagen geleden`;
  return new Date(ms).toLocaleDateString('nl-NL', { day: 'numeric', month: 'short' });
}

function NewsPanel({ news }) {
  const { loading, err, data } = news;
  const items = (data && data.items) || [];
  return (
    <section className="panel">
      <div className="panel__head">
        <h3>Laatste nieuws</h3>
        <span className="panel__sub">Yahoo Finance · Google News · feitelijk</span>
      </div>
      {loading ? <p className="divnote">Nieuws laden…</p>
        : err ? <p className="divnote">{err}</p>
        : !items.length ? <p className="divnote">Geen recent, objectief nieuws gevonden (laatste 30 dagen).</p>
        : <ul className="news">
            {items.map((n) => (
              <li key={n.link} className="news__item">
                <a href={n.link} target="_blank" rel="noopener noreferrer" className="news__title">{n.title}</a>
                <div className="news__meta">
                  <span>{n.publisher} · {relDate(n.publishedAt)}</span>
                  {Number.isFinite(n.reaction1d) &&
                    <span className={`news__chip tone--${n.reaction1d >= 0 ? 'under' : 'over'}`}
                          title="Koersverandering op de publicatiedag (slot vs. vorige slot) — correlatie, geen bewezen oorzaak">
                      {signedPct(n.reaction1d)} die dag
                    </span>}
                </div>
              </li>
            ))}
          </ul>}
      <p className="divnote">Alleen feitelijke bronnen; opinie en koopadvies zijn gefilterd. Koersreactie ≠ oorzaak.</p>
    </section>
  );
}

// AI-duiding: de getallen komen uitsluitend van dit scherm; kwalitatieve
// context (IR/strategie/markt) via web search met bronvermelding (sources.jsx
// aiSummary + api/ai-summary.js).
function AISummaryPanel({ stock, ev, news }) {
  const [state, setState] = useStateDT({ busy: false, text: '', err: '' });
  const run = async () => {
    setState({ busy: true, text: '', err: '' });
    try {
      const text = await aiSummary(stock, ev, news.data);
      setState({ busy: false, text, err: '' });
    } catch (e) {
      setState({ busy: false, text: '', err: e.message || 'AI-duiding niet beschikbaar.' });
    }
  };
  return (
    <section className="panel">
      <div className="panel__head">
        <h3>AI-duiding</h3>
        <InfoTip className="srcwrap" title="AI-duiding"
                 bron="Alle getallen komen uitsluitend van dit scherm; kwalitatieve context (strategie, guidance, dividendbeleid, marktontwikkelingen) haalt het model via web search van het officiële investor-relations-domein, met bronvermelding."
                 betekenis="Duiding of de berekende waardering plausibel is in het licht van wat het bedrijf zelf communiceert en wat er in de markt speelt — geen tweede cijferbron en geen beleggingsadvies.">
          <span className="srcchip srcchip--ai">AI</span>
        </InfoTip>
      </div>
      {state.text
        ? <>
            {state.text.split(/\n{2,}|\n(?=\S)/).map((par, i) => <p key={i} className="divnote">{par}</p>)}
            <p className="divnote">Getallen van dit scherm · context via officiële IR-bronnen en recent nieuws · modeluitkomst, geen beleggingsadvies.</p>
          </>
        : <>
            <p className="divnote">Laat de cijfers duiden mét context: wat communiceert het bedrijf via investor relations, wat speelt er in de markt, en is de berekende waardering daarmee plausibel?</p>
            <button className="refreshbtn" onClick={run} disabled={state.busy}>
              {state.busy ? <span className="spin" aria-hidden="true" /> : null}
              {state.busy ? 'Duiding maken… (±30 sec, zoekt IR-bronnen)' : 'Genereer AI-duiding'}
            </button>
            {state.err && <p className="divnote">{state.err}</p>}
          </>}
    </section>
  );
}

function Detail({ stock, ev, onBack, onSetLens, onPatch, onReset, onRefresh, refreshing }) {
  const [news, setNews] = useStateDT({ loading: true, err: '', data: null });
  useEffectDT(() => {
    let live = true;
    setNews({ loading: true, err: '', data: null });
    fetchNews(stock)
      .then((data) => live && setNews({ loading: false, err: '', data }))
      .catch((e) => live && setNews({ loading: false, err: e.message || 'Nieuws niet beschikbaar.', data: null }));
    return () => { live = false; };
  }, [stock.ticker, stock.exchange]);
  const h = stock.history || [];
  const histSpan = h.length >= 2 ? (h[h.length - 1].year - h[0].year) : 0;
  return (
    <div className="detail" data-screen-label={`detail-${stock.ticker}`}>
      <div className="detail__bar">
        <button className="backbtn" onClick={onBack}>
          <svg width="15" height="15" viewBox="0 0 15 15"><path d="M9 3.5 5 7.5l4 4" fill="none" stroke="currentColor" strokeWidth="1.6" strokeLinecap="round" strokeLinejoin="round" /></svg>
          Volglijst
        </button>
        <div className="lenstoggle">
          <span className="lenstoggle__label">Waarderingslens</span>
          <div className="seg2">
            <button className={ev.lens === 'dividend' ? 'is-on' : ''} onClick={() => onSetLens('dividend')}>Dividend</button>
            <button className={ev.lens === 'growth' ? 'is-on' : ''} onClick={() => onSetLens('growth')}>Groei</button>
          </div>
        </div>
      </div>

      <header className="dhead">
        <div className="dhead__id">
          <div className="dhead__tk">{stock.ticker}<span className="dhead__exch">{stock.exchange}</span></div>
          <h2 className="dhead__nm">{stock.name}</h2>
          <div className="dhead__sec">{stock.sector}</div>
        </div>
        <div className="dhead__price">
          <div className="dhead__p">{fmtMoney(stock.price, stock.currency)}</div>
          <ChangeTag v={stock.dayChange} />
        </div>
        <span title={ev.reason || undefined}><StatusPill status={ev.status} size="lg" /></span>
      </header>

      <section className="summary">
        <Stat label="Reële waarde" value={fmtMoney(ev.composite, stock.currency)} sub={ev.reason || ev.val.compositeLabel} />
        <Stat label="Koopprijs" value={fmtMoney(ev.buy, stock.currency)} tone="under"
              sub={`reële waarde − ${pct(stock.inputs.safetyMargin, 0)} marge`} />
        <InfoTip title="Potentieel"
                 bron="(Reële waarde − koers) ÷ koers."
                 betekenis="De waarderings-gap: hoeveel de koers onder of boven de reële waarde ligt. Zegt niets over hoe snel die gap sluit — daarvoor is het verwachte jaarrendement.">
          <Stat label="Potentieel" value={signedPct(ev.upside)} tone={ev.status} sub="koers → reële waarde" />
        </InfoTip>
        <InfoTip title="Verwacht CAGR (5j)"
                 bron="(1 + g) × (reële waarde ÷ koers)^(1/5) − 1 + dividendrendement. Aanname: de koers convergeert in 5 jaar naar de reële waarde, die meegroeit met g (dividendgroei bij de dividendlens, winstgroei bij de groeilens)."
                 betekenis="Indicatief verwacht jaarrendement — modeluitkomst onder de aannames, geen voorspelling. Zeer gevoelig voor de groei-aanname in het Aannames-paneel.">
          <Stat label="Verw. CAGR (5j)" value={signedPct(ev.proj)} sub="modeluitkomst · zie i" />
        </InfoTip>
        <Stat label="Historisch CAGR" value={signedPct(ev.hist)}
              sub={Number.isFinite(ev.hist)
                ? `${histSpan > 0 ? histSpan + 'j' : ''} totaalrendement incl. dividend`
                : `te korte historie (< ${MIN_CAGR_YEARS} j)`} />
      </section>

      <div className="cols">
        <div className="col col--main">
          <section className="panel">
            <div className="panel__head">
              <h3>Koers vs. waarderingsbanden</h3>
              <span className="panel__sub">FastGraphs-stijl · WPA × multiple</span>
            </div>
            <FairValueChart priceMonthly={stock.priceMonthly} epsAnnual={stock.history}
                            normalPE={stock.normalPE} fairPE={stock.inputs.fairPE}
                            buyPrice={ev.buy} currentPrice={stock.price} currency={stock.currency} />
            <p className="divnote">
              De blauwe en oranje lijnen zijn waarderingsbanden (WPA × historische resp. analisten-K/W,
              kalenderjaar-benadering); de “Reële waarde” in de samenvatting is de composiet van de
              methodes hieronder — dat zijn dus drie verschillende invalshoeken op dezelfde vraag.
            </p>
          </section>

          <section className="panel">
            <div className="panel__head">
              <h3>Financiële ontwikkeling</h3>
              <span className="panel__sub">
                Boekjaren{stock.financials && stock.financials.currency ? ` · ${stock.financials.currency} (rapportagevaluta)` : ''}
                {' · '}Yahoo Finance{stock.financials && stock.financials.asOf ? ` · t/m ${stock.financials.asOf}` : ''}
              </span>
            </div>
            <FinancialsChart financials={stock.financials} />
            <p className="divnote">
              Stijgen omzet, marges en kasstroom terwijl de koers daalt, dan betaalt de markt een lagere
              multiple (vergelijk de K/W met de blauwe lijn hierboven) — niet per se slechtere cijfers.
              TTM = som van de laatste vier kwartalen.
            </p>
          </section>

          <section className="panel">
            <div className="panel__head">
              <h3>52-weeks bereik</h3>
            </div>
            <RangeBar low={stock.low52} high={stock.high52} price={stock.price} currency={stock.currency} />
          </section>

          <DividendPanel stock={stock} />

          <section className="panel">
            <div className="panel__head">
              <h3>{ev.lens === 'dividend' ? 'Dividend­methodes' : 'Groei­methodes'}</h3>
              <span className="panel__sub">Klik een methode open voor de formule</span>
            </div>
            <div className="methods">
              {ev.val.methods.map((m) => (
                <MethodCard key={m.key} method={m} price={stock.price} currency={stock.currency} />
              ))}
              <div className="composite">
                <div>
                  <div className="composite__label">Composiet (mediaan)</div>
                  <div className="composite__sub">{ev.val.compositeLabel}</div>
                </div>
                <div className="composite__val">{fmtMoney(ev.composite, stock.currency)}</div>
              </div>
            </div>
          </section>

          <AISummaryPanel stock={stock} ev={ev} news={news} />
        </div>

        <div className="col col--side">
          <section className="panel panel--inputs">
            <InputsPanel stock={stock} ev={ev} onPatch={onPatch} onReset={onReset} onRefresh={onRefresh} refreshing={refreshing} />
          </section>
          <section className="panel">
            <div className="panel__head"><h3>Kerngegevens</h3></div>
            <FactGrid stock={stock} />
          </section>
          <NewsPanel news={news} />
        </div>
      </div>
    </div>
  );
}

Object.assign(window, { Detail });
