/* prototype/views/chapter.jsx
   LerenChapterView — stateful chapter-detail with tabs + edge-states.
   Tabs: Samenvatting / Mindmap / Flashcards / Vraag aan Pulse
   Edge-states: nieuw / voltooid (passed as prop chapterState from app.jsx)
*/

(function () {
  const { useState } = React;

  /* ─── Mock data (same as polish/leren-hoofdstuk-frames.jsx) ── */
  const HOOFDSTUK_BREADCRUMB = ['Bibliotheek', 'Biologie', 'havo-3', 'H3 — Cellen en celdeling'];

  const SAMENVATTING_SECTIONS = [
    {
      heading: 'Wat is een cel?',
      body: 'Een cel is de kleinste levende bouwsteen van een organisme. Alle planten, dieren en mensen zijn opgebouwd uit cellen — soms uit één (zoals een bacterie), soms uit miljarden. Cellen kunnen voedingsstoffen opnemen, energie maken, en zich vermenigvuldigen. Onder een microscoop zie je dat ze een afgesloten ruimte hebben met daarin verschillende onderdelen die elk een taak hebben.',
    },
    {
      heading: 'Mitose vs meiose',
      body: 'Mitose en meiose zijn twee soorten celdeling. Bij mitose ontstaan uit één moedercel twee identieke dochtercellen — dit gebruikt je lichaam voor groei en herstel. Bij meiose ontstaan vier verschillende geslachtscellen (eicel of zaadcel) met elk de helft van het DNA — dit is alleen voor voortplanting. Belangrijk: bij meiose verdubbelt het DNA niet voor de tweede deling, anders zou je nakomelingen veel te veel chromosomen krijgen.',
    },
    {
      heading: 'Plantencel vs dierlijke cel',
      body: 'Plantencellen en dierlijke cellen lijken op elkaar, maar er zijn drie grote verschillen. Plantencellen hebben een celwand (stevigheid), bladgroenkorrels (om met zonlicht suikers te maken) en één grote vacuole (water-opslag). Dierlijke cellen hebben deze drie niet — wel hebben ze een centriool, waardoor ze sneller en gerichter kunnen delen.',
    },
  ];

  const SAMENVATTING_HEADINGS = SAMENVATTING_SECTIONS.map(s => s.heading);

  const SAMPLE_FLASHCARDS = [
    { subject: 'biologie', source: 'Biologie voor jou · havo-3 · H3',
      front: 'Wat is mitose?',
      back: 'Een vorm van celdeling waarbij uit één moedercel twee identieke dochtercellen ontstaan.',
      note: 'Belangrijk: het DNA wordt eerst verdubbeld vóór de deling, zodat beide dochtercellen een complete set chromosomen krijgen.' },
    { subject: 'biologie', source: 'Biologie voor jou · havo-3 · H3',
      front: 'Wat is meiose?',
      back: 'Een speciale vorm van celdeling die geslachtscellen produceert; halveert het aantal chromosomen.',
      note: 'Geen tweede DNA-verdubbeling tussen de delingen — anders zou het chromosoom-aantal blijven groeien.' },
    { subject: 'biologie', source: 'Biologie voor jou · havo-3 · H3',
      front: 'Wat is osmose?',
      back: 'Diffusie van water door een semipermeabel membraan, van lage naar hoge opgeloste-stof-concentratie.',
      note: null },
    { subject: 'biologie', source: 'Biologie voor jou · havo-3 · H3',
      front: 'Verschil plantencel en dierlijke cel?',
      back: 'Plantencellen hebben celwand, bladgroenkorrels en vacuole. Dierlijke cellen hebben een centriool.',
      note: null },
    { subject: 'biologie', source: 'Biologie voor jou · havo-3 · H3',
      front: 'Wat doet een ribosoom?',
      back: 'Eiwitten aanmaken op basis van instructies van het DNA.',
      note: null },
  ];
  const SAMPLE_FLASHCARD = SAMPLE_FLASHCARDS[0]; // backwards-compat

  const SAMPLE_CHAT_MESSAGES = [
    { role: 'user', body: 'Wat is het verschil tussen mitose en meiose ook alweer?' },
    {
      role: 'pulse',
      body: 'Korte versie:\n\n• Mitose maakt 2 identieke cellen (groei en herstel).\n• Meiose maakt 4 verschillende geslachtscellen met de helft van het DNA (voortplanting).\n\nDe truc om te onthouden: mit-OSE is voor het mensen-LIJF, mei-OSE is voor de zaad/eicel-LIJN. Bij meiose is er ook geen tweede DNA-verdubbeling — anders zou je nakomelingen elke generatie verdubbelen in chromosomen.',
      citations: ['Biologie voor jou · H3 §3.2', 'Biologie voor jou · H3 §3.3'],
    },
  ];

  const HOOFDSTUK_TABS = [
    { id: 'samenvatting', label: 'Samenvatting',    icon: 'file-text' },
    { id: 'mindmap',      label: 'Mindmap',          icon: 'git-branch' },
    { id: 'flashcards',   label: 'Flashcards',       icon: 'layers', count: 12 },
    { id: 'pulse',        label: 'Vraag aan Pulse',  icon: 'message-circle' },
    { id: 'test',         label: 'Test jezelf',      icon: 'brain' },
  ];

  /* ─── Mock data: Recall / Feynman / RAG ─────────────────── */
  const RECALL_QUESTIONS = [
    {
      q: 'Wat is mitose?',
      sample: 'Een soort celdeling waarbij twee identieke cellen ontstaan',
      score: 8,
      klopt: 'Celdeling — correct',
      mist: "'identieke dochtercellen' detail"
    },
    {
      q: 'Wat is osmose?',
      sample: 'Water beweegt door een membraan van een lage naar hoge concentratie',
      score: 7,
      klopt: 'Bewegingsrichting van water — correct',
      mist: "'semipermeabel membraan' expliciet noemen"
    },
    {
      q: 'Wat is meiose?',
      sample: 'Celdeling voor geslachtscellen, waarbij het DNA gehalveerd wordt',
      score: 9,
      klopt: 'Halvering chromosomen + geslachtscellen — goed',
      mist: 'tweede deling zonder DNA-verdubbeling niet benoemd'
    },
  ];

  const FEYNMAN_TOPICS = [
    {
      id: 'mitose',
      label: 'Mitose',
      sampleAnswer: 'Stel je voor dat een cel zichzelf wil kopiëren. Eerst kopieert de cel al zijn DNA, daarna trekt hij die kopieën uit elkaar naar twee kanten en splitst hij in tweeën. Zo krijg je twee nieuwe cellen die precies hetzelfde zijn als het origineel. Dit gebeurt als je groeit of als een wond geneest.',
      feedback: {
        volledigheid: 4,
        helderheid: 5,
        eigenWoorden: 5,
        voorbeelden: 2,
        gaps: [
          'Je noemde de kerndeling (karyokinese) niet apart',
          'De fases (profase, metafase, anafase, telofase) zijn niet besproken',
        ],
        tips: [
          'Voeg één concreet voorbeeld toe, bijv. wondheling of groei',
          'Noem kort dat het DNA verdubbelt vóór de splitsing',
          'Vergelijk met meiose om het contrast te benadrukken',
        ],
      },
    },
    {
      id: 'meiose',
      label: 'Meiose',
      sampleAnswer: 'Meiose is als mitose maar dan twee keer, en het doel is geslachtscellen maken. Je begint met één cel, deelt twee keer, en eindigt met vier cellen die elk de helft van het DNA hebben. Die cellen zijn allemaal een beetje anders, wat zorgt voor genetische variatie.',
      feedback: {
        volledigheid: 4,
        helderheid: 4,
        eigenWoorden: 5,
        voorbeelden: 3,
        gaps: [
          'Crossing-over (uitwisseling van genetisch materiaal) niet genoemd',
          'Tweede deling zonder DNA-verdubbeling niet uitgelegd',
        ],
        tips: [
          'Leg uit waarom de tweede deling geen DNA-verdubbeling heeft',
          'Geef een voorbeeld: eicel of zaadcel',
        ],
      },
    },
    {
      id: 'plant-dier',
      label: 'Plant- vs dierlijke cel',
      sampleAnswer: 'Een plantencel heeft een stijve celwand om hem stevigheid te geven, en chloroplasten om zonlicht te gebruiken voor voedsel. Een dierlijke cel heeft dat niet, maar heeft wel een centriool dat helpt bij celdeling. Verder lijken ze heel erg op elkaar.',
      feedback: {
        volledigheid: 3,
        helderheid: 5,
        eigenWoorden: 4,
        voorbeelden: 3,
        gaps: [
          'De grote centrale vacuole van plantencellen niet vermeld',
          'Centriool van dierlijke cellen net iets te vaag omschreven',
        ],
        tips: [
          'Noem de vacuole: waterreservoir in de plantencel',
          'Geef een aanschouwelijk voorbeeld: boomstam vs spiercel',
        ],
      },
    },
    {
      id: 'stofwisseling',
      label: 'Stofwisseling',
      sampleAnswer: 'Stofwisseling is alles wat een cel doet om energie te maken en te gebruiken. De cel breekt suikers af om ATP te maken, en gebruikt dat ATP voor alles: bewegen, groeien, stoffen transporteren.',
      feedback: {
        volledigheid: 3,
        helderheid: 4,
        eigenWoorden: 4,
        voorbeelden: 2,
        gaps: [
          'Fotosynthese als onderdeel van stofwisseling niet vermeld',
          'Aerobe vs anaerobe ademhaling niet onderscheiden',
        ],
        tips: [
          'Onderscheid anabool (opbouwen) en katabool (afbreken)',
          'Noem de rol van mitochondriën',
        ],
      },
    },
  ];

  const RAG_QA = [
    {
      q: 'Wat is het verschil tussen mitose en meiose?',
      a: 'Mitose levert 2 identieke dochtercellen op — voor groei en herstel. Meiose levert 4 verschillende geslachtscellen met de helft van het DNA — voor voortplanting. Bij meiose is er ook geen tweede DNA-verdubbeling, anders zou het chromosomenaantal elke generatie verdubbelen.',
      sources: ['Biologie voor jou · H3 §3.2', 'Biologie voor jou · H3 §3.3'],
    },
    {
      q: 'Wat is osmose?',
      a: 'Osmose is de diffusie van water door een semipermeabel membraan, van de plek met de laagste opgeloste-stof-concentratie naar de plek met de hoogste. Het membraan laat water door, maar niet de grotere opgeloste deeltjes.',
      sources: ['Biologie voor jou · H3 §3.4'],
    },
    {
      q: 'Welke onderdelen heeft een plantencel maar een dierlijke cel niet?',
      a: 'Drie unieke onderdelen: (1) celwand voor stevigheid, (2) chloroplasten voor fotosynthese, (3) een grote centrale vacuole voor wateropslag. Dierlijke cellen hebben wél een centriool, plantencellen niet (of slechts rudimentair).',
      sources: ['Biologie voor jou · H3 §3.1'],
    },
    {
      q: 'Hoeveel cellen ontstaan er bij meiose?',
      a: 'Bij meiose ontstaan er uiteindelijk 4 cellen uit één moedercel. De eerste deling (meiose I) deelt het chromosomenaantal, de tweede deling (meiose II) lijkt op een gewone mitose. Alle 4 resulterende cellen bevatten de helft van het DNA van de moedercel.',
      sources: ['Biologie voor jou · H3 §3.3'],
    },
    {
      q: 'Wat is de rol van de vacuole?',
      a: 'De vacuole is een met celzap gevulde blaas in de cel. In plantencellen is er één grote centrale vacuole die water opslaat, de cel onder druk houdt (turgor) en zo stevigheid geeft aan de plant. In dierlijke cellen zijn er kleinere, tijdelijke vacuolen voor opslag of afbraak.',
      sources: ['Biologie voor jou · H3 §3.1'],
    },
  ];

  const MINDMAP_NODES = [
    { id: 'cel',        label: 'Wat is een cel?',       mastery: 3, angle: -90 },
    { id: 'mitose',     label: 'Mitose vs meiose',      mastery: 2, angle: -30, hover: true },
    { id: 'plant-dier', label: 'Plantencel vs dierlijk', mastery: 2, angle: 30 },
    { id: 'osmose',     label: 'Osmose & diffusie',     mastery: 1, angle: 90 },
    { id: 'organel',    label: 'Organellen & functies', mastery: 3, angle: 150 },
    { id: 'dna',        label: 'DNA in de cel',         mastery: 1, angle: 210 },
  ];

  /* ─── BronCertBadge ──────────────────────────────────────── */
  function BronCertBadge({ t, compact }) {
    const dark = t.mode === 'dark';
    const green = dark ? '#22C55E' : '#15803D';
    if (compact) {
      return (
        <span style={{
          display: 'inline-flex', alignItems: 'center', gap: 5,
          padding: '5px 10px', borderRadius: 999,
          background: dark ? 'rgba(34,197,94,0.10)' : 'rgba(21,128,61,0.06)',
          color: green,
          border: `1px solid ${dark ? 'rgba(34,197,94,0.24)' : 'rgba(21,128,61,0.22)'}`,
          fontSize: 10.5, fontWeight: 800, letterSpacing: 0.3, textTransform: 'uppercase',
          whiteSpace: 'nowrap',
        }}>
          <PI name="badge-check" size={11} color={green} strokeWidth={2.6} />
          Gecertificeerd
        </span>
      );
    }
    return (
      <div style={{
        background: t.card, border: `1px solid ${t.border}`,
        borderRadius: 8, padding: 12,
        display: 'flex', alignItems: 'flex-start', gap: 10,
      }}>
        <div style={{
          width: 30, height: 30, borderRadius: 8,
          background: dark ? 'rgba(34,197,94,0.12)' : 'rgba(21,128,61,0.08)',
          display: 'flex', alignItems: 'center', justifyContent: 'center', flexShrink: 0,
        }}>
          <PI name="badge-check" size={15} color={green} strokeWidth={2.4} />
        </div>
        <div style={{ flex: 1, minWidth: 0 }}>
          <div style={{ fontSize: 12, color: t.fg, fontWeight: 800 }}>Biologie voor jou</div>
          <div style={{ fontSize: 10.5, color: t.fgDim, fontWeight: 600, marginTop: 2 }}>
            Gecertificeerd lesmateriaal · uitgever Malmberg
          </div>
        </div>
      </div>
    );
  }

  /* ─── StandRow ───────────────────────────────────────────── */
  function StandRow({ t, label, value, icon, emphasis }) {
    const dark = t.mode === 'dark';
    const accent = emphasis ? (dark ? '#F472B6' : '#BE185D') : t.fgDim;
    return (
      <div style={{ display: 'flex', alignItems: 'center', gap: 10 }}>
        <div style={{
          width: 26, height: 26, borderRadius: 8,
          background: t.cardSunken, color: accent,
          display: 'flex', alignItems: 'center', justifyContent: 'center', flexShrink: 0,
        }}>
          <PI name={icon} size={13} color={accent} strokeWidth={2.4} />
        </div>
        <span style={{ flex: 1, fontSize: 12, color: t.fgDim, fontWeight: 700 }}>{label}</span>
        <span style={{
          fontSize: 12.5, color: emphasis ? accent : t.fg,
          fontWeight: 800, whiteSpace: 'nowrap',
        }}>{value}</span>
      </div>
    );
  }

  /* ─── StandVanZakenCard ──────────────────────────────────── */
  function StandVanZakenCard({ t, chapterState, onStartHoofdstuk, onStartHerhaling }) {
    const isNieuw = chapterState === 'nieuw';
    const isVoltooid = chapterState === 'voltooid';
    return (
      <div style={{
        background: t.card, border: `1px solid ${t.border}`,
        borderRadius: 10, padding: 16,
        display: 'flex', flexDirection: 'column', gap: 12,
      }}>
        <div style={{ display: 'flex', alignItems: 'center', gap: 8 }}>
          <PI name="activity" size={15} color={t.primary} strokeWidth={2.4} />
          <span style={{ fontFamily: 'Fredoka One', fontSize: 14, color: t.fg }}>Hoe sta je ervoor?</span>
        </div>

        <div style={{ display: 'flex', flexDirection: 'column', gap: 10 }}>
          {isNieuw && (
            <>
              <StandRow t={t} label="Beheersing"  value="nog niet"   icon="circle" />
              <StandRow t={t} label="Materiaal"   value="~ 35 min"   icon="book-open" />
              <StandRow t={t} label="Kaarten"     value="12 × nieuw" icon="layers" />
            </>
          )}
          {isVoltooid && (
            <>
              <StandRow t={t} label="Beheersing"    value="4/4 — zeker"  icon="check-circle" />
              <StandRow t={t} label="Volgende keer" value="ma 14 apr"    icon="calendar" />
              <StandRow t={t} label="Onderhoud"     value="1× per week"  icon="repeat" />
            </>
          )}
          {!isNieuw && !isVoltooid && (
            <>
              <StandRow t={t} label="Beheersing"     value="2/4 — bezig" icon="trending-up" />
              <StandRow t={t} label="Te herhalen"    value="8 kaarten"   icon="repeat" />
              <StandRow t={t} label="Resterend werk" value="~ 22 min"    icon="clock" />
              <StandRow t={t} label="Toets"          value="vrijdag"     icon="alert-circle" emphasis />
            </>
          )}
        </div>

        <div style={{
          marginTop: 4, paddingTop: 12, borderTop: `1px solid ${t.border}`,
          display: 'flex', flexDirection: 'column', gap: 8,
        }}>
          {isNieuw && (
            <>
              <BtnPrimary t={t} icon="play"
                style={{ justifyContent: 'center', width: '100%' }}
                onClick={onStartHoofdstuk}>
                Start hoofdstuk
              </BtnPrimary>
              <span style={{ fontSize: 10.5, color: t.fgMute, fontWeight: 700, textAlign: 'center' }}>
                We beginnen rustig met de samenvatting
              </span>
            </>
          )}
          {isVoltooid && (
            <>
              <BtnGhost t={t} icon="repeat"
                style={{ justifyContent: 'center', width: '100%' }}
                onClick={() => console.log('[chapter] onderhoudsherhaling starten')}>
                Onderhoudsherhaling starten
              </BtnGhost>
              <span style={{ fontSize: 10.5, color: t.fgMute, fontWeight: 700, textAlign: 'center' }}>
                1× per week · ~ 3 min
              </span>
            </>
          )}
          {!isNieuw && !isVoltooid && (
            <>
              <BtnPrimary t={t} icon="repeat"
                style={{ justifyContent: 'center', width: '100%' }}
                onClick={onStartHerhaling}>
                Begin herhaling — dit hoofdstuk
              </BtnPrimary>
              <span style={{ fontSize: 10.5, color: t.fgMute, fontWeight: 700, textAlign: 'center' }}>
                8 kaarten · ~ 6 min
              </span>
            </>
          )}
        </div>
      </div>
    );
  }

  /* ─── Tab content: Samenvatting ──────────────────────────── */
  function TabSamenvatting({ t }) {
    return (
      <div style={{ display: 'flex', flexDirection: 'column', gap: 22 }}>
        {SAMENVATTING_SECTIONS.map((sec, i) => (
          <div key={i}>
            <div style={{ display: 'flex', alignItems: 'center', gap: 10, marginBottom: 8 }}>
              <h3 style={{
                margin: 0, fontFamily: 'Fredoka One', fontSize: 18,
                color: t.fg, lineHeight: 1.2, letterSpacing: '-0.005em',
              }}>{sec.heading}</h3>
              <span style={{ flex: 1 }} />
              <BtnGhost t={t} icon="sparkles"
                onClick={() => console.log('[chapter] leg verder uit:', sec.heading)}>
                Leg verder uit
              </BtnGhost>
            </div>
            <p style={{
              margin: 0, fontSize: 14, color: t.fgDim,
              lineHeight: 1.7, fontWeight: 500, textWrap: 'pretty',
            }}>{sec.body}</p>
          </div>
        ))}
        <div style={{
          padding: '14px 16px', borderRadius: 8,
          background: t.cardSunken, border: `1px solid ${t.border}`,
          display: 'flex', alignItems: 'center', gap: 10,
        }}>
          <PI name="info" size={14} color={t.fgMute} strokeWidth={2.4} />
          <span style={{ fontSize: 11.5, color: t.fgDim, fontWeight: 600, lineHeight: 1.5, flex: 1 }}>
            Pulse heeft deze samenvatting opgesteld op basis van Biologie voor jou. Klopt iets niet, of mis je iets? Stel een vraag in de Pulse-tab.
          </span>
        </div>
      </div>
    );
  }

  /* ─── Tab content: Mindmap ───────────────────────────────── */
  function MindmapNode({ t, label, mastery, hover, style }) {
    const dark = t.mode === 'dark';
    return (
      <div style={{
        ...style,
        padding: '8px 10px', borderRadius: 10,
        background: hover
          ? (dark ? 'rgba(0,180,216,0.10)' : 'rgba(0,150,199,0.06)')
          : t.card,
        border: `1px solid ${hover ? hexToRgba(t.primary, 0.5) : t.border}`,
        boxShadow: hover
          ? (dark ? '0 6px 18px rgba(0,180,216,0.18)' : '0 4px 12px rgba(0,150,199,0.18)')
          : (dark ? '0 2px 6px rgba(0,0,0,0.30)' : '0 1px 3px rgba(15,23,42,0.06)'),
        display: 'flex', flexDirection: 'column', gap: 4,
        cursor: 'pointer',
      }}
        onClick={() => console.log('[chapter] mindmap node click:', label)}
      >
        <span style={{
          fontSize: 11.5, color: t.fg, fontWeight: 800, lineHeight: 1.25,
          textWrap: 'pretty',
        }}>{label}</span>
        <MasteryDots t={t} level={mastery} size="sm" />
      </div>
    );
  }

  function TabMindmap({ t }) {
    const dark = t.mode === 'dark';
    const W = 580, H = 420;
    const cx = W / 2, cy = H / 2;
    const R = 160;
    const lineColor = dark ? 'rgba(148,163,184,0.28)' : 'rgba(100,116,139,0.30)';

    return (
      <div style={{ display: 'grid', gridTemplateColumns: '1fr 220px', gap: 18 }}>
        <div style={{
          position: 'relative',
          background: t.cardSunken, border: `1px solid ${t.border}`,
          borderRadius: 10, padding: 14,
          minHeight: H + 28,
          backgroundImage: dark
            ? 'radial-gradient(circle at 50% 50%, rgba(0,180,216,0.05) 0%, transparent 60%)'
            : 'radial-gradient(circle at 50% 50%, rgba(0,150,199,0.04) 0%, transparent 60%)',
        }}>
          <svg width={W} height={H} style={{ display: 'block', margin: '0 auto' }}>
            {MINDMAP_NODES.map((n, i) => {
              const rad = (n.angle * Math.PI) / 180;
              const x = cx + Math.cos(rad) * R;
              const y = cy + Math.sin(rad) * R;
              return (
                <line key={i}
                  x1={cx} y1={cy} x2={x} y2={y}
                  stroke={n.hover ? t.primary : lineColor}
                  strokeWidth={n.hover ? 2 : 1.4}
                  strokeDasharray={n.hover ? null : '3 4'}
                />
              );
            })}
            <g>
              <circle cx={cx} cy={cy} r={58}
                fill={t.card}
                stroke={hexToRgba(t.primary, 0.45)}
                strokeWidth={2}
              />
              <circle cx={cx} cy={cy} r={58}
                fill={hexToRgba(t.primary, dark ? 0.10 : 0.06)}
              />
            </g>
          </svg>
          <div style={{
            position: 'absolute', left: 14 + cx - 55, top: 14 + cy - 28,
            width: 110, textAlign: 'center', pointerEvents: 'none',
          }}>
            <div style={{
              fontSize: 9.5, color: t.primary, fontWeight: 800,
              letterSpacing: 0.5, textTransform: 'uppercase', marginBottom: 2,
            }}>Hoofdstuk</div>
            <div style={{
              fontFamily: 'Fredoka One', fontSize: 12, color: t.fg,
              lineHeight: 1.15, letterSpacing: '-0.005em',
            }}>Cellen en celdeling</div>
          </div>
          {MINDMAP_NODES.map((n, i) => {
            const rad = (n.angle * Math.PI) / 180;
            const x = cx + Math.cos(rad) * R;
            const y = cy + Math.sin(rad) * R;
            return (
              <MindmapNode key={i} t={t}
                label={n.label}
                mastery={n.mastery}
                hover={n.hover}
                style={{ position: 'absolute', left: 14 + x - 74, top: 14 + y - 24, width: 148 }}
              />
            );
          })}
        </div>

        <div style={{
          background: t.cardSunken, border: `1px dashed ${t.borderStrong}`,
          borderRadius: 10, padding: '14px 14px 16px',
          display: 'flex', flexDirection: 'column', gap: 10,
          alignSelf: 'flex-start',
        }}>
          <PulseMascot size={40} mood="thinking" />
          <div>
            <div style={{
              fontSize: 11, color: t.primary, fontWeight: 800,
              letterSpacing: 0.4, textTransform: 'uppercase', marginBottom: 4,
            }}>Tip</div>
            <p style={{
              margin: 0, fontSize: 12.5, color: t.fgDim,
              lineHeight: 1.55, fontWeight: 600,
            }}>Klik op een knooppunt om er dieper in te duiken — je krijgt de samenvatting van dat onderdeel + de bijhorende kaarten.</p>
          </div>
          <div style={{
            marginTop: 4, paddingTop: 10, borderTop: `1px solid ${t.border}`,
            display: 'flex', alignItems: 'center', gap: 6, fontSize: 10.5,
            color: t.fgMute, fontWeight: 700,
          }}>
            <PI name="circle" size={9} color={t.fgMute} strokeWidth={2.4} />
            Open knooppunt: <b style={{ color: t.fg }}>Mitose vs meiose</b>
          </div>
        </div>
      </div>
    );
  }

  /* ─── Tab content: Flashcards ────────────────────────────── */
  function TabFlashcards({ t, cardIdx, setCardIdx, onGrade }) {
    const { useState: useS } = React;
    const [flipped, setFlipped] = useS(false);
    const total = SAMPLE_FLASHCARDS.length;
    const safeIdx = ((cardIdx % total) + total) % total;
    const card = SAMPLE_FLASHCARDS[safeIdx];

    function goPrev() {
      setFlipped(false);
      setCardIdx(idx => (idx - 1 + total) % total);
    }
    function goNext() {
      setFlipped(false);
      setCardIdx(idx => (idx + 1) % total);
    }
    function handleGradeAndAdvance(grade) {
      if (onGrade) onGrade(grade);
      setFlipped(false);
      setCardIdx(idx => (idx + 1) % total);
    }

    return (
      <div style={{ display: 'flex', flexDirection: 'column', gap: 18 }}>
        <div style={{ position: 'relative' }}>
          <FlashcardDeck t={t} card={card}
            flipped={flipped} idx={safeIdx + 1} total={total} showStackHint
            onGrade={handleGradeAndAdvance}
            flipCtaSub="Klik om het antwoord te zien"
          />
          {/* Flip-tap-zone over the card if not yet flipped */}
          {!flipped && (
            <div
              onClick={() => setFlipped(true)}
              style={{
                position: 'absolute', inset: 0, cursor: 'pointer',
                background: 'transparent',
              }}
              aria-label="Klik om te flippen"
            />
          )}
        </div>

        {/* Prev / Flip / Next controls */}
        <div style={{
          display: 'flex', alignItems: 'center', gap: 10,
          padding: '10px 14px', borderRadius: 10,
          background: t.card, border: `1px solid ${t.border}`,
        }}>
          <button
            onClick={goPrev}
            style={{
              display: 'inline-flex', alignItems: 'center', gap: 6,
              padding: '8px 14px', borderRadius: 999,
              background: t.cardSunken, border: `1px solid ${t.border}`,
              color: t.fgDim, fontSize: 12.5, fontWeight: 800, cursor: 'pointer',
              fontFamily: 'Nunito',
            }}>
            <PI name="chevron-left" size={13} color={t.fgDim} strokeWidth={2.4} />
            Vorige
          </button>

          <span style={{ fontSize: 11.5, color: t.fgMute, fontWeight: 800, letterSpacing: 0.3 }}>
            {safeIdx + 1} / {total}
          </span>

          <span style={{ flex: 1 }} />

          <button
            onClick={() => setFlipped(f => !f)}
            style={{
              display: 'inline-flex', alignItems: 'center', gap: 6,
              padding: '8px 14px', borderRadius: 999,
              background: t.primaryDim, border: `1px solid ${t.mode === 'dark' ? 'rgba(0,180,216,0.28)' : 'rgba(0,150,199,0.24)'}`,
              color: t.primary, fontSize: 12.5, fontWeight: 800, cursor: 'pointer',
              fontFamily: 'Nunito',
            }}>
            <PI name="repeat-2" size={13} color={t.primary} strokeWidth={2.4} />
            {flipped ? 'Terug naar vraag' : 'Toon antwoord'}
          </button>

          <span style={{ flex: 1 }} />

          <button
            onClick={goNext}
            style={{
              display: 'inline-flex', alignItems: 'center', gap: 6,
              padding: '8px 14px', borderRadius: 999,
              background: t.cardSunken, border: `1px solid ${t.border}`,
              color: t.fgDim, fontSize: 12.5, fontWeight: 800, cursor: 'pointer',
              fontFamily: 'Nunito',
            }}>
            Volgende
            <PI name="chevron-right" size={13} color={t.fgDim} strokeWidth={2.4} />
          </button>
        </div>

        <div style={{
          display: 'flex', alignItems: 'center', gap: 8,
          padding: '12px 14px', borderRadius: 8,
          background: t.cardSunken, border: `1px solid ${t.border}`,
        }}>
          <PulseMascot size={28} mood="encouraging" />
          <span style={{ fontSize: 12, color: t.fgDim, fontWeight: 600, lineHeight: 1.5, flex: 1 }}>
            Verken hier rustig — de echte herhaalsessie zit in 'Begin herhaling'. Daar tellen je grades mee voor de planning.
          </span>
        </div>
      </div>
    );
  }

  /* ─── Tab content: Pulse (interactive RAG chat) ─────────── */
  function TabPulse({ t, plan, creditsLeft, consumeCredit }) {
    const { useState: useS, useRef: useR } = React;
    const [messages, setMessages] = useS([]);
    const [draft, setDraft] = useS('');
    const [thinking, setThinking] = useS(false);
    const [localCredits, setLocalCredits] = useS(creditsLeft);
    const inputRef = useR(null);
    const bottomRef = useR(null);
    const dark = t.mode === 'dark';

    const SUGGESTIONS = [
      'Wat is het verschil tussen mitose en meiose?',
      'Wat is osmose?',
      'Welke onderdelen heeft een plantencel maar een dierlijke cel niet?',
    ];

    const noCredits = plan === 'free' && localCredits <= 0;

    function findAnswer(question) {
      const q = question.toLowerCase();
      for (const pair of RAG_QA) {
        if (pair.q.toLowerCase().split(' ').some(w => w.length > 4 && q.includes(w))) {
          return pair;
        }
      }
      return {
        a: 'Dat staat niet rechtstreeks in het materiaal van dit hoofdstuk. Probeer een specifiekere vraag over celdeling, osmose, of plantencel vs dierlijke cel.',
        sources: ['Biologie voor jou · H3'],
      };
    }

    function submit(question) {
      const text = (question || draft).trim();
      if (!text || thinking || noCredits) return;
      setDraft('');
      if (plan === 'free') {
        consumeCredit(1);
        setLocalCredits(c => Math.max(0, c - 1));
      }
      setMessages(ms => [...ms, { role: 'user', body: text }]);
      setThinking(true);
      setTimeout(() => {
        const pair = findAnswer(text);
        setThinking(false);
        // Append a streaming-placeholder pulse-message and reveal the body progressively (mock SSE)
        setMessages(ms => [...ms, { role: 'pulse', body: '', citations: [], streaming: true }]);
        const full = pair.a;
        const STEP = 3; // chars per tick
        let i = 0;
        const intervalId = setInterval(() => {
          i = Math.min(full.length, i + STEP);
          setMessages(ms => {
            if (ms.length === 0) return ms;
            const last = ms[ms.length - 1];
            if (last.role !== 'pulse') return ms;
            return [...ms.slice(0, -1), { ...last, body: full.slice(0, i) }];
          });
          if (bottomRef.current) bottomRef.current.scrollIntoView({ behavior: 'smooth' });
          if (i >= full.length) {
            clearInterval(intervalId);
            // Reveal citations + drop streaming flag
            setMessages(ms => {
              if (ms.length === 0) return ms;
              const last = ms[ms.length - 1];
              if (last.role !== 'pulse') return ms;
              return [...ms.slice(0, -1), { ...last, body: full, citations: pair.sources, streaming: false }];
            });
          }
        }, 22);
      }, 900);
    }

    function handleKeyDown(e) {
      if (e.key === 'Enter' && !e.shiftKey) { e.preventDefault(); submit(); }
    }

    const purple = dark ? '#9D4EDD' : '#7C3AED';

    return (
      <div style={{
        background: t.card, border: `1px solid ${t.border}`,
        borderRadius: 12, padding: 0,
        display: 'flex', flexDirection: 'column', height: 540,
        overflow: 'hidden',
      }}>
        {/* Header */}
        <div style={{
          display: 'flex', alignItems: 'center', gap: 10,
          padding: '14px 18px', borderBottom: `1px solid ${t.border}`,
          background: t.cardSunken,
        }}>
          <PulseMascot size={28} mood={thinking ? 'thinking' : 'curious'} />
          <div style={{ flex: 1 }}>
            <div style={{ fontFamily: 'Nunito', fontWeight: 800, fontSize: 13, color: t.fg }}>
              Pulse — vraag iets
            </div>
            <div style={{ fontSize: 10.5, color: t.fgMute, fontWeight: 700, marginTop: 2 }}>
              Antwoorden uit: <span style={{ color: t.fgDim }}>Biologie voor jou · H3</span>
            </div>
          </div>
          <span style={{
            display: 'inline-flex', alignItems: 'center', gap: 4,
            padding: '3px 9px', borderRadius: 999,
            background: dark ? 'rgba(157,78,221,0.14)' : 'rgba(124,58,237,0.10)',
            color: purple, border: `1px solid ${dark ? 'rgba(157,78,221,0.28)' : 'rgba(124,58,237,0.28)'}`,
            fontSize: 9.5, fontWeight: 800, letterSpacing: 0.4, textTransform: 'uppercase',
          }}>
            <PI name="sparkles" size={9} color={purple} strokeWidth={2.4} />RAG
          </span>
          {plan === 'free' && (
            <span style={{
              fontSize: 10.5, color: localCredits > 0 ? t.fgDim : '#EF4444',
              fontWeight: 800, whiteSpace: 'nowrap',
            }}>
              {localCredits} credit{localCredits !== 1 ? 's' : ''} over
            </span>
          )}
        </div>

        {/* Messages */}
        <div style={{
          flex: 1, overflowY: 'auto', padding: '18px',
          display: 'flex', flexDirection: 'column', gap: 14,
        }}>
          {messages.length === 0 && !thinking ? (
            <div style={{
              margin: 'auto', maxWidth: 360,
              display: 'flex', flexDirection: 'column', alignItems: 'center', gap: 12,
            }}>
              <PulseMascot size={56} mood="curious" />
              <div style={{ fontFamily: 'Fredoka One', fontSize: 17, color: t.fg, textAlign: 'center' }}>
                Wat zou je willen weten?
              </div>
              <div style={{ fontSize: 12, color: t.fgDim, textAlign: 'center', lineHeight: 1.5, fontWeight: 500 }}>
                Ik antwoord op basis van je lesmateriaal. Bronnen staan altijd onder het antwoord.
              </div>
            </div>
          ) : (
            messages.map((m, i) => <ChatBubble key={i} t={t} {...m} />)
          )}
          {thinking && (
            <div style={{ display: 'flex', alignItems: 'center', gap: 8 }}>
              <PulseMascot size={24} mood="thinking" />
              <span style={{
                fontSize: 12, color: t.fgMute, fontWeight: 700, fontStyle: 'italic',
              }}>Pulse denkt na…</span>
            </div>
          )}
          <div ref={bottomRef} />
        </div>

        {/* Paywall when no credits */}
        {noCredits && (
          <div style={{
            margin: '0 18px 10px',
            padding: '12px 14px', borderRadius: 8,
            background: dark ? 'rgba(239,68,68,0.10)' : 'rgba(239,68,68,0.06)',
            border: `1px solid ${dark ? 'rgba(239,68,68,0.30)' : 'rgba(239,68,68,0.22)'}`,
            fontSize: 12, color: dark ? '#FCA5A5' : '#991B1B', fontWeight: 700, lineHeight: 1.5,
          }}>
            Geen credits meer over deze maand. Wacht tot 1 mei of upgrade naar Premium.
          </div>
        )}

        {/* Suggestion chips — only when no messages yet */}
        {messages.length === 0 && !thinking && (
          <div style={{ display: 'flex', gap: 6, padding: '0 18px 10px', flexWrap: 'wrap' }}>
            {SUGGESTIONS.map((s, i) => (
              <button key={i} onClick={() => submit(s)} style={{
                padding: '6px 10px', borderRadius: 999,
                background: t.cardSunken, border: `1px solid ${t.border}`,
                color: t.fgDim, fontSize: 11.5, fontWeight: 700, cursor: noCredits ? 'not-allowed' : 'pointer',
                fontFamily: 'Nunito', whiteSpace: 'nowrap', opacity: noCredits ? 0.5 : 1,
              }}>{s}</button>
            ))}
          </div>
        )}

        {/* Composer */}
        <div style={{ padding: '12px 14px', borderTop: `1px solid ${t.border}`, background: t.bg }}>
          <div style={{
            display: 'flex', alignItems: 'center', gap: 8,
            padding: '8px 8px 8px 14px', borderRadius: 999,
            background: t.card, border: `1px solid ${t.borderStrong}`,
          }}>
            <input
              ref={inputRef}
              value={draft}
              onChange={e => setDraft(e.target.value)}
              onKeyDown={handleKeyDown}
              placeholder={noCredits ? 'Geen credits meer…' : 'Stel een vraag over dit hoofdstuk…'}
              disabled={noCredits || thinking}
              style={{
                flex: 1, background: 'transparent', border: 'none', outline: 'none',
                fontSize: 13, color: t.fg, fontFamily: 'Nunito', fontWeight: 600,
              }}
            />
            <button
              onClick={() => submit()}
              disabled={!draft.trim() || thinking || noCredits}
              style={{
                display: 'inline-flex', alignItems: 'center', justifyContent: 'center',
                width: 32, height: 32, borderRadius: 999,
                background: (!draft.trim() || thinking || noCredits) ? t.cardSunken : t.primary,
                border: 'none', cursor: (!draft.trim() || thinking || noCredits) ? 'not-allowed' : 'pointer',
                color: dark ? '#0A0F1E' : '#FFFFFF', flexShrink: 0,
              }}>
              <PI name="arrow-up" size={16} strokeWidth={2.6} />
            </button>
          </div>
        </div>
      </div>
    );
  }

  /* ─── Edge-state content: Nieuw ──────────────────────────── */
  function ContentNieuw({ t, onStartHoofdstuk }) {
    const dark = t.mode === 'dark';
    return (
      <div style={{ display: 'flex', flexDirection: 'column', gap: 22 }}>
        <div style={{
          padding: '24px 26px', borderRadius: 10,
          background: t.cardSunken, border: `1px dashed ${t.borderStrong}`,
          display: 'flex', alignItems: 'flex-start', gap: 18,
        }}>
          <PulseMascot size={56} mood="encouraging" />
          <div style={{ flex: 1, minWidth: 0 }}>
            <div style={{
              fontSize: 10.5, color: t.primary, fontWeight: 800,
              letterSpacing: 0.6, textTransform: 'uppercase', marginBottom: 4,
            }}>Nieuw hoofdstuk</div>
            <h2 style={{
              margin: 0, fontFamily: 'Fredoka One', fontSize: 22,
              color: t.fg, lineHeight: 1.25, letterSpacing: '-0.01em',
            }}>Klaar om dit hoofdstuk te ontdekken?</h2>
            <p style={{
              margin: '6px 0 0', fontSize: 13.5, color: t.fgDim,
              lineHeight: 1.6, fontWeight: 500,
            }}>We beginnen rustig. Eerst een samenvatting in drie stukken, daarna 12 flashcards om het in te slijpen. Stel onderweg gerust vragen.</p>
          </div>
        </div>

        <div>
          <div style={{
            fontSize: 11, color: t.fgMute, fontWeight: 800,
            letterSpacing: 0.4, textTransform: 'uppercase', marginBottom: 10,
          }}>In dit hoofdstuk · 3 onderwerpen</div>
          <div style={{ display: 'flex', flexDirection: 'column', gap: 10 }}>
            {SAMENVATTING_HEADINGS.map((heading, i) => (
              <div key={i} style={{
                display: 'flex', alignItems: 'center', gap: 12,
                padding: '12px 14px', borderRadius: 8,
                background: t.cardSunken, border: `1px solid ${t.border}`,
              }}>
                <span style={{
                  width: 22, height: 22, borderRadius: 999,
                  background: t.card, border: `1px solid ${t.borderStrong}`,
                  color: t.fgMute, fontSize: 11, fontWeight: 800,
                  display: 'flex', alignItems: 'center', justifyContent: 'center', flexShrink: 0,
                }}>{i + 1}</span>
                <span style={{ flex: 1, fontSize: 13.5, color: t.fg, fontWeight: 700 }}>{heading}</span>
                <MasteryDots t={t} level={0} size="sm" />
              </div>
            ))}
          </div>
        </div>

        <div style={{
          marginTop: 4, padding: '16px 18px', borderRadius: 10,
          background: dark ? 'rgba(0,180,216,0.06)' : 'rgba(0,150,199,0.04)',
          border: `1px solid ${hexToRgba(t.primary, dark ? 0.30 : 0.24)}`,
          display: 'flex', alignItems: 'center', gap: 14,
        }}>
          <PI name="play-circle" size={22} color={t.primary} strokeWidth={2.4} />
          <div style={{ flex: 1, minWidth: 0 }}>
            <div style={{ fontFamily: 'Fredoka One', fontSize: 15, color: t.fg }}>Start hoofdstuk</div>
            <div style={{ fontSize: 11.5, color: t.fgDim, fontWeight: 600, marginTop: 2 }}>
              We openen de samenvatting en lopen 'm samen door
            </div>
          </div>
          <BtnPrimary t={t} icon="play" onClick={onStartHoofdstuk}>
            Start hoofdstuk
          </BtnPrimary>
        </div>
      </div>
    );
  }

  /* ─── Edge-state content: Voltooid ──────────────────────── */
  function ContentVoltooid({ t }) {
    const dark = t.mode === 'dark';
    const green = dark ? '#22C55E' : '#15803D';
    return (
      <div style={{ display: 'flex', flexDirection: 'column', gap: 22 }}>
        <div style={{
          padding: '24px 26px', borderRadius: 10,
          background: dark ? 'rgba(34,197,94,0.07)' : 'rgba(21,128,61,0.04)',
          border: `1px solid ${dark ? 'rgba(34,197,94,0.28)' : 'rgba(21,128,61,0.22)'}`,
          display: 'flex', alignItems: 'flex-start', gap: 18,
        }}>
          <PulseMascot size={56} mood="celebrating" />
          <div style={{ flex: 1, minWidth: 0 }}>
            <div style={{
              fontSize: 10.5, color: green, fontWeight: 800,
              letterSpacing: 0.6, textTransform: 'uppercase', marginBottom: 4,
              display: 'inline-flex', alignItems: 'center', gap: 5,
            }}>
              <PI name="badge-check" size={11} color={green} strokeWidth={2.6} />
              Hoofdstuk afgerond
            </div>
            <h2 style={{
              margin: 0, fontFamily: 'Fredoka One', fontSize: 22,
              color: t.fg, lineHeight: 1.25, letterSpacing: '-0.01em',
            }}>Je beheerst dit hoofdstuk.</h2>
            <p style={{
              margin: '6px 0 0', fontSize: 13.5, color: t.fgDim,
              lineHeight: 1.6, fontWeight: 500,
            }}>Ik laat je 'm rustig herhalen om het vast te houden — geen druk, gewoon één keer per week kort langslopen.</p>
            <div style={{ marginTop: 12, display: 'flex', alignItems: 'center', gap: 12, flexWrap: 'wrap' }}>
              <span style={{
                display: 'inline-flex', alignItems: 'center', gap: 6,
                padding: '5px 11px', borderRadius: 999,
                background: t.card, border: `1px solid ${t.border}`,
                fontSize: 11.5, color: t.fgDim, fontWeight: 700,
              }}>
                <PI name="calendar" size={11} color={t.fgMute} strokeWidth={2.4} />
                Volgende keer: <b style={{ color: t.fg }}>ma 14 apr</b>
              </span>
              <span style={{
                display: 'inline-flex', alignItems: 'center', gap: 6,
                padding: '5px 11px', borderRadius: 999,
                background: t.card, border: `1px solid ${t.border}`,
                fontSize: 11.5, color: t.fgDim, fontWeight: 700,
              }}>
                <PI name="repeat" size={11} color={t.fgMute} strokeWidth={2.4} />
                ~ 3 min
              </span>
            </div>
          </div>
        </div>

        <div>
          <div style={{
            fontSize: 11, color: t.fgMute, fontWeight: 800,
            letterSpacing: 0.4, textTransform: 'uppercase', marginBottom: 10,
          }}>Beheersing per onderwerp</div>
          <div style={{ display: 'flex', flexDirection: 'column', gap: 10 }}>
            {SAMENVATTING_HEADINGS.map((heading, i) => (
              <div key={i} style={{
                display: 'flex', alignItems: 'center', gap: 12,
                padding: '12px 14px', borderRadius: 8,
                background: t.cardSunken, border: `1px solid ${t.border}`,
              }}>
                <span style={{
                  width: 22, height: 22, borderRadius: 999,
                  background: dark ? 'rgba(34,197,94,0.14)' : 'rgba(21,128,61,0.10)',
                  color: green,
                  display: 'flex', alignItems: 'center', justifyContent: 'center', flexShrink: 0,
                }}>
                  <PI name="check" size={13} color={green} strokeWidth={3} />
                </span>
                <span style={{ flex: 1, fontSize: 13.5, color: t.fg, fontWeight: 700 }}>{heading}</span>
                <MasteryDots t={t} level={4} size="sm" />
              </div>
            ))}
          </div>
        </div>

        <div style={{
          marginTop: 4, padding: '16px 18px', borderRadius: 10,
          background: t.cardSunken, border: `1px solid ${t.border}`,
          display: 'flex', alignItems: 'center', gap: 14,
        }}>
          <PI name="repeat" size={20} color={t.fgDim} strokeWidth={2.4} />
          <div style={{ flex: 1, minWidth: 0 }}>
            <div style={{ fontFamily: 'Fredoka One', fontSize: 14, color: t.fg }}>Onderhoudsherhaling</div>
            <div style={{ fontSize: 11.5, color: t.fgDim, fontWeight: 600, marginTop: 2 }}>
              1× per week · ~ 3 min · zo blijft het zitten
            </div>
          </div>
          <BtnGhost t={t} icon="repeat"
            onClick={() => console.log('[chapter] onderhoudsherhaling starten')}>
            Nu starten
          </BtnGhost>
        </div>
      </div>
    );
  }

  /* ─── LerenChapterView ───────────────────────────────────── */
  function LerenChapterView({ t, navigate, view, chapters, chapterState: chapterStateProp,
                              plan, creditsLeft, creditsMax, hasFeature, consumeCredit }) {
    const ch = (chapters && chapters.find(c => c.id === view.chapterId)) || {
      id: 'bio-h3', subject: 'biologie', method: 'Biologie voor jou',
      title: 'H3 — Cellen en celdeling', mastery: 2,
    };

    const [tab, setTab] = useState('samenvatting');
    const chapterState = chapterStateProp || (view && view.state) || 'normal';
    const [cardIdx, setCardIdx] = useState(0);

    const isNieuw = chapterState === 'nieuw';
    const isVoltooid = chapterState === 'voltooid';

    const masteryLevel = isNieuw ? 0 : isVoltooid ? 4 : 2;
    const toetsContext = (!isNieuw && !isVoltooid) ? 'toets vrijdag' : null;

    const subtitle = isNieuw
      ? 'Bio H3 — nog niet begonnen · ~ 35 min materiaal'
      : isVoltooid
        ? 'Bio H3 — afgerond · onderhoudsherhaling 1× per week'
        : 'Bio H3 — vrijdag toets · ~22 min resterend · 8 te herhalen';

    function handleStartHoofdstuk() {
      console.log('[chapter] start hoofdstuk:', ch.id);
      setTab('samenvatting');
    }

    function handleStartHerhaling() {
      console.log('[chapter] start herhaling → navigate review');
      navigate('review');
    }

    function handleGrade(grade) {
      console.log('[chapter] flashcard grade:', grade, 'card', cardIdx);
      setCardIdx(idx => idx + 1);
    }

    function renderTabContent() {
      if (isNieuw) {
        return <ContentNieuw t={t} onStartHoofdstuk={handleStartHoofdstuk} />;
      }
      if (isVoltooid) {
        return <ContentVoltooid t={t} />;
      }
      switch (tab) {
        case 'samenvatting': return <TabSamenvatting t={t} />;
        case 'mindmap':      return <TabMindmap t={t} />;
        case 'flashcards':   return <TabFlashcards t={t} cardIdx={cardIdx} setCardIdx={setCardIdx} onGrade={handleGrade} />;
        case 'pulse':        return <TabPulse t={t} plan={plan} creditsLeft={creditsLeft} consumeCredit={consumeCredit} />;
        case 'test':         return <TestJezelfTab t={t} hasFeature={hasFeature} />;
        default:             return <TabSamenvatting t={t} />;
      }
    }

    return (
      <LerenPage t={t}
        subtitle={subtitle}
        url="snapsnel.nl/leren/biologie/h3"
      >
        <div style={{ display: 'grid', gridTemplateColumns: '1fr 320px', gap: 20, maxWidth: 1180 }}>
          {/* Main column */}
          <div style={{ display: 'flex', flexDirection: 'column', gap: 18 }}>
            <ChapterHeader t={t}
              subject={ch.subject || 'biologie'}
              breadcrumb={HOOFDSTUK_BREADCRUMB}
              chapter="H3 — Cellen en celdeling"
              source="Biologie voor jou · havo-3"
              masteryLevel={masteryLevel}
              fromPlannen={!isVoltooid}
              toetsContext={toetsContext}
              rightExtra={<BronCertBadge t={t} compact />}
            />

            <div style={{
              background: t.card, border: `1px solid ${t.border}`,
              borderRadius: 10, overflow: 'hidden',
            }}>
              {!isNieuw && !isVoltooid && (
                <div style={{ padding: '0 22px' }}>
                  <LerenTabs
                    t={t}
                    tabs={HOOFDSTUK_TABS}
                    active={tab}
                    /* Override LerenTabs to be interactive */
                    onTabClick={setTab}
                  />
                </div>
              )}
              {(isNieuw || isVoltooid) && (
                <div style={{ padding: '0 22px' }}>
                  <LerenTabs
                    t={t}
                    tabs={HOOFDSTUK_TABS.slice(0, 1).map(tb => ({
                      ...tb,
                      label: isNieuw ? 'Samenvatting' : 'Overzicht',
                    }))}
                    active="samenvatting"
                    onTabClick={() => {}}
                  />
                </div>
              )}
              <div style={{ padding: '22px' }}>
                {renderTabContent()}
              </div>
            </div>
          </div>

          {/* Right rail */}
          <aside style={{ display: 'flex', flexDirection: 'column', gap: 14 }}>
            <StandVanZakenCard
              t={t}
              chapterState={chapterState}
              onStartHoofdstuk={handleStartHoofdstuk}
              onStartHerhaling={handleStartHerhaling}
            />
            <BronCertBadge t={t} />
            {!isNieuw && !isVoltooid && (
              <>
                <HandoffCard t={t} pillar="oefenen" direction="to"
                  title="Oefen na het leren"
                  subtitle="Een mini-quiz Bio H3 — test of het er echt zit"
                  compact
                  onClick={() => console.log('[chapter] handoff → oefenen')}
                />
                <HandoffCard t={t} pillar="plannen" direction="to"
                  title="Vrijhouden in je planner"
                  subtitle="Volgende leersessie inplannen voor donderdag"
                  compact
                  onClick={() => console.log('[chapter] handoff → plannen')}
                />
              </>
            )}
            {isNieuw && (
              <HandoffCard t={t} pillar="plannen" direction="to"
                title="Voor wanneer plan je dit in?"
                subtitle="Voeg een leersessie toe aan je planner"
                compact
                onClick={() => console.log('[chapter] handoff nieuw → plannen')}
              />
            )}
            {isVoltooid && (
              <HandoffCard t={t} pillar="oefenen" direction="to"
                title="Wil je nog testen?"
                subtitle="Mini-quiz om te zien of het écht blijft zitten"
                compact
                onClick={() => console.log('[chapter] handoff voltooid → oefenen')}
              />
            )}
          </aside>
        </div>
      </LerenPage>
    );
  }

  /* Patch LerenTabs to accept onTabClick (prototype only) */
  const _OrigLerenTabs = window.LerenTabs;
  window.LerenTabs = function LerenTabsInteractive({ t, tabs, active, accent, onTabClick }) {
    const c = accent || t.primary;
    return (
      <div style={{
        display: 'flex', gap: 4,
        borderBottom: `1px solid ${t.border}`,
        marginBottom: 0,
      }}>
        {tabs.map(tab => {
          const isActive = tab.id === active;
          return (
            <div key={tab.id}
              style={{
                padding: '12px 18px',
                borderBottom: `2px solid ${isActive ? c : 'transparent'}`,
                marginBottom: -1,
                display: 'inline-flex', alignItems: 'center', gap: 8,
                cursor: 'pointer',
              }}
              onClick={() => onTabClick && onTabClick(tab.id)}
            >
              {tab.icon && (
                <PI name={tab.icon} size={14}
                  color={isActive ? c : t.fgMute} strokeWidth={2.4} />
              )}
              <span style={{
                fontFamily: 'Nunito', fontSize: 13, fontWeight: 800,
                color: isActive ? t.fg : t.fgMute,
                whiteSpace: 'nowrap',
              }}>{tab.label}</span>
              {tab.count != null && (
                <span style={{
                  fontSize: 10.5, fontWeight: 800,
                  padding: '2px 7px', borderRadius: 999,
                  background: isActive
                    ? `color-mix(in srgb, ${c} 14%, transparent)`
                    : t.cardSunken,
                  color: isActive ? c : t.fgMute,
                  border: `1px solid ${isActive
                    ? `color-mix(in srgb, ${c} 28%, transparent)`
                    : t.border}`,
                }}>{tab.count}</span>
              )}
            </div>
          );
        })}
      </div>
    );
  };

  window.LerenChapterView = LerenChapterView;
})();
