// Moderis — Receptenbibliotheek (kern). Zelfstandig scherm met drie views:
//   list   — overzicht van opgeslagen recepten (favorieten eerst)
//   detail — één recept: macro's per portie, ingrediënten, bereiding, feedback
//   edit   — maken/bewerken; ingrediënten (naam + gram) → macro's bij opslaan
//            via /api/recepten. "Genereer met Moderis" vult een concept voor.
//
// Macro's komen altijd serverside uit de Open Food Facts + AI-pipeline; de
// client stuurt alleen naam + gram. Een ⚠ bij een ingrediënt = geschat.

const MOMENT_LABELS = { ontbijt: 'Ontbijt', lunch: 'Lunch', snack: 'Snack', avondeten: 'Avondeten', meeneem: 'Meeneem' };
const MOMENT_KEYS = ['ontbijt', 'lunch', 'snack', 'avondeten', 'meeneem'];

function recMacroObj(r) {
  return { p: Math.round(r.eiwitten || 0), c: Math.round(r.koolhydraten || 0), f: Math.round(r.vetten || 0) };
}

function bronBadge(bron) {
  if (bron === 'ai_nieuw') return { label: 'Nieuw idee', cls: 'm-label-omega' };
  if (bron === 'aangepast') return { label: 'Aangepast', cls: 'm-label-fiber' };
  return { label: 'Eigen recept', cls: 'm-label-light' };
}

// ── Kaart in de lijst ──────────────────────────────────────────────────
function ReceptKaart({ r, onOpen, onFav }) {
  return (
    <div className="tap" onClick={() => onOpen(r)}
      style={{ display: 'flex', alignItems: 'center', gap: 13, padding: '14px 14px', borderRadius: 16,
        border: '1px solid var(--m-line)', marginBottom: 10, background: 'var(--m-card)', cursor: 'pointer' }}>
      <div style={{ width: 46, height: 46, flex: '0 0 auto', borderRadius: 13, background: 'var(--m-card-2)',
        border: '1px solid var(--m-line)', display: 'flex', alignItems: 'center', justifyContent: 'center' }}>
        <MIcon name="book" size={19} color="var(--forest-600)" />
      </div>
      <div style={{ flex: 1, minWidth: 0 }}>
        <div style={{ fontSize: 14.5, fontWeight: 600, lineHeight: 1.25, textWrap: 'pretty' }}>{r.naam}</div>
        <div style={{ display: 'flex', gap: 6, alignItems: 'center', marginTop: 6, flexWrap: 'wrap' }}>
          <span className="num" style={{ fontSize: 12, fontWeight: 600 }}>{Math.round(r.kcal || 0)}</span>
          <span style={{ fontSize: 11, color: 'var(--ink-3)' }}>kcal</span>
          <MacroBadges m={recMacroObj(r)} size={11} />
          {(r.momenten || []).length > 0 && (
            <span style={{ fontSize: 11, color: 'var(--ink-3)' }}>· {r.momenten.map((m) => MOMENT_LABELS[m] || m).join(', ')}</span>
          )}
        </div>
      </div>
      <button className="tap" onClick={(e) => { e.stopPropagation(); onFav(r); }} title="Favoriet"
        style={{ width: 36, height: 36, flex: '0 0 auto', padding: 0, borderRadius: 999, border: 'none',
          background: 'transparent', cursor: 'pointer', display: 'flex', alignItems: 'center', justifyContent: 'center' }}>
        <MIcon name="star" size={19} sw={r.favoriet ? 0 : 1.8}
          color={r.favoriet ? 'var(--leaf-deep)' : 'var(--ink-3)'}
          style={r.favoriet ? { fill: 'var(--leaf-deep)' } : {}} />
      </button>
    </div>
  );
}

// ── Detail-view ────────────────────────────────────────────────────────
function ReceptDetail({ r, onBack, onEdit, onDelete, onFav, onBeoordeel, onVulIngredienten, vullenBusy, onMaakGerecht }) {
  const { useState } = React;
  const b = bronBadge(r.bron);
  const [pGemaakt, setPGemaakt] = useState(r.porties || 1);
  return (
    <div className="m-reveal">
      <button className="tap" onClick={onBack}
        style={{ display: 'flex', alignItems: 'center', gap: 7, background: 'none', border: 'none',
          color: 'var(--ink-2)', fontSize: 13, cursor: 'pointer', padding: '2px 0', marginBottom: 14 }}>
        <MIcon name="back" size={16} /> Recepten
      </button>

      <div style={{ display: 'flex', alignItems: 'flex-start', justifyContent: 'space-between', gap: 12, marginBottom: 10 }}>
        <h2 style={{ margin: 0, fontFamily: 'var(--m-serif)', fontSize: 24, fontWeight: 500, lineHeight: 1.15, letterSpacing: '-0.015em', color: 'var(--forest-950)' }}>{r.naam}</h2>
        <button className="tap" onClick={() => onFav(r)} title="Favoriet"
          style={{ width: 40, height: 40, flex: '0 0 auto', padding: 0, borderRadius: 999, border: '1px solid var(--m-line)',
            background: 'var(--m-card)', cursor: 'pointer', display: 'flex', alignItems: 'center', justifyContent: 'center' }}>
          <MIcon name="star" size={19} sw={r.favoriet ? 0 : 1.8}
            color={r.favoriet ? 'var(--leaf-deep)' : 'var(--ink-3)'}
            style={r.favoriet ? { fill: 'var(--leaf-deep)' } : {}} />
        </button>
      </div>

      <div style={{ display: 'flex', gap: 7, flexWrap: 'wrap', marginBottom: 16 }}>
        <span className={`m-badge ${b.cls}`}>{b.label}</span>
        {(r.momenten || []).map((m) => (
          <span key={m} className="m-badge m-label-light">{MOMENT_LABELS[m] || m}</span>
        ))}
      </div>

      {/* Macro's per portie */}
      <div style={{ background: 'var(--m-card)', border: '1px solid var(--m-line)', borderRadius: 18,
        padding: '16px 18px', boxShadow: 'var(--m-shadow)', marginBottom: 16 }}>
        <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'baseline', marginBottom: 10 }}>
          <span className="m-eyebrow">Per portie</span>
          <span style={{ fontSize: 11.5, color: 'var(--ink-3)' }}>{r.porties} {r.porties === 1 ? 'portie' : 'porties'} totaal</span>
        </div>
        <div style={{ display: 'flex', gap: 8, alignItems: 'center', flexWrap: 'wrap' }}>
          <span className="num" style={{ fontSize: 22, fontWeight: 600 }}>{Math.round(r.kcal || 0)}</span>
          <span style={{ fontSize: 12, color: 'var(--ink-3)', marginRight: 4 }}>kcal</span>
          <MacroBadges m={recMacroObj(r)} size={12.5} />
        </div>
      </div>

      {/* Ingrediënten */}
      <span className="m-eyebrow">Ingrediënten</span>
      <div style={{ marginTop: 8, marginBottom: 18 }}>
        {(r.ingredienten || []).map((i, idx) => (
          <div key={idx} style={{ display: 'flex', alignItems: 'center', gap: 10, padding: '9px 0',
            borderBottom: idx < r.ingredienten.length - 1 ? '1px solid var(--m-line)' : 'none' }}>
            <span style={{ flex: 1, fontSize: 14, fontWeight: 500 }}>
              {i.naam}
              {i.geschat && (
                <span title="Macro's geschat — controleer indien nodig" style={{ marginLeft: 6, color: 'var(--macro-fat)', fontSize: 12 }}>⚠</span>
              )}
            </span>
            <span className="num" style={{ fontSize: 12.5, color: 'var(--ink-2)' }}>{Math.round(i.hoeveelheid_g || 0)} g</span>
            <span className="num" style={{ fontSize: 12, color: 'var(--ink-3)', width: 58, textAlign: 'right' }}>{Math.round(i.kcal || 0)} kcal</span>
          </div>
        ))}
        {!(r.ingredienten || []).length && (
          <div style={{ padding: '12px 13px', background: 'rgba(192,106,68,0.08)', border: '1px solid rgba(192,106,68,0.25)',
            borderRadius: 13, marginTop: 4 }}>
            <div style={{ fontSize: 12.5, color: 'var(--forest-950)', lineHeight: 1.45, marginBottom: 10 }}>
              ⚠ Dit recept heeft nog geen ingrediënten — de macro's zijn niet onderbouwd. Laat Moderis ze aanvullen, dan worden de macro's herberekend.
            </div>
            <button className="m-btn m-btn-primary tap" onClick={() => onVulIngredienten(r)} disabled={vullenBusy}
              style={{ fontSize: 13, padding: '9px 14px', opacity: vullenBusy ? 0.6 : 1 }}>
              {vullenBusy ? <Spinner size={14} /> : <MIcon name="spark" size={14} color="var(--on-forest)" />} {vullenBusy ? 'Bezig…' : 'Ingrediënten aanvullen'}
            </button>
          </div>
        )}
      </div>

      {/* Bereiding */}
      {r.bereiding && (
        <React.Fragment>
          <span className="m-eyebrow">Bereiding</span>
          <div style={{ marginTop: 8, marginBottom: 18, fontSize: 14, lineHeight: 1.6, color: 'var(--forest-950)', whiteSpace: 'pre-wrap' }}>{r.bereiding}</div>
        </React.Fragment>
      )}

      {/* Feedback — voedt straks de suggesties (fase 2) */}
      <div style={{ display: 'flex', gap: 9, marginBottom: 18 }}>
        <button className="m-btn m-btn-ghost tap" onClick={() => onBeoordeel(r, r.beoordeling === 1 ? 0 : 1)}
          style={{ flex: 1, fontSize: 13, ...(r.beoordeling === 1 ? { background: 'var(--forest-100)', borderColor: 'var(--forest-200)', color: 'var(--forest-700)' } : {}) }}>
          👍 Lekker
        </button>
        <button className="m-btn m-btn-ghost tap" onClick={() => onBeoordeel(r, r.beoordeling === -1 ? 0 : -1)}
          style={{ flex: 1, fontSize: 13, ...(r.beoordeling === -1 ? { background: 'rgba(192,106,68,0.10)', borderColor: 'rgba(192,106,68,0.30)', color: 'var(--macro-fat)' } : {}) }}>
          👎 Niet voor mij
        </button>
      </div>

      {/* Gekookt? Porties als restje in de voorraad zetten */}
      {onMaakGerecht && (
        <div style={{ marginBottom: 14, padding: '13px 14px', background: 'var(--m-card-2)', border: '1px solid var(--m-line)', borderRadius: 14 }}>
          <div style={{ fontSize: 12.5, color: 'var(--ink-2)', lineHeight: 1.45, marginBottom: 10 }}>
            Gekookt? Zet de porties in je voorraad — de ingrediënten worden dan afgehaald en de porties komen bij "op te maken".
          </div>
          <div style={{ display: 'flex', gap: 8, alignItems: 'center', flexWrap: 'wrap' }}>
            <span style={{ fontSize: 13, color: 'var(--ink-2)' }}>Porties gemaakt:</span>
            <input type="number" min="0.5" step="0.5" value={pGemaakt} onChange={(e) => setPGemaakt(e.target.value)}
              style={{ width: 64, padding: '8px 10px', fontSize: 13.5, borderRadius: 10, border: '1px solid var(--m-line-2)', background: 'var(--m-card)', fontFamily: 'inherit' }} />
            <button className="m-btn m-btn-primary tap" onClick={() => onMaakGerecht(r, pGemaakt)}
              style={{ fontSize: 13, padding: '9px 13px' }}>
              <MIcon name="box" size={15} color="var(--on-forest)" /> Ik heb dit gemaakt
            </button>
          </div>
        </div>
      )}

      <div style={{ display: 'flex', gap: 9 }}>
        <button className="m-btn m-btn-primary tap" onClick={() => onEdit(r)} style={{ flex: 1, fontSize: 14 }}>
          <MIcon name="pencil" size={15} color="var(--on-forest)" /> Bewerken
        </button>
        <button className="m-btn m-btn-ghost tap" onClick={() => onDelete(r)}
          style={{ fontSize: 14, color: 'var(--macro-fat)' }}>
          <MIcon name="trash" size={15} color="var(--macro-fat)" /> Verwijderen
        </button>
      </div>
    </div>
  );
}

// iPhone-foto's zijn vaak HEIC/HEIF — dat kan een laptop-browser (Chrome/
// Firefox) niet in een <img>/canvas decoderen, en het AI-model accepteert het
// ook niet. We zetten zulke bestanden client-side om naar JPEG met heic2any,
// dat pas ingeladen wordt zodra er écht een HEIC-bestand gekozen is.
function isHeicBestand(file) {
  const t = String((file && file.type) || '').toLowerCase();
  const n = String((file && file.name) || '').toLowerCase();
  return t === 'image/heic' || t === 'image/heif' || /\.hei[cf]$/.test(n);
}
function laadHeic2any() {
  if (window.heic2any) return Promise.resolve();
  if (!window.__heic2anyLaden) {
    window.__heic2anyLaden = new Promise((resolve, reject) => {
      const s = document.createElement('script');
      s.src = 'https://cdn.jsdelivr.net/npm/heic2any@0.0.4/dist/heic2any.min.js';
      s.onload = () => resolve();
      s.onerror = () => reject(new Error('HEIC-omzetter kon niet laden (geen internet?).'));
      document.head.appendChild(s);
    });
  }
  return window.__heic2anyLaden;
}
// Zet een HEIC/HEIF-bestand om naar een JPEG-blob. Probeer eerst heic-to (heeft
// een recentere libheif die veel meer iPhone-varianten aankan); lukt dat niet,
// val terug op heic2any. Faalt alles → duidelijke, uitvoerbare tip.
async function heicNaarJpegBlob(file) {
  try {
    const mod = await import('https://esm.sh/heic-to@1.5.2');
    const fn = mod.heicTo || (mod.default && mod.default.heicTo);
    if (fn) {
      const out = await fn({ blob: file, type: 'image/jpeg', quality: 0.85 });
      return Array.isArray(out) ? out[0] : out;
    }
  } catch (e) { /* val terug op heic2any */ }
  try {
    await laadHeic2any();
    const out = await window.heic2any({ blob: file, toType: 'image/jpeg', quality: 0.85 });
    return Array.isArray(out) ? out[0] : out;
  } catch (e) { /* beide mislukt */ }
  throw new Error('Deze HEIC-foto kon niet omgezet worden. Tip: zet op je iPhone bij Instellingen → Camera → Formaten op "Meest compatibel" (maakt JPEG), of upload een JPEG/screenshot.');
}

async function normaliseerFoto(file) {
  if (!isHeicBestand(file)) return file;
  return await heicNaarJpegBlob(file);
}

// Schaal een foto/screenshot terug (max 1600 px, JPEG) vóór de upload: de
// serverless body-limiet is ~4,5 MB en het AI-model heeft geen 4K nodig.
// HEIC (iPhone) wordt eerst naar JPEG omgezet.
async function comprimeerAfbeelding(file) {
  const bron = await normaliseerFoto(file);
  return await new Promise((resolve, reject) => {
    const reader = new FileReader();
    reader.onerror = () => reject(new Error('Afbeelding lezen mislukt.'));
    reader.onload = () => {
      const img = new Image();
      img.onerror = () => reject(new Error('Dit is geen geldige afbeelding.'));
      img.onload = () => {
        const max = 1600;
        const f = Math.min(1, max / Math.max(img.width, img.height));
        const canvas = document.createElement('canvas');
        canvas.width = Math.max(1, Math.round(img.width * f));
        canvas.height = Math.max(1, Math.round(img.height * f));
        canvas.getContext('2d').drawImage(img, 0, 0, canvas.width, canvas.height);
        const dataUrl = canvas.toDataURL('image/jpeg', 0.82);
        resolve({ image: dataUrl.split(',')[1], media_type: 'image/jpeg' });
      };
      img.src = reader.result;
    };
    reader.readAsDataURL(bron);
  });
}

// Bekende per-100g-macro's van een ingrediënt: uit het recept (per100 zit in
// de opgeslagen jsonb) of afgeleid uit de opgeslagen macro's + gram. Hiermee
// herschaalt de editor een gewichtswijziging lokaal i.p.v. de macro's te
// wissen — zo verspringt het totaal niet als je één gram aanpast.
function leidPer100Af(i) {
  if (i && i.per100 && i.per100.kcal_100g != null) return i.per100;
  const g = Number(i && i.hoeveelheid_g) || 0;
  if (!(g > 0) || i == null || i.kcal == null) return null;
  const r1 = (n) => Math.round(((Number(n) || 0) * 100 / g) * 10) / 10;
  return { kcal_100g: r1(i.kcal), eiwitten_100g: r1(i.eiwitten),
    koolhydraten_100g: r1(i.koolhydraten), vetten_100g: r1(i.vetten) };
}

// ── Edit/Create-view ───────────────────────────────────────────────────
function ReceptEdit({ start, onBack, onSaved, showToast }) {
  const { useState, useRef } = React;
  const [naam, setNaam] = useState(start?.naam || '');
  const [porties, setPorties] = useState(start?.porties || 1);
  const [momenten, setMomenten] = useState(start?.momenten || []);
  const [bereiding, setBereiding] = useState(start?.bereiding || '');
  const [ingredienten, setIngredienten] = useState(
    (start?.ingredienten || []).map((i) => ({ naam: i.naam || '', hoeveelheid_g: i.hoeveelheid_g || '',
      kcal: i.kcal, eiwitten: i.eiwitten, koolhydraten: i.koolhydraten, vetten: i.vetten, geschat: i.geschat,
      per100: leidPer100Af(i) })),
  );
  const [wens, setWens] = useState('');
  const [genereren, setGenereren] = useState(false);
  const [fotoBusy, setFotoBusy] = useState(false);
  const fotoInput = useRef(null);
  const [opslaan, setOpslaan] = useState(false);
  // Schaal-hint: verschijnt als je één hoeveelheid of de porties wijzigt, en
  // biedt aan de rest evenredig mee te schalen (als je dat wilt).
  const [scaleHint, setScaleHint] = useState(null);
  // Baseline = de "vastgestelde" porties/hoeveelheden. De hint vergelijkt
  // hiertegen — niet tegen een vorige tussenwaarde — zodat terug naar de oude
  // waarde de hint weer laat verdwijnen i.p.v. een omgekeerde factor te tonen.
  const baseline = React.useRef({
    porties: Number(start?.porties) || 1,
    amounts: (start?.ingredienten || []).map((i) => Number(i.hoeveelheid_g) || 0),
  });

  const isEdit = !!start?.id;
  const round = (n) => Math.round(Number(n) || 0);
  const fmtRatio = (r) => '×' + r.toFixed(2).replace(/\.?0+$/, '').replace('.', ',');

  const rnd1 = (n) => Math.round((Number(n) || 0) * 10) / 10;

  // Gewicht gewijzigd → macro's HERSCHALEN uit per100, niet wissen: de
  // preview blijft dan kloppen (1 g meer is 1 g meer, geen sprong). Alleen
  // een andere NAAM is een ander product — dan gaan de macro's weg en zoekt
  // herberekenRegel ze proactief opnieuw op (bij het verlaten van het veld).
  const setIng = (idx, veld, waarde) => {
    setIngredienten((arr) => arr.map((it, i) => {
      if (i !== idx) return it;
      if (veld === 'hoeveelheid_g' && it.per100) {
        const f = (Number(waarde) || 0) / 100;
        return { ...it, hoeveelheid_g: waarde,
          kcal: rnd1(it.per100.kcal_100g * f), eiwitten: rnd1(it.per100.eiwitten_100g * f),
          koolhydraten: rnd1(it.per100.koolhydraten_100g * f), vetten: rnd1(it.per100.vetten_100g * f) };
      }
      return { ...it, [veld]: waarde, per100: veld === 'naam' ? null : it.per100,
        kcal: undefined, eiwitten: undefined, koolhydraten: undefined, vetten: undefined, geschat: undefined };
    }));
  };

  // Proactief inladen bij openen: alle macro's vers van de server halen — de
  // opgeslagen waarden kunnen verouderd zijn (database verbeterd, voorraad
  // veranderd) en de server-pipeline is de waarheid. Zo zie je in de editor
  // meteen dezelfde macro's die opslaan ook zou opleveren.
  React.useEffect(() => {
    (async () => {
      const rijen = ingredienten.map((r, i) => ({ r, i })).filter((x) => String(x.r.naam).trim());
      if (!rijen.length) return;
      try {
        const resp = await api.berekenMacros(rijen.map((x) => ({
          naam: String(x.r.naam).trim(), hoeveelheid_g: Number(x.r.hoeveelheid_g) || 0 })));
        const verr = resp.ingredienten || [];
        setIngredienten((arr) => {
          const next = [...arr];
          rijen.forEach((x, k) => {
            const v = verr[k];
            if (!v || !next[x.i]) return;
            // Schaal naar de HUIDIGE grammen (niet v.kcal letterlijk): heb je
            // tijdens het laden al een gram aangepast, dan telt die mee.
            const f = (Number(next[x.i].hoeveelheid_g) || 0) / 100;
            const p = v.per100;
            next[x.i] = { ...next[x.i], per100: p, geschat: v.geschat,
              kcal: p ? rnd1(p.kcal_100g * f) : v.kcal,
              eiwitten: p ? rnd1(p.eiwitten_100g * f) : v.eiwitten,
              koolhydraten: p ? rnd1(p.koolhydraten_100g * f) : v.koolhydraten,
              vetten: p ? rnd1(p.vetten_100g * f) : v.vetten };
          });
          return next;
        });
      } catch (_) { /* stil — bij opslaan rekent de server sowieso */ }
    })();
    // eslint-disable-next-line
  }, []);

  // Proactief inladen per regel: een nieuw of hernoemd ingrediënt wordt
  // meteen opgezocht zodra je het veld verlaat — je ziet de juiste macro's
  // dus al vóór het opslaan, niet pas erna.
  const herberekenRegel = async (idx, naamOverride) => {
    const r = ingredienten[idx];
    const naamNu = String(naamOverride != null ? naamOverride : (r && r.naam) || '').trim();
    if (!naamNu) return;
    if (naamOverride == null && r && r.per100) return;   // al bekend → niets doen
    try {
      const resp = await api.berekenMacros([{ naam: naamNu, hoeveelheid_g: Number(r && r.hoeveelheid_g) || 0 }]);
      const v = (resp.ingredienten || [])[0];
      if (v) setIngredienten((arr) => arr.map((it, i) => {
        if (i !== idx) return it;
        // Schaal naar de huidige grammen — die kunnen intussen gewijzigd zijn.
        const f = (Number(it.hoeveelheid_g) || 0) / 100;
        const p = v.per100;
        return { ...it, per100: p, geschat: v.geschat,
          kcal: p ? rnd1(p.kcal_100g * f) : v.kcal,
          eiwitten: p ? rnd1(p.eiwitten_100g * f) : v.eiwitten,
          koolhydraten: p ? rnd1(p.koolhydraten_100g * f) : v.koolhydraten,
          vetten: p ? rnd1(p.vetten_100g * f) : v.vetten };
      }));
    } catch (_) { /* stil — opslaan berekent alsnog wat ontbreekt */ }
  };

  // Vergelijk bij blur tegen de baseline → toon, vervang of wis de hint.
  const onAmountBlur = (idx) => {
    const now = Number(ingredienten[idx] && ingredienten[idx].hoeveelheid_g) || 0;
    const base = baseline.current.amounts[idx];
    if (base > 0 && now > 0 && now !== base) {
      setScaleHint({ type: 'ing', idx, naam: ingredienten[idx].naam || 'dit ingrediënt', ratio: now / base });
    } else {
      setScaleHint((h) => (h && h.type === 'ing' && h.idx === idx) ? null : h);
    }
  };
  // Porties is puur de DELER (totaal ÷ porties); het herschaalt de ingrediënten
  // niet meer. Zo kun je na een import gewoon zeggen "dit is voor 2 porties".

  // "Ja" — schaal de overige hoeveelheden mee en verschuif de baseline mee.
  const pasScaleToe = () => {
    if (!scaleHint) return;
    const r = scaleHint.ratio;
    setIngredienten((arr) => {
      const next = arr.map((it, i) => {
        if (scaleHint.type === 'ing' && i === scaleHint.idx) return it;
        const g = Number(it.hoeveelheid_g) || 0;
        if (!g) return it;
        const ng = round(g * r);
        // Zelfde principe als setIng: herschalen uit per100 waar dat kan.
        if (it.per100) {
          const f = ng / 100;
          return { ...it, hoeveelheid_g: ng,
            kcal: rnd1(it.per100.kcal_100g * f), eiwitten: rnd1(it.per100.eiwitten_100g * f),
            koolhydraten: rnd1(it.per100.koolhydraten_100g * f), vetten: rnd1(it.per100.vetten_100g * f) };
        }
        return { ...it, hoeveelheid_g: ng, kcal: undefined, geschat: undefined };
      });
      baseline.current.amounts = next.map((it) => Number(it.hoeveelheid_g) || 0);
      return next;
    });
    baseline.current.porties = Number(porties) || baseline.current.porties;
    setScaleHint(null);
  };

  // "Nee" — accepteer de losse wijziging als nieuwe baseline, zonder schalen.
  const negeerScale = () => {
    if (scaleHint) {
      if (scaleHint.type === 'por') {
        baseline.current.porties = Number(porties) || baseline.current.porties;
      } else {
        baseline.current.amounts[scaleHint.idx] =
          Number(ingredienten[scaleHint.idx] && ingredienten[scaleHint.idx].hoeveelheid_g) || 0;
      }
    }
    setScaleHint(null);
  };
  const addIng = () => {
    baseline.current.amounts = [...baseline.current.amounts, 0];
    setIngredienten((arr) => [...arr, { naam: '', hoeveelheid_g: '' }]);
  };
  const removeIng = (idx) => {
    baseline.current.amounts = baseline.current.amounts.filter((_, i) => i !== idx);
    setIngredienten((arr) => arr.filter((_, i) => i !== idx));
    setScaleHint((h) => (h && h.type === 'ing') ? null : h);
  };
  const toggleMoment = (m) => setMomenten((ms) => ms.includes(m) ? ms.filter((x) => x !== m) : [...ms, m]);

  // Concept (van AI of foto) in het formulier zetten — zelfde pad voor beide.
  const vulConcept = (draft, fallbackNaam) => {
    setNaam(draft.naam || fallbackNaam || '');
    setPorties(draft.porties || 1);
    setMomenten(draft.momenten && draft.momenten.length ? draft.momenten.filter((m) => MOMENT_KEYS.includes(m)) : momenten);
    setBereiding(draft.bereiding || '');
    const nieuweIng = (draft.ingredienten || []).map((i) => ({ naam: i.naam, hoeveelheid_g: i.hoeveelheid_g,
      kcal: i.kcal, eiwitten: i.eiwitten, koolhydraten: i.koolhydraten, vetten: i.vetten, geschat: i.geschat,
      per100: leidPer100Af(i) }));
    setIngredienten(nieuweIng);
    // Verse baseline → geen valse schaal-hint direct na het invullen.
    baseline.current = { porties: draft.porties || 1, amounts: nieuweIng.map((i) => Number(i.hoeveelheid_g) || 0) };
    setScaleHint(null);
  };

  const genereer = async () => {
    if (!wens.trim() || genereren || fotoBusy) return;
    setGenereren(true);
    try {
      const draft = await api.genereerRecept({ wens: wens.trim(), moment: momenten[0] || null });
      vulConcept(draft, wens.trim());
      showToast('Concept klaar — pas aan en sla op');
    } catch (err) { showToast('Genereren mislukt: ' + err.message); }
    setGenereren(false);
  };

  // Eén of meer foto's/screenshots van een recept → Moderis leest ze (en
  // combineert ze, bv. ingrediënten + bereiding van een HelloFresh-kaart) en
  // vult het formulier.
  const vanFotos = async (files) => {
    const lijst = Array.from(files || []).slice(0, 5);
    if (!lijst.length || fotoBusy || genereren) return;
    setFotoBusy(true);
    try {
      const images = [];
      for (const f of lijst) images.push(await comprimeerAfbeelding(f));
      const draft = await api.receptFoto({ images });
      vulConcept(draft);
      showToast(lijst.length > 1
        ? lijst.length + ' foto’s gelezen — controleer en sla op'
        : 'Recept van de foto gelezen — controleer en sla op');
    } catch (err) { showToast(err.message || 'Foto lezen mislukt'); }
    setFotoBusy(false);
  };

  const bewaar = async () => {
    if (!naam.trim()) { showToast('Geef het recept een naam'); return; }
    if (opslaan) return;
    setOpslaan(true);
    const payload = {
      naam: naam.trim(),
      bereiding,
      porties: Math.max(1, Math.floor(Number(porties) || 1)),
      momenten,
      ingredienten: ingredienten
        .filter((i) => String(i.naam).trim())
        .map((i) => ({ naam: String(i.naam).trim(), hoeveelheid_g: Number(i.hoeveelheid_g) || 0 })),
    };
    try {
      const saved = isEdit
        ? await api.updateRecept(start.id, { ...payload, bron: start.bron === 'ai_nieuw' ? 'aangepast' : start.bron })
        : await api.addRecept({ ...payload, bron: start?.bron || 'eigen' });
      showToast(isEdit ? 'Recept bijgewerkt' : 'Recept opgeslagen');
      onSaved(saved);
    } catch (err) { showToast('Opslaan mislukt: ' + err.message); }
    setOpslaan(false);
  };

  const inputStyle = {
    width: '100%', boxSizing: 'border-box', padding: '11px 13px', fontSize: 14,
    border: '1px solid var(--m-line-2)', borderRadius: 12, background: 'var(--m-card)',
    color: 'var(--forest-950)', fontFamily: 'inherit',
  };

  // Live per-portie-preview: som van de ingrediënt-macro's ÷ porties. Direct
  // na een import dragen de ingrediënten hun macro's, dus dit klopt meteen; bij
  // handmatig getypte ingrediënten worden de macro's pas bij opslaan bepaald.
  const por = Math.max(1, Number(porties) || 1);
  const totMacro = ingredienten.reduce((s, i) => ({
    kcal: s.kcal + (Number(i.kcal) || 0),
    eiwitten: s.eiwitten + (Number(i.eiwitten) || 0),
    koolhydraten: s.koolhydraten + (Number(i.koolhydraten) || 0),
    vetten: s.vetten + (Number(i.vetten) || 0),
  }), { kcal: 0, eiwitten: 0, koolhydraten: 0, vetten: 0 });
  const heeftMacros = ingredienten.some((i) => i.kcal != null);
  const perPortie = {
    kcal: totMacro.kcal / por, eiwitten: totMacro.eiwitten / por,
    koolhydraten: totMacro.koolhydraten / por, vetten: totMacro.vetten / por,
  };
  const zetPorties = (v) => setPorties(String(Math.max(1, Math.floor(Number(v) || 1))));

  return (
    <div className="m-reveal">
      <button className="tap" onClick={onBack}
        style={{ display: 'flex', alignItems: 'center', gap: 7, background: 'none', border: 'none',
          color: 'var(--ink-2)', fontSize: 13, cursor: 'pointer', padding: '2px 0', marginBottom: 14 }}>
        <MIcon name="back" size={16} /> Terug
      </button>

      <h2 style={{ margin: '0 0 16px', fontFamily: 'var(--m-serif)', fontSize: 24, fontWeight: 500, color: 'var(--forest-950)' }}>
        {isEdit ? 'Recept bewerken' : 'Nieuw recept'}
      </h2>

      {/* Genereer met Moderis of lees van een foto (alleen bij nieuw) */}
      {!isEdit && (
        <div style={{ background: 'var(--forest-100)', border: '1px solid var(--forest-200)', borderRadius: 16, padding: '13px 14px', marginBottom: 18 }}>
          <div style={{ display: 'flex', alignItems: 'center', gap: 8, marginBottom: 9 }}>
            <MIcon name="spark" size={15} color="var(--forest-600)" />
            <span style={{ fontSize: 12.5, color: 'var(--forest-900)', fontWeight: 500 }}>Laat Moderis een recept bedenken</span>
          </div>
          <div style={{ display: 'flex', gap: 8 }}>
            <input value={wens} onChange={(e) => setWens(e.target.value)} placeholder="bv. eiwitrijke lunch met kip"
              onKeyDown={(e) => e.key === 'Enter' && genereer()}
              style={{ ...inputStyle, flex: 1 }} />
            <button className="m-btn m-btn-primary tap" onClick={genereer} disabled={genereren || fotoBusy || !wens.trim()}
              style={{ fontSize: 13, padding: '0 16px', opacity: (genereren || fotoBusy || !wens.trim()) ? 0.5 : 1, display: 'inline-flex', alignItems: 'center', gap: 6 }}>
              {genereren ? <Spinner size={14} /> : null}{genereren ? 'Bezig' : 'Genereer'}
            </button>
          </div>
          {/* Foto('s) van een recept (kookboek, site, HelloFresh-kaart) → concept.
              multiple = camera of galerij; meerdere foto's worden gecombineerd. */}
          <input ref={fotoInput} type="file" accept="image/*,.heic,.heif" multiple style={{ display: 'none' }}
            onChange={(e) => { const fs = Array.from(e.target.files || []); e.target.value = ''; vanFotos(fs); }} />
          <button className="m-btn m-btn-ghost tap" onClick={() => fotoInput.current && fotoInput.current.click()}
            disabled={fotoBusy || genereren}
            style={{ width: '100%', fontSize: 13, padding: '10px', marginTop: 9,
              ...(fotoBusy ? { opacity: 0.6, cursor: 'wait' } : {}) }}>
            {fotoBusy ? <Spinner size={15} /> : <MIcon name="scan" size={15} color="var(--forest-600)" />}
            {fotoBusy ? 'Foto’s lezen…' : 'Of maak foto’s / kies uit galerij (bv. HelloFresh)'}
          </button>
          <div style={{ fontSize: 11, color: 'var(--ink-3)', marginTop: 6, lineHeight: 1.4 }}>
            Tip: fotografeer de ingrediëntenlijst (en eventueel de bereiding) — meerdere foto’s mag.
          </div>
        </div>
      )}

      {/* Naam */}
      <label className="m-eyebrow" style={{ display: 'block', marginBottom: 6 }}>Naam</label>
      <input value={naam} onChange={(e) => setNaam(e.target.value)} placeholder="Naam van het recept"
        style={{ ...inputStyle, marginBottom: 16 }} />

      {/* Voor hoeveel porties? Porties is de DELER: de hoeveelheden zijn het
          totaal, de macro's gelden per portie. Handig bij een import
          (bv. HelloFresh voor 2 personen → zet op 2). */}
      <label className="m-eyebrow" style={{ display: 'block', marginBottom: 6 }}>Voor hoeveel porties?</label>
      <div style={{ display: 'flex', alignItems: 'center', gap: 12, marginBottom: 6, flexWrap: 'wrap' }}>
        <div style={{ display: 'inline-flex', alignItems: 'center', border: '1px solid var(--m-line-2)', borderRadius: 12, overflow: 'hidden', flex: '0 0 auto' }}>
          <button type="button" className="tap" onClick={() => zetPorties(por - 1)} disabled={por <= 1}
            style={{ width: 42, height: 44, border: 'none', background: 'var(--m-card-2)', cursor: por <= 1 ? 'default' : 'pointer', fontSize: 22, lineHeight: 1, color: 'var(--forest-700)', opacity: por <= 1 ? 0.4 : 1 }}>−</button>
          <input type="number" min="1" value={porties} onChange={(e) => setPorties(e.target.value)}
            style={{ width: 54, height: 44, textAlign: 'center', border: 'none', borderLeft: '1px solid var(--m-line)', borderRight: '1px solid var(--m-line)', background: 'var(--m-card)', fontSize: 16, fontWeight: 600, fontFamily: 'inherit', color: 'var(--forest-950)' }} />
          <button type="button" className="tap" onClick={() => zetPorties(por + 1)}
            style={{ width: 42, height: 44, border: 'none', background: 'var(--m-card-2)', cursor: 'pointer', fontSize: 19, lineHeight: 1, color: 'var(--forest-700)' }}>＋</button>
        </div>
        {heeftMacros && (
          <div style={{ fontSize: 12.5, color: 'var(--ink-2)', lineHeight: 1.35 }}>
            <span style={{ color: 'var(--ink-3)' }}>Per portie ≈</span>{' '}
            <strong className="num">{round(perPortie.kcal)}</strong> kcal
            <span className="num" style={{ color: 'var(--ink-3)' }}> · E {round(perPortie.eiwitten)} K {round(perPortie.koolhydraten)} V {round(perPortie.vetten)}</span>
          </div>
        )}
      </div>
      <div style={{ fontSize: 11, color: 'var(--ink-3)', marginBottom: 16, lineHeight: 1.4 }}>
        De hoeveelheden hieronder zijn het totaal van het recept; de macro's worden per portie berekend (totaal ÷ porties).
      </div>

      <label className="m-eyebrow" style={{ display: 'block', marginBottom: 8 }}>Geschikt voor</label>
      <div style={{ display: 'flex', gap: 7, flexWrap: 'wrap', marginBottom: 18 }}>
        {MOMENT_KEYS.map((m) => (
          <button key={m} className={'m-chip' + (momenten.includes(m) ? ' is-active' : '')}
            onClick={() => toggleMoment(m)} style={{ padding: '7px 13px' }}>
            {MOMENT_LABELS[m]}
          </button>
        ))}
      </div>

      {/* Ingrediënten */}
      <label className="m-eyebrow" style={{ display: 'block', marginBottom: 8 }}>Ingrediënten</label>
      <div style={{ marginBottom: 10 }}>
        {ingredienten.map((i, idx) => (
          <div key={idx} style={{ display: 'flex', gap: 8, alignItems: 'center', marginBottom: 8 }}>
            <IngredientNaamInput value={i.naam}
              onChange={(v) => setIng(idx, 'naam', v)}
              onPick={(r) => { setIng(idx, 'naam', r.naam); herberekenRegel(idx, r.naam); }}
              onBlur={() => herberekenRegel(idx)}
              style={{ ...inputStyle, flex: 1 }} />
            <input type="number" min="0" value={i.hoeveelheid_g} onChange={(e) => setIng(idx, 'hoeveelheid_g', e.target.value)} placeholder="g"
              onBlur={() => { onAmountBlur(idx); herberekenRegel(idx); }}
              style={{ ...inputStyle, width: 72 }} />
            <span style={{ width: 52, fontSize: 11.5, color: 'var(--ink-3)', textAlign: 'right' }} className="num">
              {i.kcal != null ? Math.round(i.kcal) + (i.geschat ? '⚠' : '') : '–'}
            </span>
            <button className="tap" onClick={() => removeIng(idx)} title="Verwijder"
              style={{ width: 32, height: 32, flex: '0 0 auto', padding: 0, borderRadius: 999, border: '1px solid var(--m-line)',
                background: 'var(--m-card)', cursor: 'pointer', display: 'flex', alignItems: 'center', justifyContent: 'center' }}>
              <MIcon name="minus" size={15} color="var(--ink-2)" />
            </button>
          </div>
        ))}
      </div>
      {scaleHint && (
        <div style={{ display: 'flex', alignItems: 'center', gap: 10, padding: '11px 13px', marginBottom: 10,
          background: 'var(--forest-100)', border: '1px solid var(--forest-200)', borderRadius: 14 }}>
          <MIcon name="spark" size={15} color="var(--forest-600)" />
          <span style={{ flex: 1, fontSize: 12.5, color: 'var(--forest-900)', lineHeight: 1.4 }}>
            {scaleHint.type === 'ing'
              ? `Rest meeschalen met ${scaleHint.naam} (${fmtRatio(scaleHint.ratio)})?`
              : `Ingrediënten meeschalen met de porties (${fmtRatio(scaleHint.ratio)})?`}
          </span>
          <button className="m-btn m-btn-primary tap" onClick={pasScaleToe} style={{ fontSize: 12.5, padding: '6px 13px' }}>Ja</button>
          <button className="m-btn m-btn-ghost tap" onClick={negeerScale} style={{ fontSize: 12.5, padding: '6px 12px' }}>Nee</button>
        </div>
      )}
      <button className="m-btn m-btn-ghost tap" onClick={addIng} style={{ fontSize: 13, marginBottom: 6 }}>
        <MIcon name="plus" size={15} color="var(--forest-600)" /> Ingrediënt toevoegen
      </button>
      <div style={{ fontSize: 11.5, color: 'var(--ink-3)', marginBottom: 18 }}>
        Macro's rekenen live mee: gram wijzigen herschaalt, een nieuw of hernoemd
        ingrediënt wordt automatisch opgezocht (⚠ = geschat).
      </div>

      {/* Bereiding */}
      <label className="m-eyebrow" style={{ display: 'block', marginBottom: 6 }}>Bereiding</label>
      <textarea value={bereiding} onChange={(e) => setBereiding(e.target.value)} rows={6} placeholder="Hoe maak je het? Stap voor stap…"
        style={{ ...inputStyle, marginBottom: 18, resize: 'vertical', lineHeight: 1.5 }} />

      <button className="m-btn m-btn-primary tap" onClick={bewaar} disabled={opslaan}
        style={{ width: '100%', fontSize: 14.5, padding: '13px', opacity: opslaan ? 0.6 : 1 }}>
        {opslaan ? <Spinner size={16} /> : <MIcon name="check" size={16} sw={2.2} color="var(--on-forest)" />}
        {opslaan ? 'Opslaan…' : (isEdit ? 'Wijzigingen opslaan' : 'Recept opslaan')}
      </button>
    </div>
  );
}

// ── Hoofdscherm: regelt de drie views ──────────────────────────────────
function RecipesScreen({ showToast, onMaakGerecht, onClose }) {
  const { useState, useEffect, useRef } = React;
  const [view, setView] = useState('list');     // list | detail | edit
  const [recepten, setRecepten] = useState([]);
  const [actief, setActief] = useState(null);     // detail/edit doelwit
  const [loading, setLoading] = useState(true);
  const [vullenBusy, setVullenBusy] = useState(false);
  const [toonArchief, setToonArchief] = useState(false);
  const [fotoBusy, setFotoBusy] = useState(false);
  const fotoInput = useRef(null);

  // Direct vanuit de lijst: foto('s) van een recept → concept → open het
  // bewerkscherm ingevuld (controleren en opslaan). Zelfde backend als in de editor.
  const leesFotos = async (files) => {
    const lijst = Array.from(files || []).slice(0, 5);
    if (!lijst.length || fotoBusy) return;
    setFotoBusy(true);
    showToast(lijst.length > 1 ? lijst.length + ' foto’s lezen…' : 'Foto lezen…');
    try {
      const images = [];
      for (const f of lijst) images.push(await comprimeerAfbeelding(f));
      const draft = await api.receptFoto({ images });
      setActief(draft);          // geen id → opent als nieuw, maar ingevuld
      setView('edit');
      showToast('Recept gelezen — controleer en sla op');
    } catch (err) { showToast(err.message || 'Foto lezen mislukt'); }
    setFotoBusy(false);
  };

  const herlaad = async () => {
    try {
      const lijst = await api.recepten();
      setRecepten(lijst || []);
    } catch (err) { showToast('Recepten laden mislukt: ' + err.message); }
    setLoading(false);
  };
  useEffect(() => { herlaad(); /* eslint-disable-next-line */ }, []);

  const openDetail = (r) => { setActief(r); setView('detail'); };
  const openNieuw = () => { setActief(null); setView('edit'); };
  const openBewerk = (r) => { setActief(r); setView('edit'); };

  const naList = () => { setActief(null); setView('list'); herlaad(); };

  // Optimistische patch op één recept (favoriet/beoordeling), met API-sync.
  const patchRecept = async (r, patch) => {
    const next = { ...r, ...patch };
    setRecepten((L) => L.map((x) => x.id === r.id ? next : x));
    if (actief && actief.id === r.id) setActief(next);
    try { await api.updateRecept(r.id, patch); }
    catch (err) { showToast('Opslaan mislukt: ' + err.message); herlaad(); }
  };
  const toggleFav = (r) => patchRecept(r, { favoriet: !r.favoriet });
  const beoordeel = (r, waarde) => patchRecept(r, { beoordeling: waarde });
  // Uit het archief terughalen: beoordeling terug naar neutraal → verschijnt
  // weer in de pool en in deze lijst.
  const herstel = (r) => { patchRecept(r, { beoordeling: 0 }); showToast(r.naam + ' teruggezet'); };

  // Bestaand recept zonder ingrediënten alsnog ingrediënt-gebaseerd maken:
  // Moderis schat de ingrediënten op naam → updateRecept herberekent de macro's.
  const vulIngredienten = async (r) => {
    if (vullenBusy) return;
    setVullenBusy(true);
    try {
      // Eén pipeline-pass op de server (schat ingrediënten uit de naam +
      // herbereken de macro's) — niet genereren én opslaan apart.
      const updated = await api.updateRecept(r.id, { herbereken: true });
      setActief(updated);
      showToast('Ingrediënten aangevuld — macro\'s herberekend');
      herlaad();
    } catch (err) { showToast('Aanvullen mislukt: ' + err.message); }
    setVullenBusy(false);
  };

  const verwijder = async (r) => {
    try {
      await api.deleteRecept(r.id);
      showToast('Recept verwijderd');
      naList();
    } catch (err) { showToast('Verwijderen mislukt: ' + err.message); }
  };

  if (view === 'edit') {
    return (
      <div className="screen">
        <ReceptEdit start={actief} onBack={() => actief ? openDetail(actief) : setView('list')}
          onSaved={(saved) => { herlaad(); openDetail(saved); }} showToast={showToast} />
      </div>
    );
  }

  if (view === 'detail' && actief) {
    return (
      <div className="screen">
        <ReceptDetail r={actief} onBack={naList} onEdit={openBewerk} onDelete={verwijder}
          onFav={toggleFav} onBeoordeel={beoordeel}
          onVulIngredienten={vulIngredienten} vullenBusy={vullenBusy}
          onMaakGerecht={onMaakGerecht} />
      </div>
    );
  }

  // list — actieve recepten los van het archief (beoordeling -1 = gearchiveerd).
  const actieve = recepten.filter((r) => Number(r.beoordeling) !== -1);
  const gearchiveerd = recepten.filter((r) => Number(r.beoordeling) === -1);
  return (
    <div className="screen">
      {onClose && (
        <button className="tap" onClick={onClose}
          style={{ display: 'flex', alignItems: 'center', gap: 7, background: 'none', border: 'none',
            color: 'var(--ink-2)', fontSize: 13, cursor: 'pointer', padding: '2px 0', marginBottom: 12 }}>
          <MIcon name="back" size={16} /> Vandaag
        </button>
      )}
      <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', marginBottom: 18, gap: 10 }}>
        <h2 style={{ margin: 0, fontFamily: 'var(--m-serif)', fontSize: 26, fontWeight: 500, color: 'var(--forest-950)' }}>Mijn maaltijden</h2>
        <div style={{ display: 'flex', gap: 8, flex: '0 0 auto' }}>
          <input ref={fotoInput} type="file" accept="image/*,.heic,.heif" multiple style={{ display: 'none' }}
            onChange={(e) => { const fs = Array.from(e.target.files || []); e.target.value = ''; leesFotos(fs); }} />
          <button className="m-btn m-btn-ghost tap" onClick={() => fotoInput.current && fotoInput.current.click()}
            disabled={fotoBusy} title="Maak een foto van een recept (bv. HelloFresh) — of kies uit je galerij"
            style={{ fontSize: 13.5, padding: '9px 13px', opacity: fotoBusy ? 0.6 : 1 }}>
            {fotoBusy ? <Spinner size={16} /> : <MIcon name="scan" size={16} color="var(--forest-600)" />} {fotoBusy ? 'Lezen…' : 'Foto'}
          </button>
          <button className="m-btn m-btn-primary tap" onClick={openNieuw} style={{ fontSize: 13.5, padding: '9px 15px' }}>
            <MIcon name="plus" size={16} sw={2.2} color="var(--on-forest)" /> Nieuw
          </button>
        </div>
      </div>

      {loading ? (
        <React.Fragment>
          {[0, 1, 2].map((i) => (
            <div key={i} className="m-skel" style={{ height: 74, borderRadius: 16, marginBottom: 10, border: 'none' }}></div>
          ))}
        </React.Fragment>
      ) : actieve.length ? (
        actieve.map((r) => <ReceptKaart key={r.id} r={r} onOpen={openDetail} onFav={toggleFav} />)
      ) : gearchiveerd.length ? (
        <div style={{ textAlign: 'center', padding: '32px 20px 20px', color: 'var(--ink-3)' }}>
          <div style={{ fontSize: 14, fontWeight: 600, color: 'var(--ink-2)', marginBottom: 6 }}>Alle recepten staan in je archief</div>
          <div style={{ fontSize: 13, lineHeight: 1.5, marginBottom: 16 }}>Maak een nieuw recept, of zet er hieronder een terug.</div>
        </div>
      ) : (
        <div style={{ textAlign: 'center', padding: '48px 20px', color: 'var(--ink-3)' }}>
          <MIcon name="book" size={34} color="var(--m-line-2)" style={{ margin: '0 auto 14px' }} />
          <div style={{ fontSize: 15, fontWeight: 600, color: 'var(--ink-2)', marginBottom: 6 }}>Nog geen recepten</div>
          <div style={{ fontSize: 13, lineHeight: 1.5, marginBottom: 18 }}>Maak er een, fotografeer een recept (bv. HelloFresh), of laat Moderis er één bedenken.</div>
          <div style={{ display: 'flex', gap: 8, justifyContent: 'center', flexWrap: 'wrap' }}>
            <button className="m-btn m-btn-primary tap" onClick={openNieuw} style={{ fontSize: 14 }}>
              <MIcon name="plus" size={16} sw={2.2} color="var(--on-forest)" /> Eerste recept
            </button>
            <button className="m-btn m-btn-ghost tap" onClick={() => fotoInput.current && fotoInput.current.click()} disabled={fotoBusy} style={{ fontSize: 14 }}>
              {fotoBusy ? <Spinner size={16} /> : <MIcon name="scan" size={16} color="var(--forest-600)" />} {fotoBusy ? 'Lezen…' : 'Vanaf foto'}
            </button>
          </div>
        </div>
      )}

      {/* Archief — verborgen/verwijderde gerechten. Komen niet meer in de pool,
          maar zijn hier terug te halen (of definitief te verwijderen). */}
      {!loading && gearchiveerd.length > 0 && (
        <div style={{ marginTop: 22, borderTop: '1px solid var(--m-line)', paddingTop: 16 }}>
          <button className="tap" onClick={() => setToonArchief((v) => !v)}
            style={{ display: 'flex', alignItems: 'center', gap: 8, width: '100%', background: 'none',
              border: 'none', cursor: 'pointer', padding: '2px 0', color: 'var(--ink-2)' }}>
            <MIcon name="box" size={16} color="var(--ink-3)" />
            <span style={{ fontSize: 13.5, fontWeight: 600 }}>Archief</span>
            <span className="num" style={{ fontSize: 12, color: 'var(--ink-3)' }}>{gearchiveerd.length}</span>
            <span style={{ flex: 1 }}></span>
            <MIcon name="chevron" size={15} color="var(--ink-3)"
              style={{ transform: toonArchief ? 'rotate(90deg)' : 'none', transition: 'transform .15s' }} />
          </button>
          {toonArchief && (
            <div style={{ marginTop: 12 }}>
              <div style={{ fontSize: 12, color: 'var(--ink-3)', lineHeight: 1.45, marginBottom: 12 }}>
                Deze gerechten worden niet meer voorgesteld. Zet ze terug om ze weer in je pool te krijgen.
              </div>
              {gearchiveerd.map((r) => (
                <div key={r.id} style={{ display: 'flex', alignItems: 'center', gap: 10, padding: '10px 0', borderBottom: '1px solid var(--m-line)' }}>
                  <div className="tap" onClick={() => openDetail(r)} role="button" style={{ flex: 1, minWidth: 0, cursor: 'pointer' }}>
                    <div style={{ fontSize: 13.5, fontWeight: 600, minWidth: 0, overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap', color: 'var(--ink-2)' }}>{r.naam}</div>
                    <div className="num" style={{ fontSize: 11.5, color: 'var(--ink-3)', marginTop: 2 }}>{Math.round(r.kcal || 0)} kcal · E {Math.round(r.eiwitten || 0)} K {Math.round(r.koolhydraten || 0)} V {Math.round(r.vetten || 0)}</div>
                  </div>
                  <button className="m-btn m-btn-ghost tap" onClick={() => herstel(r)} style={{ fontSize: 12.5, padding: '7px 12px', flex: '0 0 auto' }}>
                    <MIcon name="back" size={14} color="var(--forest-600)" /> Terugzetten
                  </button>
                  <button className="m-btn tap" onClick={() => verwijder(r)} title="Definitief verwijderen"
                    style={{ width: 32, height: 32, padding: 0, borderRadius: 10, background: 'var(--m-card-2)', border: '1px solid var(--m-line)', flex: '0 0 auto' }}>
                    <MIcon name="trash" size={14} color="var(--ink-3)" />
                  </button>
                </div>
              ))}
            </div>
          )}
        </div>
      )}
    </div>
  );
}

// comprimeerAfbeelding wordt ook door screen-log.jsx (foto-loggen) gebruikt.
Object.assign(window, { RecipesScreen, comprimeerAfbeelding });
